mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-18 18:35:45 -04:00
dep/rcheevos: Bump to d54cf8f
This commit is contained in:
@ -37,6 +37,24 @@ static void rc_json_skip_whitespace(rc_json_iterator_t* iterator)
|
||||
++iterator->json;
|
||||
}
|
||||
|
||||
static int rc_json_find_substring(rc_json_iterator_t* iterator, const char* substring)
|
||||
{
|
||||
const char first = *substring;
|
||||
const size_t substring_len = strlen(substring);
|
||||
const char* end = iterator->end - substring_len;
|
||||
|
||||
while (iterator->json <= end) {
|
||||
if (*iterator->json == first) {
|
||||
if (memcmp(iterator->json, substring, substring_len) == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
++iterator->json;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rc_json_find_closing_quote(rc_json_iterator_t* iterator)
|
||||
{
|
||||
while (iterator->json < iterator->end) {
|
||||
@ -237,8 +255,6 @@ int rc_json_get_next_object_field(rc_json_iterator_t* iterator, rc_json_field_t*
|
||||
}
|
||||
|
||||
int rc_json_get_object_string_length(const char* json) {
|
||||
const char* json_start = json;
|
||||
|
||||
rc_json_iterator_t iterator;
|
||||
memset(&iterator, 0, sizeof(iterator));
|
||||
iterator.json = json;
|
||||
@ -246,34 +262,41 @@ int rc_json_get_object_string_length(const char* json) {
|
||||
|
||||
rc_json_parse_object(&iterator, NULL, 0, NULL);
|
||||
|
||||
return (int)(iterator.json - json_start);
|
||||
if (iterator.json == json) /* not JSON */
|
||||
return (int)strlen(json);
|
||||
|
||||
return (int)(iterator.json - json);
|
||||
}
|
||||
|
||||
static int rc_json_extract_html_error(rc_api_response_t* response, const rc_api_server_response_t* server_response) {
|
||||
const char* json = server_response->body;
|
||||
const char* end = json;
|
||||
rc_json_iterator_t iterator;
|
||||
memset(&iterator, 0, sizeof(iterator));
|
||||
iterator.json = server_response->body;
|
||||
iterator.end = server_response->body + server_response->body_length;
|
||||
|
||||
const char* title_start = strstr(json, "<title>");
|
||||
if (title_start) {
|
||||
title_start += 7;
|
||||
if (isdigit((int)*title_start)) {
|
||||
const char* title_end = strstr(title_start + 7, "</title>");
|
||||
if (title_end) {
|
||||
response->error_message = rc_buffer_strncpy(&response->buffer, title_start, title_end - title_start);
|
||||
response->succeeded = 0;
|
||||
return RC_INVALID_JSON;
|
||||
}
|
||||
/* if the title contains an HTTP status code(i.e "404 Not Found"), return the title */
|
||||
if (rc_json_find_substring(&iterator, "<title>")) {
|
||||
const char* title_start = iterator.json + 7;
|
||||
if (isdigit((int)*title_start) && rc_json_find_substring(&iterator, "</title>")) {
|
||||
response->error_message = rc_buffer_strncpy(&response->buffer, title_start, iterator.json - title_start);
|
||||
response->succeeded = 0;
|
||||
return RC_INVALID_JSON;
|
||||
}
|
||||
}
|
||||
|
||||
while (*end && *end != '\n' && end - json < 200)
|
||||
++end;
|
||||
/* title not found, or did not start with an error code, return the first line of the response */
|
||||
iterator.json = server_response->body;
|
||||
|
||||
if (end > json && end[-1] == '\r')
|
||||
--end;
|
||||
while (iterator.json < iterator.end && *iterator.json != '\n' &&
|
||||
iterator.json - server_response->body < 200) {
|
||||
++iterator.json;
|
||||
}
|
||||
|
||||
if (end > json)
|
||||
response->error_message = rc_buffer_strncpy(&response->buffer, json, end - json);
|
||||
if (iterator.json > server_response->body && iterator.json[-1] == '\r')
|
||||
--iterator.json;
|
||||
|
||||
if (iterator.json > server_response->body)
|
||||
response->error_message = rc_buffer_strncpy(&response->buffer, server_response->body, iterator.json - server_response->body);
|
||||
|
||||
response->succeeded = 0;
|
||||
return RC_INVALID_JSON;
|
||||
@ -915,6 +938,27 @@ int rc_json_get_required_bool(int* out, rc_api_response_t* response, const rc_js
|
||||
return rc_json_missing_field(response, field);
|
||||
}
|
||||
|
||||
void rc_json_extract_filename(rc_json_field_t* field) {
|
||||
if (field->value_end) {
|
||||
const char* str = field->value_end;
|
||||
|
||||
/* remove the extension */
|
||||
while (str > field->value_start && str[-1] != '/') {
|
||||
--str;
|
||||
if (*str == '.') {
|
||||
field->value_end = str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* find the path separator */
|
||||
while (str > field->value_start && str[-1] != '/')
|
||||
--str;
|
||||
|
||||
field->value_start = str;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- rc_api_request --- */
|
||||
|
||||
void rc_api_destroy_request(rc_api_request_t* request)
|
||||
|
@ -67,6 +67,8 @@ int rc_json_get_array_entry_object(rc_json_field_t* fields, size_t field_count,
|
||||
int rc_json_get_next_object_field(rc_json_iterator_t* iterator, rc_json_field_t* field);
|
||||
int rc_json_get_object_string_length(const char* json);
|
||||
|
||||
void rc_json_extract_filename(rc_json_field_t* field);
|
||||
|
||||
void rc_url_builder_append_encoded_str(rc_api_url_builder_t* builder, const char* str);
|
||||
void rc_url_builder_append_num_param(rc_api_url_builder_t* builder, const char* param, int32_t value);
|
||||
void rc_url_builder_append_unum_param(rc_api_url_builder_t* builder, const char* param, uint32_t value);
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include "rc_runtime_types.h"
|
||||
|
||||
#include "../rc_compat.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -371,3 +373,91 @@ int rc_api_process_fetch_games_list_server_response(rc_api_fetch_games_list_resp
|
||||
void rc_api_destroy_fetch_games_list_response(rc_api_fetch_games_list_response_t* response) {
|
||||
rc_buffer_destroy(&response->response.buffer);
|
||||
}
|
||||
|
||||
/* --- Fetch Game Titles --- */
|
||||
|
||||
int rc_api_init_fetch_game_titles_request(rc_api_request_t* request, const rc_api_fetch_game_titles_request_t* api_params) {
|
||||
rc_api_url_builder_t builder;
|
||||
char num[16];
|
||||
uint32_t i;
|
||||
|
||||
rc_api_url_build_dorequest_url(request);
|
||||
|
||||
if (api_params->num_game_ids == 0)
|
||||
return RC_INVALID_STATE;
|
||||
|
||||
rc_url_builder_init(&builder, &request->buffer, 48);
|
||||
rc_url_builder_append_str_param(&builder, "r", "gameinfolist");
|
||||
rc_url_builder_append_unum_param(&builder, "g", api_params->game_ids[0]);
|
||||
|
||||
for (i = 1; i < api_params->num_game_ids; i++) {
|
||||
int chars = snprintf(num, sizeof(num), "%u", api_params->game_ids[i]);
|
||||
rc_url_builder_append(&builder, ",", 1);
|
||||
rc_url_builder_append(&builder, num, chars);
|
||||
}
|
||||
|
||||
request->post_data = rc_url_builder_finalize(&builder);
|
||||
request->content_type = RC_CONTENT_TYPE_URLENCODED;
|
||||
|
||||
return builder.result;
|
||||
}
|
||||
|
||||
int rc_api_process_fetch_game_titles_server_response(rc_api_fetch_game_titles_response_t* response, const rc_api_server_response_t* server_response) {
|
||||
rc_api_game_title_entry_t* entry;
|
||||
rc_json_iterator_t iterator;
|
||||
rc_json_field_t array_field;
|
||||
int result;
|
||||
|
||||
rc_json_field_t fields[] = {
|
||||
RC_JSON_NEW_FIELD("Success"),
|
||||
RC_JSON_NEW_FIELD("Error"),
|
||||
RC_JSON_NEW_FIELD("Response")
|
||||
};
|
||||
|
||||
rc_json_field_t entry_fields[] = {
|
||||
RC_JSON_NEW_FIELD("ID"),
|
||||
RC_JSON_NEW_FIELD("Title"),
|
||||
RC_JSON_NEW_FIELD("ImageIcon")
|
||||
};
|
||||
|
||||
memset(response, 0, sizeof(*response));
|
||||
rc_buffer_init(&response->response.buffer);
|
||||
|
||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||
if (result != RC_OK)
|
||||
return result;
|
||||
|
||||
if (!rc_json_get_required_array(&response->num_entries, &array_field, &response->response, &fields[2], "Response"))
|
||||
return RC_MISSING_VALUE;
|
||||
|
||||
if (response->num_entries) {
|
||||
response->entries = (rc_api_game_title_entry_t*)rc_buffer_alloc(&response->response.buffer, response->num_entries * sizeof(rc_api_game_title_entry_t));
|
||||
if (!response->entries)
|
||||
return RC_OUT_OF_MEMORY;
|
||||
|
||||
memset(&iterator, 0, sizeof(iterator));
|
||||
iterator.json = array_field.value_start;
|
||||
iterator.end = array_field.value_end;
|
||||
|
||||
entry = response->entries;
|
||||
while (rc_json_get_array_entry_object(entry_fields, sizeof(entry_fields) / sizeof(entry_fields[0]), &iterator)) {
|
||||
if (!rc_json_get_required_unum(&entry->id, &response->response, &entry_fields[0], "ID"))
|
||||
return RC_MISSING_VALUE;
|
||||
if (!rc_json_get_required_string(&entry->title, &response->response, &entry_fields[1], "Title"))
|
||||
return RC_MISSING_VALUE;
|
||||
|
||||
/* ImageIcon will be '/Images/0123456.png' - only return the '0123456' */
|
||||
rc_json_extract_filename(&entry_fields[2]);
|
||||
if (!rc_json_get_required_string(&entry->image_name, &response->response, &entry_fields[2], "ImageIcon"))
|
||||
return RC_MISSING_VALUE;
|
||||
|
||||
++entry;
|
||||
}
|
||||
}
|
||||
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
void rc_api_destroy_fetch_game_titles_response(rc_api_fetch_game_titles_response_t* response) {
|
||||
rc_buffer_destroy(&response->response.buffer);
|
||||
}
|
||||
|
@ -111,7 +111,6 @@ int rc_api_process_fetch_game_data_server_response(rc_api_fetch_game_data_respon
|
||||
rc_api_leaderboard_definition_t* leaderboard;
|
||||
rc_json_field_t array_field;
|
||||
rc_json_iterator_t iterator;
|
||||
const char* str;
|
||||
const char* last_author = "";
|
||||
const char* last_author_field = "";
|
||||
size_t last_author_len = 0;
|
||||
@ -180,17 +179,7 @@ int rc_api_process_fetch_game_data_server_response(rc_api_fetch_game_data_respon
|
||||
return RC_MISSING_VALUE;
|
||||
|
||||
/* ImageIcon will be '/Images/0123456.png' - only return the '0123456' */
|
||||
if (patchdata_fields[3].value_end) {
|
||||
str = patchdata_fields[3].value_end - 5;
|
||||
if (memcmp(str, ".png\"", 5) == 0) {
|
||||
patchdata_fields[3].value_end -= 5;
|
||||
|
||||
while (str > patchdata_fields[3].value_start && str[-1] != '/')
|
||||
--str;
|
||||
|
||||
patchdata_fields[3].value_start = str;
|
||||
}
|
||||
}
|
||||
rc_json_extract_filename(&patchdata_fields[3]);
|
||||
rc_json_get_optional_string(&response->image_name, &response->response, &patchdata_fields[3], "ImageIcon", "");
|
||||
|
||||
/* estimate the amount of space necessary to store the rich presence script, achievements, and leaderboards.
|
||||
@ -248,9 +237,15 @@ int rc_api_process_fetch_game_data_server_response(rc_api_fetch_game_data_respon
|
||||
if (!rc_json_get_required_string(&achievement->author, &response->response, &achievement_fields[6], "Author"))
|
||||
return RC_MISSING_VALUE;
|
||||
|
||||
last_author = achievement->author;
|
||||
last_author_field = achievement_fields[6].value_start;
|
||||
last_author_len = len;
|
||||
if (achievement->author == NULL) {
|
||||
/* ensure we don't pass NULL out to client */
|
||||
last_author = achievement->author = "";
|
||||
last_author_len = 0;
|
||||
} else {
|
||||
last_author = achievement->author;
|
||||
last_author_field = achievement_fields[6].value_start;
|
||||
last_author_len = len;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rc_json_get_required_unum(&timet, &response->response, &achievement_fields[8], "Created"))
|
||||
|
Reference in New Issue
Block a user