utility/json_parser/parse_example3.c

/*
* EVALUATION AND USE OF THIS SOFTWARE IS SUBJECT TO THE TERMS AND
* CONDITIONS OF THE CONTROLLING LICENSE AGREEMENT FOUND AT LICENSE.md
* IN THIS SDK. IF YOU DO NOT AGREE TO THE LICENSE TERMS AND CONDITIONS,
* PLEASE RETURN ALL SOURCE FILES TO SILICON LABORATORIES.
* (c) Copyright 2018, Silicon Laboratories Inc. All rights reserved.
*/
#include "gos.h"
typedef struct
{
gos_handle_t handle;
bool keep_next_token;
bool in_from_object;
} parse_context_t;
static gos_result_t json_token_callback(void *user, gos_json_parse_context_t *json_context, gos_json_tok_t *tok);
static gos_result_t file_reader(void *user, void *data, uint32_t max_length, uint32_t *bytes_read);
/*************************************************************************************************
* Demonstrates how to read a JSON file in chunks only keeping certain tokens
*/
gos_result_t parse_example3(const char *filename)
{
gos_result_t result;
gos_json_parse_context_t *json_context = NULL;
char buffer[128];
parse_context_t parse_context;
const gos_json_parse_config_t config =
{
.buffer = buffer,
.buffer_len = sizeof(buffer),
.reader = file_reader,
.token_callback = json_token_callback
};
memset(&parse_context, 0, sizeof(parse_context));
GOS_LOG("\r\n\r\nParsing: %s", filename);
if (GOS_FAILED(result, gos_file_open(filename, GOS_FILE_LOCATION_EXTENDED, false, &parse_context.handle)))
{
GOS_LOG("Failed to open: %s", filename);
}
else if (GOS_FAILED(result, gos_json_parse_context_init(&json_context, &config)))
{
GOS_LOG("Failed to initialize json parsing context");
}
else if (GOS_FAILED(result, gos_json_parse_chunked(json_context, (void*)&parse_context)))
{
GOS_LOG("Failed to parse json file");
}
else
{
GOS_LOG("Name/messages:");
for (const gos_json_tok_t *tok = gos_json_context_get_token(json_context, NULL, NULL); tok != NULL; )
{
if (tok->next == NULL)
{
GOS_LOG("Malformed JSON");
break;
}
const char *name = tok->data.str;
const char *message = tok->next->data.str;
tok = tok->next->next; // skip ahead two tokens
GOS_LOG(" %s : %s", name, message);
}
}
gos_file_close(parse_context.handle);
GOS_LOG("Finished");
return result;
}
/*************************************************************************************************
* This is called before a token is allocated. If this return GOS_SUCCESS the token is allocated,
* if it returns GOS_ABORT the token is not allocated, returning anything else will cause the
* parsing to fail.
*/
static gos_result_t json_token_callback(void *user, gos_json_parse_context_t *json_context, gos_json_tok_t *tok)
{
parse_context_t *context = (parse_context_t*)user;
// We want to only keep the 'name' and 'message' VALUES.
if (context->keep_next_token)
{
// The previous token was a 'name' or 'message' key, so keep its value by returning GOS_SUCCESS
context->keep_next_token = false;
return GOS_SUCCESS;
}
// Is this a string token?
else if (tok->type == GOS_JSON_TYPE_STRING)
{
// If entering the 'from' object?
if ((context->in_from_object == 0) && (strcmp(tok->data.str, "from") == 0))
{
context->in_from_object = true;
}
// If we're in the 'from' object and this is a key 'named' then we want to keep the NEXT token
else if (context->in_from_object && strcmp(tok->data.str, "name") == 0)
{
context->in_from_object = false;
context->keep_next_token = true;
}
// If this is a 'message' token then we want to keep the next token
else if (strcmp(tok->data.str, "message") == 0)
{
context->keep_next_token = true;
}
}
return GOS_ABORTED; // Returning GOS_ABORTED discards this token
}
/*************************************************************************************************
* The parser will call this until it returns an error or the 'bytes_read' parameter is return with a 0 value.
*/
static gos_result_t file_reader(void *user, void *data, uint32_t max_length, uint32_t *bytes_read)
{
parse_context_t *context = (parse_context_t*)user;
uint32_t has_more_data;
gos_file_poll(context->handle, &has_more_data);
if (has_more_data == 0)
{
// no more data so set this to 0 to tell the parser to stop calling this reader
*bytes_read = 0;
}
else if (GOS_FAILED(result, gos_file_read(context->handle, data, max_length, bytes_read)))
{
}
return result;
}