Advertisement
nandoy

dof2-e.inc

Dec 22nd, 2017
288
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 51.32 KB | None | 0 0
  1. #if defined _ZN_included
  2.     #endinput
  3. #endif
  4. #define _ZN_included
  5.  
  6. #include <a_samp>
  7. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  8.  
  9. /*
  10.  * This is a new version of the INI script Double-O-Files.
  11.  * However, it's has completely been rewritten and has now a much better performance.
  12.  * There is also the support for sections in the INI file. (But there is no support for comments.)
  13.  * Double-O-Files 2 is compatible with DUDB, DINI, Double-O-Files and possibly y_ini since it
  14.  * can handle sections and entry of the format "key = value", not only "key=value".
  15.  * The number of spaces between the equal sign and key and value can actually be arbitrary.
  16.  * I've added some comments below. You may see that I've mentioned the big-O-notation,
  17.  * 'n' always Entries.Count.
  18.  * Double-O-Files 2 should also be useful for Russian letter because I'm using
  19.  * the functions fgetchar and fputchar to write and read the files.
  20.  *
  21.  * There is another new feature which has been inspired by ZCMD and y_ini:
  22.  * The OnParseFile callbacks. To learn more about it, read the description in
  23.  * the SA-MP forums if you haven't already.
  24.  * THE END
  25.  */
  26.  
  27. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  28.  
  29. /*
  30. native ZN_SetFile(file[]);
  31. native ZN_LoadFile();
  32. native ZN_SaveFile();
  33. native ZN_ParseFile(file[],extraid,bool:callback=true);
  34. native ZN_ReparseFile(file[],extraid,bool:callback=true);
  35. native ZN_WriteFile();
  36. native ZN_PrintFile(comment[]="");
  37. native ZN_GetString(file[],key[],tag[]="");
  38. native ZN_GetStringEx(file[],key[],result[],size,tag[]="");
  39. native Float:ZN_GetFloat(file[],key[]);
  40. native ZN_GetInt(file[],key[],tag[]="");
  41. native ZN_GetHex(file[],key[],tag[]="");
  42. native ZN_GetBin(file[],key[],tag[]="");
  43. native bool:ZN_GetBool(file[],key[],tag[]="");
  44. native ZN_SetString(file[],key[],value[],tag[]="");
  45. native ZN_SetFloat(file[],key[],Float:value);
  46. native ZN_SetInt(file[],key[],value,tag[]="");
  47. native ZN_SetHex(file[],key[],value,tag[]="");
  48. native ZN_SetBin(file[],key[],value,tag[]="");
  49. native ZN_SetBool(file[],key[],bool:value,tag[]="");
  50. native ZN_IsSet(file[],key[],tag[]="");
  51. native ZN_Unset(file[],key[],tag[]="");
  52. native ZN_FileExists(file[]);
  53. native ZN_RemoveFile(file[]);
  54. native ZN_CreateFile(file[],password[]="");
  55. native ZN_RenameFile(oldfile[],newfile[]);
  56. native ZN_RenameKey(file[],oldkey[],newkey[],tag[]="");
  57. native ZN_CopyFile(filetocopy[],newfile[]);
  58. native ZN_CheckLogin(file[],password[]);
  59. native ZN_File(user[]);
  60. native ZN_ParseInt();
  61. native ZN_ParseFloat();
  62. native ZN_ParseBool();
  63. native ZN_ParseBin();
  64. native ZN_ParseHex();
  65. native ZN_SetUTF8(bool:set);
  66. native bool:ZN_GetUTF8();
  67. native ZN_GetFile();
  68. native ZN_MakeBackup(file[]);
  69. native ZN_RemoveSection (file [], tag []);
  70. native ZN_SectionExists (file [], tag []);
  71. native ZN_SortSection (file [], tag [], bool: ignorecase = true, bool: ascending = true);
  72. native ZN_SortAllSections (file [], bool: ignorecase = true, bool: ascending = true);
  73. native ZN_SetCaseSensitivity (bool: set);
  74. native ZN_GetCaseSensitivity ();
  75. */
  76.  
  77. #define ZN_TagExists  ZN_SectionExists
  78. #define ZN_RemoveTag  ZN_RemoveSection
  79.  
  80. // OnParseFile <Tag><Key>(extraid, value [])
  81. // OnParseFile <><Key>(extraid, value [])
  82. // OnDefaultParseFile (extraid, value [], key [], tag [], file [])
  83.  
  84. // The arguments of your OnParseFile functions may have arbitrary names but must be an integer followed by a string.
  85. // Function must return a value.
  86. #define OnParseFile<%0><%1>(%2) \
  87.     forward _OnParseFile_%0_%1 (extraid, value []); \
  88.     public _OnParseFile_%0_%1 (extraid, value []) \
  89.         return __OnParseFile_%0_%1 (extraid, (value [0] == '\1' && value [1] == '\0') ? ("") : value); \
  90.     stock __OnParseFile_%0_%1 (%2)
  91.  
  92. // Also here: The argument names may be arbitrary but must be an integer followed by 4 strings.
  93. // Function must return a value.
  94. #define OnDefaultParseFile(%0) \
  95.     forward _OnDefaultParseFile (extraid, value [], key [], tag [], file []); \
  96.     public _OnDefaultParseFile (extraid, value [], key [], tag [], file []) \
  97.         return __OnDefaultParseFile (extraid, (value [0] == '\1' && value [1] == '\0') ? ("") : value, key, (tag [0] == '\1' && tag [1] == '\0') ? ("") : tag, file); \
  98.     stock __OnDefaultParseFile (%0)
  99.  
  100. #define ZN_ParseBool() \
  101.     (strval (value) || (value [0] && !strcmp (value, "true", true)))
  102.  
  103. #define ZN_ParseInt() \
  104.     (strval (value))
  105.  
  106. #define ZN_ParseFloat() \
  107.     (floatstr (value))
  108.  
  109. #define ZN_ParseBin() \
  110.     (ZN_strbin (value))
  111.  
  112. #define ZN_ParseHex() \
  113.     (ZN_strhex (value))
  114.  
  115. #define ZN_LoadFile() \
  116.     ZN_ParseFile (CurrentFile, -1, false)
  117.  
  118. #define ZN_SaveFile \
  119.     ZN_WriteFile
  120.  
  121. #define ZN_FileExists \
  122.     fexist
  123.  
  124. #define Sections. \
  125.     Sections_
  126.  
  127. #define Entries. \
  128.     Entries_
  129.  
  130. #define ZN:: \
  131.     ZN_
  132.  
  133. #if !defined private
  134.     #define private         static stock
  135. #endif
  136.  
  137. #pragma dynamic 65536
  138.  
  139. /*
  140. #define MAX_SECTION_TAG        (32)
  141. #define MAX_LINE_SIZE       (128)
  142. #define MAX_SECTIONS            (32)
  143. #define MAX_ENTRIES         (256)
  144. #define MAX_FILE_SIZE       (64)
  145.  
  146. #define USER_FILE_PATH      "Users/%s.ini"
  147. */
  148.  
  149. // The maximum length of the name of a tag.
  150. #if !defined MAX_SECTION_TAG
  151.     #define MAX_SECTION_TAG     (32)
  152. #endif
  153.  
  154. // The maximum length of a line (including key and value).
  155. #if !defined MAX_LINE_SIZE
  156.     #define MAX_LINE_SIZE       (128)
  157. #endif
  158.  
  159. // The maximum number of sections which can be handled. Be careful: MUST NOT be higher than 255.
  160. #if !defined MAX_SECTIONS
  161.     #define MAX_SECTIONS        (32)
  162. #endif
  163.  
  164. // The maximum number of entries which can be loaded into the cache.
  165. #if !defined MAX_ENTRIES
  166.     #define MAX_ENTRIES         (256)
  167. #endif
  168.  
  169. // The maximum length of the name of a file.
  170. #if !defined MAX_FILE_SIZE
  171.     #define MAX_FILE_SIZE       (64)
  172. #endif
  173.  
  174. /*
  175. If PACK_CONTENT == true tag names and lines (key + value) will get stored in cache as packed strings.
  176. The result is less memory usage. However, you won't be able to use special characters like russian or chinese ones.
  177. */
  178. #if !defined PACK_CONTENT
  179.     #define PACK_CONTENT        (false)
  180. #endif
  181.  
  182. #define INVALID_ENTRY           (-1)
  183. #define INVALID_SECTION         (-1)
  184.  
  185. // Do you want to emulate DUDB?
  186. #if !defined DUDB_CONVERT && 0 // Change to 1 to enable.
  187.     #define DUDB_CONVERT
  188. #endif
  189.  
  190. #if !defined USER_FILE_PATH
  191.     #if defined DUDB_CONVERT
  192.         #define USER_FILE_PATH  "%s.dudb.sav"
  193.     #else
  194.         #define USER_FILE_PATH  "%s.ini"
  195.     #endif
  196. #endif
  197.  
  198. #if !defined USER_PW_HASH_KEY
  199.     #if defined DUDB_CONVERT
  200.         #define USER_PW_HASH_KEY "password_hash"
  201.     #else
  202.         #define USER_PW_HASH_KEY "password_hash"
  203.     #endif
  204. #endif
  205.  
  206.  
  207. // Do you want to emulate DINI?
  208. #if !defined DINI_CONVERT && 0 // Change to 1 to enable.
  209.     #define DINI_CONVERT
  210. #endif
  211.  
  212. /*
  213. #if MAX_SECTIONS >= 256
  214.     #error MAX_SECTIONS must not be greater than 255.
  215. #endif
  216. */
  217.  
  218. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  219.  
  220. private
  221.     bool: UseUTF8 = PACK_CONTENT,
  222.     bool: CaseSensitive = false,
  223.     CurrentFile [MAX_FILE_SIZE],
  224.     bool: FileChanged,
  225.     Sections.FirstEntry [MAX_SECTIONS] = {INVALID_ENTRY, ...},
  226.     Sections.LastEntry [MAX_SECTIONS] = {INVALID_ENTRY, ...},
  227.     Sections.Count,
  228. #if PACK_CONTENT == true
  229.     Sections.Tag [MAX_SECTIONS][MAX_SECTION_TAG char],
  230.     Entries.Line [MAX_ENTRIES][MAX_LINE_SIZE char],
  231.     Entries.Tag [MAX_ENTRIES][MAX_SECTION_TAG char],
  232. #else
  233.     Sections.Tag [MAX_SECTIONS][MAX_SECTION_TAG],
  234.     Entries.Line [MAX_ENTRIES][MAX_LINE_SIZE],
  235.     Entries.Tag [MAX_ENTRIES][MAX_SECTION_TAG],
  236. #endif
  237. #if MAX_SECTIONS >= 256
  238.     Entries.Section [MAX_ENTRIES],
  239. #else
  240.     Entries.Section [MAX_ENTRIES char],
  241. #endif
  242.     Entries.NextEntry [MAX_ENTRIES] = {INVALID_ENTRY, ...},
  243.     Entries.PreviousEntry [MAX_ENTRIES] = {INVALID_ENTRY, ...},
  244.     Entries.Count,
  245.     SortedEntryList [MAX_ENTRIES][2]; // Index 0: Hashcode, Index 1: EntryID
  246.  
  247. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  248.  
  249. stock ZN::Exit ()
  250.     ZN::WriteFile ();
  251.  
  252. stock ZN::SetUTF8 (bool: set)
  253.     UseUTF8 = set;
  254.  
  255. stock bool: ZN::GetUTF8 ()
  256.     return UseUTF8;
  257.  
  258. stock bool: ZN::SetCaseSensitivity (bool: set)
  259.     CaseSensitive = set;
  260.  
  261. stock bool: ZN::GetCaseSensitivity ()
  262.     return CaseSensitive;
  263.  
  264. stock ZN::SetFile (file [])
  265.     ZN::strcpy (CurrentFile, file);
  266.  
  267. stock ZN::GetFile ()
  268.     return CurrentFile;
  269.  
  270. stock ZN::CreateFile (file [], password [] = "")
  271. {
  272.     if (!ZN::FileExists (file))
  273.     {
  274.         new File: f = fopen (file, io_append);
  275.  
  276.         if (fclose (f))
  277.         {
  278.             if (password [0])
  279.                 return ZN::SetInt (file, USER_PW_HASH_KEY, ZN::num_hash (password));
  280.             return 1;
  281.         }
  282.     }
  283.     return 0;
  284. }
  285.  
  286. stock ZN::RenameFile (oldfile [], newfile [])
  287. {
  288.     if (!ZN::FileExists (newfile))
  289.     {
  290.         // If 'CurrentFile' is 'oldfile', write it if it has been changed.
  291.         if (CurrentFile [0] && !strcmp (CurrentFile, oldfile) && FileChanged)
  292.             ZN::WriteFile ();
  293.         else if (!ZN::ParseFile (oldfile, -1, false)) // Otherwise parse 'oldfile'.
  294.             return 0;
  295.  
  296.         ZN::SetFile (newfile);
  297.         if (ZN::WriteFile ())
  298.             return fremove (oldfile);
  299.     }
  300.     return 0;
  301. }
  302.  
  303. stock ZN::CopyFile (filetocopy [], newfile [])
  304. {
  305.     if (!ZN::FileExists (newfile))
  306.     {
  307.         if (CurrentFile [0] && !strcmp (CurrentFile, filetocopy) && FileChanged)
  308.             ZN::WriteFile ();
  309.         else if(!ZN::ParseFile (filetocopy, -1, false))
  310.             return 0;
  311.  
  312.         ZN::SetFile (newfile);
  313.         return ZN::WriteFile ();
  314.     }
  315.     return 0;
  316. }
  317.  
  318. stock ZN::RemoveFile (file [])
  319. {
  320.     if (file [0])
  321.     {
  322.         if (CurrentFile [0] && !strcmp (CurrentFile, file))
  323.             CurrentFile [0] = '\0';
  324.         return fremove (file);
  325.     }
  326.     return 0;
  327. }
  328.  
  329. stock ZN::MakeBackup (file [])
  330. {
  331.     new
  332.         year,
  333.         month,
  334.         day,
  335.         hour,
  336.         minute,
  337.         second,
  338.         backupfile [MAX_FILE_SIZE];
  339.  
  340.     getdate (year, month, day);
  341.     gettime (hour, minute, second);
  342.     format (backupfile, sizeof (backupfile), "%s.%02d_%02d_%02d.%02d_%02d_%02d_%02d.bak", CurrentFile, month, day, year, hour, minute, second, GetTickCount ());
  343.     return ZN::CopyFile (CurrentFile, backupfile);
  344. }
  345.  
  346. stock bool: ZN::SectionExists (file [], tag [])
  347. {
  348.     if (file [0]) // You can't remove the empty Sections.
  349.     {
  350.         if (!tag [0])
  351.             return true; // Emptry section always exists. In every file.
  352.  
  353.         if (!CurrentFile [0] || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.
  354.             if (!ZN::ParseFile (file, -1, false))
  355.                 return false;
  356.  
  357.     #if PACK_CONTENT == true
  358.         new buf [MAX_SECTION_TAG];
  359.     #endif
  360.  
  361.         for (new i = 1; i < Sections.Count; ++i)
  362.         {
  363.         #if PACK_CONTENT == true
  364.             strunpack (buf, Sections.Tag [i]);
  365.             if (!strcmp (buf, tag, !CaseSensitive))
  366.                 return true;
  367.         #else
  368.             if (!strcmp (Sections.Tag [i], tag, !CaseSensitive))
  369.                 return true;
  370.         #endif
  371.         }
  372.     }
  373.     return false;
  374. }
  375.  
  376. stock ZN::RemoveSection (file [], tag [])
  377. {
  378.     // Removes tag 'tag' with all it's entries.
  379.     if (file [0] && tag [0]) // You can't remove the empty Sections.
  380.     {
  381.         if (!CurrentFile [0] || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.
  382.             if (!ZN::ParseFile (file, -1, false))
  383.                 return 0;
  384.  
  385.         new
  386.         #if PACK_CONTENT == true
  387.             line [MAX_LINE_SIZE],
  388.         #endif
  389.             buf [MAX_SECTION_TAG],
  390.             section = INVALID_SECTION,
  391.             entry,
  392.             key [MAX_LINE_SIZE];
  393.  
  394.         for (new i = 1; i < Sections.Count; ++i)
  395.         {
  396.         #if PACK_CONTENT == true
  397.             strunpack (buf, Sections.Tag [i]);
  398.             if (!strcmp (buf, tag, !CaseSensitive))
  399.             {
  400.                 section = i;
  401.                 break;
  402.             }
  403.         #else
  404.             if (!strcmp (Sections.Tag [i], tag, !CaseSensitive))
  405.             {
  406.                 section = i;
  407.                 break;
  408.             }
  409.         #endif
  410.         }
  411.  
  412.         if (section != INVALID_SECTION)
  413.         {
  414.             entry = Sections.FirstEntry [section];
  415.             while (entry != INVALID_ENTRY)
  416.             {
  417.                 // Remove all entries under the current Sections.
  418.             #if PACK_CONTENT == true
  419.                 strunpack (line, Entries.Line [entry]);
  420.                 ZN::ParseLine (line, key, buf);
  421.             #else
  422.                 ZN::ParseLine (Entries.Line [entry], key, buf);
  423.             #endif
  424.                 ZN::Unset (file, key, tag);
  425.                 entry = Entries.NextEntry [entry];
  426.             }
  427.  
  428.             // Move the last tag to the position of the current tag. Creates a little mess.
  429.             --Sections.Count;
  430.             Sections.Tag [section] = Sections.Tag [Sections.Count];
  431.             Sections.FirstEntry [section] = Sections.FirstEntry [Sections.Count];
  432.             Sections.LastEntry [section] = Sections.LastEntry [Sections.Count];
  433.  
  434.             // Adjust the tag IDs of the entries.
  435.             entry = Sections.FirstEntry [section];
  436.             while (entry != INVALID_ENTRY)
  437.             {
  438.             #if MAX_SECTIONS >= 256
  439.                 Entries.Section [entry] = section;
  440.             #else
  441.                 Entries.Section {entry} = section;
  442.             #endif
  443.                 entry = Entries.NextEntry [entry];
  444.             }
  445.             FileChanged = true;
  446.             return 1;
  447.         }
  448.     }
  449.     return 0;
  450. }
  451.  
  452. private ZN::SearchEntry (key [], tag [], keybuf [], valbuf [], &pos, keybufsize = sizeof (keybuf), valbufsize = sizeof (valbuf))
  453. {
  454.     if (key [0] && Entries.Count)
  455.     {
  456.         new
  457.             entry = INVALID_ENTRY,
  458.             l,
  459.             m,
  460.             r,
  461.             h,
  462.         #if PACK_CONTENT == true
  463.             line [MAX_LINE_SIZE],
  464.             buf [MAX_SECTION_TAG],
  465.         #endif
  466.             i;
  467.  
  468.         h = ZN::HashKey (key);
  469.         l = 0;
  470.         r = Entries.Count - 1;
  471.  
  472.         /*
  473.          * Binary search in a sorted list of entries in O(log n) time. This algorithm makes for example with 256 elements a maximum of ~8 steps until the entry is found if it exists.
  474.          * A sequential search would take up to 256 steps. That was the case in the first Double-O-Files script.
  475.          */
  476.         while (l <= r)
  477.         {
  478.             if ((r - l) < 2)
  479.             {
  480.                 if (h == SortedEntryList [l][0])
  481.                 {
  482.                     m = l;
  483.                     entry = SortedEntryList [l][1];
  484.                 }
  485.                 else if (r > l && h == SortedEntryList [r][0])
  486.                 {
  487.                     m = r;
  488.                     entry = SortedEntryList [r][1];
  489.                 }
  490.                 break;
  491.             }
  492.             else
  493.             {
  494.                 m = l + (r - l) / 2;
  495.                 if (h == SortedEntryList [m][0])
  496.                 {
  497.                     entry = SortedEntryList [m][1];
  498.                     break;
  499.                 }
  500.                 else if (h > SortedEntryList [m][0])
  501.                     l = m + 1;
  502.                 else
  503.                     r = m - 1;
  504.             }
  505.         }
  506.  
  507.         // Candidate found?
  508.         if (entry != INVALID_ENTRY)
  509.         {
  510.             // Check if it's the entry we want.
  511.         #if PACK_CONTENT == true
  512.             strunpack (line, Entries.Line [entry]);
  513.             ZN::ParseLine (line, keybuf, valbuf, keybufsize, valbufsize);
  514.             strunpack (buf, Entries.Tag [entry]);
  515.             if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag [0] && !buf [0]) || (tag [0] && buf [0] && !strcmp (tag, buf, !CaseSensitive))))
  516.         #else
  517.             ZN::ParseLine (Entries.Line [entry], keybuf, valbuf, keybufsize, valbufsize);
  518.             if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag [0] && !Entries.Tag [entry][0]) || (tag [0] && Entries.Tag [entry][0] && !strcmp (tag, Entries.Tag [entry], !CaseSensitive))))
  519.         #endif
  520.                 return (pos = m, entry);
  521.             else
  522.             {
  523.                 // If not, look left and right in the list for entries with the same hash code. This can be collisions or entries with the same key from another section.
  524.                 for (i = m - 1; i >= 0 && h == SortedEntryList [i][0]; --i)
  525.                 {
  526.                     entry = SortedEntryList [i][1];
  527.                 #if PACK_CONTENT == true
  528.                     strunpack (line, Entries.Line [entry]);
  529.                     ZN::ParseLine (line, keybuf, valbuf, keybufsize, valbufsize);
  530.                     strunpack (buf, Entries.Tag [entry]);
  531.                     if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag [0] && !buf [0]) || (tag [0] && buf [0] && !strcmp (tag, buf, !CaseSensitive))))
  532.                 #else
  533.                     ZN::ParseLine (Entries.Line [entry], keybuf, valbuf, keybufsize, valbufsize);
  534.                     if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag [0] && !Entries.Tag [entry][0]) || (tag [0] && Entries.Tag [entry][0] && !strcmp (tag, Entries.Tag [entry], !CaseSensitive))))
  535.                 #endif
  536.                         return (pos = i, entry);
  537.                 }
  538.  
  539.                 for (i = m + 1; i < Entries.Count && h == SortedEntryList [i][0]; ++i)
  540.                 {
  541.                     entry = SortedEntryList [i][1];
  542.                 #if PACK_CONTENT == true
  543.                     strunpack (line, Entries.Line [entry]);
  544.                     ZN::ParseLine (line, keybuf, valbuf, keybufsize, valbufsize);
  545.                     strunpack (buf, Entries.Tag [entry]);
  546.                     if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag [0] && !buf [0]) || (tag [0] && buf [0] && !strcmp (tag, buf, !CaseSensitive))))
  547.                 #else
  548.                     ZN::ParseLine (Entries.Line [entry], keybuf, valbuf, keybufsize, valbufsize);
  549.                     if (!strcmp (keybuf, key, !CaseSensitive) && ((!tag [0] && !Entries.Tag [entry][0]) || (tag [0] && Entries.Tag [entry][0] && !strcmp (tag, Entries.Tag [entry], !CaseSensitive))))
  550.                 #endif
  551.                         return (pos = i, entry);
  552.                 }
  553.             }
  554.         }
  555.     }
  556.  
  557.     keybuf [0] = valbuf [0] = '\0';
  558.     return INVALID_ENTRY;
  559. }
  560.  
  561. stock ZN::SetString (file [], key [], value [], tag [] = "")
  562. {
  563.     if (file [0] && key [0])
  564.     {
  565.         new
  566.             entry,
  567.             pos,
  568.             section = INVALID_SECTION,
  569.             keybuf [MAX_LINE_SIZE],
  570.             valbuf [MAX_LINE_SIZE],
  571.         #if PACK_CONTENT == true
  572.             buf [MAX_SECTION_TAG],
  573.             line [MAX_LINE_SIZE],
  574.         #endif
  575.             i;
  576.  
  577.         if (!CurrentFile [0] || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.
  578.             if (!ZN::ParseFile (file, -1, false))
  579.                 return 0;
  580.  
  581.         entry = ZN::SearchEntry (key, tag, keybuf, valbuf, pos);
  582.  
  583.         // If the entry has been found, just change it's content.
  584.         if (entry != INVALID_ENTRY)
  585.         {
  586.             FileChanged = true;
  587.         #if PACK_CONTENT == true
  588.             format (line, sizeof (line), "%s=%s", key, value [0] ? value : ("(null)"));
  589.             return strpack (Entries.Line [entry], line);
  590.         #else
  591.             format (Entries.Line [entry], sizeof (Entries.Line []), "%s=%s", key, value [0] ? value : ("(null)"));
  592.             return 1;
  593.         #endif
  594.         }
  595.  
  596.         if (Entries.Count >= MAX_ENTRIES)
  597.             return 0;
  598.  
  599.         // Search for the section where the entry belongs.
  600.         if (!tag [0])
  601.             section = 0;
  602.         else
  603.         {
  604.             for (i = 1; i < Sections.Count; ++i)
  605.             {
  606.             #if PACK_CONTENT == true
  607.                 strunpack (buf, Sections.Tag [i]);
  608.                 if (buf [0] && !strcmp (tag, buf, !CaseSensitive))
  609.                 {
  610.                     section = i;
  611.                     break;
  612.                 }
  613.             #else
  614.                 if (Sections.Tag [i][0] && !strcmp (tag, Sections.Tag [i], !CaseSensitive))
  615.                 {
  616.                     section = i;
  617.                     break;
  618.                 }
  619.             #endif
  620.             }
  621.         }
  622.  
  623.         // Section we want does not exist, create new one if possible.
  624.         if (section == INVALID_SECTION)
  625.         {
  626.             if (Sections.Count >= MAX_SECTIONS)
  627.                 return 0;
  628.  
  629.             section = Sections.Count++;
  630.         #if PACK_CONTENT == true
  631.             strpack (Sections.Tag [section], tag);
  632.         #else
  633.             ZN::strcpy (Sections.Tag [section], tag);
  634.         #endif
  635.             Sections.FirstEntry [section] = Sections.LastEntry [section] = INVALID_ENTRY;
  636.         }
  637.  
  638.         // Add the entry to the section. Section's content is defined by a linear two way list.
  639.     #if PACK_CONTENT == true
  640.         format (line, sizeof (line), "%s=%s", key, value [0] ? value : ("(null)"));
  641.         strpack (Entries.Line [Entries.Count], line);
  642.     #else
  643.         format (Entries.Line [Entries.Count], sizeof (Entries.Line []), "%s=%s", key, value [0] ? value : ("(null)"));
  644.     #endif
  645.         Entries.Tag [Entries.Count] = Sections.Tag [section];
  646.     #if MAX_SECTIONS >= 256
  647.         Entries.Section [Entries.Count] = section;
  648.     #else
  649.         Entries.Section {Entries.Count} = section;
  650.     #endif
  651.         Entries.NextEntry [Entries.Count] = INVALID_ENTRY;
  652.  
  653.         // Add entry to sorted list of entries and move to right correct position in O(n) time.
  654.         SortedEntryList [Entries.Count][0] = ZN::HashKey (key);
  655.         SortedEntryList [Entries.Count][1] = Entries.Count;
  656.         i = Entries.Count - 1;
  657.         while (i >= 0 && SortedEntryList [i][0] > SortedEntryList [i + 1][0])
  658.         {
  659.             ZN::SwapSortedEntries (SortedEntryList [i], SortedEntryList [i + 1]);
  660.             --i;
  661.         }
  662.  
  663.         if (Sections.LastEntry [section] == INVALID_ENTRY) // No entry in this section.
  664.         {
  665.             Sections.FirstEntry [section] = Sections.LastEntry [section] = Entries.Count;
  666.             Entries.PreviousEntry [Entries.Count] = INVALID_ENTRY;
  667.         }
  668.         else
  669.         {
  670.             Entries.NextEntry [Sections.LastEntry [section]] = Entries.Count;
  671.             Entries.PreviousEntry [Entries.Count] = Sections.LastEntry [section];
  672.             Sections.LastEntry [section] = Entries.Count;
  673.         }
  674.         ++Entries.Count;
  675.         FileChanged = true;
  676.     }
  677.     return 1;
  678. }
  679.  
  680. stock ZN::GetString (file [], key [], tag [] = "")
  681. {
  682.     new buf [MAX_LINE_SIZE];
  683.     ZN::GetStringEx (file, key, buf, sizeof (buf), tag);
  684.     return buf;
  685. }
  686.  
  687. stock ZN::GetStringEx (file [], key [], resultt [], size, tag [] = "")
  688. {
  689.     if (file [0] && key [0])
  690.     {
  691.         new
  692.             pos,
  693.             keybuf [MAX_LINE_SIZE];
  694.  
  695.         if (!CurrentFile [0] || strcmp (CurrentFile, file))
  696.         {
  697.             if (!ZN::ParseFile (file, -1, false))
  698.             {
  699.                 resultt [0] = '\0';
  700.                 return 0;
  701.             }
  702.         }
  703.  
  704.         // Find entry and assign the resultt with it's value.
  705.         return (ZN::SearchEntry (key, tag, keybuf, resultt, pos, sizeof (keybuf), size) != INVALID_ENTRY);
  706.     }
  707.     return 0;
  708. }
  709.  
  710. stock ZN::Unset (file [], key [], tag [] = "")
  711. {
  712.     if (file [0] && key [0])
  713.     {
  714.         new
  715.             entry,
  716.             pos,
  717.             keybuf [MAX_LINE_SIZE],
  718.             valbuf [MAX_LINE_SIZE];
  719.  
  720.         if (!CurrentFile [0] || strcmp (CurrentFile, file))
  721.             if (!ZN::ParseFile (file, -1, false))
  722.                 return 0;
  723.  
  724.         if ((entry = ZN::SearchEntry (key, tag, keybuf, valbuf, pos)) != INVALID_ENTRY)
  725.         {
  726.             // Remove entry from it's section.
  727.         #if MAX_SECTIONS >= 256
  728.             if (Sections.FirstEntry [Entries.Section [entry]] == entry) // Is the entry the first entry in the section? Make it's next entry the first entry.
  729.         #else
  730.             if (Sections.FirstEntry [Entries.Section {entry}] == entry)
  731.         #endif
  732.             {
  733.             #if MAX_SECTIONS >= 256
  734.                 Sections.FirstEntry [Entries.Section [entry]] = Entries.NextEntry [entry];
  735.             #else
  736.                 Sections.FirstEntry [Entries.Section {entry}] = Entries.NextEntry [entry];
  737.             #endif
  738.                 if (Entries.NextEntry [entry] != INVALID_ENTRY)
  739.                     Entries.PreviousEntry [Entries.NextEntry [entry]] = INVALID_ENTRY;
  740.             }
  741.             else
  742.             {
  743.                 Entries.NextEntry [Entries.PreviousEntry [entry]] = Entries.NextEntry [entry];
  744.                 if (Entries.NextEntry [entry] != INVALID_ENTRY)
  745.                     Entries.PreviousEntry [Entries.NextEntry [entry]] = Entries.PreviousEntry [entry];
  746.             }
  747.  
  748.         #if MAX_SECTIONS >= 256
  749.             if (Sections.LastEntry [Entries.Section [entry]] == entry)
  750.         #else
  751.             if (Sections.LastEntry [Entries.Section {entry}] == entry)
  752.         #endif
  753.             {
  754.             #if MAX_SECTIONS >= 256
  755.                 Sections.LastEntry [Entries.Section [entry]] = Entries.PreviousEntry [entry];
  756.             #else
  757.                 Sections.LastEntry [Entries.Section {entry}] = Entries.PreviousEntry [entry];
  758.             #endif
  759.                 if (Entries.PreviousEntry [entry] != INVALID_ENTRY)
  760.                     Entries.NextEntry [Entries.PreviousEntry [entry]] = INVALID_ENTRY;
  761.             }
  762.             else
  763.             {
  764.                 Entries.PreviousEntry [Entries.NextEntry [entry]] = Entries.PreviousEntry [entry];
  765.                 if (Entries.PreviousEntry [entry] != INVALID_ENTRY)
  766.                     Entries.NextEntry [Entries.PreviousEntry [entry]] = Entries.NextEntry [entry];
  767.             }
  768.  
  769.             // Move the entry to the end of the sorted list and decrement Entries.Count to forget about the unset Entries.
  770.             while (pos < (Entries.Count - 1))
  771.             {
  772.                 ZN::SwapSortedEntries (SortedEntryList [pos], SortedEntryList [pos + 1]);
  773.                 ++pos;
  774.             }
  775.             --Entries.Count;
  776.             FileChanged = true;
  777.             return 1;
  778.         }
  779.     }
  780.     return 0;
  781. }
  782.  
  783. stock ZN::RenameKey (file [], oldkey [], newkey [], tag [] = "")
  784. {
  785.     if (file [0] && oldkey [0])
  786.     {
  787.         new
  788.             entry,
  789.             pos,
  790.         #if PACK_CONTENT == true
  791.             line [MAX_LINE_SIZE],
  792.         #endif
  793.             keybuf [MAX_LINE_SIZE],
  794.             valbuf [MAX_LINE_SIZE];
  795.  
  796.         if (!CurrentFile [0] || strcmp (CurrentFile, file))
  797.             if (!ZN::ParseFile (file, -1, false))
  798.                 return 0;
  799.  
  800.         if ((entry = ZN::SearchEntry (oldkey, tag, keybuf, valbuf, pos)) != INVALID_ENTRY)
  801.         {
  802.             // Change content of Entries.
  803.         #if PACK_CONTENT == true
  804.             format (line, sizeof (line), "%s=%s", newkey, valbuf [0] ? valbuf : ("(null)"));
  805.             strpack (Entries.Line [entry], line);
  806.         #else
  807.             format (Entries.Line [entry], sizeof (Entries.Line []), "%s=%s", newkey, valbuf [0] ? valbuf : ("(null)"));
  808.         #endif
  809.  
  810.             // Because the hashcode has been changed, the entry has to move in the list.
  811.             SortedEntryList [pos][0] = ZN::HashKey (newkey);
  812.             if (pos < (MAX_ENTRIES - 1) && SortedEntryList [pos][0] > SortedEntryList [pos + 1][0])
  813.             {
  814.                 // Hash value of key is greater than the hash value of it's right neighbor, move to the right by swapping the 2 entries.
  815.                 while (pos < (MAX_ENTRIES - 1) && SortedEntryList [pos][0] > SortedEntryList [pos + 1][0])
  816.                 {
  817.                     ZN::SwapSortedEntries (SortedEntryList [pos], SortedEntryList [pos + 1]);
  818.                     ++pos;
  819.                 }
  820.             }
  821.             else if (pos > 0 && SortedEntryList [pos][0] < SortedEntryList [pos + 1][0])
  822.             {
  823.                 // Hash value of key is smaller than the hash value of it' left neighbor, move to the left by swapping the 2 entries.
  824.                 while (pos > 0 && SortedEntryList [pos][0] < SortedEntryList [pos - 1][0])
  825.                 {
  826.                     ZN::SwapSortedEntries (SortedEntryList [pos], SortedEntryList [pos - 1]);
  827.                     --pos;
  828.                 }
  829.             }
  830.  
  831.             FileChanged = true;
  832.             return 1;
  833.         }
  834.     }
  835.     return 0;
  836. }
  837.  
  838. stock bool: ZN::IsSet (file [], key [], tag [] = "")
  839. {
  840.     new
  841.         pos,
  842.         keybuf [MAX_LINE_SIZE],
  843.         valbuf [MAX_LINE_SIZE];
  844.  
  845.     if (!CurrentFile [0] || strcmp (CurrentFile, file))
  846.         if (!ZN::ParseFile (file, -1, false))
  847.             return false;
  848.  
  849.     // Try to find the Entries.
  850.     return (ZN::SearchEntry (key, tag, keybuf, valbuf, pos) != INVALID_ENTRY);
  851. }
  852.  
  853. stock ZN::SetInt (file [], key [], value, tag [] = "")
  854. {
  855.     new buf [16];
  856.     format (buf, sizeof (buf), "%d", value);
  857.     return ZN::SetString (file, key, buf, tag);
  858. }
  859.  
  860. stock ZN::GetInt (file [], key [], tag [] = "")
  861. {
  862.     new buf [16];
  863.     ZN::GetStringEx (file, key, buf, sizeof (buf), tag);
  864.     return strval (buf);
  865. }
  866.  
  867. stock ZN::SetHex (file [], key [], value, tag [] = "")
  868. {
  869.     new buf [16];
  870.     ZN::hexstr (value, buf);
  871.     return ZN::SetString (file, key, buf, tag);
  872. }
  873.  
  874. stock ZN::GetHex (file [], key [], tag [] = "")
  875. {
  876.     new buf [16];
  877.     ZN::GetStringEx (file, key, buf, sizeof (buf), tag);
  878.     return ZN::strhex (buf);
  879. }
  880.  
  881. stock ZN::SetBin (file [], key [], value, tag [] = "")
  882. {
  883.     new buf [35];
  884.     ZN::binstr (value, buf);
  885.     return ZN::SetString (file, key, buf, tag);
  886. }
  887.  
  888. stock ZN::GetBin (file [], key [], tag [] = "")
  889. {
  890.     new buf [35];
  891.     ZN::GetStringEx (file, key, buf, sizeof (buf), tag);
  892.     return ZN::strbin (buf);
  893. }
  894.  
  895. stock ZN::SetFloat (file [], key [], Float: value, tag [] = "")
  896. {
  897.     new buf [32];
  898.     format (buf, sizeof (buf), "%.8f", value);
  899.     return ZN::SetString (file, key, buf, tag);
  900. }
  901.  
  902. stock Float: ZN::GetFloat (file [], key [], tag [] = "")
  903. {
  904.     new buf [32];
  905.     ZN::GetStringEx (file, key, buf, sizeof (buf), tag);
  906.     return floatstr (buf);
  907. }
  908.  
  909. stock bool: ZN::GetBool (file [], key [], tag [] = "")
  910. {
  911.     new buf [16];
  912.     ZN::GetStringEx (file, key, buf, sizeof (buf), tag);
  913.     return (strval (buf) || (buf [0] && !strcmp (buf, "true", true)));
  914. }
  915.  
  916. stock ZN::SetBool (file [], key [], bool: value, tag [] = "")
  917.     return ZN::SetString (file, key, value ? ("true") : ("false"), tag);
  918.  
  919. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  920.  
  921. stock ZN::PrintFile (comment [] = "")
  922. {
  923.     if (CurrentFile [0])
  924.     {
  925.         new
  926.             bool: firstline = true,
  927.             entry,
  928.         #if PACK_CONTENT == true
  929.             buf [MAX_LINE_SIZE],
  930.         #endif
  931.             entries,
  932.             i;
  933.  
  934.         printf ("[DOF] Current file: %s", CurrentFile);
  935.         for ( ; i < Sections.Count; ++i)
  936.         {
  937.             if (i)
  938.             {
  939.                 if (!firstline)
  940.                     print (" ");
  941.                 else
  942.                     firstline = false;
  943.             #if PACK_CONTENT == true
  944.                 strunpack (buf, Sections.Tag [i]);
  945.                 printf ("[%s]", buf);
  946.             #else
  947.                 printf ("[%s]", Sections.Tag [i]);
  948.             #endif
  949.             }
  950.             entry = Sections.FirstEntry [i];
  951.             while (entry != INVALID_ENTRY)
  952.             {
  953.             #if PACK_CONTENT == true
  954.                 strunpack (buf, Entries.Line [entry]);
  955.                 print (buf);
  956.             #else
  957.                 print (Entries.Line [entry]);
  958.             #endif
  959.                 entry = Entries.NextEntry [entry];
  960.                 firstline = false;
  961.                 ++entries;
  962.             }
  963.         }
  964.         printf ("* %d sections, %d entries", i, entries);
  965.         if (comment [0])
  966.             printf ("* Comment: %s", comment);
  967.         return 1;
  968.     }
  969.     return 0;
  970. }
  971.  
  972. stock ZN::WriteFile ()
  973. {
  974.     if (CurrentFile [0])
  975.     {
  976.         new
  977.             File: f = fopen (CurrentFile, io_write),
  978.             bool: firstline = true,
  979.             entry;
  980.  
  981.         if (f)
  982.         {
  983.             for (new i; i < Sections.Count; ++i)
  984.             {
  985.                 if (Sections.FirstEntry [i] != INVALID_ENTRY) // Do not write when empty.
  986.                 {
  987.                     if (i)
  988.                     {
  989.                         if (!firstline)
  990.                         {
  991.                             fputchar (f, '\r', UseUTF8);
  992.                             fputchar (f, '\n', UseUTF8);
  993.                         }
  994.                         else
  995.                             firstline = false;
  996.                         fputchar (f, '[', UseUTF8);
  997.                         fwritechars (f, Sections.Tag [i]);
  998.                         fputchar (f, ']', UseUTF8);
  999.                         fputchar (f, '\r', UseUTF8);
  1000.                         fputchar (f, '\n', UseUTF8);
  1001.                     }
  1002.  
  1003.                     entry = Sections.FirstEntry [i];
  1004.                     while (entry != INVALID_ENTRY)
  1005.                     {
  1006.                         fwritechars (f, Entries.Line [entry]);
  1007.                         fputchar (f, '\r', UseUTF8);
  1008.                         fputchar (f, '\n', UseUTF8);
  1009.                         entry = Entries.NextEntry [entry];
  1010.                         firstline = false;
  1011.                     }
  1012.                 }
  1013.             }
  1014.             FileChanged = false;
  1015.             return fclose (f);
  1016.         }
  1017.     }
  1018.     return 0;
  1019. }
  1020.  
  1021. stock ZN::ParseFile (file [], extraid = -1, bool: callback = false)
  1022. {
  1023.     if (file [0] && ZN::FileExists (file))
  1024.     {
  1025.         /*
  1026.         Write the file in the buffer when:
  1027.         - There is actually a file in the buffer
  1028.         - The file in the buffer is not the file you want to parse and this file has been changed.
  1029.         - Or the current file is the file you want to and has been changed.
  1030.         */
  1031.         //if (CurrentFile [0] && ((strcmp (CurrentFile, file) && FileChanged) || FileChanged))
  1032.         if (CurrentFile [0] && FileChanged) // Equal to the query above but shorter.
  1033.             ZN::WriteFile ();
  1034.  
  1035.         new
  1036.             File: f = fopen (file, io_readwrite),
  1037.             buf [MAX_LINE_SIZE],
  1038.         #if PACK_CONTENT == true
  1039.             line [MAX_LINE_SIZE char],
  1040.             tag [MAX_SECTION_TAG],
  1041.         #else
  1042.             line [MAX_LINE_SIZE],
  1043.         #endif
  1044.             key [MAX_LINE_SIZE],
  1045.             value [MAX_LINE_SIZE],
  1046.             c,
  1047.             pos;
  1048.  
  1049.         if (f)
  1050.         {
  1051.             FileChanged = false;
  1052.             ZN::SetFile (file);
  1053.  
  1054.             Sections.Count = 1;
  1055.             Entries.Count = 0;
  1056.             Sections.FirstEntry [0] = Sections.LastEntry [0] = INVALID_ENTRY;
  1057.  
  1058.             for (new i, size = flength (f); i < size; ++i)
  1059.             {
  1060.                 c = fgetchar (f, 0, UseUTF8);
  1061.                 if (pos == MAX_LINE_SIZE - 1 || c == '\n' || c == '\r')
  1062.                     c = '\0';
  1063.             #if PACK_CONTENT == true
  1064.                 line {pos++} = c;
  1065.             #else
  1066.                 line [pos++] = c;
  1067.             #endif
  1068.  
  1069.                 if (c == '\0')
  1070.                 {
  1071.                     // A new section found. Add the section to the list of sections.
  1072.                 #if PACK_CONTENT == true
  1073.                     if (line {0} == '[')
  1074.                 #else
  1075.                     if (line [0] == '[')
  1076.                 #endif
  1077.                     {
  1078.                         if (Sections.Count < MAX_SECTIONS)
  1079.                         {
  1080.                             pos = 1;
  1081.                         #if PACK_CONTENT == true
  1082.                             while (line {pos} && line {pos} != ']' && (pos - 1) < MAX_SECTION_TAG)
  1083.                             {
  1084.                                 Sections.Tag [Sections.Count]{pos - 1} = line {pos};
  1085.                                 ++pos;
  1086.                             }
  1087.                             Sections.Tag [Sections.Count]{pos - 1} = '\0';
  1088.                         #else
  1089.                             while (line [pos] && line [pos] != ']' && (pos - 1) < MAX_SECTION_TAG)
  1090.                             {
  1091.                                 Sections.Tag [Sections.Count][pos - 1] = line [pos];
  1092.                                 ++pos;
  1093.                             }
  1094.                             Sections.Tag [Sections.Count][pos - 1] = '\0';
  1095.                         #endif
  1096.                             Sections.FirstEntry [Sections.Count] = Sections.LastEntry [Sections.Count] = INVALID_ENTRY;
  1097.                             ++Sections.Count;
  1098.                         }
  1099.                     }
  1100.                     else
  1101.                     {
  1102.                     #if PACK_CONTENT == true
  1103.                         if (line {0})
  1104.                     #else
  1105.                         if (line [0])
  1106.                     #endif
  1107.                         {
  1108.                         #if PACK_CONTENT == true
  1109.                             strunpack (buf, line);
  1110.                             ZN::ParseLine (buf, key, value);
  1111.                             strunpack (tag, Sections.Tag [Sections.Count - 1]);
  1112.  
  1113.                             // Call a specific function for a specific entry - ZCMD-style!
  1114.                             if (callback)
  1115.                             {
  1116.                                 format (buf, sizeof (buf), "_OnParseFile_%s_%s", tag, key);
  1117.                                 if (!CallRemoteFunction (buf, "is", extraid, value))
  1118.                                     CallRemoteFunction ("_OnDefaultParseFile", "issss", extraid, value [0] ? value : ("\1"), key, Sections.Tag [Sections.Count - 1][0] ? Sections.Tag [Sections.Count - 1] : ("\1"), file);
  1119.                             }
  1120.                         #else
  1121.                             ZN::ParseLine (line, key, value);
  1122.  
  1123.                             // Call a specific function for a specific entry - ZCMD-style!
  1124.                             if (callback)
  1125.                             {
  1126.                                 format (buf, sizeof (buf), "_OnParseFile_%s_%s", Sections.Tag [Sections.Count - 1], key);
  1127.                                 if (!CallRemoteFunction (buf, "is", extraid, value))
  1128.                                     CallRemoteFunction ("_OnDefaultParseFile", "issss", extraid, value [0] ? value : ("\1"), key, Sections.Tag [Sections.Count - 1][0] ? Sections.Tag [Sections.Count - 1] : ("\1"), file);
  1129.                             }
  1130.                         #endif
  1131.  
  1132.                             // Add entry to it's section and to the list which will be sorted.
  1133.                             Entries.Line [Entries.Count] = line;
  1134.                             Entries.Tag [Entries.Count] = Sections.Tag [Sections.Count - 1];
  1135.                         #if MAX_SECTIONS >= 256
  1136.                             Entries.Section [Entries.Count] = Sections.Count - 1;
  1137.                         #else
  1138.                             Entries.Section {Entries.Count} = Sections.Count - 1;
  1139.                         #endif
  1140.                             Entries.NextEntry [Entries.Count] = INVALID_ENTRY;
  1141.  
  1142.                             SortedEntryList [Entries.Count][0] = ZN::HashKey (key);
  1143.                             SortedEntryList [Entries.Count][1] = Entries.Count;
  1144.  
  1145.                             if (Sections.LastEntry [Sections.Count - 1] == INVALID_ENTRY)
  1146.                             {
  1147.                                 Sections.FirstEntry [Sections.Count - 1] = Sections.LastEntry [Sections.Count - 1] = Entries.Count;
  1148.                                 Entries.PreviousEntry [Entries.Count] = INVALID_ENTRY;
  1149.                             }
  1150.                             else
  1151.                             {
  1152.                                 Entries.NextEntry [Sections.LastEntry [Sections.Count - 1]] = Entries.Count;
  1153.                                 Entries.PreviousEntry [Entries.Count] = Sections.LastEntry [Sections.Count - 1];
  1154.                                 Sections.LastEntry [Sections.Count - 1] = Entries.Count;
  1155.                             }
  1156.                             ++Entries.Count;
  1157.                         }
  1158.                     }
  1159.                     pos = 0;
  1160.                 }
  1161.             }
  1162.             /*
  1163.              * Sort list of entries by it's hashcodes in O(n * log n) time.
  1164.              * (Worst case is actually O(n * n), however, this QuickSort implementation chooses a randomized pivot
  1165.              * to minimize the chance for the worst case.)
  1166.              */
  1167.             ZN::SortEntries (SortedEntryList, 0, Entries.Count - 1, true);
  1168.             return fclose (f);
  1169.         }
  1170.     }
  1171.     return 0;
  1172. }
  1173.  
  1174. // Rather useless.
  1175. stock ZN::ReparseFile (file [], extraid, bool: callback = true)
  1176. {
  1177.     if (file [0] && CurrentFile [0] && !strcmp (file, CurrentFile))
  1178.     {
  1179.         CurrentFile [0] = '\0';
  1180.         return ZN::ParseFile (file, extraid, callback);
  1181.     }
  1182.     return 0;
  1183. }
  1184.  
  1185. private ZN::ParseLine (line [], key [], value [], keysize = sizeof (key), valuesize = sizeof (value))
  1186. {
  1187.     new
  1188.         pos,
  1189.         readpos;
  1190.  
  1191.     if ((pos = charfind (line, '=')) != -1)
  1192.     {
  1193.         // Read key and value.
  1194.         readpos = pos - 1;
  1195.         while (readpos >= 0 && line [readpos] == '=')
  1196.             --readpos;
  1197.  
  1198.         if (readpos >= 0 && keysize > (readpos + 1))
  1199.         {
  1200.             key [readpos + 1] = '\0';
  1201.             while (readpos >= 0)
  1202.             {
  1203.                 key [readpos] = line [readpos];
  1204.                 --readpos;
  1205.             }
  1206.         }
  1207.         else
  1208.             return 0;
  1209.  
  1210.         readpos = pos + 1;
  1211.         ++pos;
  1212.         while (line [readpos] == '=')
  1213.         {
  1214.             ++pos;
  1215.             ++readpos;
  1216.         }
  1217.  
  1218.         if (line [readpos])
  1219.         {
  1220.             while (readpos >= 0 && line [readpos] && valuesize > (readpos - pos + 1))
  1221.             {
  1222.                 value [readpos - pos] = line [readpos];
  1223.                 ++readpos;
  1224.             }
  1225.             value [readpos - pos] = '\0';
  1226.         }
  1227.         else
  1228.         {
  1229.             key [0] = value [0] = '\0';
  1230.             return 0;
  1231.         }
  1232.  
  1233.         if (!strcmp (value, "(null)", true))
  1234.             value [0] = '\0';
  1235.         return 1;
  1236.     }
  1237.     key [0] = value [0] = '\0';
  1238.     return 0;
  1239. }
  1240.  
  1241. stock ZN::File (user [])
  1242. {
  1243.     new newfile [MAX_FILE_SIZE];
  1244.     format (newfile, sizeof (newfile), USER_FILE_PATH, ZN::udb_encode (user));
  1245.     return newfile;
  1246. }
  1247.  
  1248. stock bool: ZN::CheckLogin (file [], password [])
  1249.     return (file [0] && password [0] && ZN::num_hash (password) == ZN::GetInt (file, USER_PW_HASH_KEY));
  1250.  
  1251. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  1252.  
  1253. stock ZN::binstr (value, dest [], size = sizeof (dest))
  1254. {
  1255.     new buf [32 + 3] = "0b";
  1256.     for (new i = 0; i < 32; ++i)
  1257.         buf [i + 2] = '0' + ((value >>> (31 - i)) & 1);
  1258.  
  1259.     ZN::strcpy (dest, buf, size);
  1260. }
  1261.     //format (dest, size, "0b%b", value);
  1262.  
  1263. stock ZN::hexstr (value, dest [], size = sizeof (dest))
  1264. {
  1265.     static const characters [] =
  1266.     {
  1267.         '0', '1', '2', '3',
  1268.         '4', '5', '6', '7',
  1269.         '8', '9', 'A', 'B',
  1270.         'C', 'D', 'E', 'F'
  1271.     };
  1272.  
  1273.     new buf [8 + 3] = "0x";
  1274.  
  1275.     for (new i = 0; i < 8; ++i)
  1276.         buf [2 + i] = characters [(value >>> ((7 - i) << 2)) & 0x0F];
  1277.  
  1278.     ZN::strcpy (dest, buf, size);
  1279. }
  1280.     //format (dest, size, "0x%x", value);
  1281.  
  1282. stock ZN::strhex (string [])
  1283. {
  1284.     new
  1285.         i,
  1286.         value;
  1287.  
  1288.     if (string [0] == '0' && (string [1] == 'x' || string [1] == 'X'))
  1289.         i = 2;
  1290.  
  1291.     while (string [i])
  1292.     {
  1293.         value <<= 4;
  1294.         switch (string [i])
  1295.         {
  1296.             case '0' .. '9':
  1297.                 value |= string [i] - '0';
  1298.  
  1299.             case 'A' .. 'F':
  1300.                 value |= string [i] - 'A' + 10;
  1301.  
  1302.             case 'a' .. 'f':
  1303.                 value |= string [i] - 'a' + 10;
  1304.  
  1305.             default:
  1306.                 return 0;
  1307.         }
  1308.         ++i;
  1309.     }
  1310.     return value;
  1311. }
  1312.  
  1313. stock ZN::strbin (string [])
  1314. {
  1315.     new
  1316.         i,
  1317.         value;
  1318.  
  1319.     if (string [0] == '0' && (string [1] == 'b' || string [1] == 'B'))
  1320.         i = 2;
  1321.  
  1322.     while (string [i])
  1323.     {
  1324.         if (string [i] != '1' && string [i] != '0')
  1325.             return 0;
  1326.  
  1327.         value <<= 1;
  1328.         value |= (string [i] - '0');
  1329.         ++i;
  1330.     }
  1331.     return value;
  1332. }
  1333.  
  1334. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  1335.  
  1336. private charfind (string [], c)
  1337. {
  1338.     for (new i, len = strlen (string); i < len; ++i)
  1339.         if (string [i] == c)
  1340.             return i;
  1341.     return -1;
  1342. }
  1343.  
  1344. private fwritechars (File: handle, c [])
  1345. {
  1346.     new pos;
  1347. #if PACK_CONTENT == true
  1348.     while (c {pos})
  1349.         fputchar (handle, c {pos++}, UseUTF8);
  1350. #else
  1351.     while (c [pos])
  1352.         fputchar (handle, c [pos++], UseUTF8);
  1353. #endif
  1354. }
  1355.  
  1356. private ZN::SortEntries (entries [][2], l, r, bool: randomize = true)
  1357. {
  1358.     if (r > l)
  1359.     {
  1360.         if (randomize)
  1361.         {
  1362.             new k = l + (random (65535) % (r - l + 1));
  1363.             ZN::SwapSortedEntries (entries [k], entries [r]);
  1364.         }
  1365.  
  1366.         new
  1367.             i = l - 1,
  1368.             j = r,
  1369.             pivot = entries [r][0];
  1370.  
  1371.         while (i < j)
  1372.         {
  1373.             do
  1374.                 ++i;
  1375.             while (entries [i][0] <= pivot && i < r);
  1376.  
  1377.             do
  1378.                 --j;
  1379.             while (entries [j][0] >= pivot && j > l);
  1380.  
  1381.             if (i < j)
  1382.                 ZN::SwapSortedEntries (entries [i], entries [j]);
  1383.         }
  1384.         ZN::SwapSortedEntries (entries [i], entries [r]);
  1385.         ZN::SortEntries (entries, l, i - 1, randomize);
  1386.         ZN::SortEntries (entries, i + 1, r, randomize);
  1387.     }
  1388. }
  1389.  
  1390. private ZN::SwapSortedEntries (a [2], b [2])
  1391. {
  1392.     new c [2];
  1393.     c [0] = a [0];
  1394.     c [1] = a [1];
  1395.     a [0] = b [0];
  1396.     a [1] = b [1];
  1397.     b [0] = c [0];
  1398.     b [1] = c [1];
  1399. }
  1400.  
  1401. stock ZN::SortAllSections (file [], bool: ignorecase = true, bool: ascending = true)
  1402. {
  1403.     if (file [0])
  1404.     {
  1405.         if (!CurrentFile [0] || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.
  1406.             if (!ZN::ParseFile (file, -1, false))
  1407.                 return 0;
  1408.  
  1409.         new
  1410.             entries [MAX_ENTRIES],
  1411.             keys [MAX_ENTRIES][MAX_LINE_SIZE],
  1412.             key [MAX_LINE_SIZE],
  1413.             value [MAX_LINE_SIZE],
  1414.         #if PACK_CONTENT == true
  1415.             line [MAX_LINE_SIZE],
  1416.         #endif
  1417.             entry,
  1418.             i;
  1419.  
  1420.         for (new section = 0; section < Sections.Count; ++section)
  1421.         {
  1422.             i = 0;
  1423.             entry = Sections.FirstEntry [section];
  1424.             while (entry != INVALID_ENTRY)
  1425.             {
  1426.             #if PACK_CONTENT == true
  1427.                 strunpack (line, Entries.Line [entry]);
  1428.                 ZN::ParseLine (line, key, value);
  1429.             #else
  1430.                 ZN::ParseLine (Entries.Line [entry], key, value);
  1431.             #endif
  1432.                 keys [i][0] = '\0';
  1433.                 strcat (keys [i], key);
  1434.                 entries [i] = entry;
  1435.                 entry = Entries.NextEntry [entry];
  1436.                 ++i;
  1437.             }
  1438.  
  1439.             if (i > 0)
  1440.                 ZN::SortSection_Internal (section, entries, keys, 0, i - 1, ignorecase, ascending);
  1441.         }
  1442.         return 1;
  1443.     }
  1444.     return 0;
  1445. }
  1446.  
  1447. stock ZN::SortSection (file [], tag [], bool: ignorecase = true, bool: ascending = true)
  1448. {
  1449.     if (file [0])
  1450.     {
  1451.         if (!CurrentFile [0] || strcmp (CurrentFile, file)) // No file in buffer or the file you want to read from is not the file in the buffer.
  1452.             if (!ZN::ParseFile (file, -1, false))
  1453.                 return 0;
  1454.  
  1455.         new
  1456.             section = INVALID_SECTION,
  1457.             entries [MAX_ENTRIES],
  1458.             keys [MAX_ENTRIES][MAX_LINE_SIZE],
  1459.             key [MAX_LINE_SIZE],
  1460.             buf [MAX_LINE_SIZE],
  1461.         #if PACK_CONTENT == true
  1462.             line [MAX_LINE_SIZE],
  1463.         #endif
  1464.             entry,
  1465.             i;
  1466.  
  1467.         if (!tag [0])
  1468.             section = 0;
  1469.         else
  1470.         {
  1471.             for (i = 1; i < Sections.Count; ++i)
  1472.             {
  1473.             #if PACK_CONTENT == true
  1474.                 strunpack (buf, Sections.Tag [i]);
  1475.                 if (buf [0] && !strcmp (tag, buf, !CaseSensitive))
  1476.                 {
  1477.                     section = i;
  1478.                     break;
  1479.                 }
  1480.             #else
  1481.                 if (Sections.Tag [i][0] && !strcmp (tag, Sections.Tag [i], !CaseSensitive))
  1482.                 {
  1483.                     section = i;
  1484.                     break;
  1485.                 }
  1486.             #endif
  1487.             }
  1488.         }
  1489.  
  1490.         if (section != INVALID_SECTION)
  1491.         {
  1492.             i = 0;
  1493.             entry = Sections.FirstEntry [section];
  1494.             while (entry != INVALID_ENTRY)
  1495.             {
  1496.             #if PACK_CONTENT == true
  1497.                 strunpack (line, Entries.Line [entry]);
  1498.                 ZN::ParseLine (line, key, buf);
  1499.             #else
  1500.                 ZN::ParseLine (Entries.Line [entry], key, buf);
  1501.             #endif
  1502.                 keys [i][0] = '\0';
  1503.                 strcat (keys [i], key);
  1504.                 entries [i] = entry;
  1505.                 entry = Entries.NextEntry [entry];
  1506.                 ++i;
  1507.             }
  1508.  
  1509.             if (i > 0)
  1510.             {
  1511.                 ZN::SortSection_Internal (section, entries, keys, 0, i - 1, ignorecase, ascending);
  1512.                 return 1;
  1513.             }
  1514.         }
  1515.     }
  1516.     return 0;
  1517. }
  1518.  
  1519. private ZN::SortSection_Internal (section, entries [], keys [][], l, r, bool: ignorecase = true, bool: ascending = true)
  1520. {
  1521.     // Entries must be stored into an array...
  1522.     if (0 <= section < Sections.Count && r > l)
  1523.     {
  1524.         new
  1525.             i = l - 1,
  1526.             j = r,
  1527.             buf [MAX_LINE_SIZE];
  1528.  
  1529.         static
  1530.             pivot [MAX_LINE_SIZE]; // Must be static, otherwise too much memory usage during recursion ==> Script will crash!
  1531.  
  1532.         pivot [0] = '\0';
  1533.         strcat (pivot, keys [r]);
  1534.  
  1535.         while (i < j)
  1536.         {
  1537.             if (ascending)
  1538.             {
  1539.                 do
  1540.                     ++i;
  1541.                 while (strcmp (keys [i], pivot,  ignorecase) <= 0 && i < r);
  1542.  
  1543.                 do
  1544.                     --j;
  1545.                 while (strcmp (keys [j], pivot, ignorecase) >= 0 && j > l);
  1546.             }
  1547.             else
  1548.             {
  1549.                 do
  1550.                     ++i;
  1551.                 while (strcmp (keys [i], pivot,  ignorecase) >= 0 && i < r);
  1552.  
  1553.                 do
  1554.                     --j;
  1555.                 while (strcmp (keys [j], pivot, ignorecase) <= 0 && j > l);
  1556.             }
  1557.  
  1558.             if (i < j)
  1559.             {
  1560.                 ZN::SwapEntries (section, entries [i], entries [j]);
  1561.  
  1562.                 ZN::strcpy (buf, keys [i]);
  1563.                 ZN::strcpy (keys [i], keys [j], MAX_LINE_SIZE);
  1564.                 ZN::strcpy (keys [j], buf, MAX_LINE_SIZE);
  1565.  
  1566.                 entries [i] ^= entries [j];
  1567.                 entries [j] ^= entries [i];
  1568.                 entries [i] ^= entries [j];
  1569.             }
  1570.         }
  1571.  
  1572.         if (i != r)
  1573.         {
  1574.             ZN::SwapEntries (section, entries [i], entries [r]);
  1575.  
  1576.             ZN::strcpy (buf, keys [i]);
  1577.             ZN::strcpy (keys [i], keys [r], MAX_LINE_SIZE);
  1578.             ZN::strcpy (keys [r], buf, MAX_LINE_SIZE);
  1579.  
  1580.             entries [i] ^= entries [r];
  1581.             entries [r] ^= entries [i];
  1582.             entries [i] ^= entries [r];
  1583.         }
  1584.  
  1585.         ZN::SortSection_Internal (section, entries, keys, l, i - 1, ignorecase, ascending);
  1586.         ZN::SortSection_Internal (section, entries, keys, i + 1, r, ignorecase, ascending);
  1587.     }
  1588. }
  1589.  
  1590. private ZN::SwapEntries (section, entry1, entry2)
  1591. {
  1592.     // This swaps two entries in the entry list of a section. (Pointers are swapped)
  1593.     if (0 <= section < Sections.Count && 0 <= entry1 <= Entries.Count && 0 <= entry2 <= Entries.Count)
  1594.     {
  1595.         if (entry1 == Sections.FirstEntry [section])
  1596.             Sections.FirstEntry [section] = entry2;
  1597.         else if (entry2 == Sections.FirstEntry [section])
  1598.             Sections.FirstEntry [section] = entry1;
  1599.  
  1600.         if (entry1 == Sections.LastEntry [section])
  1601.             Sections.LastEntry [section] = entry2;
  1602.         else if (entry2 == Sections.LastEntry [section])
  1603.             Sections.LastEntry [section] = entry1;
  1604.  
  1605.         if (Entries.NextEntry [entry1] == entry2)
  1606.         {
  1607.             Entries.NextEntry [entry1] = Entries.NextEntry [entry2];
  1608.             Entries.PreviousEntry [entry2] = Entries.PreviousEntry [entry1];
  1609.  
  1610.             if (Entries.PreviousEntry [entry1] != INVALID_ENTRY)
  1611.                 Entries.NextEntry [Entries.PreviousEntry [entry1]] = entry2;
  1612.  
  1613.             if (Entries.NextEntry [entry2] != INVALID_ENTRY)
  1614.                 Entries.PreviousEntry [Entries.NextEntry [entry2]] = entry1;
  1615.  
  1616.             Entries.NextEntry [entry2] = entry1;
  1617.             Entries.PreviousEntry [entry1] = entry2;
  1618.         }
  1619.         else if (Entries.NextEntry [entry2] == entry1)
  1620.         {
  1621.             Entries.NextEntry [entry2] = Entries.NextEntry [entry1];
  1622.             Entries.PreviousEntry [entry1] = Entries.PreviousEntry [entry2];
  1623.  
  1624.             if (Entries.PreviousEntry [entry2] != INVALID_ENTRY)
  1625.                 Entries.NextEntry [Entries.PreviousEntry [entry2]] = entry1;
  1626.  
  1627.             if (Entries.NextEntry [entry1] != INVALID_ENTRY)
  1628.                 Entries.PreviousEntry [Entries.NextEntry [entry1]] = entry2;
  1629.  
  1630.             Entries.NextEntry [entry1] = entry2;
  1631.             Entries.PreviousEntry [entry2] = entry1;
  1632.         }
  1633.         else
  1634.         {
  1635.             new pointer;
  1636.  
  1637.             if (Entries.PreviousEntry [entry1] != INVALID_ENTRY)
  1638.                 Entries.NextEntry [Entries.PreviousEntry [entry1]] = entry2;
  1639.  
  1640.             if (Entries.NextEntry [entry1] != INVALID_ENTRY)
  1641.                 Entries.PreviousEntry [Entries.NextEntry [entry1]] = entry2;
  1642.  
  1643.             if (Entries.PreviousEntry [entry2] != INVALID_ENTRY)
  1644.                 Entries.NextEntry [Entries.PreviousEntry [entry2]] = entry1;
  1645.  
  1646.             if (Entries.NextEntry [entry2] != INVALID_ENTRY)
  1647.                 Entries.PreviousEntry [Entries.NextEntry [entry2]] = entry1;
  1648.  
  1649.             pointer = Entries.NextEntry [entry1];
  1650.             Entries.NextEntry [entry1] = Entries.NextEntry [entry2];
  1651.             Entries.NextEntry [entry2] = pointer;
  1652.  
  1653.             pointer = Entries.PreviousEntry [entry1];
  1654.             Entries.PreviousEntry [entry1] = Entries.PreviousEntry [entry2];
  1655.             Entries.PreviousEntry [entry2] = pointer;
  1656.         }
  1657.         return 1;
  1658.     }
  1659.     return 0;
  1660. }
  1661.  
  1662. private ZN::HashKey (key [])
  1663. {
  1664.     new
  1665.         h = -1,
  1666.         i,
  1667.         j;
  1668.  
  1669.     if (CaseSensitive)
  1670.     {
  1671.         while ((j = key [i++]))
  1672.             h = h * 33 + j;
  1673.     }
  1674.     else
  1675.     {
  1676.         while ((j = tolower (key [i++])))
  1677.             h = h * 33 + j;
  1678.     }
  1679.     return h;
  1680. }
  1681.  
  1682. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  1683.  
  1684. stock ZN::strcpy (dest [], const src [], size = sizeof (dest))
  1685. {
  1686.     dest [0] = '\0';
  1687.     strcat (dest, src, size);
  1688. }
  1689.  
  1690. // Replace [oldstr] with [newstr] in [srcstr] and copy write the new string to 'deststr'.
  1691.  
  1692. stock ZN::strreplace (const newstr [], const oldstr [], const srcstr [], deststr [], bool: ignorecase = false, size = sizeof (deststr))
  1693. {
  1694.     new
  1695.         newlen = strlen (newstr),
  1696.         oldlen = strlen (oldstr),
  1697.         srclen = strlen (srcstr),
  1698.         idx,
  1699.         rep;
  1700.  
  1701.     for (new i = 0; i < srclen; ++i)
  1702.     {
  1703.         if (idx < (size - 1))
  1704.         {
  1705.             if ((i + oldlen) <= srclen)
  1706.             {
  1707.                 if (!strcmp (srcstr [i], oldstr, ignorecase, oldlen))
  1708.                 {
  1709.                     deststr [idx] = '\0';
  1710.                     strcat (deststr, newstr, size);
  1711.                     ++rep;
  1712.                     idx += newlen;
  1713.                     i += oldlen - 1;
  1714.                 }
  1715.                 else
  1716.                     deststr [idx++] = srcstr [i];
  1717.             }
  1718.             else
  1719.                 deststr [idx++] = srcstr [i];
  1720.         }
  1721.         else
  1722.             return rep;
  1723.     }
  1724.     deststr [idx] = '\0';
  1725.     return rep;
  1726. }
  1727.  
  1728. stock ZN::udb_encode (nickname [])
  1729. {
  1730.   new tmp[MAX_STRING];
  1731.   set(tmp,nickname);
  1732.   tmp=strreplace("_","_00",tmp);
  1733.   tmp=strreplace(";","_01",tmp);
  1734.   tmp=strreplace("!","_02",tmp);
  1735.   tmp=strreplace("/","_03",tmp);
  1736.   tmp=strreplace("\\","_04",tmp);
  1737.   tmp=strreplace("[","_05",tmp);
  1738.   tmp=strreplace("]","_06",tmp);
  1739.   tmp=strreplace("?","_07",tmp);
  1740.   tmp=strreplace(".","_08",tmp);
  1741.   tmp=strreplace("*","_09",tmp);
  1742.   tmp=strreplace("<","_10",tmp);
  1743.   tmp=strreplace(">","_11",tmp);
  1744.   tmp=strreplace("{","_12",tmp);
  1745.   tmp=strreplace("}","_13",tmp);
  1746.   tmp=strreplace(" ","_14",tmp);
  1747.   tmp=strreplace("\"","_15",tmp);
  1748.   tmp=strreplace(":","_16",tmp);
  1749.   tmp=strreplace("|","_17",tmp);
  1750.   tmp=strreplace("=","_18",tmp);
  1751.   return tmp;
  1752. }
  1753.  
  1754. stock ZN::udb_decode (nickname [])
  1755. {
  1756.   new tmp[MAX_STRING];
  1757.   set(tmp,nickname);
  1758.   tmp=strreplace("_01",";",tmp);
  1759.   tmp=strreplace("_02","!",tmp);
  1760.   tmp=strreplace("_03","/",tmp);
  1761.   tmp=strreplace("_04","\\",tmp);
  1762.   tmp=strreplace("_05","[",tmp);
  1763.   tmp=strreplace("_06","]",tmp);
  1764.   tmp=strreplace("_07","?",tmp);
  1765.   tmp=strreplace("_08",".",tmp);
  1766.   tmp=strreplace("_09","*",tmp);
  1767.   tmp=strreplace("_10","<",tmp);
  1768.   tmp=strreplace("_11",">",tmp);
  1769.   tmp=strreplace("_12","{",tmp);
  1770.   tmp=strreplace("_13","}",tmp);
  1771.   tmp=strreplace("_14"," ",tmp);
  1772.   tmp=strreplace("_15","\"",tmp);
  1773.   tmp=strreplace("_16",":",tmp);
  1774.   tmp=strreplace("_17","|",tmp);
  1775.   tmp=strreplace("_18","=",tmp);
  1776.   tmp=strreplace("_00","_",tmp);
  1777.   return tmp;
  1778. }
  1779.  
  1780. stock ZN::num_hash (buf [])
  1781. {
  1782.     new length=strlen(buf);
  1783.     new s1 = 1;
  1784.     new s2 = 0;
  1785.     new n;
  1786.     for (n=0; n<length; n++)
  1787.     {
  1788.        s1 = (s1 + buf[n]) % 65521;
  1789.        s2 = (s2 + s1)     % 65521;
  1790.     }
  1791.     return (s2 << 16) + s1;
  1792. }
  1793.  
  1794. stock ZN::tssa_encode (passtxt [])
  1795. {
  1796.     new tmp[MAX_STRING];
  1797.     set(tmp,passtxt);
  1798.     tmp=strreplace("a","0",tmp);
  1799.     tmp=strreplace("e","1",tmp);
  1800.     tmp=strreplace("i","2",tmp);
  1801.     tmp=strreplace("o","3",tmp);
  1802.     tmp=strreplace("u","4",tmp);
  1803.     tmp=strreplace("5","x",tmp);
  1804.     tmp=strreplace("6","y",tmp);
  1805.     tmp=strreplace("7","z",tmp);
  1806.     tmp=strreplace("8","r",tmp);
  1807.     tmp=strreplace("9","s",tmp);
  1808.     tmp=strreplace("tssa","7554",tmp);
  1809.     return tmp;
  1810. }
  1811.  
  1812. /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  1813.  
  1814.     #tryinclude <dutils>
  1815.  
  1816.     #define dUser(%0).(             ZN_GetString(ZN_File(%0),
  1817.     #define dUserSet(%0).(          ZN_SetString(ZN_File(%0),
  1818.     #define dUserINT(%0).(          ZN_GetInt(ZN_File(%0),
  1819.     #define dUserSetINT(%0).(       ZN_SetInt(ZN_File(%0),
  1820.     #define dUserFLOAT(%0).(        ZN_GetFloat(ZN_File(%0),
  1821.     #define dUserSetFLOAT(%0).(     ZN_SetFloat(ZN_File(%0),
  1822.     #define udb_Create(%0,%1)       ZN_CreateFile(ZN_File(%0),%1)
  1823.     #define udb_RenameUser(%0,%1)   ZN_RenameFile(ZN_File(%0),ZN_File(%1))
  1824.     #define udb_Exists(%0)          ZN_FileExists(ZN_File(%0))
  1825.     #define udb_Remove(%0)          ZN_RemoveFile(ZN_File(%0))
  1826.     #define udb_CheckLogin(%0,%1)   ZN_CheckLogin(ZN_File(%0),%1)
  1827.  
  1828.     #if !defined _dudb_included
  1829.         #define _dudb_included
  1830.     #endif
  1831.    
  1832.     #define dini_Exists             ZN_FileExists
  1833.     #define dini_Remove             ZN_RemoveFile
  1834.     #define dini_Create             ZN_CreateFile
  1835.     #define dini_Set                ZN_SetString
  1836.     #define dini_Get                ZN_GetString
  1837.     #define dini_IntSet             ZN_SetInt
  1838.     #define dini_Int                ZN_GetInt
  1839.     #define dini_BoolSet            ZN_SetBool
  1840.     #define dini_Bool               ZN_GetBool
  1841.     #define dini_FloatSet           ZN_SetFloat
  1842.     #define dini_Float              ZN_GetFloat
  1843.     #define dini_Unset              ZN_Unset
  1844.     #define dini_Isset              ZN_IsSet
  1845.  
  1846.     #if !defined _dini_included
  1847.         #define _dini_included
  1848.     #endif
  1849.  
  1850.  
  1851.     #define udb_hash                ZN_num_hash
  1852.     #define num_hash                ZN_num_hash
  1853.     #define udb_encode              ZN_udb_encode
  1854.     #define udb_decode              ZN_udb_decode
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement