vsfjson -- 不到500行的MCU json库

参考:https://bbs.21ic.com/icview-2537088-1-1.html

源码:https://gitee.com/cksweb/vsf_open/blob/master/vsf/component/tool/json/vsfjson.c

 

注意点

1.注意加入anon_unions选项,否则联合体报错

2.因为构造json需要一个buf和存储方法,这里要自己选定一个buf,所以这里加一个静态buf和使用memcpy 

3.构造json时,buf指针是不会偏移的,注意自己处理下标的增加

4.构造完成后,使用后记得将buf清空,下标归0 

5.使用构造前,必须调用init ,将buf和存储方法导入到里面

 

我修改过的源码贴出来(STM32F030平台)

c文件

 

#include "json.h"

#include "config.h"

struct vsfjson_constructor_t json_c;
static uint16_t s_json_len = 0;
char json_s_buf[JSON_S_LEN];//注意JSON最大长度

static bool vsfjson_token_match(const char *json, const char *value)
{
    int n = strlen(value);
    return !strncmp(json, value, n) && !isalnum(json[n]);
}

enum vsfjson_type_t vsfjson_get_type(const char *json)
{
    enum vsfjson_type_t type = VSFJSON_TYPE_INVALID;
    char ch = *json;

    if (ch == '{')
        type = VSFJSON_TYPE_OBJECT;
    else if (ch == '[')
        type = VSFJSON_TYPE_ARRAY;
    else if (ch == '"')
        type = VSFJSON_TYPE_STRING;
    else if ((ch >= '0') && (ch <= '9'))
        type = VSFJSON_TYPE_NUMBER;
    else if (vsfjson_token_match(json, "true") || vsfjson_token_match(json, "false"))
        type = VSFJSON_TYPE_BOOLEAN;
    else if (vsfjson_token_match(json, "null"))
        type = VSFJSON_TYPE_NULL;
    return type;
}

static char *vsfjson_skip_space(const char *json)
{
    while ((*json != '\0') && isspace(*json)) json++;
    return *json == '\0' ? NULL : (char *)json;
}

enum vsfjson_type_t vsfjson_enumerate_start(
        struct vsfjson_enumerator_t *e, const char *json)
{
    enum vsfjson_type_t type = vsfjson_get_type(json);

    if ((type != VSFJSON_TYPE_OBJECT) && (type != VSFJSON_TYPE_ARRAY))
        type = VSFJSON_TYPE_INVALID;
    else
    {
        e->ptr = (char *)json;
        e->type = type;
        e->first = true;
        e->ptr = vsfjson_skip_space(++e->ptr);
        if (!e->ptr) type = VSFJSON_TYPE_INVALID;
    }
    return type;
}

char *vsfjson_enumerate_next(struct vsfjson_enumerator_t *e)
{
    char *cur = e->ptr;
    bool str = false;
    int brace_level = 0, square_level = 0;

    if (e->first)
    {
        e->first = false;
        if (*cur == ',') return NULL;
        goto exit;
    }
    else
    {
        while (*cur != '\0')
        {
            switch (*cur)
            {
            case '\"':
                str = !str;
                break;
            case '\\':
                if (!str) return NULL;
                cur++;
                break;
            case '{':
                if (!str)
                    brace_level++;
                break;
            case '[':
                if (!str)
                    square_level++;
                break;
            case ',':
                if (!str && !brace_level && !square_level)
                {
                    cur = vsfjson_skip_space(++cur);
                    goto exit;
                }
                break;
            case '}':
                if (!str)
                {
                    brace_level--;
                    if (brace_level < 0)
                        return NULL;
                    goto check;
                }
                break;
            case ']':
                if (!str)
                {
                    square_level--;
                    if (square_level < 0)
                        return NULL;
                check:
                    if (!brace_level && !square_level)
                    {
                        cur = vsfjson_skip_space(++cur);
                        if (*cur == ',')
                        {
                            cur = vsfjson_skip_space(++cur);
                            goto exit;
                        }
                        else
                        {
                            return NULL;
                        }
                    }
                }
                break;
            }
            cur++;
        }

    exit:
        if ((*cur == '}') || (*cur == ']'))
            return NULL;
    }
    e->ptr = cur;
    return cur;
}

static bool vsfjson_isdiv(char ch)
{
    return (ch == '/') || (ch == '\\');
}

int vsfjson_num_of_entry(const char *json)
{
    struct vsfjson_enumerator_t e;
    int num_of_entry = 0;

    if (vsfjson_enumerate_start(&e, json) != VSFJSON_TYPE_INVALID)
        while (vsfjson_enumerate_next(&e) != NULL)
            num_of_entry++;
    return num_of_entry;
}

