Пример #1
0
Файл: json.c Проект: 0x0all/mpv
/* Write the contents of *src as JSON, and append the JSON string to *dst.
 * This will use strlen() to determine the start offset, and ta_get_size()
 * and ta_realloc() to extend the memory allocation of *dst.
 * Returns: 0 on success, <0 on failure.
 */
int json_write(char **dst, struct mpv_node *src)
{
    bstr buffer = bstr0(*dst);
    int r = json_append(&buffer, src);
    *dst = buffer.start;
    return r;
}
Пример #2
0
Файл: json.c Проект: Akemi/mpv
static int json_append_str(char **dst, struct mpv_node *src, int indent)
{
    bstr buffer = bstr0(*dst);
    int r = json_append(&buffer, src, indent);
    *dst = buffer.start;
    return r;
}
Пример #3
0
Файл: json.c Проект: Akemi/mpv
static int json_append(bstr *b, const struct mpv_node *src, int indent)
{
    switch (src->format) {
    case MPV_FORMAT_NONE:
        APPEND(b, "null");
        return 0;
    case MPV_FORMAT_FLAG:
        APPEND(b, src->u.flag ? "true" : "false");
        return 0;
    case MPV_FORMAT_INT64:
        bstr_xappend_asprintf(NULL, b, "%"PRId64, src->u.int64);
        return 0;
    case MPV_FORMAT_DOUBLE:
        bstr_xappend_asprintf(NULL, b, "%f", src->u.double_);
        return 0;
    case MPV_FORMAT_STRING:
        write_json_str(b, src->u.string);
        return 0;
    case MPV_FORMAT_NODE_ARRAY:
    case MPV_FORMAT_NODE_MAP: {
        struct mpv_node_list *list = src->u.list;
        bool is_obj = src->format == MPV_FORMAT_NODE_MAP;
        APPEND(b, is_obj ? "{" : "[");
        int next_indent = indent >= 0 ? indent + 1 : -1;
        for (int n = 0; n < list->num; n++) {
            if (n)
                APPEND(b, ",");
            add_indent(b, next_indent);
            if (is_obj) {
                write_json_str(b, list->keys[n]);
                APPEND(b, ":");
            }
            json_append(b, &list->values[n], next_indent);
        }
        add_indent(b, indent);
        APPEND(b, is_obj ? "}" : "]");
        return 0;
    }
    }
    return -1; // unknown format
}
Пример #4
0
json_value *json_parse(char *source, char **error_pos, int *error_line, block_allocator *allocator)
{
	json_value *root = 0;
	json_value *top = 0;

	char *name = 0;
	char *it = source;

	int escaped_newlines = 0;

	while (*it)
	{
		switch (*it)
		{
		case '{':
		case '[':
			{
				// create new value
				json_value *object = json_alloc(allocator);

				// name
				object->name = name;
				name = 0;

				// type
				object->type = (*it == '{') ? JSON_OBJECT : JSON_ARRAY;

				// skip open character
				++it;

				// set top and root
				if (top)
				{
					json_append(top, object);
				}
				else if (!root)
				{
					root = object;
				}
				else
				{
					ERROR(it, "Second root. Only one root allowed");
				}
				top = object;
			}
			break;

		case '}':
		case ']':
			{
				if (!top || top->type != ((*it == '}') ? JSON_OBJECT : JSON_ARRAY))
				{
					ERROR(it, "Mismatch closing brace/bracket");
				}

				// skip close character
				++it;

				// set top
				top = top->parent;
			}
			break;

		case ':':
			if (!top || top->type != JSON_OBJECT)
			{
				ERROR(it, "Unexpected character");
			}
			++it;
			break;

		case ',':
			CHECK_TOP();
			++it;
			break;

		case '"':
			{
				CHECK_TOP();

				// skip '"' character
				++it;

				char *first = it;
				char *last = it;
				while (*it)
				{
					if ((unsigned char)*it < '\x20')
					{
						ERROR(first, "Control characters not allowed in strings");
					}
					else if (*it == '\\')
					{
						switch (it[1])
						{
						case '"':
							*last = '"';
							break;
						case '\\':
							*last = '\\';
							break;
						case '/':
							*last = '/';
							break;
						case 'b':
							*last = '\b';
							break;
						case 'f':
							*last = '\f';
							break;
						case 'n':
							*last = '\n';
							++escaped_newlines;
							break;
						case 'r':
							*last = '\r';
							break;
						case 't':
							*last = '\t';
							break;
						case 'u':
							{
								unsigned int codepoint;
								if (hatoui(it + 2, it + 6, &codepoint) != it + 6)
								{
									ERROR(it, "Bad unicode codepoint");
								}

								if (codepoint <= 0x7F)
								{
									*last = (char)codepoint;
								}
								else if (codepoint <= 0x7FF)
								{
									*last++ = (char)(0xC0 | (codepoint >> 6));
									*last = (char)(0x80 | (codepoint & 0x3F));
								}
								else if (codepoint <= 0xFFFF)
								{
									*last++ = (char)(0xE0 | (codepoint >> 12));
									*last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
									*last = (char)(0x80 | (codepoint & 0x3F));
								}
							}
							it += 4;
							break;
						default:
							ERROR(first, "Unrecognized escape sequence");
						}

						++last;
						it += 2;
					}
					else if (*it == '"')
					{
						*last = 0;
						++it;
						break;
					}
					else
					{
						*last++ = *it++;
					}
				}
Пример #5
0
int json_parse_object( json_task_t *task, json_object_t *parent ) {
    char ch;
    json_object_t node, * append = NULL;
    
    node.next = parent;
    node.key = NULL;
    node.key_len = 0;
    
    if( !task->callback ) {
        if( !task->root ) {
            append = task->root = json_create_object();
        } else {
            append = parent->value.p = json_create_object();
        }
    }
    
    task->status = STS_OBJECT_START;

    while(( ch = *(task->str + task->count) )) {
        task->count ++;
        
        if( ch == ' ' || ch == '\n' || ch == '\t' ) {
            continue;
        }
        
        switch( task->status ) {
            case STS_OBJECT_START:
                if( ch == '"' ) {
                    node.key = task->str + task->count;
                    if( json_parse_string( task ) != 0 ) {
                        return -1;
                    }
                    // WARNING: key_len 可能发生溢出
                    node.key_len = task->str + task->count - node.key - 1;
                    
                    task->status = STS_OBJECT_COLON;
                } else if( ch == '}' ) {
                    // 空对象 {},忽略
                    return 0;
                } else {
                    task->err_msg = "expect '\"' or '}'";
                    return -1;
                }
                break;
            case STS_OBJECT_COLON:
                if( ch == ':' ) {
                    task->status = STS_OBJECT_VALUE;
                } else {
                    task->err_msg = "expect ':'";
                    return -1;
                }
                break;
            case STS_OBJECT_VALUE:
                /* 这里需要将计数减一,因为 json_parse_value 需要根据这一个字符判断 value 类型 */
                task->count --;
                
                node.value.s = task->str + task->count;
                if( json_parse_value( task, &node ) != 0 ) {
                    if( node.value_type == JSON_OBJECT ||
                        node.value_type == JSON_ARRAY ) {
                        json_delete_object(node.value.p);
                    }
                    return -1;
                }
                // WARNING: value_len 可能发生溢出
                node.value_len = task->str + task->count - node.value.s;

                task->status = STS_OBJECT_COMMA;
                break;
            case STS_OBJECT_COMMA:
                if( ( ch == ',' || ch == '}' ) ) {
                    // 对 value 进行处理
                    switch(node.value_type) {
                        case JSON_STRING:
                            // 去除字符串两端的引号
                            node.value.s += 1;
                            node.value_len -= 2;
                            break;
                        case JSON_DOUBLE:
                            node.value.d = atof(node.value.s);
                            break;
                        case JSON_LONGLONG:
                            node.value.l = atoll(node.value.s);
                            break;
                        case JSON_ARRAY:
                        case JSON_OBJECT:
                            break;
                    }

                    if( task->callback ) {
                        task->callback( task, &node );
                    }
                    
                    if( !task->callback ) {
                        switch( node.value_type ) {
                            case JSON_ARRAY:
                            case JSON_OBJECT:
                            case JSON_STRING:
                                append = json_append(append, node.key, node.key_len,
                                        node.value_type, node.value.p, node.value_len);
                                break;
                            default:
                                append = json_append(append, node.key, node.key_len,
                                        node.value_type, &node.value, node.value_len);
                        }
                    }
                }
                
                if( ch == ',' ) {
                    task->status = STS_OBJECT_START;
                } else if( ch == '}' ) {
                    return 0;
                } else {
                    task->err_msg = "expect ',' or '}'";
                    return -1;
                }
                break;
            default:
                task->err_msg = "unknown status";
                return -1;
        }
    }
    
    task->err_msg = "unexpect EOF";
    return -1;
}
Пример #6
0
int json_parse_array( json_task_t *task, json_object_t *parent ) {
    char ch;
    json_object_t node, * append = NULL;
    
    node.next = parent;
    node.key = NULL;
    node.key_len = 0;
    
    if( !task->callback ) {
        if( !task->root ) {
            append = task->root = json_create_array();
        } else {
            append = parent->value.p = json_create_array();
        }
    }
    
    task->status = STS_ARRAY_START;

    while(( ch = *(task->str + task->count) )) {
        task->count ++;
        
        if( ch == ' ' || ch == '\n' || ch == '\t' ) {
            continue;
        }
        
        switch( task->status ) {
            case STS_ARRAY_START:
                if( ch == ']' ) {
                    return 0;
                } else {
                    /* 这里需要将计数减一,因为 json_parse_value 需要根据这一个字符判断 value 类型 */
                    task->count --;

                    node.value.s = task->str + task->count;
                    if( json_parse_value( task, &node ) != 0 ) {
                        if( node.value_type == JSON_OBJECT ||
                            node.value_type == JSON_ARRAY ) {
                            json_delete_object(node.value.p);
                        }
                        return -1;
                    }
                    // WARNING: value_len 可能发生溢出
                    node.value_len = task->str + task->count - node.value.s;
                    
                    // 对 value 进行处理
                    switch(node.value_type) {
                        case JSON_STRING:
                            // 去除字符串两端的引号
                            node.value.s += 1;
                            node.value_len -= 2;
                            break;
                        case JSON_DOUBLE:
                            // TODO 在解析测试用例时,atof 与 atoll 使解析时间延长了几乎一半
                            // 移除对数值的默认解析可以显著提升性能
                            node.value.d = atof(node.value.s);
                            break;
                        case JSON_LONGLONG:
                            node.value.l = atoll(node.value.s);
                            break;
                        case JSON_ARRAY:
                        case JSON_OBJECT:
                            break;
                    }

                    // 需要放在 node.key_len ++ 之前以便正确输出数组下标
                    if( task->callback ) {
                        task->callback( task, &node );
                    }

                    if( !task->callback ) {
                        switch( node.value_type ) {
                            case JSON_ARRAY:
                            case JSON_OBJECT:
                            case JSON_STRING:
                                append = json_append(append, node.key, node.key_len,
                                        node.value_type, node.value.p, node.value_len);
                                break;
                            default:
                                append = json_append(append, node.key, node.key_len,
                                        node.value_type, &node.value, node.value_len);
                        }
                    }
                    
                    node.key_len ++;
                    task->status = STS_ARRAY_COMMA;
                }
                break;
            case STS_ARRAY_COMMA:
                if( ch == ',' ) {
                    task->status = STS_ARRAY_START;
                } else if( ch == ']' ) {
                    return 0;
                } else {
                    task->err_msg = "expect ',' or ']'";
                    return -1;
                }
                break;
            default:
                task->err_msg = "unknown status";
                return -1;
        }
    }

    task->err_msg = "unexpect EOF";
    return -1;
}