001 #define J_STR 1 002 #define J_NUM 2 003 #define J_ARRAY 3 004 #define J_NODE 4 005 class CJson { 006 I64 type; 007 union { 008 U8 *str; 009 F64 num; 010 CHashTable *hash_table; 011 } 012 I64 cnt; 013 Bool used; 014 }; 015 016 U8 *sqstring(U8 *ptr,U8 **en) { 017 U8 *buf=MAlloc(1024); 018 I64 ch=0,C; 019 if(en) *en=ptr; 020 if(*ptr!='\'') return NULL; 021 ptr++; 022 while(*ptr&&*ptr!='\'') { 023 if(*ptr=='\\') { 024 ptr++; 025 read_one: 026 if(ch<1023) 027 buf[ch++]=*(ptr++); 028 else 029 ptr++; 030 } else 031 goto read_one; 032 } 033 buf[ch]=0; 034 if(en) *en=ptr+1; 035 return buf; 036 } 037 038 U8 *dqstring(U8 *ptr,U8 **en) { 039 U8 *buf=MAlloc(1024); 040 I64 ch=0,C; 041 if(en) *en=ptr; 042 if(*ptr!='"') return NULL; 043 ptr++; 044 while(*ptr&&*ptr!='"') { 045 if(*ptr=='\\') { 046 ptr++; 047 read_one: 048 if(ch<1023) 049 buf[ch++]=*(ptr++); 050 else 051 ptr++; 052 } else 053 goto read_one; 054 } 055 buf[ch]=0; 056 if(en) *en=ptr+1; 057 return buf; 058 } 059 060 061 U8 *SkipWhitespace(U8 *s) { 062 while(*s&&Bt(char_bmp_white_space,*s)) 063 s++; 064 return s; 065 } 066 U8 *word(U8 *ptr,U8 **en) { 067 U8 *buf=MAlloc(256); 068 I64 ch=0; 069 if(en) *en=ptr; 070 if(!Bt(char_bmp_alpha_numeric,*ptr)) return NULL; 071 while(Bt(char_bmp_alpha_numeric,*ptr)) 072 buf[ch++]=*ptr++; 073 buf[ch]=0; 074 if(en) *en=ptr; 075 return buf; 076 } 077 class CIndexBlk { 078 I32 inst_cnt; 079 I64 inst_offsets[9]; 080 I64 inst_flags[9]; 081 U32 translation_idx; 082 U32 body['z'-'a'+1]; 083 }; 084 CJson *ParseJson(U8 *st,U8 **en=NULL) { 085 CJson *ret=NULL; 086 U8 *name; 087 CHashGeneric *g; 088 st=SkipWhitespace(st); 089 if(*st=='{') { 090 ret=CAlloc(sizeof CJson); 091 ret->type=J_NODE; 092 ret->hash_table=HashTableNew(0x8); 093 st=SkipWhitespace(st+1); 094 while(*st!='}') { 095 if(!*st) throw('JSON'); 096 switch(*st) { 097 case '\'': 098 name=sqstring(st,&st); 099 break; 100 case '"': 101 name=dqstring(st,&st); 102 break; 103 default: 104 name=word(st,&st); 105 break; 106 } 107 if(!name) throw('JSON'); 108 st=StrFirstOcc(st,":"); 109 if(!st) throw('JSON'); 110 st++; 111 g=CAlloc(sizeof CHashGeneric); 112 g->str=name; 113 g->type=HTT_FRAME_PTR; 114 g->user_data0=ParseJson(st,&st); 115 HashAdd(g,ret->hash_table); 116 st=StrFirstOcc(st,",}"); 117 if(!st) throw('JSON'); 118 if(*st==',') st++; 119 st=SkipWhitespace(st); 120 } 121 st++; 122 } else if(*st=='\'') { 123 ret=CAlloc(sizeof CJson); 124 ret->type=J_STR; 125 ret->str=sqstring(st,&st); 126 } else if(*st=='\"') { 127 ret=CAlloc(sizeof CJson); 128 ret->type=J_STR; 129 ret->str=dqstring(st,&st); 130 } else if(*st=='[') { 131 st=SkipWhitespace(st+1); 132 ret=CAlloc(sizeof CJson); 133 ret->type=J_ARRAY; 134 ret->hash_table=HashTableNew(0x10); 135 while(*st!=']') { 136 g=CAlloc(sizeof CHashGeneric); 137 g->str=MStrPrint("%d",ret->cnt++); 138 g->type=HTT_FRAME_PTR; 139 g->user_data0=ParseJson(st,&st); 140 HashAdd(g,ret->hash_table); 141 st=StrFirstOcc(st,",]"); 142 if(!st) throw('JSON'); 143 if(*st==',') st++; 144 st=SkipWhitespace(st); 145 } 146 st++; 147 } else { 148 name=st; 149 ret=CAlloc(sizeof CJson); 150 ret->type=J_NUM; 151 ret->num=Str2F64(st,&st); 152 if(name==st) 153 throw('JSON'); 154 } 155 if(en) *en=st; 156 if(!ret) throw('JSON'); 157 return ret; 158 } 159 U0 JsonDel(CJson *j) { 160 I64 bucket; 161 CHashGeneric *g; 162 switch(j->type) { 163 case J_STR: 164 Free(j->str); 165 break; 166 case J_NUM: 167 break; 168 case J_NODE: 169 case J_ARRAY: 170 for(bucket=0;bucket<=j->hash_table->mask;bucket++) 171 for(g=j->hash_table->body[bucket];g;g=g->next) { 172 JsonDel(g->user_data0); 173 } 174 HashTableDel(j->hash_table); 175 } 176 Free(j); 177 } 178 U0 DumpJson(U8 *d=NULL,CJson *j) { 179 I64 bucket; 180 Bool first=TRUE; 181 U8 num[STR_LEN]; 182 CHashGeneric *g; 183 switch(j->type) { 184 case J_STR: 185 CatPrint(d,"\"%Q\"",j->str); 186 break; 187 case J_NUM: 188 CatPrint(d,"%n",j->num); 189 break; 190 case J_NODE: 191 CatPrint(d,"{"); 192 for(bucket=0;bucket<=j->hash_table->mask;bucket++) 193 for(g=j->hash_table->body[bucket];g;g=g->next) { 194 if(!first) CatPrint(d,","); 195 CatPrint(d,"%s:",g->str); 196 DumpJson(d,g->user_data0); 197 first=FALSE; 198 } 199 CatPrint(d,"}"); 200 break; 201 case J_ARRAY: 202 CatPrint(d,"["); 203 for(bucket=0;bucket<=j->hash_table->mask;bucket++) 204 for(g=j->hash_table->body[bucket];g;g=g->next) { 205 if(!first) CatPrint(d,","); 206 DumpJson(d,g->user_data0); 207 first=FALSE; 208 } 209 CatPrint(d,"]"); 210 } 211 } 212 Bool TrimJson0(CJson *j,I64 argc,U8 **argv) { 213 I64 i; 214 I64 bucket; 215 CHashGeneric *g; 216 Bool ret=FALSE; 217 if(j->type!=J_NODE&&j->type!=J_ARRAY) return FALSE; 218 CJson *sub; 219 for(bucket=0;bucket<=j->hash_table->mask;bucket++) { 220 again:; 221 for(g=j->hash_table->body[bucket];g;g=g->next) { 222 for(i=0;i!=argc;i++) { 223 if(!StrCmp(g->str,argv[i])) { 224 ret=TRUE; 225 goto skip; 226 } 227 } 228 sub=g->user_data0; 229 if(sub->used) { 230 goto skip; 231 } 232 if(!TrimJson0(sub,argc,argv)) { 233 HashRemDel(g,j->hash_table); 234 JsonDel(sub); 235 } else { 236 ret=TRUE; 237 sub->used=TRUE; 238 } 239 goto again; 240 skip:; 241 } 242 } 243 return ret; 244 } 245 Bool TrimJson(CJson *j,...) { 246 return TrimJson0(j,argc,argv); 247 } 248 249 U0 SubFBlkRead(CFile *file,CIndexBlk *out,I64 ptr) { 250 U8 dummies[BLK_SIZE]; 251 FBlkRead(file,&dummies,ptr>>1,1); 252 if(ptr&1) 253 MemCpy(out,&dummies[sizeof(CIndexBlk)],sizeof(CIndexBlk)); 254 else 255 MemCpy(out,&dummies[0],sizeof(CIndexBlk)); 256 } 257 U0 SubFBlkWrite(CFile *file,CIndexBlk *in,I64 ptr) { 258 U8 dummies[BLK_SIZE]; 259 MemSet(&dummies,0,BLK_SIZE); 260 FBlkRead(file,&dummies,ptr>>1,1); 261 if(ptr&1) 262 MemCpy(&dummies[sizeof(CIndexBlk)],in,sizeof(CIndexBlk)); 263 else 264 MemCpy(&dummies[0],in,sizeof(CIndexBlk)); 265 FBlkWrite(file,dummies,ptr>>1); 266 } 267 268 I64 GetWordPtr(I64 *max,CFile *file,U8 *str,I64 ptr=0,Bool *new=NULL) { 269 if(new) *new=FALSE; 270 if(!*str) return ptr; 271 I64 idx=ToUpper(*str)-'A'; 272 CIndexBlk dummy; 273 SubFBlkRead(file,&dummy,ptr); 274 if(!dummy.body[idx]) { 275 dummy.body[idx]=*max; 276 SubFBlkWrite(file,&dummy,ptr); 277 MemSet(&dummy,0,sizeof CIndexBlk); 278 SubFBlkWrite(file,&dummy,ptr=(*max)++); 279 if(new) *new=TRUE; 280 return GetWordPtr(max,file,str+1,ptr); 281 } 282 if(ptr>*max) throw('trie'); 283 return GetWordPtr(max,file,str+1,dummy.body[idx],new); 284 } 285 CJson *GetJsonMember(CJson *j,U8 *member,I64 type=-1) { 286 CHashGeneric *g; 287 if(j->type==J_ARRAY||j->type==J_NODE) { 288 g=HashFind(member,j->hash_table,-1); 289 if(g) { 290 j=g->user_data0; 291 if(type==-1) { 292 return j; 293 } 294 else if(type==j->type) { 295 return j; 296 } 297 } 298 } 299 return NULL; 300 }