char *vsfjson_get(const char *json, const char *key)
{
    struct vsfjson_enumerator_t e;
    unsigned long idx, curidx;
    char *cur;

    if (vsfjson_isdiv(*key))
        key++;

    while (*key != '\0')
    {
        if (VSFJSON_TYPE_INVALID == vsfjson_enumerate_start(&e, json))
            return NULL;

        if (e.type == VSFJSON_TYPE_ARRAY)
        {
            idx = strtoul(key, (char **)&key, 0);
            curidx = 0;
        }
        else
        {
            for (idx = 0; key[idx] && !vsfjson_isdiv(key[idx]); idx++);
        }

        while (1)
        {
            cur = vsfjson_enumerate_next(&e);
            if (!cur) return NULL;

            if (e.type == VSFJSON_TYPE_ARRAY)
            {
                if (curidx++ == idx)
                {
                    json = cur;
                    break;
                }
            }
            else
            {
                if (*cur++ != '\"') return NULL;
                if (!strncmp(key, cur, idx) && (cur[idx] == '\"'))
                {
                    key += idx;
                    if (*key)
                        key++;
                    cur += idx + 1;
                    cur = vsfjson_skip_space(cur);
                    if (*cur++ != ':') return NULL;

                    json = vsfjson_skip_space(cur);
                    break;
                }
            }
        }
    }
    return (char *)json;
}

int vsfjson_get_string(const char *json, char *result, int len)
{
    char ch;
    int curlen = 0;

    if (*json++ != '"')
        return -1;

    do {
        ch = *json++;
        if (ch == '\\')
        {
            ch = *json++;
            if (result && (curlen >= len))
                return VSFERR_NOT_ENOUGH_RESOURCES;
            switch (ch)
            {
            case '"':    if (result) result[curlen] = '\"';    curlen++;break;
            case '\\':    if (result) result[curlen] = '\\';    curlen++;break;
            case '/':    if (result) result[curlen] = '/';    curlen++;break;
            case 'b':    if (result) result[curlen] = '\b';    curlen++;break;
            case 'f':    if (result) result[curlen] = '\f';    curlen++;break;
            case 'n':    if (result) result[curlen] = '\n';    curlen++;break;
            case 'r':    if (result) result[curlen] = '\r';    curlen++;break;
            case 't':    if (result) result[curlen] = '\t';    curlen++;break;
            case 'u':
                // TODO:
                break;
            default:
                return -1;
            }
        }
        else if (ch != '\"')
        {
            if (result && (curlen >= len))
                return VSFERR_NOT_ENOUGH_RESOURCES;
            if (result)
                result[curlen] = ch;
            curlen++;
        }
    } while (ch != '\"');

    if (result && (curlen >= len))
        return VSFERR_NOT_ENOUGH_RESOURCES;
    if (result)
        result[curlen] = '\0';
    return ++curlen;
}

int vsfjson_get_number(const char *json, double *result)
{
    double value = strtod(json, NULL);
    if (result) *result = value;
    return sizeof(*result);
}

int vsfjson_get_boolean(const char *json, bool *result)
{
    bool value;
    if (vsfjson_token_match(json, "true"))
        value = true;
    else if (vsfjson_token_match(json, "false"))
        value = false;
    else return -1;
    if (result) *result = value;
    return sizeof(*result);
}

// constructor
void vsfjson_constructor_init(struct vsfjson_constructor_t *c, void *param,
        int (*write_str)(void *, char *, int))
{
    c->write_str = write_str;
    if (write_str != NULL)
        c->param = param;
    else
        c->len = 0;
    c->first = true;
    c->result = true;
}

int vsfjson_write_str(struct vsfjson_constructor_t *c, char *buf, int len)
{
    if (c->write_str != NULL)
    {
        int ret = c->write_str(c->param, buf, len);
        if (ret < 0) c->result = false;
        return ret;
    }
    else
    {
        c->len += len;
        return 0;
    }
}

static int vsfjson_set_token(struct vsfjson_constructor_t *c, char *token)
{
    int n = strlen(token);
    return vsfjson_write_str(c, token, n);
}

int vsfjson_set_key(struct vsfjson_constructor_t *c, char *key)
{
    int ret;

    if (c->first)
        c->first = false;
    else
    {
        ret = vsfjson_write_str(c, ",", 1);
        if (ret < 0) return ret;
    }

    if (key != NULL)
    {
        ret = vsfjson_write_str(c, "\"", 1);
        if (ret < 0) return ret;
        ret = vsfjson_set_token(c, key);
        if (ret < 0) return ret;
        ret = vsfjson_write_str(c, "\"", 1);
        if (ret < 0) return ret;

        ret = vsfjson_write_str(c, ":", 1);
        if (ret < 0) return ret;
    }
    return 0;
}

