阿里大于是阿里通信旗下产品,融合了三大运营商的通信能力,提供包括短信、语音、流量直充、私密专线、店铺手机号等个性化服务。每条四分五,价钱还算公道,经老农测试,响应速度非常快,基本上是秒到。官方文档提供了JAVA、.NET、PHP、Python、C/C++、NodeJS 等语言的 Demo,唯独没有 Dephi,但这也不能怪马云,毕竟 Delphi 实在太小众了。
最近用 Delphi 写个 App,注册用户需要用到手机短信验证,于是找到的阿里大于,使用 Delphi 7 写了个简单的 Demo 并测试通过,代码如下:
注意,这里需要添加引用IdHTTP, IdHashMessageDigest, IdGlobal, IdHash 和 superobject.pas文件。
1 unit uMain; 2 3 interface 4 5 uses 6 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 7 Dialogs, StdCtrls, RzEdit, RzButton, IdBaseComponent, IdComponent, superobject, 8 IdTCPConnection, IdTCPClient, IdHTTP, IdHashMessageDigest, IdGlobal, IdHash, 9 RzLabel, Mask; 10 11 type 12 TFrmMain = class(TForm) 13 btnExecute: TRzBitBtn; 14 mmLogs: TRzMemo; 15 lbAppKey: TRzLabel; 16 lbAppSecret: TRzLabel; 17 lbReceiveNumber: TRzLabel; 18 lbFreeSignName: TRzLabel; 19 lbTemplateCode: TRzLabel; 20 lbTemplateContent: TRzLabel; 21 edtAppKey: TRzEdit; 22 edtAppSecret: TRzEdit; 23 edtReceiveNumber: TRzEdit; 24 edtFreeSignName: TRzEdit; 25 edtTemplateCode: TRzEdit; 26 edtTemplateContent: TRzEdit; 27 btnExit: TRzBitBtn; 28 procedure MsgDsp(v_Str: string); 29 procedure btnExecuteClick(Sender: TObject); 30 procedure btnExitClick(Sender: TObject); 31 procedure FormShow(Sender: TObject); 32 private 33 { Private declarations } 34 public 35 { Public declarations } 36 end; 37 38 var 39 FrmMain: TFrmMain; 40 41 implementation 42 {$R *.dfm} 43 44 procedure TFrmMain.MsgDsp(v_Str: string); 45 begin 46 mmLogs.Lines.Add('[admin] - [' + v_Str + '] - [' + FormatDateTime('YYYY-MM-DD hh:mm:ss zzz', Now()) + ']'); 47 end; 48 49 /// <author>全能地图(QQ:64445322)</author> 50 /// <summary> 51 /// 利用阿里大于接口发短信 52 /// 阿里大于网址:http://www.alidayu.com 53 /// 阿里大于短信接口文档:https://api.alidayu.com/doc2/apiDetail.htm?apiId=25450 54 /// </summary> 55 /// <param name="AppKey">TOP分配给应用的AppKey</param> 56 /// <param name="AppSecret">AppSecret</param> 57 /// <param name="ReceiveNumber">接收手机号码</param> 58 /// <param name="FreeSignName">短信签名,传入的短信签名必须是在阿里大于“管理中心-短信签名管理”中的可用签名</param> 59 /// <param name="TemplateCode">短信模板ID</param> 60 /// <param name="TemplateContent">短信模板变量,例如:{"code":"1234","product":"alidayu"}</param> 61 /// <param name="ResultMsg">下发结果消息</param> 62 /// <returns>是否成功,True = 成功 ,false = 失败</returns> 63 64 function SendSMS(const AppKey, AppSecret, ReceiveNumber, FreeSignName, TemplateCode, TemplateContent: string; var ResultMsg: string): Boolean; 65 66 function GetStringMD5(const AInPut: string): string; 67 var 68 MD5: TIdHashMessageDigest5; 69 Digest: T4x4LongWordRecord; 70 begin 71 MD5 := TIdHashMessageDigest5.Create; 72 try 73 Digest := MD5.HashValue(AInPut); 74 Result := MD5.AsHex(Digest); 75 finally 76 MD5.Free; 77 end; 78 end; 79 80 // 签名算法:http://open.taobao.com/doc2/detail.htm?articleId=101617&docType=1&treeId=1 81 function MakeSign(const AParams: TStringList; const AppSecret: string): string; 82 var 83 I: Integer; 84 Data: string; 85 begin 86 // 参数排序 87 AParams.Sort; 88 // 参数拼接 89 Data := ''; 90 for I := 0 to AParams.Count - 1 do 91 Data := Data + StringReplace(AParams[I], '=', '', [rfReplaceAll]); 92 // MD5 算法 93 Result := GetStringMD5(AppSecret + Data + AppSecret); 94 end; 95 96 var 97 HTTP: TIdHTTP; 98 Params: TStringList; 99 Response: string; 100 JsonObject: ISuperObject; 101 begin 102 Result := False; 103 HTTP := TIdHTTP.Create(nil); 104 Params := TStringList.Create(); 105 try 106 Params.Values['app_key'] := AppKey; 107 Params.Values['format'] := 'json'; 108 Params.Values['method'] := 'alibaba.aliqin.fc.sms.num.send'; 109 Params.Values['sign_method'] := 'md5'; 110 Params.Values['timestamp'] := FormatDateTime('yyyy-MM-dd HH:mm:ss', Now); 111 Params.Values['v'] := '2.0'; 112 Params.Values['sms_type'] := 'normal'; 113 Params.Values['sms_free_sign_name'] := UTF8Encode(FreeSignName); 114 Params.Values['rec_num'] := ReceiveNumber; 115 Params.Values['sms_template_code'] := TemplateCode; 116 Params.Values['sms_param'] := UTF8Encode(TemplateContent); 117 Params.Values['sign'] := MakeSign(Params, AppSecret); 118 HTTP.HandleRedirects := True; 119 HTTP.Request.AcceptCharSet := 'utf-8'; 120 HTTP.Request.ContentType := 'application/x-www-form-urlencoded'; 121 try 122 Response := HTTP.Post('http://gw.api.taobao.com/router/rest', Params); 123 except 124 on E: Exception do 125 begin 126 ResultMsg := E.Message; 127 Exit; 128 end; 129 end; 130 JsonObject := SO(Response); 131 if JsonObject <> nil then 132 begin 133 ResultMsg := JsonObject.S['alibaba_aliqin_fc_sms_num_send_response.result.success']; 134 if ResultMsg <> '' then 135 Result := UpperCase(ResultMsg) = 'TRUE' 136 else 137 begin 138 ResultMsg := JsonObject.S['error_response.msg']; 139 Result := False; 140 end; 141 end; 142 finally 143 HTTP.Free; 144 Params.Free; 145 end; 146 end; 147 148 procedure TFrmMain.btnExecuteClick(Sender: TObject); 149 var 150 vResult: string; 151 begin 152 try 153 if SendSMS(edtAppKey.Text, edtAppSecret.Text, edtReceiveNumber.Text, edtFreeSignName.Text, edtTemplateCode.Text, edtTemplateContent.Text, vResult) then 154 begin 155 MsgDsp('API调用成功[' + vResult + '],请注意查收短消息!'); 156 end 157 else 158 begin 159 MsgDsp('API调用失败,错误信息【' + vResult + '】'); 160 end; 161 except 162 on E: Exception do 163 begin 164 MsgDsp('API调用异常,[' + vResult + '],错误信息【' + E.Message + '】'); 165 end; 166 end; 167 168 end; 169 170 procedure TFrmMain.btnExitClick(Sender: TObject); 171 begin 172 Self.Close; 173 end; 174 175 procedure TFrmMain.FormShow(Sender: TObject); 176 begin 177 MsgDsp('系统启动成功!'); 178 end; 179 180 end.View Code
Delphi 10.1 berlin 关键发送模块如下:
1 /// <author>全能地图(QQ:64445322)</author> 2 /// <summary> 3 /// 利用阿里大于接口发短信 4 /// 阿里大于网址:http://www.alidayu.com 5 /// 阿里大于短信接口文档:https://api.alidayu.com/doc2/apiDetail.htm?apiId=25450 6 /// </summary> 7 /// <param name="AppKey">TOP分配给应用的AppKey</param> 8 /// <param name="AppSecret">AppSecret</param> 9 /// <param name="ReceiveNumber">接收手机号码</param> 10 /// <param name="FreeSignName">短信签名,传入的短信签名必须是在阿里大于“管理中心-短信签名管理”中的可用签名</param> 11 /// <param name="TemplateCode">短信模板ID</param> 12 /// <param name="TemplateContent">短信模板变量,例如:{"code":"1234","product":"alidayu"}</param> 13 /// <param name="ResultMsg">下发结果消息</param> 14 /// <returns>是否成功,True = 成功 ,false = 失败</returns> 15 function SendSMS(const AppKey, AppSecret, ReceiveNumber, FreeSignName, TemplateCode, TemplateContent: string; var ResultMsg: string): Boolean; 16 17 // 签名算法:http://open.taobao.com/doc2/detail.htm?articleId=101617&docType=1&treeId=1 18 function MakeSign(const AParams: TStringList; const AppSecret: string): string; 19 var 20 I: Integer; 21 Data: string; 22 begin 23 // 参数排序 24 AParams.Sort; 25 26 // 参数拼接 27 Data := ''; 28 for I := 0 to AParams.Count - 1 do 29 Data := Data + AParams[I].Replace('=', ''); 30 31 // HMAC 算法 32 Result := THashMD5.GetHMAC(Data, AppSecret).ToUpper; 33 end; 34 35 var 36 HTTP: TNetHTTPClient; 37 JsonObject: TJSONObject; 38 Params: TStringList; 39 Response: string; 40 begin 41 Result := False; 42 43 HTTP := TNetHTTPClient.Create(nil); 44 Params := TStringList.Create(); 45 try 46 Params.Values['app_key'] := AppKey; 47 Params.Values['format'] := 'json'; 48 Params.Values['method'] := 'alibaba.aliqin.fc.sms.num.send'; 49 Params.Values['sign_method'] := 'hmac'; 50 Params.Values['timestamp'] := FormatDateTime('yyyy-MM-dd HH:mm:ss', Now); 51 Params.Values['v'] := '2.0'; 52 Params.Values['sms_type'] := 'normal'; 53 Params.Values['sms_free_sign_name'] := FreeSignName; 54 Params.Values['rec_num'] := ReceiveNumber; 55 Params.Values['sms_template_code'] := TemplateCode; 56 Params.Values['sms_param'] := TemplateContent; 57 Params.Values['sign'] := MakeSign(Params, AppSecret); 58 59 HTTP.ContentType := 'application/x-www-form-urlencoded'; 60 try 61 Response := HTTP.Post('https://eco.taobao.com/router/rest', Params).ContentAsString(); 62 except 63 on E: Exception do 64 begin 65 ResultMsg := E.Message; 66 Exit; 67 end; 68 end; 69 70 JsonObject := TJSONObject.ParseJSONValue(Response) as TJSONObject; 71 try 72 if JsonObject <> nil then 73 begin 74 if JsonObject.TryGetValue<string>('alibaba_aliqin_fc_sms_num_send_response.result.success', ResultMsg) then 75 Result := ResultMsg.ToUpper = 'TRUE' 76 else if JsonObject.TryGetValue<string>('error_response.msg', ResultMsg) then 77 Result := False; 78 end; 79 80 finally 81 JsonObject.Free; 82 end; 83 84 finally 85 HTTP.Free; 86 Params.Free; 87 end; 88 89 end;View Code
SuperObject.pas如下:
1 (* 2 * Super Object Toolkit 3 * 4 * Usage allowed under the restrictions of the Lesser GNU General Public License 5 * or alternatively the restrictions of the Mozilla Public License 1.1 6 * 7 * Software distributed under the License is distributed on an "AS IS" basis, 8 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for 9 * the specific language governing rights and limitations under the License. 10 * 11 * Unit owner : Henri Gourvest <hgourvest@gmail.com> 12 * Web site : http://www.progdigy.com 13 * 14 * This unit is inspired from the json c lib: 15 * Michael Clark <michael@metaparadigm.com> 16 * http://oss.metaparadigm.com/json-c/ 17 * 18 * CHANGES: 19 * v1.2 20 * + support of currency data type 21 * + right trim unquoted string 22 * + read Unicode Files and streams (Litle Endian with BOM) 23 * + Fix bug on javadate functions + windows nt compatibility 24 * + Now you can force to parse only the canonical syntax of JSON using the stric parameter 25 * + Delphi 2010 RTTI marshalling 26 * v1.1 27 * + Double licence MPL or LGPL. 28 * + Delphi 2009 compatibility & Unicode support. 29 * + AsString return a string instead of PChar. 30 * + Escaped and Unascaped JSON serialiser. 31 * + Missed FormFeed added \f 32 * - Removed @ trick, uses forcepath() method instead. 33 * + Fixed parse error with uppercase E symbol in numbers. 34 * + Fixed possible buffer overflow when enlarging array. 35 * + Added "delete", "pack", "insert" methods for arrays and/or objects 36 * + Multi parametters when calling methods 37 * + Delphi Enumerator (for obj1 in obj2 do ...) 38 * + Format method ex: obj.format('<%name%>%tab[1]%</%name%>') 39 * + ParseFile and ParseStream methods 40 * + Parser now understand hexdecimal c syntax ex: \xFF 41 * + Null Object Design Patern (ex: for obj in values.N['path'] do ...) 42 * v1.0 43 * + renamed class 44 * + interfaced object 45 * + added a new data type: the method 46 * + parser can now evaluate properties and call methods 47 * - removed obselet rpc class 48 * - removed "find" method, now you can use "parse" method instead 49 * v0.6 50 * + refactoring 51 * v0.5 52 * + new find method to get or set value using a path syntax 53 * ex: obj.s['obj.prop[1]'] := 'string value'; 54 * obj.a['@obj.array'].b[n] := true; // @ -> create property if necessary 55 * v0.4 56 * + bug corrected: AVL tree badly balanced. 57 * v0.3 58 * + New validator partially based on the Kwalify syntax. 59 * + extended syntax to parse unquoted fields. 60 * + Freepascal compatibility win32/64 Linux32/64. 61 * + JavaToDelphiDateTime and DelphiToJavaDateTime improved for UTC. 62 * + new TJsonObject.Compare function. 63 * v0.2 64 * + Hashed string list replaced with a faster AVL tree 65 * + JsonInt data type can be changed to int64 66 * + JavaToDelphiDateTime and DelphiToJavaDateTime helper fonctions 67 * + from json-c v0.7 68 * + Add escaping of backslash to json output 69 * + Add escaping of foward slash on tokenizing and output 70 * + Changes to internal tokenizer from using recursion to 71 * using a depth state structure to allow incremental parsing 72 * v0.1 73 * + first release 74 *) 75 76 {$IFDEF FPC} 77 {$MODE OBJFPC}{$H+} 78 {$ENDIF} 79 80 {$DEFINE SUPER_METHOD} 81 {$DEFINE WINDOWSNT_COMPATIBILITY} 82 {.$DEFINE DEBUG} // track memory leack 83 84 unit superobject; 85 86 interface 87 uses 88 Classes 89 {$IFDEF VER210} 90 ,Generics.Collections, RTTI, TypInfo 91 {$ENDIF} 92 ; 93 94 type 95 {$IFNDEF FPC} 96 PtrInt = longint; 97 PtrUInt = Longword; 98 {$ENDIF} 99 SuperInt = Int64; 100 101 {$if (sizeof(Char) = 1)} 102 SOChar = WideChar; 103 SOIChar = Word; 104 PSOChar = PWideChar; 105 SOString = WideString; 106 {$else} 107 SOChar = Char; 108 SOIChar = Word; 109 PSOChar = PChar; 110 SOString = string; 111 {$ifend} 112 113 const 114 SUPER_ARRAY_LIST_DEFAULT_SIZE = 32; 115 SUPER_TOKENER_MAX_DEPTH = 32; 116 117 SUPER_AVL_MAX_DEPTH = sizeof(longint) * 8; 118 SUPER_AVL_MASK_HIGH_BIT = not ((not longword(0)) shr 1); 119 120 type 121 // forward declarations 122 TSuperObject = class; 123 ISuperObject = interface; 124 TSuperArray = class; 125 126 (* AVL Tree 127 * This is a "special" autobalanced AVL tree 128 * It use a hash value for fast compare 129 *) 130 131 {$IFDEF SUPER_METHOD} 132 TSuperMethod = procedure(const This, Params: ISuperObject; var Result: ISuperObject); 133 {$ENDIF} 134 135 136 TSuperAvlBitArray = set of 0..SUPER_AVL_MAX_DEPTH - 1; 137 138 TSuperAvlSearchType = (stEQual, stLess, stGreater); 139 TSuperAvlSearchTypes = set of TSuperAvlSearchType; 140 TSuperAvlIterator = class; 141 142 TSuperAvlEntry = class 143 private 144 FGt, FLt: TSuperAvlEntry; 145 FBf: integer; 146 FHash: Cardinal; 147 FName: SOString; 148 FPtr: Pointer; 149 function GetValue: ISuperObject; 150 procedure SetValue(const val: ISuperObject); 151 public 152 class function Hash(const k: SOString): Cardinal; virtual; 153 constructor Create(const AName: SOString; Obj: Pointer); virtual; 154 property Name: SOString read FName; 155 property Ptr: Pointer read FPtr; 156 property Value: ISuperObject read GetValue write SetValue; 157 end; 158 159 TSuperAvlTree = class 160 private 161 FRoot: TSuperAvlEntry; 162 FCount: Integer; 163 function balance(bal: TSuperAvlEntry): TSuperAvlEntry; 164 protected 165 procedure doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); virtual; 166 function CompareNodeNode(node1, node2: TSuperAvlEntry): integer; virtual; 167 function CompareKeyNode(const k: SOString; h: TSuperAvlEntry): integer; virtual; 168 function Insert(h: TSuperAvlEntry): TSuperAvlEntry; virtual; 169 function Search(const k: SOString; st: TSuperAvlSearchTypes = [stEqual]): TSuperAvlEntry; virtual; 170 public 171 constructor Create; virtual; 172 destructor Destroy; override; 173 function IsEmpty: boolean; 174 procedure Clear(all: boolean = false); virtual; 175 procedure Pack(all: boolean); 176 function Delete(const k: SOString): ISuperObject; 177 function GetEnumerator: TSuperAvlIterator; 178 property count: Integer read FCount; 179 end; 180 181 TSuperTableString = class(TSuperAvlTree) 182 protected 183 procedure doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); override; 184 procedure PutO(const k: SOString; const value: ISuperObject); 185 function GetO(const k: SOString): ISuperObject; 186 procedure PutS(const k: SOString; const value: SOString); 187 function GetS(const k: SOString): SOString; 188 procedure PutI(const k: SOString; value: SuperInt); 189 function GetI(const k: SOString): SuperInt; 190 procedure PutD(const k: SOString; value: Double); 191 function GetD(const k: SOString): Double; 192 procedure PutB(const k: SOString; value: Boolean); 193 function GetB(const k: SOString): Boolean; 194 {$IFDEF SUPER_METHOD} 195 procedure PutM(const k: SOString; value: TSuperMethod); 196 function GetM(const k: SOString): TSuperMethod; 197 {$ENDIF} 198 procedure PutN(const k: SOString; const value: ISuperObject); 199 function GetN(const k: SOString): ISuperObject; 200 procedure PutC(const k: SOString; value: Currency); 201 function GetC(const k: SOString): Currency; 202 public 203 property O[const k: SOString]: ISuperObject read GetO write PutO; default; 204 property S[const k: SOString]: SOString read GetS write PutS; 205 property I[const k: SOString]: SuperInt read GetI write PutI; 206 property D[const k: SOString]: Double read GetD write PutD; 207 property B[const k: SOString]: Boolean read GetB write PutB; 208 {$IFDEF SUPER_METHOD} 209 property M[const k: SOString]: TSuperMethod read GetM write PutM; 210 {$ENDIF} 211 property N[const k: SOString]: ISuperObject read GetN write PutN; 212 property C[const k: SOString]: Currency read GetC write PutC; 213 214 function GetValues: ISuperObject; 215 function GetNames: ISuperObject; 216 end; 217 218 TSuperAvlIterator = class 219 private 220 FTree: TSuperAvlTree; 221 FBranch: TSuperAvlBitArray; 222 FDepth: LongInt; 223 FPath: array[0..SUPER_AVL_MAX_DEPTH - 2] of TSuperAvlEntry; 224 public 225 constructor Create(tree: TSuperAvlTree); virtual; 226 procedure Search(const k: SOString; st: TSuperAvlSearchTypes = [stEQual]); 227 procedure First; 228 procedure Last; 229 function GetIter: TSuperAvlEntry; 230 procedure Next; 231 procedure Prior; 232 // delphi enumerator 233 function MoveNext: Boolean; 234 property Current: TSuperAvlEntry read GetIter; 235 end; 236 237 TSuperObjectArray = array[0..(high(PtrInt) div sizeof(TSuperObject))-1] of ISuperObject; 238 PSuperObjectArray = ^TSuperObjectArray; 239 240 TSuperArray = class 241 private 242 FArray: PSuperObjectArray; 243 FLength: Integer; 244 FSize: Integer; 245 procedure Expand(max: Integer); 246 protected 247 function GetO(const index: integer): ISuperObject; 248 procedure PutO(const index: integer; const Value: ISuperObject); 249 function GetB(const index: integer): Boolean; 250 procedure PutB(const index: integer; Value: Boolean); 251 function GetI(const index: integer): SuperInt; 252 procedure PutI(const index: integer; Value: SuperInt); 253 function GetD(const index: integer): Double; 254 procedure PutD(const index: integer; Value: Double); 255 function GetC(const index: integer): Currency; 256 procedure PutC(const index: integer; Value: Currency); 257 function GetS(const index: integer): SOString; 258 procedure PutS(const index: integer; const Value: SOString); 259 {$IFDEF SUPER_METHOD} 260 function GetM(const index: integer): TSuperMethod; 261 procedure PutM(const index: integer; Value: TSuperMethod); 262 {$ENDIF} 263 function GetN(const index: integer): ISuperObject; 264 procedure PutN(const index: integer; const Value: ISuperObject); 265 public 266 constructor Create; virtual; 267 destructor Destroy; override; 268 function Add(const Data: ISuperObject): Integer; 269 function Delete(index: Integer): ISuperObject; 270 procedure Insert(index: Integer; const value: ISuperObject); 271 procedure Clear(all: boolean = false); 272 procedure Pack(all: boolean); 273 property Length: Integer read FLength; 274 275 property N[const index: integer]: ISuperObject read GetN write PutN; 276 property O[const index: integer]: ISuperObject read GetO write PutO; default; 277 property B[const index: integer]: boolean read GetB write PutB; 278 property I[const index: integer]: SuperInt read GetI write PutI; 279 property D[const index: integer]: Double read GetD write PutD; 280 property C[const index: integer]: Currency read GetC write PutC; 281 property S[const index: integer]: SOString read GetS write PutS; 282 {$IFDEF SUPER_METHOD} 283 property M[const index: integer]: TSuperMethod read GetM write PutM; 284 {$ENDIF} 285 // property A[const index: integer]: TSuperArray read GetA; 286 end; 287 288 TSuperWriter = class 289 public 290 // abstact methods to overide 291 function Append(buf: PSOChar; Size: Integer): Integer; overload; virtual; abstract; 292 function Append(buf: PSOChar): Integer; overload; virtual; abstract; 293 procedure Reset; virtual; abstract; 294 end; 295 296 TSuperWriterString = class(TSuperWriter) 297 private 298 FBuf: PSOChar; 299 FBPos: integer; 300 FSize: integer; 301 public 302 function Append(buf: PSOChar; Size: Integer): Integer; overload; override; 303 function Append(buf: PSOChar): Integer; overload; override; 304 procedure Reset; override; 305 procedure TrimRight; 306 constructor Create; virtual; 307 destructor Destroy; override; 308 function GetString: SOString; 309 property Data: PSOChar read FBuf; 310 property Size: Integer read FSize; 311 property Position: integer read FBPos; 312 end; 313 314 TSuperWriterStream = class(TSuperWriter) 315 private 316 FStream: TStream; 317 public 318 function Append(buf: PSOChar): Integer; override; 319 procedure Reset; override; 320 constructor Create(AStream: TStream); reintroduce; virtual; 321 end; 322 323 TSuperAnsiWriterStream = class(TSuperWriterStream) 324 public 325 function Append(buf: PSOChar; Size: Integer): Integer; override; 326 end; 327 328 TSuperUnicodeWriterStream = class(TSuperWriterStream) 329 public 330 function Append(buf: PSOChar; Size: Integer): Integer; override; 331 end; 332 333 TSuperWriterFake = class(TSuperWriter) 334 private 335 FSize: Integer; 336 public 337 function Append(buf: PSOChar; Size: Integer): Integer; override; 338 function Append(buf: PSOChar): Integer; override; 339 procedure Reset; override; 340 constructor Create; reintroduce; virtual; 341 property size: integer read FSize; 342 end; 343 344 TSuperWriterSock = class(TSuperWriter) 345 private 346 FSocket: longint; 347 FSize: Integer; 348 public 349 function Append(buf: PSOChar; Size: Integer): Integer; override; 350 function Append(buf: PSOChar): Integer; override; 351 procedure Reset; override; 352 constructor Create(ASocket: longint); reintroduce; virtual; 353 property Socket: longint read FSocket; 354 property Size: Integer read FSize; 355 end; 356 357 TSuperTokenizerError = ( 358 teSuccess, 359 teContinue, 360 teDepth, 361 teParseEof, 362 teParseUnexpected, 363 teParseNull, 364 teParseBoolean, 365 teParseNumber, 366 teParseArray, 367 teParseObjectKeyName, 368 teParseObjectKeySep, 369 teParseObjectValueSep, 370 teParseString, 371 teParseComment, 372 teEvalObject, 373 teEvalArray, 374 teEvalMethod, 375 teEvalInt 376 ); 377 378 TSuperTokenerState = ( 379 tsEatws, 380 tsStart, 381 tsFinish, 382 tsNull, 383 tsCommentStart, 384 tsComment, 385 tsCommentEol, 386 tsCommentEnd, 387 tsString, 388 tsStringEscape, 389 tsIdentifier, 390 tsEscapeUnicode, 391 tsEscapeHexadecimal, 392 tsBoolean, 393 tsNumber, 394 tsArray, 395 tsArrayAdd, 396 tsArraySep, 397 tsObjectFieldStart, 398 tsObjectField, 399 tsObjectUnquotedField, 400 tsObjectFieldEnd, 401 tsObjectValue, 402 tsObjectValueAdd, 403 tsObjectSep, 404 tsEvalProperty, 405 tsEvalArray, 406 tsEvalMethod, 407 tsParamValue, 408 tsParamPut, 409 tsMethodValue, 410 tsMethodPut 411 ); 412 413 PSuperTokenerSrec = ^TSuperTokenerSrec; 414 TSuperTokenerSrec = record 415 state, saved_state: TSuperTokenerState; 416 obj: ISuperObject; 417 current: ISuperObject; 418 field_name: SOString; 419 parent: ISuperObject; 420 gparent: ISuperObject; 421 end; 422 423 TSuperTokenizer = class 424 public 425 str: PSOChar; 426 pb: TSuperWriterString; 427 depth, is_double, floatcount, st_pos, char_offset: Integer; 428 err: TSuperTokenizerError; 429 ucs_char: Word; 430 quote_char: SOChar; 431 stack: array[0..SUPER_TOKENER_MAX_DEPTH-1] of TSuperTokenerSrec; 432 line, col: Integer; 433 public 434 constructor Create; virtual; 435 destructor Destroy; override; 436 procedure ResetLevel(adepth: integer); 437 procedure Reset; 438 end; 439 440 // supported object types 441 TSuperType = ( 442 stNull, 443 stBoolean, 444 stDouble, 445 stCurrency, 446 stInt, 447 stObject, 448 stArray, 449 stString 450 {$IFDEF SUPER_METHOD} 451 ,stMethod 452 {$ENDIF} 453 ); 454 455 TSuperValidateError = ( 456 veRuleMalformated, 457 veFieldIsRequired, 458 veInvalidDataType, 459 veFieldNotFound, 460 veUnexpectedField, 461 veDuplicateEntry, 462 veValueNotInEnum, 463 veInvalidLength, 464 veInvalidRange 465 ); 466 467 TSuperFindOption = ( 468 foCreatePath, 469 foPutValue, 470 foDelete 471 {$IFDEF SUPER_METHOD} 472 ,foCallMethod 473 {$ENDIF} 474 ); 475 476 TSuperFindOptions = set of TSuperFindOption; 477 TSuperCompareResult = (cpLess, cpEqu, cpGreat, cpError); 478 TSuperOnValidateError = procedure(sender: Pointer; error: TSuperValidateError; const objpath: SOString); 479 480 TSuperEnumerator = class 481 private 482 FObj: ISuperObject; 483 FObjEnum: TSuperAvlIterator; 484 FCount: Integer; 485 public 486 constructor Create(const obj: ISuperObject); virtual; 487 destructor Destroy; override; 488 function MoveNext: Boolean; 489 function GetCurrent: ISuperObject; 490 property Current: ISuperObject read GetCurrent; 491 end; 492 493 ISuperObject = interface 494 ['{4B86A9E3-E094-4E5A-954A-69048B7B6327}'] 495 function GetEnumerator: TSuperEnumerator; 496 function GetDataType: TSuperType; 497 function GetProcessing: boolean; 498 procedure SetProcessing(value: boolean); 499 function ForcePath(const path: SOString; dataType: TSuperType = stObject): ISuperObject; 500 function Format(const str: SOString; BeginSep: SOChar = '%'; EndSep: SOChar = '%'): SOString; 501 502 function GetO(const path: SOString): ISuperObject; 503 procedure PutO(const path: SOString; const Value: ISuperObject); 504 function GetB(const path: SOString): Boolean; 505 procedure PutB(const path: SOString; Value: Boolean); 506 function GetI(const path: SOString): SuperInt; 507 procedure PutI(const path: SOString; Value: SuperInt); 508 function GetD(const path: SOString): Double; 509 procedure PutC(const path: SOString; Value: Currency); 510 function GetC(const path: SOString): Currency; 511 procedure PutD(const path: SOString; Value: Double); 512 function GetS(const path: SOString): SOString; 513 procedure PutS(const path: SOString; const Value: SOString); 514 {$IFDEF SUPER_METHOD} 515 function GetM(const path: SOString): TSuperMethod; 516 procedure PutM(const path: SOString; Value: TSuperMethod); 517 {$ENDIF} 518 function GetA(const path: SOString): TSuperArray; 519 520 // Null Object Design patern 521 function GetN(const path: SOString): ISuperObject; 522 procedure PutN(const path: SOString; const Value: ISuperObject); 523 524 // Writers 525 function Write(writer: TSuperWriter; indent: boolean; escape: boolean; level: integer): Integer; 526 function SaveTo(stream: TStream; indent: boolean = false; escape: boolean = true): integer; overload; 527 function SaveTo(const FileName: string; indent: boolean = false; escape: boolean = true): integer; overload; 528 function SaveTo(socket: longint; indent: boolean = false; escape: boolean = true): integer; overload; 529 function CalcSize(indent: boolean = false; escape: boolean = true): integer; 530 531 // convert 532 function AsBoolean: Boolean; 533 function AsInteger: SuperInt; 534 function AsDouble: Double; 535 function AsCurrency: Currency; 536 function AsString: SOString; 537 function AsArray: TSuperArray; 538 function AsObject: TSuperTableString; 539 {$IFDEF SUPER_METHOD} 540 function AsMethod: TSuperMethod; 541 {$ENDIF} 542 function AsJSon(indent: boolean = false; escape: boolean = true): SOString; 543 544 procedure Clear(all: boolean = false); 545 procedure Pack(all: boolean = false); 546 547 property N[const path: SOString]: ISuperObject read GetN write PutN; 548 property O[const path: SOString]: ISuperObject read GetO write PutO; default; 549 property B[const path: SOString]: boolean read GetB write PutB; 550 property I[const path: SOString]: SuperInt read GetI write PutI; 551 property D[const path: SOString]: Double read GetD write PutD; 552 property C[const path: SOString]: Currency read GetC write PutC; 553 property S[const path: SOString]: SOString read GetS write PutS; 554 {$IFDEF SUPER_METHOD} 555 property M[const path: SOString]: TSuperMethod read GetM write PutM; 556 {$ENDIF} 557 property A[const path: SOString]: TSuperArray read GetA; 558 559 {$IFDEF SUPER_METHOD} 560 function call(const path: SOString; const param: ISuperObject = nil): ISuperObject; overload; 561 function call(const path, param: SOString): ISuperObject; overload; 562 {$ENDIF} 563 // clone a node 564 function Clone: ISuperObject; 565 function Delete(const path: SOString): ISuperObject; 566 // merges tow objects of same type, if reference is true then nodes are not cloned 567 procedure Merge(const obj: ISuperObject; reference: boolean = false); overload; 568 procedure Merge(const str: SOString); overload; 569 570 // validate methods 571 function Validate(const rules: SOString; const defs: SOString = ''; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload; 572 function Validate(const rules: ISuperObject; const defs: ISuperObject = nil; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload; 573 574 // compare 575 function Compare(const obj: ISuperObject): TSuperCompareResult; overload; 576 function Compare(const str: SOString): TSuperCompareResult; overload; 577 578 // the data type 579 function IsType(AType: TSuperType): boolean; 580 property DataType: TSuperType read GetDataType; 581 property Processing: boolean read GetProcessing write SetProcessing; 582 583 function GetDataPtr: Pointer; 584 procedure SetDataPtr(const Value: Pointer); 585 property DataPtr: Pointer read GetDataPtr write SetDataPtr; 586 end; 587 588 TSuperObject = class(TObject, ISuperObject) 589 private 590 FRefCount: Integer; 591 FProcessing: boolean; 592 FDataType: TSuperType; 593 FDataPtr: Pointer; 594 {.$if true} 595 FO: record 596 case TSuperType of 597 stBoolean: (c_boolean: boolean); 598 stDouble: (c_double: double); 599 stCurrency: (c_currency: Currency); 600 stInt: (c_int: SuperInt); 601 stObject: (c_object: TSuperTableString); 602 stArray: (c_array: TSuperArray); 603 {$IFDEF SUPER_METHOD} 604 stMethod: (c_method: TSuperMethod); 605 {$ENDIF} 606 end; 607 {.$ifend} 608 FOString: SOString; 609 function GetDataType: TSuperType; 610 function GetDataPtr: Pointer; 611 procedure SetDataPtr(const Value: Pointer); 612 protected 613 function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall; 614 function _AddRef: Integer; virtual; stdcall; 615 function _Release: Integer; virtual; stdcall; 616 617 function GetO(const path: SOString): ISuperObject; 618 procedure PutO(const path: SOString; const Value: ISuperObject); 619 function GetB(const path: SOString): Boolean; 620 procedure PutB(const path: SOString; Value: Boolean); 621 function GetI(const path: SOString): SuperInt; 622 procedure PutI(const path: SOString; Value: SuperInt); 623 function GetD(const path: SOString): Double; 624 procedure PutD(const path: SOString; Value: Double); 625 procedure PutC(const path: SOString; Value: Currency); 626 function GetC(const path: SOString): Currency; 627 function GetS(const path: SOString): SOString; 628 procedure PutS(const path: SOString; const Value: SOString); 629 {$IFDEF SUPER_METHOD} 630 function GetM(const path: SOString): TSuperMethod; 631 procedure PutM(const path: SOString; Value: TSuperMethod); 632 {$ENDIF} 633 function GetA(const path: SOString): TSuperArray; 634 function Write(writer: TSuperWriter; indent: boolean; escape: boolean; level: integer): Integer; virtual; 635 public 636 function GetEnumerator: TSuperEnumerator; 637 procedure AfterConstruction; override; 638 procedure BeforeDestruction; override; 639 class function NewInstance: TObject; override; 640 property RefCount: Integer read FRefCount; 641 642 function GetProcessing: boolean; 643 procedure SetProcessing(value: boolean); 644 645 // Writers 646 function SaveTo(stream: TStream; indent: boolean = false; escape: boolean = true): integer; overload; 647 function SaveTo(const FileName: string; indent: boolean = false; escape: boolean = true): integer; overload; 648 function SaveTo(socket: longint; indent: boolean = false; escape: boolean = true): integer; overload; 649 function CalcSize(indent: boolean = false; escape: boolean = true): integer; 650 function AsJSon(indent: boolean = false; escape: boolean = true): SOString; 651 652 // parser ... owned! 653 class function ParseString(s: PSOChar; strict: Boolean; partial: boolean = true; const this: ISuperObject = nil; options: TSuperFindOptions = []; 654 const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject; 655 class function ParseStream(stream: TStream; strict: Boolean; partial: boolean = true; const this: ISuperObject = nil; options: TSuperFindOptions = []; 656 const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject; 657 class function ParseFile(const FileName: string; strict: Boolean; partial: boolean = true; const this: ISuperObject = nil; options: TSuperFindOptions = []; 658 const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject; 659 class function ParseEx(tok: TSuperTokenizer; str: PSOChar; len: integer; strict: Boolean; const this: ISuperObject = nil; 660 options: TSuperFindOptions = []; const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject; 661 662 // constructors / destructor 663 constructor Create(jt: TSuperType = stObject); overload; virtual; 664 constructor Create(b: boolean); overload; virtual; 665 constructor Create(i: SuperInt); overload; virtual; 666 constructor Create(d: double); overload; virtual; 667 constructor CreateCurrency(c: Currency); overload; virtual; 668 constructor Create(const s: SOString); overload; virtual; 669 {$IFDEF SUPER_METHOD} 670 constructor Create(m: TSuperMethod); overload; virtual; 671 {$ENDIF} 672 destructor Destroy; override; 673 674 // convert 675 function AsBoolean: Boolean; virtual; 676 function AsInteger: SuperInt; virtual; 677 function AsDouble: Double; virtual; 678 function AsCurrency: Currency; virtual; 679 function AsString: SOString; virtual; 680 function AsArray: TSuperArray; virtual; 681 function AsObject: TSuperTableString; virtual; 682 {$IFDEF SUPER_METHOD} 683 function AsMethod: TSuperMethod; virtual; 684 {$ENDIF} 685 procedure Clear(all: boolean = false); virtual; 686 procedure Pack(all: boolean = false); virtual; 687 function GetN(const path: SOString): ISuperObject; 688 procedure PutN(const path: SOString; const Value: ISuperObject); 689 function ForcePath(const path: SOString; dataType: TSuperType = stObject): ISuperObject; 690 function Format(const str: SOString; BeginSep: SOChar = '%'; EndSep: SOChar = '%'): SOString; 691 692 property N[const path: SOString]: ISuperObject read GetN write PutN; 693 property O[const path: SOString]: ISuperObject read GetO write PutO; default; 694 property B[const path: SOString]: boolean read GetB write PutB; 695 property I[const path: SOString]: SuperInt read GetI write PutI; 696 property D[const path: SOString]: Double read GetD write PutD; 697 property C[const path: SOString]: Currency read GetC write PutC; 698 property S[const path: SOString]: SOString read GetS write PutS; 699 {$IFDEF SUPER_METHOD} 700 property M[const path: SOString]: TSuperMethod read GetM write PutM; 701 {$ENDIF} 702 property A[const path: SOString]: TSuperArray read GetA; 703 704 {$IFDEF SUPER_METHOD} 705 function call(const path: SOString; const param: ISuperObject = nil): ISuperObject; overload; virtual; 706 function call(const path, param: SOString): ISuperObject; overload; virtual; 707 {$ENDIF} 708 // clone a node 709 function Clone: ISuperObject; virtual; 710 function Delete(const path: SOString): ISuperObject; 711 // merges tow objects of same type, if reference is true then nodes are not cloned 712 procedure Merge(const obj: ISuperObject; reference: boolean = false); overload; 713 procedure Merge(const str: SOString); overload; 714 715 // validate methods 716 function Validate(const rules: SOString; const defs: SOString = ''; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload; 717 function Validate(const rules: ISuperObject; const defs: ISuperObject = nil; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload; 718 719 // compare 720 function Compare(const obj: ISuperObject): TSuperCompareResult; overload; 721 function Compare(const str: SOString): TSuperCompareResult; overload; 722 723 // the data type 724 function IsType(AType: TSuperType): boolean; 725 property DataType: TSuperType read GetDataType; 726 // a data pointer to link to something ele, a treeview for example 727 property DataPtr: Pointer read GetDataPtr write SetDataPtr; 728 property Processing: boolean read GetProcessing; 729 end; 730 731 {$IFDEF VER210} 732 TSuperRttiContext = class; 733 734 TSerialFromJson = function(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean; 735 TSerialToJson = function(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject; 736 737 TSuperAttribute = class(TCustomAttribute) 738 private 739 FName: string; 740 public 741 constructor Create(const AName: string); 742 property Name: string read FName; 743 end; 744 745 SOName = class(TSuperAttribute); 746 SODefault = class(TSuperAttribute); 747 748 749 TSuperRttiContext = class 750 private 751 class function GetFieldName(r: TRttiField): string; 752 class function GetFieldDefault(r: TRttiField; const obj: ISuperObject): ISuperObject; 753 public 754 Context: TRttiContext; 755 SerialFromJson: TDictionary<PTypeInfo, TSerialFromJson>; 756 SerialToJson: TDictionary<PTypeInfo, TSerialToJson>; 757 constructor Create; virtual; 758 destructor Destroy; override; 759 function FromJson(TypeInfo: PTypeInfo; const obj: ISuperObject; var Value: TValue): Boolean; virtual; 760 function ToJson(var value: TValue; const index: ISuperObject): ISuperObject; virtual; 761 function AsType<T>(const obj: ISuperObject): T; 762 function AsJson<T>(const obj: T; const index: ISuperObject = nil): ISuperObject; 763 end; 764 765 TSuperObjectHelper = class helper for TObject 766 public 767 function ToJson(ctx: TSuperRttiContext = nil): ISuperObject; 768 constructor FromJson(const obj: ISuperObject; ctx: TSuperRttiContext = nil); overload; 769 constructor FromJson(const str: string; ctx: TSuperRttiContext = nil); overload; 770 end; 771 {$ENDIF} 772 773 TSuperObjectIter = record 774 key: SOString; 775 val: ISuperObject; 776 Ite: TSuperAvlIterator; 777 end; 778 779 function ObjectIsError(obj: TSuperObject): boolean; 780 function ObjectIsType(const obj: ISuperObject; typ: TSuperType): boolean; 781 function ObjectGetType(const obj: ISuperObject): TSuperType; 782 783 function ObjectFindFirst(const obj: ISuperObject; var F: TSuperObjectIter): boolean; 784 function ObjectFindNext(var F: TSuperObjectIter): boolean; 785 procedure ObjectFindClose(var F: TSuperObjectIter); 786 787 function SO(const s: SOString = '{}'): ISuperObject; overload; 788 function SO(const value: Variant): ISuperObject; overload; 789 function SO(const Args: array of const): ISuperObject; overload; 790 791 function SA(const Args: array of const): ISuperObject; overload; 792 793 function JavaToDelphiDateTime(const dt: int64): TDateTime; 794 function DelphiToJavaDateTime(const dt: TDateTime): int64; 795 796 {$IFDEF VER210} 797 798 type 799 TSuperInvokeResult = ( 800 irSuccess, 801 irMethothodError, // method don't exist 802 irParamError, // invalid parametters 803 irError // other error 804 ); 805 806 function TrySOInvoke(var ctx: TSuperRttiContext; const obj: TValue; const method: string; const params: ISuperObject; var Return: ISuperObject): TSuperInvokeResult; overload; 807 function SOInvoke(const obj: TValue; const method: string; const params: ISuperObject; ctx: TSuperRttiContext = nil): ISuperObject; overload; 808 function SOInvoke(const obj: TValue; const method: string; const params: string; ctx: TSuperRttiContext = nil): ISuperObject; overload; 809 {$ENDIF} 810 811 implementation 812 uses sysutils, 813 {$IFDEF UNIX} 814 baseunix, unix, DateUtils 815 {$ELSE} 816 Windows 817 {$ENDIF} 818 {$IFDEF FPC} 819 ,sockets 820 {$ELSE} 821 ,WinSock 822 {$ENDIF}; 823 824 {$IFDEF DEBUG} 825 var 826 debugcount: integer = 0; 827 {$ENDIF} 828 829 const 830 super_number_chars_set = ['0'..'9','.','+','-','e','E']; 831 super_hex_chars: PSOChar = '0123456789abcdef'; 832 super_hex_chars_set = ['0'..'9','a'..'f','A'..'F']; 833 834 ESC_BS: PSOChar = '\b'; 835 ESC_LF: PSOChar = '\n'; 836 ESC_CR: PSOChar = '\r'; 837 ESC_TAB: PSOChar = '\t'; 838 ESC_FF: PSOChar = '\f'; 839 ESC_QUOT: PSOChar = '\"'; 840 ESC_SL: PSOChar = '\\'; 841 ESC_SR: PSOChar = '\/'; 842 ESC_ZERO: PSOChar = '\u0000'; 843 844 TOK_CRLF: PSOChar = #13#10; 845 TOK_SP: PSOChar = #32; 846 TOK_BS: PSOChar = #8; 847 TOK_TAB: PSOChar = #9; 848 TOK_LF: PSOChar = #10; 849 TOK_FF: PSOChar = #12; 850 TOK_CR: PSOChar = #13; 851 // TOK_SL: PSOChar = '\'; 852 // TOK_SR: PSOChar = '/'; 853 TOK_NULL: PSOChar = 'null'; 854 TOK_CBL: PSOChar = '{'; // curly bracket left 855 TOK_CBR: PSOChar = '}'; // curly bracket right 856 TOK_ARL: PSOChar = '['; 857 TOK_ARR: PSOChar = ']'; 858 TOK_ARRAY: PSOChar = '[]'; 859 TOK_OBJ: PSOChar = '{}'; // empty object 860 TOK_COM: PSOChar = ','; // Comma 861 TOK_DQT: PSOChar = '"'; // Double Quote 862 TOK_TRUE: PSOChar = 'true'; 863 TOK_FALSE: PSOChar = 'false'; 864 865 {$if (sizeof(Char) = 1)} 866 function StrLComp(const Str1, Str2: PSOChar; MaxLen: Cardinal): Integer; 867 var 868 P1, P2: PWideChar; 869 I: Cardinal; 870 C1, C2: WideChar; 871 begin 872 P1 := Str1; 873 P2 := Str2; 874 I := 0; 875 while I < MaxLen do 876 begin 877 C1 := P1^; 878 C2 := P2^; 879 880 if (C1 <> C2) or (C1 = #0) then 881 begin 882 Result := Ord(C1) - Ord(C2); 883 Exit; 884 end; 885 886 Inc(P1); 887 Inc(P2); 888 Inc(I); 889 end; 890 Result := 0; 891 end; 892 893 function StrComp(const Str1, Str2: PSOChar): Integer; 894 var 895 P1, P2: PWideChar; 896 C1, C2: WideChar; 897 begin 898 P1 := Str1; 899 P2 := Str2; 900 while True do 901 begin 902 C1 := P1^; 903 C2 := P2^; 904 905 if (C1 <> C2) or (C1 = #0) then 906 begin 907 Result := Ord(C1) - Ord(C2); 908 Exit; 909 end; 910 911 Inc(P1); 912 Inc(P2); 913 end; 914 end; 915 916 function StrLen(const Str: PSOChar): Cardinal; 917 var 918 p: PSOChar; 919 begin 920 Result := 0; 921 if Str <> nil then 922 begin 923 p := Str; 924 while p^ <> #0 do inc(p); 925 Result := (p - Str); 926 end; 927 end; 928 {$ifend} 929 930 function CurrToStr(c: Currency): SOString; 931 var 932 p: PSOChar; 933 i, len: Integer; 934 begin 935 Result := IntToStr(Abs(PInt64(@c)^)); 936 len := Length(Result); 937 SetLength(Result, len+1); 938 if c <> 0 then 939 begin 940 while len <= 4 do 941 begin 942 Result := '0' + Result; 943 inc(len); 944 end; 945 946 p := PSOChar(Result); 947 inc(p, len-1); 948 i := 0; 949 repeat 950 if p^ <> '0' then 951 begin 952 len := len - i + 1; 953 repeat 954 p[1] := p^; 955 dec(p); 956 inc(i); 957 until i > 3; 958 Break; 959 end; 960 dec(p); 961 inc(i); 962 if i > 3 then 963 begin 964 len := len - i + 1; 965 Break; 966 end; 967 until false; 968 p[1] := '.'; 969 SetLength(Result, len); 970 if c < 0 then 971 Result := '-' + Result; 972 end; 973 end; 974 975 {$IFDEF UNIX} 976 {$linklib c} 977 {$ENDIF} 978 function gcvt(value: Double; ndigit: longint; buf: PAnsiChar): PAnsiChar; cdecl; 979 external {$IFDEF MSWINDOWS} 'msvcrt.dll' name '_gcvt'{$ENDIF}; 980 981 {$IFDEF UNIX} 982 type 983 ptm = ^tm; 984 tm = record 985 tm_sec: Integer; (* Seconds: 0-59 (K&R says 0-61?) *) 986 tm_min: Integer; (* Minutes: 0-59 *) 987 tm_hour: Integer; (* Hours since midnight: 0-23 *) 988 tm_mday: Integer; (* Day of the month: 1-31 *) 989 tm_mon: Integer; (* Months *since* january: 0-11 *) 990 tm_year: Integer; (* Years since 1900 *) 991 tm_wday: Integer; (* Days since Sunday (0-6) *) 992 tm_yday: Integer; (* Days since Jan. 1: 0-365 *) 993 tm_isdst: Integer; (* +1 Daylight Savings Time, 0 No DST, -1 don't know *) 994 end; 995 996 function mktime(p: ptm): LongInt; cdecl; external; 997 function gmtime(const t: PLongint): ptm; cdecl; external; 998 function localtime (const t: PLongint): ptm; cdecl; external; 999 1000 function DelphiToJavaDateTime(const dt: TDateTime): Int64; 1001 var 1002 p: ptm; 1003 l, ms: Integer; 1004 v: Int64; 1005 begin 1006 v := Round((dt - 25569) * 86400000); 1007 ms := v mod 1000; 1008 l := v div 1000; 1009 p := localtime(@l); 1010 Result := Int64(mktime(p)) * 1000 + ms; 1011 end; 1012 1013 function JavaToDelphiDateTime(const dt: int64): TDateTime; 1014 var 1015 p: ptm; 1016 l, ms: Integer; 1017 begin 1018 l := dt div 1000; 1019 ms := dt mod 1000; 1020 p := gmtime(@l); 1021 Result := EncodeDateTime(p^.tm_year+1900, p^.tm_mon+1, p^.tm_mday, p^.tm_hour, p^.tm_min, p^.tm_sec, ms); 1022 end; 1023 {$ELSE} 1024 1025 {$IFDEF WINDOWSNT_COMPATIBILITY} 1026 function DayLightCompareDate(const date: PSystemTime; 1027 const compareDate: PSystemTime): Integer; 1028 var 1029 limit_day, dayinsecs, weekofmonth: Integer; 1030 First: Word; 1031 begin 1032 if (date^.wMonth < compareDate^.wMonth) then 1033 begin 1034 Result := -1; (* We are in a month before the date limit. *) 1035 Exit; 1036 end; 1037 1038 if (date^.wMonth > compareDate^.wMonth) then 1039 begin 1040 Result := 1; (* We are in a month after the date limit. *) 1041 Exit; 1042 end; 1043 1044 (* if year is 0 then date is in day-of-week format, otherwise 1045 * it's absolute date. 1046 *) 1047 if (compareDate^.wYear = 0) then 1048 begin 1049 (* compareDate.wDay is interpreted as number of the week in the month 1050 * 5 means: the last week in the month *) 1051 weekofmonth := compareDate^.wDay; 1052 (* calculate the day of the first DayOfWeek in the month *) 1053 First := (6 + compareDate^.wDayOfWeek - date^.wDayOfWeek + date^.wDay) mod 7 + 1; 1054 limit_day := First + 7 * (weekofmonth - 1); 1055 (* check needed for the 5th weekday of the month *) 1056 if (limit_day > MonthDays[(date^.wMonth=2) and IsLeapYear(date^.wYear)][date^.wMonth - 1]) then 1057 dec(limit_day, 7); 1058 end 1059 else 1060 limit_day := compareDate^.wDay; 1061 1062 (* convert to seconds *) 1063 limit_day := ((limit_day * 24 + compareDate^.wHour) * 60 + compareDate^.wMinute ) * 60; 1064 dayinsecs := ((date^.wDay * 24 + date^.wHour) * 60 + date^.wMinute ) * 60 + date^.wSecond; 1065 (* and compare *) 1066 1067 if dayinsecs < limit_day then 1068 Result := -1 else 1069 if dayinsecs > limit_day then 1070 Result := 1 else 1071 Result := 0; (* date is equal to the date limit. *) 1072 end; 1073 1074 function CompTimeZoneID(const pTZinfo: PTimeZoneInformation; 1075 lpFileTime: PFileTime; islocal: Boolean): LongWord; 1076 var 1077 ret: Integer; 1078 beforeStandardDate, afterDaylightDate: Boolean; 1079 llTime: Int64; 1080 SysTime: TSystemTime; 1081 ftTemp: TFileTime; 1082 begin 1083 llTime := 0; 1084 1085 if (pTZinfo^.DaylightDate.wMonth <> 0) then 1086 begin 1087 (* if year is 0 then date is in day-of-week format, otherwise 1088 * it's absolute date. 1089 *) 1090 if ((pTZinfo^.StandardDate.wMonth = 0) or 1091 ((pTZinfo^.StandardDate.wYear = 0) and 1092 ((pTZinfo^.StandardDate.wDay < 1) or 1093 (pTZinfo^.StandardDate.wDay > 5) or 1094 (pTZinfo^.DaylightDate.wDay < 1) or 1095 (pTZinfo^.DaylightDate.wDay > 5)))) then 1096 begin 1097 SetLastError(ERROR_INVALID_PARAMETER); 1098 Result := TIME_ZONE_ID_INVALID; 1099 Exit; 1100 end; 1101 1102 if (not islocal) then 1103 begin 1104 llTime := PInt64(lpFileTime)^; 1105 dec(llTime, Int64(pTZinfo^.Bias + pTZinfo^.DaylightBias) * 600000000); 1106 PInt64(@ftTemp)^ := llTime; 1107 lpFileTime := @ftTemp; 1108 end; 1109 1110 FileTimeToSystemTime(lpFileTime^, SysTime); 1111 1112 (* check for daylight savings *) 1113 ret := DayLightCompareDate(@SysTime, @pTZinfo^.StandardDate); 1114 if (ret = -2) then 1115 begin 1116 Result := TIME_ZONE_ID_INVALID; 1117 Exit; 1118 end; 1119 1120 beforeStandardDate := ret < 0; 1121 1122 if (not islocal) then 1123 begin 1124 dec(llTime, Int64(pTZinfo^.StandardBias - pTZinfo^.DaylightBias) * 600000000); 1125 PInt64(@ftTemp)^ := llTime; 1126 FileTimeToSystemTime(lpFileTime^, SysTime); 1127 end; 1128 1129 ret := DayLightCompareDate(@SysTime, @pTZinfo^.DaylightDate); 1130 if (ret = -2) then 1131 begin 1132 Result := TIME_ZONE_ID_INVALID; 1133 Exit; 1134 end; 1135 1136 afterDaylightDate := ret >= 0; 1137 1138 Result := TIME_ZONE_ID_STANDARD; 1139 if( pTZinfo^.DaylightDate.wMonth < pTZinfo^.StandardDate.wMonth ) then 1140 begin 1141 (* Northern hemisphere *) 1142 if( beforeStandardDate and afterDaylightDate) then 1143 Result := TIME_ZONE_ID_DAYLIGHT; 1144 end else (* Down south *) 1145 if( beforeStandardDate or afterDaylightDate) then 1146 Result := TIME_ZONE_ID_DAYLIGHT; 1147 end else 1148 (* No transition date *) 1149 Result := TIME_ZONE_ID_UNKNOWN; 1150 end; 1151 1152 function GetTimezoneBias(const pTZinfo: PTimeZoneInformation; 1153 lpFileTime: PFileTime; islocal: Boolean; pBias: PLongint): Boolean; 1154 var 1155 bias: LongInt; 1156 tzid: LongWord; 1157 begin 1158 bias := pTZinfo^.Bias; 1159 tzid := CompTimeZoneID(pTZinfo, lpFileTime, islocal); 1160 1161 if( tzid = TIME_ZONE_ID_INVALID) then 1162 begin 1163 Result := False; 1164 Exit; 1165 end; 1166 if (tzid = TIME_ZONE_ID_DAYLIGHT) then 1167 inc(bias, pTZinfo^.DaylightBias) 1168 else if (tzid = TIME_ZONE_ID_STANDARD) then 1169 inc(bias, pTZinfo^.StandardBias); 1170 pBias^ := bias; 1171 Result := True; 1172 end; 1173 1174 function SystemTimeToTzSpecificLocalTime( 1175 lpTimeZoneInformation: PTimeZoneInformation; 1176 lpUniversalTime, lpLocalTime: PSystemTime): BOOL; 1177 var 1178 ft: TFileTime; 1179 lBias: LongInt; 1180 llTime: Int64; 1181 tzinfo: TTimeZoneInformation; 1182 begin 1183 if (lpTimeZoneInformation <> nil) then 1184 tzinfo := lpTimeZoneInformation^ else 1185 if (GetTimeZoneInformation(tzinfo) = TIME_ZONE_ID_INVALID) then 1186 begin 1187 Result := False; 1188 Exit; 1189 end; 1190 1191 if (not SystemTimeToFileTime(lpUniversalTime^, ft)) then 1192 begin 1193 Result := False; 1194 Exit; 1195 end; 1196 llTime := PInt64(@ft)^; 1197 if (not GetTimezoneBias(@tzinfo, @ft, False, @lBias)) then 1198 begin 1199 Result := False; 1200 Exit; 1201 end; 1202 (* convert minutes to 100-nanoseconds-ticks *) 1203 dec(llTime, Int64(lBias) * 600000000); 1204 PInt64(@ft)^ := llTime; 1205 Result := FileTimeToSystemTime(ft, lpLocalTime^); 1206 end; 1207 1208 function TzSpecificLocalTimeToSystemTime( 1209 const lpTimeZoneInformation: PTimeZoneInformation; 1210 const lpLocalTime: PSystemTime; lpUniversalTime: PSystemTime): BOOL; 1211 var 1212 ft: TFileTime; 1213 lBias: LongInt; 1214 t: Int64; 1215 tzinfo: TTimeZoneInformation; 1216 begin 1217 if (lpTimeZoneInformation <> nil) then 1218 tzinfo := lpTimeZoneInformation^ 1219 else 1220 if (GetTimeZoneInformation(tzinfo) = TIME_ZONE_ID_INVALID) then 1221 begin 1222 Result := False; 1223 Exit; 1224 end; 1225 1226 if (not SystemTimeToFileTime(lpLocalTime^, ft)) then 1227 begin 1228 Result := False; 1229 Exit; 1230 end; 1231 t := PInt64(@ft)^; 1232 if (not GetTimezoneBias(@tzinfo, @ft, True, @lBias)) then 1233 begin 1234 Result := False; 1235 Exit; 1236 end; 1237 (* convert minutes to 100-nanoseconds-ticks *) 1238 inc(t, Int64(lBias) * 600000000); 1239 PInt64(@ft)^ := t; 1240 Result := FileTimeToSystemTime(ft, lpUniversalTime^); 1241 end; 1242 {$ELSE} 1243 function TzSpecificLocalTimeToSystemTime( 1244 lpTimeZoneInformation: PTimeZoneInformation; 1245 lpLocalTime, lpUniversalTime: PSystemTime): BOOL; stdcall; external 'kernel32.dll'; 1246 1247 function SystemTimeToTzSpecificLocalTime( 1248 lpTimeZoneInformation: PTimeZoneInformation; 1249 lpUniversalTime, lpLocalTime: PSystemTime): BOOL; stdcall; external 'kernel32.dll'; 1250 {$ENDIF} 1251 1252 function JavaToDelphiDateTime(const dt: int64): TDateTime; 1253 var 1254 t: TSystemTime; 1255 begin 1256 DateTimeToSystemTime(25569 + (dt / 86400000), t); 1257 SystemTimeToTzSpecificLocalTime(nil, @t, @t); 1258 Result := SystemTimeToDateTime(t); 1259 end; 1260 1261 function DelphiToJavaDateTime(const dt: TDateTime): int64; 1262 var 1263 t: TSystemTime; 1264 begin 1265 DateTimeToSystemTime(dt, t); 1266 TzSpecificLocalTimeToSystemTime(nil, @t, @t); 1267 Result := Round((SystemTimeToDateTime(t) - 25569) * 86400000) 1268 end; 1269 {$ENDIF} 1270 1271 1272 function SO(const s: SOString): ISuperObject; overload; 1273 begin 1274 Result := TSuperObject.ParseString(PSOChar(s), False); 1275 end; 1276 1277 function SA(const Args: array of const): ISuperObject; overload; 1278 type 1279 TByteArray = array[0..sizeof(integer) - 1] of byte; 1280 PByteArray = ^TByteArray; 1281 var 1282 j: Integer; 1283 intf: IInterface; 1284 begin 1285 Result := TSuperObject.Create(stArray); 1286 for j := 0 to length(Args) - 1 do 1287 with Result.AsArray do 1288 case TVarRec(Args[j]).VType of 1289 vtInteger : Add(TSuperObject.Create(TVarRec(Args[j]).VInteger)); 1290 vtInt64 : Add(TSuperObject.Create(TVarRec(Args[j]).VInt64^)); 1291 vtBoolean : Add(TSuperObject.Create(TVarRec(Args[j]).VBoolean)); 1292 vtChar : Add(TSuperObject.Create(SOString(TVarRec(Args[j]).VChar))); 1293 vtWideChar: Add(TSuperObject.Create(SOChar(TVarRec(Args[j]).VWideChar))); 1294 vtExtended: Add(TSuperObject.Create(TVarRec(Args[j]).VExtended^)); 1295 vtCurrency: Add(TSuperObject.CreateCurrency(TVarRec(Args[j]).VCurrency^)); 1296 vtString : Add(TSuperObject.Create(SOString(TVarRec(Args[j]).VString^))); 1297 vtPChar : Add(TSuperObject.Create(SOString(TVarRec(Args[j]).VPChar^))); 1298 vtAnsiString: Add(TSuperObject.Create(SOString(AnsiString(TVarRec(Args[j]).VAnsiString)))); 1299 vtWideString: Add(TSuperObject.Create(SOString(PWideChar(TVarRec(Args[j]).VWideString)))); 1300 vtInterface: 1301 if TVarRec(Args[j]).VInterface = nil then 1302 Add(nil) else 1303 if IInterface(TVarRec(Args[j]).VInterface).QueryInterface(ISuperObject, intf) = 0 then 1304 Add(ISuperObject(intf)) else 1305 Add(nil); 1306 vtPointer : 1307 if TVarRec(Args[j]).VPointer = nil then 1308 Add(nil) else 1309 Add(TSuperObject.Create(PtrInt(TVarRec(Args[j]).VPointer))); 1310 vtVariant: 1311 Add(SO(TVarRec(Args[j]).VVariant^)); 1312 vtObject: 1313 if TVarRec(Args[j]).VPointer = nil then 1314 Add(nil) else 1315 Add(TSuperObject.Create(PtrInt(TVarRec(Args[j]).VPointer))); 1316 vtClass: 1317 if TVarRec(Args[j]).VPointer = nil then 1318 Add(nil) else 1319 Add(TSuperObject.Create(PtrInt(TVarRec(Args[j]).VPointer))); 1320 {$if declared(vtUnicodeString)} 1321 vtUnicodeString: 1322 Add(TSuperObject.Create(SOString(string(TVarRec(Args[j]).VUnicodeString)))); 1323 {$ifend} 1324 else 1325 assert(false); 1326 end; 1327 end; 1328 1329 function SO(const Args: array of const): ISuperObject; overload; 1330 var 1331 j: Integer; 1332 arr: ISuperObject; 1333 begin 1334 Result := TSuperObject.Create(stObject); 1335 arr := SA(Args); 1336 with arr.AsArray do 1337 for j := 0 to (Length div 2) - 1 do 1338 Result.AsObject.PutO(O[j*2].AsString, O[(j*2) + 1]); 1339 end; 1340 1341 function SO(const value: Variant): ISuperObject; overload; 1342 begin 1343 with TVarData(value) do 1344 case VType of 1345 varNull: Result := nil; 1346 varEmpty: Result := nil; 1347 varSmallInt: Result := TSuperObject.Create(VSmallInt); 1348 varInteger: Result := TSuperObject.Create(VInteger); 1349 varSingle: Result := TSuperObject.Create(VSingle); 1350 varDouble: Result := TSuperObject.Create(VDouble); 1351 varCurrency: Result := TSuperObject.CreateCurrency(VCurrency); 1352 varDate: Result := TSuperObject.Create(DelphiToJavaDateTime(vDate)); 1353 varOleStr: Result := TSuperObject.Create(SOString(VOleStr)); 1354 varBoolean: Result := TSuperObject.Create(VBoolean); 1355 varShortInt: Result := TSuperObject.Create(VShortInt); 1356 varByte: Result := TSuperObject.Create(VByte); 1357 varWord: Result := TSuperObject.Create(VWord); 1358 varLongWord: Result := TSuperObject.Create(VLongWord); 1359 varInt64: Result := TSuperObject.Create(VInt64); 1360 varString: Result := TSuperObject.Create(SOString(AnsiString(VString))); 1361 {$if declared(varUString)} 1362 varUString: Result := TSuperObject.Create(SOString(string(VUString))); 1363 {$ifend} 1364 else 1365 raise Exception.CreateFmt('Unsuported variant data type: %d', [VType]); 1366 end; 1367 end; 1368 1369 function ObjectIsError(obj: TSuperObject): boolean; 1370 begin 1371 Result := PtrUInt(obj) > PtrUInt(-4000); 1372 end; 1373 1374 function ObjectIsType(const obj: ISuperObject; typ: TSuperType): boolean; 1375 begin 1376 if obj <> nil then 1377 Result := typ = obj.DataType else 1378 Result := typ = stNull; 1379 end; 1380 1381 function ObjectGetType(const obj: ISuperObject): TSuperType; 1382 begin 1383 if obj <> nil then 1384 Result := obj.DataType else 1385 Result := stNull; 1386 end; 1387 1388 function ObjectFindFirst(const obj: ISuperObject; var F: TSuperObjectIter): boolean; 1389 var 1390 i: TSuperAvlEntry; 1391 begin 1392 if ObjectIsType(obj, stObject) then 1393 begin 1394 F.Ite := TSuperAvlIterator.Create(obj.AsObject); 1395 F.Ite.First; 1396 i := F.Ite.GetIter; 1397 if i <> nil then 1398 begin 1399 f.key := i.Name; 1400 f.val := i.Value; 1401 Result := true; 1402 end else 1403 Result := False; 1404 end else 1405 Result := False; 1406 end; 1407 1408 function ObjectFindNext(var F: TSuperObjectIter): boolean; 1409 var 1410 i: TSuperAvlEntry; 1411 begin 1412 F.Ite.Next; 1413 i := F.Ite.GetIter; 1414 if i <> nil then 1415 begin 1416 f.key := i.FName; 1417 f.val := i.Value; 1418 Result := true; 1419 end else 1420 Result := False; 1421 end; 1422 1423 procedure ObjectFindClose(var F: TSuperObjectIter); 1424 begin 1425 F.Ite.Free; 1426 F.val := nil; 1427 end; 1428 1429 {$IFDEF VER210} 1430 1431 function serialtoboolean(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject; 1432 begin 1433 Result := TSuperObject.Create(TValueData(value).FAsSLong <> 0); 1434 end; 1435 1436 function serialtodatetime(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject; 1437 begin 1438 Result := TSuperObject.Create(DelphiToJavaDateTime(TValueData(value).FAsDouble)); 1439 end; 1440 1441 function serialtoguid(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject; 1442 var 1443 g: TGUID; 1444 begin 1445 value.ExtractRawData(@g); 1446 Result := TSuperObject.Create( 1447 format('%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x', 1448 [g.D1, g.D2, g.D3, 1449 g.D4[0], g.D4[1], g.D4[2], 1450 g.D4[3], g.D4[4], g.D4[5], 1451 g.D4[6], g.D4[7]]) 1452 ); 1453 end; 1454 1455 function serialfromboolean(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean; 1456 var 1457 o: ISuperObject; 1458 begin 1459 case ObjectGetType(obj) of 1460 stBoolean: 1461 begin 1462 TValueData(Value).FAsSLong := obj.AsInteger; 1463 Result := True; 1464 end; 1465 stInt: 1466 begin 1467 TValueData(Value).FAsSLong := ord(obj.AsInteger <> 0); 1468 Result := True; 1469 end; 1470 stString: 1471 begin 1472 o := SO(obj.AsString); 1473 if not ObjectIsType(o, stString) then 1474 Result := serialfromboolean(ctx, SO(obj.AsString), Value) else 1475 Result := False; 1476 end; 1477 else 1478 Result := False; 1479 end; 1480 end; 1481 1482 function serialfromdatetime(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean; 1483 var 1484 dt: TDateTime; 1485 begin 1486 case ObjectGetType(obj) of 1487 stInt: 1488 begin 1489 TValueData(Value).FAsDouble := JavaToDelphiDateTime(obj.AsInteger); 1490 Result := True; 1491 end; 1492 stString: 1493 begin 1494 if TryStrToDateTime(obj.AsString, dt) then 1495 begin 1496 TValueData(Value).FAsDouble := dt; 1497 Result := True; 1498 end else 1499 Result := False; 1500 end; 1501 else 1502 Result := False; 1503 end; 1504 end; 1505 1506 function UuidFromString(const s: PSOChar; Uuid: PGUID): Boolean; 1507 const 1508 hex2bin: array[#0..#102] of short = ( 1509 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, (* 0x00 *) 1510 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, (* 0x10 *) 1511 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, (* 0x20 *) 1512 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, (* 0x30 *) 1513 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, (* 0x40 *) 1514 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, (* 0x50 *) 1515 -1,10,11,12,13,14,15); (* 0x60 *) 1516 var 1517 i: Integer; 1518 begin 1519 if (strlen(s) <> 36) then Exit(False); 1520 1521 if ((s[8] <> '-') or (s[13] <> '-') or (s[18] <> '-') or (s[23] <> '-')) then 1522 Exit(False); 1523 1524 for i := 0 to 35 do 1525 begin 1526 if not i in [8,13,18,23] then 1527 if ((s[i] > 'f') or ((hex2bin[s[i]] = -1) and (s[i] <> ''))) then 1528 Exit(False); 1529 end; 1530 1531 uuid.D1 := ((hex2bin[s[0]] shl 28) or (hex2bin[s[1]] shl 24) or (hex2bin[s[2]] shl 20) or (hex2bin[s[3]] shl 16) or 1532 (hex2bin[s[4]] shl 12) or (hex2bin[s[5]] shl 8) or (hex2bin[s[6]] shl 4) or hex2bin[s[7]]); 1533 uuid.D2 := (hex2bin[s[9]] shl 12) or (hex2bin[s[10]] shl 8) or (hex2bin[s[11]] shl 4) or hex2bin[s[12]]; 1534 uuid.D3 := (hex2bin[s[14]] shl 12) or (hex2bin[s[15]] shl 8) or (hex2bin[s[16]] shl 4) or hex2bin[s[17]]; 1535 1536 uuid.D4[0] := (hex2bin[s[19]] shl 4) or hex2bin[s[20]]; 1537 uuid.D4[1] := (hex2bin[s[21]] shl 4) or hex2bin[s[22]]; 1538 uuid.D4[2] := (hex2bin[s[24]] shl 4) or hex2bin[s[25]]; 1539 uuid.D4[3] := (hex2bin[s[26]] shl 4) or hex2bin[s[27]]; 1540 uuid.D4[4] := (hex2bin[s[28]] shl 4) or hex2bin[s[29]]; 1541 uuid.D4[5] := (hex2bin[s[30]] shl 4) or hex2bin[s[31]]; 1542 uuid.D4[6] := (hex2bin[s[32]] shl 4) or hex2bin[s[33]]; 1543 uuid.D4[7] := (hex2bin[s[34]] shl 4) or hex2bin[s[35]]; 1544 Result := True; 1545 end; 1546 1547 function serialfromguid(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean; 1548 begin 1549 case ObjectGetType(obj) of 1550 stNull: 1551 begin 1552 FillChar(Value.GetReferenceToRawData^, SizeOf(TGUID), 0); 1553 Result := True; 1554 end; 1555 stString: Result := UuidFromString(PSOChar(obj.AsString), Value.GetReferenceToRawData); 1556 else 1557 Result := False; 1558 end; 1559 end; 1560 1561 function SOInvoke(const obj: TValue; const method: string; const params: ISuperObject; ctx: TSuperRttiContext): ISuperObject; overload; 1562 var 1563 owned: Boolean; 1564 begin 1565 if ctx = nil then 1566 begin 1567 ctx := TSuperRttiContext.Create; 1568 owned := True; 1569 end else 1570 owned := False; 1571 try 1572 if TrySOInvoke(ctx, obj, method, params, Result) <> irSuccess then 1573 raise Exception.Create('Invalid method call'); 1574 finally 1575 if owned then 1576 ctx.Free; 1577 end; 1578 end; 1579 1580 function SOInvoke(const obj: TValue; const method: string; const params: string; ctx: TSuperRttiContext): ISuperObject; overload; 1581 begin 1582 Result := SOInvoke(obj, method, so(params), ctx) 1583 end; 1584 1585 function TrySOInvoke(var ctx: TSuperRttiContext; const obj: TValue; 1586 const method: string; const params: ISuperObject; 1587 var Return: ISuperObject): TSuperInvokeResult; 1588 var 1589 t: TRttiInstanceType; 1590 m: TRttiMethod; 1591 a: TArray<TValue>; 1592 ps: TArray<TRttiParameter>; 1593 v: TValue; 1594 index: ISuperObject; 1595 1596 function GetParams: Boolean; 1597 var 1598 i: Integer; 1599 begin 1600 case ObjectGetType(params) of 1601 stArray: 1602 for i := 0 to Length(ps) - 1 do 1603 if (pfOut in ps[i].Flags) then 1604 TValue.Make(nil, ps[i].ParamType.Handle, a[i]) else 1605 if not ctx.FromJson(ps[i].ParamType.Handle, params.AsArray[i], a[i]) then 1606 Exit(False); 1607 stObject: 1608 for i := 0 to Length(ps) - 1 do 1609 if (pfOut in ps[i].Flags) then 1610 TValue.Make(nil, ps[i].ParamType.Handle, a[i]) else 1611 if not ctx.FromJson(ps[i].ParamType.Handle, params.AsObject[ps[i].Name], a[i]) then 1612 Exit(False); 1613 stNull: ; 1614 else 1615 Exit(False); 1616 end; 1617 Result := True; 1618 end; 1619 1620 procedure SetParams; 1621 var 1622 i: Integer; 1623 begin 1624 case ObjectGetType(params) of 1625 stArray: 1626 for i := 0 to Length(ps) - 1 do 1627 if (ps[i].Flags * [pfVar, pfOut]) <> [] then 1628 params.AsArray[i] := ctx.ToJson(a[i], index); 1629 stObject: 1630 for i := 0 to Length(ps) - 1 do 1631 if (ps[i].Flags * [pfVar, pfOut]) <> [] then 1632 params.AsObject[ps[i].Name] := ctx.ToJson(a[i], index); 1633 end; 1634 end; 1635 1636 begin 1637 Result := irSuccess; 1638 index := SO; 1639 case obj.Kind of 1640 tkClass: 1641 begin 1642 t := TRttiInstanceType(ctx.Context.GetType(obj.AsObject.ClassType)); 1643 m := t.GetMethod(method); 1644 if m = nil then Exit(irMethothodError); 1645 ps := m.GetParameters; 1646 SetLength(a, Length(ps)); 1647 if not GetParams then Exit(irParamError); 1648 if m.IsClassMethod then 1649 begin 1650 v := m.Invoke(obj.AsObject.ClassType, a); 1651 Return := ctx.ToJson(v, index); 1652 SetParams; 1653 end else 1654 begin 1655 v := m.Invoke(obj, a); 1656 Return := ctx.ToJson(v, index); 1657 SetParams; 1658 end; 1659 end; 1660 tkClassRef: 1661 begin 1662 t := TRttiInstanceType(ctx.Context.GetType(obj.AsClass)); 1663 m := t.GetMethod(method); 1664 if m = nil then Exit(irMethothodError); 1665 ps := m.GetParameters; 1666 SetLength(a, Length(ps)); 1667 1668 if not GetParams then Exit(irParamError); 1669 if m.IsClassMethod then 1670 begin 1671 v := m.Invoke(obj, a); 1672 Return := ctx.ToJson(v, index); 1673 SetParams; 1674 end else 1675 Exit(irError); 1676 end; 1677 else 1678 Exit(irError); 1679 end; 1680 end; 1681 1682 {$ENDIF} 1683 1684 { TSuperEnumerator } 1685 1686 constructor TSuperEnumerator.Create(const obj: ISuperObject); 1687 begin 1688 FObj := obj; 1689 FCount := -1; 1690 if ObjectIsType(FObj, stObject) then 1691 FObjEnum := FObj.AsObject.GetEnumerator else 1692 FObjEnum := nil; 1693 end; 1694 1695 destructor TSuperEnumerator.Destroy; 1696 begin 1697 if FObjEnum <> nil then 1698 FObjEnum.Free; 1699 end; 1700 1701 function TSuperEnumerator.MoveNext: Boolean; 1702 begin 1703 case ObjectGetType(FObj) of 1704 stObject: Result := FObjEnum.MoveNext; 1705 stArray: 1706 begin 1707 inc(FCount); 1708 if FCount < FObj.AsArray.Length then 1709 Result := True else 1710 Result := False; 1711 end; 1712 else 1713 Result := false; 1714 end; 1715 end; 1716 1717 function TSuperEnumerator.GetCurrent: ISuperObject; 1718 begin 1719 case ObjectGetType(FObj) of 1720 stObject: Result := FObjEnum.Current.Value; 1721 stArray: Result := FObj.AsArray.GetO(FCount); 1722 else 1723 Result := FObj; 1724 end; 1725 end; 1726 1727 { TSuperObject } 1728 1729 constructor TSuperObject.Create(jt: TSuperType); 1730 begin 1731 inherited Create; 1732 {$IFDEF DEBUG} 1733 InterlockedIncrement(debugcount); 1734 {$ENDIF} 1735 1736 FProcessing := false; 1737 FDataPtr := nil; 1738 FDataType := jt; 1739 case FDataType of 1740 stObject: FO.c_object := TSuperTableString.Create; 1741 stArray: FO.c_array := TSuperArray.Create; 1742 stString: FOString := ''; 1743 else 1744 FO.c_object := nil; 1745 end; 1746 end; 1747 1748 constructor TSuperObject.Create(b: boolean); 1749 begin 1750 Create(stBoolean); 1751 FO.c_boolean := b; 1752 end; 1753 1754 constructor TSuperObject.Create(i: SuperInt); 1755 begin 1756 Create(stInt); 1757 FO.c_int := i; 1758 end; 1759 1760 constructor TSuperObject.Create(d: double); 1761 begin 1762 Create(stDouble); 1763 FO.c_double := d; 1764 end; 1765 1766 constructor TSuperObject.CreateCurrency(c: Currency); 1767 begin 1768 Create(stCurrency); 1769 FO.c_currency := c; 1770 end; 1771 1772 destructor TSuperObject.Destroy; 1773 begin 1774 {$IFDEF DEBUG} 1775 InterlockedDecrement(debugcount); 1776 {$ENDIF} 1777 case FDataType of 1778 stObject: FO.c_object.Free; 1779 stArray: FO.c_array.Free; 1780 end; 1781 inherited; 1782 end; 1783 1784 function TSuperObject.Write(writer: TSuperWriter; indent: boolean; escape: boolean; level: integer): Integer; 1785 function DoEscape(str: PSOChar; len: Integer): Integer; 1786 var 1787 pos, start_offset: Integer; 1788 c: SOChar; 1789 buf: array[0..5] of SOChar; 1790 type 1791 TByteChar = record 1792 case integer of 1793 0: (a, b: Byte); 1794 1: (c: WideChar); 1795 end; 1796 begin 1797 if str = nil then 1798 begin 1799 Result := 0; 1800 exit; 1801 end; 1802 pos := 0; start_offset := 0; 1803 with writer do 1804 while pos < len do 1805 begin 1806 c := str[pos]; 1807 case c of 1808 #8,#9,#10,#12,#13,'"','\','/': 1809 begin 1810 if(pos - start_offset > 0) then 1811 Append(str + start_offset, pos - start_offset); 1812 1813 if(c = #8) then Append(ESC_BS, 2) 1814 else if (c = #9) then Append(ESC_TAB, 2) 1815 else if (c = #10) then Append(ESC_LF, 2) 1816 else if (c = #12) then Append(ESC_FF, 2) 1817 else if (c = #13) then Append(ESC_CR, 2) 1818 else if (c = '"') then Append(ESC_QUOT, 2) 1819 else if (c = '\') then Append(ESC_SL, 2) 1820 else if (c = '/') then Append(ESC_SR, 2); 1821 inc(pos); 1822 start_offset := pos; 1823 end; 1824 else 1825 if (SOIChar(c) > 255) then 1826 begin 1827 if(pos - start_offset > 0) then 1828 Append(str + start_offset, pos - start_offset); 1829 buf[0] := '\'; 1830 buf[1] := 'u'; 1831 buf[2] := super_hex_chars[TByteChar(c).b shr 4]; 1832 buf[3] := super_hex_chars[TByteChar(c).b and $f]; 1833 buf[4] := super_hex_chars[TByteChar(c).a shr 4]; 1834 buf[5] := super_hex_chars[TByteChar(c).a and $f]; 1835 Append(@buf, 6); 1836 inc(pos); 1837 start_offset := pos; 1838 end else 1839 if (c < #32) or (c > #127) then 1840 begin 1841 if(pos - start_offset > 0) then 1842 Append(str + start_offset, pos - start_offset); 1843 buf[0] := '\'; 1844 buf[1] := 'u'; 1845 buf[2] := '0'; 1846 buf[3] := '0'; 1847 buf[4] := super_hex_chars[ord(c) shr 4]; 1848 buf[5] := super_hex_chars[ord(c) and $f]; 1849 Append(buf, 6); 1850 inc(pos); 1851 start_offset := pos; 1852 end else 1853 inc(pos); 1854 end; 1855 end; 1856 if(pos - start_offset > 0) then 1857 writer.Append(str + start_offset, pos - start_offset); 1858 Result := 0; 1859 end; 1860 1861 function DoMinimalEscape(str: PSOChar; len: Integer): Integer; 1862 var 1863 pos, start_offset: Integer; 1864 c: SOChar; 1865 type 1866 TByteChar = record 1867 case integer of 1868 0: (a, b: Byte); 1869 1: (c: WideChar); 1870 end; 1871 begin 1872 if str = nil then 1873 begin 1874 Result := 0; 1875 exit; 1876 end; 1877 pos := 0; start_offset := 0; 1878 with writer do 1879 while pos < len do 1880 begin 1881 c := str[pos]; 1882 case c of 1883 #0: 1884 begin 1885 if(pos - start_offset > 0) then 1886 Append(str + start_offset, pos - start_offset); 1887 Append(ESC_ZERO, 6); 1888 inc(pos); 1889 start_offset := pos; 1890 end; 1891 '"': 1892 begin 1893 if(pos - start_offset > 0) then 1894 Append(str + start_offset, pos - start_offset); 1895 Append(ESC_QUOT, 2); 1896 inc(pos); 1897 start_offset := pos; 1898 end; 1899 '\': 1900 begin 1901 if(pos - start_offset > 0) then 1902 Append(str + start_offset, pos - start_offset); 1903 Append(ESC_SL, 2); 1904 inc(pos); 1905 start_offset := pos; 1906 end; 1907 '/': 1908 begin 1909 if(pos - start_offset > 0) then 1910 Append(str + start_offset, pos - start_offset); 1911 Append(ESC_SR, 2); 1912 inc(pos); 1913 start_offset := pos; 1914 end; 1915 else 1916 inc(pos); 1917 end; 1918 end; 1919 if(pos - start_offset > 0) then 1920 writer.Append(str + start_offset, pos - start_offset); 1921 Result := 0; 1922 end; 1923 1924 1925 procedure _indent(i: shortint; r: boolean); 1926 begin 1927 inc(level, i); 1928 if r then 1929 with writer do 1930 begin 1931 {$IFDEF MSWINDOWS} 1932 Append(TOK_CRLF, 2); 1933 {$ELSE} 1934 Append(TOK_LF, 1); 1935 {$ENDIF} 1936 for i := 0 to level - 1 do 1937 Append(TOK_SP, 1); 1938 end; 1939 end; 1940 var 1941 k,j: Integer; 1942 iter: TSuperObjectIter; 1943 st: AnsiString; 1944 val: ISuperObject; 1945 fbuffer: array[0..31] of AnsiChar; 1946 const 1947 ENDSTR_A: PSOChar = '": '; 1948 ENDSTR_B: PSOChar = '":'; 1949 begin 1950 1951 if FProcessing then 1952 begin 1953 Result := writer.Append(TOK_NULL, 4); 1954 Exit; 1955 end; 1956 1957 FProcessing := true; 1958 with writer do 1959 try 1960 case FDataType of 1961 stObject: 1962 if FO.c_object.FCount > 0 then 1963 begin 1964 k := 0; 1965 Append(TOK_CBL, 1); 1966 if indent then _indent(1, false); 1967 if ObjectFindFirst(Self, iter) then 1968 repeat 1969 {$IFDEF SUPER_METHOD} 1970 if (iter.val = nil) or not ObjectIsType(iter.val, stMethod) then 1971 begin 1972 {$ENDIF} 1973 if (iter.val = nil) or (not iter.val.Processing) then 1974 begin 1975 if(k <> 0) then 1976 Append(TOK_COM, 1); 1977 if indent then _indent(0, true); 1978 Append(TOK_DQT, 1); 1979 if escape then 1980 doEscape(PSOChar(iter.key), Length(iter.key)) else 1981 DoMinimalEscape(PSOChar(iter.key), Length(iter.key)); 1982 if indent then 1983 Append(ENDSTR_A, 3) else 1984 Append(ENDSTR_B, 2); 1985 if(iter.val = nil) then 1986 Append(TOK_NULL, 4) else 1987 iter.val.write(writer, indent, escape, level); 1988 inc(k); 1989 end; 1990 {$IFDEF SUPER_METHOD} 1991 end; 1992 {$ENDIF} 1993 until not ObjectFindNext(iter); 1994 ObjectFindClose(iter); 1995 if indent then _indent(-1, true); 1996 Result := Append(TOK_CBR, 1); 1997 end else 1998 Result := Append(TOK_OBJ, 2); 1999 stBoolean: 2000 begin 2001 if (FO.c_boolean) then 2002 Result := Append(TOK_TRUE, 4) else 2003 Result := Append(TOK_FALSE, 5); 2004 end; 2005 stInt: 2006 begin 2007 str(FO.c_int, st); 2008 Result := Append(PSOChar(SOString(st))); 2009 end; 2010 stDouble: 2011 Result := Append(PSOChar(SOString(gcvt(FO.c_double, 15, fbuffer)))); 2012 stCurrency: 2013 begin 2014 Result := Append(PSOChar(CurrToStr(FO.c_currency))); 2015 end; 2016 stString: 2017 begin 2018 Append(TOK_DQT, 1); 2019 if escape then 2020 doEscape(PSOChar(FOString), Length(FOString)) else 2021 DoMinimalEscape(PSOChar(FOString), Length(FOString)); 2022 Append(TOK_DQT, 1); 2023 Result := 0; 2024 end; 2025 stArray: 2026 if FO.c_array.FLength > 0 then 2027 begin 2028 Append(TOK_ARL, 1); 2029 if indent then _indent(1, true); 2030 k := 0; 2031 j := 0; 2032 while k < FO.c_array.FLength do 2033 begin 2034 2035 val := FO.c_array.GetO(k); 2036 {$IFDEF SUPER_METHOD} 2037 if not ObjectIsType(val, stMethod) then 2038 begin 2039 {$ENDIF} 2040 if (val = nil) or (not val.Processing) then 2041 begin 2042 if (j <> 0) then 2043 Append(TOK_COM, 1); 2044 if(val = nil) then 2045 Append(TOK_NULL, 4) else 2046 val.write(writer, indent, escape, level); 2047 inc(j); 2048 end; 2049 {$IFDEF SUPER_METHOD} 2050 end; 2051 {$ENDIF} 2052 inc(k); 2053 end; 2054 if indent then _indent(-1, false); 2055 Result := Append(TOK_ARR, 1); 2056 end else 2057 Result := Append(TOK_ARRAY, 2); 2058 stNull: 2059 Result := Append(TOK_NULL, 4); 2060 else 2061 Result := 0; 2062 end; 2063 finally 2064 FProcessing := false; 2065 end; 2066 end; 2067 2068 function TSuperObject.IsType(AType: TSuperType): boolean; 2069 begin 2070 Result := AType = FDataType; 2071 end; 2072 2073 function TSuperObject.AsBoolean: boolean; 2074 begin 2075 case FDataType of 2076 stBoolean: Result := FO.c_boolean; 2077 stInt: Result := (FO.c_int <> 0); 2078 stDouble: Result := (FO.c_double <> 0); 2079 stCurrency: Result := (FO.c_currency <> 0); 2080 stString: Result := (Length(FOString) <> 0); 2081 stNull: Result := False; 2082 else 2083 Result := True; 2084 end; 2085 end; 2086 2087 function TSuperObject.AsInteger: SuperInt; 2088 var 2089 code: integer; 2090 cint: SuperInt; 2091 begin 2092 case FDataType of 2093 stInt: Result := FO.c_int; 2094 stDouble: Result := round(FO.c_double); 2095 stCurrency: Result := round(FO.c_currency); 2096 stBoolean: Result := ord(FO.c_boolean); 2097 stString: 2098 begin 2099 Val(FOString, cint, code); 2100 if code = 0 then 2101 Result := cint else 2102 Result := 0; 2103 end; 2104 else 2105 Result := 0; 2106 end; 2107 end; 2108 2109 function TSuperObject.AsDouble: Double; 2110 var 2111 code: integer; 2112 cdouble: double; 2113 begin 2114 case FDataType of 2115 stDouble: Result := FO.c_double; 2116 stCurrency: Result := FO.c_currency; 2117 stInt: Result := FO.c_int; 2118 stBoolean: Result := ord(FO.c_boolean); 2119 stString: 2120 begin 2121 Val(FOString, cdouble, code); 2122 if code = 0 then 2123 Result := cdouble else 2124 Result := 0.0; 2125 end; 2126 else 2127 Result := 0.0; 2128 end; 2129 end; 2130 2131 function TSuperObject.AsCurrency: Currency; 2132 var 2133 code: integer; 2134 cdouble: double; 2135 begin 2136 case FDataType of 2137 stDouble: Result := FO.c_double; 2138 stCurrency: Result := FO.c_currency; 2139 stInt: Result := FO.c_int; 2140 stBoolean: Result := ord(FO.c_boolean); 2141 stString: 2142 begin 2143 Val(FOString, cdouble, code); 2144 if code = 0 then 2145 Result := cdouble else 2146 Result := 0.0; 2147 end; 2148 else 2149 Result := 0.0; 2150 end; 2151 end; 2152 2153 function TSuperObject.AsString: SOString; 2154 begin 2155 if FDataType = stString then 2156 Result := FOString else 2157 Result := AsJSon(false, false); 2158 end; 2159 2160 function TSuperObject.GetEnumerator: TSuperEnumerator; 2161 begin 2162 Result := TSuperEnumerator.Create(Self); 2163 end; 2164 2165 procedure TSuperObject.AfterConstruction; 2166 begin 2167 InterlockedDecrement(FRefCount); 2168 end; 2169 2170 procedure TSuperObject.BeforeDestruction; 2171 begin 2172 if RefCount <> 0 then 2173 raise Exception.Create('Invalid pointer'); 2174 end; 2175 2176 function TSuperObject.AsArray: TSuperArray; 2177 begin 2178 if FDataType = stArray then 2179 Result := FO.c_array else 2180 Result := nil; 2181 end; 2182 2183 function TSuperObject.AsObject: TSuperTableString; 2184 begin 2185 if FDataType = stObject then 2186 Result := FO.c_object else 2187 Result := nil; 2188 end; 2189 2190 function TSuperObject.AsJSon(indent, escape: boolean): SOString; 2191 var 2192 pb: TSuperWriterString; 2193 begin 2194 pb := TSuperWriterString.Create; 2195 try 2196 if(Write(pb, indent, escape, 0) < 0) then 2197 begin 2198 Result := ''; 2199 Exit; 2200 end; 2201 if pb.FBPos > 0 then 2202 Result := pb.FBuf else 2203 Result := ''; 2204 finally 2205 pb.Free; 2206 end; 2207 end; 2208 2209 class function TSuperObject.ParseString(s: PSOChar; strict: Boolean; partial: boolean; const this: ISuperObject; 2210 options: TSuperFindOptions; const put: ISuperObject; dt: TSuperType): ISuperObject; 2211 var 2212 tok: TSuperTokenizer; 2213 obj: ISuperObject; 2214 begin 2215 tok := TSuperTokenizer.Create; 2216 obj := ParseEx(tok, s, -1, strict, this, options, put, dt); 2217 if(tok.err <> teSuccess) or (not partial and (s[tok.char_offset] <> #0)) then 2218 Result := nil else 2219 Result := obj; 2220 tok.Free; 2221 end; 2222 2223 class function TSuperObject.ParseStream(stream: TStream; strict: Boolean; 2224 partial: boolean; const this: ISuperObject; options: TSuperFindOptions; 2225 const put: ISuperObject; dt: TSuperType): ISuperObject; 2226 const 2227 BUFFER_SIZE = 1024; 2228 var 2229 tok: TSuperTokenizer; 2230 buffera: array[0..BUFFER_SIZE-1] of AnsiChar; 2231 bufferw: array[0..BUFFER_SIZE-1] of SOChar; 2232 bom: array[0..1] of byte; 2233 unicode: boolean; 2234 j, size: Integer; 2235 st: string; 2236 begin 2237 st := ''; 2238 tok := TSuperTokenizer.Create; 2239 2240 if (stream.Read(bom, sizeof(bom)) = 2) and (bom[0] = $FF) and (bom[1] = $FE) then 2241 begin 2242 unicode := true; 2243 size := stream.Read(bufferw, BUFFER_SIZE * SizeOf(SoChar)) div SizeOf(SoChar); 2244 end else 2245 begin 2246 unicode := false; 2247 stream.Seek(0, soFromBeginning); 2248 size := stream.Read(buffera, BUFFER_SIZE); 2249 end; 2250 2251 while size > 0 do 2252 begin 2253 if not unicode then 2254 for j := 0 to size - 1 do 2255 bufferw[j] := SOChar(buffera[j]); 2256 ParseEx(tok, bufferw, size, strict, this, options, put, dt); 2257 2258 if tok.err = teContinue then 2259 begin 2260 if not unicode then 2261 size := stream.Read(buffera, BUFFER_SIZE) else 2262 size := stream.Read(bufferw, BUFFER_SIZE * SizeOf(SoChar)) div SizeOf(SoChar); 2263 end else 2264 Break; 2265 end; 2266 if(tok.err <> teSuccess) or (not partial and (st[tok.char_offset] <> #0)) then 2267 Result := nil else 2268 Result := tok.stack[tok.depth].current; 2269 tok.Free; 2270 end; 2271 2272 class function TSuperObject.ParseFile(const FileName: string; strict: Boolean; 2273 partial: boolean; const this: ISuperObject; options: TSuperFindOptions; 2274 const put: ISuperObject; dt: TSuperType): ISuperObject; 2275 var 2276 stream: TFileStream; 2277 begin 2278 stream := TFileStream.Create(FileName, fmOpenRead, fmShareDenyWrite); 2279 try 2280 Result := ParseStream(stream, strict, partial, this, options, put, dt); 2281 finally 2282 stream.Free; 2283 end; 2284 end; 2285 2286 class function TSuperObject.ParseEx(tok: TSuperTokenizer; str: PSOChar; len: integer; 2287 strict: Boolean; const this: ISuperObject; options: TSuperFindOptions; const put: ISuperObject; dt: TSuperType): ISuperObject; 2288 2289 const 2290 spaces = [#32,#8,#9,#10,#12,#13]; 2291 delimiters = ['"', '.', '[', ']', '{', '}', '(', ')', ',', ':', #0]; 2292 reserved = delimiters + spaces; 2293 path = ['a'..'z', 'A'..'Z', '.', '_']; 2294 2295 function hexdigit(x: SOChar): byte; 2296 begin 2297 if x <= '9' then 2298 Result := byte(x) - byte('0') else 2299 Result := (byte(x) and 7) + 9; 2300 end; 2301 function min(v1, v2: integer): integer; begin if v1 < v2 then result := v1 else result := v2 end; 2302 2303 var 2304 obj: ISuperObject; 2305 v: SOChar; 2306 {$IFDEF SUPER_METHOD} 2307 sm: TSuperMethod; 2308 {$ENDIF} 2309 numi: SuperInt; 2310 numd: Double; 2311 code: integer; 2312 TokRec: PSuperTokenerSrec; 2313 evalstack: integer; 2314 p: PSOChar; 2315 2316 function IsEndDelimiter(v: AnsiChar): Boolean; 2317 begin 2318 if tok.depth > 0 then 2319 case tok.stack[tok.depth - 1].state of 2320 tsArrayAdd: Result := v in [',', ']', #0]; 2321 tsObjectValueAdd: Result := v in [',', '}', #0]; 2322 else 2323 Result := v = #0; 2324 end else 2325 Result := v = #0; 2326 end; 2327 2328 label out, redo_char; 2329 begin 2330 evalstack := 0; 2331 obj := nil; 2332 Result := nil; 2333 TokRec := @tok.stack[tok.depth]; 2334 2335 tok.char_offset := 0; 2336 tok.err := teSuccess; 2337 2338 repeat 2339 if (tok.char_offset = len) then 2340 begin 2341 if (tok.depth = 0) and (TokRec^.state = tsEatws) and 2342 (TokRec^.saved_state = tsFinish) then 2343 tok.err := teSuccess else 2344 tok.err := teContinue; 2345 goto out; 2346 end; 2347 2348 v := str^; 2349 2350 case v of 2351 #10: 2352 begin 2353 inc(tok.line); 2354 tok.col := 0; 2355 end; 2356 #9: inc(tok.col, 4); 2357 else 2358 inc(tok.col); 2359 end; 2360 2361 redo_char: 2362 case TokRec^.state of 2363 tsEatws: 2364 begin 2365 if (SOIChar(v) < 256) and (AnsiChar(v) in spaces) then {nop} else 2366 if (v = '/') then 2367 begin 2368 tok.pb.Reset; 2369 tok.pb.Append(@v, 1); 2370 TokRec^.state := tsCommentStart; 2371 end else begin 2372 TokRec^.state := TokRec^.saved_state; 2373 goto redo_char; 2374 end 2375 end; 2376 2377 tsStart: 2378 case v of 2379 '"', 2380 '''': 2381 begin 2382 TokRec^.state := tsString; 2383 tok.pb.Reset; 2384 tok.quote_char := v; 2385 end; 2386 '-': 2387 begin 2388 TokRec^.state := tsNumber; 2389 tok.pb.Reset; 2390 tok.is_double := 0; 2391 tok.floatcount := -1; 2392 goto redo_char; 2393 end; 2394 2395 '0'..'9': 2396 begin 2397 if (tok.depth = 0) then 2398 case ObjectGetType(this) of 2399 stObject: 2400 begin 2401 TokRec^.state := tsIdentifier; 2402 TokRec^.current := this; 2403 goto redo_char; 2404 end; 2405 end; 2406 TokRec^.state := tsNumber; 2407 tok.pb.Reset; 2408 tok.is_double := 0; 2409 tok.floatcount := -1; 2410 goto redo_char; 2411 end; 2412 '{': 2413 begin 2414 TokRec^.state := tsEatws; 2415 TokRec^.saved_state := tsObjectFieldStart; 2416 TokRec^.current := TSuperObject.Create(stObject); 2417 end; 2418 '[': 2419 begin 2420 TokRec^.state := tsEatws; 2421 TokRec^.saved_state := tsArray; 2422 TokRec^.current := TSuperObject.Create(stArray); 2423 end; 2424 {$IFDEF SUPER_METHOD} 2425 '(': 2426 begin 2427 if (tok.depth = 0) and ObjectIsType(this, stMethod) then 2428 begin 2429 TokRec^.current := this; 2430 TokRec^.state := tsParamValue; 2431 end; 2432 end; 2433 {$ENDIF} 2434 'N', 2435 'n': 2436 begin 2437 TokRec^.state := tsNull; 2438 tok.pb.Reset; 2439 tok.st_pos := 0; 2440 goto redo_char; 2441 end; 2442 'T', 2443 't', 2444 'F', 2445 'f': 2446 begin 2447 TokRec^.state := tsBoolean; 2448 tok.pb.Reset; 2449 tok.st_pos := 0; 2450 goto redo_char; 2451 end; 2452 else 2453 TokRec^.state := tsIdentifier; 2454 tok.pb.Reset; 2455 goto redo_char; 2456 end; 2457 2458 tsFinish: 2459 begin 2460 if(tok.depth = 0) then goto out; 2461 obj := TokRec^.current; 2462 tok.ResetLevel(tok.depth); 2463 dec(tok.depth); 2464 TokRec := @tok.stack[tok.depth]; 2465 goto redo_char; 2466 end; 2467 2468 tsNull: 2469 begin 2470 tok.pb.Append(@v, 1); 2471 if (StrLComp(TOK_NULL, PSOChar(tok.pb.FBuf), min(tok.st_pos + 1, 4)) = 0) then 2472 begin 2473 if (tok.st_pos = 4) then 2474 if (((SOIChar(v) < 256) and (AnsiChar(v) in path)) or (SOIChar(v) >= 256)) then 2475 TokRec^.state := tsIdentifier else 2476 begin 2477 TokRec^.current := TSuperObject.Create(stNull); 2478 TokRec^.saved_state := tsFinish; 2479 TokRec^.state := tsEatws; 2480 goto redo_char; 2481 end; 2482 end else 2483 begin 2484 TokRec^.state := tsIdentifier; 2485 tok.pb.FBuf[tok.st_pos] := #0; 2486 dec(tok.pb.FBPos); 2487 goto redo_char; 2488 end; 2489 inc(tok.st_pos); 2490 end; 2491 2492 tsCommentStart: 2493 begin 2494 if(v = '*') then 2495 begin 2496 TokRec^.state := tsComment; 2497 end else 2498 if (v = '/') then 2499 begin 2500 TokRec^.state := tsCommentEol; 2501 end else 2502 begin 2503 tok.err := teParseComment; 2504 goto out; 2505 end; 2506 tok.pb.Append(@v, 1); 2507 end; 2508 2509 tsComment: 2510 begin 2511 if(v = '*') then 2512 TokRec^.state := tsCommentEnd; 2513 tok.pb.Append(@v, 1); 2514 end; 2515 2516 tsCommentEol: 2517 begin 2518 if (v = #10) then 2519 TokRec^.state := tsEatws else 2520 tok.pb.Append(@v, 1); 2521 end; 2522 2523 tsCommentEnd: 2524 begin 2525 tok.pb.Append(@v, 1); 2526 if (v = '/') then 2527 TokRec^.state := tsEatws else 2528 TokRec^.state := tsComment; 2529 end; 2530 2531 tsString: 2532 begin 2533 if (v = tok.quote_char) then 2534 begin 2535 TokRec^.current := TSuperObject.Create(SOString(tok.pb.GetString)); 2536 TokRec^.saved_state := tsFinish; 2537 TokRec^.state := tsEatws; 2538 end else 2539 if (v = '\') then 2540 begin 2541 TokRec^.saved_state := tsString; 2542 TokRec^.state := tsStringEscape; 2543 end else 2544 begin 2545 tok.pb.Append(@v, 1); 2546 end 2547 end; 2548 2549 tsEvalProperty: 2550 begin 2551 if (TokRec^.current = nil) and (foCreatePath in options) then 2552 begin 2553 TokRec^.current := TSuperObject.Create(stObject); 2554 TokRec^.parent.AsObject.PutO(tok.pb.Fbuf, TokRec^.current) 2555 end else 2556 if not ObjectIsType(TokRec^.current, stObject) then 2557 begin 2558 tok.err := teEvalObject; 2559 goto out; 2560 end; 2561 tok.pb.Reset; 2562 TokRec^.state := tsIdentifier; 2563 goto redo_char; 2564 end; 2565 2566 tsEvalArray: 2567 begin 2568 if (TokRec^.current = nil) and (foCreatePath in options) then 2569 begin 2570 TokRec^.current := TSuperObject.Create(stArray); 2571 TokRec^.parent.AsObject.PutO(tok.pb.Fbuf, TokRec^.current) 2572 end else 2573 if not ObjectIsType(TokRec^.current, stArray) then 2574 begin 2575 tok.err := teEvalArray; 2576 goto out; 2577 end; 2578 tok.pb.Reset; 2579 TokRec^.state := tsParamValue; 2580 goto redo_char; 2581 end; 2582 {$IFDEF SUPER_METHOD} 2583 tsEvalMethod: 2584 begin 2585 if ObjectIsType(TokRec^.current, stMethod) and assigned(TokRec^.current.AsMethod) then 2586 begin 2587 tok.pb.Reset; 2588 TokRec^.obj := TSuperObject.Create(stArray); 2589 TokRec^.state := tsMethodValue; 2590 goto redo_char; 2591 end else 2592 begin 2593 tok.err := teEvalMethod; 2594 goto out; 2595 end; 2596 end; 2597 2598 tsMethodValue: 2599 begin 2600 case v of 2601 ')': 2602 TokRec^.state := tsIdentifier; 2603 else 2604 if (tok.depth >= SUPER_TOKENER_MAX_DEPTH-1) then 2605 begin 2606 tok.err := teDepth; 2607 goto out; 2608 end; 2609 inc(evalstack); 2610 TokRec^.state := tsMethodPut; 2611 inc(tok.depth); 2612 tok.ResetLevel(tok.depth); 2613 TokRec := @tok.stack[tok.depth]; 2614 goto redo_char; 2615 end; 2616 end; 2617 2618 tsMethodPut: 2619 begin 2620 TokRec^.obj.AsArray.Add(obj); 2621 case v of 2622 ',': 2623 begin 2624 tok.pb.Reset; 2625 TokRec^.saved_state := tsMethodValue; 2626 TokRec^.state := tsEatws; 2627 end; 2628 ')': 2629 begin 2630 if TokRec^.obj.AsArray.Length = 1 then 2631 TokRec^.obj := TokRec^.obj.AsArray.GetO(0); 2632 dec(evalstack); 2633 tok.pb.Reset; 2634 TokRec^.saved_state := tsIdentifier; 2635 TokRec^.state := tsEatws; 2636 end; 2637 else 2638 tok.err := teEvalMethod; 2639 goto out; 2640 end; 2641 end; 2642 {$ENDIF} 2643 tsParamValue: 2644 begin 2645 case v of 2646 ']': 2647 TokRec^.state := tsIdentifier; 2648 else 2649 if (tok.depth >= SUPER_TOKENER_MAX_DEPTH-1) then 2650 begin 2651 tok.err := teDepth; 2652 goto out; 2653 end; 2654 inc(evalstack); 2655 TokRec^.state := tsParamPut; 2656 inc(tok.depth); 2657 tok.ResetLevel(tok.depth); 2658 TokRec := @tok.stack[tok.depth]; 2659 goto redo_char; 2660 end; 2661 end; 2662 2663 tsParamPut: 2664 begin 2665 dec(evalstack); 2666 TokRec^.obj := obj; 2667 tok.pb.Reset; 2668 TokRec^.saved_state := tsIdentifier; 2669 TokRec^.state := tsEatws; 2670 if v <> ']' then 2671 begin 2672 tok.err := teEvalArray; 2673 goto out; 2674 end; 2675 end; 2676 2677 tsIdentifier: 2678 begin 2679 if (this = nil) then 2680 begin 2681 if (SOIChar(v) < 256) and IsEndDelimiter(AnsiChar(v)) then 2682 begin 2683 if not strict then 2684 begin 2685 tok.pb.TrimRight; 2686 TokRec^.current := TSuperObject.Create(tok.pb.Fbuf); 2687 TokRec^.saved_state := tsFinish; 2688 TokRec^.state := tsEatws; 2689 goto redo_char; 2690 end else 2691 begin 2692 tok.err := teParseString; 2693 goto out; 2694 end; 2695 end else 2696 if (v = '\') then 2697 begin 2698 TokRec^.saved_state := tsIdentifier; 2699 TokRec^.state := tsStringEscape; 2700 end else 2701 tok.pb.Append(@v, 1); 2702 end else 2703 begin 2704 if (SOIChar(v) < 256) and (AnsiChar(v) in reserved) then 2705 begin 2706 TokRec^.gparent := TokRec^.parent; 2707 if TokRec^.current = nil then 2708 TokRec^.parent := this else 2709 TokRec^.parent := TokRec^.current; 2710 2711 case ObjectGetType(TokRec^.parent) of 2712 stObject: 2713 case v of 2714 '.': 2715 begin 2716 TokRec^.state := tsEvalProperty; 2717 if tok.pb.FBPos > 0 then 2718 TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); 2719 end; 2720 '[': 2721 begin 2722 TokRec^.state := tsEvalArray; 2723 if tok.pb.FBPos > 0 then 2724 TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); 2725 end; 2726 '(': 2727 begin 2728 TokRec^.state := tsEvalMethod; 2729 if tok.pb.FBPos > 0 then 2730 TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); 2731 end; 2732 else 2733 if tok.pb.FBPos > 0 then 2734 TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); 2735 if (foPutValue in options) and (evalstack = 0) then 2736 begin 2737 TokRec^.parent.AsObject.PutO(tok.pb.Fbuf, put); 2738 TokRec^.current := put 2739 end else 2740 if (foDelete in options) and (evalstack = 0) then 2741 begin 2742 TokRec^.current := TokRec^.parent.AsObject.Delete(tok.pb.Fbuf); 2743 end else 2744 if (TokRec^.current = nil) and (foCreatePath in options) then 2745 begin 2746 TokRec^.current := TSuperObject.Create(dt); 2747 TokRec^.parent.AsObject.PutO(tok.pb.Fbuf, TokRec^.current); 2748 end; 2749 TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); 2750 TokRec^.state := tsFinish; 2751 goto redo_char; 2752 end; 2753 stArray: 2754 begin 2755 if TokRec^.obj <> nil then 2756 begin 2757 if not ObjectIsType(TokRec^.obj, stInt) or (TokRec^.obj.AsInteger < 0) then 2758 begin 2759 tok.err := teEvalInt; 2760 TokRec^.obj := nil; 2761 goto out; 2762 end; 2763 numi := TokRec^.obj.AsInteger; 2764 TokRec^.obj := nil; 2765 2766 TokRec^.current := TokRec^.parent.AsArray.GetO(numi); 2767 case v of 2768 '.': 2769 if (TokRec^.current = nil) and (foCreatePath in options) then 2770 begin 2771 TokRec^.current := TSuperObject.Create(stObject); 2772 TokRec^.parent.AsArray.PutO(numi, TokRec^.current); 2773 end else 2774 if (TokRec^.current = nil) then 2775 begin 2776 tok.err := teEvalObject; 2777 goto out; 2778 end; 2779 '[': 2780 begin 2781 if (TokRec^.current = nil) and (foCreatePath in options) then 2782 begin 2783 TokRec^.current := TSuperObject.Create(stArray); 2784 TokRec^.parent.AsArray.Add(TokRec^.current); 2785 end else 2786 if (TokRec^.current = nil) then 2787 begin 2788 tok.err := teEvalArray; 2789 goto out; 2790 end; 2791 TokRec^.state := tsEvalArray; 2792 end; 2793 '(': TokRec^.state := tsEvalMethod; 2794 else 2795 if (foPutValue in options) and (evalstack = 0) then 2796 begin 2797 TokRec^.parent.AsArray.PutO(numi, put); 2798 TokRec^.current := put; 2799 end else 2800 if (foDelete in options) and (evalstack = 0) then 2801 begin 2802 TokRec^.current := TokRec^.parent.AsArray.Delete(numi); 2803 end else 2804 TokRec^.current := TokRec^.parent.AsArray.GetO(numi); 2805 TokRec^.state := tsFinish; 2806 goto redo_char 2807 end; 2808 end else 2809 begin 2810 case v of 2811 '.': 2812 begin 2813 if (foPutValue in options) then 2814 begin 2815 TokRec^.current := TSuperObject.Create(stObject); 2816 TokRec^.parent.AsArray.Add(TokRec^.current); 2817 end else 2818 TokRec^.current := TokRec^.parent.AsArray.GetO(TokRec^.parent.AsArray.FLength - 1); 2819 end; 2820 '[': 2821 begin 2822 if (foPutValue in options) then 2823 begin 2824 TokRec^.current := TSuperObject.Create(stArray); 2825 TokRec^.parent.AsArray.Add(TokRec^.current); 2826 end else 2827 TokRec^.current := TokRec^.parent.AsArray.GetO(TokRec^.parent.AsArray.FLength - 1); 2828 TokRec^.state := tsEvalArray; 2829 end; 2830 '(': 2831 begin 2832 if not (foPutValue in options) then 2833 TokRec^.current := TokRec^.parent.AsArray.GetO(TokRec^.parent.AsArray.FLength - 1) else 2834 TokRec^.current := nil; 2835 2836 TokRec^.state := tsEvalMethod; 2837 end; 2838 else 2839 if (foPutValue in options) and (evalstack = 0) then 2840 begin 2841 TokRec^.parent.AsArray.Add(put); 2842 TokRec^.current := put; 2843 end else 2844 if tok.pb.FBPos = 0 then 2845 TokRec^.current := TokRec^.parent.AsArray.GetO(TokRec^.parent.AsArray.FLength - 1); 2846 TokRec^.state := tsFinish; 2847 goto redo_char 2848 end; 2849 end; 2850 end; 2851 {$IFDEF SUPER_METHOD} 2852 stMethod: 2853 case v of 2854 '.': 2855 begin 2856 TokRec^.current := nil; 2857 sm := TokRec^.parent.AsMethod; 2858 sm(TokRec^.gparent, TokRec^.obj, TokRec^.current); 2859 TokRec^.obj := nil; 2860 end; 2861 '[': 2862 begin 2863 TokRec^.current := nil; 2864 sm := TokRec^.parent.AsMethod; 2865 sm(TokRec^.gparent, TokRec^.obj, TokRec^.current); 2866 TokRec^.state := tsEvalArray; 2867 TokRec^.obj := nil; 2868 end; 2869 '(': 2870 begin 2871 TokRec^.current := nil; 2872 sm := TokRec^.parent.AsMethod; 2873 sm(TokRec^.gparent, TokRec^.obj, TokRec^.current); 2874 TokRec^.state := tsEvalMethod; 2875 TokRec^.obj := nil; 2876 end; 2877 else 2878 if not (foPutValue in options) or (evalstack > 0) then 2879 begin 2880 TokRec^.current := nil; 2881 sm := TokRec^.parent.AsMethod; 2882 sm(TokRec^.gparent, TokRec^.obj, TokRec^.current); 2883 TokRec^.obj := nil; 2884 TokRec^.state := tsFinish; 2885 goto redo_char 2886 end else 2887 begin 2888 tok.err := teEvalMethod; 2889 TokRec^.obj := nil; 2890 goto out; 2891 end; 2892 end; 2893 {$ENDIF} 2894 end; 2895 end else 2896 tok.pb.Append(@v, 1); 2897 end; 2898 end; 2899 2900 tsStringEscape: 2901 case v of 2902 'b', 2903 'n', 2904 'r', 2905 't', 2906 'f': 2907 begin 2908 if(v = 'b') then tok.pb.Append(TOK_BS, 1) 2909 else if(v = 'n') then tok.pb.Append(TOK_LF, 1) 2910 else if(v = 'r') then tok.pb.Append(TOK_CR, 1) 2911 else if(v = 't') then tok.pb.Append(TOK_TAB, 1) 2912 else if(v = 'f') then tok.pb.Append(TOK_FF, 1); 2913 TokRec^.state := TokRec^.saved_state; 2914 end; 2915 'u': 2916 begin 2917 tok.ucs_char := 0; 2918 tok.st_pos := 0; 2919 TokRec^.state := tsEscapeUnicode; 2920 end; 2921 'x': 2922 begin 2923 tok.ucs_char := 0; 2924 tok.st_pos := 0; 2925 TokRec^.state := tsEscapeHexadecimal; 2926 end 2927 else 2928 tok.pb.Append(@v, 1); 2929 TokRec^.state := TokRec^.saved_state; 2930 end; 2931 2932 tsEscapeUnicode: 2933 begin 2934 if ((SOIChar(v) < 256) and (AnsiChar(v) in super_hex_chars_set)) then 2935 begin 2936 inc(tok.ucs_char, (Word(hexdigit(v)) shl ((3-tok.st_pos)*4))); 2937 inc(tok.st_pos); 2938 if (tok.st_pos = 4) then 2939 begin 2940 tok.pb.Append(@tok.ucs_char, 1); 2941 TokRec^.state := TokRec^.saved_state; 2942 end 2943 end else 2944 begin 2945 tok.err := teParseString; 2946 goto out; 2947 end 2948 end; 2949 tsEscapeHexadecimal: 2950 begin 2951 if ((SOIChar(v) < 256) and (AnsiChar(v) in super_hex_chars_set)) then 2952 begin 2953 inc(tok.ucs_char, (Word(hexdigit(v)) shl ((1-tok.st_pos)*4))); 2954 inc(tok.st_pos); 2955 if (tok.st_pos = 2) then 2956 begin 2957 tok.pb.Append(@tok.ucs_char, 1); 2958 TokRec^.state := TokRec^.saved_state; 2959 end 2960 end else 2961 begin 2962 tok.err := teParseString; 2963 goto out; 2964 end 2965 end; 2966 tsBoolean: 2967 begin 2968 tok.pb.Append(@v, 1); 2969 if (StrLComp('true', PSOChar(tok.pb.FBuf), min(tok.st_pos + 1, 4)) = 0) then 2970 begin 2971 if (tok.st_pos = 4) then 2972 if (((SOIChar(v) < 256) and (AnsiChar(v) in path)) or (SOIChar(v) >= 256)) then 2973 TokRec^.state := tsIdentifier else 2974 begin 2975 TokRec^.current := TSuperObject.Create(true); 2976 TokRec^.saved_state := tsFinish; 2977 TokRec^.state := tsEatws; 2978 goto redo_char; 2979 end 2980 end else 2981 if (StrLComp('false', PSOChar(tok.pb.FBuf), min(tok.st_pos + 1, 5)) = 0) then 2982 begin 2983 if (tok.st_pos = 5) then 2984 if (((SOIChar(v) < 256) and (AnsiChar(v) in path)) or (SOIChar(v) >= 256)) then 2985 TokRec^.state := tsIdentifier else 2986 begin 2987 TokRec^.current := TSuperObject.Create(false); 2988 TokRec^.saved_state := tsFinish; 2989 TokRec^.state := tsEatws; 2990 goto redo_char; 2991 end 2992 end else 2993 begin 2994 TokRec^.state := tsIdentifier; 2995 tok.pb.FBuf[tok.st_pos] := #0; 2996 dec(tok.pb.FBPos); 2997 goto redo_char; 2998 end; 2999 inc(tok.st_pos); 3000 end; 3001 3002 tsNumber: 3003 begin 3004 if (SOIChar(v) < 256) and (AnsiChar(v) in super_number_chars_set) then 3005 begin 3006 tok.pb.Append(@v, 1); 3007 if (SOIChar(v) < 256) then 3008 case v of 3009 '.': begin 3010 tok.is_double := 1; 3011 tok.floatcount := 0; 3012 end; 3013 'e','E': 3014 begin 3015 tok.is_double := 1; 3016 tok.floatcount := -1; 3017 end; 3018 '0'..'9': 3019 begin 3020 3021 if (tok.is_double = 1) and (tok.floatcount >= 0) then 3022 begin 3023 inc(tok.floatcount); 3024 if tok.floatcount > 4 then 3025 tok.floatcount := -1; 3026 end; 3027 end; 3028 end; 3029 end else 3030 begin 3031 if (tok.is_double = 0) then 3032 begin 3033 val(tok.pb.FBuf, numi, code); 3034 if ObjectIsType(this, stArray) then 3035 begin 3036 if (foPutValue in options) and (evalstack = 0) then 3037 begin 3038 this.AsArray.PutO(numi, put); 3039 TokRec^.current := put; 3040 end else 3041 if (foDelete in options) and (evalstack = 0) then 3042 TokRec^.current := this.AsArray.Delete(numi) else 3043 TokRec^.current := this.AsArray.GetO(numi); 3044 end else 3045 TokRec^.current := TSuperObject.Create(numi); 3046 3047 end else 3048 if (tok.is_double <> 0) then 3049 begin 3050 if tok.floatcount >= 0 then 3051 begin 3052 p := tok.pb.FBuf; 3053 while p^ <> '.' do inc(p); 3054 for code := 0 to tok.floatcount - 1 do 3055 begin 3056 p^ := p[1]; 3057 inc(p); 3058 end; 3059 p^ := #0; 3060 val(tok.pb.FBuf, numi, code); 3061 case tok.floatcount of 3062 0: numi := numi * 10000; 3063 1: numi := numi * 1000; 3064 2: numi := numi * 100; 3065 3: numi := numi * 10; 3066 end; 3067 TokRec^.current := TSuperObject.CreateCurrency(PCurrency(@numi)^); 3068 end else 3069 begin 3070 val(tok.pb.FBuf, numd, code); 3071 TokRec^.current := TSuperObject.Create(numd); 3072 end; 3073 end else 3074 begin 3075 tok.err := teParseNumber; 3076 goto out; 3077 end; 3078 TokRec^.saved_state := tsFinish; 3079 TokRec^.state := tsEatws; 3080 goto redo_char; 3081 end 3082 end; 3083 3084 tsArray: 3085 begin 3086 if (v = ']') then 3087 begin 3088 TokRec^.saved_state := tsFinish; 3089 TokRec^.state := tsEatws; 3090 end else 3091 begin 3092 if(tok.depth >= SUPER_TOKENER_MAX_DEPTH-1) then 3093 begin 3094 tok.err := teDepth; 3095 goto out; 3096 end; 3097 TokRec^.state := tsArrayAdd; 3098 inc(tok.depth); 3099 tok.ResetLevel(tok.depth); 3100 TokRec := @tok.stack[tok.depth]; 3101 goto redo_char; 3102 end 3103 end; 3104 3105 tsArrayAdd: 3106 begin 3107 TokRec^.current.AsArray.Add(obj); 3108 TokRec^.saved_state := tsArraySep; 3109 TokRec^.state := tsEatws; 3110 goto redo_char; 3111 end; 3112 3113 tsArraySep: 3114 begin 3115 if (v = ']') then 3116 begin 3117 TokRec^.saved_state := tsFinish; 3118 TokRec^.state := tsEatws; 3119 end else 3120 if (v = ',') then 3121 begin 3122 TokRec^.saved_state := tsArray; 3123 TokRec^.state := tsEatws; 3124 end else 3125 begin 3126 tok.err := teParseArray; 3127 goto out; 3128 end 3129 end; 3130 3131 tsObjectFieldStart: 3132 begin 3133 if (v = '}') then 3134 begin 3135 TokRec^.saved_state := tsFinish; 3136 TokRec^.state := tsEatws; 3137 end else 3138 if (SOIChar(v) < 256) and (AnsiChar(v) in ['"', '''']) then 3139 begin 3140 tok.quote_char := v; 3141 tok.pb.Reset; 3142 TokRec^.state := tsObjectField; 3143 end else 3144 if not((SOIChar(v) < 256) and ((AnsiChar(v) in reserved) or strict)) then 3145 begin 3146 TokRec^.state := tsObjectUnquotedField; 3147 tok.pb.Reset; 3148 goto redo_char; 3149 end else 3150 begin 3151 tok.err := teParseObjectKeyName; 3152 goto out; 3153 end 3154 end; 3155 3156 tsObjectField: 3157 begin 3158 if (v = tok.quote_char) then 3159 begin 3160 TokRec^.field_name := tok.pb.FBuf; 3161 TokRec^.saved_state := tsObjectFieldEnd; 3162 TokRec^.state := tsEatws; 3163 end else 3164 if (v = '\') then 3165 begin 3166 TokRec^.saved_state := tsObjectField; 3167 TokRec^.state := tsStringEscape; 3168 end else 3169 begin 3170 tok.pb.Append(@v, 1); 3171 end 3172 end; 3173 3174 tsObjectUnquotedField: 3175 begin 3176 if (SOIChar(v) < 256) and (AnsiChar(v) in [':', #0]) then 3177 begin 3178 TokRec^.field_name := tok.pb.FBuf; 3179 TokRec^.saved_state := tsObjectFieldEnd; 3180 TokRec^.state := tsEatws; 3181 goto redo_char; 3182 end else 3183 if (v = '\') then 3184 begin 3185 TokRec^.saved_state := tsObjectUnquotedField; 3186 TokRec^.state := tsStringEscape; 3187 end else 3188 tok.pb.Append(@v, 1); 3189 end; 3190 3191 tsObjectFieldEnd: 3192 begin 3193 if (v = ':') then 3194 begin 3195 TokRec^.saved_state := tsObjectValue; 3196 TokRec^.state := tsEatws; 3197 end else 3198 begin 3199 tok.err := teParseObjectKeySep; 3200 goto out; 3201 end 3202 end; 3203 3204 tsObjectValue: 3205 begin 3206 if (tok.depth >= SUPER_TOKENER_MAX_DEPTH-1) then 3207 begin 3208 tok.err := teDepth; 3209 goto out; 3210 end; 3211 TokRec^.state := tsObjectValueAdd; 3212 inc(tok.depth); 3213 tok.ResetLevel(tok.depth); 3214 TokRec := @tok.stack[tok.depth]; 3215 goto redo_char; 3216 end; 3217 3218 tsObjectValueAdd: 3219 begin 3220 TokRec^.current.AsObject.PutO(TokRec^.field_name, obj); 3221 TokRec^.field_name := ''; 3222 TokRec^.saved_state := tsObjectSep; 3223 TokRec^.state := tsEatws; 3224 goto redo_char; 3225 end; 3226 3227 tsObjectSep: 3228 begin 3229 if (v = '}') then 3230 begin 3231 TokRec^.saved_state := tsFinish; 3232 TokRec^.state := tsEatws; 3233 end else 3234 if (v = ',') then 3235 begin 3236 TokRec^.saved_state := tsObjectFieldStart; 3237 TokRec^.state := tsEatws; 3238 end else 3239 begin 3240 tok.err := teParseObjectValueSep; 3241 goto out; 3242 end 3243 end; 3244 end; 3245 inc(str); 3246 inc(tok.char_offset); 3247 until v = #0; 3248 3249 if(TokRec^.state <> tsFinish) and 3250 (TokRec^.saved_state <> tsFinish) then 3251 tok.err := teParseEof; 3252 3253 out: 3254 if(tok.err in [teSuccess]) then 3255 begin 3256 {$IFDEF SUPER_METHOD} 3257 if (foCallMethod in options) and ObjectIsType(TokRec^.current, stMethod) and assigned(TokRec^.current.AsMethod) then 3258 begin 3259 sm := TokRec^.current.AsMethod; 3260 sm(TokRec^.parent, put, Result); 3261 end else 3262 {$ENDIF} 3263 Result := TokRec^.current; 3264 end else 3265 Result := nil; 3266 end; 3267 3268 procedure TSuperObject.PutO(const path: SOString; const Value: ISuperObject); 3269 begin 3270 ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], Value); 3271 end; 3272 3273 procedure TSuperObject.PutB(const path: SOString; Value: Boolean); 3274 begin 3275 ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); 3276 end; 3277 3278 procedure TSuperObject.PutD(const path: SOString; Value: Double); 3279 begin 3280 ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); 3281 end; 3282 3283 procedure TSuperObject.PutC(const path: SOString; Value: Currency); 3284 begin 3285 ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.CreateCurrency(Value)); 3286 end; 3287 3288 procedure TSuperObject.PutI(const path: SOString; Value: SuperInt); 3289 begin 3290 ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); 3291 end; 3292 3293 procedure TSuperObject.PutS(const path: SOString; const Value: SOString); 3294 begin 3295 ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); 3296 end; 3297 3298 function TSuperObject.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; 3299 begin 3300 if GetInterface(IID, Obj) then 3301 Result := 0 3302 else 3303 Result := E_NOINTERFACE; 3304 end; 3305 3306 function TSuperObject.SaveTo(stream: TStream; indent, escape: boolean): integer; 3307 var 3308 pb: TSuperWriterStream; 3309 begin 3310 if escape then 3311 pb := TSuperAnsiWriterStream.Create(stream) else 3312 pb := TSuperUnicodeWriterStream.Create(stream); 3313 3314 if(Write(pb, indent, escape, 0) < 0) then 3315 begin 3316 pb.Reset; 3317 pb.Free; 3318 Result := 0; 3319 Exit; 3320 end; 3321 Result := stream.Size; 3322 pb.Free; 3323 end; 3324 3325 function TSuperObject.CalcSize(indent, escape: boolean): integer; 3326 var 3327 pb: TSuperWriterFake; 3328 begin 3329 pb := TSuperWriterFake.Create; 3330 if(Write(pb, indent, escape, 0) < 0) then 3331 begin 3332 pb.Free; 3333 Result := 0; 3334 Exit; 3335 end; 3336 Result := pb.FSize; 3337 pb.Free; 3338 end; 3339 3340 function TSuperObject.SaveTo(socket: Integer; indent, escape: boolean): integer; 3341 var 3342 pb: TSuperWriterSock; 3343 begin 3344 pb := TSuperWriterSock.Create(socket); 3345 if(Write(pb, indent, escape, 0) < 0) then 3346 begin 3347 pb.Free; 3348 Result := 0; 3349 Exit; 3350 end; 3351 Result := pb.FSize; 3352 pb.Free; 3353 end; 3354 3355 constructor TSuperObject.Create(const s: SOString); 3356 begin 3357 Create(stString); 3358 FOString := s; 3359 end; 3360 3361 procedure TSuperObject.Clear(all: boolean); 3362 begin 3363 if FProcessing then exit; 3364 FProcessing := true; 3365 try 3366 case FDataType of 3367 stBoolean: FO.c_boolean := false; 3368 stDouble: FO.c_double := 0.0; 3369 stCurrency: FO.c_currency := 0.0; 3370 stInt: FO.c_int := 0; 3371 stObject: FO.c_object.Clear(all); 3372 stArray: FO.c_array.Clear(all); 3373 stString: FOString := ''; 3374 {$IFDEF SUPER_METHOD} 3375 stMethod: FO.c_method := nil; 3376 {$ENDIF} 3377 end; 3378 finally 3379 FProcessing := false; 3380 end; 3381 end; 3382 3383 procedure TSuperObject.Pack(all: boolean = false); 3384 begin 3385 if FProcessing then exit; 3386 FProcessing := true; 3387 try 3388 case FDataType of 3389 stObject: FO.c_object.Pack(all); 3390 stArray: FO.c_array.Pack(all); 3391 end; 3392 finally 3393 FProcessing := false; 3394 end; 3395 end; 3396 3397 function TSuperObject.GetN(const path: SOString): ISuperObject; 3398 begin 3399 Result := ParseString(PSOChar(path), False, true, self); 3400 if Result = nil then 3401 Result := TSuperObject.Create(stNull); 3402 end; 3403 3404 procedure TSuperObject.PutN(const path: SOString; const Value: ISuperObject); 3405 begin 3406 if Value = nil then 3407 ParseString(PSOChar(path), False, True, self, [foCreatePath, foPutValue], TSuperObject.Create(stNull)) else 3408 ParseString(PSOChar(path), False, True, self, [foCreatePath, foPutValue], Value); 3409 end; 3410 3411 function TSuperObject.Delete(const path: SOString): ISuperObject; 3412 begin 3413 Result := ParseString(PSOChar(path), False, true, self, [foDelete]); 3414 end; 3415 3416 function TSuperObject.Clone: ISuperObject; 3417 var 3418 ite: TSuperObjectIter; 3419 arr: TSuperArray; 3420 j: integer; 3421 begin 3422 case FDataType of 3423 stBoolean: Result := TSuperObject.Create(FO.c_boolean); 3424 stDouble: Result := TSuperObject.Create(FO.c_double); 3425 stCurrency: Result := TSuperObject.CreateCurrency(FO.c_currency); 3426 stInt: Result := TSuperObject.Create(FO.c_int); 3427 stString: Result := TSuperObject.Create(FOString); 3428 {$IFDEF SUPER_METHOD} 3429 stMethod: Result := TSuperObject.Create(FO.c_method); 3430 {$ENDIF} 3431 stObject: 3432 begin 3433 Result := TSuperObject.Create(stObject); 3434 if ObjectFindFirst(self, ite) then 3435 with Result.AsObject do 3436 repeat 3437 PutO(ite.key, ite.val.Clone); 3438 until not ObjectFindNext(ite); 3439 ObjectFindClose(ite); 3440 end; 3441 stArray: 3442 begin 3443 Result := TSuperObject.Create(stArray); 3444 arr := AsArray; 3445 with Result.AsArray do 3446 for j := 0 to arr.Length - 1 do 3447 Add(arr.GetO(j).Clone); 3448 end; 3449 else 3450 Result := nil; 3451 end; 3452 end; 3453 3454 procedure TSuperObject.Merge(const obj: ISuperObject; reference: boolean); 3455 var 3456 prop1, prop2: ISuperObject; 3457 ite: TSuperObjectIter; 3458 arr: TSuperArray; 3459 j: integer; 3460 begin 3461 if ObjectIsType(obj, FDataType) then 3462 case FDataType of 3463 stBoolean: FO.c_boolean := obj.AsBoolean; 3464 stDouble: FO.c_double := obj.AsDouble; 3465 stCurrency: FO.c_currency := obj.AsCurrency; 3466 stInt: FO.c_int := obj.AsInteger; 3467 stString: FOString := obj.AsString; 3468 {$IFDEF SUPER_METHOD} 3469 stMethod: FO.c_method := obj.AsMethod; 3470 {$ENDIF} 3471 stObject: 3472 begin 3473 if ObjectFindFirst(obj, ite) then 3474 with FO.c_object do 3475 repeat 3476 prop1 := FO.c_object.GetO(ite.key); 3477 if (prop1 <> nil) and (ite.val <> nil) and (prop1.DataType = ite.val.DataType) then 3478 prop1.Merge(ite.val) else 3479 if reference then 3480 PutO(ite.key, ite.val) else 3481 PutO(ite.key, ite.val.Clone); 3482 until not ObjectFindNext(ite); 3483 ObjectFindClose(ite); 3484 end; 3485 stArray: 3486 begin 3487 arr := obj.AsArray; 3488 with FO.c_array do 3489 for j := 0 to arr.Length - 1 do 3490 begin 3491 prop1 := GetO(j); 3492 prop2 := arr.GetO(j); 3493 if (prop1 <> nil) and (prop2 <> nil) and (prop1.DataType = prop2.DataType) then 3494 prop1.Merge(prop2) else 3495 if reference then 3496 PutO(j, prop2) else 3497 PutO(j, prop2.Clone); 3498 end; 3499 end; 3500 end; 3501 end; 3502 3503 procedure TSuperObject.Merge(const str: SOString); 3504 begin 3505 Merge(TSuperObject.ParseString(PSOChar(str), False), true); 3506 end; 3507 3508 class function TSuperObject.NewInstance: TObject; 3509 begin 3510 Result := inherited NewInstance; 3511 TSuperObject(Result).FRefCount := 1; 3512 end; 3513 3514 function TSuperObject.ForcePath(const path: SOString; dataType: TSuperType = stObject): ISuperObject; 3515 begin 3516 Result := ParseString(PSOChar(path), False, True, Self, [foCreatePath], nil, dataType); 3517 end; 3518 3519 function TSuperObject.Format(const str: SOString; BeginSep: SOChar; EndSep: SOChar): SOString; 3520 var 3521 p1, p2: PSOChar; 3522 begin 3523 Result := ''; 3524 p2 := PSOChar(str); 3525 p1 := p2; 3526 while true do 3527 if p2^ = BeginSep then 3528 begin 3529 if p2 > p1 then 3530 Result := Result + Copy(p1, 0, p2-p1); 3531 inc(p2); 3532 p1 := p2; 3533 while true do 3534 if p2^ = EndSep then Break else 3535 if p2^ = #0 then Exit else 3536 inc(p2); 3537 Result := Result + GetS(copy(p1, 0, p2-p1)); 3538 inc(p2); 3539 p1 := p2; 3540 end 3541 else if p2^ = #0 then 3542 begin 3543 if p2 > p1 then 3544 Result := Result + Copy(p1, 0, p2-p1); 3545 Break; 3546 end else 3547 inc(p2); 3548 end; 3549 3550 function TSuperObject.GetO(const path: SOString): ISuperObject; 3551 begin 3552 Result := ParseString(PSOChar(path), False, True, Self); 3553 end; 3554 3555 function TSuperObject.GetA(const path: SOString): TSuperArray; 3556 var 3557 obj: ISuperObject; 3558 begin 3559 obj := ParseString(PSOChar(path), False, True, Self); 3560 if obj <> nil then 3561 Result := obj.AsArray else 3562 Result := nil; 3563 end; 3564 3565 function TSuperObject.GetB(const path: SOString): Boolean; 3566 var 3567 obj: ISuperObject; 3568 begin 3569 obj := GetO(path); 3570 if obj <> nil then 3571 Result := obj.AsBoolean else 3572 Result := false; 3573 end; 3574 3575 function TSuperObject.GetD(const path: SOString): Double; 3576 var 3577 obj: ISuperObject; 3578 begin 3579 obj := GetO(path); 3580 if obj <> nil then 3581 Result := obj.AsDouble else 3582 Result := 0.0; 3583 end; 3584 3585 function TSuperObject.GetC(const path: SOString): Currency; 3586 var 3587 obj: ISuperObject; 3588 begin 3589 obj := GetO(path); 3590 if obj <> nil then 3591 Result := obj.AsCurrency else 3592 Result := 0.0; 3593 end; 3594 3595 function TSuperObject.GetI(const path: SOString): SuperInt; 3596 var 3597 obj: ISuperObject; 3598 begin 3599 obj := GetO(path); 3600 if obj <> nil then 3601 Result := obj.AsInteger else 3602 Result := 0; 3603 end; 3604 3605 function TSuperObject.GetDataPtr: Pointer; 3606 begin 3607 Result := FDataPtr; 3608 end; 3609 3610 function TSuperObject.GetDataType: TSuperType; 3611 begin 3612 Result := FDataType 3613 end; 3614 3615 function TSuperObject.GetS(const path: SOString): SOString; 3616 var 3617 obj: ISuperObject; 3618 begin 3619 obj := GetO(path); 3620 if obj <> nil then 3621 Result := obj.AsString else 3622 Result := ''; 3623 end; 3624 3625 function TSuperObject.SaveTo(const FileName: string; indent, escape: boolean): integer; 3626 var 3627 stream: TFileStream; 3628 begin 3629 stream := TFileStream.Create(FileName, fmCreate); 3630 try 3631 Result := SaveTo(stream, indent, escape); 3632 finally 3633 stream.Free; 3634 end; 3635 end; 3636 3637 function TSuperObject.Validate(const rules: SOString; const defs: SOString = ''; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; 3638 begin 3639 Result := Validate(TSuperObject.ParseString(PSOChar(rules), False), TSuperObject.ParseString(PSOChar(defs), False), callback, sender); 3640 end; 3641 3642 function TSuperObject.Validate(const rules: ISuperObject; const defs: ISuperObject = nil; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; 3643 type 3644 TDataType = (dtUnknown, dtStr, dtInt, dtFloat, dtNumber, dtText, dtBool, 3645 dtMap, dtSeq, dtScalar, dtAny); 3646 var 3647 datatypes: ISuperObject; 3648 names: ISuperObject; 3649 3650 function FindInheritedProperty(const prop: PSOChar; p: ISuperObject): ISuperObject; 3651 var 3652 o: ISuperObject; 3653 e: TSuperAvlEntry; 3654 begin 3655 o := p[prop]; 3656 if o <> nil then 3657 result := o else 3658 begin 3659 o := p['inherit']; 3660 if (o <> nil) and ObjectIsType(o, stString) then 3661 begin 3662 e := names.AsObject.Search(o.AsString); 3663 if (e <> nil) then 3664 Result := FindInheritedProperty(prop, e.Value) else 3665 Result := nil; 3666 end else 3667 Result := nil; 3668 end; 3669 end; 3670 3671 function FindDataType(o: ISuperObject): TDataType; 3672 var 3673 e: TSuperAvlEntry; 3674 obj: ISuperObject; 3675 begin 3676 obj := FindInheritedProperty('type', o); 3677 if obj <> nil then 3678 begin 3679 e := datatypes.AsObject.Search(obj.AsString); 3680 if e <> nil then 3681 Result := TDataType(e.Value.AsInteger) else 3682 Result := dtUnknown; 3683 end else 3684 Result := dtUnknown; 3685 end; 3686 3687 procedure GetNames(o: ISuperObject); 3688 var 3689 obj: ISuperObject; 3690 f: TSuperObjectIter; 3691 begin 3692 obj := o['name']; 3693 if ObjectIsType(obj, stString) then 3694 names[obj.AsString] := o; 3695 3696 case FindDataType(o) of 3697 dtMap: 3698 begin 3699 obj := o['mapping']; 3700 if ObjectIsType(obj, stObject) then 3701 begin 3702 if ObjectFindFirst(obj, f) then 3703 repeat 3704 if ObjectIsType(f.val, stObject) then 3705 GetNames(f.val); 3706 until not ObjectFindNext(f); 3707 ObjectFindClose(f); 3708 end; 3709 end; 3710 dtSeq: 3711 begin 3712 obj := o['sequence']; 3713 if ObjectIsType(obj, stObject) then 3714 GetNames(obj); 3715 end; 3716 end; 3717 end; 3718 3719 function FindInheritedField(const prop: SOString; p: ISuperObject): ISuperObject; 3720 var 3721 o: ISuperObject; 3722 e: TSuperAvlEntry; 3723 begin 3724 o := p['mapping']; 3725 if ObjectIsType(o, stObject) then 3726 begin 3727 o := o.AsObject.GetO(prop); 3728 if o <> nil then 3729 begin 3730 Result := o; 3731 Exit; 3732 end; 3733 end; 3734 3735 o := p['inherit']; 3736 if ObjectIsType(o, stString) then 3737 begin 3738 e := names.AsObject.Search(o.AsString); 3739 if (e <> nil) then 3740 Result := FindInheritedField(prop, e.Value) else 3741 Result := nil; 3742 end else 3743 Result := nil; 3744 end; 3745 3746 function InheritedFieldExist(const obj: ISuperObject; p: ISuperObject; const name: SOString = ''): boolean; 3747 var 3748 o: ISuperObject; 3749 e: TSuperAvlEntry; 3750 j: TSuperAvlIterator; 3751 begin 3752 Result := true; 3753 o := p['mapping']; 3754 if ObjectIsType(o, stObject) then 3755 begin 3756 j := TSuperAvlIterator.Create(o.AsObject); 3757 try 3758 j.First; 3759 e := j.GetIter; 3760 while e <> nil do 3761 begin 3762 if obj.AsObject.Search(e.Name) = nil then 3763 begin 3764 Result := False; 3765 if assigned(callback) then 3766 callback(sender, veFieldNotFound, name + '.' + e.Name); 3767 end; 3768 j.Next; 3769 e := j.GetIter; 3770 end; 3771 3772 finally 3773 j.Free; 3774 end; 3775 end; 3776 3777 o := p['inherit']; 3778 if ObjectIsType(o, stString) then 3779 begin 3780 e := names.AsObject.Search(o.AsString); 3781 if (e <> nil) then 3782 Result := InheritedFieldExist(obj, e.Value, name) and Result; 3783 end; 3784 end; 3785 3786 function getInheritedBool(f: PSOChar; p: ISuperObject; default: boolean = false): boolean; 3787 var 3788 o: ISuperObject; 3789 begin 3790 o := FindInheritedProperty(f, p); 3791 case ObjectGetType(o) of 3792 stBoolean: Result := o.AsBoolean; 3793 stNull: Result := Default; 3794 else 3795 Result := default; 3796 if assigned(callback) then 3797 callback(sender, veRuleMalformated, f); 3798 end; 3799 end; 3800 3801 procedure GetInheritedFieldList(list: ISuperObject; p: ISuperObject); 3802 var 3803 o: ISuperObject; 3804 e: TSuperAvlEntry; 3805 i: TSuperAvlIterator; 3806 begin 3807 Result := true; 3808 o := p['mapping']; 3809 if ObjectIsType(o, stObject) then 3810 begin 3811 i := TSuperAvlIterator.Create(o.AsObject); 3812 try 3813 i.First; 3814 e := i.GetIter; 3815 while e <> nil do 3816 begin 3817 if list.AsObject.Search(e.Name) = nil then 3818 list[e.Name] := e.Value; 3819 i.Next; 3820 e := i.GetIter; 3821 end; 3822 3823 finally 3824 i.Free; 3825 end; 3826 end; 3827 3828 o := p['inherit']; 3829 if ObjectIsType(o, stString) then 3830 begin 3831 e := names.AsObject.Search(o.AsString); 3832 if (e <> nil) then 3833 GetInheritedFieldList(list, e.Value); 3834 end; 3835 end; 3836 3837 function CheckEnum(o: ISuperObject; p: ISuperObject; name: SOString = ''): boolean; 3838 var 3839 enum: ISuperObject; 3840 i: integer; 3841 begin 3842 Result := false; 3843 enum := FindInheritedProperty('enum', p); 3844 case ObjectGetType(enum) of 3845 stArray: 3846 for i := 0 to enum.AsArray.Length - 1 do 3847 if (o.AsString = enum.AsArray[i].AsString) then 3848 begin 3849 Result := true; 3850 exit; 3851 end; 3852 stNull: Result := true; 3853 else 3854 Result := false; 3855 if assigned(callback) then 3856 callback(sender, veRuleMalformated, ''); 3857 Exit; 3858 end; 3859 3860 if (not Result) and assigned(callback) then 3861 callback(sender, veValueNotInEnum, name); 3862 end; 3863 3864 function CheckLength(len: integer; p: ISuperObject; const objpath: SOString): boolean; 3865 var 3866 length, o: ISuperObject; 3867 begin 3868 result := true; 3869 length := FindInheritedProperty('length', p); 3870 case ObjectGetType(length) of 3871 stObject: 3872 begin 3873 o := length.AsObject.GetO('min'); 3874 if (o <> nil) and (o.AsInteger > len) then 3875 begin 3876 Result := false; 3877 if assigned(callback) then 3878 callback(sender, veInvalidLength, objpath); 3879 end; 3880 o := length.AsObject.GetO('max'); 3881 if (o <> nil) and (o.AsInteger < len) then 3882 begin 3883 Result := false; 3884 if assigned(callback) then 3885 callback(sender, veInvalidLength, objpath); 3886 end; 3887 o := length.AsObject.GetO('minex'); 3888 if (o <> nil) and (o.AsInteger >= len) then 3889 begin 3890 Result := false; 3891 if assigned(callback) then 3892 callback(sender, veInvalidLength, objpath); 3893 end; 3894 o := length.AsObject.GetO('maxex'); 3895 if (o <> nil) and (o.AsInteger <= len) then 3896 begin 3897 Result := false; 3898 if assigned(callback) then 3899 callback(sender, veInvalidLength, objpath); 3900 end; 3901 end; 3902 stNull: ; 3903 else 3904 Result := false; 3905 if assigned(callback) then 3906 callback(sender, veRuleMalformated, ''); 3907 end; 3908 end; 3909 3910 function CheckRange(obj: ISuperObject; p: ISuperObject; const objpath: SOString): boolean; 3911 var 3912 length, o: ISuperObject; 3913 begin 3914 result := true; 3915 length := FindInheritedProperty('range', p); 3916 case ObjectGetType(length) of 3917 stObject: 3918 begin 3919 o := length.AsObject.GetO('min'); 3920 if (o <> nil) and (o.Compare(obj) = cpGreat) then 3921 begin 3922 Result := false; 3923 if assigned(callback) then 3924 callback(sender, veInvalidRange, objpath); 3925 end; 3926 o := length.AsObject.GetO('max'); 3927 if (o <> nil) and (o.Compare(obj) = cpLess) then 3928 begin 3929 Result := false; 3930 if assigned(callback) then 3931 callback(sender, veInvalidRange, objpath); 3932 end; 3933 o := length.AsObject.GetO('minex'); 3934 if (o <> nil) and (o.Compare(obj) in [cpGreat, cpEqu]) then 3935 begin 3936 Result := false; 3937 if assigned(callback) then 3938 callback(sender, veInvalidRange, objpath); 3939 end; 3940 o := length.AsObject.GetO('maxex'); 3941 if (o <> nil) and (o.Compare(obj) in [cpLess, cpEqu]) then 3942 begin 3943 Result := false; 3944 if assigned(callback) then 3945 callback(sender, veInvalidRange, objpath); 3946 end; 3947 end; 3948 stNull: ; 3949 else 3950 Result := false; 3951 if assigned(callback) then 3952 callback(sender, veRuleMalformated, ''); 3953 end; 3954 end; 3955 3956 3957 function process(o: ISuperObject; p: ISuperObject; objpath: SOString = ''): boolean; 3958 var 3959 ite: TSuperAvlIterator; 3960 ent: TSuperAvlEntry; 3961 p2, o2, sequence: ISuperObject; 3962 s: SOString; 3963 i: integer; 3964 uniquelist, fieldlist: ISuperObject; 3965 begin 3966 Result := true; 3967 if (o = nil) then 3968 begin 3969 if getInheritedBool('required', p) then 3970 begin 3971 if assigned(callback) then 3972 callback(sender, veFieldIsRequired, objpath); 3973 result := false; 3974 end; 3975 end else 3976 case FindDataType(p) of 3977 dtStr: 3978 case ObjectGetType(o) of 3979 stString: 3980 begin 3981 Result := Result and CheckLength(Length(o.AsString), p, objpath); 3982 Result := Result and CheckRange(o, p, objpath); 3983 end; 3984 else 3985 if assigned(callback) then 3986 callback(sender, veInvalidDataType, objpath); 3987 result := false; 3988 end; 3989 dtBool: 3990 case ObjectGetType(o) of 3991 stBoolean: 3992 begin 3993 Result := Result and CheckRange(o, p, objpath); 3994 end; 3995 else 3996 if assigned(callback) then 3997 callback(sender, veInvalidDataType, objpath); 3998 result := false; 3999 end; 4000 dtInt: 4001 case ObjectGetType(o) of 4002 stInt: 4003 begin 4004 Result := Result and CheckRange(o, p, objpath); 4005 end; 4006 else 4007 if assigned(callback) then 4008 callback(sender, veInvalidDataType, objpath); 4009 result := false; 4010 end; 4011 dtFloat: 4012 case ObjectGetType(o) of 4013 stDouble, stCurrency: 4014 begin 4015 Result := Result and CheckRange(o, p, objpath); 4016 end; 4017 else 4018 if assigned(callback) then 4019 callback(sender, veInvalidDataType, objpath); 4020 result := false; 4021 end; 4022 dtMap: 4023 case ObjectGetType(o) of 4024 stObject: 4025 begin 4026 // all objects have and match a rule ? 4027 ite := TSuperAvlIterator.Create(o.AsObject); 4028 try 4029 ite.First; 4030 ent := ite.GetIter; 4031 while ent <> nil do 4032 begin 4033 p2 := FindInheritedField(ent.Name, p); 4034 if ObjectIsType(p2, stObject) then 4035 result := process(ent.Value, p2, objpath + '.' + ent.Name) and result else 4036 begin 4037 if assigned(callback) then 4038 callback(sender, veUnexpectedField, objpath + '.' + ent.Name); 4039 result := false; // field have no rule 4040 end; 4041 ite.Next; 4042 ent := ite.GetIter; 4043 end; 4044 finally 4045 ite.Free; 4046 end; 4047 4048 // all expected field exists ? 4049 Result := InheritedFieldExist(o, p, objpath) and Result; 4050 end; 4051 stNull: {nop}; 4052 else 4053 result := false; 4054 if assigned(callback) then 4055 callback(sender, veRuleMalformated, objpath); 4056 end; 4057 dtSeq: 4058 case ObjectGetType(o) of 4059 stArray: 4060 begin 4061 sequence := FindInheritedProperty('sequence', p); 4062 if sequence <> nil then 4063 case ObjectGetType(sequence) of 4064 stObject: 4065 begin 4066 for i := 0 to o.AsArray.Length - 1 do 4067 result := process(o.AsArray.GetO(i), sequence, objpath + '[' + IntToStr(i) + ']') and result; 4068 if getInheritedBool('unique', sequence) then 4069 begin 4070 // type is unique ? 4071 uniquelist := TSuperObject.Create(stObject); 4072 try 4073 for i := 0 to o.AsArray.Length - 1 do 4074 begin 4075 s := o.AsArray.GetO(i).AsString; 4076 if (s <> '') then 4077 begin 4078 if uniquelist.AsObject.Search(s) = nil then 4079 uniquelist[s] := nil else 4080 begin 4081 Result := False; 4082 if Assigned(callback) then 4083 callback(sender, veDuplicateEntry, objpath + '[' + IntToStr(i) + ']'); 4084 end; 4085 end; 4086 end; 4087 finally 4088 uniquelist := nil; 4089 end; 4090 end; 4091 4092 // field is unique ? 4093 if (FindDataType(sequence) = dtMap) then 4094 begin 4095 fieldlist := TSuperObject.Create(stObject); 4096 try 4097 GetInheritedFieldList(fieldlist, sequence); 4098 ite := TSuperAvlIterator.Create(fieldlist.AsObject); 4099 try 4100 ite.First; 4101 ent := ite.GetIter; 4102 while ent <> nil do 4103 begin 4104 if getInheritedBool('unique', ent.Value) then 4105 begin 4106 uniquelist := TSuperObject.Create(stObject); 4107 try 4108 for i := 0 to o.AsArray.Length - 1 do 4109 begin 4110 o2 := o.AsArray.GetO(i); 4111 if o2 <> nil then 4112 begin 4113 s := o2.AsObject.GetO(ent.Name).AsString; 4114 if (s <> '') then 4115 if uniquelist.AsObject.Search(s) = nil then 4116 uniquelist[s] := nil else 4117 begin 4118 Result := False; 4119 if Assigned(callback) then 4120 callback(sender, veDuplicateEntry, objpath + '[' + IntToStr(i) + '].' + ent.name); 4121 end; 4122 end; 4123 end; 4124 finally 4125 uniquelist := nil; 4126 end; 4127 end; 4128 ite.Next; 4129 ent := ite.GetIter; 4130 end; 4131 finally 4132 ite.Free; 4133 end; 4134 finally 4135 fieldlist := nil; 4136 end; 4137 end; 4138 4139 4140 end; 4141 stNull: {nop}; 4142 else 4143 result := false; 4144 if assigned(callback) then 4145 callback(sender, veRuleMalformated, objpath); 4146 end; 4147 Result := Result and CheckLength(o.AsArray.Length, p, objpath); 4148 4149 end; 4150 else 4151 result := false; 4152 if assigned(callback) then 4153 callback(sender, veRuleMalformated, objpath); 4154 end; 4155 dtNumber: 4156 case ObjectGetType(o) of 4157 stInt, 4158 stDouble, stCurrency: 4159 begin 4160 Result := Result and CheckRange(o, p, objpath); 4161 end; 4162 else 4163 if assigned(callback) then 4164 callback(sender, veInvalidDataType, objpath); 4165 result := false; 4166 end; 4167 dtText: 4168 case ObjectGetType(o) of 4169 stInt, 4170 stDouble, 4171 stCurrency, 4172 stString: 4173 begin 4174 result := result and CheckLength(Length(o.AsString), p, objpath); 4175 Result := Result and CheckRange(o, p, objpath); 4176 end; 4177 else 4178 if assigned(callback) then 4179 callback(sender, veInvalidDataType, objpath); 4180 result := false; 4181 end; 4182 dtScalar: 4183 case ObjectGetType(o) of 4184 stBoolean, 4185 stDouble, 4186 stCurrency, 4187 stInt, 4188 stString: 4189 begin 4190 result := result and CheckLength(Length(o.AsString), p, objpath); 4191 Result := Result and CheckRange(o, p, objpath); 4192 end; 4193 else 4194 if assigned(callback) then 4195 callback(sender, veInvalidDataType, objpath); 4196 result := false; 4197 end; 4198 dtAny:; 4199 else 4200 if assigned(callback) then 4201 callback(sender, veRuleMalformated, objpath); 4202 result := false; 4203 end; 4204 Result := Result and CheckEnum(o, p, objpath) 4205 4206 end; 4207 var 4208 j: integer; 4209 4210 begin 4211 Result := False; 4212 datatypes := TSuperObject.Create(stObject); 4213 names := TSuperObject.Create; 4214 try 4215 datatypes.I['str'] := ord(dtStr); 4216 datatypes.I['int'] := ord(dtInt); 4217 datatypes.I['float'] := ord(dtFloat); 4218 datatypes.I['number'] := ord(dtNumber); 4219 datatypes.I['text'] := ord(dtText); 4220 datatypes.I['bool'] := ord(dtBool); 4221 datatypes.I['map'] := ord(dtMap); 4222 datatypes.I['seq'] := ord(dtSeq); 4223 datatypes.I['scalar'] := ord(dtScalar); 4224 datatypes.I['any'] := ord(dtAny); 4225 4226 if ObjectIsType(defs, stArray) then 4227 for j := 0 to defs.AsArray.Length - 1 do 4228 if ObjectIsType(defs.AsArray[j], stObject) then 4229 GetNames(defs.AsArray[j]) else 4230 begin 4231 if assigned(callback) then 4232 callback(sender, veRuleMalformated, ''); 4233 Exit; 4234 end; 4235 4236 4237 if ObjectIsType(rules, stObject) then 4238 GetNames(rules) else 4239 begin 4240 if assigned(callback) then 4241 callback(sender, veRuleMalformated, ''); 4242 Exit; 4243 end; 4244 4245 Result := process(self, rules); 4246 4247 finally 4248 datatypes := nil; 4249 names := nil; 4250 end; 4251 end; 4252 4253 function TSuperObject._AddRef: Integer; stdcall; 4254 begin 4255 Result := InterlockedIncrement(FRefCount); 4256 end; 4257 4258 function TSuperObject._Release: Integer; stdcall; 4259 begin 4260 Result := InterlockedDecrement(FRefCount); 4261 if Result = 0 then 4262 Destroy; 4263 end; 4264 4265 function TSuperObject.Compare(const str: SOString): TSuperCompareResult; 4266 begin 4267 Result := Compare(TSuperObject.ParseString(PSOChar(str), False)); 4268 end; 4269 4270 function TSuperObject.Compare(const obj: ISuperObject): TSuperCompareResult; 4271 function GetIntCompResult(const i: int64): TSuperCompareResult; 4272 begin 4273 if i < 0 then result := cpLess else 4274 if i = 0 then result := cpEqu else 4275 Result := cpGreat; 4276 end; 4277 4278 function GetDblCompResult(const d: double): TSuperCompareResult; 4279 begin 4280 if d < 0 then result := cpLess else 4281 if d = 0 then result := cpEqu else 4282 Result := cpGreat; 4283 end; 4284 4285 begin 4286 case DataType of 4287 stBoolean: 4288 case ObjectGetType(obj) of 4289 stBoolean: Result := GetIntCompResult(ord(FO.c_boolean) - ord(obj.AsBoolean)); 4290 stDouble: Result := GetDblCompResult(ord(FO.c_boolean) - obj.AsDouble); 4291 stCurrency:Result := GetDblCompResult(ord(FO.c_boolean) - obj.AsCurrency); 4292 stInt: Result := GetIntCompResult(ord(FO.c_boolean) - obj.AsInteger); 4293 stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); 4294 else 4295 Result := cpError; 4296 end; 4297 stDouble: 4298 case ObjectGetType(obj) of 4299 stBoolean: Result := GetDblCompResult(FO.c_double - ord(obj.AsBoolean)); 4300 stDouble: Result := GetDblCompResult(FO.c_double - obj.AsDouble); 4301 stCurrency:Result := GetDblCompResult(FO.c_double - obj.AsCurrency); 4302 stInt: Result := GetDblCompResult(FO.c_double - obj.AsInteger); 4303 stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); 4304 else 4305 Result := cpError; 4306 end; 4307 stCurrency: 4308 case ObjectGetType(obj) of 4309 stBoolean: Result := GetDblCompResult(FO.c_currency - ord(obj.AsBoolean)); 4310 stDouble: Result := GetDblCompResult(FO.c_currency - obj.AsDouble); 4311 stCurrency:Result := GetDblCompResult(FO.c_currency - obj.AsCurrency); 4312 stInt: Result := GetDblCompResult(FO.c_currency - obj.AsInteger); 4313 stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); 4314 else 4315 Result := cpError; 4316 end; 4317 stInt: 4318 case ObjectGetType(obj) of 4319 stBoolean: Result := GetIntCompResult(FO.c_int - ord(obj.AsBoolean)); 4320 stDouble: Result := GetDblCompResult(FO.c_int - obj.AsDouble); 4321 stCurrency:Result := GetDblCompResult(FO.c_int - obj.AsCurrency); 4322 stInt: Result := GetIntCompResult(FO.c_int - obj.AsInteger); 4323 stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); 4324 else 4325 Result := cpError; 4326 end; 4327 stString: 4328 case ObjectGetType(obj) of 4329 stBoolean, 4330 stDouble, 4331 stCurrency, 4332 stInt, 4333 stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); 4334 else 4335 Result := cpError; 4336 end; 4337 else 4338 Result := cpError; 4339 end; 4340 end; 4341 4342 {$IFDEF SUPER_METHOD} 4343 function TSuperObject.AsMethod: TSuperMethod; 4344 begin 4345 if FDataType = stMethod then 4346 Result := FO.c_method else 4347 Result := nil; 4348 end; 4349 {$ENDIF} 4350 4351 {$IFDEF SUPER_METHOD} 4352 constructor TSuperObject.Create(m: TSuperMethod); 4353 begin 4354 Create(stMethod); 4355 FO.c_method := m; 4356 end; 4357 {$ENDIF} 4358 4359 {$IFDEF SUPER_METHOD} 4360 function TSuperObject.GetM(const path: SOString): TSuperMethod; 4361 var 4362 v: ISuperObject; 4363 begin 4364 v := ParseString(PSOChar(path), False, True, Self); 4365 if (v <> nil) and (ObjectGetType(v) = stMethod) then 4366 Result := v.AsMethod else 4367 Result := nil; 4368 end; 4369 {$ENDIF} 4370 4371 {$IFDEF SUPER_METHOD} 4372 procedure TSuperObject.PutM(const path: SOString; Value: TSuperMethod); 4373 begin 4374 ParseString(PSOChar(path), False, True, Self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); 4375 end; 4376 {$ENDIF} 4377 4378 {$IFDEF SUPER_METHOD} 4379 function TSuperObject.call(const path: SOString; const param: ISuperObject): ISuperObject; 4380 begin 4381 Result := ParseString(PSOChar(path), False, True, Self, [foCallMethod], param); 4382 end; 4383 {$ENDIF} 4384 4385 {$IFDEF SUPER_METHOD} 4386 function TSuperObject.call(const path, param: SOString): ISuperObject; 4387 begin 4388 Result := ParseString(PSOChar(path), False, True, Self, [foCallMethod], TSuperObject.ParseString(PSOChar(param), False)); 4389 end; 4390 {$ENDIF} 4391 4392 function TSuperObject.GetProcessing: boolean; 4393 begin 4394 Result := FProcessing; 4395 end; 4396 4397 procedure TSuperObject.SetDataPtr(const Value: Pointer); 4398 begin 4399 FDataPtr := Value; 4400 end; 4401 4402 procedure TSuperObject.SetProcessing(value: boolean); 4403 begin 4404 FProcessing := value; 4405 end; 4406 4407 { TSuperArray } 4408 4409 function TSuperArray.Add(const Data: ISuperObject): Integer; 4410 begin 4411 Result := FLength; 4412 PutO(Result, data); 4413 end; 4414 4415 function TSuperArray.Delete(index: Integer): ISuperObject; 4416 begin 4417 if (Index >= 0) and (Index < FLength) then 4418 begin 4419 Result := FArray^[index]; 4420 FArray^[index] := nil; 4421 Dec(FLength); 4422 if Index < FLength then 4423 begin 4424 Move(FArray^[index + 1], FArray^[index], 4425 (FLength - index) * SizeOf(Pointer)); 4426 Pointer(FArray^[FLength]) := nil; 4427 end; 4428 end; 4429 end; 4430 4431 procedure TSuperArray.Insert(index: Integer; const value: ISuperObject); 4432 begin 4433 if (Index >= 0) then 4434 if (index < FLength) then 4435 begin 4436 if FLength = FSize then 4437 Expand(index); 4438 if Index < FLength then 4439 Move(FArray^[index], FArray^[index + 1], 4440 (FLength - index) * SizeOf(Pointer)); 4441 Pointer(FArray^[index]) := nil; 4442 FArray^[index] := value; 4443 Inc(FLength); 4444 end else 4445 PutO(index, value); 4446 end; 4447 4448 procedure TSuperArray.Clear(all: boolean); 4449 var 4450 j: Integer; 4451 begin 4452 for j := 0 to FLength - 1 do 4453 if FArray^[j] <> nil then 4454 begin 4455 if all then 4456 FArray^[j].Clear(all); 4457 FArray^[j] := nil; 4458 end; 4459 FLength := 0; 4460 end; 4461 4462 procedure TSuperArray.Pack(all: boolean); 4463 var 4464 PackedCount, StartIndex, EndIndex, j: Integer; 4465 begin 4466 if FLength > 0 then 4467 begin 4468 PackedCount := 0; 4469 StartIndex := 0; 4470 repeat 4471 while (StartIndex < FLength) and (FArray^[StartIndex] = nil) do 4472 Inc(StartIndex); 4473 if StartIndex < FLength then 4474 begin 4475 EndIndex := StartIndex; 4476 while (EndIndex < FLength) and (FArray^[EndIndex] <> nil) do 4477 Inc(EndIndex); 4478 4479 Dec(EndIndex); 4480 4481 if StartIndex > PackedCount then 4482 Move(FArray^[StartIndex], FArray^[PackedCount], (EndIndex - StartIndex + 1) * SizeOf(Pointer)); 4483 4484 Inc(PackedCount, EndIndex - StartIndex + 1); 4485 StartIndex := EndIndex + 1; 4486 end; 4487 until StartIndex >= FLength; 4488 FillChar(FArray^[PackedCount], (FLength - PackedCount) * sizeof(Pointer), 0); 4489 FLength := PackedCount; 4490 if all then 4491 for j := 0 to FLength - 1 do 4492 FArray^[j].Pack(all); 4493 end; 4494 end; 4495 4496 constructor TSuperArray.Create; 4497 begin 4498 inherited Create; 4499 FSize := SUPER_ARRAY_LIST_DEFAULT_SIZE; 4500 FLength := 0; 4501 GetMem(FArray, sizeof(Pointer) * FSize); 4502 FillChar(FArray^, sizeof(Pointer) * FSize, 0); 4503 end; 4504 4505 destructor TSuperArray.Destroy; 4506 begin 4507 Clear; 4508 FreeMem(FArray); 4509 inherited; 4510 end; 4511 4512 procedure TSuperArray.Expand(max: Integer); 4513 var 4514 new_size: Integer; 4515 begin 4516 if (max < FSize) then 4517 Exit; 4518 if max < (FSize shl 1) then 4519 new_size := (FSize shl 1) else 4520 new_size := max + 1; 4521 ReallocMem(FArray, new_size * sizeof(Pointer)); 4522 FillChar(FArray^[FSize], (new_size - FSize) * sizeof(Pointer), 0); 4523 FSize := new_size; 4524 end; 4525 4526 function TSuperArray.GetO(const index: Integer): ISuperObject; 4527 begin 4528 if(index >= FLength) then 4529 Result := nil else 4530 Result := FArray^[index]; 4531 end; 4532 4533 function TSuperArray.GetB(const index: integer): Boolean; 4534 var 4535 obj: ISuperObject; 4536 begin 4537 obj := GetO(index); 4538 if obj <> nil then 4539 Result := obj.AsBoolean else 4540 Result := false; 4541 end; 4542 4543 function TSuperArray.GetD(const index: integer): Double; 4544 var 4545 obj: ISuperObject; 4546 begin 4547 obj := GetO(index); 4548 if obj <> nil then 4549 Result := obj.AsDouble else 4550 Result := 0.0; 4551 end; 4552 4553 function TSuperArray.GetI(const index: integer): SuperInt; 4554 var 4555 obj: ISuperObject; 4556 begin 4557 obj := GetO(index); 4558 if obj <> nil then 4559 Result := obj.AsInteger else 4560 Result := 0; 4561 end; 4562 4563 function TSuperArray.GetS(const index: integer): SOString; 4564 var 4565 obj: ISuperObject; 4566 begin 4567 obj := GetO(index); 4568 if obj <> nil then 4569 Result := obj.AsString else 4570 Result := ''; 4571 end; 4572 4573 procedure TSuperArray.PutO(const index: Integer; const Value: ISuperObject); 4574 begin 4575 Expand(index); 4576 FArray^[index] := value; 4577 if(FLength <= index) then FLength := index + 1; 4578 end; 4579 4580 function TSuperArray.GetN(const index: integer): ISuperObject; 4581 begin 4582 Result := GetO(index); 4583 if Result = nil then 4584 Result := TSuperObject.Create(stNull); 4585 end; 4586 4587 procedure TSuperArray.PutN(const index: integer; const Value: ISuperObject); 4588 begin 4589 if Value <> nil then 4590 PutO(index, Value) else 4591 PutO(index, TSuperObject.Create(stNull)); 4592 end; 4593 4594 procedure TSuperArray.PutB(const index: integer; Value: Boolean); 4595 begin 4596 PutO(index, TSuperObject.Create(Value)); 4597 end; 4598 4599 procedure TSuperArray.PutD(const index: integer; Value: Double); 4600 begin 4601 PutO(index, TSuperObject.Create(Value)); 4602 end; 4603 4604 function TSuperArray.GetC(const index: integer): Currency; 4605 var 4606 obj: ISuperObject; 4607 begin 4608 obj := GetO(index); 4609 if obj <> nil then 4610 Result := obj.AsCurrency else 4611 Result := 0.0; 4612 end; 4613 4614 procedure TSuperArray.PutC(const index: integer; Value: Currency); 4615 begin 4616 PutO(index, TSuperObject.CreateCurrency(Value)); 4617 end; 4618 4619 procedure TSuperArray.PutI(const index: integer; Value: SuperInt); 4620 begin 4621 PutO(index, TSuperObject.Create(Value)); 4622 end; 4623 4624 procedure TSuperArray.PutS(const index: integer; const Value: SOString); 4625 begin 4626 PutO(index, TSuperObject.Create(Value)); 4627 end; 4628 4629 {$IFDEF SUPER_METHOD} 4630 function TSuperArray.GetM(const index: integer): TSuperMethod; 4631 var 4632 v: ISuperObject; 4633 begin 4634 v := GetO(index); 4635 if (ObjectGetType(v) = stMethod) then 4636 Result := v.AsMethod else 4637 Result := nil; 4638 end; 4639 {$ENDIF} 4640 4641 {$IFDEF SUPER_METHOD} 4642 procedure TSuperArray.PutM(const index: integer; Value: TSuperMethod); 4643 begin 4644 PutO(index, TSuperObject.Create(Value)); 4645 end; 4646 {$ENDIF} 4647 4648 { TSuperWriterString } 4649 4650 function TSuperWriterString.Append(buf: PSOChar; Size: Integer): Integer; 4651 function max(a, b: Integer): integer; begin if a > b then Result := a else Result := b end; 4652 begin 4653 Result := size; 4654 if Size > 0 then 4655 begin 4656 if (FSize - FBPos <= size) then 4657 begin 4658 FSize := max(FSize * 2, FBPos + size + 8); 4659 ReallocMem(FBuf, FSize * SizeOf(SOChar)); 4660 end; 4661 // fast move 4662 case size of 4663 1: FBuf[FBPos] := buf^; 4664 2: PInteger(@FBuf[FBPos])^ := PInteger(buf)^; 4665 4: PInt64(@FBuf[FBPos])^ := PInt64(buf)^; 4666 else 4667 move(buf^, FBuf[FBPos], size * SizeOf(SOChar)); 4668 end; 4669 inc(FBPos, size); 4670 FBuf[FBPos] := #0; 4671 end; 4672 end; 4673 4674 function TSuperWriterString.Append(buf: PSOChar): Integer; 4675 begin 4676 Result := Append(buf, strlen(buf)); 4677 end; 4678 4679 constructor TSuperWriterString.Create; 4680 begin 4681 inherited; 4682 FSize := 32; 4683 FBPos := 0; 4684 GetMem(FBuf, FSize * SizeOf(SOChar)); 4685 end; 4686 4687 destructor TSuperWriterString.Destroy; 4688 begin 4689 inherited; 4690 if FBuf <> nil then 4691 FreeMem(FBuf) 4692 end; 4693 4694 function TSuperWriterString.GetString: SOString; 4695 begin 4696 SetString(Result, FBuf, FBPos); 4697 end; 4698 4699 procedure TSuperWriterString.Reset; 4700 begin 4701 FBuf[0] := #0; 4702 FBPos := 0; 4703 end; 4704 4705 procedure TSuperWriterString.TrimRight; 4706 begin 4707 while (FBPos > 0) and (FBuf[FBPos-1] < #256) and (AnsiChar(FBuf[FBPos-1]) in [#32, #13, #10]) do 4708 begin 4709 dec(FBPos); 4710 FBuf[FBPos] := #0; 4711 end; 4712 end; 4713 4714 { TSuperWriterStream } 4715 4716 function TSuperWriterStream.Append(buf: PSOChar): Integer; 4717 begin 4718 Result := Append(buf, StrLen(buf)); 4719 end; 4720 4721 constructor TSuperWriterStream.Create(AStream: TStream); 4722 begin 4723 inherited Create; 4724 FStream := AStream; 4725 end; 4726 4727 procedure TSuperWriterStream.Reset; 4728 begin 4729 FStream.Size := 0; 4730 end; 4731 4732 { TSuperWriterStream } 4733 4734 function TSuperAnsiWriterStream.Append(buf: PSOChar; Size: Integer): Integer; 4735 var 4736 Buffer: array[0..1023] of AnsiChar; 4737 pBuffer: PAnsiChar; 4738 i: Integer; 4739 begin 4740 if Size = 1 then 4741 Result := FStream.Write(buf^, Size) else 4742 begin 4743 if Size > SizeOf(Buffer) then 4744 GetMem(pBuffer, Size) else 4745 pBuffer := @Buffer; 4746 try 4747 for i := 0 to Size - 1 do 4748 pBuffer[i] := AnsiChar(buf[i]); 4749 Result := FStream.Write(pBuffer^, Size); 4750 finally 4751 if pBuffer <> @Buffer then 4752 FreeMem(pBuffer); 4753 end; 4754 end; 4755 end; 4756 4757 { TSuperUnicodeWriterStream } 4758 4759 function TSuperUnicodeWriterStream.Append(buf: PSOChar; Size: Integer): Integer; 4760 begin 4761 Result := FStream.Write(buf^, Size * 2); 4762 end; 4763 4764 { TSuperWriterFake } 4765 4766 function TSuperWriterFake.Append(buf: PSOChar; Size: Integer): Integer; 4767 begin 4768 inc(FSize, Size); 4769 Result := FSize; 4770 end; 4771 4772 function TSuperWriterFake.Append(buf: PSOChar): Integer; 4773 begin 4774 inc(FSize, Strlen(buf)); 4775 Result := FSize; 4776 end; 4777 4778 constructor TSuperWriterFake.Create; 4779 begin 4780 inherited Create; 4781 FSize := 0; 4782 end; 4783 4784 procedure TSuperWriterFake.Reset; 4785 begin 4786 FSize := 0; 4787 end; 4788 4789 { TSuperWriterSock } 4790 4791 function TSuperWriterSock.Append(buf: PSOChar; Size: Integer): Integer; 4792 var 4793 Buffer: array[0..1023] of AnsiChar; 4794 pBuffer: PAnsiChar; 4795 i: Integer; 4796 begin 4797 if Size = 1 then 4798 {$IFDEF FPC} 4799 Result := fpsend(FSocket, buf, size, 0) else 4800 {$ELSE} 4801 Result := send(FSocket, buf^, size, 0) else 4802 {$ENDIF} 4803 begin 4804 if Size > SizeOf(Buffer) then 4805 GetMem(pBuffer, Size) else 4806 pBuffer := @Buffer; 4807 try 4808 for i := 0 to Size - 1 do 4809 pBuffer[i] := AnsiChar(buf[i]); 4810 {$IFDEF FPC} 4811 Result := fpsend(FSocket, pBuffer, size, 0); 4812 {$ELSE} 4813 Result := send(FSocket, pBuffer^, size, 0); 4814 {$ENDIF} 4815 finally 4816 if pBuffer <> @Buffer then 4817 FreeMem(pBuffer); 4818 end; 4819 end; 4820 inc(FSize, Result); 4821 end; 4822 4823 function TSuperWriterSock.Append(buf: PSOChar): Integer; 4824 begin 4825 Result := Append(buf, StrLen(buf)); 4826 end; 4827 4828 constructor TSuperWriterSock.Create(ASocket: Integer); 4829 begin 4830 inherited Create; 4831 FSocket := ASocket; 4832 FSize := 0; 4833 end; 4834 4835 procedure TSuperWriterSock.Reset; 4836 begin 4837 FSize := 0; 4838 end; 4839 4840 { TSuperTokenizer } 4841 4842 constructor TSuperTokenizer.Create; 4843 begin 4844 pb := TSuperWriterString.Create; 4845 line := 1; 4846 col := 0; 4847 Reset; 4848 end; 4849 4850 destructor TSuperTokenizer.Destroy; 4851 begin 4852 Reset; 4853 pb.Free; 4854 inherited; 4855 end; 4856 4857 procedure TSuperTokenizer.Reset; 4858 var 4859 i: integer; 4860 begin 4861 for i := depth downto 0 do 4862 ResetLevel(i); 4863 depth := 0; 4864 err := teSuccess; 4865 end; 4866 4867 procedure TSuperTokenizer.ResetLevel(adepth: integer); 4868 begin 4869 stack[adepth].state := tsEatws; 4870 stack[adepth].saved_state := tsStart; 4871 stack[adepth].current := nil; 4872 stack[adepth].field_name := ''; 4873 stack[adepth].obj := nil; 4874 stack[adepth].parent := nil; 4875 stack[adepth].gparent := nil; 4876 end; 4877 4878 { TSuperAvlTree } 4879 4880 constructor TSuperAvlTree.Create; 4881 begin 4882 FRoot := nil; 4883 FCount := 0; 4884 end; 4885 4886 destructor TSuperAvlTree.Destroy; 4887 begin 4888 Clear; 4889 inherited; 4890 end; 4891 4892 function TSuperAvlTree.IsEmpty: boolean; 4893 begin 4894 result := FRoot = nil; 4895 end; 4896 4897 function TSuperAvlTree.balance(bal: TSuperAvlEntry): TSuperAvlEntry; 4898 var 4899 deep, old: TSuperAvlEntry; 4900 bf: integer; 4901 begin 4902 if (bal.FBf > 0) then 4903 begin 4904 deep := bal.FGt; 4905 if (deep.FBf < 0) then 4906 begin 4907 old := bal; 4908 bal := deep.FLt; 4909 old.FGt := bal.FLt; 4910 deep.FLt := bal.FGt; 4911 bal.FLt := old; 4912 bal.FGt := deep; 4913 bf := bal.FBf; 4914 if (bf <> 0) then 4915 begin 4916 if (bf > 0) then 4917 begin 4918 old.FBf := -1; 4919 deep.FBf := 0; 4920 end else 4921 begin 4922 deep.FBf := 1; 4923 old.FBf := 0; 4924 end; 4925 bal.FBf := 0; 4926 end else 4927 begin 4928 old.FBf := 0; 4929 deep.FBf := 0; 4930 end; 4931 end else 4932 begin 4933 bal.FGt := deep.FLt; 4934 deep.FLt := bal; 4935 if (deep.FBf = 0) then 4936 begin 4937 deep.FBf := -1; 4938 bal.FBf := 1; 4939 end else 4940 begin 4941 deep.FBf := 0; 4942 bal.FBf := 0; 4943 end; 4944 bal := deep; 4945 end; 4946 end else 4947 begin 4948 (* "Less than" subtree is deeper. *) 4949 4950 deep := bal.FLt; 4951 if (deep.FBf > 0) then 4952 begin 4953 old := bal; 4954 bal := deep.FGt; 4955 old.FLt := bal.FGt; 4956 deep.FGt := bal.FLt; 4957 bal.FGt := old; 4958 bal.FLt := deep; 4959 4960 bf := bal.FBf; 4961 if (bf <> 0) then 4962 begin 4963 if (bf < 0) then 4964 begin 4965 old.FBf := 1; 4966 deep.FBf := 0; 4967 end else 4968 begin 4969 deep.FBf := -1; 4970 old.FBf := 0; 4971 end; 4972 bal.FBf := 0; 4973 end else 4974 begin 4975 old.FBf := 0; 4976 deep.FBf := 0; 4977 end; 4978 end else 4979 begin 4980 bal.FLt := deep.FGt; 4981 deep.FGt := bal; 4982 if (deep.FBf = 0) then 4983 begin 4984 deep.FBf := 1; 4985 bal.FBf := -1; 4986 end else 4987 begin 4988 deep.FBf := 0; 4989 bal.FBf := 0; 4990 end; 4991 bal := deep; 4992 end; 4993 end; 4994 Result := bal; 4995 end; 4996 4997 function TSuperAvlTree.Insert(h: TSuperAvlEntry): TSuperAvlEntry; 4998 var 4999 unbal, parentunbal, hh, parent: TSuperAvlEntry; 5000 depth, unbaldepth: longint; 5001 cmp: integer; 5002 unbalbf: integer; 5003 branch: TSuperAvlBitArray; 5004 p: Pointer; 5005 begin 5006 inc(FCount); 5007 h.FLt := nil; 5008 h.FGt := nil; 5009 h.FBf := 0; 5010 branch := []; 5011 5012 if (FRoot = nil) then 5013 FRoot := h 5014 else 5015 begin 5016 unbal := nil; 5017 parentunbal := nil; 5018 depth := 0; 5019 unbaldepth := 0; 5020 hh := FRoot; 5021 parent := nil; 5022 repeat 5023 if (hh.FBf <> 0) then 5024 begin 5025 unbal := hh; 5026 parentunbal := parent; 5027 unbaldepth := depth; 5028 end; 5029 if hh.FHash <> h.FHash then 5030 begin 5031 if hh.FHash < h.FHash then cmp := -1 else 5032 if hh.FHash > h.FHash then cmp := 1 else 5033 cmp := 0; 5034 end else 5035 cmp := CompareNodeNode(h, hh); 5036 if (cmp = 0) then 5037 begin 5038 Result := hh; 5039 //exchange data 5040 p := hh.Ptr; 5041 hh.FPtr := h.Ptr; 5042 h.FPtr := p; 5043 doDeleteEntry(h, false); 5044 dec(FCount); 5045 exit; 5046 end; 5047 parent := hh; 5048 if (cmp > 0) then 5049 begin 5050 hh := hh.FGt; 5051 include(branch, depth); 5052 end else 5053 begin 5054 hh := hh.FLt; 5055 exclude(branch, depth); 5056 end; 5057 inc(depth); 5058 until (hh = nil); 5059 5060 if (cmp < 0) then 5061 parent.FLt := h else 5062 parent.FGt := h; 5063 5064 depth := unbaldepth; 5065 5066 if (unbal = nil) then 5067 hh := FRoot 5068 else 5069 begin 5070 if depth in branch then 5071 cmp := 1 else 5072 cmp := -1; 5073 inc(depth); 5074 unbalbf := unbal.FBf; 5075 if (cmp < 0) then 5076 dec(unbalbf) else 5077 inc(unbalbf); 5078 if cmp < 0 then 5079 hh := unbal.FLt else 5080 hh := unbal.FGt; 5081 if ((unbalbf <> -2) and (unbalbf <> 2)) then 5082 begin 5083 unbal.FBf := unbalbf; 5084 unbal := nil; 5085 end; 5086 end; 5087 5088 if (hh <> nil) then 5089 while (h <> hh) do 5090 begin 5091 if depth in branch then 5092 cmp := 1 else 5093 cmp := -1; 5094 inc(depth); 5095 if (cmp < 0) then 5096 begin 5097 hh.FBf := -1; 5098 hh := hh.FLt; 5099 end else (* cmp > 0 *) 5100 begin 5101 hh.FBf := 1; 5102 hh := hh.FGt; 5103 end; 5104 end; 5105 5106 if (unbal <> nil) then 5107 begin 5108 unbal := balance(unbal); 5109 if (parentunbal = nil) then 5110 FRoot := unbal 5111 else 5112 begin 5113 depth := unbaldepth - 1; 5114 if depth in branch then 5115 cmp := 1 else 5116 cmp := -1; 5117 if (cmp < 0) then 5118 parentunbal.FLt := unbal else 5119 parentunbal.FGt := unbal; 5120 end; 5121 end; 5122 end; 5123 result := h; 5124 end; 5125 5126 function TSuperAvlTree.Search(const k: SOString; st: TSuperAvlSearchTypes): TSuperAvlEntry; 5127 var 5128 cmp, target_cmp: integer; 5129 match_h, h: TSuperAvlEntry; 5130 ha: Cardinal; 5131 begin 5132 ha := TSuperAvlEntry.Hash(k); 5133 5134 match_h := nil; 5135 h := FRoot; 5136 5137 if (stLess in st) then 5138 target_cmp := 1 else 5139 if (stGreater in st) then 5140 target_cmp := -1 else 5141 target_cmp := 0; 5142 5143 while (h <> nil) do 5144 begin 5145 if h.FHash < ha then cmp := -1 else 5146 if h.FHash > ha then cmp := 1 else 5147 cmp := 0; 5148 5149 if cmp = 0 then 5150 cmp := CompareKeyNode(PSOChar(k), h); 5151 if (cmp = 0) then 5152 begin 5153 if (stEqual in st) then 5154 begin 5155 match_h := h; 5156 break; 5157 end; 5158 cmp := -target_cmp; 5159 end 5160 else 5161 if (target_cmp <> 0) then 5162 if ((cmp xor target_cmp) and SUPER_AVL_MASK_HIGH_BIT) = 0 then 5163 match_h := h; 5164 if cmp < 0 then 5165 h := h.FLt else 5166 h := h.FGt; 5167 end; 5168 result := match_h; 5169 end; 5170 5171 function TSuperAvlTree.Delete(const k: SOString): ISuperObject; 5172 var 5173 depth, rm_depth: longint; 5174 branch: TSuperAvlBitArray; 5175 h, parent, child, path, rm, parent_rm: TSuperAvlEntry; 5176 cmp, cmp_shortened_sub_with_path, reduced_depth, bf: integer; 5177 ha: Cardinal; 5178 begin 5179 ha := TSuperAvlEntry.Hash(k); 5180 cmp_shortened_sub_with_path := 0; 5181 branch := []; 5182 5183 depth := 0; 5184 h := FRoot; 5185 parent := nil; 5186 while true do 5187 begin 5188 if (h = nil) then 5189 exit; 5190 if h.FHash < ha then cmp := -1 else 5191 if h.FHash > ha then cmp := 1 else 5192 cmp := 0; 5193 5194 if cmp = 0 then 5195 cmp := CompareKeyNode(k, h); 5196 if (cmp = 0) then 5197 break; 5198 parent := h; 5199 if (cmp > 0) then 5200 begin 5201 h := h.FGt; 5202 include(branch, depth) 5203 end else 5204 begin 5205 h := h.FLt; 5206 exclude(branch, depth) 5207 end; 5208 inc(depth); 5209 cmp_shortened_sub_with_path := cmp; 5210 end; 5211 rm := h; 5212 parent_rm := parent; 5213 rm_depth := depth; 5214 5215 if (h.FBf < 0) then 5216 begin 5217 child := h.FLt; 5218 exclude(branch, depth); 5219 cmp := -1; 5220 end else 5221 begin 5222 child := h.FGt; 5223 include(branch, depth); 5224 cmp := 1; 5225 end; 5226 inc(depth); 5227 5228 if (child <> nil) then 5229 begin 5230 cmp := -cmp; 5231 repeat 5232 parent := h; 5233 h := child; 5234 if (cmp < 0) then 5235 begin 5236 child := h.FLt; 5237 exclude(branch, depth); 5238 end else 5239 begin 5240 child := h.FGt; 5241 include(branch, depth); 5242 end; 5243 inc(depth); 5244 until (child = nil); 5245 5246 if (parent = rm) then 5247 cmp_shortened_sub_with_path := -cmp else 5248 cmp_shortened_sub_with_path := cmp; 5249 5250 if cmp > 0 then 5251 child := h.FLt else 5252 child := h.FGt; 5253 end; 5254 5255 if (parent = nil) then 5256 FRoot := child else 5257 if (cmp_shortened_sub_with_path < 0) then 5258 parent.FLt := child else 5259 parent.FGt := child; 5260 5261 if parent = rm then 5262 path := h else 5263 path := parent; 5264 5265 if (h <> rm) then 5266 begin 5267 h.FLt := rm.FLt; 5268 h.FGt := rm.FGt; 5269 h.FBf := rm.FBf; 5270 if (parent_rm = nil) then 5271 FRoot := h 5272 else 5273 begin 5274 depth := rm_depth - 1; 5275 if (depth in branch) then 5276 parent_rm.FGt := h else 5277 parent_rm.FLt := h; 5278 end; 5279 end; 5280 5281 if (path <> nil) then 5282 begin 5283 h := FRoot; 5284 parent := nil; 5285 depth := 0; 5286 while (h <> path) do 5287 begin 5288 if (depth in branch) then 5289 begin 5290 child := h.FGt; 5291 h.FGt := parent; 5292 end else 5293 begin 5294 child := h.FLt; 5295 h.FLt := parent; 5296 end; 5297 inc(depth); 5298 parent := h; 5299 h := child; 5300 end; 5301 5302 reduced_depth := 1; 5303 cmp := cmp_shortened_sub_with_path; 5304 while true do 5305 begin 5306 if (reduced_depth <> 0) then 5307 begin 5308 bf := h.FBf; 5309 if (cmp < 0) then 5310 inc(bf) else 5311 dec(bf); 5312 if ((bf = -2) or (bf = 2)) then 5313 begin 5314 h := balance(h); 5315 bf := h.FBf; 5316 end else 5317 h.FBf := bf; 5318 reduced_depth := integer(bf = 0); 5319 end; 5320 if (parent = nil) then 5321 break; 5322 child := h; 5323 h := parent; 5324 dec(depth); 5325 if depth in branch then 5326 cmp := 1 else 5327 cmp := -1; 5328 if (cmp < 0) then 5329 begin 5330 parent := h.FLt; 5331 h.FLt := child; 5332 end else 5333 begin 5334 parent := h.FGt; 5335 h.FGt := child; 5336 end; 5337 end; 5338 FRoot := h; 5339 end; 5340 if rm <> nil then 5341 begin 5342 Result := rm.GetValue; 5343 doDeleteEntry(rm, false); 5344 dec(FCount); 5345 end; 5346 end; 5347 5348 procedure TSuperAvlTree.Pack(all: boolean); 5349 var 5350 node1, node2: TSuperAvlEntry; 5351 list: TList; 5352 i: Integer; 5353 begin 5354 node1 := FRoot; 5355 list := TList.Create; 5356 while node1 <> nil do 5357 begin 5358 if (node1.FLt = nil) then 5359 begin 5360 node2 := node1.FGt; 5361 if (node1.FPtr = nil) then 5362 list.Add(node1) else 5363 if all then 5364 node1.Value.Pack(all); 5365 end 5366 else 5367 begin 5368 node2 := node1.FLt; 5369 node1.FLt := node2.FGt; 5370 node2.FGt := node1; 5371 end; 5372 node1 := node2; 5373 end; 5374 for i := 0 to list.Count - 1 do 5375 Delete(TSuperAvlEntry(list[i]).FName); 5376 list.Free; 5377 end; 5378 5379 procedure TSuperAvlTree.Clear(all: boolean); 5380 var 5381 node1, node2: TSuperAvlEntry; 5382 begin 5383 node1 := FRoot; 5384 while node1 <> nil do 5385 begin 5386 if (node1.FLt = nil) then 5387 begin 5388 node2 := node1.FGt; 5389 doDeleteEntry(node1, all); 5390 end 5391 else 5392 begin 5393 node2 := node1.FLt; 5394 node1.FLt := node2.FGt; 5395 node2.FGt := node1; 5396 end; 5397 node1 := node2; 5398 end; 5399 FRoot := nil; 5400 FCount := 0; 5401 end; 5402 5403 function TSuperAvlTree.CompareKeyNode(const k: SOString; h: TSuperAvlEntry): integer; 5404 begin 5405 Result := StrComp(PSOChar(k), PSOChar(h.FName)); 5406 end; 5407 5408 function TSuperAvlTree.CompareNodeNode(node1, node2: TSuperAvlEntry): integer; 5409 begin 5410 Result := StrComp(PSOChar(node1.FName), PSOChar(node2.FName)); 5411 end; 5412 5413 { TSuperAvlIterator } 5414 5415 (* Initialize depth to invalid value, to indicate iterator is 5416 ** invalid. (Depth is zero-base.) It's not necessary to initialize 5417 ** iterators prior to passing them to the "start" function. 5418 *) 5419 5420 constructor TSuperAvlIterator.Create(tree: TSuperAvlTree); 5421 begin 5422 FDepth := not 0; 5423 FTree := tree; 5424 end; 5425 5426 procedure TSuperAvlIterator.Search(const k: SOString; st: TSuperAvlSearchTypes); 5427 var 5428 h: TSuperAvlEntry; 5429 d: longint; 5430 cmp, target_cmp: integer; 5431 ha: Cardinal; 5432 begin 5433 ha := TSuperAvlEntry.Hash(k); 5434 h := FTree.FRoot; 5435 d := 0; 5436 FDepth := not 0; 5437 if (h = nil) then 5438 exit; 5439 5440 if (stLess in st) then 5441 target_cmp := 1 else 5442 if (stGreater in st) then 5443 target_cmp := -1 else 5444 target_cmp := 0; 5445 5446 while true do 5447 begin 5448 if h.FHash < ha then cmp := -1 else 5449 if h.FHash > ha then cmp := 1 else 5450 cmp := 0; 5451 5452 if cmp = 0 then 5453 cmp := FTree.CompareKeyNode(k, h); 5454 if (cmp = 0) then 5455 begin 5456 if (stEqual in st) then 5457 begin 5458 FDepth := d; 5459 break; 5460 end; 5461 cmp := -target_cmp; 5462 end 5463 else 5464 if (target_cmp <> 0) then 5465 if ((cmp xor target_cmp) and SUPER_AVL_MASK_HIGH_BIT) = 0 then 5466 FDepth := d; 5467 if cmp < 0 then 5468 h := h.FLt else 5469 h := h.FGt; 5470 if (h = nil) then 5471 break; 5472 if (cmp > 0) then 5473 include(FBranch, d) else 5474 exclude(FBranch, d); 5475 FPath[d] := h; 5476 inc(d); 5477 end; 5478 end; 5479 5480 procedure TSuperAvlIterator.First; 5481 var 5482 h: TSuperAvlEntry; 5483 begin 5484 h := FTree.FRoot; 5485 FDepth := not 0; 5486 FBranch := []; 5487 while (h <> nil) do 5488 begin 5489 if (FDepth <> not 0) then 5490 FPath[FDepth] := h; 5491 inc(FDepth); 5492 h := h.FLt; 5493 end; 5494 end; 5495 5496 procedure TSuperAvlIterator.Last; 5497 var 5498 h: TSuperAvlEntry; 5499 begin 5500 h := FTree.FRoot; 5501 FDepth := not 0; 5502 FBranch := [0..SUPER_AVL_MAX_DEPTH - 1]; 5503 while (h <> nil) do 5504 begin 5505 if (FDepth <> not 0) then 5506 FPath[FDepth] := h; 5507 inc(FDepth); 5508 h := h.FGt; 5509 end; 5510 end; 5511 5512 function TSuperAvlIterator.MoveNext: boolean; 5513 begin 5514 if FDepth = not 0 then 5515 First else 5516 Next; 5517 Result := GetIter <> nil; 5518 end; 5519 5520 function TSuperAvlIterator.GetIter: TSuperAvlEntry; 5521 begin 5522 if (FDepth = not 0) then 5523 begin 5524 result := nil; 5525 exit; 5526 end; 5527 if FDepth = 0 then 5528 Result := FTree.FRoot else 5529 Result := FPath[FDepth - 1]; 5530 end; 5531 5532 procedure TSuperAvlIterator.Next; 5533 var 5534 h: TSuperAvlEntry; 5535 begin 5536 if (FDepth <> not 0) then 5537 begin 5538 if FDepth = 0 then 5539 h := FTree.FRoot.FGt else 5540 h := FPath[FDepth - 1].FGt; 5541 5542 if (h = nil) then 5543 repeat 5544 if (FDepth = 0) then 5545 begin 5546 FDepth := not 0; 5547 break; 5548 end; 5549 dec(FDepth); 5550 until (not (FDepth in FBranch)) 5551 else 5552 begin 5553 include(FBranch, FDepth); 5554 FPath[FDepth] := h; 5555 inc(FDepth); 5556 while true do 5557 begin 5558 h := h.FLt; 5559 if (h = nil) then 5560 break; 5561 exclude(FBranch, FDepth); 5562 FPath[FDepth] := h; 5563 inc(FDepth); 5564 end; 5565 end; 5566 end; 5567 end; 5568 5569 procedure TSuperAvlIterator.Prior; 5570 var 5571 h: TSuperAvlEntry; 5572 begin 5573 if (FDepth <> not 0) then 5574 begin 5575 if FDepth = 0 then 5576 h := FTree.FRoot.FLt else 5577 h := FPath[FDepth - 1].FLt; 5578 if (h = nil) then 5579 repeat 5580 if (FDepth = 0) then 5581 begin 5582 FDepth := not 0; 5583 break; 5584 end; 5585 dec(FDepth); 5586 until (FDepth in FBranch) 5587 else 5588 begin 5589 exclude(FBranch, FDepth); 5590 FPath[FDepth] := h; 5591 inc(FDepth); 5592 while true do 5593 begin 5594 h := h.FGt; 5595 if (h = nil) then 5596 break; 5597 include(FBranch, FDepth); 5598 FPath[FDepth] := h; 5599 inc(FDepth); 5600 end; 5601 end; 5602 end; 5603 end; 5604 5605 procedure TSuperAvlTree.doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); 5606 begin 5607 Entry.Free; 5608 end; 5609 5610 function TSuperAvlTree.GetEnumerator: TSuperAvlIterator; 5611 begin 5612 Result := TSuperAvlIterator.Create(Self); 5613 end; 5614 5615 { TSuperAvlEntry } 5616 5617 constructor TSuperAvlEntry.Create(const AName: SOString; Obj: Pointer); 5618 begin 5619 FName := AName; 5620 FPtr := Obj; 5621 FHash := Hash(FName); 5622 end; 5623 5624 function TSuperAvlEntry.GetValue: ISuperObject; 5625 begin 5626 Result := ISuperObject(FPtr) 5627 end; 5628 5629 {$UNDEF SaveQ} {$IFOPT Q+} {$Q-} {$DEFINE SaveQ} {$ENDIF} 5630 class function TSuperAvlEntry.Hash(const k: SOString): Cardinal; 5631 var 5632 h: cardinal; 5633 i: Integer; 5634 begin 5635 h := 0; 5636 //{$Q-} 5637 5638 for i := 1 to Length(k) do 5639 h := h*129 + ord(k[i]) + $9e370001; 5640 //{$Q+} 5641 Result := h; 5642 end; 5643 {$IFDEF SaveQ} {$Q+} {$UNDEF SaveQ} {$ENDIF} 5644 5645 procedure TSuperAvlEntry.SetValue(const val: ISuperObject); 5646 begin 5647 ISuperObject(FPtr) := val; 5648 end; 5649 5650 { TSuperTableString } 5651 5652 function TSuperTableString.GetValues: ISuperObject; 5653 var 5654 ite: TSuperAvlIterator; 5655 obj: TSuperAvlEntry; 5656 begin 5657 Result := TSuperObject.Create(stArray); 5658 ite := TSuperAvlIterator.Create(Self); 5659 try 5660 ite.First; 5661 obj := ite.GetIter; 5662 while obj <> nil do 5663 begin 5664 Result.AsArray.Add(obj.Value); 5665 ite.Next; 5666 obj := ite.GetIter; 5667 end; 5668 finally 5669 ite.Free; 5670 end; 5671 end; 5672 5673 function TSuperTableString.GetNames: ISuperObject; 5674 var 5675 ite: TSuperAvlIterator; 5676 obj: TSuperAvlEntry; 5677 begin 5678 Result := TSuperObject.Create(stArray); 5679 ite := TSuperAvlIterator.Create(Self); 5680 try 5681 ite.First; 5682 obj := ite.GetIter; 5683 while obj <> nil do 5684 begin 5685 Result.AsArray.Add(TSuperObject.Create(obj.FName)); 5686 ite.Next; 5687 obj := ite.GetIter; 5688 end; 5689 finally 5690 ite.Free; 5691 end; 5692 end; 5693 5694 procedure TSuperTableString.doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); 5695 begin 5696 if Entry.Ptr <> nil then 5697 begin 5698 if all then Entry.Value.Clear(true); 5699 Entry.Value := nil; 5700 end; 5701 inherited; 5702 end; 5703 5704 function TSuperTableString.GetO(const k: SOString): ISuperObject; 5705 var 5706 e: TSuperAvlEntry; 5707 begin 5708 e := Search(k); 5709 if e <> nil then 5710 Result := e.Value else 5711 Result := nil 5712 end; 5713 5714 procedure TSuperTableString.PutO(const k: SOString; const value: ISuperObject); 5715 var 5716 entry: TSuperAvlEntry; 5717 begin 5718 entry := Insert(TSuperAvlEntry.Create(k, Pointer(value))); 5719 if entry.FPtr <> nil then 5720 ISuperObject(entry.FPtr)._AddRef; 5721 end; 5722 5723 procedure TSuperTableString.PutS(const k: SOString; const value: SOString); 5724 begin 5725 PutO(k, TSuperObject.Create(Value)); 5726 end; 5727 5728 function TSuperTableString.GetS(const k: SOString): SOString; 5729 var 5730 obj: ISuperObject; 5731 begin 5732 obj := GetO(k); 5733 if obj <> nil then 5734 Result := obj.AsString else 5735 Result := ''; 5736 end; 5737 5738 procedure TSuperTableString.PutI(const k: SOString; value: SuperInt); 5739 begin 5740 PutO(k, TSuperObject.Create(Value)); 5741 end; 5742 5743 function TSuperTableString.GetI(const k: SOString): SuperInt; 5744 var 5745 obj: ISuperObject; 5746 begin 5747 obj := GetO(k); 5748 if obj <> nil then 5749 Result := obj.AsInteger else 5750 Result := 0; 5751 end; 5752 5753 procedure TSuperTableString.PutD(const k: SOString; value: Double); 5754 begin 5755 PutO(k, TSuperObject.Create(Value)); 5756 end; 5757 5758 procedure TSuperTableString.PutC(const k: SOString; value: Currency); 5759 begin 5760 PutO(k, TSuperObject.CreateCurrency(Value)); 5761 end; 5762 5763 function TSuperTableString.GetC(const k: SOString): Currency; 5764 var 5765 obj: ISuperObject; 5766 begin 5767 obj := GetO(k); 5768 if obj <> nil then 5769 Result := obj.AsCurrency else 5770 Result := 0.0; 5771 end; 5772 5773 function TSuperTableString.GetD(const k: SOString): Double; 5774 var 5775 obj: ISuperObject; 5776 begin 5777 obj := GetO(k); 5778 if obj <> nil then 5779 Result := obj.AsDouble else 5780 Result := 0.0; 5781 end; 5782 5783 procedure TSuperTableString.PutB(const k: SOString; value: Boolean); 5784 begin 5785 PutO(k, TSuperObject.Create(Value)); 5786 end; 5787 5788 function TSuperTableString.GetB(const k: SOString): Boolean; 5789 var 5790 obj: ISuperObject; 5791 begin 5792 obj := GetO(k); 5793 if obj <> nil then 5794 Result := obj.AsBoolean else 5795 Result := False; 5796 end; 5797 5798 {$IFDEF SUPER_METHOD} 5799 procedure TSuperTableString.PutM(const k: SOString; value: TSuperMethod); 5800 begin 5801 PutO(k, TSuperObject.Create(Value)); 5802 end; 5803 {$ENDIF} 5804 5805 {$IFDEF SUPER_METHOD} 5806 function TSuperTableString.GetM(const k: SOString): TSuperMethod; 5807 var 5808 obj: ISuperObject; 5809 begin 5810 obj := GetO(k); 5811 if obj <> nil then 5812 Result := obj.AsMethod else 5813 Result := nil; 5814 end; 5815 {$ENDIF} 5816 5817 procedure TSuperTableString.PutN(const k: SOString; const value: ISuperObject); 5818 begin 5819 if value <> nil then 5820 PutO(k, TSuperObject.Create(stNull)) else 5821 PutO(k, value); 5822 end; 5823 5824 function TSuperTableString.GetN(const k: SOString): ISuperObject; 5825 var 5826 obj: ISuperObject; 5827 begin 5828 obj := GetO(k); 5829 if obj <> nil then 5830 Result := obj else 5831 Result := TSuperObject.Create(stNull); 5832 end; 5833 5834 5835 {$IFDEF VER210} 5836 5837 { TSuperAttribute } 5838 5839 constructor TSuperAttribute.Create(const AName: string); 5840 begin 5841 FName := AName; 5842 end; 5843 5844 { TSuperRttiContext } 5845 5846 constructor TSuperRttiContext.Create; 5847 begin 5848 Context := TRttiContext.Create; 5849 SerialFromJson := TDictionary<PTypeInfo, TSerialFromJson>.Create; 5850 SerialToJson := TDictionary<PTypeInfo, TSerialToJson>.Create; 5851 5852 SerialFromJson.Add(TypeInfo(Boolean), serialfromboolean); 5853 SerialFromJson.Add(TypeInfo(TDateTime), serialfromdatetime); 5854 SerialFromJson.Add(TypeInfo(TGUID), serialfromguid); 5855 SerialToJson.Add(TypeInfo(Boolean), serialtoboolean); 5856 SerialToJson.Add(TypeInfo(TDateTime), serialtodatetime); 5857 SerialToJson.Add(TypeInfo(TGUID), serialtoguid); 5858 end; 5859 5860 destructor TSuperRttiContext.Destroy; 5861 begin 5862 SerialFromJson.Free; 5863 SerialToJson.Free; 5864 Context.Free; 5865 end; 5866 5867 class function TSuperRttiContext.GetFieldName(r: TRttiField): string; 5868 var 5869 o: TCustomAttribute; 5870 begin 5871 for o in r.GetAttributes do 5872 if o is SOName then 5873 Exit(SOName(o).Name); 5874 Result := r.Name; 5875 end; 5876 5877 class function TSuperRttiContext.GetFieldDefault(r: TRttiField; const obj: ISuperObject): ISuperObject; 5878 var 5879 o: TCustomAttribute; 5880 begin 5881 if not ObjectIsType(obj, stNull) then Exit(obj); 5882 for o in r.GetAttributes do 5883 if o is SODefault then 5884 Exit(SO(SODefault(o).Name)); 5885 Result := obj; 5886 end; 5887 5888 function TSuperRttiContext.AsType<T>(const obj: ISuperObject): T; 5889 var 5890 ret: TValue; 5891 begin 5892 if FromJson(TypeInfo(T), obj, ret) then 5893 Result := ret.AsType<T> else 5894 raise exception.Create('Marshalling error'); 5895 end; 5896 5897 function TSuperRttiContext.AsJson<T>(const obj: T; const index: ISuperObject = nil): ISuperObject; 5898 var 5899 v: TValue; 5900 begin 5901 TValue.MakeWithoutCopy(@obj, TypeInfo(T), v); 5902 if index <> nil then 5903 Result := ToJson(v, index) else 5904 Result := ToJson(v, so); 5905 end; 5906 5907 function TSuperRttiContext.FromJson(TypeInfo: PTypeInfo; const obj: ISuperObject; 5908 var Value: TValue): Boolean; 5909 5910 procedure FromChar; 5911 begin 5912 if ObjectIsType(obj, stString) and (Length(obj.AsString) = 1) then 5913 begin 5914 Value := string(AnsiString(obj.AsString)[1]); 5915 Result := True; 5916 end else 5917 Result := False; 5918 end; 5919 5920 procedure FromWideChar; 5921 begin 5922 if ObjectIsType(obj, stString) and (Length(obj.AsString) = 1) then 5923 begin 5924 Value := obj.AsString[1]; 5925 Result := True; 5926 end else 5927 Result := False; 5928 end; 5929 5930 procedure FromInt64; 5931 var 5932 i: Int64; 5933 begin 5934 case ObjectGetType(obj) of 5935 stInt: 5936 begin 5937 TValue.Make(nil, TypeInfo, Value); 5938 TValueData(Value).FAsSInt64 := obj.AsInteger; 5939 Result := True; 5940 end; 5941 stString: 5942 begin 5943 if TryStrToInt64(obj.AsString, i) then 5944 begin 5945 TValue.Make(nil, TypeInfo, Value); 5946 TValueData(Value).FAsSInt64 := i; 5947 Result := True; 5948 end else 5949 Result := False; 5950 end; 5951 else 5952 Result := False; 5953 end; 5954 end; 5955 5956 procedure FromInt(const obj: ISuperObject); 5957 var 5958 TypeData: PTypeData; 5959 i: Integer; 5960 o: ISuperObject; 5961 begin 5962 case ObjectGetType(obj) of 5963 stInt, stBoolean: 5964 begin 5965 i := obj.AsInteger; 5966 TypeData := GetTypeData(TypeInfo); 5967 Result := (i >= TypeData.MinValue) and (i <= TypeData.MaxValue); 5968 if Result then 5969 TValue.Make(@i, TypeInfo, Value); 5970 end; 5971 stString: 5972 begin 5973 o := SO(obj.AsString); 5974 if not ObjectIsType(o, stString) then 5975 FromInt(o) else 5976 Result := False; 5977 end; 5978 else 5979 Result := False; 5980 end; 5981 end; 5982 5983 procedure fromSet; 5984 begin 5985 if ObjectIsType(obj, stInt) then 5986 begin 5987 TValue.Make(nil, TypeInfo, Value); 5988 TValueData(Value).FAsSLong := obj.AsInteger; 5989 Result := True; 5990 end else 5991 Result := False; 5992 end; 5993 5994 procedure FromFloat(const obj: ISuperObject); 5995 var 5996 o: ISuperObject; 5997 begin 5998 case ObjectGetType(obj) of 5999 stInt, stDouble, stCurrency: 6000 begin 6001 TValue.Make(nil, TypeInfo, Value); 6002 case GetTypeData(TypeInfo).FloatType of 6003 ftSingle: TValueData(Value).FAsSingle := obj.AsDouble; 6004 ftDouble: TValueData(Value).FAsDouble := obj.AsDouble; 6005 ftExtended: TValueData(Value).FAsExtended := obj.AsDouble; 6006 ftComp: TValueData(Value).FAsSInt64 := obj.AsInteger; 6007 ftCurr: TValueData(Value).FAsCurr := obj.AsCurrency; 6008 end; 6009 Result := True; 6010 end; 6011 stString: 6012 begin 6013 o := SO(obj.AsString); 6014 if not ObjectIsType(o, stString) then 6015 FromFloat(o) else 6016 Result := False; 6017 end 6018 else 6019 Result := False; 6020 end; 6021 end; 6022 6023 procedure FromString; 6024 begin 6025 case ObjectGetType(obj) of 6026 stObject, stArray: 6027 Result := False; 6028 stnull: 6029 begin 6030 Value := ''; 6031 Result := True; 6032 end; 6033 else 6034 Value := obj.AsString; 6035 Result := True; 6036 end; 6037 end; 6038 6039 procedure FromClass; 6040 var 6041 f: TRttiField; 6042 v: TValue; 6043 begin 6044 case ObjectGetType(obj) of 6045 stObject: 6046 begin 6047 Result := True; 6048 if Value.Kind <> tkClass then 6049 Value := GetTypeData(TypeInfo).ClassType.Create; 6050 for f in Context.GetType(Value.AsObject.ClassType).GetFields do 6051 if f.FieldType <> nil then 6052 begin 6053 Result := FromJson(f.FieldType.Handle, GetFieldDefault(f, obj.AsObject[GetFieldName(f)]), v); 6054 if Result then 6055 f.SetValue(Value.AsObject, v) else 6056 Exit; 6057 end; 6058 end; 6059 stNull: 6060 begin 6061 Value := nil; 6062 Result := True; 6063 end 6064 else 6065 // error 6066 Value := nil; 6067 Result := False; 6068 end; 6069 end; 6070 6071 procedure FromRecord; 6072 var 6073 f: TRttiField; 6074 p: Pointer; 6075 v: TValue; 6076 begin 6077 Result := True; 6078 TValue.Make(nil, TypeInfo, Value); 6079 for f in Context.GetType(TypeInfo).GetFields do 6080 begin 6081 if ObjectIsType(obj, stObject) and (f.FieldType <> nil) then 6082 begin 6083 p := IValueData(TValueData(Value).FHeapData).GetReferenceToRawData; 6084 Result := FromJson(f.FieldType.Handle, GetFieldDefault(f, obj.AsObject[GetFieldName(f)]), v); 6085 if Result then 6086 f.SetValue(p, v) else 6087 Exit; 6088 end else 6089 begin 6090 Result := False; 6091 Exit; 6092 end; 6093 end; 6094 end; 6095 6096 procedure FromDynArray; 6097 var 6098 i: Integer; 6099 p: Pointer; 6100 pb: PByte; 6101 val: TValue; 6102 typ: PTypeData; 6103 el: PTypeInfo; 6104 begin 6105 case ObjectGetType(obj) of 6106 stArray: 6107 begin 6108 i := obj.AsArray.Length; 6109 p := nil; 6110 DynArraySetLength(p, TypeInfo, 1, @i); 6111 pb := p; 6112 typ := GetTypeData(TypeInfo); 6113 if typ.elType <> nil then 6114 el := typ.elType^ else 6115 el := typ.elType2^; 6116 6117 Result := True; 6118 for i := 0 to i - 1 do 6119 begin 6120 Result := FromJson(el, obj.AsArray[i], val); 6121 if not Result then 6122 Break; 6123 val.ExtractRawData(pb); 6124 val := TValue.Empty; 6125 Inc(pb, typ.elSize); 6126 end; 6127 if Result then 6128 TValue.MakeWithoutCopy(@p, TypeInfo, Value) else 6129 DynArrayClear(p, TypeInfo); 6130 end; 6131 stNull: 6132 begin 6133 TValue.MakeWithoutCopy(nil, TypeInfo, Value); 6134 Result := True; 6135 end; 6136 else 6137 i := 1; 6138 p := nil; 6139 DynArraySetLength(p, TypeInfo, 1, @i); 6140 pb := p; 6141 typ := GetTypeData(TypeInfo); 6142 if typ.elType <> nil then 6143 el := typ.elType^ else 6144 el := typ.elType2^; 6145 6146 Result := FromJson(el, obj, val); 6147 val.ExtractRawData(pb); 6148 val := TValue.Empty; 6149 6150 if Result then 6151 TValue.MakeWithoutCopy(@p, TypeInfo, Value) else 6152 DynArrayClear(p, TypeInfo); 6153 end; 6154 end; 6155 6156 procedure FromArray; 6157 var 6158 ArrayData: PArrayTypeData; 6159 idx: Integer; 6160 function ProcessDim(dim: Byte; const o: ISuperobject): Boolean; 6161 var 6162 i: Integer; 6163 v: TValue; 6164 a: PTypeData; 6165 begin 6166 if ObjectIsType(o, stArray) and (ArrayData.Dims[dim-1] <> nil) then 6167 begin 6168 a := @GetTypeData(ArrayData.Dims[dim-1]^).ArrayData; 6169 if (a.MaxValue - a.MinValue + 1) <> o.AsArray.Length then 6170 begin 6171 Result := False; 6172 Exit; 6173 end; 6174 Result := True; 6175 if dim = ArrayData.DimCount then 6176 for i := a.MinValue to a.MaxValue do 6177 begin 6178 Result := FromJson(ArrayData.ElType^, o.AsArray[i], v); 6179 if not Result then 6180 Exit; 6181 Value.SetArrayElement(idx, v); 6182 inc(idx); 6183 end 6184 else 6185 for i := a.MinValue to a.MaxValue do 6186 begin 6187 Result := ProcessDim(dim + 1, o.AsArray[i]); 6188 if not Result then 6189 Exit; 6190 end; 6191 end else 6192 Result := False; 6193 end; 6194 var 6195 i: Integer; 6196 v: TValue; 6197 begin 6198 TValue.Make(nil, TypeInfo, Value); 6199 ArrayData := @GetTypeData(TypeInfo).ArrayData; 6200 idx := 0; 6201 if ArrayData.DimCount = 1 then 6202 begin 6203 if ObjectIsType(obj, stArray) and (obj.AsArray.Length = ArrayData.ElCount) then 6204 begin 6205 Result := True; 6206 for i := 0 to ArrayData.ElCount - 1 do 6207 begin 6208 Result := FromJson(ArrayData.ElType^, obj.AsArray[i], v); 6209 if not Result then 6210 Exit; 6211 Value.SetArrayElement(idx, v); 6212 v := TValue.Empty; 6213 inc(idx); 6214 end; 6215 end else 6216 Result := False; 6217 end else 6218 Result := ProcessDim(1, obj); 6219 end; 6220 6221 procedure FromClassRef; 6222 var 6223 r: TRttiType; 6224 begin 6225 if ObjectIsType(obj, stString) then 6226 begin 6227 r := Context.FindType(obj.AsString); 6228 if r <> nil then 6229 begin 6230 Value := TRttiInstanceType(r).MetaclassType; 6231 Result := True; 6232 end else 6233 Result := False; 6234 end else 6235 Result := False; 6236 end; 6237 6238 procedure FromUnknown; 6239 begin 6240 case ObjectGetType(obj) of 6241 stBoolean: 6242 begin 6243 Value := obj.AsBoolean; 6244 Result := True; 6245 end; 6246 stDouble: 6247 begin 6248 Value := obj.AsDouble; 6249 Result := True; 6250 end; 6251 stCurrency: 6252 begin 6253 Value := obj.AsCurrency; 6254 Result := True; 6255 end; 6256 stInt: 6257 begin 6258 Value := obj.AsInteger; 6259 Result := True; 6260 end; 6261 stString: 6262 begin 6263 Value := obj.AsString; 6264 Result := True; 6265 end 6266 else 6267 Value := nil; 6268 Result := False; 6269 end; 6270 end; 6271 6272 procedure FromInterface; 6273 const soguid: TGuid = '{4B86A9E3-E094-4E5A-954A-69048B7B6327}'; 6274 var 6275 o: ISuperObject; 6276 begin 6277 if CompareMem(@GetTypeData(TypeInfo).Guid, @soguid, SizeOf(TGUID)) then 6278 begin 6279 if obj <> nil then 6280 TValue.Make(@obj, TypeInfo, Value) else 6281 begin 6282 o := TSuperObject.Create(stNull); 6283 TValue.Make(@o, TypeInfo, Value); 6284 end; 6285 Result := True; 6286 end else 6287 Result := False; 6288 end; 6289 var 6290 Serial: TSerialFromJson; 6291 begin 6292 if TypeInfo <> nil then 6293 begin 6294 if not SerialFromJson.TryGetValue(TypeInfo, Serial) then 6295 case TypeInfo.Kind of 6296 tkChar: FromChar; 6297 tkInt64: FromInt64; 6298 tkEnumeration, tkInteger: FromInt(obj); 6299 tkSet: fromSet; 6300 tkFloat: FromFloat(obj); 6301 tkString, tkLString, tkUString, tkWString: FromString; 6302 tkClass: FromClass; 6303 tkMethod: ; 6304 tkWChar: FromWideChar; 6305 tkRecord: FromRecord; 6306 tkPointer: ; 6307 tkInterface: FromInterface; 6308 tkArray: FromArray; 6309 tkDynArray: FromDynArray; 6310 tkClassRef: FromClassRef; 6311 else 6312 FromUnknown 6313 end else 6314 begin 6315 TValue.Make(nil, TypeInfo, Value); 6316 Result := Serial(Self, obj, Value); 6317 end; 6318 end else 6319 Result := False; 6320 end; 6321 6322 function TSuperRttiContext.ToJson(var value: TValue; const index: ISuperObject): ISuperObject; 6323 procedure ToInt64; 6324 begin 6325 Result := TSuperObject.Create(SuperInt(Value.AsInt64)); 6326 end; 6327 6328 procedure ToChar; 6329 begin 6330 Result := TSuperObject.Create(string(Value.AsType<AnsiChar>)); 6331 end; 6332 6333 procedure ToInteger; 6334 begin 6335 Result := TSuperObject.Create(TValueData(Value).FAsSLong); 6336 end; 6337 6338 procedure ToFloat; 6339 begin 6340 case Value.TypeData.FloatType of 6341 ftSingle: Result := TSuperObject.Create(TValueData(Value).FAsSingle); 6342 ftDouble: Result := TSuperObject.Create(TValueData(Value).FAsDouble); 6343 ftExtended: Result := TSuperObject.Create(TValueData(Value).FAsExtended); 6344 ftComp: Result := TSuperObject.Create(TValueData(Value).FAsSInt64); 6345 ftCurr: Result := TSuperObject.CreateCurrency(TValueData(Value).FAsCurr); 6346 end; 6347 end; 6348 6349 procedure ToString; 6350 begin 6351 Result := TSuperObject.Create(string(Value.AsType<string>)); 6352 end; 6353 6354 procedure ToClass; 6355 var 6356 o: ISuperObject; 6357 f: TRttiField; 6358 v: TValue; 6359 begin 6360 if TValueData(Value).FAsObject <> nil then 6361 begin 6362 o := index[IntToStr(Integer(Value.AsObject))]; 6363 if o = nil then 6364 begin 6365 Result := TSuperObject.Create(stObject); 6366 index[IntToStr(Integer(Value.AsObject))] := Result; 6367 for f in Context.GetType(Value.AsObject.ClassType).GetFields do 6368 if f.FieldType <> nil then 6369 begin 6370 v := f.GetValue(Value.AsObject); 6371 Result.AsObject[GetFieldName(f)] := ToJson(v, index); 6372 end 6373 end else 6374 Result := o; 6375 end else 6376 Result := nil; 6377 end; 6378 6379 procedure ToWChar; 6380 begin 6381 Result := TSuperObject.Create(string(Value.AsType<WideChar>)); 6382 end; 6383 6384 procedure ToVariant; 6385 begin 6386 Result := SO(Value.AsVariant); 6387 end; 6388 6389 procedure ToRecord; 6390 var 6391 f: TRttiField; 6392 v: TValue; 6393 begin 6394 Result := TSuperObject.Create(stObject); 6395 for f in Context.GetType(Value.TypeInfo).GetFields do 6396 begin 6397 v := f.GetValue(IValueData(TValueData(Value).FHeapData).GetReferenceToRawData); 6398 Result.AsObject[GetFieldName(f)] := ToJson(v, index); 6399 end; 6400 end; 6401 6402 procedure ToArray; 6403 var 6404 idx: Integer; 6405 ArrayData: PArrayTypeData; 6406 6407 procedure ProcessDim(dim: Byte; const o: ISuperObject); 6408 var 6409 dt: PTypeData; 6410 i: Integer; 6411 o2: ISuperObject; 6412 v: TValue; 6413 begin 6414 if ArrayData.Dims[dim-1] = nil then Exit; 6415 dt := GetTypeData(ArrayData.Dims[dim-1]^); 6416 if Dim = ArrayData.DimCount then 6417 for i := dt.MinValue to dt.MaxValue do 6418 begin 6419 v := Value.GetArrayElement(idx); 6420 o.AsArray.Add(toJSon(v, index)); 6421 inc(idx); 6422 end 6423 else 6424 for i := dt.MinValue to dt.MaxValue do 6425 begin 6426 o2 := TSuperObject.Create(stArray); 6427 o.AsArray.Add(o2); 6428 ProcessDim(dim + 1, o2); 6429 end; 6430 end; 6431 var 6432 i: Integer; 6433 v: TValue; 6434 begin 6435 Result := TSuperObject.Create(stArray); 6436 ArrayData := @Value.TypeData.ArrayData; 6437 idx := 0; 6438 if ArrayData.DimCount = 1 then 6439 for i := 0 to ArrayData.ElCount - 1 do 6440 begin 6441 v := Value.GetArrayElement(i); 6442 Result.AsArray.Add(toJSon(v, index)) 6443 end 6444 else 6445 ProcessDim(1, Result); 6446 end; 6447 6448 procedure ToDynArray; 6449 var 6450 i: Integer; 6451 v: TValue; 6452 begin 6453 Result := TSuperObject.Create(stArray); 6454 for i := 0 to Value.GetArrayLength - 1 do 6455 begin 6456 v := Value.GetArrayElement(i); 6457 Result.AsArray.Add(toJSon(v, index)); 6458 end; 6459 end; 6460 6461 procedure ToClassRef; 6462 begin 6463 if TValueData(Value).FAsClass <> nil then 6464 Result := TSuperObject.Create(string( 6465 TValueData(Value).FAsClass.UnitName + '.' + 6466 TValueData(Value).FAsClass.ClassName)) else 6467 Result := nil; 6468 end; 6469 6470 procedure ToInterface; 6471 begin 6472 if TValueData(Value).FHeapData <> nil then 6473 TValueData(Value).FHeapData.QueryInterface(ISuperObject, Result) else 6474 Result := nil; 6475 end; 6476 6477 var 6478 Serial: TSerialToJson; 6479 begin 6480 if not SerialToJson.TryGetValue(value.TypeInfo, Serial) then 6481 case Value.Kind of 6482 tkInt64: ToInt64; 6483 tkChar: ToChar; 6484 tkSet, tkInteger, tkEnumeration: ToInteger; 6485 tkFloat: ToFloat; 6486 tkString, tkLString, tkUString, tkWString: ToString; 6487 tkClass: ToClass; 6488 tkWChar: ToWChar; 6489 tkVariant: ToVariant; 6490 tkRecord: ToRecord; 6491 tkArray: ToArray; 6492 tkDynArray: ToDynArray; 6493 tkClassRef: ToClassRef; 6494 tkInterface: ToInterface; 6495 else 6496 result := nil; 6497 end else 6498 Result := Serial(Self, value, index); 6499 end; 6500 6501 { TSuperObjectHelper } 6502 6503 constructor TSuperObjectHelper.FromJson(const obj: ISuperObject; ctx: TSuperRttiContext = nil); 6504 var 6505 v: TValue; 6506 ctxowned: Boolean; 6507 begin 6508 if ctx = nil then 6509 begin 6510 ctx := TSuperRttiContext.Create; 6511 ctxowned := True; 6512 end else 6513 ctxowned := False; 6514 try 6515 v := Self; 6516 if not ctx.FromJson(v.TypeInfo, obj, v) then 6517 raise Exception.Create('Invalid object'); 6518 finally 6519 if ctxowned then 6520 ctx.Free; 6521 end; 6522 end; 6523 6524 constructor TSuperObjectHelper.FromJson(const str: string; ctx: TSuperRttiContext = nil); 6525 begin 6526 FromJson(SO(str), ctx); 6527 end; 6528 6529 function TSuperObjectHelper.ToJson(ctx: TSuperRttiContext = nil): ISuperObject; 6530 var 6531 v: TValue; 6532 ctxowned: boolean; 6533 begin 6534 if ctx = nil then 6535 begin 6536 ctx := TSuperRttiContext.Create; 6537 ctxowned := True; 6538 end else 6539 ctxowned := False; 6540 try 6541 v := Self; 6542 Result := ctx.ToJson(v, SO); 6543 finally 6544 if ctxowned then 6545 ctx.Free; 6546 end; 6547 end; 6548 6549 {$ENDIF} 6550 6551 {$IFDEF DEBUG} 6552 initialization 6553 6554 finalization 6555 Assert(debugcount = 0, 'Memory leak'); 6556 {$ENDIF} 6557 end.View Code