jsonc.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /*
  2. * jsonc.c
  3. *
  4. * Copyright (C) 2018 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * @brief Memory allocation-free, extremely fast JSON parser in pure ANSI C
  27. *
  28. */
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #define JSON_MAXPATHLEVEL 32
  32. /**
  33. * jsonstr: zero terminated UTF-8 string
  34. * key: path to a value, like "0.6.0.1" or "result.items.0.name"
  35. * returns the value in a malloc'd string or NULL
  36. */
  37. __attribute_malloc__ char *json_get(const char *jsonstr, char *key)
  38. {
  39. char *m=key, *ret=NULL;
  40. unsigned char *c=(unsigned char*)jsonstr,*k[JSON_MAXPATHLEVEL+1];
  41. unsigned char *v,*s=NULL,*e=NULL;
  42. int l=0, j=1, i, n, x[JSON_MAXPATHLEVEL+1]={0};
  43. if(!jsonstr || !jsonstr[0] || !key) return NULL;
  44. while(1) {
  45. /* skip white spaces */
  46. while(*c && *c<=' ') c++;
  47. if(j) { j=0; k[l]=v=c; }
  48. switch(*c) {
  49. /* string literals */
  50. case '\"': c++; while(*c && *c!='\"'){if(*c=='\\'){c++;} c++;} break;
  51. /* field names */
  52. case ':': c++; while(*c && *c<=' ') { c++; } v=c--; break;
  53. /* control blocks */
  54. case 0: case ',': case '{': case '[': case '}': case ']':
  55. if(*v!=','&&*v!='{'&&*v!='['&&*v!=']'&&*v!='}') {
  56. /* skip index for topmost object */
  57. n=k[0][0]=='{'?1:0;
  58. /* match the path */
  59. m=key;
  60. for(i=n;i<=l && *m;i++) {
  61. if(i!=n) { if(*m=='.') m++; else break; }
  62. if(k[i][0]=='\"' && k[i]!=v && (*m<'0'||*m>'9')) {
  63. s=e=k[i]+1;
  64. while(*e&&*e!='\"') { if(*e=='\\') { e++; } e++; }
  65. if(memcmp(m,s,e-s)) break;
  66. m+=e-s;
  67. } else {
  68. if(atoi(m)!=x[i]) break;
  69. while(*m && *m!='.') m++;
  70. }
  71. }
  72. /* find start and end of the return value */
  73. if(!*m) {
  74. switch(*v) {
  75. case '\"':
  76. s=e=v+1;
  77. while(*e&&*e!='\"') { if(*e=='\\') { e++; } e++; }
  78. break;
  79. case 'n': return NULL;
  80. default:
  81. s=e=v;
  82. while(*e&&*e>' '&&*e!=','&&*e!=']'&&*e!='}') e++;
  83. break;
  84. }
  85. /* we can't break the loop inside a switch in ANSI C */
  86. goto end;
  87. }
  88. }
  89. switch(*c) {
  90. case 0: return NULL;
  91. case '{': case '[': x[++l]=0; if(l>=(int)sizeof(x)-1) return NULL; break;
  92. case '}': case ']': l--; break;
  93. case ',': x[l]++; break;
  94. }
  95. j++;
  96. break;
  97. }
  98. c++;
  99. }
  100. /* copy a zero terminated string of the value if any */
  101. end:if(!*m && e>s) {
  102. ret=malloc(e-s+1);
  103. if(ret) { memcpy(ret,s,e-s); ret[e-s]=0; }
  104. }
  105. return ret;
  106. }