int vsfjson_set_string(struct vsfjson_constructor_t *c, char *key, char *value)
{
    int ret;
    char ch, buf[2];

    ret = vsfjson_set_key(c, key);
    if (ret < 0) return ret;
    ret = vsfjson_write_str(c, "\"", 1);
    if (ret < 0) return ret;

    do {
        ch = *value++;
        switch (ch)
        {
        case '\0':    break;
        case '\"':    buf[1] = '"';    goto set_esc;
        case '\\':    buf[1] = '\\';    goto set_esc;
        case '/':    buf[1] = '/';    goto set_esc;
        case '\b':    buf[1] = 'b';    goto set_esc;
        case '\f':    buf[1] = 'b';    goto set_esc;
        case '\n':    buf[1] = 'n';    goto set_esc;
        case '\r':    buf[1] = 'r';    goto set_esc;
        case '\t':    buf[1] = 't';
        set_esc:
            buf[0] = '\\';
            ret = vsfjson_write_str(c, buf, 2);
            if (ret < 0) return ret;
            break;
        default:
            buf[0] = ch;
            ret = vsfjson_write_str(c, buf, 1);
            if (ret < 0) return ret;
            break;
        }
    } while (ch != '\0');

    ret = vsfjson_write_str(c, "\"", 1);
    return (ret < 0) ? ret : 0;
}

int vsfjson_set_number(struct vsfjson_constructor_t *c, char *key, double value)
{
    int ret;
    char buf[64];

    ret = vsfjson_set_key(c, key);
    if (ret < 0) return ret;

    ret = snprintf(buf, sizeof(buf), "%f", value);
    ret = vsfjson_write_str(c, buf, ret);
    return (ret < 0) ? ret : 0;
}

int vsfjson_set_boolean(struct vsfjson_constructor_t *c, char *key, bool value)
{
    if (vsfjson_set_key(c, key) < 0)
        return -1;
    return vsfjson_set_token(c, value ? "true" : "false");
}

int vsfjson_set_null(struct vsfjson_constructor_t *c, char *key)
{
    if (vsfjson_set_key(c, key) < 0)
        return -1;
    return vsfjson_set_token(c, "null");
}


static int usrapp_json_write_str(void *param, char *ch, int len)
{
        #if 0
        struct vsf_transaction_buffer_t *buf = (struct vsf_transaction_buffer_t *)param;
        if (buf->buffer.buffer != NULL)
        {
                if ((buf->buffer.size - buf->position) >= len)
                {
                        memcpy(&buf->buffer.buffer[buf->position], ch, len);
                        buf->position += len;
                        return 0;
                }
        }
        return -1;
        #else
         if(s_json_len < JSON_S_LEN)
         {
             memcpy( (char *)param+s_json_len, ch, len);
             s_json_len += len;
             return 0;
         }
        return -1;
        #endif
}

void json_user_flush()
{
    s_json_len = 0;
    memset(json_s_buf,0,JSON_S_LEN);
}
void json_user_init()
{
    vsfjson_constructor_init(&json_c, json_s_buf, usrapp_json_write_str);
    json_user_flush();
}

