djson.inc 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106
  1. /*
  2. * DJson 1.6.2
  3. * (c) Copyright 2008-2010 by DracoBlue
  4. *
  5. * @author : DracoBlue (http://dracoblue.com)
  6. * @date : 20th Aug 2008
  7. * @update : 8th May 2010
  8. *
  9. * This file is provided as is (no warranties).
  10. *
  11. * DJson is released under the terms of MIT License
  12. *
  13. * Feel free to use it, a little message in
  14. * about box is honoring thing, isn't it?
  15. *
  16. */
  17. #define DJSON_MAX_DEPTH 20
  18. #if !defined DJSON_MAX_STRING
  19. #define DJSON_MAX_STRING 255
  20. #endif
  21. #define DJSON_RUN_TESTCASES_AT_INIT 0
  22. #pragma dynamic 4000000
  23. #define DJSON_CACHE_USE_TEMPTABLES 1
  24. #define DJSON_ALLOW_STYLED_OUTPUT 1
  25. /**
  26. * @access private
  27. * @ingroup private
  28. */
  29. new DJSON_cache_file_name[DJSON_MAX_STRING];
  30. /**
  31. * @access public
  32. */
  33. new DJSON_LastError[DJSON_MAX_STRING];
  34. /**
  35. * 1 = Can not open File
  36. * 2 = Syntax Error in File
  37. * 3 = Error In djson Parser, please report to DracoBlue
  38. * 4 = This path you trying to access is not set, falling back to default value
  39. * 5 = File was not loaded, can't commit!
  40. * 6 = The path is invalid
  41. * @access public
  42. */
  43. new DJSON_LastErrorCode=0;
  44. /**
  45. * @access private
  46. * @ingroup private
  47. */
  48. new DJSON_path[DJSON_MAX_DEPTH][DJSON_MAX_STRING];
  49. /**
  50. * @access private
  51. * @ingroup private
  52. */
  53. new DJSON_path_id[DJSON_MAX_DEPTH];
  54. /**
  55. * @access private
  56. * @ingroup private
  57. */
  58. new DJSON_path_type[DJSON_MAX_DEPTH];
  59. /**
  60. * @access private
  61. * @ingroup private
  62. */
  63. new DJSON_path_arraypos[DJSON_MAX_DEPTH];
  64. /**
  65. * @access private
  66. * @ingroup private
  67. */
  68. new DJSON_autocommit = true;
  69. #if DJSON_ALLOW_STYLED_OUTPUT
  70. /**
  71. * @access private
  72. * @ingroup private
  73. */
  74. new DJSON_styled_output = false;
  75. #endif
  76. /**
  77. * @access private
  78. * @ingroup private
  79. */
  80. stock DJSON_ret_memcpy(source[],index=0,numbytes) {
  81. new tmp[DJSON_MAX_STRING];
  82. new i=0;
  83. tmp[0]=0;
  84. if (index>=strlen(source)) return tmp;
  85. if (numbytes+index>=strlen(source)) numbytes=strlen(source)-index;
  86. if (numbytes<=0) return tmp;
  87. for (i=index;i<numbytes+index;i++) {
  88. tmp[i-index]=source[i];
  89. if (source[i]==0) return tmp;
  90. }
  91. tmp[numbytes]=0;
  92. return tmp;
  93. }
  94. /**
  95. * @access private
  96. * @ingroup private
  97. */
  98. stock DJSON_implode(c,path_pos) {
  99. new tmp[DJSON_MAX_STRING];
  100. for (new i=0;i<path_pos;i++) {
  101. if (i==path_pos-1) {
  102. format(tmp,DJSON_MAX_STRING,"%s%s",tmp,DJSON_path[i]);
  103. } else {
  104. format(tmp,DJSON_MAX_STRING,"%s%s%c",tmp,DJSON_path[i],c);
  105. }
  106. }
  107. return tmp;
  108. }
  109. /**
  110. * @access private
  111. * @ingroup private
  112. */
  113. new DB:DJSON_cache_db;
  114. /**
  115. * @access private
  116. * @ingroup private
  117. */
  118. #define DJSON_TYPE_OBJECT 1
  119. /**
  120. * @access private
  121. * @ingroup private
  122. */
  123. #define DJSON_TYPE_ARRAY 2
  124. /**
  125. * @access private
  126. * @ingroup private
  127. */
  128. #define DJSON_TYPE_NUMBER 3
  129. /**
  130. * @access private
  131. * @ingroup private
  132. */
  133. #define DJSON_TYPE_STRING 4
  134. /**
  135. * @access private
  136. * @ingroup private
  137. */
  138. stock DJSON_cache_init() {
  139. new max_id = 1000;
  140. new id;
  141. while (max_id++) {
  142. id = random(max_id);
  143. format(DJSON_cache_file_name,DJSON_MAX_STRING,"djson-db-cache.%d.db",id);
  144. if (!fexist(DJSON_cache_file_name)) {
  145. break;
  146. }
  147. }
  148. DJSON_cache_db=db_open(DJSON_cache_file_name);
  149. #if DJSON_CACHE_USE_TEMPTABLES
  150. db_query(DJSON_cache_db,"PRAGMA journal_mode = OFF;");
  151. db_query(DJSON_cache_db,"PRAGMA temp_store = MEMORY;");
  152. db_query(DJSON_cache_db,"DROP TABLE IF EXISTS `c`");
  153. db_query(DJSON_cache_db,"CREATE TEMPORARY TABLE IF NOT EXISTS `c` ( `file` varchar(255), `id` INTEGER PRIMARY KEY, `path` varchar(255), `value` varchar(255), `type` int(6),`parent` int(6),`pos` int(6))");
  154. db_query(DJSON_cache_db,"DROP TABLE IF EXISTS `is_c`");
  155. db_query(DJSON_cache_db,"CREATE TEMPORARY TABLE IF NOT EXISTS `is_c` ( `file` varchar(255))");
  156. #else
  157. db_query(DJSON_cache_db,"DROP TABLE IF EXISTS `c`");
  158. db_query(DJSON_cache_db,"CREATE TABLE IF NOT EXISTS `c` ( `file` varchar(255), `id` INTEGER PRIMARY KEY, `path` varchar(255), `value` varchar(255), `type` int(6),`parent` int(6),`pos` int(6))");
  159. db_query(DJSON_cache_db,"DROP TABLE IF EXISTS `is_c`");
  160. db_query(DJSON_cache_db,"CREATE TABLE IF NOT EXISTS `is_c` ( `file` varchar(255))");
  161. #endif
  162. }
  163. /**
  164. * @access private
  165. * @ingroup private
  166. */
  167. stock DJSON_cache_close() {
  168. db_close(DJSON_cache_db);
  169. fremove(DJSON_cache_file_name);
  170. }
  171. /**
  172. * @access private
  173. * @ingroup private
  174. */
  175. stock DJSON_strreplace(trg[],newstr[],src[]) {
  176. new f=0;
  177. new s1[DJSON_MAX_STRING];
  178. new tmp[DJSON_MAX_STRING];
  179. if (strlen(src)==0) return tmp;
  180. format(s1,sizeof(s1),"%s",src);
  181. f = strfind(s1,trg);
  182. tmp[0]=0;
  183. while (f>=0) {
  184. strcat(tmp,DJSON_ret_memcpy(s1, 0, f));
  185. strcat(tmp,newstr);
  186. format(s1,sizeof(s1),"%s",DJSON_ret_memcpy(s1, f+strlen(trg), strlen(s1)-f));
  187. f = strfind(s1,trg);
  188. }
  189. strcat(tmp,s1);
  190. return tmp;
  191. }
  192. /**
  193. * @access private
  194. * @ingroup private
  195. */
  196. stock DJSON_sql_escape(src[]) {
  197. new tmp[DJSON_MAX_STRING];
  198. new src_len = strlen(src);
  199. new nxt_trg_pos = 0;
  200. new i = 0;
  201. while (i<src_len) {
  202. switch (src[i]) {
  203. case '\'': {
  204. tmp[nxt_trg_pos]='\'';
  205. nxt_trg_pos++;
  206. tmp[nxt_trg_pos]='\'';
  207. }
  208. default: {
  209. tmp[nxt_trg_pos] = src[i];
  210. }
  211. }
  212. nxt_trg_pos++;
  213. i++;
  214. }
  215. tmp[nxt_trg_pos] = 0;
  216. return tmp;
  217. }
  218. /**
  219. * @access private
  220. * @ingroup private
  221. */
  222. stock DJSON_json_escape(src[]) {
  223. new tmp[DJSON_MAX_STRING];
  224. new src_len = strlen(src);
  225. new nxt_trg_pos = 0;
  226. new i = 0;
  227. while (i<src_len) {
  228. switch (src[i]) {
  229. case 10: {
  230. tmp[nxt_trg_pos]='\\';
  231. nxt_trg_pos++;
  232. tmp[nxt_trg_pos]='n';
  233. }
  234. case 13: {
  235. tmp[nxt_trg_pos]='\\';
  236. nxt_trg_pos++;
  237. tmp[nxt_trg_pos]='r';
  238. }
  239. case '"': {
  240. tmp[nxt_trg_pos]='\\';
  241. nxt_trg_pos++;
  242. tmp[nxt_trg_pos]='"';
  243. }
  244. case 9: {
  245. tmp[nxt_trg_pos]='\\';
  246. nxt_trg_pos++;
  247. tmp[nxt_trg_pos]='t';
  248. }
  249. case '\\': {
  250. tmp[nxt_trg_pos]='\\';
  251. nxt_trg_pos++;
  252. tmp[nxt_trg_pos]='\\';
  253. }
  254. default: {
  255. tmp[nxt_trg_pos] = src[i];
  256. }
  257. }
  258. nxt_trg_pos++;
  259. i++;
  260. }
  261. tmp[nxt_trg_pos] = 0;
  262. return tmp;
  263. }
  264. /**
  265. * @access private
  266. * @ingroup private
  267. */
  268. stock DJSON_cache_createNode(file[],key[],type_id,value[],parent,pos=-1) {
  269. new query[DJSON_MAX_STRING];
  270. format(query,DJSON_MAX_STRING,"INSERT INTO `c` (`id`,`file`,`path`,`value`,`type`, `pos`,`parent`) VALUES ((SELECT max(`id`) FROM `c`)+1,'%s','%s','%s',%d,%d,%d)",DJSON_sql_escape(file),DJSON_sql_escape(key),DJSON_sql_escape(value),type_id,pos,parent);
  271. db_query(DJSON_cache_db,query);
  272. new DBResult:res;
  273. format(query,DJSON_MAX_STRING,"SELECT `id` FROM `c` WHERE file = '%s' AND path = '%s'",DJSON_sql_escape(file),DJSON_sql_escape(key));
  274. res = db_query(DJSON_cache_db,query);
  275. new has_next = db_num_rows(res) != 0;
  276. new the_id[DJSON_MAX_STRING]="-1";
  277. if (has_next) {
  278. db_get_field(res,0,the_id,DJSON_MAX_STRING);
  279. }
  280. db_free_result(res);
  281. return strval(the_id);
  282. }
  283. /**
  284. * @access private
  285. * @ingroup private
  286. */
  287. stock DJSON_cache_updateNode(file[],key[],type_id,value[]) {
  288. new query[DJSON_MAX_STRING];
  289. new DBResult:res;
  290. format(query,DJSON_MAX_STRING,"SELECT `id` FROM `c` WHERE file = '%s' AND path = '%s' LIMIT 1",DJSON_sql_escape(file),DJSON_sql_escape(key));
  291. res = db_query(DJSON_cache_db,query);
  292. if (db_num_rows(res) != 0) {
  293. // it exists
  294. new the_id[DJSON_MAX_STRING]="-1";
  295. db_get_field(res,0,the_id,DJSON_MAX_STRING);
  296. db_free_result(res);
  297. format(query,DJSON_MAX_STRING,"UPDATE `c` SET `value`='%s',type=%d WHERE file='%s' AND path='%s'",DJSON_sql_escape(value),type_id,DJSON_sql_escape(file),DJSON_sql_escape(key));
  298. db_query(DJSON_cache_db,query);
  299. return strval(the_id);
  300. } else {
  301. db_free_result(res);
  302. return 0;
  303. }
  304. }
  305. /**
  306. * @access private
  307. * @ingroup private
  308. */
  309. stock DJSON_cache_createArrayNode(file[],key[],parent,pos=-1) {
  310. return DJSON_cache_createNode(file,key,DJSON_TYPE_ARRAY,"",parent,pos);
  311. }
  312. /**
  313. * @access private
  314. * @ingroup private
  315. */
  316. stock DJSON_cache_createObjectNode(file[],key[],parent,pos=-1) {
  317. return DJSON_cache_createNode(file,key,DJSON_TYPE_OBJECT,"",parent,pos);
  318. }
  319. /**
  320. * @access private
  321. * @ingroup private
  322. */
  323. stock DJSON_cache_createString(file[],key[],value[],parent,pos=-1) {
  324. return DJSON_cache_createNode(file,key,DJSON_TYPE_STRING,value,parent,pos);
  325. }
  326. /**
  327. * @access private
  328. * @ingroup private
  329. */
  330. stock DJSON_cache_updateString(file[],key[],value[]) {
  331. return DJSON_cache_updateNode(file,key,DJSON_TYPE_STRING,value);
  332. }
  333. /**
  334. * @access private
  335. * @ingroup private
  336. */
  337. stock DJSON_cache_updateArrayNode(file[],key[]) {
  338. return DJSON_cache_updateNode(file,key,DJSON_TYPE_ARRAY,"");
  339. }
  340. /**
  341. * @access private
  342. * @ingroup private
  343. */
  344. stock DJSON_cache_createNumberFromStr(file[],key[],value[],parent,pos=-1) {
  345. return DJSON_cache_createNode(file,key,DJSON_TYPE_NUMBER,value,parent,pos);
  346. }
  347. /**
  348. * @access private
  349. * @ingroup private
  350. */
  351. stock DJSON_cache_updateNumberFromStr(file[],key[],value[]) {
  352. return DJSON_cache_updateNode(file,key,DJSON_TYPE_NUMBER,value);
  353. }
  354. /**
  355. * @access private
  356. * @ingroup private
  357. */
  358. stock DJSON_cache_createNumber(file[],key[],value,parent,pos=-1) {
  359. new tmp[DJSON_MAX_STRING];
  360. format(tmp,DJSON_MAX_STRING,"%d",value);
  361. return DJSON_cache_createNode(file,key,DJSON_TYPE_NUMBER,tmp,parent,pos);
  362. }
  363. /**
  364. * @access private
  365. * @ingroup private
  366. */
  367. stock DJSON_cache_updateNumber(file[],key[],value) {
  368. new tmp[DJSON_MAX_STRING];
  369. format(tmp,DJSON_MAX_STRING,"%d",value);
  370. return DJSON_cache_updateNode(file,key,DJSON_TYPE_NUMBER,tmp);
  371. }
  372. /**
  373. * @access private
  374. * @ingroup private
  375. */
  376. stock DJSON_cache_putchartofile(File:fhnd,stream[DJSON_MAX_STRING],&stream_pos,c) {
  377. if (stream_pos==DJSON_MAX_STRING-1) {
  378. stream[stream_pos] = 0;
  379. fwrite(fhnd,stream);
  380. stream_pos = 0;
  381. }
  382. stream[stream_pos] = c;
  383. stream_pos++;
  384. }
  385. /**
  386. * @access private
  387. * @ingroup private
  388. */
  389. stock DJSON_cache_putstringtofile(File:fhnd,stream[DJSON_MAX_STRING],&stream_pos,str[]) {
  390. new strl = strlen(str);
  391. new i = 0;
  392. if (strl+stream_pos<DJSON_MAX_STRING-1) {
  393. // if it's smaller anyways, we can do a fast copy
  394. while (i<strl) {
  395. stream[stream_pos] = str[i];
  396. stream_pos++;
  397. i++;
  398. }
  399. } else {
  400. // if it's bigger, we need to be careful
  401. while (i<strl) {
  402. if (stream_pos<DJSON_MAX_STRING-1) {
  403. stream[stream_pos] = str[i];
  404. stream_pos++;
  405. i++;
  406. } else {
  407. stream[stream_pos] = 0;
  408. fwrite(fhnd,stream);
  409. stream_pos = 0;
  410. }
  411. }
  412. }
  413. }
  414. /**
  415. * @access private
  416. * @ingroup private
  417. */
  418. stock DJSON_cache_debug_save_file(file[],tofile[]) {
  419. #if DJSON_ALLOW_STYLED_OUTPUT
  420. if (DJSON_styled_output) return DJSON_cache_save_file_indented(file,tofile);
  421. #endif
  422. new DBResult:res;
  423. new query[DJSON_MAX_STRING];
  424. format(query,DJSON_MAX_STRING,"SELECT `path`,`value`,`type`,`id`,`parent`,`pos` FROM `c` WHERE file='%s' ORDER BY `path`",DJSON_sql_escape(file));
  425. res = db_query(DJSON_cache_db,query);
  426. new has_next = db_num_rows(res) != 0;
  427. new cur_parent[DJSON_MAX_DEPTH];
  428. new cur_type[DJSON_MAX_DEPTH];
  429. new cur_el[DJSON_MAX_DEPTH];
  430. new cur_path[DJSON_MAX_DEPTH][DJSON_MAX_STRING];
  431. new c_d = 0;
  432. new tmp[DJSON_MAX_STRING];
  433. cur_parent[c_d]=0;
  434. cur_type[c_d]=DJSON_TYPE_OBJECT;
  435. cur_el[c_d]=0;
  436. cur_path[c_d][0]=0;
  437. new row_path[DJSON_MAX_STRING];
  438. new row_value[DJSON_MAX_STRING];
  439. new row_id = 0;
  440. new row_parent = 0;
  441. new row_type = 0;
  442. new File:fhnd=fopen(tofile,io_write);
  443. new stream[DJSON_MAX_STRING];
  444. new stream_pos = 0;
  445. if (!fhnd) {
  446. format(DJSON_LastError,DJSON_MAX_STRING,"Can not open File for writing!");
  447. DJSON_LastErrorCode = 2;
  448. return false;
  449. }
  450. if (has_next) {
  451. db_get_field(res,0,row_path,DJSON_MAX_STRING);
  452. db_get_field(res,1,row_value,DJSON_MAX_STRING);
  453. db_get_field(res,2,tmp,DJSON_MAX_STRING);
  454. row_type = strval(tmp);
  455. db_get_field(res,3,tmp,DJSON_MAX_STRING);
  456. row_id = strval(tmp);
  457. db_get_field(res,4,tmp,DJSON_MAX_STRING);
  458. row_parent = strval(tmp);
  459. }
  460. DJSON_cache_putchartofile(fhnd,stream, stream_pos,'{');
  461. while (row_id != 0) {
  462. while (row_parent != cur_parent[c_d]) {
  463. // this is not the correct parent yet, so we need to get down.
  464. if (cur_type[c_d] == DJSON_TYPE_OBJECT) DJSON_cache_putchartofile(fhnd,stream,stream_pos,'}'); else DJSON_cache_putchartofile(fhnd,stream,stream_pos,']');
  465. c_d--;
  466. }
  467. if (cur_type[c_d] == DJSON_TYPE_OBJECT || cur_type[c_d] == DJSON_TYPE_ARRAY) {
  468. cur_el[c_d]++;
  469. if (cur_el[c_d]>1) {
  470. DJSON_cache_putchartofile(fhnd,stream,stream_pos,',');
  471. }
  472. }
  473. if (cur_type[c_d] == DJSON_TYPE_OBJECT) {
  474. DJSON_cache_putchartofile(fhnd,stream,stream_pos,'"');
  475. if (strlen(cur_path[c_d])>0) {
  476. DJSON_cache_putstringtofile(fhnd,stream,stream_pos,row_path[strlen(cur_path[c_d])+1]);
  477. } else {
  478. DJSON_cache_putstringtofile(fhnd,stream,stream_pos,row_path);
  479. }
  480. DJSON_cache_putchartofile(fhnd,stream,stream_pos,'"');
  481. DJSON_cache_putchartofile(fhnd,stream,stream_pos,':');
  482. }
  483. if (row_type == DJSON_TYPE_NUMBER) {
  484. DJSON_cache_putstringtofile(fhnd,stream,stream_pos,row_value);
  485. }
  486. if (row_type == DJSON_TYPE_STRING) {
  487. DJSON_cache_putchartofile(fhnd,stream,stream_pos,'"');
  488. DJSON_cache_putstringtofile(fhnd,stream,stream_pos,DJSON_json_escape(row_value));
  489. DJSON_cache_putchartofile(fhnd,stream,stream_pos,'"');
  490. }
  491. if (row_type == DJSON_TYPE_OBJECT || row_type == DJSON_TYPE_ARRAY) {
  492. if (row_type == DJSON_TYPE_OBJECT) DJSON_cache_putchartofile(fhnd,stream,stream_pos,'{'); else DJSON_cache_putchartofile(fhnd,stream,stream_pos,'[');
  493. c_d++;
  494. format(cur_path[c_d],DJSON_MAX_STRING,"%s",row_path);
  495. cur_parent[c_d] = row_id;
  496. cur_type[c_d] = row_type;
  497. cur_el[c_d] = 0;
  498. }
  499. has_next = db_next_row(res);
  500. if (has_next) {
  501. db_get_field(res,0,row_path,DJSON_MAX_STRING);
  502. db_get_field(res,1,row_value,DJSON_MAX_STRING);
  503. db_get_field(res,2,tmp,DJSON_MAX_STRING);
  504. row_type = strval(tmp);
  505. db_get_field(res,3,tmp,DJSON_MAX_STRING);
  506. row_id = strval(tmp);
  507. db_get_field(res,4,tmp,DJSON_MAX_STRING);
  508. row_parent = strval(tmp);
  509. } else {
  510. row_id = 0;
  511. }
  512. }
  513. while (0 != cur_parent[c_d]) {
  514. // this is not the correct parent yet, so we need to get down.
  515. if (cur_type[c_d] == DJSON_TYPE_OBJECT) DJSON_cache_putchartofile(fhnd,stream,stream_pos,'}'); else DJSON_cache_putchartofile(fhnd,stream,stream_pos,']');
  516. c_d--;
  517. }
  518. DJSON_cache_putchartofile(fhnd,stream,stream_pos,'}');
  519. if (stream_pos>0) {
  520. stream[stream_pos]=0;
  521. fwrite(fhnd,stream);
  522. }
  523. fclose(fhnd);
  524. db_free_result(res);
  525. return true;
  526. }
  527. #if DJSON_ALLOW_STYLED_OUTPUT
  528. /**
  529. * @access private
  530. * @ingroup private
  531. */
  532. stock DJSON_cache_save_file_indented(file[],tofile[]) {
  533. new DBResult:res;
  534. new query[DJSON_MAX_STRING];
  535. format(query,DJSON_MAX_STRING,"SELECT `path`,`value`,`type`,`id`,`parent`,`pos` FROM `c` WHERE file='%s' ORDER BY `path`",DJSON_sql_escape(file));
  536. res = db_query(DJSON_cache_db,query);
  537. new has_next = db_num_rows(res) != 0;
  538. new cur_parent[DJSON_MAX_DEPTH];
  539. new cur_type[DJSON_MAX_DEPTH];
  540. new cur_el[DJSON_MAX_DEPTH];
  541. new cur_path[DJSON_MAX_DEPTH][DJSON_MAX_STRING];
  542. new c_d = 0;
  543. new tmp[DJSON_MAX_STRING];
  544. cur_parent[c_d]=0;
  545. cur_type[c_d]=DJSON_TYPE_OBJECT;
  546. cur_el[c_d]=0;
  547. cur_path[c_d][0]=0;
  548. new row_path[DJSON_MAX_STRING];
  549. new row_value[DJSON_MAX_STRING];
  550. new row_id = 0;
  551. new row_parent = 0;
  552. new row_type = 0;
  553. new File:fhnd=fopen(tofile,io_write);
  554. new stream[DJSON_MAX_STRING];
  555. new stream_pos = 0;
  556. if (!fhnd) {
  557. format(DJSON_LastError,DJSON_MAX_STRING,"Can not open File for writing!");
  558. DJSON_LastErrorCode = 2;
  559. return false;
  560. }
  561. if (has_next) {
  562. db_get_field(res,0,row_path,DJSON_MAX_STRING);
  563. db_get_field(res,1,row_value,DJSON_MAX_STRING);
  564. db_get_field(res,2,tmp,DJSON_MAX_STRING);
  565. row_type = strval(tmp);
  566. db_get_field(res,3,tmp,DJSON_MAX_STRING);
  567. row_id = strval(tmp);
  568. db_get_field(res,4,tmp,DJSON_MAX_STRING);
  569. row_parent = strval(tmp);
  570. }
  571. DJSON_cache_putchartofile(fhnd,stream, stream_pos,'{');
  572. new indention_string[DJSON_MAX_STRING];
  573. format(indention_string,DJSON_MAX_STRING,"\r\n ");
  574. while (row_id != 0) {
  575. while (row_parent != cur_parent[c_d]) {
  576. // this is not the correct parent yet, so we need to get down.
  577. format(indention_string,DJSON_MAX_STRING,"\r\n%s",indention_string[4]);
  578. DJSON_cache_putstringtofile(fhnd,stream,stream_pos,indention_string);
  579. if (cur_type[c_d] == DJSON_TYPE_OBJECT) DJSON_cache_putchartofile(fhnd,stream,stream_pos,'}'); else DJSON_cache_putchartofile(fhnd,stream,stream_pos,']');
  580. c_d--;
  581. }
  582. if (cur_type[c_d] == DJSON_TYPE_OBJECT || cur_type[c_d] == DJSON_TYPE_ARRAY) {
  583. cur_el[c_d]++;
  584. if (cur_el[c_d]>1) {
  585. DJSON_cache_putchartofile(fhnd,stream,stream_pos,',');
  586. }
  587. }
  588. DJSON_cache_putstringtofile(fhnd,stream,stream_pos,indention_string);
  589. if (cur_type[c_d] == DJSON_TYPE_OBJECT) {
  590. DJSON_cache_putchartofile(fhnd,stream,stream_pos,'"');
  591. if (strlen(cur_path[c_d])>0) {
  592. DJSON_cache_putstringtofile(fhnd,stream,stream_pos,row_path[strlen(cur_path[c_d])+1]);
  593. } else {
  594. DJSON_cache_putstringtofile(fhnd,stream,stream_pos,row_path);
  595. }
  596. DJSON_cache_putchartofile(fhnd,stream,stream_pos,'"');
  597. DJSON_cache_putchartofile(fhnd,stream,stream_pos,':');
  598. }
  599. if (row_type == DJSON_TYPE_NUMBER) {
  600. DJSON_cache_putstringtofile(fhnd,stream,stream_pos,row_value);
  601. }
  602. if (row_type == DJSON_TYPE_STRING) {
  603. DJSON_cache_putchartofile(fhnd,stream,stream_pos,'"');
  604. DJSON_cache_putstringtofile(fhnd,stream,stream_pos,DJSON_json_escape(row_value));
  605. DJSON_cache_putchartofile(fhnd,stream,stream_pos,'"');
  606. }
  607. if (row_type == DJSON_TYPE_OBJECT || row_type == DJSON_TYPE_ARRAY) {
  608. if (row_type == DJSON_TYPE_OBJECT) DJSON_cache_putchartofile(fhnd,stream,stream_pos,'{'); else DJSON_cache_putchartofile(fhnd,stream,stream_pos,'[');
  609. format(indention_string,DJSON_MAX_STRING,"%s ",indention_string);
  610. c_d++;
  611. format(cur_path[c_d],DJSON_MAX_STRING,"%s",row_path);
  612. cur_parent[c_d] = row_id;
  613. cur_type[c_d] = row_type;
  614. cur_el[c_d] = 0;
  615. }
  616. has_next = db_next_row(res);
  617. if (has_next) {
  618. db_get_field(res,0,row_path,DJSON_MAX_STRING);
  619. db_get_field(res,1,row_value,DJSON_MAX_STRING);
  620. db_get_field(res,2,tmp,DJSON_MAX_STRING);
  621. row_type = strval(tmp);
  622. db_get_field(res,3,tmp,DJSON_MAX_STRING);
  623. row_id = strval(tmp);
  624. db_get_field(res,4,tmp,DJSON_MAX_STRING);
  625. row_parent = strval(tmp);
  626. } else {
  627. row_id = 0;
  628. }
  629. }
  630. while (0 != cur_parent[c_d]) {
  631. // this is not the correct parent yet, so we need to get down.
  632. format(indention_string,DJSON_MAX_STRING,"\r\n%s",indention_string[4]);
  633. DJSON_cache_putstringtofile(fhnd,stream,stream_pos,indention_string);
  634. if (cur_type[c_d] == DJSON_TYPE_OBJECT) DJSON_cache_putchartofile(fhnd,stream,stream_pos,'}'); else DJSON_cache_putchartofile(fhnd,stream,stream_pos,']');
  635. c_d--;
  636. }
  637. DJSON_cache_putstringtofile(fhnd,stream,stream_pos,"\r\n");
  638. DJSON_cache_putchartofile(fhnd,stream,stream_pos,'}');
  639. if (stream_pos>0) {
  640. stream[stream_pos]=0;
  641. fwrite(fhnd,stream);
  642. }
  643. fclose(fhnd);
  644. db_free_result(res);
  645. return true;
  646. }
  647. #endif
  648. /**
  649. * @access private
  650. * @ingroup private
  651. */
  652. stock DJSON_cache_debug_print() {
  653. new DBResult:res;
  654. res = db_query(DJSON_cache_db,"SELECT `file`,`path`,`value`,`type`,`id`,`parent`,`pos` FROM `c` ORDER BY path");
  655. new i = 0;
  656. new file[DJSON_MAX_STRING];
  657. new key[DJSON_MAX_STRING];
  658. new value[DJSON_MAX_STRING];
  659. new type[DJSON_MAX_STRING];
  660. new id[DJSON_MAX_STRING];
  661. new pos[DJSON_MAX_STRING];
  662. new parent[DJSON_MAX_STRING];
  663. new has_next = db_num_rows(res) != 0;
  664. new cur_file[DJSON_MAX_STRING] = "\\";
  665. while (has_next) {
  666. i++;
  667. db_get_field(res,0,file,DJSON_MAX_STRING);
  668. db_get_field(res,1,key,DJSON_MAX_STRING);
  669. db_get_field(res,2,value,DJSON_MAX_STRING);
  670. db_get_field(res,3,type,DJSON_MAX_STRING);
  671. db_get_field(res,4,id,DJSON_MAX_STRING);
  672. db_get_field(res,5,parent,DJSON_MAX_STRING);
  673. db_get_field(res,6,pos,DJSON_MAX_STRING);
  674. new type_id = strval(type);
  675. if (type_id == 0) {
  676. type = "---";
  677. } else if (type_id == DJSON_TYPE_ARRAY) {
  678. type = "ARR";
  679. } else if (type_id == DJSON_TYPE_OBJECT) {
  680. type = "OBJ";
  681. } else if (type_id == DJSON_TYPE_NUMBER) {
  682. type = "NUM";
  683. } else if (type_id == DJSON_TYPE_STRING) {
  684. type = "STR";
  685. }
  686. new line[DJSON_MAX_STRING];
  687. if (strcmp(cur_file,file,true)) {
  688. printf(">>%s<<",file);
  689. cur_file = file;
  690. }
  691. format(line,DJSON_MAX_STRING," [%s/%s/%s] '%s' #%s / value:'%s'",id,parent,type,key,pos,value);
  692. print(line);
  693. has_next = db_next_row(res);
  694. }
  695. db_free_result(res);
  696. }
  697. #define DJSON_STATE_A 1
  698. #define DJSON_STATE_B 2
  699. #define DJSON_STATE_C 3
  700. #define DJSON_STATE_D 4
  701. #define DJSON_STATE_E 5
  702. #define DJSON_STATE_F 6
  703. #define DJSON_STATE_C2 7
  704. #define DJSON_STATE_C3 8
  705. #define DJSON_STATE_C4 9
  706. #define DJSON_STATE_C5 10
  707. #define DJSON_STATE_D2 11
  708. #define DJSON_STATE_F2 12
  709. #define DJSON_STATE_B2 13
  710. #define DJSON_STATE_C6 14
  711. #define DJSON_STATE_G 15
  712. /**
  713. * @access private
  714. * @ingroup private
  715. */
  716. stock DJSON_cache_UnloadFile(filename[]) {
  717. new query[DJSON_MAX_STRING];
  718. format(query,DJSON_MAX_STRING,"DELETE FROM `c` WHERE file='%s'",DJSON_sql_escape(filename));
  719. db_query(DJSON_cache_db,query);
  720. format(query,DJSON_MAX_STRING,"DELETE FROM `is_c` WHERE file='%s'",DJSON_sql_escape(filename));
  721. db_query(DJSON_cache_db,query);
  722. }
  723. /**
  724. * @access private
  725. * @ingroup private
  726. */
  727. stock DJSON_cache_IsFileCached(filename[]) {
  728. new query[DJSON_MAX_STRING];
  729. new DBResult:res;
  730. format(query,DJSON_MAX_STRING,"SELECT * FROM `is_c` WHERE file='%s'",DJSON_sql_escape(filename));
  731. res = db_query(DJSON_cache_db,query);
  732. new is_cached = db_num_rows(res) != 0;
  733. db_free_result(res);
  734. return is_cached;
  735. }
  736. /**
  737. * @access private
  738. * @ingroup private
  739. */
  740. stock DJSON_cache_ReloadFile(filename[]) {
  741. DJSON_cache_UnloadFile(filename);
  742. new path_pos = 0;
  743. new states[DJSON_MAX_DEPTH];
  744. new states_pos = 0;
  745. new s = DJSON_STATE_A;
  746. new pos = 0;
  747. new File:fohnd;
  748. new c=0;
  749. fohnd=fopen(filename,io_read);
  750. if (!fohnd) {
  751. format(DJSON_LastError,DJSON_MAX_STRING,"Can not open file %s",filename);
  752. DJSON_LastErrorCode = 1;
  753. return false;
  754. }
  755. c = fgetchar(fohnd,1);
  756. new cur_str[DJSON_MAX_STRING];
  757. new bool:dont_read_next = false;
  758. while (c!=-1 && s != DJSON_STATE_G) {
  759. while (c!=-1 && (
  760. s == DJSON_STATE_C4 ||
  761. s == DJSON_STATE_C5 ||
  762. s == DJSON_STATE_C6 ||
  763. s == DJSON_STATE_C ||
  764. s == DJSON_STATE_B ||
  765. s == DJSON_STATE_B2 ||
  766. s == DJSON_STATE_A
  767. ) && c<33
  768. ) {
  769. pos++;
  770. c = fgetchar(fohnd,1);
  771. if (c==-1) c=-1;
  772. }
  773. if (c==-1) {
  774. fclose(fohnd);
  775. return true;
  776. }
  777. if (s == DJSON_STATE_A) {
  778. if (c == '[') {
  779. s = DJSON_STATE_B;
  780. format(DJSON_path[path_pos],DJSON_MAX_STRING,"%d",0);
  781. DJSON_path_type[path_pos] = DJSON_TYPE_ARRAY;
  782. DJSON_path_id[path_pos] = DJSON_cache_createArrayNode(filename,DJSON_implode('/',path_pos),DJSON_path_id[path_pos-1],DJSON_path_arraypos[path_pos-1]-1);
  783. DJSON_path_arraypos[path_pos]=1;
  784. path_pos++;
  785. } else if (c == '{') {
  786. s = DJSON_STATE_C;
  787. DJSON_path_type[path_pos] = DJSON_TYPE_OBJECT;
  788. DJSON_path_id[path_pos] = path_pos==0 ? 0 : DJSON_cache_createObjectNode(filename,DJSON_implode('/',path_pos),path_pos==0 ? 0 : DJSON_path_id[path_pos-1],path_pos==0 ? -1 : DJSON_path_arraypos[path_pos-1]-1);
  789. } else if (c == '"') {
  790. cur_str[0] = 0;
  791. s = DJSON_STATE_D;
  792. } else if (c == '0') {
  793. format(cur_str,DJSON_MAX_STRING,"0");
  794. s = DJSON_STATE_E;
  795. } else if (c == '-') {
  796. format(cur_str,DJSON_MAX_STRING,"%c",c);
  797. s = DJSON_STATE_F;
  798. } else if (c > '0' && c<='9') {
  799. format(cur_str,DJSON_MAX_STRING,"%c",c);
  800. s = DJSON_STATE_F;
  801. } else {
  802. format(DJSON_LastError,DJSON_MAX_STRING,"'Invalid Token %s in DJSON_STATE_A'",c);
  803. DJSON_LastErrorCode = 2;
  804. fclose(fohnd);
  805. return false;
  806. }
  807. } else if (s == DJSON_STATE_B) {
  808. if (c == ']') {
  809. path_pos--;
  810. s = DJSON_STATE_G;
  811. } else {
  812. states[states_pos]=DJSON_STATE_B2;
  813. states_pos++;
  814. s = DJSON_STATE_A;
  815. dont_read_next = true;
  816. }
  817. } else if (s == DJSON_STATE_B2) {
  818. if (c == ']') {
  819. path_pos--;
  820. s = DJSON_STATE_G;
  821. } else if (c == ',') {
  822. DJSON_path_arraypos[path_pos-1]++;
  823. format(DJSON_path[path_pos-1],DJSON_MAX_STRING,"%d",DJSON_path_arraypos[path_pos-1]-1);
  824. states[states_pos]=DJSON_STATE_B2;
  825. states_pos++;
  826. s = DJSON_STATE_A;
  827. } else {
  828. format(DJSON_LastError,DJSON_MAX_STRING,"'Invalid Token %c in DJSON_STATE_B2'",c);
  829. DJSON_LastErrorCode = 2;
  830. fclose(fohnd);
  831. return false;
  832. }
  833. } else if (s == DJSON_STATE_C) {
  834. if (c == '}') {
  835. s = DJSON_STATE_G;
  836. } else if (c == '"') {
  837. cur_str[0] = 0;
  838. s = DJSON_STATE_C2;
  839. } else {
  840. format(DJSON_LastError,DJSON_MAX_STRING,"'Invalid Token %c in DJSON_STATE_C'",c);
  841. DJSON_LastErrorCode = 2;
  842. fclose(fohnd);
  843. return false;
  844. }
  845. } else if (s == DJSON_STATE_C2) {
  846. if (c == '"') {
  847. s = DJSON_STATE_C4;
  848. } else if (c == '\\') {
  849. s = DJSON_STATE_C3;
  850. } else {
  851. format(cur_str,DJSON_MAX_STRING,"%s%c",cur_str,c);
  852. }
  853. } else if (s == DJSON_STATE_C3) {
  854. // escaper in string
  855. if (c == '\\') {
  856. strcat(cur_str,"\\");
  857. } else if (c == 'n') {
  858. strcat(cur_str,"\n");
  859. } else if (c == 'b') {
  860. strcat(cur_str,"\b");
  861. } else if (c == 'f') {
  862. strcat(cur_str,"\f");
  863. } else if (c == '"') {
  864. strcat(cur_str,"\"");
  865. } else if (c == 'r') {
  866. strcat(cur_str,"\r");
  867. } else if (c == 't') {
  868. strcat(cur_str,"\t");
  869. format(cur_str,DJSON_MAX_STRING,"%s\t",cur_str);
  870. } else {
  871. format(DJSON_LastError,DJSON_MAX_STRING,"'Invalid Token %c in DJSON_STATE_C3'",c);
  872. DJSON_LastErrorCode = 2;
  873. fclose(fohnd);
  874. return false;
  875. }
  876. s = DJSON_STATE_C2;
  877. } else if (s == DJSON_STATE_C4) {
  878. if (c == ':') {
  879. format(DJSON_path[path_pos],DJSON_MAX_STRING,"%s",cur_str);
  880. path_pos++;
  881. states[states_pos]=DJSON_STATE_C6;
  882. states_pos++;
  883. s = DJSON_STATE_A;
  884. } else {
  885. format(DJSON_LastError,DJSON_MAX_STRING,"'Invalid Token %c in DJSON_STATE_C4'",c);
  886. DJSON_LastErrorCode = 2;
  887. fclose(fohnd);
  888. return false;
  889. }
  890. } else if (s == DJSON_STATE_C5) {
  891. if (c == '"') {
  892. cur_str[0]=0;
  893. s = DJSON_STATE_C2;
  894. } else {
  895. format(DJSON_LastError,DJSON_MAX_STRING,"'Invalid Token %c in DJSON_STATE_C5'",c);
  896. DJSON_LastErrorCode = 2;
  897. fclose(fohnd);
  898. return false;
  899. }
  900. } else if (s == DJSON_STATE_C6) {
  901. if (c == '}') {
  902. path_pos--;
  903. s = DJSON_STATE_G;
  904. } else if (c == ',') {
  905. path_pos--;
  906. s = DJSON_STATE_C5;
  907. } else {
  908. format(DJSON_LastError,DJSON_MAX_STRING,"'Invalid Token %c in DJSON_STATE_C6'",c);
  909. DJSON_LastErrorCode = 2;
  910. fclose(fohnd);
  911. return false;
  912. }
  913. } else if (s == DJSON_STATE_D) {
  914. // string
  915. if (c == '\\') {
  916. s = DJSON_STATE_D2;
  917. } else if (c == '"') {
  918. DJSON_cache_createString(filename,DJSON_implode('/',path_pos),cur_str,DJSON_path_id[path_pos-1],DJSON_path_arraypos[path_pos-1]-1);
  919. s = DJSON_STATE_G;
  920. } else {
  921. format(cur_str,DJSON_MAX_STRING,"%s%c",cur_str,c);
  922. }
  923. } else if (s == DJSON_STATE_D2) {
  924. // escaper in string
  925. if (c == '\\') {
  926. format(cur_str,DJSON_MAX_STRING,"%s\\",cur_str);
  927. } else if (c == 'n') {
  928. format(cur_str,DJSON_MAX_STRING,"%s\n",cur_str);
  929. } else if (c == 'b') {
  930. format(cur_str,DJSON_MAX_STRING,"%s\b",cur_str);
  931. } else if (c == 'f') {
  932. format(cur_str,DJSON_MAX_STRING,"%s\f",cur_str);
  933. } else if (c == '"') {
  934. format(cur_str,DJSON_MAX_STRING,"%s\"",cur_str);
  935. } else if (c == 'r') {
  936. format(cur_str,DJSON_MAX_STRING,"%s\r",cur_str);
  937. } else if (c == 't') {
  938. format(cur_str,DJSON_MAX_STRING,"%s\t",cur_str);
  939. } else {
  940. format(DJSON_LastError,DJSON_MAX_STRING,"'Invalid Token %c in DJSON_STATE_D2'",c);
  941. DJSON_LastErrorCode = 2;
  942. fclose(fohnd);
  943. return false;
  944. }
  945. s = DJSON_STATE_D;
  946. } else if (s == DJSON_STATE_E) {
  947. if (c == '.') {
  948. format(cur_str,DJSON_MAX_STRING,"%s.",cur_str);
  949. s = DJSON_STATE_F2;
  950. } else {
  951. DJSON_cache_createNumberFromStr(filename,DJSON_implode('/',path_pos),cur_str,DJSON_path_id[path_pos-1],DJSON_path_arraypos[path_pos-1]-1);
  952. dont_read_next=true;
  953. s = DJSON_STATE_G;
  954. }
  955. } else if (s == DJSON_STATE_F) {
  956. if (c >= '0' && c<='9') {
  957. format(cur_str,DJSON_MAX_STRING,"%s%c",cur_str,c);
  958. } else if (c=='.') {
  959. format(cur_str,DJSON_MAX_STRING,"%s%c",cur_str,c);
  960. s = DJSON_STATE_F2;
  961. } else {
  962. DJSON_cache_createNumberFromStr(filename,DJSON_implode('/',path_pos),cur_str,DJSON_path_id[path_pos-1],DJSON_path_arraypos[path_pos-1]-1);
  963. dont_read_next=true;
  964. s = DJSON_STATE_G;
  965. }
  966. } else if (s == DJSON_STATE_F2) {
  967. if (c >= '0' && c<='9') {
  968. format(cur_str,DJSON_MAX_STRING,"%s%c",cur_str,c);
  969. } else {
  970. DJSON_cache_createNumberFromStr(filename,DJSON_implode('/',path_pos),cur_str,DJSON_path_id[path_pos-1],DJSON_path_arraypos[path_pos-1]-1);
  971. dont_read_next=true;
  972. s = DJSON_STATE_G;
  973. }
  974. } else {
  975. format(DJSON_LastError,DJSON_MAX_STRING,"'Invalid State %d'",s);
  976. DJSON_LastErrorCode = 3;
  977. fclose(fohnd);
  978. return false;
  979. }
  980. if (!dont_read_next) {
  981. pos++;
  982. c = fgetchar(fohnd,1);
  983. } else {
  984. dont_read_next = false;
  985. }
  986. if (s == DJSON_STATE_G) {
  987. if (states_pos!=0) {
  988. states_pos--;
  989. s = states[states_pos];
  990. }
  991. }
  992. }
  993. DJSON_LastErrorCode = 0;
  994. new query[DJSON_MAX_STRING];
  995. format(query,DJSON_MAX_STRING,"INSERT INTO `is_c` (`file`) VALUES ('%s')",DJSON_sql_escape(filename));
  996. db_query(DJSON_cache_db,query);
  997. fclose(fohnd);
  998. return true;
  999. }
  1000. /**
  1001. * @access private
  1002. * @ingroup private
  1003. * @return int id of the element
  1004. */
  1005. stock DJSON_prepareTreeForPath(file[],path[]) {
  1006. if (!DJSON_cache_IsFileCached(file)) {
  1007. DJSON_cache_ReloadFile(file);
  1008. if (DJSON_LastErrorCode == 1) {
  1009. new File:fhnd = fopen(file,io_write);
  1010. if (!fhnd) {
  1011. // ok, we can't even create it!
  1012. return 0;
  1013. }
  1014. fwrite(fhnd,"{}");
  1015. fclose(fhnd);
  1016. }
  1017. }
  1018. new query[DJSON_MAX_STRING];
  1019. // Secure, that everypart is available:
  1020. new path_len = strlen(path);
  1021. new current_path_depth=0;
  1022. new current_path_part[DJSON_MAX_STRING];
  1023. new current_path_part_len = 0;
  1024. new current_path[DJSON_MAX_DEPTH][DJSON_MAX_STRING];
  1025. new parent_id = 0;
  1026. new tmp[DJSON_MAX_STRING];
  1027. new our_current_path[DJSON_MAX_STRING];
  1028. for (new i=0;i<path_len;i++) {
  1029. if (path[i]=='/') {
  1030. if (current_path_part_len == 0) {
  1031. DJSON_LastErrorCode = 6;
  1032. format(DJSON_LastError,DJSON_MAX_STRING,"The path %s is invalid",path);
  1033. return 0;
  1034. }
  1035. new DBResult:res;
  1036. format(our_current_path,DJSON_MAX_STRING,"%s",DJSON_ret_memcpy(path,0,i));
  1037. format(query,DJSON_MAX_STRING,"SELECT id,`type`,`pos` FROM `c` WHERE file = '%s' AND path = '%s' LIMIT 1",DJSON_sql_escape(file),our_current_path);
  1038. res = db_query(DJSON_cache_db,query);
  1039. if (db_num_rows(res) == 1) {
  1040. // it exists
  1041. db_get_field(res,2,query,DJSON_MAX_STRING);
  1042. new prev_pos = strval(query);
  1043. db_get_field(res,0,query,DJSON_MAX_STRING);
  1044. new prev_parent_id = parent_id;
  1045. parent_id = strval(query);
  1046. db_get_field(res,1,tmp,DJSON_MAX_STRING);
  1047. db_free_result(res);
  1048. if (strval(tmp)!=DJSON_TYPE_OBJECT && strval(tmp)!=DJSON_TYPE_ARRAY) {
  1049. // it is _no_ object nor an array, so we have to remove it :/.
  1050. format(query,DJSON_MAX_STRING,"DELETE FROM `c` WHERE file = '%s' AND path = '%s'",DJSON_sql_escape(file),our_current_path);
  1051. db_query(DJSON_cache_db,query);
  1052. format(query,DJSON_MAX_STRING,"DELETE FROM `c` WHERE file = '%s' AND path LIKE '%s/%s'",DJSON_sql_escape(file),our_current_path,"%");
  1053. db_query(DJSON_cache_db,query);
  1054. parent_id = DJSON_cache_createObjectNode(file,DJSON_ret_memcpy(path,0,i),prev_parent_id,prev_pos);
  1055. }
  1056. } else {
  1057. // The something/this is missing, so we can't create something/this/that
  1058. // thatswhy we create something/this first
  1059. db_free_result(res);
  1060. parent_id = DJSON_cache_createObjectNode(file,DJSON_ret_memcpy(path,0,i),parent_id);
  1061. }
  1062. format(current_path[current_path_depth],DJSON_MAX_STRING,"%s",current_path_part);
  1063. current_path_depth++;
  1064. current_path_part_len=0;
  1065. current_path_part[0]=0;
  1066. } else {
  1067. current_path_part[current_path_part_len] = path[i];
  1068. current_path_part_len++;
  1069. }
  1070. }
  1071. // Unset its children
  1072. format(query,DJSON_MAX_STRING,"DELETE FROM `c` WHERE file = '%s' AND path LIKE '%s/%s'",DJSON_sql_escape(file),DJSON_sql_escape(path),"%");
  1073. db_query(DJSON_cache_db,query);
  1074. new DBResult:res;
  1075. format(query,DJSON_MAX_STRING,"SELECT id,`type` FROM `c` WHERE file = '%s' AND path = '%s' LIMIT 1",DJSON_sql_escape(file),path);
  1076. res = db_query(DJSON_cache_db,query);
  1077. if (db_num_rows(res) != 1) {
  1078. db_free_result(res);
  1079. // it does not exist, let's create it!
  1080. return DJSON_cache_createString(file,path,"",parent_id);
  1081. } else {
  1082. // it does exist, great!
  1083. db_get_field(res,0,query,DJSON_MAX_STRING);
  1084. new id = strval(query);
  1085. db_free_result(res);
  1086. return id;
  1087. }
  1088. }
  1089. /**
  1090. * Calculate the Items of a djson-Array
  1091. *
  1092. * @param string file Name of the file
  1093. * @param string path Path you want to count
  1094. * @param bool use_cached_value Set this to false, if you want to reload the file everytime
  1095. * @ingroup djson
  1096. * @return int Number of items in the djson Array
  1097. */
  1098. stock djCount(file[],path[],use_cached_value=true) {
  1099. DJSON_LastErrorCode=0;
  1100. if (!DJSON_cache_IsFileCached(file) || !use_cached_value) DJSON_cache_ReloadFile(file);
  1101. new query[DJSON_MAX_STRING];
  1102. new DBResult:res;
  1103. format(query,DJSON_MAX_STRING,"SELECT id,type FROM `c` WHERE file = '%s' AND path = '%s' LIMIT 1",DJSON_sql_escape(file),DJSON_sql_escape(path));
  1104. res = db_query(DJSON_cache_db,query);
  1105. new parent_id;
  1106. if (db_num_rows(res) == 1) {
  1107. // it exists ...
  1108. db_get_field(res,0,query,DJSON_MAX_STRING);
  1109. parent_id = strval(query);
  1110. db_get_field(res,1,query,DJSON_MAX_STRING);
  1111. db_free_result(res);
  1112. if (strval(query)!=DJSON_TYPE_ARRAY) {
  1113. format(DJSON_LastError,DJSON_MAX_STRING,"The path %s, is not an array!",path);
  1114. DJSON_LastErrorCode = 7;
  1115. return 0;
  1116. }
  1117. } else {
  1118. db_free_result(res);
  1119. // does not exist!
  1120. return 0;
  1121. }
  1122. format(query,DJSON_MAX_STRING,"SELECT COUNT(pos) m_p FROM `c` WHERE file = '%s' AND parent = %d",DJSON_sql_escape(file),parent_id);
  1123. res = db_query(DJSON_cache_db,query);
  1124. if (db_num_rows(res) == 1) {
  1125. db_get_field(res,0,query,DJSON_MAX_STRING);
  1126. db_free_result(res);
  1127. return strval(query);
  1128. } else {
  1129. db_free_result(res);
  1130. return 0;
  1131. }
  1132. }
  1133. /**
  1134. * Checks if a specific path in the json-file exists
  1135. *
  1136. * Example:
  1137. * djIsSet("draco.json","player/name")
  1138. * will return true if the draco.json looks like that:
  1139. * {"player":{"name":"DracoBlue"}}
  1140. * @param string file Name of the json file
  1141. * @param string path Name of the path in the file
  1142. * @param bool use_cached_value Set this to false, if you want to reload the file everytime
  1143. * @return bool If the path is available
  1144. * @ingroup djson
  1145. */
  1146. stock djIsSet(file[],path[],use_cached_value=true) {
  1147. DJSON_LastErrorCode=0;
  1148. if (!DJSON_cache_IsFileCached(file) || !use_cached_value) DJSON_cache_ReloadFile(file);
  1149. new query[DJSON_MAX_STRING];
  1150. if (DJSON_LastErrorCode) {
  1151. return false;
  1152. }
  1153. new DBResult:res;
  1154. format(query,DJSON_MAX_STRING,"SELECT `value` FROM `c` WHERE file = '%s' AND path = '%s' LIMIT 1",DJSON_sql_escape(file),DJSON_sql_escape(path));
  1155. res = db_query(DJSON_cache_db,query);
  1156. if (db_num_rows(res) == 1) {
  1157. db_free_result(res);
  1158. return true;
  1159. } else {
  1160. db_free_result(res);
  1161. return false;
  1162. }
  1163. }
  1164. /**
  1165. * Unsets a specific path in a json-file
  1166. *
  1167. * Example:
  1168. * djUnset("draco.json","player/pos")
  1169. * will unset
  1170. * {"player":{"name":"DracoBlue"}}
  1171. * @param string file Name of the json file
  1172. * @param string path Name of the path in the file
  1173. * @param bool use_cached_value Set this to false, if you want to reload the file everytime
  1174. * @return bool If it was posssible to unset the value
  1175. * @see djAutocommit
  1176. * @see djCommit
  1177. * @ingroup djson
  1178. */
  1179. stock djUnset(file[],path[],use_cached_value=true) {
  1180. DJSON_LastErrorCode=0;
  1181. if (!DJSON_cache_IsFileCached(file) || !use_cached_value) DJSON_cache_ReloadFile(file);
  1182. new query[DJSON_MAX_STRING];
  1183. if (DJSON_LastErrorCode) {
  1184. return false;
  1185. }
  1186. // let's find out, if the entry is an item of an array
  1187. new DBResult:res;
  1188. format(query,DJSON_MAX_STRING,"SELECT parent,pos FROM `c` WHERE file = '%s' AND path = '%s' LIMIT 1",DJSON_sql_escape(file),DJSON_sql_escape(path));
  1189. res = db_query(DJSON_cache_db,query);
  1190. if (db_num_rows(res) == 1) {
  1191. // it exists ...
  1192. new parent_id, pos_in_array;
  1193. db_get_field(res,0,query,DJSON_MAX_STRING);
  1194. parent_id = strval(query);
  1195. db_get_field(res,1,query,DJSON_MAX_STRING);
  1196. pos_in_array = strval(query);
  1197. db_free_result(res);
  1198. // first of all: let's remove the item, we'll take care of the rest later!
  1199. format(query,DJSON_MAX_STRING,"DELETE FROM `c` WHERE file = '%s' AND path = '%s'",DJSON_sql_escape(file),DJSON_sql_escape(path));
  1200. db_query(DJSON_cache_db,query);
  1201. format(query,DJSON_MAX_STRING,"DELETE FROM `c` WHERE file = '%s' AND path LIKE '%s/%s'",DJSON_sql_escape(file),DJSON_sql_escape(path),"%");
  1202. db_query(DJSON_cache_db,query);
  1203. // is direct child of an array ?
  1204. if (pos_in_array!=-1) {
  1205. // so we need to rearrange the items now.
  1206. format(query,DJSON_MAX_STRING,"SELECT path FROM `c` WHERE file = '%s' AND id = %d LIMIT 1",DJSON_sql_escape(file),parent_id);
  1207. res = db_query(DJSON_cache_db,query);
  1208. new parent_path[DJSON_MAX_STRING];
  1209. db_get_field(res,0,parent_path,DJSON_MAX_STRING);
  1210. db_free_result(res);
  1211. new shifting_min = pos_in_array+1;
  1212. new shifting_max;
  1213. format(query,DJSON_MAX_STRING,"SELECT COUNT(id) m_p FROM `c` WHERE file = '%s' AND parent = %d",DJSON_sql_escape(file),parent_id);
  1214. res = db_query(DJSON_cache_db,query);
  1215. if (db_num_rows(res) == 1) {
  1216. db_get_field(res,0,query,DJSON_MAX_STRING);
  1217. shifting_max = strval(query);
  1218. } else {
  1219. shifting_max = shifting_min;
  1220. }
  1221. db_free_result(res);
  1222. new shifting_pos = shifting_min - 1;
  1223. new its_id = 0;
  1224. new has_next = false;
  1225. while (shifting_pos<shifting_max) {
  1226. shifting_pos++;
  1227. // receive all items, which are in children of the parts, except the direct children!
  1228. format(query,DJSON_MAX_STRING,"SELECT id,path FROM `c` WHERE file = '%s' AND path LIKE '%s/%d/%s'",DJSON_sql_escape(file),DJSON_sql_escape(parent_path),shifting_pos,"%");
  1229. res = db_query(DJSON_cache_db,query);
  1230. has_next = (db_num_rows(res) > 0);
  1231. while (has_next) {
  1232. db_get_field(res,0,query,DJSON_MAX_STRING);
  1233. its_id = strval(query);
  1234. db_get_field(res,1,query,DJSON_MAX_STRING);
  1235. // query = items path, its_id = id
  1236. format(query,DJSON_MAX_STRING,"UPDATE `c` SET path='%s/%d%s' WHERE file = '%s' AND id = %d",DJSON_sql_escape(parent_path),shifting_pos-1,query[strlen(parent_path)+floatround(shifting_pos/10)+2],DJSON_sql_escape(file),its_id);
  1237. db_query(DJSON_cache_db,query);
  1238. has_next = db_next_row(res);
  1239. }
  1240. db_free_result(res);
  1241. }
  1242. // receive all items now, which are direct children!
  1243. format(query,DJSON_MAX_STRING,"SELECT id,pos FROM `c` WHERE file = '%s' AND parent=%d AND pos>%d",DJSON_sql_escape(file),parent_id,shifting_min-1);
  1244. res = db_query(DJSON_cache_db,query);
  1245. has_next = (db_num_rows(res) > 0);
  1246. new cur_pos = 0;
  1247. while (has_next) {
  1248. db_get_field(res,0,query,DJSON_MAX_STRING);
  1249. its_id = strval(query);
  1250. db_get_field(res,1,query,DJSON_MAX_STRING);
  1251. cur_pos = strval(query);
  1252. format(query,DJSON_MAX_STRING,"UPDATE `c` SET path='%s/%d',pos=%d WHERE file = '%s' AND id = %d",DJSON_sql_escape(parent_path),cur_pos-1,cur_pos-1,DJSON_sql_escape(file),its_id);
  1253. db_query(DJSON_cache_db,query);
  1254. has_next = db_next_row(res);
  1255. }
  1256. db_free_result(res);
  1257. }
  1258. if (DJSON_autocommit) djCommit(file);
  1259. return true;
  1260. } else {
  1261. // it does not ..., but it's unset: true!
  1262. db_free_result(res);
  1263. return true;
  1264. }
  1265. }
  1266. /**
  1267. * Append an item to a djson-Array
  1268. * @param string file Name of the file
  1269. * @param string path Path you want to append to
  1270. * @param string value String you want to append
  1271. * @param bool use_cached_value Set this to false, if you want to reload the file every time
  1272. * @return bool If it was possible to append the value
  1273. * @ingroup djson
  1274. * @see djAutocommit
  1275. * @see djCommit
  1276. */
  1277. stock djAppend(file[],path[],value[],use_cached_value=true) {
  1278. DJSON_LastErrorCode=0;
  1279. if (!DJSON_cache_IsFileCached(file) || !use_cached_value) DJSON_cache_ReloadFile(file);
  1280. new query[DJSON_MAX_STRING];
  1281. if (DJSON_LastErrorCode) {
  1282. return false;
  1283. }
  1284. // let's find out, if the entry is an item of an array
  1285. new DBResult:res;
  1286. new parent_id;
  1287. format(query,DJSON_MAX_STRING,"SELECT id,type FROM `c` WHERE file = '%s' AND path = '%s' LIMIT 1",DJSON_sql_escape(file),DJSON_sql_escape(path));
  1288. res = db_query(DJSON_cache_db,query);
  1289. new the_pos = 0;
  1290. if (db_num_rows(res) == 1) {
  1291. new row_type;
  1292. db_get_field(res,0,query,DJSON_MAX_STRING);
  1293. parent_id = strval(query);
  1294. db_get_field(res,1,query,DJSON_MAX_STRING);
  1295. row_type = strval(query);
  1296. db_free_result(res);
  1297. if (row_type != DJSON_TYPE_ARRAY) {
  1298. DJSON_LastErrorCode = 7;
  1299. format(DJSON_LastError,DJSON_MAX_STRING,"The path %s, is not an array!",path);
  1300. return false;
  1301. }
  1302. format(query,DJSON_MAX_STRING,"SELECT COUNT(pos) m_p FROM `c` WHERE file = '%s' AND parent = %d",DJSON_sql_escape(file),parent_id);
  1303. res = db_query(DJSON_cache_db,query);
  1304. if (db_num_rows(res) == 1) {
  1305. db_get_field(res,0,query,DJSON_MAX_STRING);
  1306. the_pos = strval(query);
  1307. } else {
  1308. the_pos = 0;
  1309. }
  1310. db_free_result(res);
  1311. } else {
  1312. db_free_result(res);
  1313. // it does not exist yet!
  1314. parent_id = DJSON_prepareTreeForPath(file,path);
  1315. // if creating the tree path, failed :(
  1316. if (DJSON_LastErrorCode) {
  1317. return false;
  1318. }
  1319. parent_id = DJSON_cache_updateArrayNode(file,path);
  1320. }
  1321. new tmp[DJSON_MAX_STRING];
  1322. format(tmp,DJSON_MAX_STRING,"%s/%d",path,the_pos);
  1323. DJSON_cache_createNode(file,tmp,DJSON_TYPE_STRING,value,parent_id,the_pos);
  1324. if (DJSON_autocommit) djCommit(file);
  1325. return true;
  1326. }
  1327. /**
  1328. * Set a specific path string value
  1329. *
  1330. * Example:
  1331. * djSet("draco.json","player/name","Hans")
  1332. * will set
  1333. * {"player":{"name":"Hans"}}
  1334. * @param string file Name of the json file
  1335. * @param string path Name of the path in the file
  1336. * @param string new_value The new value
  1337. * @param bool use_cached_value Set this to false, if you want to reload the file every time
  1338. * @return bool If it was posssible to set the value
  1339. * @see djAutocommit
  1340. * @see djCommit
  1341. * @ingroup djson
  1342. */
  1343. stock djSet(file[],path[],new_value[],use_cached_value=true) {
  1344. DJSON_LastErrorCode=0;
  1345. if (!DJSON_cache_IsFileCached(file) || !use_cached_value) DJSON_cache_ReloadFile(file);
  1346. DJSON_prepareTreeForPath(file,path);
  1347. // And update it:
  1348. DJSON_cache_updateString(file,path,new_value);
  1349. if (DJSON_autocommit) djCommit(file);
  1350. return true;
  1351. }
  1352. /**
  1353. * Set a specific path integer value
  1354. *
  1355. * Example:
  1356. * djSetInt("draco.json","player/id",5)
  1357. * will set
  1358. * {"player":{"name":"Hans","id":5}}
  1359. * @param string file Name of the json file
  1360. * @param string path Name of the path in the file
  1361. * @param int new_value The new value
  1362. * @param bool use_cached_value Set this to false, if you want to reload the file every time
  1363. * @return bool If it was posssible to set the value
  1364. * @see djAutocommit
  1365. * @see djCommit
  1366. * @ingroup djson
  1367. */
  1368. stock djSetInt(file[],path[],new_value,use_cached_value=true) {
  1369. DJSON_LastErrorCode=0;
  1370. if (!DJSON_cache_IsFileCached(file) || !use_cached_value) DJSON_cache_ReloadFile(file);
  1371. DJSON_prepareTreeForPath(file,path);
  1372. // And update it:
  1373. DJSON_cache_updateNumber(file,path,new_value);
  1374. if (DJSON_autocommit) djCommit(file);
  1375. return true;
  1376. }
  1377. /**
  1378. * Set a specific path integer value
  1379. *
  1380. * Example:
  1381. * djSetFloat("draco.json","player/pos/x",15.5)
  1382. * will set
  1383. * {"player":{"name":"Hans","pos":{"x":15.5}}}
  1384. * @param string file Name of the json file
  1385. * @param string path Name of the path in the file
  1386. * @param float new_value The new value
  1387. * @param bool use_cached_value Set this to false, if you want to reload the file every time
  1388. * @return bool If it was posssible to set the value
  1389. * @see djAutocommit
  1390. * @see djCommit
  1391. * @ingroup djson
  1392. */
  1393. stock djSetFloat(file[],path[],Float:new_value,use_cached_value=true) {
  1394. DJSON_LastErrorCode=0;
  1395. if (!DJSON_cache_IsFileCached(file) || !use_cached_value) DJSON_cache_ReloadFile(file);
  1396. DJSON_prepareTreeForPath(file,path);
  1397. // And update it:
  1398. new tmp[DJSON_MAX_STRING];
  1399. format(tmp,DJSON_MAX_STRING,"%f",new_value);
  1400. DJSON_cache_updateNumberFromStr(file,path,tmp);
  1401. if (DJSON_autocommit) djCommit(file);
  1402. return true;
  1403. }
  1404. /**
  1405. * Reads a specific value from a json-File by path
  1406. *
  1407. * Example:
  1408. * dj("draco.json","player/name")
  1409. * will return "DracoBlue" if the draco.json looks like that:
  1410. * {"player":{"name":"DracoBlue"}}
  1411. * @param string file Name of the json file
  1412. * @param string path Name of the path in the file
  1413. * @param bool use_cached_value Set this to false, if you want to reload the file everytime
  1414. * @return string The value of the path or ""
  1415. * @ingroup djson
  1416. */
  1417. stock dj(file[],path[],use_cached_value=true) {
  1418. DJSON_LastErrorCode=0;
  1419. if (!DJSON_cache_IsFileCached(file) || !use_cached_value) DJSON_cache_ReloadFile(file);
  1420. new query[DJSON_MAX_STRING];
  1421. if (DJSON_LastErrorCode) {
  1422. query[0] = 0;
  1423. return query;
  1424. }
  1425. new DBResult:res;
  1426. format(query,DJSON_MAX_STRING,"SELECT `value` FROM `c` WHERE file = '%s' AND path = '%s' LIMIT 1",DJSON_sql_escape(file),DJSON_sql_escape(path));
  1427. res = db_query(DJSON_cache_db,query);
  1428. if (db_num_rows(res) == 1) {
  1429. db_get_field(res,0,query,DJSON_MAX_STRING);
  1430. } else {
  1431. query[0] = 0;
  1432. DJSON_LastErrorCode = 4;
  1433. format(DJSON_LastError,DJSON_MAX_STRING,"The path %s is not set",path);
  1434. }
  1435. db_free_result(res);
  1436. return query;
  1437. }
  1438. /**
  1439. * Reads a specific value from a json-File by path
  1440. *
  1441. * Example:
  1442. * djInt("draco.json","player/id")
  1443. * will return 2 if the draco.json looks like that:
  1444. * {"player":{"name":"DracoBlue","id":2}}
  1445. * @param string file Name of the json file
  1446. * @param string path Name of the path in the file
  1447. * @param bool use_cached_value Set this to false, if you want to reload the file everytime
  1448. * @return int The value of the path or 0
  1449. * @ingroup djson
  1450. */
  1451. stock djInt(file[],path[],use_cached_value=true) {
  1452. return strval(dj(file,path,use_cached_value));
  1453. }
  1454. /**
  1455. * Reads a specific value from a json-File by path
  1456. *
  1457. * Example:
  1458. * djInt("draco.json","player/posx")
  1459. * will return 15.5 if the draco.json looks like that:
  1460. * {"player":{"name":"DracoBlue","pos":{"x":15.5,"y":20.0"}}}
  1461. * @param string file Name of the json file
  1462. * @param string path Name of the path in the file
  1463. * @param bool use_cached_value Set this to false, if you want to reload the file everytime
  1464. * @return float The value of the path or 0.0
  1465. * @ingroup djson
  1466. */
  1467. stock Float:djFloat(file[],path[],use_cached_value=true) {
  1468. return floatstr(dj(file,path,use_cached_value));
  1469. }
  1470. /**
  1471. * Activates and deactivates djson autocommit
  1472. * @param bool toggle Set this true to enable autocommit, set it to false to disable!
  1473. * @ingroup djson
  1474. * @see djRevert
  1475. * @see djCommit
  1476. */
  1477. stock djAutocommit(toggle) {
  1478. DJSON_autocommit = toggle;
  1479. }
  1480. /**
  1481. * Commit changes to a json file to the filesystem
  1482. * @param string file Name of the json file
  1483. * @return bool If it was possible to commit the changes
  1484. * @ingroup djson
  1485. * @see djAutocommit
  1486. * @see djRevert
  1487. */
  1488. stock djCommit(file[]) {
  1489. DJSON_LastErrorCode = 0;
  1490. DJSON_cache_debug_save_file(file,file);
  1491. return (DJSON_LastErrorCode == 0);
  1492. }
  1493. /**
  1494. * Revert changes from a json file and reload from disk
  1495. * @param string file Name of the json file
  1496. * @return bool If it was possible to revert the changes
  1497. * @ingroup djson
  1498. * @see djAutocommit
  1499. * @see djCommit
  1500. */
  1501. stock djRevert(file[]) {
  1502. DJSON_LastErrorCode = 0;
  1503. DJSON_cache_ReloadFile(file);
  1504. return (DJSON_LastErrorCode == 0);
  1505. }
  1506. #if DJSON_ALLOW_STYLED_OUTPUT
  1507. /**
  1508. * Activates and deactivates djson styled output
  1509. * @param bool toggle Set this true to enable indented json file output
  1510. * @ingroup djson
  1511. */
  1512. stock djStyled(toggle) {
  1513. DJSON_styled_output = toggle;
  1514. }
  1515. #endif
  1516. /**
  1517. * Creates a new dj-File
  1518. * @param string file Name of the json file
  1519. * @return bool If it was possible to create it
  1520. * @ingroup djson
  1521. */
  1522. stock djCreateFile(file[]) {
  1523. DJSON_LastErrorCode=0;
  1524. new File:fhnd = fopen(file,io_write);
  1525. if (!fhnd) {
  1526. DJSON_LastErrorCode = 1;
  1527. format(DJSON_LastError,DJSON_MAX_STRING,"File %s was not created, can't open file!",file);
  1528. return false;
  1529. }
  1530. fwrite(fhnd,"{}");
  1531. fclose(fhnd);
  1532. if (DJSON_cache_IsFileCached(file)) DJSON_cache_UnloadFile(file);
  1533. return true;
  1534. }
  1535. /**
  1536. * Removes a dj-File
  1537. * @param string file Name of the json file
  1538. * @return bool If it was possible to remove it
  1539. * @ingroup djson
  1540. */
  1541. stock djRemoveFile(file[]) {
  1542. DJSON_LastErrorCode=0;
  1543. if (DJSON_cache_IsFileCached(file)) DJSON_cache_UnloadFile(file);
  1544. if (fremove(file)) {
  1545. DJSON_LastErrorCode = 1;
  1546. format(DJSON_LastError,DJSON_MAX_STRING,"File %s was not accessible, can't remove file!",file);
  1547. return false;
  1548. }
  1549. return true;
  1550. }
  1551. /**
  1552. * Initializes the djson-Engine, _must_ be executed on gamemode init!
  1553. * @ingroup callback
  1554. * @see djson_GameModeExit
  1555. */
  1556. djson_GameModeInit() {
  1557. DJSON_cache_init();
  1558. #if DJSON_RUN_TESTCASES_AT_INIT
  1559. printf("[djson] Initializing TestCases");
  1560. printf(" o Creating djson_test.json");
  1561. print(" \"player\": {");
  1562. print(" \"name\": \"Draco\",");
  1563. print(" \"pos\": {");
  1564. print(" \"x\": 15.0,");
  1565. print(" \"y\": 20");
  1566. print(" }");
  1567. print(" }");
  1568. new File:fhnd = fopen("djson_test.json",io_write);
  1569. fwrite(fhnd,"{\"player\":{\"name\":\"Draco\",\"pos\":{\"x\":15.0,\"y\":20}}}");
  1570. fclose(fhnd);
  1571. new BEFORE_AUTOCOMMIT_VAL = DJSON_autocommit;
  1572. // Even though this is the default, reforce it!
  1573. djAutocommit(true);
  1574. if (DJSON_cache_ReloadFile("djson_test.json")) {
  1575. print(" o Loading djson_test.json worked!");
  1576. } else {
  1577. printf(" x Error loading djson_test.json: %s", DJSON_LastError);
  1578. return ;
  1579. }
  1580. djStyled(true);
  1581. DJSON_cache_debug_save_file("djson_test.json","djson_test_styled.json");
  1582. djStyled(false);
  1583. // try loading all data, and check if correct
  1584. new tmp[DJSON_MAX_STRING];
  1585. new tmp_int;
  1586. new Float:tmp_float;
  1587. format(tmp,DJSON_MAX_STRING,dj("djson_test.json","player/name"));
  1588. if (strcmp(tmp,"Draco")!=0 && strlen(tmp)==0) printf(" x Error reading: player/name, was: %s",tmp);
  1589. else printf(" o Read: player/name, is: %s",tmp);
  1590. if (djFloat("djson_test.json","player/pos/x")!=15.0) printf(" x Error reading: player/pos/x, was: %f",djFloat("djson_test.json","player/pos/x"));
  1591. else printf(" o Read: player/pos/x, is: %f",djFloat("djson_test.json","player/pos/x"));
  1592. if (djInt("djson_test.json","player/pos/y")!=20) printf(" x Error reading: player/pos/y, was: %d",djInt("djson_test.json","player/pos/y"));
  1593. else printf(" o Read: player/pos/y, is: %d",djInt("djson_test.json","player/pos/y"));
  1594. if (djInt("djson_test.json","player/pos/d")!=0) printf(" x Error reading: player/pos/d, was: %d",djInt("djson_test.json","player/pos/d"));
  1595. else printf(" o Read: player/pos/d, is: %d",djInt("djson_test.json","player/pos/d"));
  1596. if (djInt("djson_test.json","player/pos/y")!=20) printf(" x Error reading: player/pos/y, was: %d",djInt("djson_test.json","player/pos/y"));
  1597. else printf(" o Read: player/pos/y, is: %d",djInt("djson_test.json","player/pos/y"));
  1598. // Create a player/id entry
  1599. if (djIsSet("djson_test.json","player/id")) printf(" x Error player/id should not be set");
  1600. else printf(" o Check player/id is not set, yet: correct!");
  1601. if (!djSetInt("djson_test.json","player/id",2)) printf(" x Error creating player/id");
  1602. else printf(" o Created player/id");
  1603. if (djInt("djson_test.json","player/id")!=2) printf(" x Error reading: player/id, was: %d",djInt("djson_test.json","player/id"));
  1604. else printf(" o Read: player/id, is: %d",djInt("djson_test.json","player/id"));
  1605. // some complicated testing now
  1606. if (!djSet("djson_test.json","this/is/a/path","a value")) printf(" x Error creating this/is/a/path");
  1607. else printf(" o Created this/is/a/path");
  1608. if (!djUnset("djson_test.json","this/is/a")) printf(" x Error unsetting this/is/a");
  1609. else printf(" o Unset this/is/a");
  1610. if (djIsSet("djson_test.json","this/is/a")) printf(" x Error this/is/a should not be set");
  1611. else printf(" o Check this/is/a is not set, yet: correct!");
  1612. if (djIsSet("djson_test.json","this/is/a/path")) printf(" x Error this/is/a/path should not be set");
  1613. else printf(" o Check this/is/a/path is not set, yet: correct!");
  1614. if (!djIsSet("djson_test.json","this/is")) printf(" x Error this/is should be set");
  1615. else printf(" o Check this/is should be set, yet: correct!");
  1616. if (!djSet("djson_test.json","this/is","a value")) printf(" x Error setting this/is");
  1617. else printf(" o Setting this/is");
  1618. format(tmp,DJSON_MAX_STRING,dj("djson_test.json","this/is"));
  1619. if (strcmp(tmp,"a value")!=0 && strlen(tmp)==0) printf(" x Error reading: this/is, was: %s",tmp);
  1620. else printf(" o Read: this/is, is: %s",tmp);
  1621. if (!djUnset("djson_test.json","this")) printf(" x Error unsetting this");
  1622. else printf(" o Unset this");
  1623. // we'll create something strange now, to check if the auto-path-creation works
  1624. if (!djSet("djson_test.json","player/about/web/site","http://dracoblue.net")) printf(" x Error creating player/about/web/site");
  1625. else printf(" o Created player/about/web/site");
  1626. if (!djIsSet("djson_test.json","player/about/web")) printf(" x Error player/about/web should be set");
  1627. else printf(" o Check player/about/web should be set, yet: correct!");
  1628. format(tmp,DJSON_MAX_STRING,dj("djson_test.json","player/about/web/site"));
  1629. if (strcmp(tmp,"http://dracoblue.net")!=0 && strlen(tmp)==0) printf(" x Error reading: player/about/web/site, was: %s",tmp);
  1630. else printf(" o Read: player/about/web/site, is: %s",tmp);
  1631. // Now let's have some fun with the arrays
  1632. if (!djAppend("djson_test.json","vehicle/ids","35")) printf(" x Error not existant vehicle/ids should be possible to append.");
  1633. else printf(" o The non existant vehicle/ids should be possible to append: correct!");
  1634. if (!djAppend("djson_test.json","vehicle/ids","12")) printf(" x Error vehicle/ids should be appendable");
  1635. else printf(" o The vehicle/ids should be appendable: correct!");
  1636. if (!djAppend("djson_test.json","vehicle/ids","2")) printf(" x Error vehicle/ids should be appendable");
  1637. else printf(" o The vehicle/ids should be appendable: correct!");
  1638. if (!djAppend("djson_test.json","vehicle/ids","234")) printf(" x Error vehicle/ids should be appendable");
  1639. else printf(" o The vehicle/ids should be appendable: correct!");
  1640. tmp_int = djInt("djson_test.json","vehicle/ids/3");
  1641. if (tmp_int!=234) printf(" x Error reading: vehicle/ids/3, was: %d",tmp_int);
  1642. else printf(" o Read: vehicle/ids/3, is: %d",tmp_int);
  1643. if (!djAppend("djson_test.json","vehicle/ids","123")) printf(" x Error vehicle/ids should be appendable");
  1644. else printf(" o The vehicle/ids should be appendable: correct!");
  1645. DJSON_cache_debug_print();
  1646. if (!djUnset("djson_test.json","vehicle/ids/0")) printf(" x Error unsetting vehicle/ids/2");
  1647. else printf(" o Unset vehicle/ids/0");
  1648. if (!djUnset("djson_test.json","vehicle/ids/2")) printf(" x Error unsetting vehicle/ids/2");
  1649. else printf(" o Unset vehicle/ids/2");
  1650. DJSON_cache_debug_print();
  1651. tmp_int = djInt("djson_test.json","vehicle/ids/2");
  1652. if (tmp_int!=123) printf(" x Error reading: vehicle/ids/2, was: %d",tmp_int);
  1653. else printf(" o Read: vehicle/ids/2, is: %d",tmp_int);
  1654. // Check the value now
  1655. tmp_int = djInt("djson_test.json","vehicle/ids/0");
  1656. if (tmp_int!=12) printf(" x Error reading: vehicle/ids/0, was: %d",tmp_int);
  1657. else printf(" o Read: vehicle/ids/0, is: %d",tmp_int);
  1658. tmp_int = djInt("djson_test.json","vehicle/ids/1");
  1659. if (tmp_int!=2) printf(" x Error reading: vehicle/ids/1, was: %d",tmp_int);
  1660. else printf(" o Read: vehicle/ids/1, is: %d",tmp_int);
  1661. tmp_int = djCount("djson_test.json","vehicle/ids");
  1662. if (tmp_int!=3) printf(" x Error counting the vehicleids, were: %d",tmp_int);
  1663. else printf(" o Found a total of %d vehicle/ids",tmp_int);
  1664. // now check the autocommit feature
  1665. djAutocommit(false);
  1666. if (!djSetFloat("djson_test.json","player/id",1.0)) printf(" x Error creating player/id");
  1667. else printf(" o Set player/id to cache");
  1668. if (!djSetInt("djson_test.json","player/id",1)) printf(" x Error setting player/id");
  1669. else printf(" o Set player/id to cache");
  1670. if (djInt("djson_test.json","player/id")!=1) printf(" x Error reading: player/id, was: %d",djInt("djson_test.json","player/id"));
  1671. else printf(" o Read: player/id from cache, is: %d",djInt("djson_test.json","player/id"));
  1672. if (djInt("djson_test.json","player/id")!=1) printf(" x Error reading: player/id, was: %d",djInt("djson_test.json","player/id"));
  1673. else printf(" o Read: player/id from cache, is: %d",djInt("djson_test.json","player/id"));
  1674. tmp_int = djInt("djson_test.json","player/id",false);
  1675. if (tmp_int!=2) printf(" x Error reading: player/id from file, was: %d",tmp_int);
  1676. else printf(" o Read: player/id from file (instead of cache), is: %d",tmp_int);
  1677. // Now doing that again, but commiting the changes
  1678. if (!djSetInt("djson_test.json","player/id",1)) printf(" x Error creating player/id");
  1679. else printf(" o Set player/id to cache");
  1680. djCommit("djson_test.json");
  1681. tmp_int = djInt("djson_test.json","player/id",false);
  1682. if (tmp_int!=1) printf(" x Error reading: player/id from file, was: %d",tmp_int);
  1683. else printf(" o Read: player/id from file (instead of cache), is: %d",tmp_int);
  1684. printf(" o Testing reference values:");
  1685. print(" {");
  1686. print(" \"player\":{");
  1687. print(" \"about\":{");
  1688. print(" \"web\":{");
  1689. print(" \"site\":\"http://dracoblue.net\"");
  1690. print(" }");
  1691. print(" },");
  1692. print(" \"id\":1,");
  1693. print(" \"name\":\"Draco\",");
  1694. print(" \"pos\":{");
  1695. print(" \"x\":15.0,");
  1696. print(" \"y\":20");
  1697. print(" }");
  1698. print(" },");
  1699. print(" \"vehicle\":{");
  1700. print(" \"ids\":[");
  1701. print(" \"12\",");
  1702. print(" \"2\",");
  1703. print(" \"123\"");
  1704. print(" ]");
  1705. print(" }");
  1706. print(" }");
  1707. // now let's check if the file is correct
  1708. fhnd = fopen("djson_test.json",io_read);
  1709. fread(fhnd,tmp,DJSON_MAX_STRING);
  1710. fclose(fhnd);
  1711. new what_we_want[] = "{\"player\":{\"about\":{\"web\":{\"site\":\"http://dracoblue.net\"}},\"id\":1,\"name\":\"Draco\",\"pos\":{\"x\":15.0,\"y\":20}},\"vehicle\":{\"ids\":[\"12\",\"2\",\"123\"]}}";
  1712. new what_we_want_pos = 0;
  1713. new was_correct = true;
  1714. while (what_we_want_pos<strlen(what_we_want)) {
  1715. if (what_we_want[what_we_want_pos]!=tmp[what_we_want_pos]) {
  1716. printf(" x Character %d (%c!=%c) was wrong in generated djson_test.json!",what_we_want_pos,tmp[what_we_want_pos],what_we_want[what_we_want_pos]);
  1717. was_correct = false;
  1718. }
  1719. what_we_want_pos++ ;
  1720. }
  1721. if (was_correct) printf(" o Checked generated djson_test.json: correct!");
  1722. DJSON_cache_debug_print();
  1723. DJSON_cache_UnloadFile("djson_test.json");
  1724. printf("%s",dj("djson_simple_test.json","test2"));
  1725. djAutocommit(true);
  1726. // now let's test a simple testcase:
  1727. djCreateFile("djson_simple_test.json");
  1728. djAppend("djson_simple_test.json","items","");
  1729. djSet("djson_simple_test.json","items/0","Hallo");
  1730. DJSON_cache_debug_print();
  1731. djSet("djson_simple_test.json","items/0/id","2");
  1732. DJSON_cache_debug_print();
  1733. djUnset("djson_simple_test.json","items/0");
  1734. DJSON_cache_debug_print();
  1735. djCommit("djson_simple_test.json");
  1736. djRemoveFile("djson_simple_test.json");
  1737. // now let's do a simple different testcase:
  1738. djCreateFile("djson_simple_test.json");
  1739. djAppend("djson_simple_test.json","items","");
  1740. djSet("djson_simple_test.json","items/0/id","123");
  1741. djSet("djson_simple_test.json","items/0/name","A");
  1742. djAppend("djson_simple_test.json","items","");
  1743. djSet("djson_simple_test.json","items/1/id","234");
  1744. djSet("djson_simple_test.json","items/1/name","\"B\"");
  1745. djAppend("djson_simple_test.json","items","");
  1746. djSet("djson_simple_test.json","items/2/id","345");
  1747. djSet("djson_simple_test.json","items/2/name","C");
  1748. djAppend("djson_simple_test.json","items","");
  1749. djSet("djson_simple_test.json","items/3/id","456");
  1750. djSet("djson_simple_test.json","items/3/name","D");
  1751. djAppend("djson_simple_test.json","items","");
  1752. djSet("djson_simple_test.json","items/4/id","567");
  1753. djSet("djson_simple_test.json","items/4/name","E");
  1754. DJSON_cache_debug_print();
  1755. printf("unsetting ...");
  1756. djUnset("djson_simple_test.json","items/2");
  1757. printf("unsetting ... done!");
  1758. DJSON_cache_debug_print();
  1759. printf("reading something with \" and \" ...");
  1760. DJSON_cache_UnloadFile("djson_simple_test.json");
  1761. format(tmp,DJSON_MAX_STRING,dj("djson_simple_test.json","items/1/name"));
  1762. if (strcmp(tmp,"\"B\"")!=0 || strlen(tmp)==0) printf(" X Could not read the escaped value back, it's: %s", tmp);
  1763. else printf(" o Could read the escaped value back, it's: %s", tmp);
  1764. printf("reading something with \" and \" ... done");
  1765. djCreateFile("djson_number_test.json");
  1766. djAutocommit(true);
  1767. djSetInt("djson_number_test.json","number/one/is",200);
  1768. djSetInt("djson_number_test.json","number/two/is",-210);
  1769. djSetInt("djson_number_test.json","number/three",0);
  1770. djSetFloat("djson_number_test.json","number/four",0.5);
  1771. djSetFloat("djson_number_test.json","number/five",-0.1);
  1772. djSetFloat("djson_number_test.json","number/six",-1.2);
  1773. djSetFloat("djson_number_test.json","number/seven",-1.0);
  1774. DJSON_cache_UnloadFile("djson_number_test.json");
  1775. tmp_int = djInt("djson_number_test.json","number/one/is",false);
  1776. if (tmp_int!=200) printf(" x Error reading: number/one/is from file, was: %d",tmp_int);
  1777. else printf(" o Read: number/one/is from file, is: %d",tmp_int);
  1778. tmp_int = djInt("djson_number_test.json","number/two/is",false);
  1779. if (tmp_int!=-210) printf(" x Error reading: number/two/is from file, was: %d",tmp_int);
  1780. else printf(" o Read: number/two/is from file, is: %d",tmp_int);
  1781. tmp_int = djInt("djson_number_test.json","number/three",false);
  1782. if (tmp_int!=0) printf(" x Error reading: number/three from file, was: %d",tmp_int);
  1783. else printf(" o Read: number/three from file, is: %d",tmp_int);
  1784. tmp_float = djFloat("djson_number_test.json","number/four",false);
  1785. if (tmp_float!=0.5) printf(" x Error reading: number/four from file, was: %f",tmp_float);
  1786. else printf(" o Read: number/four from file, is: %f",tmp_float);
  1787. tmp_float = djFloat("djson_number_test.json","number/five",false);
  1788. if (tmp_float!=-0.1) printf(" x Error reading: number/five from file, was: %f",tmp_float);
  1789. else printf(" o Read: number/five from file, is: %f",tmp_float);
  1790. tmp_float = djFloat("djson_number_test.json","number/six",false);
  1791. if (tmp_float!=-1.2) printf(" x Error reading: number/six from file, was: %f",tmp_float);
  1792. else printf(" o Read: number/six from file, is: %f",tmp_float);
  1793. tmp_float = djFloat("djson_number_test.json","number/seven",false);
  1794. if (tmp_float!=-1.0) printf(" x Error reading: number/seven from file, was: %f",tmp_float);
  1795. else printf(" o Read: number/seven from file, is: %f",tmp_float);
  1796. // testing negative, positive and numbers which are non of that :-)
  1797. fremove("djson_number_test.json");
  1798. DJSON_cache_UnloadFile("djson_number_test.json");
  1799. DJSON_cache_UnloadFile("djson_simple_test.json");
  1800. DJSON_cache_UnloadFile("djson_test.json");
  1801. djCreateFile("djappend_test.json");
  1802. djAppend("djappend_test.json","Object","");
  1803. djAppend("djappend_test.json", "Object", "TestValue1");
  1804. format(tmp,DJSON_MAX_STRING,dj("djappend_test.json","Object/1"));
  1805. if (strcmp(tmp,"TestValue1")!=0 || strlen(tmp)==0) printf(" X Could not append Testvalue1 to Object");
  1806. else printf(" o Append TestValue1 to Object");
  1807. tmp_int = djSet("djappend_test_between.json", "Dummy", "0");
  1808. if (tmp_int) printf(" o Set Dummy to 0");
  1809. else printf(" X Could not set Dummy 0");
  1810. djAppend("djappend_test.json", "Object", "TestValue2");
  1811. format(tmp,DJSON_MAX_STRING,dj("djappend_test.json","Object/2"));
  1812. if (strcmp(tmp,"TestValue2")!=0 || strlen(tmp)==0) printf(" X Could not append Testvalue2 to Object");
  1813. else printf(" o Append TestValue2 to Object");
  1814. // Reset to default before test started
  1815. djAutocommit(BEFORE_AUTOCOMMIT_VAL);
  1816. djSet("djson_simple_test.json","test2","1");
  1817. printf("done!");
  1818. #endif
  1819. }
  1820. /**
  1821. * Destroys the djson-Engine, _must_ be executed on gamemode exit!
  1822. * @ingroup callback
  1823. * @see djson_GameModeInit
  1824. */
  1825. djson_GameModeExit() {
  1826. DJSON_cache_close();
  1827. }