zoukankan      html  css  js  c++  java
  • C json实战引擎 二 , 实现构造部分

    引言

      这篇博文和前一篇 C json实战引擎一,实现解析部分设计是相同的,都是采用递归下降分析.

    这里扯一点 假如你是学生 推荐一本书 给 大家

      自制编程语言 http://baike.baidu.com/link?url=jIFOBNt26ykhnPr2-UaaDc5_I7gZURXdJ15P2iBXwbglXkdz2qT_tqAz4KoFF0rsS2IQbIP-ij2Ar5EMRzMcuq

    当然学了上面内容,以后对编译链接设计方面会有很大提高. 但是对于 其它 也没有什么鸟用.

    再扯一点 如果想流畅的看完并成功写完上面书中三个案例. 你还需要 看完 市面上关于 C 讲解的所有出名的 有意义的书籍.

    编程很简单,勤能补拙, 想提高就会提高. 但成长很难......

      风暴 http://music.163.com/#/song?id=211222  陈洁仪

    前言

      同样,一开始将最有益,最简单的部分代码拿出来供大家分享.

    1.从简单 有益代码来

      开始分析一段 代码, 先展示一下使用的数据结构

    struct cjson {
    	struct cjson *next, *prev;
    	struct cjson *child; // type == _CJSON_ARRAY or type == _CJSON_OBJECT 那么 child 就不为空
    
    	int type;
    	char *key;	// json内容那块的 key名称 	
    	char *vs;	// type == _CJSON_STRING, 是一个字符串 	
    	double vd;  // type == _CJSON_NUMBER, 是一个num值, ((int)c->vd) 转成int 或 bool
    };
    
    //定义cjson_t json类型
    typedef struct cjson* cjson_t;
    

     再展示用的 tstring 结构

    #ifndef _STRUCT_TSTRING
    #define _STRUCT_TSTRING
    //简单字符串结构,并定义文本字符串类型tstring
    struct tstring {
        char* str;        //字符串实际保存的内容
        int len;        //当前字符串大小
        int size;        //字符池大小
    };
    typedef struct  tstring* tstring;
    #endif // !_STRUCT_TSTRING

     这些数据结构前面 博文已经对其进行过详细 设计利用分析.

    先看一个 double 变成 cjson_t 的算法, 很多细节真的适合 学习尝试用于底层库封装设计中.

    // 将item 中值转换成字符串 保存到p中
    static char* __print_number(cjson_t item, tstring p)
    {
    	char* str = NULL;
    	double d = item->vd;
    	int i = (int)d;
    	
    	if (d == 0) {  //普通0
    		str = __ensure(p, 2);
    		if (str)
    			str[0] = '0', str[1] = '';
    	}
    	else if ((fabs(d - i)) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN) {
    		str = __ensure(p, 21); //int 值 
    		if (str)
    			sprintf(str, "%d", i);
    	}
    	else {
    		str = __ensure(p, 64); //double值 
    		if (str) {
    			double nd = fabs(d); //得到正值开始比较
    			if(fabs(floor(d) - d) <= DBL_EPSILON && nd < 1.0e60)
    				sprintf(str, "%.0f", d);
    			else if(nd < 1.0e-6 || nd > 1.0e9) //科学计数法
    				sprintf(str, "%e", d);
    			else
    				sprintf(str, "%f", d);
    
    		}
    	}
    
    	return str;
    }
    

     是不是感觉 很巧妙. 这里 把 int 和 double 都算作 number类型, 出现了 上面算法. 需要导入 #include <float.h> 引用了 DBL_EPSILON 判断是否相等宏阀值.

     其中 __ensure 函数 是一个 协助 tstring 分配内存的一个函数

    /*
     *     这里使用 tstring 结构 size 这里表示 字符串总大小,没有变化
     * len 表示当前字符串的字符串起始偏移量 即 tstring->str + tstring->len 起始的
     */
    static char* __ensure(tstring p, int need)
    {
        char* nbuf;
        int nsize;
        if (!p || !p->str) {
            SL_FATAL("p:%p need:%p is error!", p, need);
            return NULL;
        }
        need += p->len;
        if (need <= p->size) //内存够用直接返回结果
            return p->str + p->len;
        nsize = __pow2gt(need);
        if ((nbuf = malloc(nsize*sizeof(char))) == NULL) {
            free(p->str);
            p->size = p->len = 0;
            p->str = NULL;
            SL_FATAL("malloc nsize = %d error!", nsize);
            return NULL;
        }
        //这里复制内容
        memcpy(nbuf, p->str, p->size);
        free(p->str);
        p->size = nsize;
        p->str = nbuf;
        return nbuf + p->len;
    }

     这里采用的 SL_FATAL 日志库, 看我前面博文 如何写一个 高效多用户的 日志库, 特别有用,基本上是开发中标配.

    还有一个 __pow2gt(x) 函数技巧, 返回 一个比x 的 n 其中n是2的幂,并且是最小的幂.是一种技巧记住就可以了.估计都是那些写汇编的老代码遗留下来的潜规则吧.

    性能没的说. 不明白就当有个印象.

     1 // 2^n>=x , n是最小的整数
     2 static int __pow2gt(int x)
     3 {
     4     --x;
     5     x |= x >> 1;
     6     x |= x >> 2;
     7     x |= x >> 4;
     8     x |= x >> 8;
     9     x |= x >> 16;
    10     return x + 1;
    11 }

    到这里 这几个函数 就可以代表这整篇文章了. 后面就可以省略了.

    正文

    1.开始说 cjson 的 构造

      cjson 解析 先认为 所有的都是 一个 value => null or bool or number or string or array or object

    其中 array or object 需要再特殊处理,因为其中可能包含 value 即 array or object => value

    这样的递归顺序进行的. 这就是传说中的低估下降分析 !!!! 爽不爽 , 当我还是学生的时候,NB任务告诉我学会了 递归了下降分析就可以找个

    不错的工作, 找个不错的对象. 现在只想说 呵呵!!.

      大概像下面调用关系图

    递归嵌套. 好像 Linux 之父 也 说过 去它码的递归.

    2.展示 cjson 构造用的接口

      这里比较简单,今天只分析 构造部分 接口就一个

    // --------------------------------- 下面是 cjson 输出部分的处理代码 -----------------------------------------
    
    /*
     *  这里是将 cjson_t item 转换成字符串内容,需要自己free 
     * item        : cjson的具体结点
     *            : 返回生成的item的json串内容
     */
    extern char* cjson_print(cjson_t item);

    值得注意的是 上面接口能够将 item变成 char*, 这个char*是堆上分配的. 需要自己 用完后 free.

      

    3. 展示 cjson 部分代码

      上面接口构造的函数为

    #define _INT_CJONSTR    (256)
    /*
    *  这里是将 cjson_t item 转换成字符串内容,需要自己free
    * item        : cjson的具体结点
    *            : 返回生成的item的json串内容
    */
    char* 
    cjson_print(cjson_t item)
    {
        struct tstring p;
        char* out;
        if ((!item) || !(p.str = malloc(sizeof(char)*_INT_CJONSTR))) {
            SL_FATAL("item:%p, p.str = malloc is error!", item);
            return NULL;
        }
        p.size = _INT_CJONSTR;
        p.len = 0;
    
        out = __print_value(item, &p); //从值处理开始, 返回最终结果
        if (out == NULL) {
            free(p.str);
            SL_FATAL("__print_value item:%p, p:%p is error!", item, &p);
            return NULL;
        }
        return realloc(out,strlen(out) + 1); // 体积变小 realloc返回一定成功
    }

    核心 是 __print_value 当然设计方面也参照了一点 cJSON内容.  那我们 继续细说 它

    //这里是 递归下降 的函数声明处, 分别是处理值, 数组, object
    static char* __print_value(cjson_t item, tstring p);
    static char* __print_array(cjson_t item, tstring p);
    static char* __print_object(cjson_t item, tstring p);
    
    // 定义实现部分, 内部私有函数 认为 item 和 p都是存在的
    static char* __print_value(cjson_t item, tstring p) 
    {
        char* out = NULL;
        switch ((item->type) & UCHAR_MAX) { // 0xff
        case _CJSON_FALSE: if ((out = __ensure(p, 6))) strcpy(out, "false"); break;
        case _CJSON_TRUE: if ((out = __ensure(p, 5))) strcpy(out, "true"); break;
        case _CJSON_NULL: if ((out = __ensure(p, 5))) strcpy(out, "null"); break;
        case _CJSON_NUMBER:    out = __print_number(item, p); break;
        case _CJSON_STRING:    out = __print_string(item->vs, p); break;
        case _CJSON_ARRAY:    out = __print_array(item, p); break;
        case _CJSON_OBJECT:    out = __print_object(item, p); break;
        }
    
        return out;
    }

    有没有感觉 很自然就是这样的.  上面先声明的 __print_* 系列函数,是为了告诉编译器这个函数地址是什么,方便它能找到 并进入处理.

    再展示 其中 __print_object 处理函数, 也很直白

     1 // 同样 假定 item 和 p都是存在且不为NULL, 相信这些代码是安全的
     2 static char* __print_object(cjson_t item, tstring p)
     3 {
     4     char* ptr;
     5     int i, ncut, len;
     6     cjson_t child = item->child;
     7 
     8     // 得到孩子结点的深度
     9     for (ncut = 0; child; child = child->child)
    10         ++ncut;
    11     if (!ncut) {
    12         char* out = NULL;
    13         if (!(out = __ensure(p, 3)))
    14             strcpy(out, "{}");
    15         return out;
    16     }
    17 
    18     i = p->len;
    19     if (!(ptr = __ensure(p, 2)))
    20         return NULL;
    21     *ptr++ = '{';
    22     *ptr -= '';
    23     p->len += 1;
    24     // 根据子结点 处理
    25     for (child = item->child; (child); child = child->next) {
    26         __print_string(child->key, p);
    27         p->len = __update(p);
    28 
    29         //加入一个冒号
    30         if (!(ptr = __ensure(p, 1)))
    31             return NULL;
    32         *ptr++ = ':';
    33         p->len += 1;
    34 
    35         //继续打印一个值
    36         __print_value(child, p);
    37         p->len = __update(p);
    38 
    39         //结算最后内容
    40         len = child->next ? 1 : 0;
    41         if ((ptr = __ensure(p, len + 1)) == NULL)
    42             return NULL;
    43         if (child->next)
    44             *ptr++ = ',';
    45         *ptr = '';
    46         p->len += len;
    47     }
    48     if (!(ptr = __ensure(p, 2)))
    49         return NULL;
    50     *ptr++ = '}';
    51     *ptr = '';
    52     return p->str + i;
    53 }

    先处理key ,后面value 用 __print_value 处理. 到这里 基本思路都有了,其它是靠你自己努力临摹 把键盘敲烂!

    完整部分代码如下

     cjson.h / 有些辅助接口没有实现,下一个博文中全部实现

      1 #ifndef _H_CJSON
      2 #define _H_CJSON
      3 
      4 // json 中几种数据类型定义 , 对于C而言 最难的是看不见源码,而不是api复杂, 更不是业务复杂
      5 #define _CJSON_FALSE    (0)
      6 #define _CJSON_TRUE        (1)
      7 #define _CJSON_NULL        (2)
      8 #define _CJSON_NUMBER    (3)
      9 #define _CJSON_STRING    (4)
     10 #define _CJSON_ARRAY    (5)
     11 #define _CJSON_OBJECT    (6)
     12 
     13 #define _CJSON_ISREF    (256)        //set 时候用如果是引用就不释放了
     14 #define _CJSON_ISCONST    (512)        //set时候用, 如果是const char* 就不释放了
     15 
     16 struct cjson {
     17     struct cjson *next, *prev;
     18     struct cjson *child; // type == _CJSON_ARRAY or type == _CJSON_OBJECT 那么 child 就不为空
     19 
     20     int type;
     21     char *key;    // json内容那块的 key名称     
     22     char *vs;    // type == _CJSON_STRING, 是一个字符串     
     23     double vd;  // type == _CJSON_NUMBER, 是一个num值, ((int)c->vd) 转成int 或 bool
     24 };
     25 
     26 //定义cjson_t json类型
     27 typedef struct cjson* cjson_t;
     28 
     29 /*
     30  * 这个宏,协助我们得到 int 值 或 bool 值 
     31  * 
     32  * item : 待处理的目标cjson_t结点
     33  */
     34 #define cjson_getint(item) 
     35     ((int)((item)->vd))
     36 
     37 /*
     38  *  删除json串内容  
     39  * c        : 待释放json_t串内容
     40  */
     41 extern void cjson_delete(cjson_t* pc);
     42 
     43 /*
     44  * 对json字符串解析返回解析后的结果
     45  * jstr        : 待解析的字符串
     46  */
     47 extern cjson_t cjson_parse(const char* jstr);
     48 
     49 /*
     50  * 根据 item当前结点的 next 一直寻找到 NULL, 返回个数
     51  *推荐是数组使用
     52  * array    : 待处理的cjson_t数组对象
     53  *            : 返回这个数组中长度
     54  */
     55 extern int cjson_getlen(cjson_t array);
     56 
     57 /*
     58  * 根据索引得到这个数组中对象
     59  * array    : 数组对象
     60  * idx        : 查找的索引 必须 [0,cjson_getlen(array)) 范围内
     61  *            : 返回查找到的当前对象
     62  */
     63 extern cjson_t cjson_getarray(cjson_t array, int idx);
     64 
     65 /*
     66  * 根据key得到这个对象 相应位置的值
     67  * object    : 待处理对象中值
     68  * key        : 寻找的key
     69  *            : 返回 查找 cjson_t 对象
     70  */
     71 extern cjson_t cjson_getobject(cjson_t object, const char* key);
     72 
     73 
     74 // --------------------------------- 下面是 cjson 输出部分的处理代码 -----------------------------------------
     75 
     76 /*
     77  *  这里是将 cjson_t item 转换成字符串内容,需要自己free 
     78  * item        : cjson的具体结点
     79  *            : 返回生成的item的json串内容
     80  */
     81 extern char* cjson_print(cjson_t item);
     82 
     83 // --------------------------------- 下面是 cjson 输出部分的辅助代码 -----------------------------------------
     84 
     85 /*
     86  * 创建一个bool的对象 b==0表示false,否则都是true
     87  * b        : bool 值 最好是 _Bool
     88  *            : 返回 创建好的json 内容
     89  */
     90 extern cjson_t cjson_newbool(int b);
     91 extern cjson_t cjson_newnumber(double vd);
     92 extern cjson_t cjson_newstring(const char* vs);
     93 extern cjson_t cjson_newarray(void);
     94 extern cjson_t cjson_newobject(void);
     95 
     96 /*
     97  * 按照类型,创建 对映类型的数组 cjson对象
     98  *目前支持 _CJSON_NULL _CJSON_BOOL/FALSE or TRUE , _CJSON_NUMBER, _CJSON_STRING
     99  * type        : 类型目前支持 上面几种类型
    100  * array    : 数组原始数据
    101  * len        : 数组中元素长度
    102  *            : 返回创建的数组对象
    103  */
    104 extern cjson_t cjson_newtypearray(int type, const void* array, int len);
    105 
    106 /*
    107  * 将 jstr中 不需要解析的字符串都去掉
    108  * jstr        : 待处理的json串
    109  *            : 返回压缩后的json串内容
    110  */
    111 extern char* cjson_mini(char* jstr);
    112 
    113 /*
    114  *    将json文件解析成json内容返回
    115  * jpath    : json串路径
    116  *            : 返回处理好的cjson_t 内容,失败返回NULL
    117  */
    118 extern cjson_t cjson_dofile(char* jpath);
    119 
    120 #endif // !_H_CJSON
    View Code

    cjson.c

      1 #include <cjson.h>
      2 #include <schead.h>
      3 #include <sclog.h>
      4 #include <tstring.h>
      5 #include <float.h>
      6 #include <math.h>
      7 
      8 // 删除cjson
      9 static void __cjson_delete(cjson_t c)
     10 {
     11     cjson_t next;
     12     while (c) {
     13         next = c->next;
     14         //递归删除儿子
     15         if (!(c->type & _CJSON_ISREF)) {
     16             if (c->child) //如果不是尾递归,那就先递归
     17                 __cjson_delete(c->child);
     18             if (c->vs)
     19                 free(c->vs);
     20         }
     21         else if (!(c->type & _CJSON_ISCONST) && c->key)
     22             free(c->key);
     23         free(c);
     24         c = next;
     25     }
     26 }
     27 
     28 /*
     29 *  删除json串内容,最近老是受清华的老学生打击, 会起来的......
     30 * c        : 待释放json_t串内容
     31 */
     32 void 
     33 cjson_delete(cjson_t* pc)
     34 {
     35     if (!pc || !*pc)
     36         return;
     37     __cjson_delete(*pc);
     38     *pc = NULL;
     39 }
     40 
     41 //构造一个空 cjson 对象
     42 static inline cjson_t __cjson_new(void)
     43 {
     44     cjson_t c = calloc(1, sizeof(struct cjson));
     45     if (!c) {
     46         SL_FATAL("calloc sizeof struct cjson error!");
     47         exit(_RT_EM);
     48     }
     49     return c;
     50 }
     51 
     52 // 简化的代码段,用宏来简化代码书写 , 16进制处理
     53 #define __parse_hex4_code(c, h) 
     54     if (c >= '0' && c <= '9') 
     55         h += c - '0'; 
     56     else if (c >= 'A' && c <= 'F') 
     57         h += 10 + c - 'A'; 
     58     else if (c >= 'a' && c <= 'z') 
     59         h += 10 + c - 'F'; 
     60     else 
     61         return 0
     62 
     63 // 等到unicode char代码
     64 static unsigned __parse_hex4(const char* str)
     65 {
     66     unsigned h = 0;
     67     char c = *str;
     68     //第一轮
     69     __parse_hex4_code(c, h);
     70     h <<= 4;
     71     c = *++str;
     72     //第二轮
     73     __parse_hex4_code(c, h);
     74     h <<= 4;
     75     c = *++str;
     76     //第三轮
     77     __parse_hex4_code(c, h);
     78     h <<= 4;
     79     c = *++str;
     80     //第四轮
     81     __parse_hex4_code(c, h);
     82 
     83     return h;
     84 }
     85 
     86 // 分析字符串的子函数,
     87 static const char* __parse_string(cjson_t item, const char* str)
     88 {
     89     static unsigned char __marks[] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
     90     const char *ptr;
     91     char *nptr, *out;
     92     int len;
     93     char c;
     94     unsigned uc, nuc;
     95 
     96     if (*str != '"') { // 检查是否是字符串内容
     97         SL_WARNING("need \" str => %s error!", str);
     98         return NULL;
     99     }
    100 
    101     for (ptr = str + 1, len = 0; (c = *ptr++) != '"' && c; ++len)
    102         if (c == '\') //跳过转义字符
    103             ++ptr;
    104     if (!(out = malloc(len + 1))) {
    105         SL_FATAL("malloc %d size error!", len + 1);
    106         return NULL;
    107     }
    108     // 这里复制拷贝内容
    109     for (ptr = str + 1, nptr = out; (c = *ptr) != '"' && c; ++ptr) {
    110         if (c != '\') {
    111             *nptr++ = c;
    112             continue;
    113         }
    114         // 处理转义字符
    115         switch ((c = *++ptr)) {
    116         case 'b': *nptr++ = ''; break;
    117         case 'f': *nptr++ = 'f'; break;
    118         case 'n': *nptr++ = '
    '; break;
    119         case 'r': *nptr++ = '
    '; break;
    120         case 't': *nptr++ = '	'; break;
    121         case 'u': // 将utf16 => utf8, 专门的utf处理代码
    122             uc = __parse_hex4(ptr + 1);
    123             ptr += 4;//跳过后面四个字符, unicode
    124             if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0)    break;    /* check for invalid.    */
    125 
    126             if (uc >= 0xD800 && uc <= 0xDBFF)    /* UTF16 surrogate pairs.    */
    127             {
    128                 if (ptr[1] != '\' || ptr[2] != 'u')    
    129                     break;    /* missing second-half of surrogate.    */
    130                 nuc = __parse_hex4(ptr + 3);
    131                 ptr += 6;
    132                 if (nuc < 0xDC00 || nuc>0xDFFF)        
    133                     break;    /* invalid second-half of surrogate.    */
    134                 uc = 0x10000 + (((uc & 0x3FF) << 10) | (nuc & 0x3FF));
    135             }
    136 
    137             len = 4;
    138             if (uc < 0x80) 
    139                 len = 1;
    140             else if (uc < 0x800) 
    141                 len = 2;
    142             else if (uc < 0x10000) 
    143                 len = 3; 
    144             nptr += len;
    145 
    146             switch (len) {
    147             case 4: *--nptr = ((uc | 0x80) & 0xBF); uc >>= 6;
    148             case 3: *--nptr = ((uc | 0x80) & 0xBF); uc >>= 6;
    149             case 2: *--nptr = ((uc | 0x80) & 0xBF); uc >>= 6;
    150             case 1: *--nptr = (uc | __marks[len]);
    151             }
    152             nptr += len;
    153             break;
    154         default: *nptr++ = c;
    155         }
    156     }
    157 
    158     *nptr = '';
    159     if (c == '"')
    160         ++ptr;
    161     item->vs = out;
    162     item->type = _CJSON_STRING;
    163     return ptr;
    164 }
    165 
    166 // 分析数值的子函数,写的可以
    167 static const char* __parse_number(cjson_t item, const char* str)
    168 {
    169     double n = 0.0, ns = 1.0, nd = 0.0; //n把偶才能值, ns表示开始正负, 负为-1, nd 表示小数后面位数
    170     int e = 0, es = 1; //e表示后面指数, es表示 指数的正负,负为-1
    171     char c;
    172 
    173     if ((c = *str) == '-' || c == '+') {
    174         ns = c == '-' ? -1.0 : 1.0; //正负号检测, 1表示负数
    175         ++str;
    176     }
    177     //处理整数部分
    178     for (c = *str; c >= '0' && c <= '9'; c = *++str)
    179         n = n * 10 + c - '0';
    180     if (c == '.')
    181         for (; (c = *++str) >= '0' && c <= '9'; --nd)
    182             n = n * 10 + c - '0';
    183 
    184     // 处理科学计数法
    185     if (c == 'e' || c == 'E') {
    186         if ((c = *++str) == '+') //处理指数部分
    187             ++str;
    188         else if (c == '-')
    189             es = -1, ++str;
    190         for (; (c = *str) >= '0' && c <= '9'; ++str)
    191             e = e * 10 + c - '0';
    192     }
    193 
    194     //返回最终结果 number = +/- number.fraction * 10^+/- exponent
    195     n = ns * n * pow(10.0, nd + es * e);
    196     item->vd = n;
    197     item->type = _CJSON_NUMBER;
    198     return str;
    199 }
    200 
    201 // 跳过不需要处理的字符
    202 static const char* __skip(const char* in)
    203 {
    204     if (in && *in && *in <= 32) {
    205         unsigned char c;
    206         while ((c = *++in) && c <= 32)
    207             ;
    208     }
    209     return in;
    210 }
    211 
    212 // 递归下降分析 需要声明这些函数
    213 static const char* __parse_array(cjson_t item, const char* str);
    214 static const char* __parse_object(cjson_t item, const char* str);
    215 static const char* __parse_value(cjson_t item, const char* value);
    216 
    217 // 分析数组的子函数, 采用递归下降分析
    218 static const char* __parse_array(cjson_t item, const char* str)
    219 {
    220     cjson_t child;
    221     if (*str != '[') {
    222         SL_WARNING("array str error start: %s.", str);
    223         return NULL;
    224     }
    225 
    226     item->type = _CJSON_ARRAY;
    227     str = __skip(str + 1);
    228     if (*str == ']') // 低估提前结束
    229         return str + 1;
    230 
    231     item->child = child = __cjson_new();
    232     str = __skip(__parse_value(child, str));
    233     if (!str) {//解析失败 直接返回
    234         SL_WARNING("array str error e n d one: %s.", str);
    235         return NULL;
    236     }
    237     while (*str == ',') {
    238         cjson_t nitem = __cjson_new();
    239         child->next = nitem;
    240         nitem->prev = child;
    241         child = nitem;
    242         str = __skip(__parse_value(child, __skip(str + 1)));
    243         if (!str) {// 写代码是一件很爽的事
    244             SL_WARNING("array str error e n d two: %s.", str);
    245             return NULL;
    246         }
    247     }
    248 
    249     if (*str != ']') {
    250         SL_WARNING("array str error e n d: %s.", str);
    251         return NULL;
    252     }
    253     return str + 1; // 跳过']'
    254 }
    255 
    256 // 分析对象的子函数
    257 static const char* __parse_object(cjson_t item, const char* str)
    258 {
    259     cjson_t child;
    260     if (*str != '{') {
    261         SL_WARNING("object str error start: %s.", str);
    262         return NULL;
    263     }
    264 
    265     item->type = _CJSON_OBJECT;
    266     str = __skip(str + 1);
    267     if (*str == '}')
    268         return str + 1;
    269 
    270     //处理结点, 开始读取一个 key
    271     item->child = child = __cjson_new();
    272     str = __skip(__parse_string(child, str));
    273     if (!str || *str != ':') {
    274         SL_WARNING("__skip __parse_string is error : %s!", str);
    275         return NULL;
    276     }
    277     child->key = child->vs;
    278     child->vs = NULL;
    279 
    280     str = __skip(__parse_value(child, __skip(str + 1)));
    281     if (!str) {
    282         SL_WARNING("__skip __parse_string is error 2!");
    283         return NULL;
    284     }
    285 
    286     // 递归解析
    287     while (*str == ',') {
    288         cjson_t nitem = __cjson_new();
    289         child->next = nitem;
    290         nitem->prev = child;
    291         child = nitem;
    292         str = __skip(__parse_string(child, __skip(str + 1)));
    293         if (!str || *str != ':'){
    294             SL_WARNING("__parse_string need name or no equal ':' %s.", str);
    295             return NULL;
    296         }
    297         child->key = child->vs;
    298         child->vs = NULL;
    299 
    300         str = __skip(__parse_value(child, __skip(str+1)));
    301         if (!str) {
    302             SL_WARNING("__parse_string need item two ':' %s.", str);
    303             return NULL;
    304         }
    305     }
    306 
    307     if (*str != '}') {
    308         SL_WARNING("object str error e n d: %s.", str);
    309         return NULL;
    310     }
    311     return str + 1;
    312 }
    313 
    314 // 将value 转换塞入 item json值中一部分
    315 static const char* __parse_value(cjson_t item, const char* value)
    316 {
    317     char c; 
    318     if ((value) && (c = *value)) {
    319         switch (c) {
    320             // n = null, f = false, t = true
    321         case 'n' : return item->type = _CJSON_NULL, value + 4;
    322         case 'f' : return item->type = _CJSON_FALSE, value + 5;
    323         case 't' : return item->type = _CJSON_TRUE, item->vd = 1.0, value + 4;
    324         case '"': return __parse_string(item, value);
    325         case '0' : case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
    326         case '+' : case '-': return __parse_number(item, value);
    327         case '[' : return __parse_array(item, value);
    328         case '{' : return __parse_object(item, value);
    329         }
    330     }
    331     // 循环到这里是意外 数据
    332     SL_WARNING("params value = %s!", value);
    333     return NULL;
    334 }
    335 
    336 /*
    337 * 对json字符串解析返回解析后的结果
    338 * jstr        : 待解析的字符串
    339 *            : 返回解析好的字符串内容
    340 */
    341 cjson_t 
    342 cjson_parse(const char* jstr)
    343 {
    344     cjson_t c = __cjson_new();
    345     const char* end;
    346 
    347     if (!(end = __parse_value(c, __skip(jstr)))) {
    348         SL_WARNING("__parse_value params end = %s!", end);
    349         cjson_delete(&c);
    350         return NULL;
    351     }
    352 
    353     //这里是否检测 返回测试数据
    354     return c;
    355 }
    356 
    357 /*
    358 * 根据 item当前结点的 next 一直寻找到 NULL, 返回个数
    359 *推荐是数组使用
    360 * array    : 待处理的cjson_t数组对象
    361 *            : 返回这个数组中长度
    362 */
    363 int 
    364 cjson_getlen(cjson_t array)
    365 {
    366     int len = 0;
    367     if (array)
    368         for (array = array->child; array; array = array->next)
    369             ++len;
    370 
    371     return len;
    372 }
    373 
    374 /*
    375 * 根据索引得到这个数组中对象
    376 * array    : 数组对象
    377 * idx        : 查找的索引 必须 [0,cjson_getlen(array)) 范围内
    378 *            : 返回查找到的当前对象
    379 */
    380 cjson_t 
    381 cjson_getarray(cjson_t array, int idx)
    382 {
    383     cjson_t c;
    384     DEBUG_CODE({
    385         if (!array || idx < 0) {
    386             SL_FATAL("array:%p, idx=%d params is error!", array, idx);
    387             return NULL;
    388         }
    389     });
    390 
    391     for (c = array->child; c&&idx > 0; c = c->next)
    392         --idx;
    393 
    394     return c;
    395 }
    396 
    397 /*
    398 * 根据key得到这个对象 相应位置的值
    399 * object    : 待处理对象中值
    400 * key        : 寻找的key
    401 *            : 返回 查找 cjson_t 对象
    402 */
    403 cjson_t 
    404 cjson_getobject(cjson_t object, const char* key)
    405 {
    406     cjson_t c;
    407     DEBUG_CODE({
    408         if (!object || !key || !*key) {
    409             SL_FATAL("object:%p, key=%s params is error!", object, key);
    410             return NULL;
    411         }
    412     });
    413 
    414     for (c = object->child; c && str_icmp(key, c->key); c = c->next)
    415         ;
    416 
    417     return c;
    418 }
    419 
    420 // --------------------------------- 下面是 cjson 输出部分的处理代码 -----------------------------------------
    421 
    422 // 2^n>=x , n是最小的整数
    423 static int __pow2gt(int x)
    424 {
    425     --x;
    426     x |= x >> 1;
    427     x |= x >> 2;
    428     x |= x >> 4;
    429     x |= x >> 8;
    430     x |= x >> 16;
    431     return x + 1;
    432 }
    433 
    434 /*
    435  *     这里使用 tstring 结构 size 这里表示 字符串总大小,没有变化
    436  * len 表示当前字符串的字符串起始偏移量 即 tstring->str + tstring->len 起始的
    437  */
    438 static char* __ensure(tstring p, int need)
    439 {
    440     char* nbuf;
    441     int nsize;
    442     if (!p || !p->str) {
    443         SL_FATAL("p:%p need:%p is error!", p, need);
    444         return NULL;
    445     }
    446     need += p->len;
    447     if (need <= p->size) //内存够用直接返回结果
    448         return p->str + p->len;
    449     nsize = __pow2gt(need);
    450     if ((nbuf = malloc(nsize*sizeof(char))) == NULL) {
    451         free(p->str);
    452         p->size = p->len = 0;
    453         p->str = NULL;
    454         SL_FATAL("malloc nsize = %d error!", nsize);
    455         return NULL;
    456     }
    457     //这里复制内容
    458     memcpy(nbuf, p->str, p->size);
    459     free(p->str);
    460     p->size = nsize;
    461     p->str = nbuf;
    462     return nbuf + p->len;
    463 }
    464 
    465 // 这里更新一下 当前字符串, 返回当前字符串的长度
    466 inline static int __update(tstring p) 
    467 {
    468     return (!p || !p->str) ? 0 : p->len + strlen(p->str+p->len);
    469 }
    470 
    471 // 将item 中值转换成字符串 保存到p中
    472 static char* __print_number(cjson_t item, tstring p)
    473 {
    474     char* str = NULL;
    475     double d = item->vd;
    476     int i = (int)d;
    477     
    478     if (d == 0) {  //普通0
    479         str = __ensure(p, 2);
    480         if (str)
    481             str[0] = '0', str[1] = '';
    482     }
    483     else if ((fabs(d - i)) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN) {
    484         str = __ensure(p, 21); //int 值 
    485         if (str)
    486             sprintf(str, "%d", i);
    487     }
    488     else {
    489         str = __ensure(p, 64); //double值 
    490         if (str) {
    491             double nd = fabs(d); //得到正值开始比较
    492             if(fabs(floor(d) - d) <= DBL_EPSILON && nd < 1.0e60)
    493                 sprintf(str, "%.0f", d);
    494             else if(nd < 1.0e-6 || nd > 1.0e9) //科学计数法
    495                 sprintf(str, "%e", d);
    496             else
    497                 sprintf(str, "%f", d);
    498 
    499         }
    500     }
    501 
    502     return str;
    503 }
    504 
    505 // 输出字符串内容
    506 static char* __print_string(char* str, tstring p)
    507 {
    508     const char* ptr;
    509     char *nptr, *out;
    510     int len = 0, flag = 0;
    511     unsigned char c;
    512 
    513     if (!str || !*str) { //最特殊情况,什么都没有 返回NULL
    514         out = __ensure(p, 3);
    515         if (!out)
    516             return NULL;
    517         out[0] = '"', out[1] = '"', out[2] = '';
    518         return out;
    519     }
    520 
    521 
    522     for (ptr = str; (c=*ptr); ++ptr)
    523         flag |= ((c > 0 && c < 32) || c == '"' || c == '\');
    524     
    525     if (!flag) {  //没有特殊字符直接处理结果
    526         len = ptr - str;
    527         out = __ensure(p,len + 3);
    528         if (!out)
    529             return NULL;
    530         nptr = out;
    531         *nptr++ = '"';
    532         strcpy(nptr, str);
    533         nptr[len] = '"';
    534         nptr[len + 1] = '';
    535         return out;
    536     }
    537 
    538     //处理 存在 "和转义字符内容
    539     for (ptr = str; (c = *ptr) && ++len; ++ptr) {
    540         if (strchr(""\f
    
    	", c))
    541             ++len;
    542         else if (c < 32) //隐藏字符的处理, 这里可以改
    543             len += 5;
    544     }
    545 
    546     if ((out = __ensure(p, len + 3)) == NULL)
    547         return NULL;
    548     //先添加 "
    549     nptr = out;
    550     *nptr++ = '"';
    551     for (ptr = str; (c = *ptr); ++ptr) {
    552         if (c > 31 && c != '"' && c != '\') {
    553             *nptr++ = c;
    554             continue;
    555         }
    556         *nptr++ = '\';
    557         switch (c){
    558         case '\':    *nptr++ = '\';    break;
    559         case '"':    *nptr++ = '"';    break;
    560         case '':    *nptr++ = 'b';    break;
    561         case 'f':    *nptr++ = 'f';    break;
    562         case '
    ':    *nptr++ = 'n';    break;
    563         case '
    ':    *nptr++ = 'r';    break;
    564         case '	':    *nptr++ = 't';    break;
    565         default: sprintf(nptr, "u%04x", c);nptr += 5;    /* 不可见字符 采用 4字节字符编码 */
    566         }
    567     }
    568     *nptr++ = '"';
    569     *nptr = '';
    570     return out;
    571 }
    572 
    573 //这里是 递归下降 的函数声明处, 分别是处理值, 数组, object
    574 static char* __print_value(cjson_t item, tstring p);
    575 static char* __print_array(cjson_t item, tstring p);
    576 static char* __print_object(cjson_t item, tstring p);
    577 
    578 // 定义实现部分, 内部私有函数 认为 item 和 p都是存在的
    579 static char* __print_value(cjson_t item, tstring p) 
    580 {
    581     char* out = NULL;
    582     switch ((item->type) & UCHAR_MAX) { // 0xff
    583     case _CJSON_FALSE: if ((out = __ensure(p, 6))) strcpy(out, "false"); break;
    584     case _CJSON_TRUE: if ((out = __ensure(p, 5))) strcpy(out, "true"); break;
    585     case _CJSON_NULL: if ((out = __ensure(p, 5))) strcpy(out, "null"); break;
    586     case _CJSON_NUMBER:    out = __print_number(item, p); break;
    587     case _CJSON_STRING:    out = __print_string(item->vs, p); break;
    588     case _CJSON_ARRAY:    out = __print_array(item, p); break;
    589     case _CJSON_OBJECT:    out = __print_object(item, p); break;
    590     }
    591 
    592     return out;
    593 }
    594 
    595 // 同样 假定 item 和 p都是存在且不为NULL
    596 static char* __print_array(cjson_t item, tstring p)
    597 {
    598     char* ptr;
    599     cjson_t child = item->child;
    600     int ncut, i;
    601     // 得到孩子结点的深度
    602     for (ncut = 0; (child); child = child->child)
    603         ++ncut;
    604     if (!ncut) { //没有孩子结点 直接空数组返回结果
    605         char* out = NULL;
    606         if (!(out = __ensure(p, 3))) 
    607             strcpy(out, "[]");
    608         return out;
    609     }
    610 
    611     i = p->len;
    612     if (!(ptr = __ensure(p, 1)))
    613         return NULL;
    614     *ptr = '[';
    615     ++p->len;
    616     for (child = item->child; (child); child = child->next) {
    617         __print_value(child, p);
    618         p->len = __update(p);
    619         if (child->next) {
    620             if (!(ptr = __ensure(p, 2)))
    621                 return NULL;
    622             *ptr++ = ',';
    623             *ptr = '';
    624             p->len += 1;
    625         }
    626     }
    627     if (!(ptr = __ensure(p, 2)))
    628         return NULL;
    629     *ptr++ = ']';
    630     *ptr = '';
    631     return p->str + i;
    632 
    633 }
    634 
    635 // 同样 假定 item 和 p都是存在且不为NULL, 相信这些代码是安全的
    636 static char* __print_object(cjson_t item, tstring p)
    637 {
    638     char* ptr;
    639     int i, ncut, len;
    640     cjson_t child = item->child;
    641 
    642     // 得到孩子结点的深度
    643     for (ncut = 0; child; child = child->child)
    644         ++ncut;
    645     if (!ncut) {
    646         char* out = NULL;
    647         if (!(out = __ensure(p, 3)))
    648             strcpy(out, "{}");
    649         return out;
    650     }
    651 
    652     i = p->len;
    653     if (!(ptr = __ensure(p, 2)))
    654         return NULL;
    655     *ptr++ = '{';
    656     *ptr -= '';
    657     p->len += 1;
    658     // 根据子结点 处理
    659     for (child = item->child; (child); child = child->next) {
    660         __print_string(child->key, p);
    661         p->len = __update(p);
    662 
    663         //加入一个冒号
    664         if (!(ptr = __ensure(p, 1)))
    665             return NULL;
    666         *ptr++ = ':';
    667         p->len += 1;
    668 
    669         //继续打印一个值
    670         __print_value(child, p);
    671         p->len = __update(p);
    672 
    673         //结算最后内容
    674         len = child->next ? 1 : 0;
    675         if ((ptr = __ensure(p, len + 1)) == NULL)
    676             return NULL;
    677         if (child->next)
    678             *ptr++ = ',';
    679         *ptr = '';
    680         p->len += len;
    681     }
    682     if (!(ptr = __ensure(p, 2)))
    683         return NULL;
    684     *ptr++ = '}';
    685     *ptr = '';
    686     return p->str + i;
    687 }
    688 
    689 #define _INT_CJONSTR    (256)
    690 /*
    691 *  这里是将 cjson_t item 转换成字符串内容,需要自己free
    692 * item        : cjson的具体结点
    693 *            : 返回生成的item的json串内容
    694 */
    695 char* 
    696 cjson_print(cjson_t item)
    697 {
    698     struct tstring p;
    699     char* out;
    700     if ((!item) || !(p.str = malloc(sizeof(char)*_INT_CJONSTR))) {
    701         SL_FATAL("item:%p, p.str = malloc is error!", item);
    702         return NULL;
    703     }
    704     p.size = _INT_CJONSTR;
    705     p.len = 0;
    706 
    707     out = __print_value(item, &p); //从值处理开始, 返回最终结果
    708     if (out == NULL) {
    709         free(p.str);
    710         SL_FATAL("__print_value item:%p, p:%p is error!", item, &p);
    711         return NULL;
    712     }
    713     return realloc(out,strlen(out) + 1); // 体积变小 realloc返回一定成功
    714 }
    715 
    716 // --------------------------------- 下面是 cjson 输出部分的辅助代码 -----------------------------------------
    View Code

    到这里基本前期主场都完了. 后面就是玩测试了.

    4. 展示 cjson 测试部分

    首先展示 test_cjson_write.c 测试脚本

    #include <schead.h>
    #include <sclog.h>
    #include <cjson.h>
    
    // 测试 cjson 函数
    int main(int argc, char* argv[])
    {
        //注册等待函数
        INIT_PAUSE();
    
        //启动日志记录功能
        sl_start();
    
        // 测试json 串
        char jstr[] = "{
    "name": "Jack (\"Bee\") Nimble", 
    "format": {"type":[1, 3, 4, 5.66], 
    "height":     1080, 
    "interlace":  false}
    }";
    
        printf("源码串 :
     %s
    ", jstr);
    
        // 先生成 json 对象
        cjson_t root = cjson_parse(jstr);
        if (root == NULL) {
            puts("jstr 解析失败! 程序退出中....");
            exit(EXIT_FAILURE);
        }
    
        //这里简单测试输出内容
        char* njstr = cjson_print(root);
    
        if (njstr == NULL) {
            puts("输出内容失败,程序退出中!");
            cjson_delete(&root);
            exit(EXIT_FAILURE);
        }
    
        //合法范围直接输出 内容
        printf("解析串 :
     %s
    ", njstr);
    
        //解析完需要释放
        free(njstr);
    
        //解析好 一定要注意释放操作
        cjson_delete(&root);
    
    
        //另一个测试 输出内存值
        printf("d = %d
    ", strlen("{"name":"Jack (\"Bee\") Nimble","format":{"type":[1,3,4,5.660000],"height":1080,"interlace":false}}"));
    }

    需要大家写一遍或看三遍. 测试结果 如下:

    一切正常. 这里输出是可以的. 欢迎大家尝试了.

    5.下次来个 cjson 较完整demo

      下次写好这个cjson库, 我们 测试一个下面 json 文件 实战解析一下

    firefighting_rule.json 

    {     
    "firefighting_rule":     
     {    
      "key1":   
       {  
        "id":1,
        "dungeon_id":40008,
        "level_contain":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],
        "active_time":[[1,"110000"],[4,"110000"],[5,"210000"]],
        "boss_ui_head":"UI_icon/IMG_ShiJieBoss_TouXiang.png",
        "activity_tag_icon":"IMG_GaiBan_HuoDong_ShiJieBoss_TuBiao.png",
        "activity_tag_word":"IMG_GaiBan_ZhuCheng_ShiJieBoss_TuBiao_MingZi.png",
        "activity_pic_json":"UI_HuoDong_ShiJieBoss.json",
        "jinbi_buff_icon":"UI_icon/IMG_WorldBoss_JinbiBuff_Atk.png",
        "jinbi_buff_damage":[[8,1000],[9,1000],[11,1000],[12,1000]],
        "jinbi_buff_price":10,
        "jinbi_buff_limit":999,
        "free_change":1,
        "refresh_price":20,
        "change_price":20,
        "show_hero_num":20 
       }  
     }    
    }     

    解析成我们想要的那样的东西. 尝试, 追求, 按部就班 , 人生...........................................

    后记 

      错误是难免,欢迎批评指正. 下次会对cjson 进行简单总结, 再添加一些辅助函数. 一切会从简单来.

  • 相关阅读:
    理论四:接口隔离原则有哪三种应用?原则中的“接口”该如何理解?
    gunicorn 配置文件
    转载——gunicorn的实践经验
    pympler 模块
    类属性的名称空间
    django——实现事务
    django-apscheduler报错——Run time of job …… next run at: ……)” was missed by
    阿里云连接数据库服务
    第十三周总结
    IDEA常用模板
  • 原文地址:https://www.cnblogs.com/life2refuel/p/5225507.html
Copyright © 2011-2022 走看看