jsonparser.pp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. {
  2. This file is part of the Free Component Library
  3. JSON source parser
  4. Copyright (c) 2007 by Michael Van Canneyt [email protected]
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$h+}
  13. {$IFNDEF FPC_DOTTEDUNITS}
  14. unit jsonparser;
  15. {$ENDIF FPC_DOTTEDUNITS}
  16. interface
  17. {$IFDEF FPC_DOTTEDUNITS}
  18. uses
  19. System.Classes, System.SysUtils, FpJson.Data, FpJson.Scanner, FpJson.Reader;
  20. {$ELSE FPC_DOTTEDUNITS}
  21. uses
  22. Classes, SysUtils, fpJSON, jsonscanner, jsonreader;
  23. {$ENDIF FPC_DOTTEDUNITS}
  24. Type
  25. { TJSONParser }
  26. TJSONParser = Class(TBaseJSONReader)
  27. private
  28. FStack : Array of TJSONData;
  29. FStackPos : integer;
  30. FStruct : TJSONData;
  31. FValue : TJSONData;
  32. FKey: TJSONStringType;
  33. procedure Pop(aType: TJSONType);
  34. Procedure Push(AValue : TJSONData);
  35. Function NewValue(AValue : TJSONData) : TJSONData;
  36. Protected
  37. Procedure KeyValue(Const AKey : TJSONStringType); override;
  38. Procedure StringValue(Const AValue : TJSONStringType);override;
  39. Procedure NullValue; override;
  40. Procedure FloatValue(Const AValue : Double); override;
  41. Procedure BooleanValue(Const AValue : Boolean); override;
  42. Procedure NumberValue(Const AValue : TJSONStringType); override;
  43. Procedure IntegerValue(Const AValue : integer); override;
  44. Procedure Int64Value(Const AValue : int64); override;
  45. Procedure QWordValue(Const AValue : QWord); override;
  46. Procedure StartArray; override;
  47. Procedure StartObject; override;
  48. Procedure EndArray; override;
  49. Procedure EndObject; override;
  50. Public
  51. function Parse: TJSONData;
  52. end;
  53. EJSONParser = {$IFDEF FPC_DOTTEDUNITS}FpJson.Reader{$ELSE}jsonReader{$ENDIF}.EJSONParser;
  54. implementation
  55. Resourcestring
  56. SErrStructure = 'Structural error';
  57. { TJSONParser }
  58. procedure DefJSONParserHandler(AStream: TStream; const AUseUTF8: Boolean; out
  59. Data: TJSONData);
  60. Var
  61. P : TJSONParser;
  62. AOptions: TJSONOptions;
  63. begin
  64. Data:=Nil;
  65. AOptions:=[];
  66. if AUseUTF8 then
  67. Include(AOptions,joUTF8);
  68. P:=TJSONParser.Create(AStream,AOptions);
  69. try
  70. Data:=P.Parse;
  71. finally
  72. P.Free;
  73. end;
  74. end;
  75. procedure DefJSONStringParserHandler(Const S : TJSONStringType; const AUseUTF8: Boolean; out
  76. Data: TJSONData);
  77. Var
  78. P : TJSONParser;
  79. AOptions: TJSONOptions;
  80. begin
  81. Data:=Nil;
  82. AOptions:=[];
  83. if AUseUTF8 then
  84. Include(AOptions,joUTF8);
  85. P:=TJSONParser.Create(S,AOptions);
  86. try
  87. Data:=P.Parse;
  88. finally
  89. P.Free;
  90. end;
  91. end;
  92. procedure TJSONParser.Pop(aType: TJSONType);
  93. begin
  94. if (FStackPos=0) then
  95. DoError(SErrStructure);
  96. If (FStruct.JSONType<>aType) then
  97. DoError(SErrStructure);
  98. Dec(FStackPos);
  99. FStruct:=FStack[FStackPos];
  100. end;
  101. procedure TJSONParser.Push(AValue: TJSONData);
  102. begin
  103. if (FStackPos=Length(FStack)) then
  104. SetLength(FStack,FStackPos+10);
  105. FStack[FStackPos]:=FStruct;
  106. Inc(FStackPos);
  107. FStruct:=AValue;
  108. end;
  109. function TJSONParser.NewValue(AValue: TJSONData): TJSONData;
  110. begin
  111. Result:=AValue;
  112. // Add to existing structural type
  113. if (FStruct is TJSONObject) then
  114. begin
  115. if (Not (joIgnoreDuplicates in options)) then
  116. try
  117. TJSONObject(FStruct).Add(FKey,AValue);
  118. except
  119. AValue.Free;
  120. Raise;
  121. end
  122. else if (TJSONObject(FStruct).IndexOfName(FKey)=-1) then
  123. TJSONObject(FStruct).Add(FKey,AValue)
  124. else
  125. AValue.Free;
  126. FKey:='';
  127. end
  128. else if (FStruct is TJSONArray) then
  129. TJSONArray(FStruct).Add(AValue);
  130. // The first actual value is our result
  131. if (FValue=Nil) then
  132. FValue:=AValue;
  133. end;
  134. procedure TJSONParser.KeyValue(const AKey: TJSONStringType);
  135. begin
  136. if (FStruct is TJSONObject) and (FKey='') then
  137. FKey:=Akey
  138. else
  139. DoError('Duplicatekey or no object');
  140. end;
  141. procedure TJSONParser.StringValue(const AValue: TJSONStringType);
  142. begin
  143. NewValue(CreateJSON(AValue));
  144. end;
  145. procedure TJSONParser.NullValue;
  146. begin
  147. NewValue(CreateJSON);
  148. end;
  149. procedure TJSONParser.FloatValue(const AValue: Double);
  150. begin
  151. NewValue(CreateJSON(AValue));
  152. end;
  153. procedure TJSONParser.BooleanValue(const AValue: Boolean);
  154. begin
  155. NewValue(CreateJSON(AValue));
  156. end;
  157. procedure TJSONParser.NumberValue(const AValue: TJSONStringType);
  158. begin
  159. // Do nothing
  160. if AValue='' then ;
  161. end;
  162. procedure TJSONParser.IntegerValue(const AValue: integer);
  163. begin
  164. NewValue(CreateJSON(AValue));
  165. end;
  166. procedure TJSONParser.Int64Value(const AValue: int64);
  167. begin
  168. NewValue(CreateJSON(AValue));
  169. end;
  170. procedure TJSONParser.QWordValue(const AValue: QWord);
  171. begin
  172. NewValue(CreateJSON(AValue));
  173. end;
  174. procedure TJSONParser.StartArray;
  175. begin
  176. Push(NewValue(CreateJSONArray([])))
  177. end;
  178. procedure TJSONParser.StartObject;
  179. begin
  180. Push(NewValue(CreateJSONObject([])));
  181. end;
  182. procedure TJSONParser.EndArray;
  183. begin
  184. Pop(jtArray);
  185. end;
  186. procedure TJSONParser.EndObject;
  187. begin
  188. Pop(jtObject);
  189. end;
  190. function TJSONParser.Parse: TJSONData;
  191. begin
  192. SetLength(FStack,0);
  193. FStackPos:=0;
  194. FValue:=Nil;
  195. FStruct:=Nil;
  196. try
  197. DoExecute;
  198. Result:=FValue;
  199. except
  200. On E : exception do
  201. begin
  202. FreeAndNil(FValue);
  203. FStackPos:=0;
  204. SetLength(FStack,0);
  205. Raise;
  206. end;
  207. end;
  208. end;
  209. {
  210. Consume next token and convert to JSON data structure.
  211. If AtCurrent is true, the current token is used. If false,
  212. a token is gotten from the scanner.
  213. If AllowEOF is false, encountering a tkEOF will result in an exception.
  214. }
  215. Procedure InitJSONHandler;
  216. begin
  217. if GetJSONParserHandler=Nil then
  218. SetJSONParserHandler(@DefJSONParserHandler);
  219. if GetJSONStringParserHandler=Nil then
  220. SetJSONStringParserHandler(@DefJSONStringParserHandler);
  221. end;
  222. Procedure DoneJSONHandler;
  223. begin
  224. if GetJSONParserHandler=@DefJSONParserHandler then
  225. SetJSONParserHandler(Nil);
  226. if GetJSONStringParserHandler=@DefJSONStringParserHandler then
  227. SetJSONStringParserHandler(Nil);
  228. end;
  229. initialization
  230. InitJSONHandler;
  231. finalization
  232. DoneJSONHandler;
  233. end.