ppujson.pp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. {
  2. Copyright (c) 2013 by Yury Sidorov and the FPC Development Team
  3. JSON output of a PPU File
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************}
  16. unit ppujson;
  17. {$mode objfpc}{$H+}
  18. interface
  19. uses
  20. SysUtils, Classes, ppuout;
  21. type
  22. { TPpuJsonOutput }
  23. TPpuJsonOutput = class(TPpuOutput)
  24. private
  25. FNeedDelim: array of boolean;
  26. function JsonStr(const s: string): string;
  27. procedure BeforeWriteElement;
  28. procedure WriteAttr(const AName, AValue: string);
  29. protected
  30. procedure WriteDefStart(Def: TPpuDef); override;
  31. procedure WriteDefEnd(Def: TPpuDef); override;
  32. procedure WriteSubItemsStart(Def: TPpuContainerDef); override;
  33. procedure WriteSubItemsEnd(Def: TPpuContainerDef); override;
  34. procedure WriteArrayStart(const AName: string); override;
  35. procedure WriteArrayEnd(const AName: string); override;
  36. procedure WriteStr(const AName, AValue: string); override;
  37. procedure WriteInt(const AName: string; AValue: Int64); override;
  38. procedure WriteFloat(const AName: string; AValue: extended); override;
  39. procedure WriteBool(const AName: string; AValue: boolean); override;
  40. public
  41. constructor Create(var OutFile: Text); override;
  42. procedure IncI; override;
  43. procedure DecI; override;
  44. end;
  45. implementation
  46. { TPpuJsonOutput }
  47. function TPpuJsonOutput.JsonStr(const s: string): string;
  48. var
  49. ws: widestring;
  50. ps: PWideChar;
  51. pd: PAnsiChar;
  52. i, slen, dlen, dpos: integer;
  53. procedure _AddChar(c: ansichar);
  54. begin
  55. if dpos = dlen then begin
  56. dlen:=dlen*2;
  57. SetLength(Result, dlen);
  58. pd:=PAnsiChar(Result) + dpos;
  59. end;
  60. pd^:=c;
  61. Inc(pd);
  62. Inc(dpos);
  63. end;
  64. var
  65. c: widechar;
  66. ss: shortstring;
  67. begin
  68. ws:=UTF8Decode(s);
  69. ps:=PWideChar(ws);
  70. slen:=Length(ws);
  71. dlen:=slen + 2;
  72. SetLength(Result, dlen);
  73. pd:=PAnsiChar(Result);
  74. dpos:=0;
  75. _AddChar('"');
  76. while slen > 0 do begin
  77. c:=ps^;
  78. case c of
  79. '"', '\', '/':
  80. begin
  81. _AddChar('\');
  82. _AddChar(c);
  83. end;
  84. #8:
  85. begin
  86. _AddChar('\');
  87. _AddChar('b');
  88. end;
  89. #9:
  90. begin
  91. _AddChar('\');
  92. _AddChar('t');
  93. end;
  94. #10:
  95. begin
  96. _AddChar('\');
  97. _AddChar('n');
  98. end;
  99. #13:
  100. begin
  101. _AddChar('\');
  102. _AddChar('r');
  103. end;
  104. #12:
  105. begin
  106. _AddChar('\');
  107. _AddChar('f');
  108. end;
  109. else
  110. if (c < #32) or (c > #127) then begin
  111. _AddChar('\');
  112. _AddChar('u');
  113. ss:=hexStr(integer(c), 4);
  114. for i:=1 to 4 do
  115. _AddChar(ss[i]);
  116. end
  117. else
  118. _AddChar(c);
  119. end;
  120. Inc(ps);
  121. Dec(slen);
  122. end;
  123. _AddChar('"');
  124. SetLength(Result, dpos);
  125. end;
  126. procedure TPpuJsonOutput.BeforeWriteElement;
  127. begin
  128. if FNeedDelim[Indent] then
  129. WriteLn(',');
  130. FNeedDelim[Indent]:=True;
  131. end;
  132. procedure TPpuJsonOutput.WriteAttr(const AName, AValue: string);
  133. begin
  134. BeforeWriteElement;
  135. if AName <> '' then
  136. Write(Format('"%s": %s', [AName, AValue]))
  137. else
  138. Write(AValue);
  139. end;
  140. procedure TPpuJsonOutput.WriteDefStart(Def: TPpuDef);
  141. begin
  142. if Def.Parent = nil then
  143. // Top level container
  144. exit;
  145. WriteLn('{');
  146. IncI;
  147. if Def.DefType <> dtNone then
  148. WriteStr('Type', Def.DefTypeName);
  149. if Def.Name <> '' then
  150. WriteStr('Name', Def.Name);
  151. end;
  152. procedure TPpuJsonOutput.WriteDefEnd(Def: TPpuDef);
  153. var
  154. s: string;
  155. begin
  156. if Def.Parent = nil then
  157. // Top level container
  158. exit;
  159. DecI;
  160. s:='}';
  161. // Last def in list?
  162. if (Def.Parent <> nil) and (Def.Parent[Def.Parent.Count - 1] <> Def) then
  163. s:=s + ',';
  164. WriteLn(s);
  165. end;
  166. procedure TPpuJsonOutput.WriteSubItemsStart(Def: TPpuContainerDef);
  167. begin
  168. if Def.Parent = nil then begin
  169. // Top level container
  170. WriteLn('[');
  171. exit;
  172. end;
  173. BeforeWriteElement;
  174. WriteLn(Format('"%s": [', [Def.ItemsName]));
  175. end;
  176. procedure TPpuJsonOutput.WriteSubItemsEnd(Def: TPpuContainerDef);
  177. begin
  178. Write(']');
  179. if Def.Parent = nil then
  180. // Top level container
  181. WriteLn;
  182. end;
  183. procedure TPpuJsonOutput.WriteStr(const AName, AValue: string);
  184. begin
  185. WriteAttr(AName, JsonStr(AValue));
  186. end;
  187. procedure TPpuJsonOutput.WriteInt(const AName: string; AValue: Int64);
  188. begin
  189. WriteAttr(AName, IntToStr(AValue));
  190. end;
  191. procedure TPpuJsonOutput.WriteFloat(const AName: string; AValue: extended);
  192. var
  193. s: string;
  194. begin
  195. Str(AValue, s);
  196. WriteAttr(AName, s);
  197. end;
  198. procedure TPpuJsonOutput.WriteBool(const AName: string; AValue: boolean);
  199. begin
  200. if AValue then
  201. WriteAttr(AName, 'true')
  202. else
  203. WriteAttr(AName, 'false');
  204. end;
  205. procedure TPpuJsonOutput.WriteArrayStart(const AName: string);
  206. begin
  207. BeforeWriteElement;
  208. WriteLn(Format('"%s": [', [AName]));
  209. IncI;
  210. end;
  211. procedure TPpuJsonOutput.WriteArrayEnd(const AName: string);
  212. begin
  213. DecI;
  214. Write(']');
  215. end;
  216. constructor TPpuJsonOutput.Create(var OutFile: Text);
  217. begin
  218. inherited Create(OutFile);
  219. SetLength(FNeedDelim, 10);
  220. FNeedDelim[0]:=False;
  221. end;
  222. procedure TPpuJsonOutput.IncI;
  223. begin
  224. inherited IncI;
  225. if Length(FNeedDelim) >= Indent then
  226. SetLength(FNeedDelim, Indent + 1);
  227. FNeedDelim[Indent]:=False;
  228. end;
  229. procedure TPpuJsonOutput.DecI;
  230. begin
  231. if FNeedDelim[Indent] then
  232. WriteLn;
  233. inherited DecI;
  234. end;
  235. end.