qemu/json-streamer.c
<<
>>
Prefs
   1/*
   2 * JSON streaming support
   3 *
   4 * Copyright IBM, Corp. 2009
   5 *
   6 * Authors:
   7 *  Anthony Liguori   <aliguori@us.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  10 * See the COPYING.LIB file in the top-level directory.
  11 *
  12 */
  13
  14#include "qlist.h"
  15#include "qint.h"
  16#include "qdict.h"
  17#include "qemu-common.h"
  18#include "json-lexer.h"
  19#include "json-streamer.h"
  20
  21#define MAX_TOKEN_SIZE (64ULL << 20)
  22#define MAX_NESTING (1ULL << 10)
  23
  24static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTokenType type, int x, int y)
  25{
  26    JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
  27    QDict *dict;
  28
  29    if (type == JSON_OPERATOR) {
  30        switch (qstring_get_str(token)[0]) {
  31        case '{':
  32            parser->brace_count++;
  33            break;
  34        case '}':
  35            parser->brace_count--;
  36            break;
  37        case '[':
  38            parser->bracket_count++;
  39            break;
  40        case ']':
  41            parser->bracket_count--;
  42            break;
  43        default:
  44            break;
  45        }
  46    }
  47
  48    dict = qdict_new();
  49    qdict_put(dict, "type", qint_from_int(type));
  50    QINCREF(token);
  51    qdict_put(dict, "token", token);
  52    qdict_put(dict, "x", qint_from_int(x));
  53    qdict_put(dict, "y", qint_from_int(y));
  54
  55    parser->token_size += token->length;
  56
  57    qlist_append(parser->tokens, dict);
  58
  59    if (type == JSON_ERROR) {
  60        goto out_emit_bad;
  61    } else if (parser->brace_count < 0 ||
  62        parser->bracket_count < 0 ||
  63        (parser->brace_count == 0 &&
  64         parser->bracket_count == 0)) {
  65        goto out_emit;
  66    } else if (parser->token_size > MAX_TOKEN_SIZE ||
  67               parser->bracket_count > MAX_NESTING ||
  68               parser->brace_count > MAX_NESTING) {
  69        /* Security consideration, we limit total memory allocated per object
  70         * and the maximum recursion depth that a message can force.
  71         */
  72        goto out_emit;
  73    }
  74
  75    return;
  76
  77out_emit_bad:
  78    /* clear out token list and tell the parser to emit and error
  79     * indication by passing it a NULL list
  80     */
  81    QDECREF(parser->tokens);
  82    parser->tokens = NULL;
  83out_emit:
  84    /* send current list of tokens to parser and reset tokenizer */
  85    parser->brace_count = 0;
  86    parser->bracket_count = 0;
  87    parser->emit(parser, parser->tokens);
  88    if (parser->tokens) {
  89        QDECREF(parser->tokens);
  90    }
  91    parser->tokens = qlist_new();
  92    parser->token_size = 0;
  93}
  94
  95void json_message_parser_init(JSONMessageParser *parser,
  96                              void (*func)(JSONMessageParser *, QList *))
  97{
  98    parser->emit = func;
  99    parser->brace_count = 0;
 100    parser->bracket_count = 0;
 101    parser->tokens = qlist_new();
 102    parser->token_size = 0;
 103
 104    json_lexer_init(&parser->lexer, json_message_process_token);
 105}
 106
 107int json_message_parser_feed(JSONMessageParser *parser,
 108                             const char *buffer, size_t size)
 109{
 110    return json_lexer_feed(&parser->lexer, buffer, size);
 111}
 112
 113int json_message_parser_flush(JSONMessageParser *parser)
 114{
 115    return json_lexer_flush(&parser->lexer);
 116}
 117
 118void json_message_parser_destroy(JSONMessageParser *parser)
 119{
 120    json_lexer_destroy(&parser->lexer);
 121    QDECREF(parser->tokens);
 122}
 123