void json_user_test()
{
        const char *json = "{\"obj\":{\"arr\":[0.01,\"1000\"],\"str\":\"abcd\"},\"uuid\":\"012376545672184\"}";
        double double_value;
        char buff[128];
        int len;


        char *result = vsfjson_get(json, "uuid");
        if (result != NULL)
        {
                len = vsfjson_get_string(result, NULL, 0);
                if (len < sizeof(buff))
                {
                        vsfjson_get_string(result, buff, len);
                        printf("len = %d data=%s\r\n",len,buff);
                }
        }
        result = vsfjson_get(json, "obj");
        if (result != NULL)
        {
                result = vsfjson_get(result, "str");
                if (result != NULL)
                {
                        len = vsfjson_get_string(result, NULL, 0);
                        if (len < sizeof(buff))
                        {
                                vsfjson_get_string(result, buff, len);
                                printf("len = %d data=%s\r\n",len,buff);
                        }
                }
        }
        result = vsfjson_get(json, "obj/arr/0");
        if (result != NULL)
        {
               len = vsfjson_get_number(result, &double_value);
                printf("len = %d data=%f\r\n",len,double_value);
            
        }
        result = vsfjson_get(json, "obj/arr/1");
        if (result != NULL)
        {
               // len = vsfjson_get_number(result, &double_value);
               // DBG("len = %d data=%f\r\n",len,double_value);
                len = vsfjson_get_string(result, NULL, 0);
                if (len < sizeof(buff))
                {
                        vsfjson_get_string(result, buff, len);
                        printf("len = %d data=%s\r\n",len,buff);
                }
            
        }
        
        
    json_user_init();
    vsfjson_set_object(&json_c, NULL,
    {
            vsfjson_set_number(&json_c, "key0", 1.0);
            vsfjson_set_boolean(&json_c, "key1", true);
            vsfjson_set_array(&json_c, "key2",
            {
                    vsfjson_set_string(&json_c, NULL, "123");
                    vsfjson_set_number(&json_c, NULL, 4.67);
            });
            vsfjson_set_null(&json_c, "key3");
    });
    printf("s_buf = %s\r\n",json_s_buf);
    json_user_flush();
    
    
    vsfjson_set_object(&json_c, NULL,
    {
            vsfjson_set_number(&json_c, "测试1", 1.0);
            vsfjson_set_boolean(&json_c, "测试2", true);
            vsfjson_set_array(&json_c, "key2",
            {
                    vsfjson_set_string(&json_c, NULL, "123");
                    vsfjson_set_number(&json_c, NULL, 1000);
                    vsfjson_set_number(&json_c, NULL, 4.67);
                    vsfjson_set_number(&json_c, NULL, 4.67);
                    vsfjson_set_string(&json_c, NULL, "cba");
            });
            
            vsfjson_set_null(&json_c, "key3");
    });
    printf("s_buf = %s\r\n",json_s_buf);
    json_user_flush();
}


///测试
#if 0
static uint8_t s_json_len = 0;
static int usrapp_json_write_str(void *param, char *ch, int len)
{
        #if 0
        struct vsf_transaction_buffer_t *buf = (struct vsf_transaction_buffer_t *)param;
        if (buf->buffer.buffer != NULL)
        {
                if ((buf->buffer.size - buf->position) >= len)
                {
                        memcpy(&buf->buffer.buffer[buf->position], ch, len);
                        buf->position += len;
                        return 0;
                }
        }
        return -1;
        #else
         memcpy( (char *)param+s_json_len, ch, len);
         s_json_len += len;
         return 0;
        #endif
}

char s_buf[128];
void usrapp_json_test(void)
{
        const char *json = "{\"obj\":{\"arr\":[0.01,\"1000\"],\"str\":\"abcd\"},\"uuid\":\"012376545672184\"}";
        double double_value;
        char buff[128];
        
        int len;
    
        struct vsfjson_constructor_t c;

        char *result = vsfjson_get(json, "uuid");
        if (result != NULL)
        {
                len = vsfjson_get_string(result, NULL, 0);
                if (len < sizeof(buff))
                {
                        vsfjson_get_string(result, buff, len);
                        DBG("len = %d data=%s\r\n",len,buff);
                }
        }
        result = vsfjson_get(json, "obj");
        if (result != NULL)
        {
                result = vsfjson_get(result, "str");
                if (result != NULL)
                {
                        len = vsfjson_get_string(result, NULL, 0);
                        if (len < sizeof(buff))
                        {
                                vsfjson_get_string(result, buff, len);
                                DBG("len = %d data=%s\r\n",len,buff);
                        }
                }
        }
        result = vsfjson_get(json, "obj/arr/0");
        if (result != NULL)
        {
               len = vsfjson_get_number(result, &double_value);
                DBG("len = %d data=%f\r\n",len,double_value);
            
        }
        result = vsfjson_get(json, "obj/arr/1");
        if (result != NULL)
        {
               // len = vsfjson_get_number(result, &double_value);
               // DBG("len = %d data=%f\r\n",len,double_value);
                len = vsfjson_get_string(result, NULL, 0);
                if (len < sizeof(buff))
                {
                        vsfjson_get_string(result, buff, len);
                        DBG("len = %d data=%s\r\n",len,buff);
                }
            
        }

/*        "{
                "key0":1.0,
                "key1":true,
                "key2":["123", 4.56],
                "key3":null
        }
*/  
            vsfjson_constructor_init(&c, s_buf, usrapp_json_write_str);
            vsfjson_set_object(&c, NULL,
            {
                    vsfjson_set_number(&c, "key0", 1.0);
                    vsfjson_set_boolean(&c, "key1", true);
                    vsfjson_set_array(&c, "key2",
                    {
                            vsfjson_set_string(&c, NULL, "123");
                            vsfjson_set_number(&c, NULL, 4.67);
                    });
                    vsfjson_set_null(&c, "key3");
            });
            s_json_len = 0;
            printf("s_buf = %s\r\n",s_buf);
        #if 0
        struct vsfjson_constructor_t c;
        struct vsf_transaction_buffer_t buf = { NULL, 0 };
        
        do
        {
                if (buf.buffer.size)
                {
                        if (buf.buffer.size < sizeof(buff))
                        {
                                buf.buffer.buffer = (uint8_t *)buff;
                                buf.position = 0;
                                vsfjson_constructor_init(&c, &buf, usrapp_json_write_str);
                        }
                        else
                                break;
                }
                else
                {
                        vsfjson_constructor_init(&c, NULL, NULL);
                }

                vsfjson_set_object(&c, NULL,
                {
                        vsfjson_set_number(&c, "key0", 1.0);
                        vsfjson_set_boolean(&c, "key1", true);
                        vsfjson_set_array(&c, "key2",
                        {
                                vsfjson_set_string(&c, NULL, "123");
                                vsfjson_set_number(&c, NULL, 4.67);
                        });
                        vsfjson_set_null(&c, "key3");
                });
                if (!c.write_str)
                        buf.buffer.size = c.len + 1;
                else
                        c.write_str(c.param, "\0", 1);
        } while (!buf.buffer.buffer);
        #endif
}
#endif

 

 

