djson.inc 62 KB

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