static int send_response(GAState *s, QObject *payload) { const char *buf; QString *payload_qstr, *response_qstr; GIOStatus status; g_assert(payload && s->channel); payload_qstr = qobject_to_json(payload); if (!payload_qstr) { return -EINVAL; } if (s->delimit_response) { s->delimit_response = false; response_qstr = qstring_new(); qstring_append_chr(response_qstr, QGA_SENTINEL_BYTE); qstring_append(response_qstr, qstring_get_str(payload_qstr)); QDECREF(payload_qstr); } else { response_qstr = payload_qstr; } qstring_append_chr(response_qstr, '\n'); buf = qstring_get_str(response_qstr); status = ga_channel_write_all(s->channel, buf, strlen(buf)); QDECREF(response_qstr); if (status != G_IO_STATUS_NORMAL) { return -EIO; } return 0; }
void json_prop_str(QJSON *json, const char *name, const char *str) { json_emit_element(json, name); qstring_append_chr(json->str, '"'); qstring_append(json->str, str); qstring_append_chr(json->str, '"'); }
static int conn_channel_send_payload(GIOChannel *channel, QObject *payload) { int ret = 0; const char *buf; QString *payload_qstr; GError *err = NULL; g_assert(payload && channel); payload_qstr = qobject_to_json(payload); if (!payload_qstr) { return -EINVAL; } qstring_append_chr(payload_qstr, '\n'); buf = qstring_get_str(payload_qstr); ret = conn_channel_send_buf(channel, buf, strlen(buf)); if (ret) { goto out_free; } g_io_channel_flush(channel, &err); if (err != NULL) { g_warning("error flushing payload: %s", err->message); ret = err->code; goto out_free; } out_free: QDECREF(payload_qstr); if (err) { g_error_free(err); } return ret; }
/** * qerror_human(): Format QError data into human-readable string. * * Formats according to member 'desc' of the specified QError object. */ QString *qerror_human(const QError *qerror) { const char *p; QString *qstring; assert(qerror->entry != NULL); qstring = qstring_new(); for (p = qerror->entry->desc; *p != '\0';) { if (*p != '%') { qstring_append_chr(qstring, *p++); } else if (*(p + 1) == '%') { qstring_append_chr(qstring, '%'); p += 2; } else { p = append_field(qstring, qerror, p); } } return qstring; }
static QString *qerror_format_desc(QDict *error, const QErrorStringTable *entry) { QString *qstring; const char *p; assert(entry != NULL); qstring = qstring_new(); for (p = entry->desc; *p != '\0';) { if (*p != '%') { qstring_append_chr(qstring, *p++); } else if (*(p + 1) == '%') { qstring_append_chr(qstring, '%'); p += 2; } else { p = append_field(error, qstring, entry, p); } } return qstring; }
static int json_lexer_feed_char(JSONLexer *lexer, char ch) { int char_consumed, new_state; lexer->x++; if (ch == '\n') { lexer->x = 0; lexer->y++; } do { new_state = json_lexer[lexer->state][(uint8_t)ch]; char_consumed = !TERMINAL_NEEDED_LOOKAHEAD(lexer->state, new_state); if (char_consumed) { qstring_append_chr(lexer->token, ch); } switch (new_state) { case JSON_OPERATOR: case JSON_ESCAPE: case JSON_INTEGER: case JSON_FLOAT: case JSON_KEYWORD: case JSON_STRING: lexer->emit(lexer, lexer->token, new_state, lexer->x, lexer->y); case JSON_SKIP: QDECREF(lexer->token); lexer->token = qstring_new(); new_state = IN_START; break; case IN_ERROR: return -EINVAL; default: break; } lexer->state = new_state; } while (!char_consumed); return 0; }
static void qobject_is_equal_string_test(void) { QString *str_base, *str_whitespace_0, *str_whitespace_1, *str_whitespace_2; QString *str_whitespace_3, *str_case, *str_built; str_base = qstring_from_str("foo"); str_whitespace_0 = qstring_from_str(" foo"); str_whitespace_1 = qstring_from_str("foo "); str_whitespace_2 = qstring_from_str("foo\b"); str_whitespace_3 = qstring_from_str("fooo\b"); str_case = qstring_from_str("Foo"); /* Should yield "foo" */ str_built = qstring_from_substr("form", 0, 1); qstring_append_chr(str_built, 'o'); check_unequal(str_base, str_whitespace_0, str_whitespace_1, str_whitespace_2, str_whitespace_3, str_case); check_equal(str_base, str_built); free_all(str_base, str_whitespace_0, str_whitespace_1, str_whitespace_2, str_whitespace_3, str_case, str_built); }
static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush) { int char_consumed, new_state; lexer->x++; if (ch == '\n') { lexer->x = 0; lexer->y++; } do { new_state = json_lexer[lexer->state][(uint8_t)ch]; char_consumed = !TERMINAL_NEEDED_LOOKAHEAD(lexer->state, new_state); if (char_consumed) { qstring_append_chr(lexer->token, ch); } switch (new_state) { case JSON_OPERATOR: case JSON_ESCAPE: case JSON_INTEGER: case JSON_FLOAT: case JSON_KEYWORD: case JSON_STRING: lexer->emit(lexer, lexer->token, new_state, lexer->x, lexer->y); /* fall through */ case JSON_SKIP: QDECREF(lexer->token); lexer->token = qstring_new(); new_state = IN_START; break; case IN_ERROR: /* XXX: To avoid having previous bad input leaving the parser in an * unresponsive state where we consume unpredictable amounts of * subsequent "good" input, percolate this error state up to the * tokenizer/parser by forcing a NULL object to be emitted, then * reset state. * * Also note that this handling is required for reliable channel * negotiation between QMP and the guest agent, since chr(0xFF) * is placed at the beginning of certain events to ensure proper * delivery when the channel is in an unknown state. chr(0xFF) is * never a valid ASCII/UTF-8 sequence, so this should reliably * induce an error/flush state. */ lexer->emit(lexer, lexer->token, JSON_ERROR, lexer->x, lexer->y); QDECREF(lexer->token); lexer->token = qstring_new(); new_state = IN_START; lexer->state = new_state; return 0; default: break; } lexer->state = new_state; } while (!char_consumed && !flush); /* Do not let a single token grow to an arbitrarily large size, * this is a security consideration. */ if (lexer->token->length > MAX_TOKEN_SIZE) { lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y); QDECREF(lexer->token); lexer->token = qstring_new(); lexer->state = IN_START; } return 0; }