h文件

#ifndef __VSFJSON_H_INCLUDED__
#define __VSFJSON_H_INCLUDED__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <ctype.h>

#pragma anon_unions

#define JSON_S_LEN  512
extern struct vsfjson_constructor_t json_c;
extern char json_s_buf[JSON_S_LEN];

static uint16_t s_json_len ;

#define VSFERR_NOT_ENOUGH_RESOURCES -1
enum vsfjson_type_t
{
    VSFJSON_TYPE_INVALID,
    VSFJSON_TYPE_OBJECT,
    VSFJSON_TYPE_ARRAY,
    VSFJSON_TYPE_STRING,
    VSFJSON_TYPE_NUMBER,
    VSFJSON_TYPE_BOOLEAN,
    VSFJSON_TYPE_NULL,
};

struct vsfjson_enumerator_t
{
    char *ptr;
    enum vsfjson_type_t type;
    bool first;
};

struct vsfjson_constructor_t
{
    union
    {
        void *param;
        uint32_t len;
    };
    int (*write_str)(void *, char *, int);

    bool first;
    bool result;
};

enum vsfjson_type_t vsfjson_enumerate_start(struct vsfjson_enumerator_t *e,
        const char *json);
char *vsfjson_enumerate_next(struct vsfjson_enumerator_t *e);
char *vsfjson_get(const char *json, const char *key);
int vsfjson_num_of_entry(const char *json);

enum vsfjson_type_t vsfjson_get_type(const char *json);
int vsfjson_get_string(const char *json, char *result, int len);
int vsfjson_get_number(const char *json, double *result);
int vsfjson_get_boolean(const char *json, bool *result);

void vsfjson_constructor_init(struct vsfjson_constructor_t *c, void *param,
        int (*write_str)(void *, char *, int));

int vsfjson_write_str(struct vsfjson_constructor_t *c, char *buf, int len);
int vsfjson_set_key(struct vsfjson_constructor_t *c, char *key);
#define vsfjson_set_object(c, key, member)    \
do {\
    int len = vsfjson_set_key((c), (key));\
    if (len < 0) break;\
    (c)->first = true;\
    len = vsfjson_write_str((c), "{", 1);\
    if (len < 0) break;\
    member\
    len = vsfjson_write_str((c), "}", 1);\
    if (len < 0) break;\
} while (0)


#define vsfjson_set_array(c, key, member)    \
do {\
    int len = vsfjson_set_key((c), (key));\
    if (len < 0) break;\
    (c)->first = true;\
    len = vsfjson_write_str((c), "[", 1);\
    if (len < 0) break;\
    member\
    len = vsfjson_write_str((c), "]", 1);\
    if (len < 0) break;\
} while (0)

int vsfjson_set_string(struct vsfjson_constructor_t *c, char *key, char *value);
int vsfjson_set_number(struct vsfjson_constructor_t *c, char *key, double value);
int vsfjson_set_boolean(struct vsfjson_constructor_t *c, char *key, bool value);
int vsfjson_set_null(struct vsfjson_constructor_t *c, char *key);
void json_user_init(void);
void json_user_flush(void);
void json_user_test(void);



#endif    // __VSFJSON_H_INCLUDED__

 

posted @ 2020-11-25 10:04  XZHDJH  阅读(335)  评论(0)    收藏  举报