From fc3934bcb78f6feee79843d1ad8a30a07f52d94b Mon Sep 17 00:00:00 2001 From: andot Date: Sat, 5 Jan 2013 11:58:21 +0800 Subject: [PATCH] Dealing with line endings --- .gitattributes | 22 + .gitignore | 22 +- README.md | 92 +- bin/1.3/asp/hprose.js | 6 +- bin/1.3/asp/hproseClient.js | 6 +- bin/1.3/asp/hproseServer.js | 6 +- bin/1.3/java/hprose_for_cldc_1.0.jad | 14 +- bin/1.3/java/hprose_for_cldc_1.1.jad | 14 +- bin/1.3/java/hprose_for_cldc_1.1_ext.jad | 14 +- bin/1.3/javascript/hprose.js | 6 +- src/aauto/hprose/_.aau | 6 +- src/aauto/hprose/client.aau | 684 +- src/aauto/hprose/common.aau | 76 +- src/aauto/hprose/io.aau | 2474 +++--- src/actionscript/as2/hprose/HproseLoader.as | 114 +- .../as2/hprose/client/HproseFilter.as | 56 +- .../as2/hprose/client/HproseHttpClient.as | 470 +- .../as2/hprose/client/HproseHttpInvoker.as | 518 +- .../as2/hprose/client/HproseHttpRequest.as | 216 +- .../as2/hprose/client/IHproseFilter.as | 46 +- .../as2/hprose/io/HproseReader.as | 1108 +-- .../as2/hprose/io/HproseWriter.as | 702 +- src/actionscript/as3/hprose/HproseLoader.as | 112 +- .../as3/hprose/client/HproseFilter.as | 58 +- .../as3/hprose/client/HproseHttpClient.as | 424 +- .../as3/hprose/client/HproseHttpInvoker.as | 374 +- .../as3/hprose/client/HproseHttpRequest.as | 370 +- .../as3/hprose/client/IHproseFilter.as | 52 +- .../as3/hprose/io/ClassManager.as | 216 +- .../as3/hprose/io/HproseReader.as | 1570 ++-- .../as3/hprose/io/HproseWriter.as | 892 +-- src/asp/jscript/hproseCommon.js | 296 +- src/asp/jscript/hproseHttpClient.js | 1262 +-- src/asp/jscript/hproseHttpServer.js | 886 +- src/delphi/Hprose.inc | 234 +- src/delphi/HproseClient.pas | 1552 ++-- src/delphi/HproseCommon.pas | 5294 ++++++------ src/delphi/HproseIO.pas | 6100 +++++++------- src/delphi/HproseSynaHttpClient.pas | 684 +- .../HproseTest/HproseClient/App.config | 10 +- .../HproseClient/HproseClient.csproj | 120 +- .../HproseTest/HproseClient/Program.cs | 96 +- .../HproseTest/HproseServer/App.config | 10 +- .../HproseServer/HproseServer.csproj | 120 +- .../HproseTest/HproseServer/Program.cs | 90 +- .../HproseServer/bin/Debug/crossdomain.xml | 28 +- .../HproseServer/bin/Release/crossdomain.xml | 28 +- src/dotnet/examples/HproseTest/HproseTest.sln | 160 +- .../SilverlightHproseClient/App.xaml | 16 +- .../SilverlightHproseClient/MainPage.xaml | 26 +- .../SilverlightHproseClient/MainPage.xaml.cs | 172 +- .../Properties/AppManifest.xml | 12 +- .../SilverlightHproseClient.csproj | 254 +- .../SilverlightHproseClient.csproj.user | 56 +- .../HproseTest/TestHashMap/App.config | 10 +- .../HproseTest/TestHashMap/Program.cs | 52 +- .../HproseTest/TestHashMap/TestHashMap.csproj | 120 +- .../HproseTest/TestSerialize/Program.cs | 232 +- .../TestSerialize/TestSerialize.csproj | 114 +- src/dotnet/make.bat | 794 +- .../Hprose.Client/4.5/AssemblyInfo.cs | 20 +- .../WindowsPhone8/AssemblyInfo.cs | 20 +- .../AssemblyInfo/Hprose/4.5/AssemblyInfo.cs | 20 +- .../WindowsPhone8/AssemblyInfo.cs | 18 +- src/dotnet/src/Hprose/Client/Extension.cs | 1052 +-- src/dotnet/src/Hprose/Client/HproseClient.cs | 1386 ++-- .../src/Hprose/Client/HproseHttpClient.cs | 760 +- .../Hprose/Common/HproseInvocationHandler.cs | 250 +- src/dotnet/src/Hprose/Common/HproseMethod.cs | 154 +- src/dotnet/src/Hprose/Common/HproseMethods.cs | 850 +- src/dotnet/src/Hprose/Common/IHproseFilter.cs | 52 +- .../src/Hprose/Common/IHproseInvoker.cs | 176 +- src/dotnet/src/Hprose/Common/InvokeHelper.cs | 84 +- src/dotnet/src/Hprose/IO/ClassManager.cs | 150 +- src/dotnet/src/Hprose/IO/HproseHelper.cs | 2526 +++--- src/dotnet/src/Hprose/IO/HproseReader.cs | 7094 ++++++++--------- src/dotnet/src/Hprose/IO/HproseWriter.cs | 3212 ++++---- src/dotnet/src/Hprose/IO/ObjectSerializer.cs | 508 +- .../src/Hprose/IO/ObjectUnserializer.cs | 654 +- src/dotnet/src/Hprose/IO/TypeEnum.cs | 310 +- .../src/Hprose/Reflection/CtorAccessor.cs | 404 +- .../Hprose/Reflection/IInvocationHandler.cs | 56 +- .../src/Hprose/Reflection/PropertyAccessor.cs | 266 +- src/dotnet/src/Hprose/Reflection/Proxy.cs | 972 +-- .../Hprose/Server/HproseHttpListenerServer.cs | 574 +- .../Server/HproseHttpListenerService.cs | 430 +- .../src/Hprose/Server/HproseHttpMethods.cs | 88 +- .../src/Hprose/Server/HproseHttpService.cs | 442 +- src/dotnet/src/Hprose/Server/HproseService.cs | 924 +-- .../src/System/Collections/Generic/HashMap.cs | 1138 +-- src/dotnet/src/System/Collections/HashMap.cs | 546 +- .../src/System/MissingMethodException.cs | 34 +- src/dotnet/src/System/Numerics/BigInteger.cs | 3280 ++++---- src/dotnet/src/System/Numerics/Complex.cs | 648 +- .../src/System/SerializableAttribute.cs | 28 +- .../Threading/SynchronizationContext.cs | 70 +- src/java/j2me/cdc/nbproject/build-impl.xml | 2494 +++--- .../j2me/cdc/nbproject/genfiles.properties | 16 +- .../cdc/nbproject/private/private.properties | 16 +- .../j2me/cdc/nbproject/project.properties | 284 +- .../cdc/src/hprose/client/HproseClient.java | 666 +- .../src/hprose/client/HproseHttpClient.java | 280 +- .../j2me/cdc/src/hprose/io/HproseReader.java | 4564 +++++------ .../j2me/cdc/src/hprose/io/HproseWriter.java | 2142 ++--- src/java/j2me/cldc/1.0/make.bat | 14 +- .../j2me/cldc/1.0/nbproject/build-impl.xml | 2494 +++--- .../cldc/1.0/nbproject/genfiles.properties | 16 +- .../1.0/nbproject/private/private.properties | 18 +- .../cldc/1.0/nbproject/project.properties | 286 +- .../1.0/src/hprose/client/HproseClient.java | 556 +- .../src/hprose/client/HproseHttpClient.java | 276 +- src/java/j2me/cldc/1.1/make.bat | 14 +- .../j2me/cldc/1.1/nbproject/build-impl.xml | 2494 +++--- .../cldc/1.1/nbproject/genfiles.properties | 16 +- .../1.1/nbproject/private/private.properties | 18 +- .../cldc/1.1/nbproject/project.properties | 284 +- .../1.1/src/hprose/client/HproseClient.java | 552 +- .../src/hprose/client/HproseHttpClient.java | 276 +- src/java/j2me/cldc/1.1ext/make.bat | 14 +- .../j2me/cldc/1.1ext/nbproject/build-impl.xml | 2494 +++--- .../cldc/1.1ext/nbproject/genfiles.properties | 16 +- .../nbproject/private/private.properties | 18 +- .../cldc/1.1ext/nbproject/project.properties | 284 +- .../src/hprose/client/HproseClient.java | 552 +- .../src/hprose/client/HproseHttpClient.java | 278 +- src/java/java2/make.bat | 20 +- src/java/java2/nbproject/build-impl.xml | 2822 +++---- src/java/java2/nbproject/genfiles.properties | 16 +- .../nbproject/private/private.properties | 14 +- .../java2/src/hprose/client/HproseClient.java | 664 +- .../src/hprose/client/HproseHttpClient.java | 430 +- .../java2/src/hprose/io/HproseReader.java | 4744 +++++------ .../java2/src/hprose/io/HproseWriter.java | 2294 +++--- .../src/hprose/server/HproseHttpService.java | 356 +- .../src/hprose/server/HproseService.java | 946 +-- src/java/java5/make.bat | 52 +- src/java/java5/nbproject/build-impl.xml | 2854 +++---- src/java/java5/nbproject/genfiles.properties | 16 +- .../nbproject/private/private.properties | 12 +- src/java/java5/nbproject/private/private.xml | 8 +- src/java/java5/nbproject/project.properties | 168 +- src/java/java5/nbproject/project.xml | 28 +- .../java5/src/hprose/client/HproseClient.java | 742 +- .../src/hprose/client/HproseHttpClient.java | 424 +- .../src/hprose/common/HproseMethods.java | 680 +- .../java5/src/hprose/io/FieldAccessor.java | 96 +- .../java5/src/hprose/io/HproseFormatter.java | 352 +- .../java5/src/hprose/io/HproseHelper.java | 1166 +-- .../java5/src/hprose/io/HproseReader.java | 4616 +++++------ .../java5/src/hprose/io/HproseWriter.java | 2930 +++---- .../java5/src/hprose/io/MemberAccessor.java | 68 +- .../java5/src/hprose/io/ObjectIntMap.java | 346 +- .../java5/src/hprose/io/PropertyAccessor.java | 104 +- src/java/java5/src/hprose/io/TypeCode.java | 424 +- .../src/hprose/server/HproseService.java | 960 +-- src/javascript/hproseCommon.js | 74 +- src/javascript/hproseHttpClient.js | 760 +- src/javascript/hproseHttpRequest.js | 788 +- src/javascript/hproseIO.js | 1998 ++--- src/nodejs/hprose/README.md | 122 +- src/nodejs/hprose/client/HproseClient.js | 474 +- src/nodejs/hprose/client/HproseHttpClient.js | 434 +- src/nodejs/hprose/common/HproseException.js | 42 +- src/nodejs/hprose/common/HproseFilter.js | 52 +- src/nodejs/hprose/common/HproseResultMode.js | 56 +- src/nodejs/hprose/example/client.js | 46 +- src/nodejs/hprose/example/crossdomain.xml | 28 +- src/nodejs/hprose/example/serialize.js | 84 +- src/nodejs/hprose/example/server.js | 38 +- src/nodejs/hprose/hprose.js | 90 +- src/nodejs/hprose/io/ClassManager.js | 80 +- src/nodejs/hprose/io/ClassManager2.js | 78 +- .../hprose/io/HproseBufferInputStream.js | 206 +- .../hprose/io/HproseBufferOutputStream.js | 158 +- src/nodejs/hprose/io/HproseFormatter.js | 80 +- src/nodejs/hprose/io/HproseReader.js | 992 +-- src/nodejs/hprose/io/HproseTags.js | 122 +- src/nodejs/hprose/io/HproseWriter.js | 798 +- src/nodejs/hprose/io/HproseWriter2.js | 806 +- src/nodejs/hprose/package.json | 34 +- src/nodejs/hprose/server/HproseHttpServer.js | 82 +- src/nodejs/hprose/server/HproseHttpService.js | 404 +- src/nodejs/hprose/server/HproseService.js | 700 +- src/objc/src/HproseHelper.m | 778 +- src/objc/src/HproseReader.m | 3314 ++++---- src/objc/src/HproseWriter.m | 1746 ++-- src/perl/Hprose/ClassManager.pm | 144 +- src/perl/Hprose/Exception.pm | 76 +- src/perl/Hprose/Filter.pm | 66 +- src/perl/Hprose/Formatter.pm | 56 +- src/perl/Hprose/Numeric.pm | 118 +- src/perl/Hprose/Reader.pm | 1574 ++-- src/perl/Hprose/ResultMode.pm | 64 +- src/perl/Hprose/Tags.pm | 130 +- src/perl/Hprose/Writer.pm | 820 +- src/php/php5/HproseHttpClient.php | 558 +- src/php/php5/HproseHttpServer.php | 946 +-- src/php/php5_curl/HproseHttpClient.php | 614 +- src/php/php5_curl/HproseHttpServer.php | 946 +-- src/php/php5_sae/HproseHttpClient.php | 554 +- src/php/php5_sae/HproseHttpServer.php | 946 +-- src/python/py23/src/hprose/client.py | 362 +- src/python/py23/src/hprose/common.py | 68 +- src/python/py23/src/hprose/httpclient.py | 796 +- src/python/py23/src/hprose/httpserver.py | 622 +- src/python/py23/src/hprose/io.py | 1606 ++-- src/python/py23/src/hprose/server.py | 662 +- src/python/py3k/src/hprose/client.py | 358 +- src/python/py3k/src/hprose/common.py | 68 +- src/python/py3k/src/hprose/httpclient.py | 754 +- src/python/py3k/src/hprose/httpserver.py | 622 +- src/python/py3k/src/hprose/io.py | 1550 ++-- src/python/py3k/src/hprose/server.py | 646 +- src/ruby/gem.spec | 58 +- src/ruby/lib/hprose.rb | 94 +- src/ruby/lib/hprose/client.rb | 328 +- src/ruby/lib/hprose/common.rb | 80 +- src/ruby/lib/hprose/httpclient.rb | 332 +- src/ruby/lib/hprosecommon.rb | 58 +- src/ruby/lib/hproseio.rb | 66 +- 220 files changed, 70388 insertions(+), 70366 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index bcee98f..6f6df48 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,12 @@ -/src/java/j2me/cdc/build/ -/src/java/j2me/cdc/dist/ -/src/java/j2me/cldc/1.0/dist/ -/src/java/j2me/cldc/1.0/build/ -/src/java/j2me/cldc/1.1/build/ -/src/java/j2me/cldc/1.1/dist/ -/src/java/j2me/cldc/1.1ext/build/ -/src/java/j2me/cldc/1.1ext/dist/ -/src/java/java2/build/ -/src/java/java2/dist/ -/src/java/java5/dist/ +/src/java/j2me/cdc/build/ +/src/java/j2me/cdc/dist/ +/src/java/j2me/cldc/1.0/dist/ +/src/java/j2me/cldc/1.0/build/ +/src/java/j2me/cldc/1.1/build/ +/src/java/j2me/cldc/1.1/dist/ +/src/java/j2me/cldc/1.1ext/build/ +/src/java/j2me/cldc/1.1ext/dist/ +/src/java/java2/build/ +/src/java/java2/dist/ +/src/java/java5/dist/ /src/java/java5/build/ \ No newline at end of file diff --git a/README.md b/README.md index e9088d9..e3b8643 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,46 @@ -Hprose -=============== - -*Hprose* is a High Performance Remote Object Service Engine. - -It is a modern, lightweight, cross-language, cross-platform, object-oriented, -high performance, remote dynamic communication middleware. It is not only easy to -use, but powerful. You just need a little time to learn, then you can use it to -easily construct cross language cross platform distributed application system. - -Language support ----------------- - -*Hprose* supports many programming languages, for example: - - * C++ - * .NET(C#, Visual Basic...) - * Java - * Delphi/Free Pascal - * Objective-C - * ActionScript - * JavaScript - * Node.js - * Python - * Ruby - * PHP - * ASP - * Perl - * AAuto Quicker - * ... - -Through *Hprose*, You can conveniently and efficiently intercommunicate between those -programming languages. - -License -------- - -*Hprose* is free software, available with full source. You may use *hprose* under the terms of the MIT License. - -The MIT License is simple and easy to understand and it places almost no restrictions on what you can do with *hprose*. - -You are free to use *hprose* in commercial projects as long as the copyright header is left intact. - - - - +Hprose +=============== + +*Hprose* is a High Performance Remote Object Service Engine. + +It is a modern, lightweight, cross-language, cross-platform, object-oriented, +high performance, remote dynamic communication middleware. It is not only easy to +use, but powerful. You just need a little time to learn, then you can use it to +easily construct cross language cross platform distributed application system. + +Language support +---------------- + +*Hprose* supports many programming languages, for example: + + * C++ + * .NET(C#, Visual Basic...) + * Java + * Delphi/Free Pascal + * Objective-C + * ActionScript + * JavaScript + * Node.js + * Python + * Ruby + * PHP + * ASP + * Perl + * AAuto Quicker + * ... + +Through *Hprose*, You can conveniently and efficiently intercommunicate between those +programming languages. + +License +------- + +*Hprose* is free software, available with full source. You may use *hprose* under the terms of the MIT License. + +The MIT License is simple and easy to understand and it places almost no restrictions on what you can do with *hprose*. + +You are free to use *hprose* in commercial projects as long as the copyright header is left intact. + + + + diff --git a/bin/1.3/asp/hprose.js b/bin/1.3/asp/hprose.js index 761b1af..90404c2 100644 --- a/bin/1.3/asp/hprose.js +++ b/bin/1.3/asp/hprose.js @@ -1,4 +1,4 @@ -/* - * Compressed by JSA(www.xidea.org) - */ +/* + * Compressed by JSA(www.xidea.org) + */ eval(function(B,D,A,G,E,F){function C(A){return A<62?String.fromCharCode(A+=A<26?65:A<52?71:-4):A<63?'_':A<64?'$':C(A>>6)+C(A&63)}while(A>0)E[C(G--)]=D[--A];return B.replace(/[\w\$]+/g,function(A){return E[A]==F[A]?A:E[A]})}('m Dg={Cg:d,DG:e,Db:f,C_:g};7 Bu(i){p.message=i;p.Dy=i}Bu.B6=n Error;Bu.B6.Ck="Bu";7 D$(){p.D2=7(i){2 i};p.Dc=7(i){2 i}}m C9={DC:7(i){2((i!=t)&&(4(i)=="B8")&&(i instanceof B5)&&(4(i.Da)=="BR")&&(4(i.Exists)=="BR")&&(4(i.ER)=="BR")&&(4(i.DM)=="BR")&&(4(i.Remove)=="BR")&&(4(i.RemoveAll)=="BR")&&(4(i.Count)=="B_")&&(4(i.Item)=="BR")&&(4(i.Key)=="BR"))},Bj:7(i){2((i!=t)&&(4(i)=="BR")&&(i.Br==Cm)&&(4(i.DL)=="7")&&(4(i.Ep)=="7")&&(4(i.Df)=="7")&&(4(i.Cp)=="7")&&(4(i.D6)=="7"))},Do:7(h){m B=(n Cm(h.DM())).Cp(),i={};o(m A=d;AC){E[C]=d;C++}m F=i.Df(C),D=i.D6(C),h=[];o(m G=F;G<=D;G++){E[C-e]=G;j(B==C)h[G]=i.Ep.BS(i,E);r h[G]=A(i,C,E)}2 h}m i=n Cm(h);j(i.DL()==e&&i.Df()==d)2 i.Cp();2 A(i,d,[])},Dq:7(i){2 p.En(i).ER()},Ee:7(h,C){Bt{m D=f,i=e,B=n B5("ADODB.Stream");B.Cs=i;B.Open();B.Write(h);B.Position=d;B.Cs=D;j(C)B.Dx=C;r B.Dx="UTF-Bm";2 B.ReadText()}Bw(A){2""}}};7 C3(i){m A=d,h=i.3;p.u=7(){2 i.CL(A++)};p.w=7(B){m h=i.BC(A,B);p.BG(B);2 h};p.BG=7(i){A+=i};p.CD=7(C){m D=i.BU(C,A),B;j(D!==-e){B=i.BC(A,D-A);A=D+C.3}r{B=i.BC(A);A=h}2 B}}7 CV(i){j(i===9)i="";m h=[i],A=h.3;p.x=7(i){h[A++]=i};p.mark=7(){i=p.BB()};p.BP=7(){h=[i]};p.DK=7(){h=[]};p.BB=7(){2 h.B0("")}}m _={CC:"Be",B$:"Es",CJ:"BX",CZ:"Cj",CF:"Bn",Bh:"Dv",Cc:"b",CG:"N",B9:"I",Ba:"D",BO:"T",B1:"Z",CQ:"Ev",CW:"BE",Cl:"c",Bo:"a",B3:"Et",B7:"BY",CI:"Eu",6:"Dw",EU:"+",DP:"-",$:";",BN:"{",Bx:"}",Bf:"\\"",Bc:".",C2:"F",Bd:"C",Cf:"R",Cd:"A",BW:"E",BA:"Ew"},Ei=n(7(){m i={"BJ":BJ};p.CA=7(h,A){i[A]=h};p.EL=7(h){o(m A l i)j(h===i[A])2 A;2""};p.Ds=7(h){2 i[h]}})(),CE,CS;(7(){7 CH(EX){2 Cz(EX)}(7(){m H=C9,N=_,G=Bu,I=Ei;7 C(B,h){m i=B.3;o(m A=d;A-e){B[B.3]=C;C=A.BU("h",C+e)}j(B.3>d){m h=A.B4("");i=J(h,B,d,".");j(i==t)i=J(h,B,d,"h");j(i!=t){I.CA(i,A);2 i}}i=7(){p.Dm=7(){2 A}};I.CA(i,A);2 i}m A=7(){m i={};o(m h l[])i[h]=s;2 i}(),h=7(){m i={};o(m h l{})i[h]=s;2 i}();7 E(i){Bb(i.BB()){q"d":q"e":q"f":q"g":q"BD":q"Ce":q"Bz":q"Bl":q"Bm":q"BT":2 s}2 y}7 L(i){m h=i.3;o(m A=(i.CL(d)=="-")?e:d;A2147483647))}7 M(i){2(BJ.B6.BB.BS(i)==="[B8 Cx]")}7 D(B){j(B===9||B.Br===9)2"BJ";m i=B.Br,A=I.EL(i);j(A)2 A;m h=i.BB();A=h.BC(d,h.BU("(")).CR(/(^\\BE*7\\BE*)|(\\BE*i)/EE,"");j(A==""||A=="BJ")2(4(B.Dm)=="7")?B.Dm():"BJ";j(A!="BJ")I.CA(i,A);2 A}CE=7 F(D,S){m c=[],Y=[];7 B(h,i){j(i===9)i=D.u();j(i!=h)1 n G("Tag \'"+h+"\' D4, but \'"+i+"\' DT l CU")}7 L(i,h){j(h===9)h=D.u();j(C(i,h)!=-e)2 h;1 n G("\'"+h+"\' CM CT the D4 De")}7 h(h){m i=D.CD(h);j(i.3==d)2 d;2 8(i)}7 X(i){j(i===9)i=D.u();Bb(i){q"d":q"e":q"f":q"g":q"BD":q"Ce":q"Bz":q"Bl":q"Bm":q"BT":2 8(i);q N.CC:2 U(y);q N.B$:2 T(y);q N.CJ:2 b(y);q N.CZ:2 t;q N.CF:2"";q N.Bh:2 s;q N.Cc:2 y;q N.CG:2 EC;q N.B9:2 Bn(y);q N.Ba:2 BL(y);q N.BO:2 V(y);q N.CQ:2 D.u();q N.CW:2 W(y);q N.Cl:2 a(y);q N.Bo:2 P(y);q N.B3:2 BX(y);q N.B7:K();2 X();q N.CI:2 Z(y);q N.6:2 BZ();q _.BW:1 n G(W());q"":1 n G("EB D7 DT l CU");Cb:1 n G("EA Bk De \'"+i+"\' l CU")}}7 U(i){j(i===9)i=s;j(i){m A=D.u();j((A>="d")&&(A<="BT"))2 8(A);B(N.CC,A)}2 h(N.$)}7 T(i){j(i===9)i=s;j(i){m h=D.u();j((h>="d")&&(h<="BT"))2 h;B(N.B$,h)}2 D.CD(N.$)}7 b(i){j(i===9)i=s;j(i){m h=D.u();j((h>="d")&&(h<="BT"))2 D0(h);B(N.CJ,h)}2 D0(D.CD(N.$))}7 I(){B(N.CG);2 EC}7 Bn(i){j(i===9)i=s;j(i)B(N.B9);2((D.u()==N.DP)?-Ea:Ea)}7 BY(){B(N.CZ);2 t}7 E(){B(N.CF);2""}7 O(){m i=L([N.Bh,N.Cc]);2(i==N.Bh)}7 BL(A){j(A===9)A=s;m C;j(A){C=L([N.Ba,N.6]);j(C==N.6)2 BZ()}m F=8(D.w(BD)),E=8(D.w(f))-e,H=8(D.w(f)),I;C=D.u();j(C==N.BO){m G=8(D.w(f)),i=8(D.w(f)),h=8(D.w(f)),B=d;C=D.u();j(C==N.Bc){B=8(D.w(g));C=D.u();j((C>="d")&&(C<="BT")){D.BG(f);C=D.u();j((C>="d")&&(C<="BT")){D.BG(f);C=D.u()}}}j(C==N.B1)I=n v(v.C8(F,E,H,G,i,h,B));r I=n v(F,E,H,G,i,h,B)}r j(C==N.B1)I=n v(v.C8(F,E,H));r I=n v(F,E,H);j(S)I=I.DO();c[c.3]=I;2 I}7 V(B){j(B===9)B=s;m E;j(B){E=L([N.BO,N.6]);j(E==N.6)2 BZ()}m h,F=8(D.w(f)),i=8(D.w(f)),A=8(D.w(f)),C=d;E=D.u();j(E==N.Bc){C=8(D.w(g));E=D.u();j((E>="d")&&(E<="BT")){D.BG(f);E=D.u();j((E>="d")&&(E<="BT")){D.BG(f);E=D.u()}}}j(E==N.B1){j(S)h=n v(v.C8(DJ,EN,DV,F,i,A,C)).DO();r h=n v(v.C8(DU,d,e,F,i,A,C))}r j(S)h=n v(DJ,EN,DV,F,i,A,C).DO();r h=n v(DU,d,e,F,i,A,C);c[c.3]=h;2 h}7 Dt(i){j(i===9)i=s;j(i)B(N.CQ);2 D.u()}7 W(A,C){j(A===9)A=s;j(C===9)C=s;j(A){m B=L([N.CW,N.6]);j(B==N.6)2 BZ()}m i=D.w(h(N.Bf));D.BG(e);j(C)c[c.3]=i;2 i}7 a(h){j(h===9)h=s;j(h){m A=L([N.Cl,N.6]);j(A==N.6)2 BZ()}D.BG(e);m i=D.w(36);D.BG(e);c[c.3]=i;2 i}7 P(A){j(A===9)A=s;j(A){m B=L([N.Bo,N.6]);j(B==N.6)2 BZ()}m E=[],C=c.3;c[C]=E;m i=h(N.BN);o(m F=d;Fd)A=8(i);B.x(D.w(A+e))}7 M(h,i){h.x(i);h.x(D.w(38))}7 A(h,i){h.x(i);Ch{i=D.u();h.x(i)}Bp(i!=_.BN);Bp((i=D.u())!=_.Bx)J(h,i);h.x(i)}7 R(){c.3=d;Y.3=d}p.EM=B;p.Bs=L;p.Cn=X;p.readInteger=U;p.readLong=T;p.readDouble=b;p.readNaN=I;p.readInfinity=Bn;p.readNull=BY;p.readEmpty=E;p.readBoolean=O;p.readDate=BL;p.readTime=V;p.readUTF8Char=Dt;p.Cv=W;p.C5=P;p.readMap=BX;p.readObject=Z;p.D_=J;p.BP=R};CS=7 K(i){m a=[],Y=[];7 W(J){j(4(J)=="date"){I(J);2}r j(H.Bj(J))J=H.Bg(J);r j(H.DC(J)){Q(J);2}r j(J===9||J===t||J.Br==Function){L();2}r j(J===""){BX();2}Bb(J.Br){q Boolean:Bn(J);z;q Number:E(J)?i.x(J):B(J)?V(J):O(J);z;q String:J.3==e?BL(J):BY(J);z;q v:G(J);z;Cb:m h=C(a,J);j(h>-e)b(h);r j(M(J))X(J,y);r{m A=D(J);j(A=="BJ")F(J,y);r R(J,y)}}}7 V(h){i.x(N.CC+h+N.$)}7 P(h){i.x(N.B$+h+N.$)}7 O(h){j(isNaN(h))c();r j(isFinite(h))i.x(N.CJ+h+N.$);r Z(h>d)}7 c(){i.x(N.CG)}7 Z(h){i.x(N.B9+(h?N.EU:N.DP))}7 L(){i.x(N.CZ)}7 BX(){i.x(N.CF)}7 Bn(h){i.x(h?N.Bh:N.Cc)}7 J(J,I){j(I===9)I=s;m F=("DB"+J.getUTCFullYear()).0(-BD),E=("k"+(J.getUTCMonth()+e)).0(-f),H=("k"+J.getUTCDate()).0(-f),G=("k"+J.getUTCHours()).0(-f),h=("k"+J.getUTCMinutes()).0(-f),A=("k"+J.getUTCSeconds()).0(-f),D=("BH"+J.getUTCMilliseconds()).0(-g);J=N.Ba+F+E+H+N.BO+G+h+A;j(D!="BH")J+=N.Bc+D;J+=N.B1;m B;j(I&&((B=C(a,J))>-e))b(B);r{a[a.3]=J;i.x(J)}}7 I(J,I){j(I===9)I=s;m B;j(I&&((B=C(a,J))>-e))b(B);r{a[a.3]=J;J=n v(J);m F=("DB"+J.EY()).0(-BD),E=("k"+(J.El()+e)).0(-f),H=("k"+J.ED()).0(-f),G=("k"+J.DF()).0(-f),h=("k"+J.DD()).0(-f),A=("k"+J.DX()).0(-f),D=("BH"+J.DS()).0(-g);j((G=="k")&&(h=="k")&&(A=="k")&&(D=="BH"))J=N.Ba+F+E+H+N.$;r j((F=="DJ")&&(E=="EO")&&(H=="DV")){J=N.BO+G+h+A;j(D!="BH")J+=N.Bc+D;J+=N.$}r{J=N.Ba+F+E+H+N.BO+G+h+A;j(D!="BH")J+=N.Bc+D;J+=N.$}i.x(J)}}7 G(J,I){j(I===9)I=s;m F=("DB"+J.EY()).0(-BD),E=("k"+(J.El()+e)).0(-f),H=("k"+J.ED()).0(-f),G=("k"+J.DF()).0(-f),h=("k"+J.DD()).0(-f),A=("k"+J.DX()).0(-f),D=("BH"+J.DS()).0(-g);j((G=="k")&&(h=="k")&&(A=="k")&&(D=="BH"))J=N.Ba+F+E+H+N.$;r j((F=="DU")&&(E=="ES")&&(H=="ES")){J=N.BO+G+h+A;j(D!="BH")J+=N.Bc+D;J+=N.$}r{J=N.Ba+F+E+H+N.BO+G+h+A;j(D!="BH")J+=N.Bc+D;J+=N.$}m B;j(I&&((B=C(a,J))>-e))b(B);r{a[a.3]=J;i.x(J)}}7 S(A,G){j(G===9)G=s;m F=("k"+A.DF()).0(-f),h=("k"+A.DD()).0(-f),B=("k"+A.DX()).0(-f),E=("BH"+A.DS()).0(-g);A=N.BO+F+h+B;j(E!="BH")A+=N.Bc+E;A+=N.$;m D;j(G&&((D=C(a,A))>-e))b(D);r{a[a.3]=A;i.x(A)}}7 BL(h){i.x(N.CQ+h)}7 BY(h,B){j(B===9)B=s;h=N.CW+(h.3>d?h.3:"")+N.Bf+h+N.Bf;m A;j(B&&((A=C(a,h))>-e))b(A);r{a[a.3]=h;i.x(h)}}7 X(B,D){j(D===9)D=s;m A;j(D&&((A=C(a,B))>-e))b(A);r{a[a.3]=B;m h=B.3;i.x(N.Bo+(h>d?h:"")+N.BN);o(m E=d;E-e))b(B);r{a[a.3]=h;m F=(n Cm(h.DM())).Cp(),A=F.3;i.x(N.B3+(A>d?A:"")+N.BN);o(m E=d;E-e))b(E);r{a[a.3]=F;m K=[];o(m I l F){Bt{j(4(F[I])!="7"&&(4(F[I])!="BR"||H.Bj(F[I]))&&!h[I]&&!A[I])K[K.3]=I}Bw(B){}}m D=K.3;i.x(N.B3+(D>d?D:"")+N.BN);o(m J=d;J-e))b(E);r{m K=[];o(m I l G)j(4(G[I])!="7"&&!h[I])K[K.3]=I.BB();m A=C(Y,F);j(A===-e)A=T(F,K);a[a.3]=G;m B=K.3;i.x(N.CI+A+N.BN);o(m J=d;Jd?A:"")+N.BN);o(m C=d;C-e){m A=[];o(m B l D[C]){m i=D[C][B];j(i["CP"]&&((n v()).C$()>i["CP"]))A.Eo(B);r j(F.BU(i["BQ"])===d)j(((E&&i["Ct"])||!i["Ct"])&&(i["DN"]!==t))G.Eo(i["Ck"]+"="+i["DN"])}o(m H l A)5 D[C][A[H]]}j(G.3>d)2 G.B0("; ");2""}7 F(C,h,D){j(C.Ej==200){m i=C.getAllResponseHeaders().B4("\\Dw\\Cj");O(i,h);2 D.intputFilter(C.responseText)}r{m A=C.Ej+":"+C.statusText;2 B.BW+P.Bk(A)+B.BA}}7 h(H,J,D,N,h,R,S,T,O){m B,P,C,M;j(H.BC(d,Bl).BK()=="D9://"){C=y;M=Bl}r j(H.BC(d,Bm).BK()=="https://"){C=s;M=Bm}j(M>d){B=H.EI(M,H.BU("/",M));m G=B.Em(/^([^:]*):([^@]*)@(.*)i/);j(G!=t)B=G[g];P=H.BC(H.BU("/",M))}r 1 n I("Url must be DI absolute path.");m Q=i();Q.setTimeouts(S,S,S,S);j(N){Bt{Q.Dz(f,N);j(h)Q.setProxyCredentials(h,R)}Bw(A){}}j(O){Q.Ed("DH",H,s);Q.onreadystatechange=7(){j(Q.readyState==BD)O(F(Q,B,T))}}r Q.Ed("DH",H,y);o(m L l J)Q.Er(L,J[L]);m K=E(B,P,C);j(K!="")Q.Er("Cookie",K);Q.send(T.Dc(D));j(O)2 Q;r 2 F(Q,B,T)}7 N(P,C,i){m D={"Dr-Cs":"application/hprose; charset=utf-Bm"},Y,N,R,E,T=30000,U=y,F=[],Q=n L(),G=p;p.EJ=7(B,i,A){j(4(i)=="CN"&&A===9)A=i;m h=p;j(A)h={};j(B===9)2 n I("You should DE server url first!");Y=B;j(4(i)=="BI"||(i&&i.Br==BJ))i=[i];j(BJ.B6.BB.BS(i)==="[B8 Cx]")Z.Bi(h,i);r V.BS(h);2 h};p.invoke=7(){m i=ET,h=Cx.B6.shift.BS(i);2 S.Bi(p,h,i)};p.setHeader=7(h,A){m i=h.BK();j(i!="EK-type"&&i!="EK-3"&&i!="host")j(A)D[h]=A;r 5 D[h]};p.Dz=7(A,i,h,F){j(!A)N=t;r j(i===9){m C=d;j(A.BC(d,Bl).BK()=="D9://")C=Bl;r j(A.BC(d,Bz).BK()=="tcp://")C=Bz;m B=A.BU("/",C);j(B>d){A=A.EI(C,B);m D=A.Em(/^([^:]*):([^@]*)@(.*)i/);j(D!=t){R=Dp(D[e]);E=Dp(D[f]);A=D[g]}}N=A}r{N=A+":"+i;j(h!==9&&F!==9){R=h;E=F}}};p.setTimeout=7(i){T=i};p.getTimeout=7(){2 T};p.getByRef=7(){2 U};p.setByRef=7(i){j(i===9)i=s;U=i};p.setFilter=7(i){Q=i};p.D1=7(h,i){};p.DQ=7(C){o(m D=d,B=F.3;Dd||I){a.BP();a.Cw(H,y);j(I)a.Eb(s)}i.x(B.BA);m V=i.BB();j(W){m S=F.3;2 F[S]=h(Y,D,V,N,R,E,T,Q,7(i){Bt{m h=O(i,X,H,Z)}Bw(A){j(J)J(X,A);r G.D1(X,A);2}W(h,H);5 F[S]})}r{m P=h(Y,D,V,N,R,E,T,Q);2 O(P,X,H,Z)}}j(4(P)=="BI")p.EJ(P,C)}N.Ef=7(h,i){2 n N(h,i,s)};N.keepSession=7(){C=s;j(C1("DR"))D=C1("DR")};2 N})(),HproseHttpServer=(7(){7 Dn(BF,BV,By,CB){m Bv;j(4(BF)=="7")Bv=BF.BS(By,CB);r j(BV&&4(BV[BF])=="7")Bv=BV[BF].BS(By,CB);r{m a=[];o(m Be=d,Cj=CB.3;Bed)A=i.Ee(h);C1.EZ=EW;BM.EZ=EW;BM.Buffer=s;j(U)A=U.D2(A);a=n H(A);V=n E(a,J);j(U)R=I();r R=BM;Z=n B(R)}7 O(){j(p.Di!=t)p.Di();BM.CO("Dr-Cs","text/plain");j(P)BM.CO("P3P","Ex=\\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi "+"CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL "+"UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV\\"");j(T){m i=CX.Dd("HTTP_ORIGIN");j(i&&i!="t"){BM.CO("Dh-DY-DZ-Ec",i);BM.CO("Dh-DY-DZ-Credentials","s")}r BM.CO("Dh-DY-DZ-Ec","*")}}7 BY(i){j(p.DW!=t)p.DW(i);R.DK();Z.BP();R.x(C.BW);Z.Dl(i,y);R.x(C.BA)}7 M(){Ch{V.BP();m L=V.Cv(),h=L.BK(),E=[],F=y,D=V.Bs([C.Bo,C.BA,C.Bd]);j(D==C.Bo){V.BP();E=V.C5(y);j(J)E=i.Bg(E);D=V.Bs([C.Bh,C.BA,C.Bd]);j(D==C.Bh){F=s;D=V.Bs([C.BA,C.Bd])}}j(p.Dj!=t)p.Dj(L,E,F);m I,H,A;j(I=Y[h]){H=BL[h];A=Dn(I.BF,I.BV,I.By,E)}r j(I=Y["*"]){H=BL["*"];m B=[L,E];A=Dn(I.BF,I.BV,I.By,B)}r 1 n G("Can\'Dv find p 7 "+L+"().");j(p.Dk!=t)p.Dk(L,E,F,A);j(H==K.C_){R.x(A);2}r j(H==K.Db)R.x(A);r{R.x(C.Cf);j(H==K.DG)R.x(A);r{Z.BP();Z.Bk(A)}j(F){R.x(C.Cd);Z.BP();Z.Cw(E,y)}}}Bp(D==C.Bd);R.x(C.BA)}7 X(){m i=D(S);R.x(C.C2);Z.Cw(i,y);R.x(C.BA)}7 N(){Bt{m i=[C.Bd,C.BA],A=V.Bs(i);Bb(A){q C.Bd:M.BS(p);z;q C.BA:X();z}}Bw(h){BY.Bi(p,h.Dy)}}p.addMissingFunction=7(h,i){p.B2(h,"*",i)};p.addMissingMethod=7(B,A,i,h){p.Ca(B,A,"*",i,h)};p.B2=7(B,h,A){j(A===9)A=K.Cg;j(h===9||h==t)Bb(4(B)){q"BI":h=B;z;q"B8":h=F(B);z;q"7":h=L(B);j(h!="")z;Cb:1 n G("D3 DI Cu")}j(4(h)=="BI"){m i=h.BK();Y[i]={BF:B,BV:t,By:t};S[i]=h;BL[i]=A}r 1 n G("Ek Cu CM CT a BI")};p.addFunctions=7(h,C,B){j(i.Bj(h))h=i.Bg(h);m A=h.3,D;j(C===9||C==t){o(D=d;D>6)+C(A&63)}while(A>0)E[C(G--)]=D[--A];return B.replace(/[\w\$]+/g,function(A){return E[A]==F[A]?A:E[A]})}('l Ds={DN:b,Dj:c,Db:d,DG:e};7 Bi(h){o.message=h;o.description=h}Bi.Bm=m Error;Bi.Bm.CM="Bi";7 Dv(){o.inputFilter=7(h){1 h};o.Dg=7(h){1 h}}l DD={Cp:7(h){1((h!=t)&&(3(h)=="CZ")&&(h instanceof Bl)&&(3(h.Cn)=="BK")&&(3(h.Exists)=="BK")&&(3(h.DQ)=="BK")&&(3(h.C1)=="BK")&&(3(h.Remove)=="BK")&&(3(h.RemoveAll)=="BK")&&(3(h.Count)=="Bw")&&(3(h.Item)=="BK")&&(3(h.Key)=="BK"))},Cb:7(h){1((h!=t)&&(3(h)=="BK")&&(h.Bc==CO)&&(3(h.C0)=="7")&&(3(h.D9)=="7")&&(3(h.Cx)=="7")&&(3(h.CU)=="7")&&(3(h.Dp)=="7"))},DB:7(g){l B=(m CO(g.C1())).CU(),h={};n(l A=b;AC){E[C]=b;C++}l F=h.Cx(C),D=h.Dp(C),g=[];n(l G=F;G<=D;G++){E[C-c]=G;i(B==C)g[G]=h.D9.Bq(h,E);q g[G]=A(h,C,E)}1 g}l h=m CO(g);i(h.C0()==c&&h.Cx()==b)1 h.CU();1 A(h,b,[])},DO:7(h){1 o.D7(h).DQ()},binaryToString:7(g,C){Bg{l D=d,h=c,B=m Bl("ADODB.Stream");B.C5=h;B.Open();B.Write(g);B.Position=b;B.C5=D;i(C)B.DY=C;q B.DY="UTF-BU";1 B.ReadText()}Bj(A){1""}}};7 Cv(h){l A=b,g=h.2;o.s=7(){1 h.CE(A++)};o.v=7(B){l g=h.6(A,B);o.w(B);1 g};o.w=7(h){A+=h};o.B4=7(C){l D=h.BO(C,A),B;i(D!==-c){B=h.6(A,D-A);A=D+C.2}q{B=h.6(A);A=g}1 B}}7 CS(h){i(h===9)h="";l g=[h],A=g.2;o.x=7(h){g[A++]=h};o.mark=7(){h=o.BC()};o.Bn=7(){g=[h]};o.clear=7(){g=[]};o.BC=7(){1 g.Cj("")}}l _={B2:"Ck",By:"EA",CB:"BV",B9:"DS",B7:"BW",Bs:"ED",CC:"Z",B_:"N",Bv:"I",BN:"D",BF:"T",Bk:"X",Bz:"EE",B6:"BI",CN:"a",B3:"Y",Br:"EB",Bp:"BX",CA:"EC",5:"DX",DZ:"+",C7:"-",$:";",BE:"{",BY:"}",BR:"\\"",BP:".",Cu:"F",DC:"C",Ch:"R",Ce:"A",BQ:"E",BZ:"EF"},Dz=m(7(){l h={"BB":BB};o.B0=7(g,A){h[A]=g};o.DI=7(g){n(l A k h)i(g===h[A])1 A;1""};o.DR=7(g){1 h[g]}})(),CQ,CL;(7(){7 B$(De){1 eval(De)}(7(){l H=DD,N=_,G=Bi,I=Dz;7 C(B,g){l h=B.2;n(l A=b;A-c){B[B.2]=C;C=A.BO("g",C+c)}i(B.2>b){l g=A.Bf("");h=J(g,B,b,".");i(h==t)h=J(g,B,b,"g");i(h!=t){I.B0(h,A);1 h}}h=7(){o.C6=7(){1 A}};I.B0(h,A);1 h}l A=7(){l h={};n(l g k[])h[g]=r;1 h}(),g=7(){l h={};n(l g k{})h[g]=r;1 h}();7 E(h){Bo(h.BC()){p"b":p"c":p"d":p"e":p"f":p"CI":p"Be":p"BT":p"BU":p"BH":1 r}1 z}7 L(h){l g=h.2;n(l A=(h.CE(b)=="-")?c:b;A2147483647))}7 M(h){1(BB.Bm.BC.Bq(h)==="[CZ CF]")}7 D(B){i(B===9||B.Bc===9)1"BB";l h=B.Bc,A=I.DI(h);i(A)1 A;l g=h.BC();A=g.6(b,g.BO("(")).CK(/(^\\BI*7\\BI*)|(\\BI*h)/ig,"");i(A==""||A=="BB")1(3(B.C6)=="7")?B.C6():"BB";i(A!="BB")I.B0(h,A);1 A}CQ=7 F(D,S){l a=[],W=[];7 B(g,h){i(h===9)h=D.s();i(h!=g)BJ m G("Tag \'"+g+"\' Dl, but \'"+h+"\' DA k B5")}7 L(h,g){i(g===9)g=D.s();i(C(h,g)!=-c)1 g;BJ m G("\'"+g+"\' is not the Dl Cw")}7 g(g){l h=D.B4(g);i(h.2==b)1 b;1 8(h)}7 V(h){i(h===9)h=D.s();Bo(h){p"b":p"c":p"d":p"e":p"f":p"CI":p"Be":p"BT":p"BU":p"BH":1 8(h);p N.B2:1 BL(z);p N.By:1 T(z);p N.CB:1 Z(z);p N.B9:1 t;p N.B7:1"";p N.Bs:1 r;p N.CC:1 z;p N.B_:1 D2;p N.Bv:1 BW(z);p N.BN:1 Bh(z);p N.BF:1 BD(z);p N.Bz:1 D.s();p N.B6:1 U(z);p N.CN:1 Y(z);p N.B3:1 P(z);p N.Br:1 BV(z);p N.Bp:K();1 V();p N.CA:1 X(z);p N.5:1 BM();p _.BQ:BJ m G(U());p"":BJ m G("Dy Dq DA k B5");C4:BJ m G("Dx Bd Cw \'"+h+"\' k B5")}}7 BL(h){i(h===9)h=r;i(h){l A=D.s();i((A>="b")&&(A<="BH"))1 8(A);B(N.B2,A)}1 g(N.$)}7 T(h){i(h===9)h=r;i(h){l g=D.s();i((g>="b")&&(g<="BH"))1 g;B(N.By,g)}1 D.B4(N.$)}7 Z(h){i(h===9)h=r;i(h){l g=D.s();i((g>="b")&&(g<="BH"))1 Df(g);B(N.CB,g)}1 Df(D.B4(N.$))}7 I(){B(N.B_);1 D2}7 BW(h){i(h===9)h=r;i(h)B(N.Bv);1((D.s()==N.C7)?-Dm:Dm)}7 BX(){B(N.B9);1 t}7 E(){B(N.B7);1""}7 O(){l h=L([N.Bs,N.CC]);1(h==N.Bs)}7 Bh(A){i(A===9)A=r;l C;i(A){C=L([N.BN,N.5]);i(C==N.5)1 BM()}l F=8(D.v(f)),E=8(D.v(d))-c,H=8(D.v(d)),I;C=D.s();i(C==N.BF){l G=8(D.v(d)),h=8(D.v(d)),g=8(D.v(d)),B=b;C=D.s();i(C==N.BP){B=8(D.v(e));C=D.s();i((C>="b")&&(C<="BH")){D.w(d);C=D.s();i((C>="b")&&(C<="BH")){D.w(d);C=D.s()}}}i(C==N.Bk)I=m u(u.CY(F,E,H,G,h,g,B));q I=m u(F,E,H,G,h,g,B)}q i(C==N.Bk)I=m u(u.CY(F,E,H));q I=m u(F,E,H);i(S)I=I.C3();a[a.2]=I;1 I}7 BD(B){i(B===9)B=r;l E;i(B){E=L([N.BF,N.5]);i(E==N.5)1 BM()}l g,F=8(D.v(d)),h=8(D.v(d)),A=8(D.v(d)),C=b;E=D.s();i(E==N.BP){C=8(D.v(e));E=D.s();i((E>="b")&&(E<="BH")){D.w(d);E=D.s();i((E>="b")&&(E<="BH")){D.w(d);E=D.s()}}}i(E==N.Bk){i(S)g=m u(u.CY(Cy,DL,Cf,F,h,A,C)).C3();q g=m u(u.CY(Cd,b,c,F,h,A,C))}q i(S)g=m u(Cy,DL,Cf,F,h,A,C).C3();q g=m u(Cd,b,c,F,h,A,C);a[a.2]=g;1 g}7 DT(h){i(h===9)h=r;i(h)B(N.Bz);1 D.s()}7 U(A,C){i(A===9)A=r;i(C===9)C=r;i(A){l B=L([N.B6,N.5]);i(B==N.5)1 BM()}l h=D.v(g(N.BR));D.w(c);i(C)a[a.2]=h;1 h}7 Y(g){i(g===9)g=r;i(g){l A=L([N.CN,N.5]);i(A==N.5)1 BM()}D.w(c);l h=D.v(36);D.w(c);a[a.2]=h;1 h}7 P(A){i(A===9)A=r;i(A){l B=L([N.B3,N.5]);i(B==N.5)1 BM()}l E=[],C=a.2;a[C]=E;l h=g(N.BE);n(l F=b;Fb)A=8(h);B.x(D.v(A+c))}7 M(g,h){g.x(h);g.x(D.v(38))}7 A(g,h){g.x(h);Ci{h=D.s();g.x(h)}Bt(h!=_.BE);Bt((h=D.s())!=_.BY)J(g,h);g.x(h)}7 R(){a.2=b;W.2=b}o.DK=B;o.Cc=L;o.CR=V;o.readInteger=BL;o.readLong=T;o.readDouble=Z;o.readNaN=I;o.readInfinity=BW;o.readNull=BX;o.readEmpty=E;o.readBoolean=O;o.readDate=Bh;o.readTime=BD;o.readUTF8Char=DT;o.C8=U;o.Cz=P;o.readMap=BV;o.readObject=X;o.Du=J;o.Bn=R};CL=7 K(h){l Y=[],W=[];7 U(J){i(3(J)=="date"){I(J);1}q i(H.Cb(J))J=H.Ct(J);q i(H.Cp(J)){Q(J);1}q i(J===9||J===t||J.Bc==Function){L();1}q i(J===""){BV();1}Bo(J.Bc){p Boolean:BW(J);0;p Number:E(J)?h.x(J):B(J)?BD(J):O(J);0;p String:J.2==c?Bh(J):BX(J);0;p u:G(J);0;C4:l g=C(Y,J);i(g>-c)Z(g);q i(M(J))V(J,z);q{l A=D(J);i(A=="BB")F(J,z);q R(J,z)}}}7 BD(g){h.x(N.B2+g+N.$)}7 P(g){h.x(N.By+g+N.$)}7 O(g){i(isNaN(g))a();q i(isFinite(g))h.x(N.CB+g+N.$);q X(g>b)}7 a(){h.x(N.B_)}7 X(g){h.x(N.Bv+(g?N.DZ:N.C7))}7 L(){h.x(N.B9)}7 BV(){h.x(N.B7)}7 BW(g){h.x(g?N.Bs:N.CC)}7 J(J,I){i(I===9)I=r;l F=("Co"+J.getUTCFullYear()).y(-f),E=("j"+(J.getUTCMonth()+c)).y(-d),H=("j"+J.getUTCDate()).y(-d),G=("j"+J.getUTCHours()).y(-d),g=("j"+J.getUTCMinutes()).y(-d),A=("j"+J.getUTCSeconds()).y(-d),D=("BA"+J.getUTCMilliseconds()).y(-e);J=N.BN+F+E+H+N.BF+G+g+A;i(D!="BA")J+=N.BP+D;J+=N.Bk;l B;i(I&&((B=C(Y,J))>-c))Z(B);q{Y[Y.2]=J;h.x(J)}}7 I(J,I){i(I===9)I=r;l B;i(I&&((B=C(Y,J))>-c))Z(B);q{Y[Y.2]=J;J=m u(J);l F=("Co"+J.Di()).y(-f),E=("j"+(J.D4()+c)).y(-d),H=("j"+J.D3()).y(-d),G=("j"+J.Cs()).y(-d),g=("j"+J.Cq()).y(-d),A=("j"+J.Cg()).y(-d),D=("BA"+J.C$()).y(-e);i((G=="j")&&(g=="j")&&(A=="j")&&(D=="BA"))J=N.BN+F+E+H+N.$;q i((F=="Cy")&&(E=="DM")&&(H=="Cf")){J=N.BF+G+g+A;i(D!="BA")J+=N.BP+D;J+=N.$}q{J=N.BN+F+E+H+N.BF+G+g+A;i(D!="BA")J+=N.BP+D;J+=N.$}h.x(J)}}7 G(J,I){i(I===9)I=r;l F=("Co"+J.Di()).y(-f),E=("j"+(J.D4()+c)).y(-d),H=("j"+J.D3()).y(-d),G=("j"+J.Cs()).y(-d),g=("j"+J.Cq()).y(-d),A=("j"+J.Cg()).y(-d),D=("BA"+J.C$()).y(-e);i((G=="j")&&(g=="j")&&(A=="j")&&(D=="BA"))J=N.BN+F+E+H+N.$;q i((F=="Cd")&&(E=="DU")&&(H=="DU")){J=N.BF+G+g+A;i(D!="BA")J+=N.BP+D;J+=N.$}q{J=N.BN+F+E+H+N.BF+G+g+A;i(D!="BA")J+=N.BP+D;J+=N.$}l B;i(I&&((B=C(Y,J))>-c))Z(B);q{Y[Y.2]=J;h.x(J)}}7 S(A,G){i(G===9)G=r;l F=("j"+A.Cs()).y(-d),g=("j"+A.Cq()).y(-d),B=("j"+A.Cg()).y(-d),E=("BA"+A.C$()).y(-e);A=N.BF+F+g+B;i(E!="BA")A+=N.BP+E;A+=N.$;l D;i(G&&((D=C(Y,A))>-c))Z(D);q{Y[Y.2]=A;h.x(A)}}7 Bh(g){h.x(N.Bz+g)}7 BX(g,B){i(B===9)B=r;g=N.B6+(g.2>b?g.2:"")+N.BR+g+N.BR;l A;i(B&&((A=C(Y,g))>-c))Z(A);q{Y[Y.2]=g;h.x(g)}}7 V(B,D){i(D===9)D=r;l A;i(D&&((A=C(Y,B))>-c))Z(A);q{Y[Y.2]=B;l g=B.2;h.x(N.B3+(g>b?g:"")+N.BE);n(l E=b;E-c))Z(B);q{Y[Y.2]=g;l F=(m CO(g.C1())).CU(),A=F.2;h.x(N.Br+(A>b?A:"")+N.BE);n(l E=b;E-c))Z(E);q{Y[Y.2]=F;l K=[];n(l I k F){Bg{i(3(F[I])!="7"&&(3(F[I])!="BK"||H.Cb(F[I]))&&!g[I]&&!A[I])K[K.2]=I}Bj(B){}}l D=K.2;h.x(N.Br+(D>b?D:"")+N.BE);n(l J=b;J-c))Z(E);q{l K=[];n(l I k G)i(3(G[I])!="7"&&!g[I])K[K.2]=I.BC();l A=C(W,F);i(A===-c)A=T(F,K);Y[Y.2]=G;l B=K.2;h.x(N.CA+A+N.BE);n(l J=b;Jb?A:"")+N.BE);n(l C=b;C-c){l A=[];n(l B k D[C]){l h=D[C][B];i(h["Bx"]&&((m u()).Cl()>h["Bx"]))A.D8(B);q i(F.BO(h["BG"])===b)i(((E&&h["Ca"])||!h["Ca"])&&(h["C2"]!==t))G.D8(h["CM"]+"="+h["C2"])}n(l H k A)4 D[C][A[H]]}i(G.2>b)1 G.Cj("; ");1""}7 F(C,g,D){i(C.D1==200){l h=C.getAllResponseHeaders().Bf("\\DX\\DS");O(h,g);1 D.intputFilter(C.responseText)}q{l A=C.D1+":"+C.statusText;1 B.BQ+P.Bd(A)+B.BZ}}7 g(H,J,D,N,g,R,S,T,O){l B,P,C,M;i(H.6(b,BT).BS()=="Dt://"){C=z;M=BT}q i(H.6(b,BU).BS()=="https://"){C=r;M=BU}i(M>b){B=H.DE(M,H.BO("/",M));l G=B.D6(/^([^:]*):([^@]*)@(.*)h/);i(G!=t)B=G[e];P=H.6(H.BO("/",M))}q BJ m I("Url must be an absolute path.");l Q=h();Q.setTimeouts(S,S,S,S);i(N){Bg{Q.Dd(d,N);i(g)Q.setProxyCredentials(g,R)}Bj(A){}}i(O){Q.Do("Dk",H,r);Q.onreadystatechange=7(){i(Q.readyState==f)O(F(Q,B,T))}}q Q.Do("Dk",H,z);n(l L k J)Q.D$(L,J[L]);l K=E(B,P,C);i(K!="")Q.D$("Cookie",K);Q.send(T.Dg(D));i(O)1 Q;q 1 F(Q,B,T)}7 N(P,C,h){l D={"Content-C5":"application/hprose; charset=utf-BU"},W,N,R,E,T=30000,BL=z,F=[],Q=m L(),G=o;o.DF=7(B,h,A){i(3(h)=="Bu"&&A===9)A=h;l g=o;i(A)g={};i(B===9)1 m I("You should Cr server url first!");W=B;i(3(h)=="B1"||(h&&h.Bc==BB))h=[h];i(BB.Bm.BC.Bq(h)==="[CZ CF]")X.Ba(g,h);q BD.Bq(g);1 g};o.invoke=7(){l h=DW,g=CF.Bm.shift.Bq(h);1 S.Ba(o,g,h)};o.setHeader=7(g,A){l h=g.BS();i(h!="DH-type"&&h!="DH-2"&&h!="host")i(A)D[g]=A;q 4 D[g]};o.Dd=7(A,h,g,F){i(!A)N=t;q i(h===9){l C=b;i(A.6(b,BT).BS()=="Dt://")C=BT;q i(A.6(b,Be).BS()=="tcp://")C=Be;l B=A.BO("/",C);i(B>b){A=A.DE(C,B);l D=A.D6(/^([^:]*):([^@]*)@(.*)h/);i(D!=t){R=DJ(D[c]);E=DJ(D[d]);A=D[e]}}N=A}q{N=A+":"+h;i(g!==9&&F!==9){R=g;E=F}}};o.setTimeout=7(h){T=h};o.getTimeout=7(){1 T};o.getByRef=7(){1 BL};o.setByRef=7(h){i(h===9)h=r;BL=h};o.setFilter=7(h){Q=h};o.Dh=7(g,h){};o.C9=7(C){n(l D=b,B=F.2;Db||I){Y.Bn();Y.D_(H,z);i(I)Y.Dn(r)}h.x(B.BZ);l BD=h.BC();i(U){l S=F.2;1 F[S]=g(W,D,BD,N,R,E,T,Q,7(h){Bg{l g=O(h,V,H,X)}Bj(A){i(J)J(V,A);q G.Dh(V,A);1}U(g,H);4 F[S]})}q{l P=g(W,D,BD,N,R,E,T,Q);1 O(P,V,H,X)}}i(3(P)=="B1")o.DF(P,C)}N.create=7(g,h){1 m N(g,h,r)};N.keepSession=7(){C=r;i(Cm("C_"))D=Cm("C_")};1 N})()','W|X|Y|Z|a|f|g|0|1|2|3|4|_|$|if|00|in|var|new|for|this|case|else|true|getc|null|Date|read|skip|write|slice|false|break|return|length|typeof|delete|TagRef|substr|function|parseInt|undefined|HproseTags|TagSemicolon|000|Object|toString|V|TagOpenbrace|TagTime|PATH|9|s|throw|unknown|U|h|TagDate|indexOf|TagPoint|TagError|TagQuote|toLowerCase|7|8|d|e|c|TagClosebrace|TagEnd|call|DOMAIN|constructor|serialize|6|split|try|b|HproseException|catch|TagUTC|ActiveXObject|prototype|reset|switch|TagClass|apply|TagMap|TagTrue|while|boolean|TagInfinity|number|EXPIRES|TagLong|TagUTF8Char|register|string|TagInteger|TagList|readuntil|stream|TagString|TagEmpty|ServerXMLHTTP|TagNull|TagNaN|freeEval|TagObject|TagDouble|TagFalse|MSXML2|charAt|Array|_onsuccess|_onSuccess|5|_Callback|replace|HproseWriter|name|TagGuid|VBArray|_callback|HproseReader|unserialize|HproseStringOutputStream|_OnError|toArray|_onerror|_OnSuccess|_onError|UTC|object|SECURE|isVBArray|checkTags|1970|TagArgument|30|getSeconds|TagResult|do|join|i|getTime|Session|Add|0000|isDictionary|getMinutes|set|getHours|toJSArray|TagFunctions|HproseStringInputStream|tag|lbound|1899|readList|dimensions|Keys|value|getVarDate|default|Type|getClassName|TagNeg|readString|waitForResponse|HPROSE_COOKIE_MANAGER|getMilliseconds|found|toObject|TagCall|HproseUtil|substring|useService|RawWithEndTag|content|getClassAlias|decodeURIComponent|checkTag|11|12|Normal|toVBArray|Scripting|Items|getClass|n|j|01|k|arguments|r|CharSet|TagPos|HproseFormatter|Raw|fields|setProxy|str|parseFloat|outputFilter|onError|getFullYear|Serialized|POST|expected|Infinity|writeBoolean|open|ubound|byte|classname|HproseResultMode|http|readRaw|HproseFilter|Dictionary|Unexpected|No|HproseClassManager|count|status|NaN|getDate|getMonth|writeString|match|toDictionary|push|getItem|writeList|setRequestHeader|l|m|o|t|u|z'.split('|'),242,261,{},{})) \ No newline at end of file diff --git a/bin/1.3/asp/hproseServer.js b/bin/1.3/asp/hproseServer.js index 8e28e7a..d6178cc 100644 --- a/bin/1.3/asp/hproseServer.js +++ b/bin/1.3/asp/hproseServer.js @@ -1,4 +1,4 @@ -/* - * Compressed by JSA(www.xidea.org) - */ +/* + * Compressed by JSA(www.xidea.org) + */ eval(function(B,D,A,G,E,F){function C(A){return A<62?String.fromCharCode(A+=A<26?65:A<52?71:-4):A<63?'_':A<64?'$':C(A>>6)+C(A&63)}while(A>0)E[C(G--)]=D[--A];return B.replace(/[\w\$]+/g,function(A){return E[A]==F[A]?A:E[A]})}('h Dx={Ca:Z,DN:a,Dm:b,DA:BB};5 Bn(d){l.message=d;l.DJ=d}Bn.C3=i Error;Bn.C3.name="Bn";5 HproseFilter(){l.DL=5(d){z d};l.Dq=5(d){z d}}h CV={Cd:5(d){z((d!=p)&&(1(d)=="CU")&&(d instanceof CR)&&(1(d.Cy)=="BA")&&(1(d.Exists)=="BA")&&(1(d.Di)=="BA")&&(1(d.Ck)=="BA")&&(1(d.Remove)=="BA")&&(1(d.RemoveAll)=="BA")&&(1(d.Count)=="number")&&(1(d.Item)=="BA")&&(1(d.Key)=="BA"))},BU:5(d){z((d!=p)&&(1(d)=="BA")&&(d.B3==CI)&&(1(d.Cj)=="5")&&(1(d.D6)=="5")&&(1(d.C2)=="5")&&(1(d.CK)=="5")&&(1(d.DR)=="5"))},C_:5(c){h B=(i CI(c.Ck())).CK(),d={};j(h A=Z;AC){E[C]=Z;C++}h F=d.C2(C),D=d.DR(C),c=[];j(h G=F;G<=D;G++){E[C-a]=G;e(B==C)c[G]=d.D6.Bc(d,E);n c[G]=A(d,C,E)}z c}h d=i CI(c);e(d.Cj()==a&&d.C2()==Z)z d.CK();z A(d,Z,[])},DC:5(d){z l.D5(d).Di()},Dw:5(c,C){CO{h D=b,d=a,B=i CR("ADODB.Stream");B.Cm=d;B.Open();B.Write(c);B.Position=Z;B.Cm=D;e(C)B.DH=C;n B.DH="UTF-CF";z B.ReadText()}CQ(A){z""}}};5 Cz(d){h A=Z,c=d.0;l.q=5(){z d.Cn(A++)};l.r=5(B){h c=d.Bq(A,B);l.t(B);z c};l.t=5(d){A+=d};l.Bw=5(C){h D=d.Bx(C,A),B;e(D!==-a){B=d.Bq(A,D-A);A=D+C.0}n{B=d.Bq(A);A=c}z B}}5 CS(d){e(d===8)d="";h c=[d],A=c.0;l.u=5(d){c[A++]=d};l.mark=5(){d=l.BF()};l.BP=5(){c=[d]};l.Ci=5(){c=[]};l.BF=5(){z c.Bs("")}}h 9={Bv:"BO",Br:"D8",B2:"BH",CA:"Cb",By:"BZ",BT:"DG",CD:"X",Bz:"M",Bp:"I",BK:"D",4:"BD",Bj:"U",B7:"EA",B_:"Ba",CH:"Y",Bb:"V",Bl:"D9",Bo:"BI",B1:"D_",2:"D$",Dl:"+",Co:"-",_:";",$:"{",Bf:"}",BQ:"\\"",BM:".",Dt:"F",BV:"C",DB:"N",C$:"A",CE:"E",BL:"EB"},D1=i(5(){h d={"BS":BS};l.Bt=5(c,A){d[A]=c};l.Dd=5(c){j(h A g d)e(c===d[A])z A;z""};l.DD=5(c){z d[c]}})(),CJ,CP;(5(){5 B0(Dp){z CN(Dp)}(5(){h H=CV,M=9,G=Bn,I=D1;5 C(B,c){h d=B.0;j(h A=Z;A-a){B[B.0]=C;C=A.Bx("c",C+a)}e(B.0>Z){h c=A.split("");d=J(c,B,Z,".");e(d==p)d=J(c,B,Z,"c");e(d!=p){I.Bt(d,A);z d}}d=5(){l.C8=5(){z A}};I.Bt(d,A);z d}h A=5(){h d={};j(h c g[])d[c]=o;z d}(),c=5(){h d={};j(h c g{})d[c]=o;z d}();5 E(d){Bg(d.BF()){m"Z":m"a":m"b":m"BB":m"BW":m"CY":m"CX":m"CW":m"CF":m"BC":z o}z v}5 L(d){h c=d.0;j(h A=(d.Cn(Z)=="-")?a:Z;A2147483647))}5 BX(d){z(BS.C3.BF.Bc(d)==="[CU Array]")}5 D(B){e(B===8||B.B3===8)z"BS";h d=B.B3,A=I.Dd(d);e(A)z A;h c=d.BF();A=c.Bq(Z,c.Bx("(")).Dk(/(^\\Ba*5\\Ba*)|(\\Ba*d)/DY,"");e(A==""||A=="BS")z(1(B.C8)=="5")?B.C8():"BS";e(A!="BS")I.Bt(d,A);z A}CJ=5 F(D,O){h Y=[],T=[];5 B(c,d){e(d===8)d=D.q();e(d!=c)y i G("Tag \'"+c+"\' DO, but \'"+d+"\' Cr g B9")}5 L(d,c){e(c===8)c=D.q();e(C(d,c)!=-a)z c;y i G("\'"+c+"\' B4 B8 the DO C0")}5 c(c){h d=D.Bw(c);e(d.0==Z)z Z;z 6(d)}5 S(d){e(d===8)d=D.q();Bg(d){m"Z":m"a":m"b":m"BB":m"BW":m"CY":m"CX":m"CW":m"CF":m"BC":z 6(d);m M.Bv:z P(v);m M.Br:z BD(v);m M.B2:z X(v);m M.CA:z p;m M.By:z"";m M.BT:z o;m M.CD:z v;m M.Bz:z DW;m M.Bp:z BZ(v);m M.BK:z W(v);m M.4:z Q(v);m M.B7:z D.q();m M.B_:z R(v);m M.CH:z V(v);m M.Bb:z BG(v);m M.Bl:z BH(v);m M.Bo:K();z S();m M.B1:z U(v);m M.2:z BJ();m 9.CE:y i G(R());m"":y i G("DV DS Cr g B9");CC:y i G("DU Bi C0 \'"+d+"\' g B9")}}5 P(d){e(d===8)d=o;e(d){h A=D.q();e((A>="Z")&&(A<="BC"))z 6(A);B(M.Bv,A)}z c(M._)}5 BD(d){e(d===8)d=o;e(d){h c=D.q();e((c>="Z")&&(c<="BC"))z c;B(M.Br,c)}z D.Bw(M._)}5 X(d){e(d===8)d=o;e(d){h c=D.q();e((c>="Z")&&(c<="BC"))z DK(c);B(M.B2,c)}z DK(D.Bw(M._))}5 I(){B(M.Bz);z DW}5 BZ(d){e(d===8)d=o;e(d)B(M.Bp);z((D.q()==M.Co)?-Du:Du)}5 BI(){B(M.CA);z p}5 E(){B(M.By);z""}5 BY(){h d=L([M.BT,M.CD]);z(d==M.BT)}5 W(A){e(A===8)A=o;h C;e(A){C=L([M.BK,M.2]);e(C==M.2)z BJ()}h F=6(D.r(BW)),E=6(D.r(b))-a,H=6(D.r(b)),I;C=D.q();e(C==M.4){h G=6(D.r(b)),d=6(D.r(b)),c=6(D.r(b)),B=Z;C=D.q();e(C==M.BM){B=6(D.r(BB));C=D.q();e((C>="Z")&&(C<="BC")){D.t(b);C=D.q();e((C>="Z")&&(C<="BC")){D.t(b);C=D.q()}}}e(C==M.Bj)I=i s(s.CT(F,E,H,G,d,c,B));n I=i s(F,E,H,G,d,c,B)}n e(C==M.Bj)I=i s(s.CT(F,E,H));n I=i s(F,E,H);e(O)I=I.Cl();Y[Y.0]=I;z I}5 Q(B){e(B===8)B=o;h E;e(B){E=L([M.4,M.2]);e(E==M.2)z BJ()}h c,F=6(D.r(b)),d=6(D.r(b)),A=6(D.r(b)),C=Z;E=D.q();e(E==M.BM){C=6(D.r(BB));E=D.q();e((E>="Z")&&(E<="BC")){D.t(b);E=D.q();e((E>="Z")&&(E<="BC")){D.t(b);E=D.q()}}}e(E==M.Bj){e(O)c=i s(s.CT(Cg,De,Ct,F,d,A,C)).Cl();n c=i s(s.CT(Cs,Z,a,F,d,A,C))}n e(O)c=i s(Cg,De,Ct,F,d,A,C).Cl();n c=i s(Cs,Z,a,F,d,A,C);Y[Y.0]=c;z c}5 DE(d){e(d===8)d=o;e(d)B(M.B7);z D.q()}5 R(A,C){e(A===8)A=o;e(C===8)C=o;e(A){h B=L([M.B_,M.2]);e(B==M.2)z BJ()}h d=D.r(c(M.BQ));D.t(a);e(C)Y[Y.0]=d;z d}5 V(c){e(c===8)c=o;e(c){h A=L([M.CH,M.2]);e(A==M.2)z BJ()}D.t(a);h d=D.r(36);D.t(a);Y[Y.0]=d;z d}5 BG(A){e(A===8)A=o;e(A){h B=L([M.Bb,M.2]);e(B==M.2)z BJ()}h E=[],C=Y.0;Y[C]=E;h d=c(M.$);j(h F=Z;FZ)A=6(d);B.u(D.r(A+a))}5 BX(c,d){c.u(d);c.u(D.r(38))}5 A(c,d){c.u(d);CG{d=D.q();c.u(d)}Bm(d!=9.$);Bm((d=D.q())!=9.Bf)J(c,d);c.u(d)}5 N(){Y.0=Z;T.0=Z}l.checkTag=B;l.B5=L;l.Ch=S;l.readInteger=P;l.readLong=BD;l.readDouble=X;l.readNaN=I;l.readInfinity=BZ;l.readNull=BI;l.readEmpty=E;l.readBoolean=BY;l.readDate=W;l.readTime=Q;l.readUTF8Char=DE;l.Da=R;l.Dz=BG;l.readMap=BH;l.readObject=U;l.readRaw=J;l.BP=N};CP=5 K(d){h V=[],T=[];5 R(J){e(1(J)=="date"){I(J);z}n e(H.BU(J))J=H.BR(J);n e(H.Cd(J)){BN(J);z}n e(J===8||J===p||J.B3==Function){L();z}n e(J===""){BH();z}Bg(J.B3){m Boolean:BZ(J);x;m Number:E(J)?d.u(J):B(J)?Q(J):BY(J);x;m String:J.0==a?W(J):BI(J);x;m s:G(J);x;CC:h c=C(V,J);e(c>-a)X(c);n e(BX(J))S(J,v);n{h A=D(J);e(A=="BS")F(J,v);n N(J,v)}}}5 Q(c){d.u(M.Bv+c+M._)}5 BG(c){d.u(M.Br+c+M._)}5 BY(c){e(isNaN(c))Y();n e(isFinite(c))d.u(M.B2+c+M._);n U(c>Z)}5 Y(){d.u(M.Bz)}5 U(c){d.u(M.Bp+(c?M.Dl:M.Co))}5 L(){d.u(M.CA)}5 BH(){d.u(M.By)}5 BZ(c){d.u(c?M.BT:M.CD)}5 J(J,I){e(I===8)I=o;h F=("Cc"+J.getUTCFullYear()).w(-BW),E=("f"+(J.getUTCMonth()+a)).w(-b),H=("f"+J.getUTCDate()).w(-b),G=("f"+J.getUTCHours()).w(-b),c=("f"+J.getUTCMinutes()).w(-b),A=("f"+J.getUTCSeconds()).w(-b),D=("k"+J.getUTCMilliseconds()).w(-BB);J=M.BK+F+E+H+M.4+G+c+A;e(D!="k")J+=M.BM+D;J+=M.Bj;h B;e(I&&((B=C(V,J))>-a))X(B);n{V[V.0]=J;d.u(J)}}5 I(J,I){e(I===8)I=o;h B;e(I&&((B=C(V,J))>-a))X(B);n{V[V.0]=J;J=i s(J);h F=("Cc"+J.Dr()).w(-BW),E=("f"+(J.D3()+a)).w(-b),H=("f"+J.DX()).w(-b),G=("f"+J.Cf()).w(-b),c=("f"+J.Ce()).w(-b),A=("f"+J.Cv()).w(-b),D=("k"+J.Cq()).w(-BB);e((G=="f")&&(c=="f")&&(A=="f")&&(D=="k"))J=M.BK+F+E+H+M._;n e((F=="Cg")&&(E=="Df")&&(H=="Ct")){J=M.4+G+c+A;e(D!="k")J+=M.BM+D;J+=M._}n{J=M.BK+F+E+H+M.4+G+c+A;e(D!="k")J+=M.BM+D;J+=M._}d.u(J)}}5 G(J,I){e(I===8)I=o;h F=("Cc"+J.Dr()).w(-BW),E=("f"+(J.D3()+a)).w(-b),H=("f"+J.DX()).w(-b),G=("f"+J.Cf()).w(-b),c=("f"+J.Ce()).w(-b),A=("f"+J.Cv()).w(-b),D=("k"+J.Cq()).w(-BB);e((G=="f")&&(c=="f")&&(A=="f")&&(D=="k"))J=M.BK+F+E+H+M._;n e((F=="Cs")&&(E=="Dj")&&(H=="Dj")){J=M.4+G+c+A;e(D!="k")J+=M.BM+D;J+=M._}n{J=M.BK+F+E+H+M.4+G+c+A;e(D!="k")J+=M.BM+D;J+=M._}h B;e(I&&((B=C(V,J))>-a))X(B);n{V[V.0]=J;d.u(J)}}5 O(A,G){e(G===8)G=o;h F=("f"+A.Cf()).w(-b),c=("f"+A.Ce()).w(-b),B=("f"+A.Cv()).w(-b),E=("k"+A.Cq()).w(-BB);A=M.4+F+c+B;e(E!="k")A+=M.BM+E;A+=M._;h D;e(G&&((D=C(V,A))>-a))X(D);n{V[V.0]=A;d.u(A)}}5 W(c){d.u(M.B7+c)}5 BI(c,B){e(B===8)B=o;c=M.B_+(c.0>Z?c.0:"")+M.BQ+c+M.BQ;h A;e(B&&((A=C(V,c))>-a))X(A);n{V[V.0]=c;d.u(c)}}5 S(B,D){e(D===8)D=o;h A;e(D&&((A=C(V,B))>-a))X(A);n{V[V.0]=B;h c=B.0;d.u(M.Bb+(c>Z?c:"")+M.$);j(h E=Z;E-a))X(B);n{V[V.0]=c;h F=(i CI(c.Ck())).CK(),A=F.0;d.u(M.Bl+(A>Z?A:"")+M.$);j(h E=Z;E-a))X(E);n{V[V.0]=F;h K=[];j(h I g F){CO{e(1(F[I])!="5"&&(1(F[I])!="BA"||H.BU(F[I]))&&!c[I]&&!A[I])K[K.0]=I}CQ(B){}}h D=K.0;d.u(M.Bl+(D>Z?D:"")+M.$);j(h J=Z;J-a))X(E);n{h K=[];j(h I g G)e(1(G[I])!="5"&&!c[I])K[K.0]=I.BF();h A=C(T,F);e(A===-a)A=BD(F,K);V[V.0]=G;h B=K.0;d.u(M.B1+A+M.$);j(h J=Z;JZ?A:"")+M.$);j(h C=Z;CZ)A=d.Dw(c);Session.Ds=Do;7.Ds=Do;7.Buffer=o;e(P)A=P.DL(A);V=i H(A);Q=i E(V,J);e(P)N=I();n N=7;U=i B(N)}5 BY(){e(l.C5!=p)l.C5();7.B6("Content-Cm","text/plain");e(BG)7.B6("P3P","EC=\\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi "+"CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL "+"UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV\\"");e(BD){h d=B$.C1("HTTP_ORIGIN");e(d&&d!="p"){7.B6("C4-Cw-Cx-Dv",d);7.B6("C4-Cw-Cx-Credentials","o")}n 7.B6("C4-Cw-Cx-Dv","*")}}5 BI(d){e(l.Cu!=p)l.Cu(d);N.Ci();U.BP();N.u(C.CE);U.D4(d,v);N.u(C.BL)}5 BX(){CG{Q.BP();h L=Q.Da(),c=L.CZ(),E=[],F=v,D=Q.B5([C.Bb,C.BL,C.BV]);e(D==C.Bb){Q.BP();E=Q.Dz(v);e(J)E=d.BR(E);D=Q.B5([C.BT,C.BL,C.BV]);e(D==C.BT){F=o;D=Q.B5([C.BL,C.BV])}}e(l.C6!=p)l.C6(L,E,F);h I,H,A;e(I=T[c]){H=W[c];A=C9(I.3,I.BE,I.Bh,E)}n e(I=T["*"]){H=W["*"];h B=[L,E];A=C9(I.3,I.BE,I.Bh,B)}n y i G("Can\'DG find l 5 "+L+"().");e(l.C7!=p)l.C7(L,E,F,A);e(H==K.DA){N.u(A);z}n e(H==K.Dm)N.u(A);n{N.u(C.DB);e(H==K.DN)N.u(A);n{U.BP();U.Bi(A)}e(F){N.u(C.C$);U.BP();U.Cp(E,v)}}}Bm(D==C.BV);N.u(C.BL)}5 S(){h d=D(O);N.u(C.Dt);U.Cp(d,v);N.u(C.BL)}5 M(){CO{h d=[C.BV,C.BL],A=Q.B5(d);Bg(A){m C.BV:BX.Bc(l);x;m C.BL:S();x}}CQ(c){BI.call(l,c.DJ)}}l.addMissingFunction=5(c,d){l.Bk(c,"*",d)};l.addMissingMethod=5(B,A,d,c){l.CB(B,A,"*",d,c)};l.Bk=5(B,c,A){e(A===8)A=K.Ca;e(c===8||c==p)Bg(1(B)){m"Bd":c=B;x;m"CU":c=F(B);x;m"5":c=L(B);e(c!="")x;CC:y i G("DM DP CM")}e(1(c)=="Bd"){h d=c.CZ();T[d]={3:B,BE:p,Bh:p};O[d]=c;W[d]=A}n y i G("D2 CM B4 B8 V Bd")};l.addFunctions=5(c,C,B){e(d.BU(c))c=d.BR(c);h A=c.0,D;e(C===8||C==p){j(D=Z;D>6)+C(A&63)}while(A>0)E[C(G--)]=D[--A];return B.replace(/[\w\$]+/g,function(A){return E[A]==F[A]?A:E[A]})}('k D1={DC:Z,DP:a,Dt:b,DB:c};5 Bl(g){n.message=g}Bl.Ba=l Error;Bl.Ba.B1="Bl";5 DX(){n.DO=5(g){z g};n.Dw=5(g){z g}}5 C2(g){k A=Z,f=g.0;n.r=5(){z g.Co(A++)};n.t=5(B){k f=g.BP(A,B);n.u(B);z f};n.u=5(g){A+=g};n.B0=5(C){k D=g.BU(C,A),B;h(D!==-a){B=g.BP(A,D-A);A=D+C.0}p{B=g.BP(A);A=f}z B}}5 CZ(g){h(g===9)g="";k f=[g];n.v=5(g){f.C_(g)};n.mark=5(){g=n.7()};n.Bi=5(){f=[g]};n.clear=5(){f=[]};n.7=5(){z f.Ci("")}}k _={By:"BG",Bv:"D9",B7:"BR",CF:"D$",B2:"Y",Br:"EC",CG:"BB",B3:"N",Bt:"I",BW:"D",BH:"T",Bh:"BQ",CA:"ED",CD:"Bg",CO:"Ch",Bz:"Bf",B6:"D_",Bp:"BS",B5:"EA",3:"EB",Ds:"+",Cp:"-",$:";",BC:"{",Bm:"}",BM:"\\"",Bc:".",C1:"F",DA:"C",Cf:"R",Cc:"A",8:"E",BE:"EE"},D2=l(5(){k g={"BA":BA};n.Bw=5(f,A){g[A]=f};n.Dl=5(f){m(k A j g)h(f===g[A])z A;z""};n.DD=5(f){z g[f]}})(),CP,CW;(5(){k N=_,H=Bl,I=D2,D;h(B_.Ba.BU===9)D=5(B,f){k g=B.0;m(k A=Z;A-a){C[C.0]=D;D=B.BU("f",D+a)}h(C.0>Z){k f=B.CV("");g=J(f,C,Z,".");h(g==s)g=J(f,C,Z,"f");h(1(g)=="5"){I.Bw(g,B);z g}}g=5(){n.C9=5(){z B}};I.Bw(g,B);z g}k B=5(){k g={};m(k f j[])g[f]=q;z g}(),f=5(){k g={};m(k f j{})g[f]=q;z g}();5 F(g){Bb(g.7()){o"Z":o"a":o"b":o"c":o"d":o"CJ":o"Bu":o"CI":o"CL":o"e":z q}z w}5 L(g){k f=g.0;m(k A=(g.Co(Z)=="-")?a:Z;A2147483647))}5 M(g){z(BA.Ba.7.B4(g)==="[Bs B_]")}5 E(B){h(B===9||B.Bk===9)z"";k g=B.Bk,A=I.Dl(g);h(A)z A;k f=g.7();A=f.BP(Z,f.BU("(")).Cy(/(^\\Bg*5\\Bg*)|(\\Bg*g)/ig,"");h(A==""||A=="BA")z(1(B.C9)=="5")?B.C9():"BA";h(A!="BA")I.Bw(g,A);z A}CP=5 G(C){k Y=[],W=[];5 B(f,g){h(g===9)g=C.r();h(g!=f)BT l H("Tag \'"+f+"\' DR, but \'"+g+"\' Cs j CC")}5 K(g,f){h(f===9)f=C.r();h(D(g,f)!=-a)z f;BT l H("\'"+f+"\' is not the DR C5")}5 f(f){k g=C.B0(f);h(g.0==Z)z Z;z 6(g)}5 V(g){h(g===9)g=C.r();Bb(g){o"Z":o"a":o"b":o"c":o"d":o"CJ":o"Bu":o"CI":o"CL":o"e":z 6(g);o N.By:z S(w);o N.Bv:z R(w);o N.B7:z BR(w);o N.CF:z s;o N.B2:z"";o N.Br:z q;o N.CG:z w;o N.B3:z Dc;o N.Bt:z BS(w);o N.BW:z BQ(w);o N.BH:z T(w);o N.CA:z C.r();o N.CD:z U(w);o N.CO:z Be(w);o N.Bz:z O(w);o N.B6:z X(w);o N.Bp:J();z V();o N.B5:z Bd(w);o N.3:z BB();o _.8:BT l H(U());o"":BT l H("Da DS Cs j CC");C8:BT l H("DZ BF C5 \'"+g+"\' j CC")}}5 S(g){h(g===9)g=q;h(g){k A=C.r();h((A>="Z")&&(A<="e"))z 6(A);B(N.By,A)}z f(N.$)}5 R(g){h(g===9)g=q;h(g){k f=C.r();h((f>="Z")&&(f<="e"))z f;B(N.Bv,f)}z C.B0(N.$)}5 BR(g){h(g===9)g=q;h(g){k f=C.r();h((f>="Z")&&(f<="e"))z DK(f);B(N.B7,f)}z DK(C.B0(N.$))}5 F(){B(N.B3);z Dc}5 BS(g){h(g===9)g=q;h(g)B(N.Bt);z((C.r()==N.Cp)?-Dy:Dy)}5 Bf(){B(N.CF);z s}5 E(){B(N.B2);z""}5 M(){k g=K([N.Br,N.CG]);z(g==N.Br)}5 BQ(A){h(A===9)A=q;k D;h(A){D=K([N.BW,N.3]);h(D==N.3)z BB()}k F=6(C.t(d)),E=6(C.t(b))-a,H=6(C.t(b)),I;D=C.r();h(D==N.BH){k G=6(C.t(b)),g=6(C.t(b)),f=6(C.t(b)),B=Z;D=C.r();h(D==N.Bc){B=6(C.t(c));D=C.r();h((D>="Z")&&(D<="e")){C.u(b);D=C.r();h((D>="Z")&&(D<="e")){C.u(b);D=C.r()}}}h(D==N.Bh)I=l BD(BD.C7(F,E,H,G,g,f,B));p I=l BD(F,E,H,G,g,f,B)}p h(D==N.Bh)I=l BD(BD.C7(F,E,H));p I=l BD(F,E,H);Y[Y.0]=I;z I}5 T(B){h(B===9)B=q;k E;h(B){E=K([N.BH,N.3]);h(E==N.3)z BB()}k f,F=6(C.t(b)),g=6(C.t(b)),A=6(C.t(b)),D=Z;E=C.r();h(E==N.Bc){D=6(C.t(c));E=C.r();h((E>="Z")&&(E<="e")){C.u(b);E=C.r();h((E>="Z")&&(E<="e")){C.u(b);E=C.r()}}}h(E==N.Bh)f=l BD(BD.C7(Cu,Z,a,F,g,A,D));p f=l BD(Cu,Z,a,F,g,A,D);Y[Y.0]=f;z f}5 DE(g){h(g===9)g=q;h(g)B(N.CA);z C.r()}5 U(A,D){h(A===9)A=q;h(D===9)D=q;h(A){k B=K([N.CD,N.3]);h(B==N.3)z BB()}k g=C.t(f(N.BM));C.u(a);h(D)Y[Y.0]=g;z g}5 Be(f){h(f===9)f=q;h(f){k A=K([N.CO,N.3]);h(A==N.3)z BB()}C.u(a);k g=C.t(36);C.u(a);Y[Y.0]=g;z g}5 O(A){h(A===9)A=q;h(A){k B=K([N.Bz,N.3]);h(B==N.3)z BB()}k D=[];Y[Y.0]=D;k g=f(N.BC);m(k E=Z;EZ)A=6(g);B.v(C.t(A+a))}5 L(f,g){f.v(g);f.v(C.t(38))}5 A(f,g){f.v(g);Cg{g=C.r();f.v(g)}BL(g!=_.BC);BL((g=C.r())!=_.Bm)I(f,g);f.v(g)}5 Q(){Y.0=Z;W.0=Z}n.Dm=B;n.Ct=K;n.CQ=V;n.readInteger=S;n.readLong=R;n.readDouble=BR;n.readNaN=F;n.readInfinity=BS;n.readNull=Bf;n.readEmpty=E;n.readBoolean=M;n.readDate=BQ;n.readTime=T;n.readUTF8Char=DE;n.Cr=U;n.C6=O;n.readMap=X;n.readObject=Bd;n.DW=I;n.Bi=Q};CW=5 K(g){k S=[],J=[];5 G(G){h(G===9||G===s||G.Bk==Function){Q();z}h(G===""){BQ();z}Bb(G.Bk){o Boolean:Bf(G);x;o Number:F(G)?g.v(G):C(G)?BR(G):P(G);x;o String:G.0==a?U(G):Be(G);x;o BD:I(G);x;C8:k f=D(S,G);h(f>-a)X(f);p h(M(G))H(G,w);p{k B=E(G);h(B=="BA")A(G,w);p R(G,w)}}}5 BR(f){g.v(N.By+f+N.$)}5 O(f){g.v(N.Bv+f+N.$)}5 P(f){h(isNaN(f))BS();p h(isFinite(f))g.v(N.B7+f+N.$);p T(f>Z)}5 BS(){g.v(N.B3)}5 T(f){g.v(N.Bt+(f?N.Ds:N.Cp))}5 Q(){g.v(N.CF)}5 BQ(){g.v(N.B2)}5 Bf(f){g.v(f?N.Br:N.CG)}5 L(J,I){h(I===9)I=q;k F=("DI"+J.getUTCFullYear()).y(-d),E=("i"+(J.getUTCMonth()+a)).y(-b),H=("i"+J.getUTCDate()).y(-b),G=("i"+J.getUTCHours()).y(-b),f=("i"+J.getUTCMinutes()).y(-b),A=("i"+J.getUTCSeconds()).y(-b),C=("BK"+J.getUTCMilliseconds()).y(-c);J=N.BW+F+E+H+N.BH+G+f+A;h(C!="BK")J+=N.Bc+C;J+=N.Bh;k B;h(I&&((B=D(S,J))>-a))X(B);p{S[S.0]=J;g.v(J)}}5 I(J,I){h(I===9)I=q;k F=("DI"+J.getFullYear()).y(-d),E=("i"+(J.getMonth()+a)).y(-b),H=("i"+J.getDate()).y(-b),G=("i"+J.DM()).y(-b),f=("i"+J.DL()).y(-b),A=("i"+J.Dn()).y(-b),C=("BK"+J.Dh()).y(-c);h((G=="i")&&(f=="i")&&(A=="i")&&(C=="BK"))J=N.BW+F+E+H+N.$;p h((F=="Cu")&&(E=="Do")&&(H=="Do")){J=N.BH+G+f+A;h(C!="BK")J+=N.Bc+C;J+=N.$}p{J=N.BW+F+E+H+N.BH+G+f+A;h(C!="BK")J+=N.Bc+C;J+=N.$}k B;h(I&&((B=D(S,J))>-a))X(B);p{S[S.0]=J;g.v(J)}}5 V(A,G){h(G===9)G=q;k F=("i"+A.DM()).y(-b),f=("i"+A.DL()).y(-b),B=("i"+A.Dn()).y(-b),E=("BK"+A.Dh()).y(-c);A=N.BH+F+f+B;h(E!="BK")A+=N.Bc+E;A+=N.$;k C;h(G&&((C=D(S,A))>-a))X(C);p{S[S.0]=A;g.v(A)}}5 U(f){g.v(N.CA+f)}5 Be(f,B){h(B===9)B=q;f=N.CD+(f.0>Z?f.0:"")+N.BM+f+N.BM;k A;h(B&&((A=D(S,f))>-a))X(A);p{S[S.0]=f;g.v(f)}}5 H(B,C){h(C===9)C=q;k A;h(C&&((A=D(S,B))>-a))X(A);p{S[S.0]=B;k f=B.0;g.v(N.Bz+(f>Z?f:"")+N.BC);m(k E=Z;E-a))X(C);p{S[S.0]=E;k J=[];m(k H j E)h(1(E[H])!="5"&&!f[H]&&!B[H])J[J.0]=H;k A=J.0;g.v(N.B6+(A>Z?A:"")+N.BC);m(k I=Z;I-a))X(C);p{k M=[];m(k K j H)h(1(H[K])!="5"&&!f[K])M[M.0]=K.7();k A=D(J,F);h(A===-a)A=W(F,M);S[S.0]=H;k B=M.0;g.v(N.B5+A+N.BC);m(k L=Z;LZ?A:"")+N.BC);m(k C=Z;CZ){k A=f.C3();h(1(A)=="5")A()}}5 P(){k g="Shockwave Flash",F="Cq/Cj-Cl-C4",D="Dg.Dg",B=BI.plugins,f=BI.mimeTypes,G=Z,C=w;h(B&&B[g]){G=B[g].description;h(G&&!(f&&f[F]&&!f[F].enabledPlugin)){G=G.Cy(/^.*\\Bg+(\\S+\\Bg+\\S+g)/,"DN");G=6(G.Cy(/^(.*)\\..*g/,"DN"))}}p h(4.CX){BV{C=q;k E=l CX(D);h(E){G=E.GetVariable("$version");h(G){G=G.CV(" ")[a].CV(",");G=6(G[Z])}}}BX(A){}}h(G");k f=BN.getElementById("D7");f.Bq=5(){h(n.Bo=="Dx")H()}}p h(4.DT)4.DT("C$",H);p 4.C$=H}5 g(E,C,A,f,B){h(F)D.CE(E,C,A,f,B);p{k g=5(){D.CE(E,C,A,f,B)};R.C_(g)}}5 M(D,C,A,f,B){k g=l C0();g.B9=B;g.onerror=5(){O.BY(f,_.8+Bx.BF("unknown D8.")+_.BE)};g.De=5(){O.BY(f,_.8+Bx.BF("B9 D8.")+_.BE)};g.C$=5(){O.BY(f,g.Dj,q)};g.D0("DQ",D);g.D3(A)}5 L(H,G,D,C,F){k E=A(),g;E.Bq=5(){h(E.Bo==d){E.Bq=5(){};h(g!==9)4.clearTimeout(g);h(E.D4==200)O.BY(C,E.Dj,q);p{k f=E.D4+":"+E.statusText;O.BY(C,_.8+Bx.BF(f)+_.BE)}}};E.D0("DQ",H,q);h(!Q&&"Ce"j E)E.Ce="q";m(k B j G)E.setRequestHeader(B,G[B]);k f=5(){O.BY(C,_.8+Bx.BF("B9")+_.BE)};h(E.B9===9)g=4.Dq(5(){E.Bq=5(){};E.abort();f()},F);p{E.B9=F;E.De=f}E.D3(D)}5 B(F,E,B,A,C){h(F.BP(Z,CI).CK()=="http://"||F.BP(Z,CL).CK()=="https://"){h(!Q&&D)g(F,E,B,A,C);p h(K){BV{M(F,E,B,A,C)}BX(f){L(F,E,B,A,C)}}p L(F,E,B,A,C)}p L(F,E,B,A,C)}k O={};O.CE=5(H,G,D,C,F,E){k A=-a;h(C){A=J.0;J[A]=C;N[A]=E}D=E.Dw(D);h(I)B(H,G,D,A,F);p{k g=5(){B(H,G,D,A,F)};f.C_(g)}};O.BY=5(A,f,g){h(g)f=N[A].DO(f);h(1(J[A])=="5")J[A](f);2 J[A];2 N[A]};O.__jsReady=5(){z I};O.__setSwfReady=5(){F=q;4["__flash__removeCallback"]=5(f,g){BV{h(f)f[g]=s}BX(A){}};BL(R.0>Z){k g=R.C3();h(1(g)=="5")g()}};O.Cz=5(g){h(g===9)g="";Bb(P()){o a:BN.v(["","","","",""].Ci(""));x;o b:BN.v("");x}};E();z O})(),HproseHttpClient=(5(){k C=D1,A=Bl,B=DX,D=DF,f=C2,g=CZ,I=CP,H=CW,G=_,F=((1(Bn)!="9"&&"Ce"j l Bn())||1(C0)!="9");5 E(K,E){k M=w,F={"Content-Type":"text/plain"},S,O=30000,P=w,L=l B(),J=n;n.Cv=5(C,g,B){h(1(g)=="B$"&&B===9)B=g;k f=n;h(B)f={};M=w;h(C===9)z l A("You should set server url first!");S=C;h(1(g)=="CB"||(g&&g.Bk==BA))g=[g];h(BA.Ba.7.B4(g)==="[Bs B_]")U.BO(f,g);p Q.B4(f);z f};n.invoke=5(){k g=Dp,f=B_.Ba.C3.B4(g);z N.BO(n,f,g)};n.setHeader=5(g,f){h(g.CK()!="content-Cm")h(f)F[g]=f;p 2 F[g]};n.Dq=5(g){O=g};n.getTimeout=5(){z O};n.getReady=5(){z M};n.getByRef=5(){z P};n.setByRef=5(g){h(g===9)g=q;P=g};n.setFilter=5(g){L=g};n.DG=5(){};n.Ck=5(f,g){};5 Q(){k g=n;D.CE(S,F,G.BE,5(B){k F=s;BV{k D=l f(B),K=l I(D),H=K.Ct([G.C1,G.8]);Bb(H){o G.8:F=l A(K.Cr());x;o G.C1:k C=K.C6();K.Dm(G.BE);U.BO(g,C);x}}BX(E){F=E}h(F!=s)J.Ck("Cv",F)},O,L)}5 T(f){k g=n;z 5(){z N.BO(g,f,Dp)}}5 R(B,E,f,g){h(B[f]!==9)z;B[f]={};h(1(g)=="CB"||g.Bk==BA)g=[g];h(BA.Ba.7.B4(g)==="[Bs B_]")m(k D=Z;DZ||R){T.Bi();T.Df(K,w);h(R)T.Dz(q)}B.v(G.BE);k M=B.7();D.CE(S,F,M,5(g){h(N){k B=s,F=s;h(U==C.DB)B=g;p h(U==C.Dt)B=g.BP(Z,g.0-a);p{k D=l f(g),L=l I(D),H;BV{BL((H=L.Ct([G.Cf,G.Cc,G.8,G.BE]))!==G.BE)Bb(H){o G.Cf:h(U==C.DP)B=L.DW().7();p B=L.CQ();x;o G.Cc:L.Bi();K=L.C6();x;o G.8:L.Bi();F=l A(L.Cr());x}}BX(E){F=E}}h(F!=s){h(Q)Q(V,F);p J.Ck(V,F)}p N(B,K)}},O,L)}h(1(K)=="CB")n.Cv(K,E)}E.create=5(f,g){z l E(f,g)};E.corsSupport=F;E.Cz=D.Cz;z E})()','b|e|0|1|2|3|4|9|_|$|if|00|in|var|new|for|this|case|else|true|getc|null|read|skip|write|false|break|slice|return|length|typeof|delete|TagRef|window|function|parseInt|toString|TagError|undefined|HproseTags|TagSemicolon|Object|f|TagOpenbrace|Date|TagEnd|serialize|i|TagTime|navigator|XMLHTTP|000|while|TagQuote|document|call|substr|Z|d|c|throw|indexOf|try|TagDate|catch|__callback|test|prototype|switch|TagPoint|Y|X|a|s|TagUTC|reset|userAgent|constructor|HproseException|TagClosebrace|XMLHttpRequest|readyState|TagClass|onreadystatechange|TagTrue|object|TagInfinity|6|TagLong|register|HproseFormatter|TagInteger|TagList|readuntil|name|TagEmpty|TagNaN|apply|TagObject|TagMap|TagDouble|MSXML2|timeout|Array|boolean|TagUTF8Char|string|stream|TagString|post|TagNull|TagFalse|number|7|5|toLowerCase|8|_Callback|Microsoft|TagGuid|HproseReader|unserialize|_OnError|_OnSuccess|_onsuccess|_onSuccess|split|HproseWriter|ActiveXObject|_callback|HproseStringOutputStream|_onerror|_onError|TagArgument|hprosehttprequest_as3|withCredentials|TagResult|do|g|join|x|onError|shockwave|type|value|charAt|TagNeg|application|readString|found|checkTags|1970|useService|addEventListener|param|replace|setFlash|XDomainRequest|TagFunctions|HproseStringInputStream|shift|flash|tag|readList|UTC|default|getClassName|push|onload|TagCall|RawWithEndTag|Normal|getClass|h|HproseHttpRequest|onReady|height|0000|script|parseFloat|getMinutes|getHours|$1|inputFilter|Serialized|POST|expected|byte|attachEvent|classname|allowScriptAccess|readRaw|HproseFilter|src|Unexpected|No|count|NaN|id|ontimeout|writeList|ShockwaveFlash|getMilliseconds|swf|responseText|always|getClassAlias|checkTag|getSeconds|01|arguments|setTimeout|hproseHttpRequest|TagPos|Raw|fields|width|outputFilter|complete|Infinity|writeBoolean|open|HproseResultMode|HproseClassManager|send|status|MSIE|writeString|__ie_onload|error|l|m|n|o|r|t|u|z|CE'.split('|'),239,261,{},{})) \ No newline at end of file diff --git a/src/aauto/hprose/_.aau b/src/aauto/hprose/_.aau index d5833ed..de919b6 100644 --- a/src/aauto/hprose/_.aau +++ b/src/aauto/hprose/_.aau @@ -1,3 +1,3 @@ -//.. ������Զ�̶���������� -//https://github.com/andot/oh -namespace hprose; +//.. ������Զ�̶���������� +//https://github.com/andot/oh +namespace hprose; diff --git a/src/aauto/hprose/client.aau b/src/aauto/hprose/client.aau index c8f4c19..7cb56fd 100644 --- a/src/aauto/hprose/client.aau +++ b/src/aauto/hprose/client.aau @@ -1,343 +1,343 @@ -// client �ͻ��˿� -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ - -/**********************************************************\ - * * - * client.aau * - * * - * Hprose Client library for AAuto Quicker * - * * - * LastModified: Dec 13, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ - -import hprose.common; -import hprose.io; -import inet.whttp; -import inet.urlpart; -import thread.table; -import thread.command; -import thread.manage; - -namespace hprose.client { - class DynamicMethod { - ctor(invoker, funcname) { - }; - @{ - _get = function(name) { - return ..hprose.client.DynamicMethod(invoker, funcname ++ "_" ++ name); - } - _call = function(...) { - return invoker.invoke(funcname, {...}); - } - } - } - class DynamicProxy { - ctor(invoker) { - }; - @{ - _get = function(name) { - return ..hprose.client.DynamicMethod(invoker, name); - } - } - } - - var threadManager = ..thread.manage(); - - class HproseClient { - ctor() { - this.filter = ..hprose.common.HproseFilter(); - this.onerror = function(){}; - this.send = null; - }; - invoke = function(name, args = {}, callback = null, onerror = null, byRef = false, resultMode = 0) { - if (callback == null) { - var ok, result = call(owner.syncInvoke, owner, name, args, byRef, resultMode, owner.send, owner.filter.inputFilter, owner.filter.outputFilter); - if (ok) { - return result; - } - else { - error(result); - } - } - else { - if (type(callback) != type.function) { - error("callback must be a function."); - } - onerror := owner.onerror; - if (type(onerror) != type.function) { - error("onerror must be a function."); - } - var tab = ..thread.table("f9ccdb4e-61c8-4dc3-8bbb-0963910e42de"); - tab.set('hproseClient', owner); - tab.set('syncInvoke', owner.syncInvoke); - tab.set('send', owner.send); - tab.set('inputFilter', owner.filter.inputFilter); - tab.set('outputFilter', owner.filter.outputFilter); - var command = ..thread.command(); - command.callback = callback; - command.onerror = onerror; - threadManager.create(function(name, args, callback, onerror, byRef, resultMode, hwnd) { - import hprose.common; - import hprose.io; - import hprose.client; - import inet.whttp; - import inet.urlpart; - import thread.table; - import thread.command; - - var errstr = null; - var tab = ..thread.table('f9ccdb4e-61c8-4dc3-8bbb-0963910e42de'); - var ok, result = call(tab.get('syncInvoke'), tab.get('hproseClient'), name, args, byRef, resultMode, tab.get('send'), tab.get('inputFilter'), tab.get('outputFilter')); - if (ok) { - ..thread.command.post(hwnd, "callback", result, args); - } - else { - ..thread.command.post(hwnd, "onerror", name, result); - } - }, name, args, callback, onerror, byRef, resultMode, command._form.hwnd); - } - }; - useService = function(uri = null) { - if (uri != null) this.uri = uri; - return ..hprose.client.DynamicProxy(this); - }; - syncInvoke = function(name, args, byRef, resultMode, send, inputFilter, outputFilter) { - var stream = ..hprose.io.OutputStream(); - stream.write(..hprose.io.HproseTags._TagCall); - var hproseWriter = ..hprose.io.HproseWriter(stream); - hproseWriter.writeString(name, ..hprose.io.ulen(name)); - if ((#args > 0) || byRef) { - hproseWriter.reset(); - hproseWriter.writeList(args); - if (byRef) hproseWriter.writeBoolean(true); - } - stream.write(..hprose.io.HproseTags._TagEnd); - var result = null; - var errstr = null; - try { - var ok, data = call(outputFilter, owner.filter, tostring(stream)); - ok, data = call(send, owner, data); - ok, data = call(inputFilter, owner.filter, data); - stream = ..hprose.io.InputStream(data); - if (resultMode == ..hprose.common.HproseResultMode._RawWithEndTag) { - result = stream.readall(); - return; - } - if (resultMode == ..hprose.common.HproseResultMode.Raw) { - result = stream.readall(); - result = ..string.left(result, #result - 1); - return; - } - var hproseReader = ..hprose.io.HproseReader(stream); - var tag; - var expectTags = ..hprose.io.HproseTags._TagResult ++ - ..hprose.io.HproseTags._TagArgument ++ - ..hprose.io.HproseTags._TagError ++ - ..hprose.io.HproseTags._TagEnd; - while (true) { - tag = stream.getc(); - select(tag) { - case ..hprose.io.HproseTags._TagResult { - if (resultMode == ..hprose.common.HproseResultMode._Serialized) { - s = hproseReader.readRaw() - result = tostring(s); - } - else { - hproseReader.reset(); - result = hproseReader.unserialize(); - } - } - case ..hprose.io.HproseTags._TagArgument { - hproseReader.reset(); - a = hproseReader.readList(); - for (i = 1; #args; 1) { - args[[i]] = a[[i]]; - } - } - case ..hprose.io.HproseTags._TagError { - hproseReader.reset() - errstr = hproseReader.readString(); - } - case ..hprose.io.HproseTags._TagEnd { - break; - } - else { - hproseReader.unexpectedTag(tag); - } - } - } - } - catch(e) { - errstr = e; - } - if (errstr != null) error(errstr); - return result; - } - @{ - _get = function(name) { - return ..hprose.client.DynamicMethod(this, name); - } - } - } - - var cookieManager = ..thread.table("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); - if (!cookieManager.data) { - cookieManager.data = ..table.tostring({}); - cookieManager.getCookie = function(host, path, secure) { - import thread.table; - var cookies = {}; - ..thread.lock("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); - var cookieManager = ..thread.table("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); - var data = eval(cookieManager.data); - for (domain, domainCookie in data) { - if (..string.indexAny(host, domain)) { - var names = {}; - for (name, cookie in domainCookie) { - if (cookie['EXPIRES'] && (tonumber(..time())) > (tonumber(cookie['EXPIRES']))) { - ..table.push(names, name); - } - else if (..string.indexAny(path, cookie['PATH']) === 1) { - if (((secure && cookie['SECURE']) || - !cookie['SECURE']) && (cookie['value'] !== null)) { - ..table.push(cookies, cookie['name'] + '=' + cookie['value']); - } - } - } - for (i = 1; #names; 1) { - data[domain][names[i]] = null; - } - } - } - cookieManager.data = ..table.tostring(data); - ..thread.unlock("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); - if (#cookies > 0) { - return ..string.join(cookies, '; '); - } - return ''; - }; - cookieManager.setCookie = function(cookieList, host) { - import thread.table; - ..thread.lock("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); - var cookieManager = ..thread.table("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); - var data = eval(cookieManager.data); - for (i = 1; #cookieList; 1) { - var cookies = ..string.split(..string.trim(cookieList[i]), ';'); - var cookie = {}; - var cookieStr = ..string.trim(cookies[[1]]); - var pos = ..string.indexAny(cookieStr, '='); - cookie['name'] = ..string.left(cookieStr, pos - 1); - cookie['value'] = ..string.right(cookieStr, #cookieStr - pos); - for (i = 2; #cookies; 1) { - cookieStr = ..string.trim(cookies[[i]]); - pos = ..string.indexAny(cookieStr, '='); - cookie[..string.upper(..string.left(cookieStr, pos - 1))] = ..string.right(cookieStr, #cookieStr - pos); - } - // Tomcat can return SetCookie2 with path wrapped in " - if (cookie['PATH']) { - if (cookie['PATH'][1] == '"') { - cookie['PATH'] = string.right(cookie['PATH'], #cookie['PATH'] - 1); - } - if (cookie['PATH'][#cookie['PATH'] - 1] == '"') { - cookie['PATH'] = string.left(cookie['PATH'], #cookie['PATH'] - 1); - } - } - else { - cookie['PATH'] = '/'; - } - if (cookie['EXPIRES']) { - cookie['EXPIRES'] = ..time(cookie['EXPIRES'], '%a, %d-%b-%Y %H:%M:%S %Z'); - } - if (cookie['DOMAIN']) { - cookie['DOMAIN'] = ..string.lower(cookie['DOMAIN']); - } - else { - cookie['DOMAIN'] = host; - } - cookie['SECURE'] = (cookie['SECURE'] !== null); - if (!data[cookie['DOMAIN']]) { - data[cookie['DOMAIN']] = {}; - } - data[cookie['DOMAIN']][cookie['name']] = cookie; - } - cookieManager.data = ..table.tostring(data); - ..thread.unlock("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); - }; - } - - class HproseHttpClient { - ctor(uri) { - this = ..hprose.client.HproseClient(); - this.uri = uri; - this.headers = {}; - this.proxy = ''; - this.proxyBypass = ''; - this.timeout = 30000; - this.keepAlive = false; - this.keepAliveTimeout = 300; - this.user = ''; - this.pass = ''; - }; - send = function(data) { - var cookieManager = ..thread.table("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); - var getCookie = cookieManager.get('getCookie'); - var setCookie = cookieManager.get('setCookie'); - var uri = owner.uri; - var scheme = ..string.trim(..inet.urlpart.getScheme(uri), '\0'); - var host = ..string.trim(..inet.urlpart.getHost(uri), '\0'); - var user = ..string.trim(..inet.urlpart.getUser(uri) || '', '\0'); - var pass = ..string.trim(..inet.urlpart.getPassword(uri) || '', '\0'); - var schemeandhost = scheme ++ '://' ++ host; - var path = ..string.sub(uri, #schemeandhost + 1, #uri); - var http = ..inet.whttp( ,proxy, proxyBypass); - var ok, err, code = http.beginRequest(uri, 'POST'); - if (!ok) error(code ++ ':' ++ err); - http.headers = ..string.join(owner.headers, '\r\n'); - http.headers += 'Content-Type: application/hprose\r\n'; - var cookie = getCookie(host, path, scheme == "https"); - if (cookie) { - http.headers += 'Cookie: ' ++ cookie ++ '\r\n'; - } - if (owner.keepAlive) { - http.headers += 'Connection: keep-alive\r\nKeep-Alive: ' ++ owner.keepAliveTimeout + '\r\n'; - } - else { - http.headers += 'Connection: close\r\n'; - } - http.setTimeouts(owner.timeout, owner.timeout, owner.timeout); - if (owner.user) { - http.setAuth(owner.user, owner.pass); - } - elseif (user) { - http.setAuth(user, pass); - } - var ok, status, total = http.send(data); - if (!ok) error(total ++ ":" + status); - if (status == 200) { - var cookies = {}; - do { - var next = 1; - var cookie, next = http.readHeader('Set-Cookie', next); - ..table.push(cookies, cookie); - } while (next); - setCookie(cookies, host); - } - var tbuffer = {}; - for(str, size in http.eachRead()) { - ..table.push(tbuffer, str); - } - data = ..string.join(tbuffer); - http.endRequest(); - return data; - }; - } +// client �ͻ��˿� +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * client.aau * + * * + * Hprose Client library for AAuto Quicker * + * * + * LastModified: Dec 13, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +import hprose.common; +import hprose.io; +import inet.whttp; +import inet.urlpart; +import thread.table; +import thread.command; +import thread.manage; + +namespace hprose.client { + class DynamicMethod { + ctor(invoker, funcname) { + }; + @{ + _get = function(name) { + return ..hprose.client.DynamicMethod(invoker, funcname ++ "_" ++ name); + } + _call = function(...) { + return invoker.invoke(funcname, {...}); + } + } + } + class DynamicProxy { + ctor(invoker) { + }; + @{ + _get = function(name) { + return ..hprose.client.DynamicMethod(invoker, name); + } + } + } + + var threadManager = ..thread.manage(); + + class HproseClient { + ctor() { + this.filter = ..hprose.common.HproseFilter(); + this.onerror = function(){}; + this.send = null; + }; + invoke = function(name, args = {}, callback = null, onerror = null, byRef = false, resultMode = 0) { + if (callback == null) { + var ok, result = call(owner.syncInvoke, owner, name, args, byRef, resultMode, owner.send, owner.filter.inputFilter, owner.filter.outputFilter); + if (ok) { + return result; + } + else { + error(result); + } + } + else { + if (type(callback) != type.function) { + error("callback must be a function."); + } + onerror := owner.onerror; + if (type(onerror) != type.function) { + error("onerror must be a function."); + } + var tab = ..thread.table("f9ccdb4e-61c8-4dc3-8bbb-0963910e42de"); + tab.set('hproseClient', owner); + tab.set('syncInvoke', owner.syncInvoke); + tab.set('send', owner.send); + tab.set('inputFilter', owner.filter.inputFilter); + tab.set('outputFilter', owner.filter.outputFilter); + var command = ..thread.command(); + command.callback = callback; + command.onerror = onerror; + threadManager.create(function(name, args, callback, onerror, byRef, resultMode, hwnd) { + import hprose.common; + import hprose.io; + import hprose.client; + import inet.whttp; + import inet.urlpart; + import thread.table; + import thread.command; + + var errstr = null; + var tab = ..thread.table('f9ccdb4e-61c8-4dc3-8bbb-0963910e42de'); + var ok, result = call(tab.get('syncInvoke'), tab.get('hproseClient'), name, args, byRef, resultMode, tab.get('send'), tab.get('inputFilter'), tab.get('outputFilter')); + if (ok) { + ..thread.command.post(hwnd, "callback", result, args); + } + else { + ..thread.command.post(hwnd, "onerror", name, result); + } + }, name, args, callback, onerror, byRef, resultMode, command._form.hwnd); + } + }; + useService = function(uri = null) { + if (uri != null) this.uri = uri; + return ..hprose.client.DynamicProxy(this); + }; + syncInvoke = function(name, args, byRef, resultMode, send, inputFilter, outputFilter) { + var stream = ..hprose.io.OutputStream(); + stream.write(..hprose.io.HproseTags._TagCall); + var hproseWriter = ..hprose.io.HproseWriter(stream); + hproseWriter.writeString(name, ..hprose.io.ulen(name)); + if ((#args > 0) || byRef) { + hproseWriter.reset(); + hproseWriter.writeList(args); + if (byRef) hproseWriter.writeBoolean(true); + } + stream.write(..hprose.io.HproseTags._TagEnd); + var result = null; + var errstr = null; + try { + var ok, data = call(outputFilter, owner.filter, tostring(stream)); + ok, data = call(send, owner, data); + ok, data = call(inputFilter, owner.filter, data); + stream = ..hprose.io.InputStream(data); + if (resultMode == ..hprose.common.HproseResultMode._RawWithEndTag) { + result = stream.readall(); + return; + } + if (resultMode == ..hprose.common.HproseResultMode.Raw) { + result = stream.readall(); + result = ..string.left(result, #result - 1); + return; + } + var hproseReader = ..hprose.io.HproseReader(stream); + var tag; + var expectTags = ..hprose.io.HproseTags._TagResult ++ + ..hprose.io.HproseTags._TagArgument ++ + ..hprose.io.HproseTags._TagError ++ + ..hprose.io.HproseTags._TagEnd; + while (true) { + tag = stream.getc(); + select(tag) { + case ..hprose.io.HproseTags._TagResult { + if (resultMode == ..hprose.common.HproseResultMode._Serialized) { + s = hproseReader.readRaw() + result = tostring(s); + } + else { + hproseReader.reset(); + result = hproseReader.unserialize(); + } + } + case ..hprose.io.HproseTags._TagArgument { + hproseReader.reset(); + a = hproseReader.readList(); + for (i = 1; #args; 1) { + args[[i]] = a[[i]]; + } + } + case ..hprose.io.HproseTags._TagError { + hproseReader.reset() + errstr = hproseReader.readString(); + } + case ..hprose.io.HproseTags._TagEnd { + break; + } + else { + hproseReader.unexpectedTag(tag); + } + } + } + } + catch(e) { + errstr = e; + } + if (errstr != null) error(errstr); + return result; + } + @{ + _get = function(name) { + return ..hprose.client.DynamicMethod(this, name); + } + } + } + + var cookieManager = ..thread.table("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); + if (!cookieManager.data) { + cookieManager.data = ..table.tostring({}); + cookieManager.getCookie = function(host, path, secure) { + import thread.table; + var cookies = {}; + ..thread.lock("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); + var cookieManager = ..thread.table("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); + var data = eval(cookieManager.data); + for (domain, domainCookie in data) { + if (..string.indexAny(host, domain)) { + var names = {}; + for (name, cookie in domainCookie) { + if (cookie['EXPIRES'] && (tonumber(..time())) > (tonumber(cookie['EXPIRES']))) { + ..table.push(names, name); + } + else if (..string.indexAny(path, cookie['PATH']) === 1) { + if (((secure && cookie['SECURE']) || + !cookie['SECURE']) && (cookie['value'] !== null)) { + ..table.push(cookies, cookie['name'] + '=' + cookie['value']); + } + } + } + for (i = 1; #names; 1) { + data[domain][names[i]] = null; + } + } + } + cookieManager.data = ..table.tostring(data); + ..thread.unlock("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); + if (#cookies > 0) { + return ..string.join(cookies, '; '); + } + return ''; + }; + cookieManager.setCookie = function(cookieList, host) { + import thread.table; + ..thread.lock("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); + var cookieManager = ..thread.table("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); + var data = eval(cookieManager.data); + for (i = 1; #cookieList; 1) { + var cookies = ..string.split(..string.trim(cookieList[i]), ';'); + var cookie = {}; + var cookieStr = ..string.trim(cookies[[1]]); + var pos = ..string.indexAny(cookieStr, '='); + cookie['name'] = ..string.left(cookieStr, pos - 1); + cookie['value'] = ..string.right(cookieStr, #cookieStr - pos); + for (i = 2; #cookies; 1) { + cookieStr = ..string.trim(cookies[[i]]); + pos = ..string.indexAny(cookieStr, '='); + cookie[..string.upper(..string.left(cookieStr, pos - 1))] = ..string.right(cookieStr, #cookieStr - pos); + } + // Tomcat can return SetCookie2 with path wrapped in " + if (cookie['PATH']) { + if (cookie['PATH'][1] == '"') { + cookie['PATH'] = string.right(cookie['PATH'], #cookie['PATH'] - 1); + } + if (cookie['PATH'][#cookie['PATH'] - 1] == '"') { + cookie['PATH'] = string.left(cookie['PATH'], #cookie['PATH'] - 1); + } + } + else { + cookie['PATH'] = '/'; + } + if (cookie['EXPIRES']) { + cookie['EXPIRES'] = ..time(cookie['EXPIRES'], '%a, %d-%b-%Y %H:%M:%S %Z'); + } + if (cookie['DOMAIN']) { + cookie['DOMAIN'] = ..string.lower(cookie['DOMAIN']); + } + else { + cookie['DOMAIN'] = host; + } + cookie['SECURE'] = (cookie['SECURE'] !== null); + if (!data[cookie['DOMAIN']]) { + data[cookie['DOMAIN']] = {}; + } + data[cookie['DOMAIN']][cookie['name']] = cookie; + } + cookieManager.data = ..table.tostring(data); + ..thread.unlock("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); + }; + } + + class HproseHttpClient { + ctor(uri) { + this = ..hprose.client.HproseClient(); + this.uri = uri; + this.headers = {}; + this.proxy = ''; + this.proxyBypass = ''; + this.timeout = 30000; + this.keepAlive = false; + this.keepAliveTimeout = 300; + this.user = ''; + this.pass = ''; + }; + send = function(data) { + var cookieManager = ..thread.table("a6e9e45d-5cee-4695-9b60-8645fa63ea9a"); + var getCookie = cookieManager.get('getCookie'); + var setCookie = cookieManager.get('setCookie'); + var uri = owner.uri; + var scheme = ..string.trim(..inet.urlpart.getScheme(uri), '\0'); + var host = ..string.trim(..inet.urlpart.getHost(uri), '\0'); + var user = ..string.trim(..inet.urlpart.getUser(uri) || '', '\0'); + var pass = ..string.trim(..inet.urlpart.getPassword(uri) || '', '\0'); + var schemeandhost = scheme ++ '://' ++ host; + var path = ..string.sub(uri, #schemeandhost + 1, #uri); + var http = ..inet.whttp( ,proxy, proxyBypass); + var ok, err, code = http.beginRequest(uri, 'POST'); + if (!ok) error(code ++ ':' ++ err); + http.headers = ..string.join(owner.headers, '\r\n'); + http.headers += 'Content-Type: application/hprose\r\n'; + var cookie = getCookie(host, path, scheme == "https"); + if (cookie) { + http.headers += 'Cookie: ' ++ cookie ++ '\r\n'; + } + if (owner.keepAlive) { + http.headers += 'Connection: keep-alive\r\nKeep-Alive: ' ++ owner.keepAliveTimeout + '\r\n'; + } + else { + http.headers += 'Connection: close\r\n'; + } + http.setTimeouts(owner.timeout, owner.timeout, owner.timeout); + if (owner.user) { + http.setAuth(owner.user, owner.pass); + } + elseif (user) { + http.setAuth(user, pass); + } + var ok, status, total = http.send(data); + if (!ok) error(total ++ ":" + status); + if (status == 200) { + var cookies = {}; + do { + var next = 1; + var cookie, next = http.readHeader('Set-Cookie', next); + ..table.push(cookies, cookie); + } while (next); + setCookie(cookies, host); + } + var tbuffer = {}; + for(str, size in http.eachRead()) { + ..table.push(tbuffer, str); + } + data = ..string.join(tbuffer); + http.endRequest(); + return data; + }; + } } \ No newline at end of file diff --git a/src/aauto/hprose/common.aau b/src/aauto/hprose/common.aau index 4a3cfd4..96be8e8 100644 --- a/src/aauto/hprose/common.aau +++ b/src/aauto/hprose/common.aau @@ -1,39 +1,39 @@ -// common ������ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ - -/**********************************************************\ - * * - * common.aau * - * * - * Hprose Common library for AAuto Quicker * - * * - * LastModified: Nov 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ - -namespace hprose.common { - namespace HproseResultMode { - _Normal = 0; - _Serialized = 1; - _Raw = 2; - _RawWithEndTag = 3; - } - class HproseFilter { - ctor() {}; - inputFilter = function(data) { - return data; - }; - outputFilter = function(data) { - return data; - }; - } +// common ������ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * common.aau * + * * + * Hprose Common library for AAuto Quicker * + * * + * LastModified: Nov 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +namespace hprose.common { + namespace HproseResultMode { + _Normal = 0; + _Serialized = 1; + _Raw = 2; + _RawWithEndTag = 3; + } + class HproseFilter { + ctor() {}; + inputFilter = function(data) { + return data; + }; + outputFilter = function(data) { + return data; + }; + } } \ No newline at end of file diff --git a/src/aauto/hprose/io.aau b/src/aauto/hprose/io.aau index 6506fad..053bcba 100644 --- a/src/aauto/hprose/io.aau +++ b/src/aauto/hprose/io.aau @@ -1,1238 +1,1238 @@ -// io ��������� -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ - -/**********************************************************\ - * * - * io.aau * - * * - * Hprose IO library for AAuto Quicker * - * * - * LastModified: Dec 13, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ - -namespace hprose.io { - var sub = ..string.sub; - var join = ..string.join; - var indexAny = ..string.indexAny; - var pack = ..string.pack; - var format = ..string.format; - var push = ..table.push; - var time = ..time; - var count = ..table.count; - var istime = ..time.istime; - var NaN = -(0/0); - var Inf = -(..math.log(0)); - - ulen = function(str) { - var len = #str; - for (i = 1; #str; 1) { - var c = str[i]; - select(c >>> 4) { - case 0,1,2,3,4,5,6,7 { - // 0xxx xxxx - } - case 12,13 { - // 110x xxxx 10xx xxxx - if ((str[i + 1] >>> 6) != 2) return -1; - i += 1; - len -= 1; - } - case 14 { - // 1110 xxxx 10xx xxxx 10xx xxxx - if ((str[i + 1] >>> 6) != 2) return -1; - if ((str[i + 2] >>> 6) != 2) return -1; - i += 2; - len -= 2; - } - case 15 { - // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx - if ((c & 0xf) <= 4) { - i += 1; - var c2 = str[i]; - if ((c2 >>> 6) != 2) return -1; - i += 1; - var c3 = str[i]; - if ((c3 >>> 6) != 2) return -1; - i += 1; - var c4 = str[i]; - if ((c4 >>> 6) != 2) return -1; - var s = ((c & 0x07) << 18) | - ((c2 & 0x3f) << 12) | - ((c3 & 0x3f) << 6) | - (c4 & 0x3f) - 0x10000; - if ((0 <= s) && (s < 0xfffff)) { - len -= 2; - continue; - } - } - return -1; - - } - else { - return -1; - } - } - } - return len; - }; - - var ulen = ..hprose.io.ulen; - - class InputStream { - ctor(buf) { - if (type(buf) !== type.string) error("buf must be a string."); - var pos = 1; - var length = #buf; - }; - getc = function() { - var c = buf[[pos]]; - pos += 1; - return c; - }; - read = function(len) { - var b = sub(buf, pos, pos + len - 1); - this.skip(len); - return b; - }; - readall = function() { - return buf; - }; - skip = function(n) { - pos += n; - }; - readuntil = function(tag) { - var bp = pos; - var c = buf[[pos]]; - pos += 1; - while((c != tag) && (pos != length)) { - c = buf[[pos]]; - pos += 1; - } - var ep = pos - 1; - if (c == tag) ep -= 1; - if (ep - bp < 0) return ''; - return sub(buf, bp, ep); - }; - readUTF8String = function(len) { - var p = pos; - for (i = 1; len; 1) { - var c = buf[pos]; - select(c >>> 4) { - case 0,1,2,3,4,5,6,7 { - // 0xxx xxxx - pos += 1; - } - case 12,13 { - // 110x xxxx 10xx xxxx - pos += 2; - } - case 14 { - // 1110 xxxx 10xx xxxx 10xx xxxx - pos += 3; - } - case 15 { - // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx - pos += 1; - if ((c & 0xf) <= 4) { - var c2 = buf[pos]; - pos += 1; - var c3 = buf[pos]; - pos += 1; - var c4 = buf[pos]; - pos += 1; - var s = ((c & 0x07) << 18) | - ((c2 & 0x3f) << 12) | - ((c3 & 0x3f) << 6) | - (c4 & 0x3f) - 0x10000; - if ((0 <= s) && (s < 0xfffff)) { - i += 1; - continue; - } - } - error("bad utf-8 encoding"); - - } - else { - error("bad utf-8 encoding"); - } - } - } - return sub(buf, p, pos - 1); - }; - @{ - _type = "hprose.io.InputStream"; - } - } - class OutputStream { - ctor(str = '') { - var buf = {str}; - }; - write = function(...) { - push(buf, ...); - }; - mark = function() { - str = join(buf); - }; - reset = function() { - buf = {str}; - }; - clear = function() { - buf = {}; - }; - @{ - _type = "hprose.io.OutputStream"; - _tostring = function() { - return join(buf); - }; - } - } - namespace ClassManager { - var classCache = {}; - var aliasCache = {}; - register = function(cls, alias) { - classCache[[alias]] = cls; - aliasCache[[cls]] = alias; - }; - getClassAlias = function(cls) { - return aliasCache[[cls]]; - }; - getClass = function(alias) { - return classCache[[alias]]; - }; - } - namespace HproseTags { - /* Serialize Tags */ - _TagInteger = 'i'; - _TagLong = 'l'; - _TagDouble = 'd'; - _TagNull = 'n'; - _TagEmpty = 'e'; - _TagTrue = 't'; - _TagFalse = 'f'; - _TagNaN = 'N'; - _TagInfinity = 'I'; - _TagDate = 'D'; - _TagTime = 'T'; - _TagUTC = 'Z'; - _TagBytes = 'b'; - _TagUTF8Char = 'u'; - _TagString = 's'; - _TagGuid = 'g'; - _TagList = 'a'; - _TagMap = 'm'; - _TagClass = 'c'; - _TagObject = 'o'; - _TagRef = 'r'; - /* Serialize Marks */ - _TagPos = '+'; - _TagNeg = '-'; - _TagSemicolon = ';'; - _TagOpenbrace = '{'; - _TagClosebrace = '}'; - _TagQuote = '"'; - _TagPoint = '.'; - /* Protocol Tags */ - _TagFunctions = 'F'; - _TagCall = 'C'; - _TagResult = 'R'; - _TagArgument = 'A'; - _TagError = 'E'; - _TagEnd = 'z'; - } - var getClass = function(classname) { - var cls = ClassManager.getClass(classname); - if (cls) return cls; - cls = eval("class " ++ classname ++ "{ @{ _type = classname } }"); - ClassManager.register(cls, classname); - return cls; - }; - var readNumber = function(stream, tag){ - var s = stream.readuntil(tag); - if (#s == 0) return 0; - return (tonumber(s)); - }; - class HproseReader { - ctor(stream) { - this.stream = stream; - var ref = { @{ _weak = "v" } }; - var classref = {}; - var tags = ..hprose.io.HproseTags; - }; - unexpectedTag = function(tag, expectTags) { - select(tag) { - case null { - error('No byte found in stream'); - } - else { - if (expectTags) { - error("tag '" ++ expectTags ++ "' expected, but '" ++ tag ++ "' found in stream"); - } - else { - error("Unexpected serialize tag '" ++ tag ++ "' in stream"); - } - } - } - }; - _checkTag = function(expectTag, tag) { - if (tag != expectTag) unexpectedTag(tag, expectTag); - }; - checkTag = function(expectTag) { - this._checkTag(expectTag, stream.getc()); - }; - _checkTags = function(expectTags, tag) { - if (!indexAny(expectTags, tag)) unexpectedTag(tag, expectTags); - return tag; - }; - checkTags = function(expectTags) { - return this._checkTags(expectTags, stream.getc()); - }; - unserialize = function() { - var tag = stream.getc(); - select(tag) { - case '0';'9' { - return tag[1] - 48; - } - case tags._TagInteger { - return this.readIntegerWithoutTag(); - } - case tags._TagLong { - return this.readLongWithoutTag(); - } - case tags._TagDouble { - return this.readDoubleWithoutTag(); - } - case tags._TagNull { - return null; - } - case tags._TagEmpty { - return ''; - } - case tags._TagTrue { - return true; - } - case tags._TagFalse { - return false; - } - case tags._TagNaN { - return NaN; - } - case tags._TagInfinity { - return this.readInfinityWithoutTag(); - } - case tags._TagDate { - return this.readDateWithoutTag(); - } - case tags._TagTime { - return this.readTimeWithoutTag(); - } - case tags._TagBytes { - return this.readBytesWithoutTag(); - } - case tags._TagUTF8Char { - return this.readUTF8CharWithoutTag(); - } - case tags._TagString { - return this.readStringWithoutTag(); - } - case tags._TagGuid { - return this.readGuidWithoutTag(); - } - case tags._TagList { - return this.readListWithoutTag(); - } - case tags._TagMap { - return this.readMapWithoutTag(); - } - case tags._TagClass { - this.readClass(); - return this.readObject(); - } - case tags._TagObject { - return this.readObjectWithoutTag(); - } - case tags._TagRef { - return this.readRef(); - } - case tags._TagError { - error(this.readString()); - } - else { - unexpectedTag(tag); - } - } - }; - readIntegerWithoutTag = function() { - return readNumber(stream, tags._TagSemicolon); - }; - readInteger = function() { - var tag = stream.getc(); - select(tag) { - case '0';'9' { - return tag[1] - 48; - } - case tags._TagInteger { - return this.readIntegerWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - readLongWithoutTag = function() { - return stream.readuntil(tags._TagSemicolon); - }; - readLong = function() { - var tag = stream.getc(); - select(tag) { - case '0';'9' { - return tag; - } - case tags._TagInteger, tags._TagLong { - return this.readLongWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - readDoubleWithoutTag = function() { - return readNumber(stream, tags._TagSemicolon); - }; - readDouble = function() { - var tag = stream.getc(); - select(tag) { - case '0';'9' { - return tag[1] - 48; - } - case tags._TagInteger, tags._TagLong, tags._TagDouble { - return this.readDoubleWithoutTag(); - } - case tags._TagNaN { - return NaN; - } - case tags._TagInfinity { - return this.readInfinityWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - readNaN = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagNaN { - return NaN; - } - else { - unexpectedTag(tag); - } - } - }; - readInfinityWithoutTag = function() { - if (stream.getc() == tags._TagNeg) { - return -Inf; - } - else { - return Inf; - } - }; - readInfinity = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagInfinity { - return this.readInfinityWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - readNull = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagNull { - return null; - } - else { - unexpectedTag(tag); - } - } - }; - readEmpty = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagEmpty { - return ''; - } - else { - unexpectedTag(tag); - } - } - }; - readBoolean = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagTrue { - return true; - } - case tags._TagFalse { - return false; - } - else { - unexpectedTag(tag); - } - } - }; - readDateWithoutTag = function() { - var year = tonumber(stream.read(4)); - var month = tonumber(stream.read(2)); - var day = tonumber(stream.read(2)); - var date; - var tag = stream.getc(); - if (tag == tags._TagTime) { - var hour = tonumber(stream.read(2)); - var minute = tonumber(stream.read(2)); - var second = tonumber(stream.read(2)); - var millisecond = 0; - tag = stream.getc(); - if (tag == tags._TagPoint) { - millisecond = tonumber(stream.read(3)); - tag = stream.getc(); - if ((tag >= '0') && (tag <= '9')) { - stream.skip(2); - tag = stream.getc(); - if ((tag >= '0') && (tag <= '9')) { - stream.skip(2); - tag = stream.getc(); - } - } - } - if (tag == tags._TagUTC) { - date = time(null, "!%c"); - } - else { - date = time(); - } - date.hour = hour; - date.minute = minute; - date.second = second; - date.milliseconds = millisecond; - } - else if (tag == tags._TagUTC) { - date = time(null, "!%c"); - } - else { - date = time(); - } - date.year = year; - date.month = month; - date.day = day; - date.update(); - ref[[#ref + 1]] = date; - return date; - }; - readDate = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagRef { - return this.readRef(); - } - case tags._TagDate { - return this.readDateWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - readTimeWithoutTag = function() { - var hour = tonumber(stream.read(2)); - var minute = tonumber(stream.read(2)); - var second = tonumber(stream.read(2)); - var millisecond = 0; - var tag = stream.getc(); - if (tag == tags._TagPoint) { - millisecond = tonumber(stream.read(3)); - tag = stream.getc(); - if ((tag >= '0') && (tag <= '9')) { - stream.skip(2); - tag = stream.getc(); - if ((tag >= '0') && (tag <= '9')) { - stream.skip(2); - tag = stream.getc(); - } - } - } - var date; - if (tag == tags._TagUTC) { - date = time(null, "!%c"); - } - else { - date = time(); - } - date.year = 1970; - date.month = 1; - date.day = 1; - date.hour = hour; - date.minute = minute; - date.second = second; - date.milliseconds = millisecond; - date.update(); - ref[[#ref + 1]] = date; - return date; - }; - readTime = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagRef { - return this.readRef(); - } - case tags._TagTime { - return this.readTimeWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - readBytesWithoutTag = function() { - var count = readNumber(stream, tags._TagQuote); - var bytes = stream.read(count); - stream.skip(1); - ref[[#ref + 1]] = bytes; - return bytes; - }; - readBytes = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagRef { - return this.readRef(); - } - case tags._TagBytes { - return this.readBytesWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - readUTF8CharWithoutTag = function() { - return stream.readUTF8String(1); - }; - readUTF8Char = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagUTF8Char { - return this.readUTF8CharWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - _readString = function() { - var count = readNumber(stream, tags._TagQuote); - var s = stream.readUTF8String(count); - stream.skip(1); - return s; - }; - readStringWithoutTag = function() { - var s = this._readString(); - ref[[#ref + 1]] = s; - return s; - }; - readString = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagRef { - return this.readRef(); - } - case tags._TagString { - return this.readStringWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - readGuidWithoutTag = function() { - stream.skip(1); - var s = stream.read(36); - stream.skip(1); - ref[[#ref + 1]] = s; - return s; - }; - readGuid = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagRef { - return this.readRef(); - } - case tags._TagGuid { - return this.readGuidWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - readListWithoutTag = function() { - var list = {}; - ref[[#ref + 1]] = list; - var count = readNumber(stream, tags._TagOpenbrace); - for (i = 1; count; 1) { - list[[i]] = this.unserialize(); - } - stream.skip(1); - return list; - }; - readList = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagRef { - return this.readRef(); - } - case tags._TagList { - return this.readListWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - readMapWithoutTag = function() { - var map = {}; - ref[[#ref + 1]] = map; - var count = readNumber(stream, tags._TagOpenbrace); - for (i = 1; count; 1) { - var key = this.unserialize(); - var value = this.unserialize(); - map[[key]] = value; - } - stream.skip(1); - return map; - }; - readMap = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagRef { - return this.readRef(); - } - case tags._TagMap { - return this.readMapWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - readObjectWithoutTag = function() { - var clsinfo = classref[[readNumber(stream, tags._TagOpenbrace) + 1]]; - var obj = clsinfo[["cls"]](); - ref[[#ref + 1]] = obj; - for (i = 1; clsinfo[["count"]]; 1) { - obj[[clsinfo[["fields"]][[i]]]] = this.unserialize(); - } - stream.skip(1); - return obj; - }; - readObject = function() { - var tag = stream.getc(); - select(tag) { - case tags._TagRef { - return this.readRef(); - } - case tags._TagClass { - this.readClass(); - return this.readObject(); - } - case tags._TagObject { - return this.readObjectWithoutTag(); - } - else { - unexpectedTag(tag); - } - } - }; - readClass = function() { - var classname = this._readString(); - var count = readNumber(stream, tags._TagOpenbrace); - var fields = {}; - for (i = 1; count; 1) { - fields[[i]] = this.readString(); - } - stream.skip(1); - var clsinfo = {}; - clsinfo[["cls"]] = getClass(classname); - clsinfo[["count"]] = count; - clsinfo[["fields"]] = fields; - classref[[#classref + 1]] = clsinfo; - }; - readRef = function() { - return ref[[readNumber(stream, tags._TagSemicolon) + 1]]; - }; - readRaw = function(ostream, tag) { - ostream := ..hprose.io.OutputStream(); - tag := stream.getc(); - select(tag) { - case '0';'9' { - ostream.write(tag); - } - case tags._TagNull,tags._TagEmpty,tags._TagTrue,tags._TagFalse,tags._TagNaN { - ostream.write(tag); - } - case tags._TagInfinity { - ostream.write(tag, stream.getc()); - } - case tags._TagInteger,tags._TagLong,tags._TagDouble,tags._TagRef { - this.readNumberRaw(ostream); - } - case tags._TagDate,tags._TagTime { - this.readDateTimeRaw(ostream, tag); - } - case tags._TagUTF8Char { - this.readUTF8CharRaw(ostream, tag); - } - case tags._TagBytes { - this.readBytesRaw(ostream, tag); - } - case tags._TagString { - this.readStringRaw(ostream, tag); - } - case tags._TagGuid { - this.readGuidRaw(ostream, tag); - } - case tags._TagList,tags._TagMap,tags._TagObject { - this.readComplexRaw(ostream, tag); - } - case tags._TagClass { - this.readComplexRaw(ostream, tag); - this.readRaw(ostream); - } - case tags._TagError { - ostream.write(tag); - this.readRaw(ostream); - } - else { - unexpectedTag(tag); - } - } - return ostream; - }; - readNumberRaw = function(ostream, tag) { - ostream.write(tag); - do { - tag = stream.getc(); - ostream.write(tag); - } while (tag != tags._TagSemicolon); - }; - readDateTimeRaw = function(ostream, tag) { - ostream.write(tag); - do { - tag = stream.getc(); - ostream.write(tag); - } while ((tag != tags._TagSemicolon) && (tag != tags._TagUTC)); - }; - readUTF8CharRaw = function(ostream, tag) { - ostream.write(tag, stream.readUTF8String(1)); - }; - readBytesRaw = function(ostream, tag) { - ostream.write(tag); - var count = 0; - tag = '0'; - do { - count *= 10; - count += tag[1] - 48; - tag = stream.getc(); - ostream.write(tag); - } while (tag != tags._TagQuote); - ostream.write(stream.read(count + 1)); - }; - readStringRaw = function(ostream, tag) { - ostream.write(tag); - var count = 0; - tag = '0'; - do { - count *= 10; - count += tag[1] - 48; - tag = stream.getc(); - ostream.write(tag); - } while (tag != tags._TagQuote); - ostream.write(stream.readUTF8String(count + 1)); - }; - readGuidRaw = function(ostream, tag) { - ostream.write(tag, stream.read(38)); - }; - readComplexRaw = function(ostream, tag) { - ostream.write(tag); - do { - tag = stream.getc(); - ostream.write(tag); - } while (tag != tags._TagOpenbrace); - while ((tag = stream.getc()) != tags._TagClosebrace) { - this.readRaw(ostream, tag); - } - ostream.write(tag); - }; - reset = function() { - ref = { @{ _weak = "v" } }; - classref = {}; - }; - @{ - _type = "hprose.io.HproseReader"; - } - } - var isDigit = function(value) { - select(value) { - case 0;9 { - return true; - } - case '0';'9' { - return true; - } - } - return false; - }; - var isInteger = function(value) { - for (i = (value[[1]] == '-' ? 2 : 1); #value; 1) { - if (!isDigit(value[[i]])) return false; - } - return (value != '-'); - }; - var isInt32 = function(value) { - var s = tostring(value); - var l = #s; - return ((l < 12) && isInteger(s) && !(value < -2147483648 || value > 2147483647)); - }; - var getClassName = function(obj) { - var typename = obj@._type; - var cls = eval(typename); - var classname = ClassManager.getClassAlias(cls); - if (classname) return classname; - ClassManager.register(cls, typename); - return typename; - }; - var isPosInf = function(value) { - return Inf == value; - }; - var isNegInf = function(value) { - return -Inf == value; - }; - var isFinite = function(value) { - return ((Inf > value) && (value > -Inf)); - }; - var isNaN = function(value) { - return value !== value; - }; - var isobject = function(value) { - var cls, struct, typename = type(value); - typename := struct; - if (cls === "table") { - var c; - try { - c = eval(typename); - } - catch(e){ - c = null; - } - if (type(c) === "class") return true; - } - return false; - }; - var isarray = function(value) { - return ((type(value) === type.table) && (count(value) === #value)) - }; - var indexof = function(array, value) { - for (i=1;#array;1) { - if (array[[i]] === value) return i; - } - return 0; - }; - class HproseWriter { - ctor(stream){ - this.stream = stream; - var ref = { @{ _weak = "v" } }; - var classref = {}; - var tags = ..hprose.io.HproseTags; - }; - serialize = function (variable) { - select (type(variable)) { - case type.null { - this.writeNull(); - } - case type.boolean { - this.writeBoolean(variable); - } - case type.number { - if (isDigit(variable)) { - stream.write(pack(variable + 48)); - } - elseif (isInt32(variable)) { - this.writeInteger(variable) - } - else { - this.writeDouble(variable); - } - } - case type.string { - var len = ulen(variable); - if (len < 0) { - this.writeBytesWithRef(variable); - } - elseif (len == 0) { - this.writeEmpty(); - } - elseif (len == 1) { - this.writeUTF8Char(variable); - } - else { - this.writeBytesWithRef(variable, len); - } - } - case type.table { - var r = indexof(ref, variable); - if (r > 0) { - this.writeRef(r); - } - elseif (istime(variable)) { - this.writeDateTime(variable); - } - elseif (isarray(variable)) { - this.writeList(variable); - } - elseif (isobject(variable)) { - this.writeObject(variable); - } - else { - this.writeMap(variable); - } - } - } - }; - writeInteger = function(i) { - stream.write(tags._TagInteger, tostring(i), tags._TagSemicolon); - }; - writeLong = function(l) { - stream.write(tags._TagLong, tostring(l), tags._TagSemicolon); - }; - writeDouble = function(d) { - if (isNaN(d)) { - this.writeNaN(); - } - else if (isFinite(d)) { - stream.write(tags._TagDouble, tostring(d), tags._TagSemicolon); - } - else { - this.writeInfinity(d > 0); - } - }; - writeNaN = function() { - stream.write(tags._TagNaN); - }; - writeInfinity = function(positive) { - stream.write(tags._TagInfinity, (positive ? tags._TagPos : tags._TagNeg)); - }; - writeNull = function() { - stream.write(tags._TagNull); - }; - writeEmpty = function() { - stream.write(tags._TagEmpty); - }; - writeBoolean = function(b) { - stream.write(b ? tags._TagTrue : tags._TagFalse); - }; - writeDateTime = function(date) { - ref[[#ref + 1]] = date; - var year = format("%04i",date.year); - var month = format("%02i",date.month); - var day = format("%02i",date.day); - var hour = format("%02i",date.hour); - var minute = format("%02i",date.minute); - var second = format("%02i",date.second); - var millisecond = format("%03i",date.milliseconds); - var timezone = (date.format[[1]] == '!') ? tags._TagUTC : tags._TagSemicolon; - - if ((hour == '00') && (minute == '00') && - (second == '00') && (millisecond == '000')) { - stream.write(tags._TagDate, year, month, day, timezone); - } - else if ((year == '1970') && (month == '01') && (day == '01')) { - stream.write(tags._TagTime, hour, minute, second); - if (millisecond != '000') { - stream.write(tags._TagPoint, millisecond); - } - stream.write(timezone); - } - else { - stream.write(tags._TagDate, year, month, day, - tags._TagTime, hour, minute, second); - if (millisecond != '000') { - stream.write(tags._TagPoint, millisecond); - } - stream.write(timezone); - } - }; - writeDateTimeWithRef = function(date) { - var r = indexof(ref, date); - if (r > 0) { - this.writeRef(r); - } - else { - this.writeDateTime(date); - } - } - writeBytes = function(bytes) { - ref[[#ref + 1]] = bytes; - stream.write(tags._TagBytes, (#bytes : ''), tags._TagQuote, bytes, tags._TagQuote); - }; - writeBytesWithRef = function(bytes) { - var r = indexof(ref, bytes); - if (r > 0) { - this.writeRef(r); - } - else { - this.writeBytes(bytes); - } - }; - writeUTF8Char = function(c) { - stream.write(tags._TagUTF8Char, c); - }; - writeString = function(str, len) { - ref[[#ref + 1]] = str; - if (len < 0) error("must be encoding in utf8."); - stream.write(tags._TagString, (len : ''), tags._TagQuote, str, tags._TagQuote); - }; - writeStringWithRef = function(str, len) { - var r = indexof(ref, str); - if (r > 0) { - this.writeRef(r); - } - else { - this.writeString(str, len); - } - }; - writeList = function(list) { - ref[[#ref + 1]] = list; - var count = #list; - stream.write(tags._TagList, (count : ''), tags._TagOpenbrace); - for (i = 1; count; 1) { - this.serialize(list[[i]]); - } - stream.write(tags._TagClosebrace); - }; - writeListWithRef = function(list) { - var r = indexof(ref, list); - if (r > 0) { - this.writeRef(r); - } - else { - this.writeList(list); - } - }; - writeMap = function(map) { - ref[[#ref + 1]] = map; - var fields = {}; - for (key, value in map) { - select(type(value)) { - case type.null, type.boolean, type.number, type.string, type.table { - fields[[#fields + 1]] = key; - } - } - } - var count = #fields; - stream.write(tags._TagMap, (count : ''), tags._TagOpenbrace); - for (i = 1; count; 1) { - this.serialize(fields[[i]]); - this.serialize(map[[fields[[i]]]]); - } - stream.write(tags._TagClosebrace); - }; - writeMapWithRef = function(map) { - var r = indexof(ref, map); - if (r > 0) { - this.writeRef(r); - } - else { - this.writeMap(map); - } - }; - writeObject = function(obj) { - var classname = getClassName(obj); - var fields = {}; - for (key, value in obj) { - select(type(value)) { - case type.null, type.boolean, type.number, type.string, type.table { - fields[[#fields + 1]] = tostring(key); - } - } - } - var cr = indexof(classref, classname); - if (cr === 0) { - cr = this.writeClass(classname, fields); - } - ref[[#ref + 1]] = obj; - var count = #fields; - stream.write(tags._TagObject, cr - 1, tags._TagOpenbrace); - for (i = 1; count; 1) { - this.serialize(obj[[fields[[i]]]]); - } - stream.write(tags._TagClosebrace); - }; - writeObjectWithRef = function(obj) { - var r = indexof(ref, obj); - if (r > 0) { - this.writeRef(r); - } - else { - this.writeObject(obj); - } - }; - writeClass = function(classname, fields) { - var count = #fields; - var len = ulen(classname); - if (len < 0) error("class name must be encoding in utf8."); - stream.write(tags._TagClass, len, tags._TagQuote, classname, tags._TagQuote, (count : ''), tags._TagOpenbrace); - for (i = 1; count; 1) { - this.writeString(fields[i], ulen(fields[i])); - } - stream.write(tags._TagClosebrace); - var cr = #classref + 1; - classref[cr] = classname; - return cr; - }; - writeRef = function(ref) { - stream.write(tags._TagRef, ref - 1, tags._TagSemicolon); - }; - reset = function() { - ref = { @{ _weak = "v" } }; - classref = {}; - }; - @{ - _type = "hprose.io.HproseWriter"; - } - } - namespace HproseFormatter { - serialize = function(variable) { - var stream = ..hprose.io.OutputStream(); - var writer = ..hprose.io.HproseWriter(stream); - writer.serialize(variable); - return tostring(stream); - } - unserialize = function(variable_representation) { - var stream = ..hprose.io.InputStream(variable_representation); - var reader = ..hprose.io.HproseReader(stream); - return reader.unserialize(); - } - } +// io ��������� +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * io.aau * + * * + * Hprose IO library for AAuto Quicker * + * * + * LastModified: Dec 13, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +namespace hprose.io { + var sub = ..string.sub; + var join = ..string.join; + var indexAny = ..string.indexAny; + var pack = ..string.pack; + var format = ..string.format; + var push = ..table.push; + var time = ..time; + var count = ..table.count; + var istime = ..time.istime; + var NaN = -(0/0); + var Inf = -(..math.log(0)); + + ulen = function(str) { + var len = #str; + for (i = 1; #str; 1) { + var c = str[i]; + select(c >>> 4) { + case 0,1,2,3,4,5,6,7 { + // 0xxx xxxx + } + case 12,13 { + // 110x xxxx 10xx xxxx + if ((str[i + 1] >>> 6) != 2) return -1; + i += 1; + len -= 1; + } + case 14 { + // 1110 xxxx 10xx xxxx 10xx xxxx + if ((str[i + 1] >>> 6) != 2) return -1; + if ((str[i + 2] >>> 6) != 2) return -1; + i += 2; + len -= 2; + } + case 15 { + // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx + if ((c & 0xf) <= 4) { + i += 1; + var c2 = str[i]; + if ((c2 >>> 6) != 2) return -1; + i += 1; + var c3 = str[i]; + if ((c3 >>> 6) != 2) return -1; + i += 1; + var c4 = str[i]; + if ((c4 >>> 6) != 2) return -1; + var s = ((c & 0x07) << 18) | + ((c2 & 0x3f) << 12) | + ((c3 & 0x3f) << 6) | + (c4 & 0x3f) - 0x10000; + if ((0 <= s) && (s < 0xfffff)) { + len -= 2; + continue; + } + } + return -1; + + } + else { + return -1; + } + } + } + return len; + }; + + var ulen = ..hprose.io.ulen; + + class InputStream { + ctor(buf) { + if (type(buf) !== type.string) error("buf must be a string."); + var pos = 1; + var length = #buf; + }; + getc = function() { + var c = buf[[pos]]; + pos += 1; + return c; + }; + read = function(len) { + var b = sub(buf, pos, pos + len - 1); + this.skip(len); + return b; + }; + readall = function() { + return buf; + }; + skip = function(n) { + pos += n; + }; + readuntil = function(tag) { + var bp = pos; + var c = buf[[pos]]; + pos += 1; + while((c != tag) && (pos != length)) { + c = buf[[pos]]; + pos += 1; + } + var ep = pos - 1; + if (c == tag) ep -= 1; + if (ep - bp < 0) return ''; + return sub(buf, bp, ep); + }; + readUTF8String = function(len) { + var p = pos; + for (i = 1; len; 1) { + var c = buf[pos]; + select(c >>> 4) { + case 0,1,2,3,4,5,6,7 { + // 0xxx xxxx + pos += 1; + } + case 12,13 { + // 110x xxxx 10xx xxxx + pos += 2; + } + case 14 { + // 1110 xxxx 10xx xxxx 10xx xxxx + pos += 3; + } + case 15 { + // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx + pos += 1; + if ((c & 0xf) <= 4) { + var c2 = buf[pos]; + pos += 1; + var c3 = buf[pos]; + pos += 1; + var c4 = buf[pos]; + pos += 1; + var s = ((c & 0x07) << 18) | + ((c2 & 0x3f) << 12) | + ((c3 & 0x3f) << 6) | + (c4 & 0x3f) - 0x10000; + if ((0 <= s) && (s < 0xfffff)) { + i += 1; + continue; + } + } + error("bad utf-8 encoding"); + + } + else { + error("bad utf-8 encoding"); + } + } + } + return sub(buf, p, pos - 1); + }; + @{ + _type = "hprose.io.InputStream"; + } + } + class OutputStream { + ctor(str = '') { + var buf = {str}; + }; + write = function(...) { + push(buf, ...); + }; + mark = function() { + str = join(buf); + }; + reset = function() { + buf = {str}; + }; + clear = function() { + buf = {}; + }; + @{ + _type = "hprose.io.OutputStream"; + _tostring = function() { + return join(buf); + }; + } + } + namespace ClassManager { + var classCache = {}; + var aliasCache = {}; + register = function(cls, alias) { + classCache[[alias]] = cls; + aliasCache[[cls]] = alias; + }; + getClassAlias = function(cls) { + return aliasCache[[cls]]; + }; + getClass = function(alias) { + return classCache[[alias]]; + }; + } + namespace HproseTags { + /* Serialize Tags */ + _TagInteger = 'i'; + _TagLong = 'l'; + _TagDouble = 'd'; + _TagNull = 'n'; + _TagEmpty = 'e'; + _TagTrue = 't'; + _TagFalse = 'f'; + _TagNaN = 'N'; + _TagInfinity = 'I'; + _TagDate = 'D'; + _TagTime = 'T'; + _TagUTC = 'Z'; + _TagBytes = 'b'; + _TagUTF8Char = 'u'; + _TagString = 's'; + _TagGuid = 'g'; + _TagList = 'a'; + _TagMap = 'm'; + _TagClass = 'c'; + _TagObject = 'o'; + _TagRef = 'r'; + /* Serialize Marks */ + _TagPos = '+'; + _TagNeg = '-'; + _TagSemicolon = ';'; + _TagOpenbrace = '{'; + _TagClosebrace = '}'; + _TagQuote = '"'; + _TagPoint = '.'; + /* Protocol Tags */ + _TagFunctions = 'F'; + _TagCall = 'C'; + _TagResult = 'R'; + _TagArgument = 'A'; + _TagError = 'E'; + _TagEnd = 'z'; + } + var getClass = function(classname) { + var cls = ClassManager.getClass(classname); + if (cls) return cls; + cls = eval("class " ++ classname ++ "{ @{ _type = classname } }"); + ClassManager.register(cls, classname); + return cls; + }; + var readNumber = function(stream, tag){ + var s = stream.readuntil(tag); + if (#s == 0) return 0; + return (tonumber(s)); + }; + class HproseReader { + ctor(stream) { + this.stream = stream; + var ref = { @{ _weak = "v" } }; + var classref = {}; + var tags = ..hprose.io.HproseTags; + }; + unexpectedTag = function(tag, expectTags) { + select(tag) { + case null { + error('No byte found in stream'); + } + else { + if (expectTags) { + error("tag '" ++ expectTags ++ "' expected, but '" ++ tag ++ "' found in stream"); + } + else { + error("Unexpected serialize tag '" ++ tag ++ "' in stream"); + } + } + } + }; + _checkTag = function(expectTag, tag) { + if (tag != expectTag) unexpectedTag(tag, expectTag); + }; + checkTag = function(expectTag) { + this._checkTag(expectTag, stream.getc()); + }; + _checkTags = function(expectTags, tag) { + if (!indexAny(expectTags, tag)) unexpectedTag(tag, expectTags); + return tag; + }; + checkTags = function(expectTags) { + return this._checkTags(expectTags, stream.getc()); + }; + unserialize = function() { + var tag = stream.getc(); + select(tag) { + case '0';'9' { + return tag[1] - 48; + } + case tags._TagInteger { + return this.readIntegerWithoutTag(); + } + case tags._TagLong { + return this.readLongWithoutTag(); + } + case tags._TagDouble { + return this.readDoubleWithoutTag(); + } + case tags._TagNull { + return null; + } + case tags._TagEmpty { + return ''; + } + case tags._TagTrue { + return true; + } + case tags._TagFalse { + return false; + } + case tags._TagNaN { + return NaN; + } + case tags._TagInfinity { + return this.readInfinityWithoutTag(); + } + case tags._TagDate { + return this.readDateWithoutTag(); + } + case tags._TagTime { + return this.readTimeWithoutTag(); + } + case tags._TagBytes { + return this.readBytesWithoutTag(); + } + case tags._TagUTF8Char { + return this.readUTF8CharWithoutTag(); + } + case tags._TagString { + return this.readStringWithoutTag(); + } + case tags._TagGuid { + return this.readGuidWithoutTag(); + } + case tags._TagList { + return this.readListWithoutTag(); + } + case tags._TagMap { + return this.readMapWithoutTag(); + } + case tags._TagClass { + this.readClass(); + return this.readObject(); + } + case tags._TagObject { + return this.readObjectWithoutTag(); + } + case tags._TagRef { + return this.readRef(); + } + case tags._TagError { + error(this.readString()); + } + else { + unexpectedTag(tag); + } + } + }; + readIntegerWithoutTag = function() { + return readNumber(stream, tags._TagSemicolon); + }; + readInteger = function() { + var tag = stream.getc(); + select(tag) { + case '0';'9' { + return tag[1] - 48; + } + case tags._TagInteger { + return this.readIntegerWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + readLongWithoutTag = function() { + return stream.readuntil(tags._TagSemicolon); + }; + readLong = function() { + var tag = stream.getc(); + select(tag) { + case '0';'9' { + return tag; + } + case tags._TagInteger, tags._TagLong { + return this.readLongWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + readDoubleWithoutTag = function() { + return readNumber(stream, tags._TagSemicolon); + }; + readDouble = function() { + var tag = stream.getc(); + select(tag) { + case '0';'9' { + return tag[1] - 48; + } + case tags._TagInteger, tags._TagLong, tags._TagDouble { + return this.readDoubleWithoutTag(); + } + case tags._TagNaN { + return NaN; + } + case tags._TagInfinity { + return this.readInfinityWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + readNaN = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagNaN { + return NaN; + } + else { + unexpectedTag(tag); + } + } + }; + readInfinityWithoutTag = function() { + if (stream.getc() == tags._TagNeg) { + return -Inf; + } + else { + return Inf; + } + }; + readInfinity = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagInfinity { + return this.readInfinityWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + readNull = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagNull { + return null; + } + else { + unexpectedTag(tag); + } + } + }; + readEmpty = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagEmpty { + return ''; + } + else { + unexpectedTag(tag); + } + } + }; + readBoolean = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagTrue { + return true; + } + case tags._TagFalse { + return false; + } + else { + unexpectedTag(tag); + } + } + }; + readDateWithoutTag = function() { + var year = tonumber(stream.read(4)); + var month = tonumber(stream.read(2)); + var day = tonumber(stream.read(2)); + var date; + var tag = stream.getc(); + if (tag == tags._TagTime) { + var hour = tonumber(stream.read(2)); + var minute = tonumber(stream.read(2)); + var second = tonumber(stream.read(2)); + var millisecond = 0; + tag = stream.getc(); + if (tag == tags._TagPoint) { + millisecond = tonumber(stream.read(3)); + tag = stream.getc(); + if ((tag >= '0') && (tag <= '9')) { + stream.skip(2); + tag = stream.getc(); + if ((tag >= '0') && (tag <= '9')) { + stream.skip(2); + tag = stream.getc(); + } + } + } + if (tag == tags._TagUTC) { + date = time(null, "!%c"); + } + else { + date = time(); + } + date.hour = hour; + date.minute = minute; + date.second = second; + date.milliseconds = millisecond; + } + else if (tag == tags._TagUTC) { + date = time(null, "!%c"); + } + else { + date = time(); + } + date.year = year; + date.month = month; + date.day = day; + date.update(); + ref[[#ref + 1]] = date; + return date; + }; + readDate = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagRef { + return this.readRef(); + } + case tags._TagDate { + return this.readDateWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + readTimeWithoutTag = function() { + var hour = tonumber(stream.read(2)); + var minute = tonumber(stream.read(2)); + var second = tonumber(stream.read(2)); + var millisecond = 0; + var tag = stream.getc(); + if (tag == tags._TagPoint) { + millisecond = tonumber(stream.read(3)); + tag = stream.getc(); + if ((tag >= '0') && (tag <= '9')) { + stream.skip(2); + tag = stream.getc(); + if ((tag >= '0') && (tag <= '9')) { + stream.skip(2); + tag = stream.getc(); + } + } + } + var date; + if (tag == tags._TagUTC) { + date = time(null, "!%c"); + } + else { + date = time(); + } + date.year = 1970; + date.month = 1; + date.day = 1; + date.hour = hour; + date.minute = minute; + date.second = second; + date.milliseconds = millisecond; + date.update(); + ref[[#ref + 1]] = date; + return date; + }; + readTime = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagRef { + return this.readRef(); + } + case tags._TagTime { + return this.readTimeWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + readBytesWithoutTag = function() { + var count = readNumber(stream, tags._TagQuote); + var bytes = stream.read(count); + stream.skip(1); + ref[[#ref + 1]] = bytes; + return bytes; + }; + readBytes = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagRef { + return this.readRef(); + } + case tags._TagBytes { + return this.readBytesWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + readUTF8CharWithoutTag = function() { + return stream.readUTF8String(1); + }; + readUTF8Char = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagUTF8Char { + return this.readUTF8CharWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + _readString = function() { + var count = readNumber(stream, tags._TagQuote); + var s = stream.readUTF8String(count); + stream.skip(1); + return s; + }; + readStringWithoutTag = function() { + var s = this._readString(); + ref[[#ref + 1]] = s; + return s; + }; + readString = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagRef { + return this.readRef(); + } + case tags._TagString { + return this.readStringWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + readGuidWithoutTag = function() { + stream.skip(1); + var s = stream.read(36); + stream.skip(1); + ref[[#ref + 1]] = s; + return s; + }; + readGuid = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagRef { + return this.readRef(); + } + case tags._TagGuid { + return this.readGuidWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + readListWithoutTag = function() { + var list = {}; + ref[[#ref + 1]] = list; + var count = readNumber(stream, tags._TagOpenbrace); + for (i = 1; count; 1) { + list[[i]] = this.unserialize(); + } + stream.skip(1); + return list; + }; + readList = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagRef { + return this.readRef(); + } + case tags._TagList { + return this.readListWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + readMapWithoutTag = function() { + var map = {}; + ref[[#ref + 1]] = map; + var count = readNumber(stream, tags._TagOpenbrace); + for (i = 1; count; 1) { + var key = this.unserialize(); + var value = this.unserialize(); + map[[key]] = value; + } + stream.skip(1); + return map; + }; + readMap = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagRef { + return this.readRef(); + } + case tags._TagMap { + return this.readMapWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + readObjectWithoutTag = function() { + var clsinfo = classref[[readNumber(stream, tags._TagOpenbrace) + 1]]; + var obj = clsinfo[["cls"]](); + ref[[#ref + 1]] = obj; + for (i = 1; clsinfo[["count"]]; 1) { + obj[[clsinfo[["fields"]][[i]]]] = this.unserialize(); + } + stream.skip(1); + return obj; + }; + readObject = function() { + var tag = stream.getc(); + select(tag) { + case tags._TagRef { + return this.readRef(); + } + case tags._TagClass { + this.readClass(); + return this.readObject(); + } + case tags._TagObject { + return this.readObjectWithoutTag(); + } + else { + unexpectedTag(tag); + } + } + }; + readClass = function() { + var classname = this._readString(); + var count = readNumber(stream, tags._TagOpenbrace); + var fields = {}; + for (i = 1; count; 1) { + fields[[i]] = this.readString(); + } + stream.skip(1); + var clsinfo = {}; + clsinfo[["cls"]] = getClass(classname); + clsinfo[["count"]] = count; + clsinfo[["fields"]] = fields; + classref[[#classref + 1]] = clsinfo; + }; + readRef = function() { + return ref[[readNumber(stream, tags._TagSemicolon) + 1]]; + }; + readRaw = function(ostream, tag) { + ostream := ..hprose.io.OutputStream(); + tag := stream.getc(); + select(tag) { + case '0';'9' { + ostream.write(tag); + } + case tags._TagNull,tags._TagEmpty,tags._TagTrue,tags._TagFalse,tags._TagNaN { + ostream.write(tag); + } + case tags._TagInfinity { + ostream.write(tag, stream.getc()); + } + case tags._TagInteger,tags._TagLong,tags._TagDouble,tags._TagRef { + this.readNumberRaw(ostream); + } + case tags._TagDate,tags._TagTime { + this.readDateTimeRaw(ostream, tag); + } + case tags._TagUTF8Char { + this.readUTF8CharRaw(ostream, tag); + } + case tags._TagBytes { + this.readBytesRaw(ostream, tag); + } + case tags._TagString { + this.readStringRaw(ostream, tag); + } + case tags._TagGuid { + this.readGuidRaw(ostream, tag); + } + case tags._TagList,tags._TagMap,tags._TagObject { + this.readComplexRaw(ostream, tag); + } + case tags._TagClass { + this.readComplexRaw(ostream, tag); + this.readRaw(ostream); + } + case tags._TagError { + ostream.write(tag); + this.readRaw(ostream); + } + else { + unexpectedTag(tag); + } + } + return ostream; + }; + readNumberRaw = function(ostream, tag) { + ostream.write(tag); + do { + tag = stream.getc(); + ostream.write(tag); + } while (tag != tags._TagSemicolon); + }; + readDateTimeRaw = function(ostream, tag) { + ostream.write(tag); + do { + tag = stream.getc(); + ostream.write(tag); + } while ((tag != tags._TagSemicolon) && (tag != tags._TagUTC)); + }; + readUTF8CharRaw = function(ostream, tag) { + ostream.write(tag, stream.readUTF8String(1)); + }; + readBytesRaw = function(ostream, tag) { + ostream.write(tag); + var count = 0; + tag = '0'; + do { + count *= 10; + count += tag[1] - 48; + tag = stream.getc(); + ostream.write(tag); + } while (tag != tags._TagQuote); + ostream.write(stream.read(count + 1)); + }; + readStringRaw = function(ostream, tag) { + ostream.write(tag); + var count = 0; + tag = '0'; + do { + count *= 10; + count += tag[1] - 48; + tag = stream.getc(); + ostream.write(tag); + } while (tag != tags._TagQuote); + ostream.write(stream.readUTF8String(count + 1)); + }; + readGuidRaw = function(ostream, tag) { + ostream.write(tag, stream.read(38)); + }; + readComplexRaw = function(ostream, tag) { + ostream.write(tag); + do { + tag = stream.getc(); + ostream.write(tag); + } while (tag != tags._TagOpenbrace); + while ((tag = stream.getc()) != tags._TagClosebrace) { + this.readRaw(ostream, tag); + } + ostream.write(tag); + }; + reset = function() { + ref = { @{ _weak = "v" } }; + classref = {}; + }; + @{ + _type = "hprose.io.HproseReader"; + } + } + var isDigit = function(value) { + select(value) { + case 0;9 { + return true; + } + case '0';'9' { + return true; + } + } + return false; + }; + var isInteger = function(value) { + for (i = (value[[1]] == '-' ? 2 : 1); #value; 1) { + if (!isDigit(value[[i]])) return false; + } + return (value != '-'); + }; + var isInt32 = function(value) { + var s = tostring(value); + var l = #s; + return ((l < 12) && isInteger(s) && !(value < -2147483648 || value > 2147483647)); + }; + var getClassName = function(obj) { + var typename = obj@._type; + var cls = eval(typename); + var classname = ClassManager.getClassAlias(cls); + if (classname) return classname; + ClassManager.register(cls, typename); + return typename; + }; + var isPosInf = function(value) { + return Inf == value; + }; + var isNegInf = function(value) { + return -Inf == value; + }; + var isFinite = function(value) { + return ((Inf > value) && (value > -Inf)); + }; + var isNaN = function(value) { + return value !== value; + }; + var isobject = function(value) { + var cls, struct, typename = type(value); + typename := struct; + if (cls === "table") { + var c; + try { + c = eval(typename); + } + catch(e){ + c = null; + } + if (type(c) === "class") return true; + } + return false; + }; + var isarray = function(value) { + return ((type(value) === type.table) && (count(value) === #value)) + }; + var indexof = function(array, value) { + for (i=1;#array;1) { + if (array[[i]] === value) return i; + } + return 0; + }; + class HproseWriter { + ctor(stream){ + this.stream = stream; + var ref = { @{ _weak = "v" } }; + var classref = {}; + var tags = ..hprose.io.HproseTags; + }; + serialize = function (variable) { + select (type(variable)) { + case type.null { + this.writeNull(); + } + case type.boolean { + this.writeBoolean(variable); + } + case type.number { + if (isDigit(variable)) { + stream.write(pack(variable + 48)); + } + elseif (isInt32(variable)) { + this.writeInteger(variable) + } + else { + this.writeDouble(variable); + } + } + case type.string { + var len = ulen(variable); + if (len < 0) { + this.writeBytesWithRef(variable); + } + elseif (len == 0) { + this.writeEmpty(); + } + elseif (len == 1) { + this.writeUTF8Char(variable); + } + else { + this.writeBytesWithRef(variable, len); + } + } + case type.table { + var r = indexof(ref, variable); + if (r > 0) { + this.writeRef(r); + } + elseif (istime(variable)) { + this.writeDateTime(variable); + } + elseif (isarray(variable)) { + this.writeList(variable); + } + elseif (isobject(variable)) { + this.writeObject(variable); + } + else { + this.writeMap(variable); + } + } + } + }; + writeInteger = function(i) { + stream.write(tags._TagInteger, tostring(i), tags._TagSemicolon); + }; + writeLong = function(l) { + stream.write(tags._TagLong, tostring(l), tags._TagSemicolon); + }; + writeDouble = function(d) { + if (isNaN(d)) { + this.writeNaN(); + } + else if (isFinite(d)) { + stream.write(tags._TagDouble, tostring(d), tags._TagSemicolon); + } + else { + this.writeInfinity(d > 0); + } + }; + writeNaN = function() { + stream.write(tags._TagNaN); + }; + writeInfinity = function(positive) { + stream.write(tags._TagInfinity, (positive ? tags._TagPos : tags._TagNeg)); + }; + writeNull = function() { + stream.write(tags._TagNull); + }; + writeEmpty = function() { + stream.write(tags._TagEmpty); + }; + writeBoolean = function(b) { + stream.write(b ? tags._TagTrue : tags._TagFalse); + }; + writeDateTime = function(date) { + ref[[#ref + 1]] = date; + var year = format("%04i",date.year); + var month = format("%02i",date.month); + var day = format("%02i",date.day); + var hour = format("%02i",date.hour); + var minute = format("%02i",date.minute); + var second = format("%02i",date.second); + var millisecond = format("%03i",date.milliseconds); + var timezone = (date.format[[1]] == '!') ? tags._TagUTC : tags._TagSemicolon; + + if ((hour == '00') && (minute == '00') && + (second == '00') && (millisecond == '000')) { + stream.write(tags._TagDate, year, month, day, timezone); + } + else if ((year == '1970') && (month == '01') && (day == '01')) { + stream.write(tags._TagTime, hour, minute, second); + if (millisecond != '000') { + stream.write(tags._TagPoint, millisecond); + } + stream.write(timezone); + } + else { + stream.write(tags._TagDate, year, month, day, + tags._TagTime, hour, minute, second); + if (millisecond != '000') { + stream.write(tags._TagPoint, millisecond); + } + stream.write(timezone); + } + }; + writeDateTimeWithRef = function(date) { + var r = indexof(ref, date); + if (r > 0) { + this.writeRef(r); + } + else { + this.writeDateTime(date); + } + } + writeBytes = function(bytes) { + ref[[#ref + 1]] = bytes; + stream.write(tags._TagBytes, (#bytes : ''), tags._TagQuote, bytes, tags._TagQuote); + }; + writeBytesWithRef = function(bytes) { + var r = indexof(ref, bytes); + if (r > 0) { + this.writeRef(r); + } + else { + this.writeBytes(bytes); + } + }; + writeUTF8Char = function(c) { + stream.write(tags._TagUTF8Char, c); + }; + writeString = function(str, len) { + ref[[#ref + 1]] = str; + if (len < 0) error("must be encoding in utf8."); + stream.write(tags._TagString, (len : ''), tags._TagQuote, str, tags._TagQuote); + }; + writeStringWithRef = function(str, len) { + var r = indexof(ref, str); + if (r > 0) { + this.writeRef(r); + } + else { + this.writeString(str, len); + } + }; + writeList = function(list) { + ref[[#ref + 1]] = list; + var count = #list; + stream.write(tags._TagList, (count : ''), tags._TagOpenbrace); + for (i = 1; count; 1) { + this.serialize(list[[i]]); + } + stream.write(tags._TagClosebrace); + }; + writeListWithRef = function(list) { + var r = indexof(ref, list); + if (r > 0) { + this.writeRef(r); + } + else { + this.writeList(list); + } + }; + writeMap = function(map) { + ref[[#ref + 1]] = map; + var fields = {}; + for (key, value in map) { + select(type(value)) { + case type.null, type.boolean, type.number, type.string, type.table { + fields[[#fields + 1]] = key; + } + } + } + var count = #fields; + stream.write(tags._TagMap, (count : ''), tags._TagOpenbrace); + for (i = 1; count; 1) { + this.serialize(fields[[i]]); + this.serialize(map[[fields[[i]]]]); + } + stream.write(tags._TagClosebrace); + }; + writeMapWithRef = function(map) { + var r = indexof(ref, map); + if (r > 0) { + this.writeRef(r); + } + else { + this.writeMap(map); + } + }; + writeObject = function(obj) { + var classname = getClassName(obj); + var fields = {}; + for (key, value in obj) { + select(type(value)) { + case type.null, type.boolean, type.number, type.string, type.table { + fields[[#fields + 1]] = tostring(key); + } + } + } + var cr = indexof(classref, classname); + if (cr === 0) { + cr = this.writeClass(classname, fields); + } + ref[[#ref + 1]] = obj; + var count = #fields; + stream.write(tags._TagObject, cr - 1, tags._TagOpenbrace); + for (i = 1; count; 1) { + this.serialize(obj[[fields[[i]]]]); + } + stream.write(tags._TagClosebrace); + }; + writeObjectWithRef = function(obj) { + var r = indexof(ref, obj); + if (r > 0) { + this.writeRef(r); + } + else { + this.writeObject(obj); + } + }; + writeClass = function(classname, fields) { + var count = #fields; + var len = ulen(classname); + if (len < 0) error("class name must be encoding in utf8."); + stream.write(tags._TagClass, len, tags._TagQuote, classname, tags._TagQuote, (count : ''), tags._TagOpenbrace); + for (i = 1; count; 1) { + this.writeString(fields[i], ulen(fields[i])); + } + stream.write(tags._TagClosebrace); + var cr = #classref + 1; + classref[cr] = classname; + return cr; + }; + writeRef = function(ref) { + stream.write(tags._TagRef, ref - 1, tags._TagSemicolon); + }; + reset = function() { + ref = { @{ _weak = "v" } }; + classref = {}; + }; + @{ + _type = "hprose.io.HproseWriter"; + } + } + namespace HproseFormatter { + serialize = function(variable) { + var stream = ..hprose.io.OutputStream(); + var writer = ..hprose.io.HproseWriter(stream); + writer.serialize(variable); + return tostring(stream); + } + unserialize = function(variable_representation) { + var stream = ..hprose.io.InputStream(variable_representation); + var reader = ..hprose.io.HproseReader(stream); + return reader.unserialize(); + } + } } \ No newline at end of file diff --git a/src/actionscript/as2/hprose/HproseLoader.as b/src/actionscript/as2/hprose/HproseLoader.as index f1d6e61..368d39a 100644 --- a/src/actionscript/as2/hprose/HproseLoader.as +++ b/src/actionscript/as2/hprose/HproseLoader.as @@ -1,58 +1,58 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseLoader.as * - * * - * hprose class loader for ActionScript 2.0. * - * * - * LastModified: Jun 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -import hprose.client.HproseHttpClient; -import hprose.client.HproseHttpInvoker; -import hprose.client.HproseHttpRequest; -import hprose.client.HproseSuccessEvent; -import hprose.client.HproseErrorEvent; -import hprose.client.HproseProgressEvent; -import hprose.client.HproseResultMode; -import hprose.client.HproseFilter; -import hprose.client.IHproseFilter; -import hprose.io.ClassManager; -import hprose.io.HproseException; -import hprose.io.HproseFormatter; -import hprose.io.HproseReader; -import hprose.io.HproseStringInputStream; -import hprose.io.HproseStringOutputStream; -import hprose.io.HproseTags; -import hprose.io.HproseWriter; - -class hprose.HproseLoader extends MovieClip { - public function export() { - hprose.client.HproseHttpClient; - hprose.client.HproseHttpInvoker; - hprose.client.HproseHttpRequest; - hprose.client.HproseSuccessEvent; - hprose.client.HproseErrorEvent; - hprose.client.HproseProgressEvent; - hprose.client.HproseResultMode; - hprose.client.HproseFilter; - hprose.client.IHproseFilter; - hprose.io.ClassManager; - hprose.io.HproseException; - hprose.io.HproseFormatter; - hprose.io.HproseReader; - hprose.io.HproseStringInputStream; - hprose.io.HproseStringOutputStream; - hprose.io.HproseTags; - hprose.io.HproseWriter; - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseLoader.as * + * * + * hprose class loader for ActionScript 2.0. * + * * + * LastModified: Jun 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +import hprose.client.HproseHttpClient; +import hprose.client.HproseHttpInvoker; +import hprose.client.HproseHttpRequest; +import hprose.client.HproseSuccessEvent; +import hprose.client.HproseErrorEvent; +import hprose.client.HproseProgressEvent; +import hprose.client.HproseResultMode; +import hprose.client.HproseFilter; +import hprose.client.IHproseFilter; +import hprose.io.ClassManager; +import hprose.io.HproseException; +import hprose.io.HproseFormatter; +import hprose.io.HproseReader; +import hprose.io.HproseStringInputStream; +import hprose.io.HproseStringOutputStream; +import hprose.io.HproseTags; +import hprose.io.HproseWriter; + +class hprose.HproseLoader extends MovieClip { + public function export() { + hprose.client.HproseHttpClient; + hprose.client.HproseHttpInvoker; + hprose.client.HproseHttpRequest; + hprose.client.HproseSuccessEvent; + hprose.client.HproseErrorEvent; + hprose.client.HproseProgressEvent; + hprose.client.HproseResultMode; + hprose.client.HproseFilter; + hprose.client.IHproseFilter; + hprose.io.ClassManager; + hprose.io.HproseException; + hprose.io.HproseFormatter; + hprose.io.HproseReader; + hprose.io.HproseStringInputStream; + hprose.io.HproseStringOutputStream; + hprose.io.HproseTags; + hprose.io.HproseWriter; + } } \ No newline at end of file diff --git a/src/actionscript/as2/hprose/client/HproseFilter.as b/src/actionscript/as2/hprose/client/HproseFilter.as index 6cdc58b..11558e4 100644 --- a/src/actionscript/as2/hprose/client/HproseFilter.as +++ b/src/actionscript/as2/hprose/client/HproseFilter.as @@ -1,29 +1,29 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseFilter.as * - * * - * hprose filter class for ActionScript 2.0. * - * * - * LastModified: Jun 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -import hprose.client.IHproseFilter; - -class hprose.client.HproseFilter implements IHproseFilter { - public function inputFilter(data: String):String { - return data; - } - public function outputFilter(data: String):String { - return data; - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseFilter.as * + * * + * hprose filter class for ActionScript 2.0. * + * * + * LastModified: Jun 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +import hprose.client.IHproseFilter; + +class hprose.client.HproseFilter implements IHproseFilter { + public function inputFilter(data: String):String { + return data; + } + public function outputFilter(data: String):String { + return data; + } } \ No newline at end of file diff --git a/src/actionscript/as2/hprose/client/HproseHttpClient.as b/src/actionscript/as2/hprose/client/HproseHttpClient.as index 6a92ead..9b0f52c 100644 --- a/src/actionscript/as2/hprose/client/HproseHttpClient.as +++ b/src/actionscript/as2/hprose/client/HproseHttpClient.as @@ -1,236 +1,236 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseHttpClient.as * - * * - * hprose http client class for ActionScript 2.0. * - * * - * LastModified: Jun 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -import hprose.client.HproseHttpInvoker; -import hprose.client.HproseResultMode; -import hprose.client.IHproseFilter; -import hprose.client.HproseFilter; -import hprose.io.HproseException; - -dynamic class hprose.client.HproseHttpClient extends Object { - private var url:String; - private var header:Object; - private var onerror:Array; - public var byref:Boolean; - public var timeout:Number; - public var filter:IHproseFilter; - public function HproseHttpClient(url:String) { - this.url = null; - this.header = {}; - this.onerror = []; - this.byref = false; - this.timeout = 30000; - this.filter = new HproseFilter(); - if (url) { - useService(url); - } - } - private function __resolve(name:String):Function { - function createProxy(client:HproseHttpClient, ns:String) { - return function (n:String):Function { - var proxy = function () { - if (ns == '') { - arguments.unshift(n); - } - else { - arguments.unshift(ns + '_' + n); - } - return client.invoke.apply(client, arguments); - } - if (ns == '') { - proxy.__resolve = createProxy(client, n); - } - else { - proxy.__resolve = createProxy(client, ns + '_' + n); - } - return proxy; - } - } - return createProxy(this, '')(name); - } - public function useService(url:String) { - if (url != null) { - this.url = url; - } - if (this.url == null) { - throw new HproseException("You should set server url first!"); - } - return __resolve(''); - } - public function set uri(value:String) { - this.useService(value); - } - - public function get uri():String { - return this.url; - } - - public function setHeader(name:String, value:String) { - if (name.toLowerCase() != 'content-type' && - name.toLowerCase() != 'content-length') { - if (value) { - header[name] = value; - } - else { - delete header[name]; - } - } - } - public function addEventListener(type:String, listener:Function) { - function addEvent(events:Array, listener:Function) { - for (var i = 0, l = events.length; i < l; i++) { - if (events[i] == listener) { - return; - } - } - events.push(listener); - } - switch (type.toLowerCase()) { - case 'error': - case 'onerror': - addEvent(onerror, listener); - break; - } - return this; - } - - public function removeEventListener(type:String, listener:Function) { - function deleteEvent(events:Array, listener:Function) { - for (var i = events.length - 1; i >= 0; i--) { - if (events[i] == listener) { - events.splice(i, 1); - } - } - } - switch (type.toLowerCase()) { - case 'error': - case 'onerror': - deleteEvent(onerror, listener); - break; - } - return this; - } - public function invoke():HproseHttpInvoker { - var args:Array = arguments; - var func:String = args.shift().toString(); - var byref:Boolean = this.byref; - var resultMode:Number = HproseResultMode.Normal; - var callback:Function = null; - var errorHandler:Function = null; - var progressHandler:Function = null; - var count = args.length; - if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'boolean' && - typeof(args[count - 3]) == 'function' && - typeof(args[count - 4]) == 'function' && - typeof(args[count - 5]) == 'function') { - resultMode = args[count - 1]; - byref = args[count - 2]; - progressHandler = args[count - 3]; - errorHandler = args[count - 4]; - callback = args[count - 5]; - args.length -= 5; - } - else if (typeof(args[count - 1]) == 'boolean' && - typeof(args[count - 2]) == 'function' && - typeof(args[count - 3]) == 'function' && - typeof(args[count - 4]) == 'function') { - byref = args[count - 1]; - progressHandler = args[count - 2]; - errorHandler = args[count - 3]; - callback = args[count - 4]; - args.length -= 4; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'function' && - typeof(args[count - 3]) == 'function' && - typeof(args[count - 4]) == 'function') { - resultMode = args[count - 1]; - progressHandler = args[count - 2]; - errorHandler = args[count - 3]; - callback = args[count - 4]; - args.length -= 4; - } - else if (typeof(args[count - 1]) == 'function' && - typeof(args[count - 2]) == 'function' && - typeof(args[count - 3]) == 'function') { - progressHandler = args[count - 1]; - errorHandler = args[count - 2]; - callback = args[count - 3]; - args.length -= 3; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'boolean' && - typeof(args[count - 3]) == 'function' && - typeof(args[count - 4]) == 'function') { - resultMode = args[count - 1]; - byref = args[count - 2]; - errorHandler = args[count - 3]; - callback = args[count - 4]; - args.length -= 4; - } - else if (typeof(args[count - 1]) == 'boolean' && - typeof(args[count - 2]) == 'function' && - typeof(args[count - 3]) == 'function') { - byref = args[count - 1]; - errorHandler = args[count - 2]; - callback = args[count - 3]; - args.length -= 3; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'function' && - typeof(args[count - 3]) == 'function') { - resultMode = args[count - 1]; - errorHandler = args[count - 2]; - callback = args[count - 3]; - args.length -= 3; - } - else if (typeof(args[count - 1]) == 'function' && - typeof(args[count - 2]) == 'function') { - errorHandler = args[count - 1]; - callback = args[count - 2]; - args.length -= 2; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'boolean' && - typeof(args[count - 3]) == 'function') { - resultMode = args[count - 1]; - byref = args[count - 2]; - callback = args[count - 3]; - args.length -= 3; - } - else if (typeof(args[count - 1]) == 'boolean' && - typeof(args[count - 2]) == 'function') { - byref = args[count - 1]; - callback = args[count - 2]; - args.length -= 2; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'function') { - resultMode = args[count - 1]; - callback = args[count - 2]; - args.length -= 2; - } - else if (typeof(args[count - 1]) == 'function') { - callback = args[count - 1]; - args.length--; - } - return new HproseHttpInvoker(url, header, func, args, byref, callback, errorHandler, progressHandler, onerror, timeout, resultMode, filter); - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseHttpClient.as * + * * + * hprose http client class for ActionScript 2.0. * + * * + * LastModified: Jun 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +import hprose.client.HproseHttpInvoker; +import hprose.client.HproseResultMode; +import hprose.client.IHproseFilter; +import hprose.client.HproseFilter; +import hprose.io.HproseException; + +dynamic class hprose.client.HproseHttpClient extends Object { + private var url:String; + private var header:Object; + private var onerror:Array; + public var byref:Boolean; + public var timeout:Number; + public var filter:IHproseFilter; + public function HproseHttpClient(url:String) { + this.url = null; + this.header = {}; + this.onerror = []; + this.byref = false; + this.timeout = 30000; + this.filter = new HproseFilter(); + if (url) { + useService(url); + } + } + private function __resolve(name:String):Function { + function createProxy(client:HproseHttpClient, ns:String) { + return function (n:String):Function { + var proxy = function () { + if (ns == '') { + arguments.unshift(n); + } + else { + arguments.unshift(ns + '_' + n); + } + return client.invoke.apply(client, arguments); + } + if (ns == '') { + proxy.__resolve = createProxy(client, n); + } + else { + proxy.__resolve = createProxy(client, ns + '_' + n); + } + return proxy; + } + } + return createProxy(this, '')(name); + } + public function useService(url:String) { + if (url != null) { + this.url = url; + } + if (this.url == null) { + throw new HproseException("You should set server url first!"); + } + return __resolve(''); + } + public function set uri(value:String) { + this.useService(value); + } + + public function get uri():String { + return this.url; + } + + public function setHeader(name:String, value:String) { + if (name.toLowerCase() != 'content-type' && + name.toLowerCase() != 'content-length') { + if (value) { + header[name] = value; + } + else { + delete header[name]; + } + } + } + public function addEventListener(type:String, listener:Function) { + function addEvent(events:Array, listener:Function) { + for (var i = 0, l = events.length; i < l; i++) { + if (events[i] == listener) { + return; + } + } + events.push(listener); + } + switch (type.toLowerCase()) { + case 'error': + case 'onerror': + addEvent(onerror, listener); + break; + } + return this; + } + + public function removeEventListener(type:String, listener:Function) { + function deleteEvent(events:Array, listener:Function) { + for (var i = events.length - 1; i >= 0; i--) { + if (events[i] == listener) { + events.splice(i, 1); + } + } + } + switch (type.toLowerCase()) { + case 'error': + case 'onerror': + deleteEvent(onerror, listener); + break; + } + return this; + } + public function invoke():HproseHttpInvoker { + var args:Array = arguments; + var func:String = args.shift().toString(); + var byref:Boolean = this.byref; + var resultMode:Number = HproseResultMode.Normal; + var callback:Function = null; + var errorHandler:Function = null; + var progressHandler:Function = null; + var count = args.length; + if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'boolean' && + typeof(args[count - 3]) == 'function' && + typeof(args[count - 4]) == 'function' && + typeof(args[count - 5]) == 'function') { + resultMode = args[count - 1]; + byref = args[count - 2]; + progressHandler = args[count - 3]; + errorHandler = args[count - 4]; + callback = args[count - 5]; + args.length -= 5; + } + else if (typeof(args[count - 1]) == 'boolean' && + typeof(args[count - 2]) == 'function' && + typeof(args[count - 3]) == 'function' && + typeof(args[count - 4]) == 'function') { + byref = args[count - 1]; + progressHandler = args[count - 2]; + errorHandler = args[count - 3]; + callback = args[count - 4]; + args.length -= 4; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'function' && + typeof(args[count - 3]) == 'function' && + typeof(args[count - 4]) == 'function') { + resultMode = args[count - 1]; + progressHandler = args[count - 2]; + errorHandler = args[count - 3]; + callback = args[count - 4]; + args.length -= 4; + } + else if (typeof(args[count - 1]) == 'function' && + typeof(args[count - 2]) == 'function' && + typeof(args[count - 3]) == 'function') { + progressHandler = args[count - 1]; + errorHandler = args[count - 2]; + callback = args[count - 3]; + args.length -= 3; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'boolean' && + typeof(args[count - 3]) == 'function' && + typeof(args[count - 4]) == 'function') { + resultMode = args[count - 1]; + byref = args[count - 2]; + errorHandler = args[count - 3]; + callback = args[count - 4]; + args.length -= 4; + } + else if (typeof(args[count - 1]) == 'boolean' && + typeof(args[count - 2]) == 'function' && + typeof(args[count - 3]) == 'function') { + byref = args[count - 1]; + errorHandler = args[count - 2]; + callback = args[count - 3]; + args.length -= 3; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'function' && + typeof(args[count - 3]) == 'function') { + resultMode = args[count - 1]; + errorHandler = args[count - 2]; + callback = args[count - 3]; + args.length -= 3; + } + else if (typeof(args[count - 1]) == 'function' && + typeof(args[count - 2]) == 'function') { + errorHandler = args[count - 1]; + callback = args[count - 2]; + args.length -= 2; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'boolean' && + typeof(args[count - 3]) == 'function') { + resultMode = args[count - 1]; + byref = args[count - 2]; + callback = args[count - 3]; + args.length -= 3; + } + else if (typeof(args[count - 1]) == 'boolean' && + typeof(args[count - 2]) == 'function') { + byref = args[count - 1]; + callback = args[count - 2]; + args.length -= 2; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'function') { + resultMode = args[count - 1]; + callback = args[count - 2]; + args.length -= 2; + } + else if (typeof(args[count - 1]) == 'function') { + callback = args[count - 1]; + args.length--; + } + return new HproseHttpInvoker(url, header, func, args, byref, callback, errorHandler, progressHandler, onerror, timeout, resultMode, filter); + } } \ No newline at end of file diff --git a/src/actionscript/as2/hprose/client/HproseHttpInvoker.as b/src/actionscript/as2/hprose/client/HproseHttpInvoker.as index 274eabb..0e0b981 100644 --- a/src/actionscript/as2/hprose/client/HproseHttpInvoker.as +++ b/src/actionscript/as2/hprose/client/HproseHttpInvoker.as @@ -1,260 +1,260 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseHttpInvoker.as * - * * - * hprose http invoker class for ActionScript 2.0. * - * * - * LastModified: Dec 13, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -import hprose.client.HproseHttpRequest; -import hprose.client.HproseSuccessEvent; -import hprose.client.HproseErrorEvent; -import hprose.client.HproseProgressEvent; -import hprose.client.HproseResultMode; -import hprose.client.IHproseFilter; -import hprose.io.HproseException; -import hprose.io.HproseReader; -import hprose.io.HproseStringInputStream; -import hprose.io.HproseStringOutputStream; -import hprose.io.HproseTags; -import hprose.io.HproseWriter; - -class hprose.client.HproseHttpInvoker { - private var url:String; - private var header:Object; - private var func:String; - private var args:Array; - private var byref:Boolean; - private var onsuccess:Array; - private var onerror:Array; - private var onprogress:Array; - private var globalonerror:Array; - private var progressId:Number; - private var result; - private var success:Boolean; - private var completed:Boolean; - private var lv:LoadVars; - private var timeout:Number; - private var resultMode:Number; - private var filter:IHproseFilter; - - public function HproseHttpInvoker(url:String, header:Object, func:String, args:Array, byref:Boolean, callback:Function, errorHandler:Function, progressHandler:Function, onerror:Array, timeout:Number, resultMode:Number, filter:IHproseFilter) { - this.url = url; - this.header = header; - this.func = func; - this.args = args; - this.byref = byref; - this.onsuccess = []; - this.onerror = []; - this.onprogress = []; - this.globalonerror = onerror; - this.progressId = 0; - this.result = null; - this.success = false; - this.completed = false; - this.lv = null; - this.timeout = timeout; - this.resultMode = resultMode; - this.filter = filter; - if (callback) { - start(callback, errorHandler, progressHandler); - } - } - - public function get byRef():Boolean { - return byref; - } - - public function set byRef(value:Boolean) { - byref = value; - } - - public function isSuccess():Boolean { - return success; - } - - public function isCompleted():Boolean { - return completed; - } - - public function addEventListener(type:String, listener:Function) { - function addEvent(events:Array, listener:Function) { - for (var i = 0, l = events.length; i < l; i++) { - if (events[i] == listener) { - return; - } - } - events.push(listener); - } - switch (type.toLowerCase()) { - case 'success': - case 'onsuccess': - addEvent(onsuccess, listener); - break; - case 'error': - case 'onerror': - addEvent(onerror, listener); - break; - case 'progress': - case 'onprogress': - addEvent(onprogress, listener); - break; - } - return this; - } - - public function removeEventListener(type:String, listener:Function) { - function deleteEvent(events:Array, listener:Function) { - for (var i = events.length - 1; i >= 0; i--) { - if (events[i] == listener) { - events.splice(i, 1); - } - } - } - switch (type.toLowerCase()) { - case 'success': - case 'onsuccess': - deleteEvent(onsuccess, listener); - break; - case 'error': - case 'onerror': - deleteEvent(onerror, listener); - break; - case 'progress': - case 'onprogress': - deleteEvent(onprogress, listener); - break; - } - return this; - } - - private function fireEvent(events:Array, event) { - for (var i = 0, l = events.length; i < l; i++) { - events[i].call(this, event); - } - } - - public function getResult() { - return result; - } - - public function getArguments() { - return args; - } - - public function start(callback, errorHandler, progressHandler) { - var stream:HproseStringOutputStream = new HproseStringOutputStream(); - stream.write(HproseTags.TagCall); - var writer:HproseWriter = new HproseWriter(stream); - writer.writeString(func); - if (args.length > 0) { - writer.reset(); - writer.writeList(args); - } - if (byref) { - writer.writeBoolean(true); - } - stream.write(HproseTags.TagEnd); - completed = false; - var invoker = this; - lv = HproseHttpRequest.post(url, header, stream.toString(), function(data) { - if (invoker.resultMode == HproseResultMode.RawWithEndTag) { - invoker.result = data; - } - else if (invoker.resultMode == HproseResultMode.Raw) { - invoker.result = data.substr(0, data.length - 1); - } - else { - var stream:HproseStringInputStream = new HproseStringInputStream(data); - var reader:HproseReader = new HproseReader(stream); - var tag; - var error = null; - try { - while ((tag = stream.getc()) !== HproseTags.TagEnd) { - switch (tag) { - case HproseTags.TagResult: - if (invoker.resultMode == HproseResultMode.Serialized) { - invoker.result = reader.readRaw().toString(); - } - else { - invoker.result = reader.unserialize(); - } - break; - case HproseTags.TagArgument: - reader.reset(); - invoker.args = reader.readList(); - break; - case HproseTags.TagError: - reader.reset(); - error = new HproseException(reader.readString()); - break; - default: - reader.unexpectedTag(tag); - break; - } - } - } - catch (e:Error) { - error = e; - } - } - _global.clearTimeout(invoker.progressId); - invoker.fireEvent(invoker.onprogress, new HproseProgressEvent(invoker.lv.getBytesLoaded(), invoker.lv.getBytesTotal())); - invoker.completed = true; - invoker.success = (error == null); - if (invoker.success) { - if (callback) { - callback(invoker.result, invoker.args); - } - else if (invoker.onsuccess.length > 0) { - invoker.fireEvent(invoker.onsuccess, new HproseSuccessEvent(invoker.result, invoker.args)); - } - } - else { - if (errorHandler) { - errorHandler(invoker.func, error); - } - else if (invoker.onerror.length > 0) { - invoker.fireEvent(invoker.onerror, new HproseErrorEvent(invoker.func, error)); - } - else { - invoker.fireEvent(invoker.globalonerror, new HproseErrorEvent(invoker.func, error)); - } - } - }, timeout, filter); - function doprogress() { - var byteloaded = invoker.lv.getBytesLoaded(); - var bytetotal = invoker.lv.getBytesTotal(); - if (progressHandler) { - progressHandler(byteloaded, bytetotal); - } - else if (invoker.onprogress.length > 0) { - invoker.fireEvent(invoker.onprogress, new HproseProgressEvent(byteloaded, bytetotal)); - } - _global.clearTimeout(invoker.progressId); - invoker.progressId = _global.setTimeout(doprogress, 100); - } - if (invoker.onprogress.length > 0) { - progressId = _global.setTimeout(doprogress, 100); - } - return this; - } - - public function stop() { - onprogress = []; - onsuccess = []; - onerror = []; - lv = null; - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseHttpInvoker.as * + * * + * hprose http invoker class for ActionScript 2.0. * + * * + * LastModified: Dec 13, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +import hprose.client.HproseHttpRequest; +import hprose.client.HproseSuccessEvent; +import hprose.client.HproseErrorEvent; +import hprose.client.HproseProgressEvent; +import hprose.client.HproseResultMode; +import hprose.client.IHproseFilter; +import hprose.io.HproseException; +import hprose.io.HproseReader; +import hprose.io.HproseStringInputStream; +import hprose.io.HproseStringOutputStream; +import hprose.io.HproseTags; +import hprose.io.HproseWriter; + +class hprose.client.HproseHttpInvoker { + private var url:String; + private var header:Object; + private var func:String; + private var args:Array; + private var byref:Boolean; + private var onsuccess:Array; + private var onerror:Array; + private var onprogress:Array; + private var globalonerror:Array; + private var progressId:Number; + private var result; + private var success:Boolean; + private var completed:Boolean; + private var lv:LoadVars; + private var timeout:Number; + private var resultMode:Number; + private var filter:IHproseFilter; + + public function HproseHttpInvoker(url:String, header:Object, func:String, args:Array, byref:Boolean, callback:Function, errorHandler:Function, progressHandler:Function, onerror:Array, timeout:Number, resultMode:Number, filter:IHproseFilter) { + this.url = url; + this.header = header; + this.func = func; + this.args = args; + this.byref = byref; + this.onsuccess = []; + this.onerror = []; + this.onprogress = []; + this.globalonerror = onerror; + this.progressId = 0; + this.result = null; + this.success = false; + this.completed = false; + this.lv = null; + this.timeout = timeout; + this.resultMode = resultMode; + this.filter = filter; + if (callback) { + start(callback, errorHandler, progressHandler); + } + } + + public function get byRef():Boolean { + return byref; + } + + public function set byRef(value:Boolean) { + byref = value; + } + + public function isSuccess():Boolean { + return success; + } + + public function isCompleted():Boolean { + return completed; + } + + public function addEventListener(type:String, listener:Function) { + function addEvent(events:Array, listener:Function) { + for (var i = 0, l = events.length; i < l; i++) { + if (events[i] == listener) { + return; + } + } + events.push(listener); + } + switch (type.toLowerCase()) { + case 'success': + case 'onsuccess': + addEvent(onsuccess, listener); + break; + case 'error': + case 'onerror': + addEvent(onerror, listener); + break; + case 'progress': + case 'onprogress': + addEvent(onprogress, listener); + break; + } + return this; + } + + public function removeEventListener(type:String, listener:Function) { + function deleteEvent(events:Array, listener:Function) { + for (var i = events.length - 1; i >= 0; i--) { + if (events[i] == listener) { + events.splice(i, 1); + } + } + } + switch (type.toLowerCase()) { + case 'success': + case 'onsuccess': + deleteEvent(onsuccess, listener); + break; + case 'error': + case 'onerror': + deleteEvent(onerror, listener); + break; + case 'progress': + case 'onprogress': + deleteEvent(onprogress, listener); + break; + } + return this; + } + + private function fireEvent(events:Array, event) { + for (var i = 0, l = events.length; i < l; i++) { + events[i].call(this, event); + } + } + + public function getResult() { + return result; + } + + public function getArguments() { + return args; + } + + public function start(callback, errorHandler, progressHandler) { + var stream:HproseStringOutputStream = new HproseStringOutputStream(); + stream.write(HproseTags.TagCall); + var writer:HproseWriter = new HproseWriter(stream); + writer.writeString(func); + if (args.length > 0) { + writer.reset(); + writer.writeList(args); + } + if (byref) { + writer.writeBoolean(true); + } + stream.write(HproseTags.TagEnd); + completed = false; + var invoker = this; + lv = HproseHttpRequest.post(url, header, stream.toString(), function(data) { + if (invoker.resultMode == HproseResultMode.RawWithEndTag) { + invoker.result = data; + } + else if (invoker.resultMode == HproseResultMode.Raw) { + invoker.result = data.substr(0, data.length - 1); + } + else { + var stream:HproseStringInputStream = new HproseStringInputStream(data); + var reader:HproseReader = new HproseReader(stream); + var tag; + var error = null; + try { + while ((tag = stream.getc()) !== HproseTags.TagEnd) { + switch (tag) { + case HproseTags.TagResult: + if (invoker.resultMode == HproseResultMode.Serialized) { + invoker.result = reader.readRaw().toString(); + } + else { + invoker.result = reader.unserialize(); + } + break; + case HproseTags.TagArgument: + reader.reset(); + invoker.args = reader.readList(); + break; + case HproseTags.TagError: + reader.reset(); + error = new HproseException(reader.readString()); + break; + default: + reader.unexpectedTag(tag); + break; + } + } + } + catch (e:Error) { + error = e; + } + } + _global.clearTimeout(invoker.progressId); + invoker.fireEvent(invoker.onprogress, new HproseProgressEvent(invoker.lv.getBytesLoaded(), invoker.lv.getBytesTotal())); + invoker.completed = true; + invoker.success = (error == null); + if (invoker.success) { + if (callback) { + callback(invoker.result, invoker.args); + } + else if (invoker.onsuccess.length > 0) { + invoker.fireEvent(invoker.onsuccess, new HproseSuccessEvent(invoker.result, invoker.args)); + } + } + else { + if (errorHandler) { + errorHandler(invoker.func, error); + } + else if (invoker.onerror.length > 0) { + invoker.fireEvent(invoker.onerror, new HproseErrorEvent(invoker.func, error)); + } + else { + invoker.fireEvent(invoker.globalonerror, new HproseErrorEvent(invoker.func, error)); + } + } + }, timeout, filter); + function doprogress() { + var byteloaded = invoker.lv.getBytesLoaded(); + var bytetotal = invoker.lv.getBytesTotal(); + if (progressHandler) { + progressHandler(byteloaded, bytetotal); + } + else if (invoker.onprogress.length > 0) { + invoker.fireEvent(invoker.onprogress, new HproseProgressEvent(byteloaded, bytetotal)); + } + _global.clearTimeout(invoker.progressId); + invoker.progressId = _global.setTimeout(doprogress, 100); + } + if (invoker.onprogress.length > 0) { + progressId = _global.setTimeout(doprogress, 100); + } + return this; + } + + public function stop() { + onprogress = []; + onsuccess = []; + onerror = []; + lv = null; + } } \ No newline at end of file diff --git a/src/actionscript/as2/hprose/client/HproseHttpRequest.as b/src/actionscript/as2/hprose/client/HproseHttpRequest.as index a571246..abcad87 100644 --- a/src/actionscript/as2/hprose/client/HproseHttpRequest.as +++ b/src/actionscript/as2/hprose/client/HproseHttpRequest.as @@ -1,109 +1,109 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseHttpRequest.as * - * * - * hprose http request class for ActionScript 2.0. * - * * - * LastModified: Nov 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -import hprose.client.IHproseFilter; -import hprose.io.HproseFormatter; -import hprose.io.HproseTags; - -class hprose.client.HproseHttpRequest { - public static function post(url:String, header:Object, data:String, callback:Function, timeout:Number, filter:IHproseFilter) { - var lv:LoadVars = new LoadVars(); - var timeoutID:Number; - lv.contentType = "application/hprose; charset=utf-8"; - lv.toString = function () { - return filter.outputFilter(data); - } - for (var name:String in header) { - lv.addRequestHeader(name, header[name]); - } - lv.onData = function (src:String) { - _global.clearTimeout(timeoutID); - if (src) { - callback(filter.inputFilter(src)); - } - else { - callback(this.error); - } - }; - lv.onHTTPStatus = function (httpStatus:Number) { - if ((httpStatus != 200) && (httpStatus != 100) && (httpStatus != 0)) { - _global.clearTimeout(timeoutID); - var Status = {}; - Status['101'] = 'Switching Protocols', - Status['201'] = 'Created', - Status['202'] = 'Accepted', - Status['203'] = 'Non-Authoritative Information', - Status['204'] = 'No Content', - Status['205'] = 'Reset Content', - Status['206'] = 'Partial Content', - Status['300'] = 'Multiple Choices', - Status['301'] = 'Moved Permanently', - Status['302'] = 'Found', - Status['303'] = 'See Other', - Status['304'] = 'Not Modified', - Status['305'] = 'Use Proxy', - Status['306'] = 'No Longer Used', - Status['307'] = 'Temporary Redirect', - Status['400'] = 'Bad Request', - Status['401'] = 'Not Authorised', - Status['402'] = 'Payment Required', - Status['403'] = 'Forbidden', - Status['404'] = 'Not Found', - Status['405'] = 'Method Not Allowed', - Status['406'] = 'Not Acceptable', - Status['407'] = 'Proxy Authentication Required', - Status['408'] = 'Request Timeout', - Status['409'] = 'Conflict', - Status['410'] = 'Gone', - Status['411'] = 'Length Required', - Status['412'] = 'Precondition Failed', - Status['413'] = 'Request Entity Too Large', - Status['414'] = 'Request URI Too Long', - Status['415'] = 'Unsupported Media Type', - Status['416'] = 'Requested Range Not Satisfiable', - Status['417'] = 'Expectation Failed', - Status['500'] = 'Internal Server Error', - Status['501'] = 'Not Implemented', - Status['502'] = 'Bad Gateway', - Status['503'] = 'Service Unavailable', - Status['504'] = 'Gateway Timeout', - Status['505'] = 'HTTP Version Not Supported'; - var error:String = '[' + httpStatus + ':' + (Status[httpStatus] || "Unknown Error") + ']'; - this.error = HproseTags.TagError + - HproseFormatter.serialize(error) + - HproseTags.TagEnd; - } - }; - if (timeout) { - timeoutID = _global.setTimeout(function () { - _global.clearTimeout(timeoutID); - delete(timeoutID); - lv.onData = function(src:String) { }; - lv.onLoad = function(success:Boolean) { lv.loaded = false; return; }; - lv.onHTTPStatus = function (httpStatus:Number) { }; - delete(lv); - callback(HproseTags.TagError + - HproseFormatter.serialize("timeout") + - HproseTags.TagEnd); - }, timeout); - } - lv.sendAndLoad(url, lv, 'POST'); - return lv; - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseHttpRequest.as * + * * + * hprose http request class for ActionScript 2.0. * + * * + * LastModified: Nov 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +import hprose.client.IHproseFilter; +import hprose.io.HproseFormatter; +import hprose.io.HproseTags; + +class hprose.client.HproseHttpRequest { + public static function post(url:String, header:Object, data:String, callback:Function, timeout:Number, filter:IHproseFilter) { + var lv:LoadVars = new LoadVars(); + var timeoutID:Number; + lv.contentType = "application/hprose; charset=utf-8"; + lv.toString = function () { + return filter.outputFilter(data); + } + for (var name:String in header) { + lv.addRequestHeader(name, header[name]); + } + lv.onData = function (src:String) { + _global.clearTimeout(timeoutID); + if (src) { + callback(filter.inputFilter(src)); + } + else { + callback(this.error); + } + }; + lv.onHTTPStatus = function (httpStatus:Number) { + if ((httpStatus != 200) && (httpStatus != 100) && (httpStatus != 0)) { + _global.clearTimeout(timeoutID); + var Status = {}; + Status['101'] = 'Switching Protocols', + Status['201'] = 'Created', + Status['202'] = 'Accepted', + Status['203'] = 'Non-Authoritative Information', + Status['204'] = 'No Content', + Status['205'] = 'Reset Content', + Status['206'] = 'Partial Content', + Status['300'] = 'Multiple Choices', + Status['301'] = 'Moved Permanently', + Status['302'] = 'Found', + Status['303'] = 'See Other', + Status['304'] = 'Not Modified', + Status['305'] = 'Use Proxy', + Status['306'] = 'No Longer Used', + Status['307'] = 'Temporary Redirect', + Status['400'] = 'Bad Request', + Status['401'] = 'Not Authorised', + Status['402'] = 'Payment Required', + Status['403'] = 'Forbidden', + Status['404'] = 'Not Found', + Status['405'] = 'Method Not Allowed', + Status['406'] = 'Not Acceptable', + Status['407'] = 'Proxy Authentication Required', + Status['408'] = 'Request Timeout', + Status['409'] = 'Conflict', + Status['410'] = 'Gone', + Status['411'] = 'Length Required', + Status['412'] = 'Precondition Failed', + Status['413'] = 'Request Entity Too Large', + Status['414'] = 'Request URI Too Long', + Status['415'] = 'Unsupported Media Type', + Status['416'] = 'Requested Range Not Satisfiable', + Status['417'] = 'Expectation Failed', + Status['500'] = 'Internal Server Error', + Status['501'] = 'Not Implemented', + Status['502'] = 'Bad Gateway', + Status['503'] = 'Service Unavailable', + Status['504'] = 'Gateway Timeout', + Status['505'] = 'HTTP Version Not Supported'; + var error:String = '[' + httpStatus + ':' + (Status[httpStatus] || "Unknown Error") + ']'; + this.error = HproseTags.TagError + + HproseFormatter.serialize(error) + + HproseTags.TagEnd; + } + }; + if (timeout) { + timeoutID = _global.setTimeout(function () { + _global.clearTimeout(timeoutID); + delete(timeoutID); + lv.onData = function(src:String) { }; + lv.onLoad = function(success:Boolean) { lv.loaded = false; return; }; + lv.onHTTPStatus = function (httpStatus:Number) { }; + delete(lv); + callback(HproseTags.TagError + + HproseFormatter.serialize("timeout") + + HproseTags.TagEnd); + }, timeout); + } + lv.sendAndLoad(url, lv, 'POST'); + return lv; + } } \ No newline at end of file diff --git a/src/actionscript/as2/hprose/client/IHproseFilter.as b/src/actionscript/as2/hprose/client/IHproseFilter.as index 377b14a..2a060b3 100644 --- a/src/actionscript/as2/hprose/client/IHproseFilter.as +++ b/src/actionscript/as2/hprose/client/IHproseFilter.as @@ -1,24 +1,24 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * IHproseFilter.as * - * * - * hprose filter interface for ActionScript 2.0. * - * * - * LastModified: Jun 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ - -interface hprose.client.IHproseFilter { - function inputFilter(data: String):String; - function outputFilter(data: String):String; +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * IHproseFilter.as * + * * + * hprose filter interface for ActionScript 2.0. * + * * + * LastModified: Jun 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +interface hprose.client.IHproseFilter { + function inputFilter(data: String):String; + function outputFilter(data: String):String; } \ No newline at end of file diff --git a/src/actionscript/as2/hprose/io/HproseReader.as b/src/actionscript/as2/hprose/io/HproseReader.as index 4cc82f4..3379996 100644 --- a/src/actionscript/as2/hprose/io/HproseReader.as +++ b/src/actionscript/as2/hprose/io/HproseReader.as @@ -1,555 +1,555 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseReader.as * - * * - * hprose reader class for ActionScript 2.0. * - * * - * LastModified: Dec 13, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -import hprose.io.ClassManager; -import hprose.io.HproseException; -import hprose.io.HproseStringInputStream; -import hprose.io.HproseStringOutputStream; -import hprose.io.HproseTags; - -class hprose.io.HproseReader { - private var ref:Array; - private var classref:Array; - private var stream:HproseStringInputStream; - - public function HproseReader(stream:HproseStringInputStream) { - this.ref = []; - this.classref = []; - this.stream = stream; - } - - public function get inputStream():HproseStringInputStream { - return stream; - } - - public function unserialize() { - var tag = stream.getc(); - switch (tag) { - case '0': return 0; - case '1': return 1; - case '2': return 2; - case '3': return 3; - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - case HproseTags.TagInteger: return readIntegerWithoutTag(); - case HproseTags.TagLong: return readLongWithoutTag(); - case HproseTags.TagDouble: return readDoubleWithoutTag(); - case HproseTags.TagNull: return null; - case HproseTags.TagTrue: return true; - case HproseTags.TagFalse: return false; - case HproseTags.TagNaN: return NaN; - case HproseTags.TagEmpty: return ""; - case HproseTags.TagInfinity: return readInfinityWithoutTag(); - case HproseTags.TagDate: return readDateWithoutTag(); - case HproseTags.TagTime: return readTimeWithoutTag(); - case HproseTags.TagUTF8Char: return stream.getc(); - case HproseTags.TagString: return readStringWithoutTag(); - case HproseTags.TagGuid: return readGuidWithoutTag(); - case HproseTags.TagList: return readListWithoutTag(); - case HproseTags.TagMap: return readMapWithoutTag(); - case HproseTags.TagClass: readClass(); return readObject(); - case HproseTags.TagObject: return readObjectWithoutTag(); - case HproseTags.TagRef: return readRef(); - case HproseTags.TagError: throw new HproseException(readString()); - default: unexpectedTag(tag); - } - } - - public function unexpectedTag(tag:String, expectTags:String):Void { - if (tag && expectTags) { - throw new HproseException("Tag '" + expectTags + "' expected, but '" + tag + "' found in stream"); - } - else if (tag) { - throw new HproseException("Unexpected serialize tag '" + tag + "' in stream") - } - else { - throw new HproseException('No byte found in stream'); - } - } - - private function _checkTag(tag:String, expectTag:String):Void { - if (tag != expectTag) unexpectedTag(tag, expectTag); - } - - public function checkTag(expectTag:String):Void { - _checkTag(stream.getc(), expectTag); - } - - private function _checkTags(tag:String, expectTags:Array):String { - if (expectTags.indexOf(tag) < 0) unexpectedTag(tag, expectTags.join('')); - return tag; - } - - public function checkTags(expectTags:Array):String { - return _checkTags(stream.getc(), expectTags); - } - - private function readInt(tag) { - var s = stream.readuntil(tag); - if (s.length == 0) return 0; - return parseInt(s); - } - - public function readIntegerWithoutTag():Number { - return readInt(HproseTags.TagSemicolon); - } - - public function readInteger():Number { - var tag = stream.getc(); - switch (tag) { - case '0': return 0; - case '1': return 1; - case '2': return 2; - case '3': return 3; - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - case HproseTags.TagInteger: return readIntegerWithoutTag(); - default: unexpectedTag(tag); - } - } - - public function readLongWithoutTag():String { - return stream.readuntil(HproseTags.TagSemicolon); - } - - public function readLong():String { - var tag = stream.getc(); - switch (tag) { - case '0': return '0'; - case '1': return '1'; - case '2': return '2'; - case '3': return '3'; - case '4': return '4'; - case '5': return '5'; - case '6': return '6'; - case '7': return '7'; - case '8': return '8'; - case '9': return '9'; - case HproseTags.TagInteger: return readLongWithoutTag(); - case HproseTags.TagLong: return readLongWithoutTag(); - default: unexpectedTag(tag); - } - } - - public function readDoubleWithoutTag():Number { - return parseFloat(stream.readuntil(HproseTags.TagSemicolon)); - } - - public function readDouble():Number { - var tag = stream.getc(); - switch (tag) { - case '0': return 0; - case '1': return 1; - case '2': return 2; - case '3': return 3; - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - case HproseTags.TagInteger: return readDoubleWithoutTag(); - case HproseTags.TagLong: return readDoubleWithoutTag(); - case HproseTags.TagDouble: return readDoubleWithoutTag(); - case HproseTags.TagNaN: return NaN; - case HproseTags.TagInfinity: return readInfinityWithoutTag(); - default: unexpectedTag(tag); - } - } - - public function readNaN():Number { - var tag = stream.getc(); - switch (tag) { - case HproseTags.TagNaN: return NaN; - default: unexpectedTag(tag); - } - } - - public function readInfinityWithoutTag():Number { - return ((stream.getc() == HproseTags.TagNeg) ? -Infinity : Infinity); - } - - public function readInfinity():Number { - var tag = stream.getc(); - switch (tag) { - case HproseTags.TagInfinity: return readInfinityWithoutTag(); - default: unexpectedTag(tag); - } - } - - public function readNull():Object { - var tag = stream.getc(); - switch (tag) { - case HproseTags.TagNull: return null; - default: unexpectedTag(tag); - } - } - - public function readEmpty():Object { - var tag = stream.getc(); - switch (tag) { - case HproseTags.TagEmpty: return ''; - default: unexpectedTag(tag); - } - } - - public function readBoolean():Boolean { - var tag = stream.getc(); - switch (tag) { - case HproseTags.TagTrue: return true; - case HproseTags.TagFalse: return false; - default: unexpectedTag(tag); - } - } - - public function readDateWithoutTag():Date { - var year = parseInt(stream.read(4)); - var month = parseInt(stream.read(2)) - 1; - var day = parseInt(stream.read(2)); - var date; - var tag = stream.getc(); - if (tag == HproseTags.TagTime) { - var hour = parseInt(stream.read(2)); - var minute = parseInt(stream.read(2)); - var second = parseInt(stream.read(2)); - var millisecond = 0; - tag = stream.getc(); - if (tag == HproseTags.TagPoint) { - millisecond = parseInt(stream.read(3)); - tag = stream.getc(); - if ((tag >= '0') && (tag <= '9')) { - stream.read(2); - tag = stream.getc(); - if ((tag >= '0') && (tag <= '9')) { - stream.read(2); - tag = stream.getc(); - } - } - } - if (tag == HproseTags.TagUTC) { - date = new Date(Date.UTC(year, month, day, hour, minute, second, millisecond)); - } - else { - date = new Date(year, month, day, hour, minute, second, millisecond); - } - } - else if (tag == HproseTags.TagUTC) { - date = new Date(Date.UTC(year, month, day)); - } - else { - date = new Date(year, month, day); - } - return ref[ref.length] = date; - } - - public function readDate():Date { - var tag = stream.getc(); - switch (tag) { - case HproseTags.TagDate: return readDateWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: unexpectedTag(tag); - } - } - - public function readTimeWithoutTag():Date { - var time; - var hour = parseInt(stream.read(2)); - var minute = parseInt(stream.read(2)); - var second = parseInt(stream.read(2)); - var millisecond = 0; - var tag = stream.getc(); - if (tag == HproseTags.TagPoint) { - millisecond = parseInt(stream.read(3)); - tag = stream.getc(); - if ((tag >= '0') && (tag <= '9')) { - stream.read(2); - tag = stream.getc(); - if ((tag >= '0') && (tag <= '9')) { - stream.read(2); - tag = stream.getc(); - } - } - } - if (tag == HproseTags.TagUTC) { - time = new Date(Date.UTC(1970, 0, 1, hour, minute, second, millisecond)); - } - else { - time = new Date(1970, 0, 1, hour, minute, second, millisecond); - } - return ref[ref.length] = time; - } - - public function readTime():Date { - var tag = stream.getc(); - switch (tag) { - case HproseTags.TagTime: return readTimeWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: unexpectedTag(tag); - } - } - - public function readUTF8CharWithoutTag() { - return stream.getc(); - } - - public function readUTF8Char() { - var tag = stream.getc(); - switch (tag) { - case HproseTags.TagUTF8Char: return stream.getc(); - default: unexpectedTag(tag); - } - } - - private function _readString():String { - var str = stream.read(readInt(HproseTags.TagQuote)); - stream.skip(1); - return str; - } - - public function readStringWithoutTag():String { - return ref[ref.length] = _readString(); - } - - public function readString():String { - var tag = stream.getc(); - switch (tag) { - case HproseTags.TagString: return readStringWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: unexpectedTag(tag); - } - } - - public function readGuidWithoutTag():String { - stream.skip(1); - var guid = stream.read(36); - stream.skip(1); - return ref[ref.length] = guid; - } - - public function readGuid():String { - var tag = stream.getc(); - switch (tag) { - case HproseTags.TagGuid: return readGuidWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: unexpectedTag(tag); - } - } - - public function readListWithoutTag():Array { - var list = []; - ref[ref.length] = list; - var count = readInt(HproseTags.TagOpenbrace); - for (var i = 0; i < count; i++) { - list[i] = unserialize(); - } - stream.skip(1); - return list; - } - - public function readList():Array { - var tag = stream.getc(); - switch (tag) { - case HproseTags.TagList: return readListWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: unexpectedTag(tag); - } - } - - public function readMapWithoutTag():Object { - var map = {}; - ref[ref.length] = map; - var count = readInt(HproseTags.TagOpenbrace); - for (var i = 0; i < count; i++) { - map[unserialize()] = unserialize(); - } - stream.skip(1); - return map; - } - - public function readMap():Object { - var tag = stream.getc(); - switch (tag) { - case HproseTags.TagMap: return readMapWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: unexpectedTag(tag); - } - } - - public function readObjectWithoutTag() { - var cls = classref[readInt(HproseTags.TagOpenbrace)]; - var obj = new cls.classname(); - ref[ref.length] = obj; - for (var i = 0; i < cls.count; i++) { - obj[cls.fields[i]] = unserialize(); - } - stream.skip(1); - return obj; - } - - public function readObject():Array { - var tag = stream.getc(); - switch(tag) { - case HproseTags.TagClass: readClass(); return readObject(); - case HproseTags.TagObject: return readObjectWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: unexpectedTag(tag); - } - } - - private function readClass():Void { - var classname = _readString(); - var count = readInt(HproseTags.TagOpenbrace); - var fields = []; - for (var i = 0; i < count; i++) { - fields[i] = readString(); - } - stream.skip(1); - classref[classref.length] = { - classname: ClassManager.getClass(classname), - count: count, - fields: fields - }; - } - - private function readRef() { - return ref[readInt(HproseTags.TagSemicolon)]; - } - - public function readRaw(ostream:HproseStringOutputStream, tag:String) { - if (ostream === undefined) ostream = new HproseStringOutputStream(); - if (tag === undefined) tag = stream.getc(); - switch (tag) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case HproseTags.TagNull: - case HproseTags.TagEmpty: - case HproseTags.TagTrue: - case HproseTags.TagFalse: - case HproseTags.TagNaN: - ostream.write(tag); - break; - case HproseTags.TagInfinity: - case HproseTags.TagUTF8Char: - ostream.write(tag); - ostream.write(stream.getc()); - break; - case HproseTags.TagInteger: - case HproseTags.TagLong: - case HproseTags.TagDouble: - case HproseTags.TagRef: - readNumberRaw(ostream); - break; - case HproseTags.TagDate: - case HproseTags.TagTime: - readDateTimeRaw(ostream, tag); - break; - case HproseTags.TagString: - readStringRaw(ostream, tag); - break; - case HproseTags.TagGuid: - readGuidRaw(ostream, tag); - break; - case HproseTags.TagList: - case HproseTags.TagMap: - case HproseTags.TagObject: - readComplexRaw(ostream, tag); - break; - case HproseTags.TagClass: - readComplexRaw(ostream, tag); - readRaw(ostream); - break; - case HproseTags.TagError: - ostream.write(tag); - readRaw(ostream); - break; - case '': - throw new HproseException('No byte found in stream'); - default: - throw new HproseException("Unexpected serialize tag '" + - tag + "' in stream"); - } - return ostream; - } - - private function readNumberRaw(ostream:HproseStringOutputStream, tag:String) { - ostream.write(tag); - do { - tag = stream.getc(); - ostream.write(tag); - } while (tag != HproseTags.TagSemicolon); - } - - private function readDateTimeRaw(ostream:HproseStringOutputStream, tag:String) { - ostream.write(tag); - do { - tag = stream.getc(); - ostream.write(tag); - } while (tag != HproseTags.TagSemicolon && - tag != HproseTags.TagUTC); - } - - private function readStringRaw(ostream:HproseStringOutputStream, tag:String) { - ostream.write(tag); - var s:String = stream.readuntil(HproseTags.TagQuote); - ostream.write(s); - ostream.write(HproseTags.TagQuote); - var len = 0; - if (s.length > 0) len = parseInt(s); - ostream.write(stream.read(len)); - ostream.write(stream.getc()); - } - - private function readGuidRaw(ostream:HproseStringOutputStream, tag:String) { - ostream.write(tag); - ostream.write(stream.read(38)); - } - - private function readComplexRaw(ostream:HproseStringOutputStream, tag:String) { - ostream.write(tag); - do { - tag = stream.getc(); - ostream.write(tag); - } while (tag != HproseTags.TagOpenbrace); - while ((tag = stream.getc()) != HproseTags.TagClosebrace) { - readRaw(ostream, tag); - } - ostream.write(tag); - } - - public function reset() { - ref.length = 0; - classref.length = 0; - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseReader.as * + * * + * hprose reader class for ActionScript 2.0. * + * * + * LastModified: Dec 13, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +import hprose.io.ClassManager; +import hprose.io.HproseException; +import hprose.io.HproseStringInputStream; +import hprose.io.HproseStringOutputStream; +import hprose.io.HproseTags; + +class hprose.io.HproseReader { + private var ref:Array; + private var classref:Array; + private var stream:HproseStringInputStream; + + public function HproseReader(stream:HproseStringInputStream) { + this.ref = []; + this.classref = []; + this.stream = stream; + } + + public function get inputStream():HproseStringInputStream { + return stream; + } + + public function unserialize() { + var tag = stream.getc(); + switch (tag) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case HproseTags.TagInteger: return readIntegerWithoutTag(); + case HproseTags.TagLong: return readLongWithoutTag(); + case HproseTags.TagDouble: return readDoubleWithoutTag(); + case HproseTags.TagNull: return null; + case HproseTags.TagTrue: return true; + case HproseTags.TagFalse: return false; + case HproseTags.TagNaN: return NaN; + case HproseTags.TagEmpty: return ""; + case HproseTags.TagInfinity: return readInfinityWithoutTag(); + case HproseTags.TagDate: return readDateWithoutTag(); + case HproseTags.TagTime: return readTimeWithoutTag(); + case HproseTags.TagUTF8Char: return stream.getc(); + case HproseTags.TagString: return readStringWithoutTag(); + case HproseTags.TagGuid: return readGuidWithoutTag(); + case HproseTags.TagList: return readListWithoutTag(); + case HproseTags.TagMap: return readMapWithoutTag(); + case HproseTags.TagClass: readClass(); return readObject(); + case HproseTags.TagObject: return readObjectWithoutTag(); + case HproseTags.TagRef: return readRef(); + case HproseTags.TagError: throw new HproseException(readString()); + default: unexpectedTag(tag); + } + } + + public function unexpectedTag(tag:String, expectTags:String):Void { + if (tag && expectTags) { + throw new HproseException("Tag '" + expectTags + "' expected, but '" + tag + "' found in stream"); + } + else if (tag) { + throw new HproseException("Unexpected serialize tag '" + tag + "' in stream") + } + else { + throw new HproseException('No byte found in stream'); + } + } + + private function _checkTag(tag:String, expectTag:String):Void { + if (tag != expectTag) unexpectedTag(tag, expectTag); + } + + public function checkTag(expectTag:String):Void { + _checkTag(stream.getc(), expectTag); + } + + private function _checkTags(tag:String, expectTags:Array):String { + if (expectTags.indexOf(tag) < 0) unexpectedTag(tag, expectTags.join('')); + return tag; + } + + public function checkTags(expectTags:Array):String { + return _checkTags(stream.getc(), expectTags); + } + + private function readInt(tag) { + var s = stream.readuntil(tag); + if (s.length == 0) return 0; + return parseInt(s); + } + + public function readIntegerWithoutTag():Number { + return readInt(HproseTags.TagSemicolon); + } + + public function readInteger():Number { + var tag = stream.getc(); + switch (tag) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case HproseTags.TagInteger: return readIntegerWithoutTag(); + default: unexpectedTag(tag); + } + } + + public function readLongWithoutTag():String { + return stream.readuntil(HproseTags.TagSemicolon); + } + + public function readLong():String { + var tag = stream.getc(); + switch (tag) { + case '0': return '0'; + case '1': return '1'; + case '2': return '2'; + case '3': return '3'; + case '4': return '4'; + case '5': return '5'; + case '6': return '6'; + case '7': return '7'; + case '8': return '8'; + case '9': return '9'; + case HproseTags.TagInteger: return readLongWithoutTag(); + case HproseTags.TagLong: return readLongWithoutTag(); + default: unexpectedTag(tag); + } + } + + public function readDoubleWithoutTag():Number { + return parseFloat(stream.readuntil(HproseTags.TagSemicolon)); + } + + public function readDouble():Number { + var tag = stream.getc(); + switch (tag) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case HproseTags.TagInteger: return readDoubleWithoutTag(); + case HproseTags.TagLong: return readDoubleWithoutTag(); + case HproseTags.TagDouble: return readDoubleWithoutTag(); + case HproseTags.TagNaN: return NaN; + case HproseTags.TagInfinity: return readInfinityWithoutTag(); + default: unexpectedTag(tag); + } + } + + public function readNaN():Number { + var tag = stream.getc(); + switch (tag) { + case HproseTags.TagNaN: return NaN; + default: unexpectedTag(tag); + } + } + + public function readInfinityWithoutTag():Number { + return ((stream.getc() == HproseTags.TagNeg) ? -Infinity : Infinity); + } + + public function readInfinity():Number { + var tag = stream.getc(); + switch (tag) { + case HproseTags.TagInfinity: return readInfinityWithoutTag(); + default: unexpectedTag(tag); + } + } + + public function readNull():Object { + var tag = stream.getc(); + switch (tag) { + case HproseTags.TagNull: return null; + default: unexpectedTag(tag); + } + } + + public function readEmpty():Object { + var tag = stream.getc(); + switch (tag) { + case HproseTags.TagEmpty: return ''; + default: unexpectedTag(tag); + } + } + + public function readBoolean():Boolean { + var tag = stream.getc(); + switch (tag) { + case HproseTags.TagTrue: return true; + case HproseTags.TagFalse: return false; + default: unexpectedTag(tag); + } + } + + public function readDateWithoutTag():Date { + var year = parseInt(stream.read(4)); + var month = parseInt(stream.read(2)) - 1; + var day = parseInt(stream.read(2)); + var date; + var tag = stream.getc(); + if (tag == HproseTags.TagTime) { + var hour = parseInt(stream.read(2)); + var minute = parseInt(stream.read(2)); + var second = parseInt(stream.read(2)); + var millisecond = 0; + tag = stream.getc(); + if (tag == HproseTags.TagPoint) { + millisecond = parseInt(stream.read(3)); + tag = stream.getc(); + if ((tag >= '0') && (tag <= '9')) { + stream.read(2); + tag = stream.getc(); + if ((tag >= '0') && (tag <= '9')) { + stream.read(2); + tag = stream.getc(); + } + } + } + if (tag == HproseTags.TagUTC) { + date = new Date(Date.UTC(year, month, day, hour, minute, second, millisecond)); + } + else { + date = new Date(year, month, day, hour, minute, second, millisecond); + } + } + else if (tag == HproseTags.TagUTC) { + date = new Date(Date.UTC(year, month, day)); + } + else { + date = new Date(year, month, day); + } + return ref[ref.length] = date; + } + + public function readDate():Date { + var tag = stream.getc(); + switch (tag) { + case HproseTags.TagDate: return readDateWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: unexpectedTag(tag); + } + } + + public function readTimeWithoutTag():Date { + var time; + var hour = parseInt(stream.read(2)); + var minute = parseInt(stream.read(2)); + var second = parseInt(stream.read(2)); + var millisecond = 0; + var tag = stream.getc(); + if (tag == HproseTags.TagPoint) { + millisecond = parseInt(stream.read(3)); + tag = stream.getc(); + if ((tag >= '0') && (tag <= '9')) { + stream.read(2); + tag = stream.getc(); + if ((tag >= '0') && (tag <= '9')) { + stream.read(2); + tag = stream.getc(); + } + } + } + if (tag == HproseTags.TagUTC) { + time = new Date(Date.UTC(1970, 0, 1, hour, minute, second, millisecond)); + } + else { + time = new Date(1970, 0, 1, hour, minute, second, millisecond); + } + return ref[ref.length] = time; + } + + public function readTime():Date { + var tag = stream.getc(); + switch (tag) { + case HproseTags.TagTime: return readTimeWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: unexpectedTag(tag); + } + } + + public function readUTF8CharWithoutTag() { + return stream.getc(); + } + + public function readUTF8Char() { + var tag = stream.getc(); + switch (tag) { + case HproseTags.TagUTF8Char: return stream.getc(); + default: unexpectedTag(tag); + } + } + + private function _readString():String { + var str = stream.read(readInt(HproseTags.TagQuote)); + stream.skip(1); + return str; + } + + public function readStringWithoutTag():String { + return ref[ref.length] = _readString(); + } + + public function readString():String { + var tag = stream.getc(); + switch (tag) { + case HproseTags.TagString: return readStringWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: unexpectedTag(tag); + } + } + + public function readGuidWithoutTag():String { + stream.skip(1); + var guid = stream.read(36); + stream.skip(1); + return ref[ref.length] = guid; + } + + public function readGuid():String { + var tag = stream.getc(); + switch (tag) { + case HproseTags.TagGuid: return readGuidWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: unexpectedTag(tag); + } + } + + public function readListWithoutTag():Array { + var list = []; + ref[ref.length] = list; + var count = readInt(HproseTags.TagOpenbrace); + for (var i = 0; i < count; i++) { + list[i] = unserialize(); + } + stream.skip(1); + return list; + } + + public function readList():Array { + var tag = stream.getc(); + switch (tag) { + case HproseTags.TagList: return readListWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: unexpectedTag(tag); + } + } + + public function readMapWithoutTag():Object { + var map = {}; + ref[ref.length] = map; + var count = readInt(HproseTags.TagOpenbrace); + for (var i = 0; i < count; i++) { + map[unserialize()] = unserialize(); + } + stream.skip(1); + return map; + } + + public function readMap():Object { + var tag = stream.getc(); + switch (tag) { + case HproseTags.TagMap: return readMapWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: unexpectedTag(tag); + } + } + + public function readObjectWithoutTag() { + var cls = classref[readInt(HproseTags.TagOpenbrace)]; + var obj = new cls.classname(); + ref[ref.length] = obj; + for (var i = 0; i < cls.count; i++) { + obj[cls.fields[i]] = unserialize(); + } + stream.skip(1); + return obj; + } + + public function readObject():Array { + var tag = stream.getc(); + switch(tag) { + case HproseTags.TagClass: readClass(); return readObject(); + case HproseTags.TagObject: return readObjectWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: unexpectedTag(tag); + } + } + + private function readClass():Void { + var classname = _readString(); + var count = readInt(HproseTags.TagOpenbrace); + var fields = []; + for (var i = 0; i < count; i++) { + fields[i] = readString(); + } + stream.skip(1); + classref[classref.length] = { + classname: ClassManager.getClass(classname), + count: count, + fields: fields + }; + } + + private function readRef() { + return ref[readInt(HproseTags.TagSemicolon)]; + } + + public function readRaw(ostream:HproseStringOutputStream, tag:String) { + if (ostream === undefined) ostream = new HproseStringOutputStream(); + if (tag === undefined) tag = stream.getc(); + switch (tag) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case HproseTags.TagNull: + case HproseTags.TagEmpty: + case HproseTags.TagTrue: + case HproseTags.TagFalse: + case HproseTags.TagNaN: + ostream.write(tag); + break; + case HproseTags.TagInfinity: + case HproseTags.TagUTF8Char: + ostream.write(tag); + ostream.write(stream.getc()); + break; + case HproseTags.TagInteger: + case HproseTags.TagLong: + case HproseTags.TagDouble: + case HproseTags.TagRef: + readNumberRaw(ostream); + break; + case HproseTags.TagDate: + case HproseTags.TagTime: + readDateTimeRaw(ostream, tag); + break; + case HproseTags.TagString: + readStringRaw(ostream, tag); + break; + case HproseTags.TagGuid: + readGuidRaw(ostream, tag); + break; + case HproseTags.TagList: + case HproseTags.TagMap: + case HproseTags.TagObject: + readComplexRaw(ostream, tag); + break; + case HproseTags.TagClass: + readComplexRaw(ostream, tag); + readRaw(ostream); + break; + case HproseTags.TagError: + ostream.write(tag); + readRaw(ostream); + break; + case '': + throw new HproseException('No byte found in stream'); + default: + throw new HproseException("Unexpected serialize tag '" + + tag + "' in stream"); + } + return ostream; + } + + private function readNumberRaw(ostream:HproseStringOutputStream, tag:String) { + ostream.write(tag); + do { + tag = stream.getc(); + ostream.write(tag); + } while (tag != HproseTags.TagSemicolon); + } + + private function readDateTimeRaw(ostream:HproseStringOutputStream, tag:String) { + ostream.write(tag); + do { + tag = stream.getc(); + ostream.write(tag); + } while (tag != HproseTags.TagSemicolon && + tag != HproseTags.TagUTC); + } + + private function readStringRaw(ostream:HproseStringOutputStream, tag:String) { + ostream.write(tag); + var s:String = stream.readuntil(HproseTags.TagQuote); + ostream.write(s); + ostream.write(HproseTags.TagQuote); + var len = 0; + if (s.length > 0) len = parseInt(s); + ostream.write(stream.read(len)); + ostream.write(stream.getc()); + } + + private function readGuidRaw(ostream:HproseStringOutputStream, tag:String) { + ostream.write(tag); + ostream.write(stream.read(38)); + } + + private function readComplexRaw(ostream:HproseStringOutputStream, tag:String) { + ostream.write(tag); + do { + tag = stream.getc(); + ostream.write(tag); + } while (tag != HproseTags.TagOpenbrace); + while ((tag = stream.getc()) != HproseTags.TagClosebrace) { + readRaw(ostream, tag); + } + ostream.write(tag); + } + + public function reset() { + ref.length = 0; + classref.length = 0; + } } \ No newline at end of file diff --git a/src/actionscript/as2/hprose/io/HproseWriter.as b/src/actionscript/as2/hprose/io/HproseWriter.as index 09dba9b..4135d00 100644 --- a/src/actionscript/as2/hprose/io/HproseWriter.as +++ b/src/actionscript/as2/hprose/io/HproseWriter.as @@ -1,352 +1,352 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseWriter.as * - * * - * hprose writer class for ActionScript 2.0. * - * * - * LastModified: Dec 12, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -import hprose.io.ClassManager; -import hprose.io.HproseStringOutputStream; -import hprose.io.HproseTags; - -class hprose.io.HproseWriter { - private static function arrayIndexOf(a, v) { - var count = a.length; - for (var i = 0; i < count; i++) { - if (a[i] === v) return i; - } - return -1; - } - - private static function isDigit(value) { - switch (value.toString()) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': return true; - } - return false; - } - - private static function isInteger(s) { - var l = s.length; - for (var i = (s.charAt(0) == '-') ? 1 : 0; i < l; i++) { - if (!isDigit(s.charAt(i))) return false; - } - return (s != '-'); - } - - private static function isInt32(value) { - var s = value.toString(); - return ((s.length < 12) && - isInteger(s) && - (value >= -2147483648) && - (value <= 2147483647)); - } - - private var ref:Array; - private var classref:Array; - private var stream:HproseStringOutputStream; - - public function HproseWriter(stream:HproseStringOutputStream) { - ref = []; - classref = []; - this.stream = stream; - } - - public function get outputStream():HproseStringOutputStream { - return stream; - } - - public function serialize(o) { - if (o == null) { - writeNull(); - return; - } - switch (o.constructor) { - case Boolean: - writeBoolean(o); - break; - case Number: - isDigit(o) ? - stream.write(o) : - isInt32(o) ? - writeInteger(o) : - writeDouble(o); - break; - case String: - o.length == 0 ? - writeEmpty() : - o.length == 1 ? - writeUTF8Char(o) : - writeStringWithRef(o); - break; - case Date: - writeDateWithRef(o); - break; - case Array: - writeListWithRef(o); - break; - default: - var classAlias:String = ClassManager.getClassAlias(o); - (classAlias == "Object") ? writeMapWithRef(o) : _writeObjectWithRef(o, classAlias); - break; - } - } - - public function writeInteger(i) { - stream.write(HproseTags.TagInteger + i + HproseTags.TagSemicolon); - } - - public function writeLong(l) { - stream.write(HproseTags.TagLong + l + HproseTags.TagSemicolon); - } - - public function writeDouble(d) { - if (isNaN(d)) { - writeNaN(); - } - else if (isFinite(d)) { - stream.write(HproseTags.TagDouble + d + HproseTags.TagSemicolon); - } - else { - writeInfinity(d > 0); - } - } - - public function writeNaN() { - stream.write(HproseTags.TagNaN); - } - - public function writeInfinity(positive) { - stream.write(HproseTags.TagInfinity + (positive ? - HproseTags.TagPos : - HproseTags.TagNeg)); - } - - public function writeNull() { - stream.write(HproseTags.TagNull); - } - - public function writeEmpty() { - stream.write(HproseTags.TagEmpty); - } - - public function writeBoolean(bool) { - stream.write(bool ? HproseTags.TagTrue : HproseTags.TagFalse); - } - - public function writeUTCDate(date) { - ref[ref.length] = date; - var year = ('0000' + date.getUTCFullYear()).slice(-4); - var month = ('00' + (date.getUTCMonth() + 1)).slice(-2); - var day = ('00' + date.getUTCDate()).slice(-2); - var hour = ('00' + date.getUTCHours()).slice(-2); - var minute = ('00' + date.getUTCMinutes()).slice(-2); - var second = ('00' + date.getUTCSeconds()).slice(-2); - var millisecond = ('000' + date.getUTCMilliseconds()).slice(-3); - if ((hour == '00') && (minute == '00') && (second == '00') && (millisecond == '000')) { - stream.write(HproseTags.TagDate + year + month + day + HproseTags.TagUTC); - } - else if ((year == '1970') && (month == '01') && (day == '01')) { - stream.write(HproseTags.TagTime + hour + minute + second); - if (millisecond != '000') { - stream.write(HproseTags.TagPoint + millisecond); - } - stream.write(HproseTags.TagUTC); - } - else { - stream.write(HproseTags.TagDate + year + month + day + - HproseTags.TagTime + hour + minute + second); - if (millisecond != '000') { - stream.write(HproseTags.TagPoint + millisecond); - } - stream.write(HproseTags.TagUTC); - } - } - - public function writeUTCDateWithRef(date) { - var r = arrayIndexOf(ref, date); - (r > -1) ? writeRef(r) : writeUTCDate(date); - } - - public function writeDate(date, checkRef) { - ref[ref.length] = date; - var year = ('0000' + date.getFullYear()).slice(-4); - var month = ('00' + (date.getMonth() + 1)).slice(-2); - var day = ('00' + date.getDate()).slice(-2); - var hour = ('00' + date.getHours()).slice(-2); - var minute = ('00' + date.getMinutes()).slice(-2); - var second = ('00' + date.getSeconds()).slice(-2); - var millisecond = ('000' + date.getMilliseconds()).slice(-3); - if ((hour == '00') && (minute == '00') && (second == '00') && (millisecond == '000')) { - stream.write(HproseTags.TagDate + year + month + day + HproseTags.TagSemicolon); - } - else if ((year == '1970') && (month == '01') && (day == '01')) { - stream.write(HproseTags.TagTime + hour + minute + second); - if (millisecond != '000') { - stream.write(HproseTags.TagPoint + millisecond); - } - stream.write(HproseTags.TagSemicolon); - } - else { - stream.write(HproseTags.TagDate + year + month + day + - HproseTags.TagTime + hour + minute + second); - if (millisecond != '000') { - stream.write(HproseTags.TagPoint + millisecond); - } - stream.write(HproseTags.TagSemicolon); - } - } - - public function writeDateWithRef(date) { - var r = arrayIndexOf(ref, date); - (r > -1) ? writeRef(r) : writeDate(date); - } - - public function writeTime(time) { - ref[ref.length] = time; - var hour = ('00' + time.getHours()).slice(-2); - var minute = ('00' + time.getMinutes()).slice(-2); - var second = ('00' + time.getSeconds()).slice(-2); - var millisecond = ('000' + time.getMilliseconds()).slice(-3); - stream.write(HproseTags.TagTime + hour + minute + second); - if (millisecond != '000') { - stream.write(HproseTags.TagPoint + millisecond); - } - stream.write(HproseTags.TagSemicolon); - } - - public function writeTimeWithRef(time) { - var r = arrayIndexOf(ref, time); - (r > -1) ? writeRef(r) : writeTime(time); - } - - public function writeUTF8Char(c) { - stream.write(HproseTags.TagUTF8Char + c); - } - - public function writeString(str) { - ref[ref.length] = str; - stream.write(HproseTags.TagString + - (str.length > 0 ? str.length : '') + - HproseTags.TagQuote + str + HproseTags.TagQuote); - } - - public function writeStringWithRef(str) { - var r = arrayIndexOf(ref, str); - (r > -1) ? writeRef(r) : writeString(str); - } - - public function writeList(list) { - ref[ref.length] = list; - var count = list.length; - stream.write(HproseTags.TagList + (count > 0 ? count : '') + HproseTags.TagOpenbrace); - for (var i = 0; i < count; i++) { - serialize(list[i]); - } - stream.write(HproseTags.TagClosebrace); - } - - public function writeListWithRef(list) { - var r = arrayIndexOf(ref, list); - (r > -1) ? writeRef(r) : writeList(list); - } - - public function writeMap(map, checkRef) { - ref[ref.length] = map; - var fields = []; - for (var key in map) { - if (typeof(map[key]) != 'function') { - fields[fields.length] = key; - } - } - var count = fields.length; - stream.write(HproseTags.TagMap + (count > 0 ? count : '') + HproseTags.TagOpenbrace); - for (var i = 0; i < count; i++) { - serialize(fields[i]); - serialize(map[fields[i]]); - } - stream.write(HproseTags.TagClosebrace); - } - - public function writeMapWithRef(map) { - var r = arrayIndexOf(ref, map); - (r > -1) ? writeRef(r) : writeMap(map); - } - - private function _writeObject(obj, classAlias) { - var fields = []; - for (var key in obj) { - if (typeof(obj[key]) != 'function') { - fields[fields.length] = key; - } - } - var cr = arrayIndexOf(classref, classAlias); - if (cr == -1) { - cr = writeClass(classAlias, fields); - } - ref[ref.length] = obj; - var count = fields.length; - stream.write(HproseTags.TagObject + cr + HproseTags.TagOpenbrace); - for (var i = 0; i < count; i++) { - serialize(obj[fields[i]]); - } - stream.write(HproseTags.TagClosebrace); - } - - private function _writeObjectWithRef(obj, classAlias) { - var r = arrayIndexOf(ref, obj); - (r > -1) ? writeRef(r) : _writeObject(obj, classAlias); - } - - public function writeObject(obj) { - _writeObject(obj, ClassManager.getClassAlias(obj)); - } - - public function writeObjectWithRef(obj) { - var r = arrayIndexOf(ref, obj); - (r > -1) ? writeRef(r) : writeObject(obj); - } - - private function writeClass(classAlias, fields) { - var count = fields.length; - stream.write(HproseTags.TagClass + classAlias.length + - HproseTags.TagQuote + classAlias + HproseTags.TagQuote + - (count > 0 ? count : '') + HproseTags.TagOpenbrace); - for (var i = 0; i < count; i++) { - writeString(fields[i]); - } - stream.write(HproseTags.TagClosebrace); - var cr = classref.length; - classref[cr] = classAlias; - return cr; - } - - private function writeRef(ref) { - stream.write(HproseTags.TagRef + ref + HproseTags.TagSemicolon); - } - - public function reset() { - ref.length = 0; - classref.length = 0; - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseWriter.as * + * * + * hprose writer class for ActionScript 2.0. * + * * + * LastModified: Dec 12, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +import hprose.io.ClassManager; +import hprose.io.HproseStringOutputStream; +import hprose.io.HproseTags; + +class hprose.io.HproseWriter { + private static function arrayIndexOf(a, v) { + var count = a.length; + for (var i = 0; i < count; i++) { + if (a[i] === v) return i; + } + return -1; + } + + private static function isDigit(value) { + switch (value.toString()) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': return true; + } + return false; + } + + private static function isInteger(s) { + var l = s.length; + for (var i = (s.charAt(0) == '-') ? 1 : 0; i < l; i++) { + if (!isDigit(s.charAt(i))) return false; + } + return (s != '-'); + } + + private static function isInt32(value) { + var s = value.toString(); + return ((s.length < 12) && + isInteger(s) && + (value >= -2147483648) && + (value <= 2147483647)); + } + + private var ref:Array; + private var classref:Array; + private var stream:HproseStringOutputStream; + + public function HproseWriter(stream:HproseStringOutputStream) { + ref = []; + classref = []; + this.stream = stream; + } + + public function get outputStream():HproseStringOutputStream { + return stream; + } + + public function serialize(o) { + if (o == null) { + writeNull(); + return; + } + switch (o.constructor) { + case Boolean: + writeBoolean(o); + break; + case Number: + isDigit(o) ? + stream.write(o) : + isInt32(o) ? + writeInteger(o) : + writeDouble(o); + break; + case String: + o.length == 0 ? + writeEmpty() : + o.length == 1 ? + writeUTF8Char(o) : + writeStringWithRef(o); + break; + case Date: + writeDateWithRef(o); + break; + case Array: + writeListWithRef(o); + break; + default: + var classAlias:String = ClassManager.getClassAlias(o); + (classAlias == "Object") ? writeMapWithRef(o) : _writeObjectWithRef(o, classAlias); + break; + } + } + + public function writeInteger(i) { + stream.write(HproseTags.TagInteger + i + HproseTags.TagSemicolon); + } + + public function writeLong(l) { + stream.write(HproseTags.TagLong + l + HproseTags.TagSemicolon); + } + + public function writeDouble(d) { + if (isNaN(d)) { + writeNaN(); + } + else if (isFinite(d)) { + stream.write(HproseTags.TagDouble + d + HproseTags.TagSemicolon); + } + else { + writeInfinity(d > 0); + } + } + + public function writeNaN() { + stream.write(HproseTags.TagNaN); + } + + public function writeInfinity(positive) { + stream.write(HproseTags.TagInfinity + (positive ? + HproseTags.TagPos : + HproseTags.TagNeg)); + } + + public function writeNull() { + stream.write(HproseTags.TagNull); + } + + public function writeEmpty() { + stream.write(HproseTags.TagEmpty); + } + + public function writeBoolean(bool) { + stream.write(bool ? HproseTags.TagTrue : HproseTags.TagFalse); + } + + public function writeUTCDate(date) { + ref[ref.length] = date; + var year = ('0000' + date.getUTCFullYear()).slice(-4); + var month = ('00' + (date.getUTCMonth() + 1)).slice(-2); + var day = ('00' + date.getUTCDate()).slice(-2); + var hour = ('00' + date.getUTCHours()).slice(-2); + var minute = ('00' + date.getUTCMinutes()).slice(-2); + var second = ('00' + date.getUTCSeconds()).slice(-2); + var millisecond = ('000' + date.getUTCMilliseconds()).slice(-3); + if ((hour == '00') && (minute == '00') && (second == '00') && (millisecond == '000')) { + stream.write(HproseTags.TagDate + year + month + day + HproseTags.TagUTC); + } + else if ((year == '1970') && (month == '01') && (day == '01')) { + stream.write(HproseTags.TagTime + hour + minute + second); + if (millisecond != '000') { + stream.write(HproseTags.TagPoint + millisecond); + } + stream.write(HproseTags.TagUTC); + } + else { + stream.write(HproseTags.TagDate + year + month + day + + HproseTags.TagTime + hour + minute + second); + if (millisecond != '000') { + stream.write(HproseTags.TagPoint + millisecond); + } + stream.write(HproseTags.TagUTC); + } + } + + public function writeUTCDateWithRef(date) { + var r = arrayIndexOf(ref, date); + (r > -1) ? writeRef(r) : writeUTCDate(date); + } + + public function writeDate(date, checkRef) { + ref[ref.length] = date; + var year = ('0000' + date.getFullYear()).slice(-4); + var month = ('00' + (date.getMonth() + 1)).slice(-2); + var day = ('00' + date.getDate()).slice(-2); + var hour = ('00' + date.getHours()).slice(-2); + var minute = ('00' + date.getMinutes()).slice(-2); + var second = ('00' + date.getSeconds()).slice(-2); + var millisecond = ('000' + date.getMilliseconds()).slice(-3); + if ((hour == '00') && (minute == '00') && (second == '00') && (millisecond == '000')) { + stream.write(HproseTags.TagDate + year + month + day + HproseTags.TagSemicolon); + } + else if ((year == '1970') && (month == '01') && (day == '01')) { + stream.write(HproseTags.TagTime + hour + minute + second); + if (millisecond != '000') { + stream.write(HproseTags.TagPoint + millisecond); + } + stream.write(HproseTags.TagSemicolon); + } + else { + stream.write(HproseTags.TagDate + year + month + day + + HproseTags.TagTime + hour + minute + second); + if (millisecond != '000') { + stream.write(HproseTags.TagPoint + millisecond); + } + stream.write(HproseTags.TagSemicolon); + } + } + + public function writeDateWithRef(date) { + var r = arrayIndexOf(ref, date); + (r > -1) ? writeRef(r) : writeDate(date); + } + + public function writeTime(time) { + ref[ref.length] = time; + var hour = ('00' + time.getHours()).slice(-2); + var minute = ('00' + time.getMinutes()).slice(-2); + var second = ('00' + time.getSeconds()).slice(-2); + var millisecond = ('000' + time.getMilliseconds()).slice(-3); + stream.write(HproseTags.TagTime + hour + minute + second); + if (millisecond != '000') { + stream.write(HproseTags.TagPoint + millisecond); + } + stream.write(HproseTags.TagSemicolon); + } + + public function writeTimeWithRef(time) { + var r = arrayIndexOf(ref, time); + (r > -1) ? writeRef(r) : writeTime(time); + } + + public function writeUTF8Char(c) { + stream.write(HproseTags.TagUTF8Char + c); + } + + public function writeString(str) { + ref[ref.length] = str; + stream.write(HproseTags.TagString + + (str.length > 0 ? str.length : '') + + HproseTags.TagQuote + str + HproseTags.TagQuote); + } + + public function writeStringWithRef(str) { + var r = arrayIndexOf(ref, str); + (r > -1) ? writeRef(r) : writeString(str); + } + + public function writeList(list) { + ref[ref.length] = list; + var count = list.length; + stream.write(HproseTags.TagList + (count > 0 ? count : '') + HproseTags.TagOpenbrace); + for (var i = 0; i < count; i++) { + serialize(list[i]); + } + stream.write(HproseTags.TagClosebrace); + } + + public function writeListWithRef(list) { + var r = arrayIndexOf(ref, list); + (r > -1) ? writeRef(r) : writeList(list); + } + + public function writeMap(map, checkRef) { + ref[ref.length] = map; + var fields = []; + for (var key in map) { + if (typeof(map[key]) != 'function') { + fields[fields.length] = key; + } + } + var count = fields.length; + stream.write(HproseTags.TagMap + (count > 0 ? count : '') + HproseTags.TagOpenbrace); + for (var i = 0; i < count; i++) { + serialize(fields[i]); + serialize(map[fields[i]]); + } + stream.write(HproseTags.TagClosebrace); + } + + public function writeMapWithRef(map) { + var r = arrayIndexOf(ref, map); + (r > -1) ? writeRef(r) : writeMap(map); + } + + private function _writeObject(obj, classAlias) { + var fields = []; + for (var key in obj) { + if (typeof(obj[key]) != 'function') { + fields[fields.length] = key; + } + } + var cr = arrayIndexOf(classref, classAlias); + if (cr == -1) { + cr = writeClass(classAlias, fields); + } + ref[ref.length] = obj; + var count = fields.length; + stream.write(HproseTags.TagObject + cr + HproseTags.TagOpenbrace); + for (var i = 0; i < count; i++) { + serialize(obj[fields[i]]); + } + stream.write(HproseTags.TagClosebrace); + } + + private function _writeObjectWithRef(obj, classAlias) { + var r = arrayIndexOf(ref, obj); + (r > -1) ? writeRef(r) : _writeObject(obj, classAlias); + } + + public function writeObject(obj) { + _writeObject(obj, ClassManager.getClassAlias(obj)); + } + + public function writeObjectWithRef(obj) { + var r = arrayIndexOf(ref, obj); + (r > -1) ? writeRef(r) : writeObject(obj); + } + + private function writeClass(classAlias, fields) { + var count = fields.length; + stream.write(HproseTags.TagClass + classAlias.length + + HproseTags.TagQuote + classAlias + HproseTags.TagQuote + + (count > 0 ? count : '') + HproseTags.TagOpenbrace); + for (var i = 0; i < count; i++) { + writeString(fields[i]); + } + stream.write(HproseTags.TagClosebrace); + var cr = classref.length; + classref[cr] = classAlias; + return cr; + } + + private function writeRef(ref) { + stream.write(HproseTags.TagRef + ref + HproseTags.TagSemicolon); + } + + public function reset() { + ref.length = 0; + classref.length = 0; + } } \ No newline at end of file diff --git a/src/actionscript/as3/hprose/HproseLoader.as b/src/actionscript/as3/hprose/HproseLoader.as index 7dc830a..fde55ee 100644 --- a/src/actionscript/as3/hprose/HproseLoader.as +++ b/src/actionscript/as3/hprose/HproseLoader.as @@ -1,57 +1,57 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseLoader.as * - * * - * hprose class loader for ActionScript 3.0. * - * * - * LastModified: Jun 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -package hprose { - import hprose.client.HproseHttpClient; - import hprose.client.HproseHttpInvoker; - import hprose.client.HproseHttpRequest; - import hprose.client.HproseHttpProxy; - import hprose.client.HproseSuccessEvent; - import hprose.client.HproseErrorEvent; - import hprose.client.HproseResultMode; - import hprose.client.HproseFilter; - import hprose.client.IHproseFilter; - import hprose.io.ClassManager; - import hprose.io.HproseException; - import hprose.io.HproseFormatter; - import hprose.io.HproseReader; - import hprose.io.HproseTags; - import hprose.io.HproseWriter; - import flash.display.Sprite; - - public class HproseLoader extends Sprite { - public function export():void { - hprose.client.HproseHttpClient; - hprose.client.HproseHttpInvoker; - hprose.client.HproseHttpRequest; - hprose.client.HproseHttpProxy; - hprose.client.HproseSuccessEvent; - hprose.client.HproseErrorEvent; - hprose.client.HproseResultMode; - hprose.client.HproseFilter; - hprose.client.IHproseFilter; - hprose.io.ClassManager; - hprose.io.HproseException; - hprose.io.HproseFormatter; - hprose.io.HproseReader; - hprose.io.HproseTags; - hprose.io.HproseWriter; - } - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseLoader.as * + * * + * hprose class loader for ActionScript 3.0. * + * * + * LastModified: Jun 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +package hprose { + import hprose.client.HproseHttpClient; + import hprose.client.HproseHttpInvoker; + import hprose.client.HproseHttpRequest; + import hprose.client.HproseHttpProxy; + import hprose.client.HproseSuccessEvent; + import hprose.client.HproseErrorEvent; + import hprose.client.HproseResultMode; + import hprose.client.HproseFilter; + import hprose.client.IHproseFilter; + import hprose.io.ClassManager; + import hprose.io.HproseException; + import hprose.io.HproseFormatter; + import hprose.io.HproseReader; + import hprose.io.HproseTags; + import hprose.io.HproseWriter; + import flash.display.Sprite; + + public class HproseLoader extends Sprite { + public function export():void { + hprose.client.HproseHttpClient; + hprose.client.HproseHttpInvoker; + hprose.client.HproseHttpRequest; + hprose.client.HproseHttpProxy; + hprose.client.HproseSuccessEvent; + hprose.client.HproseErrorEvent; + hprose.client.HproseResultMode; + hprose.client.HproseFilter; + hprose.client.IHproseFilter; + hprose.io.ClassManager; + hprose.io.HproseException; + hprose.io.HproseFormatter; + hprose.io.HproseReader; + hprose.io.HproseTags; + hprose.io.HproseWriter; + } + } } \ No newline at end of file diff --git a/src/actionscript/as3/hprose/client/HproseFilter.as b/src/actionscript/as3/hprose/client/HproseFilter.as index 7d7b92f..0b6aa71 100644 --- a/src/actionscript/as3/hprose/client/HproseFilter.as +++ b/src/actionscript/as3/hprose/client/HproseFilter.as @@ -1,30 +1,30 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseFilter.as * - * * - * hprose filter class for ActionScript 3.0. * - * * - * LastModified: Jun 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -package hprose.client { - import flash.utils.ByteArray; - public class HproseFilter implements IHproseFilter { - public function inputFilter(data: ByteArray):ByteArray { - return data; - } - public function outputFilter(data: ByteArray):ByteArray { - return data; - } - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseFilter.as * + * * + * hprose filter class for ActionScript 3.0. * + * * + * LastModified: Jun 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +package hprose.client { + import flash.utils.ByteArray; + public class HproseFilter implements IHproseFilter { + public function inputFilter(data: ByteArray):ByteArray { + return data; + } + public function outputFilter(data: ByteArray):ByteArray { + return data; + } + } } \ No newline at end of file diff --git a/src/actionscript/as3/hprose/client/HproseHttpClient.as b/src/actionscript/as3/hprose/client/HproseHttpClient.as index 6e943eb..2ec811c 100644 --- a/src/actionscript/as3/hprose/client/HproseHttpClient.as +++ b/src/actionscript/as3/hprose/client/HproseHttpClient.as @@ -1,213 +1,213 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseHttpClient.as * - * * - * hprose http client class for ActionScript 3.0. * - * * - * LastModified: Nov 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -package hprose.client { - import hprose.io.HproseException; - import flash.events.Event; - import flash.events.IEventDispatcher; - import flash.events.EventDispatcher; - import flash.utils.Proxy; - import flash.utils.flash_proxy; - - [Event(name="error",type="hprose.client.HproseErrorEvent")] - public dynamic class HproseHttpClient extends Proxy implements IEventDispatcher { - private var url:String = null; - private const header:Object = { }; - public var byref:Boolean = false; - public var timeout:uint = 30000; - public var filter:IHproseFilter = new HproseFilter(); - private var dispatcher:EventDispatcher; - public function HproseHttpClient(url:String = "") { - dispatcher = new EventDispatcher(this); - if (url != "") { - useService(url); - } - } - - flash_proxy override function callProperty(name:*, ...rest):* { - rest.unshift(name); - return invoke.apply(this, rest); - } - - flash_proxy override function getProperty(name:*):* { - return new HproseHttpProxy(this, name); - } - - public function useService(url:String = ""):HproseHttpProxy { - if (url != "") { - this.url = url; - } - if (this.url == null) { - throw new HproseException("You should set server url first!"); - } - return new HproseHttpProxy(this, ''); - } - - public function set uri(value:String):void { - this.useService(value); - } - - public function get uri():String { - return this.url; - } - - public function setHeader(name:String, value:String):void { - if (name.toLowerCase() != 'content-type' && - name.toLowerCase() != 'content-length') { - if (value) { - header[name] = value; - } - else { - delete header[name]; - } - } - } - - public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void { - dispatcher.addEventListener(type, listener, useCapture, priority); - } - - public function dispatchEvent(evt:Event):Boolean { - return dispatcher.dispatchEvent(evt); - } - - public function hasEventListener(type:String):Boolean { - return dispatcher.hasEventListener(type); - } - - public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void { - dispatcher.removeEventListener(type, listener, useCapture); - } - - public function willTrigger(type:String):Boolean { - return dispatcher.willTrigger(type); - } - - public function invoke(func:String, ...rest):HproseHttpInvoker { - var args:Array = rest; - var byref:Boolean = this.byref; - var resultMode:int = HproseResultMode.Normal; - var callback:Function = null; - var errorHandler:Function = null; - var progressHandler:Function = null; - var count = args.length; - if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'boolean' && - typeof(args[count - 3]) == 'function' && - typeof(args[count - 4]) == 'function' && - typeof(args[count - 5]) == 'function') { - resultMode = args[count - 1]; - byref = args[count - 2]; - progressHandler = args[count - 3]; - errorHandler = args[count - 4]; - callback = args[count - 5]; - args.length -= 5; - } - else if (typeof(args[count - 1]) == 'boolean' && - typeof(args[count - 2]) == 'function' && - typeof(args[count - 3]) == 'function' && - typeof(args[count - 4]) == 'function') { - byref = args[count - 1]; - progressHandler = args[count - 2]; - errorHandler = args[count - 3]; - callback = args[count - 4]; - args.length -= 4; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'function' && - typeof(args[count - 3]) == 'function' && - typeof(args[count - 4]) == 'function') { - resultMode = args[count - 1]; - progressHandler = args[count - 2]; - errorHandler = args[count - 3]; - callback = args[count - 4]; - args.length -= 4; - } - else if (typeof(args[count - 1]) == 'function' && - typeof(args[count - 2]) == 'function' && - typeof(args[count - 3]) == 'function') { - progressHandler = args[count - 1]; - errorHandler = args[count - 2]; - callback = args[count - 3]; - args.length -= 3; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'boolean' && - typeof(args[count - 3]) == 'function' && - typeof(args[count - 4]) == 'function') { - resultMode = args[count - 1]; - byref = args[count - 2]; - errorHandler = args[count - 3]; - callback = args[count - 4]; - args.length -= 4; - } - else if (typeof(args[count - 1]) == 'boolean' && - typeof(args[count - 2]) == 'function' && - typeof(args[count - 3]) == 'function') { - byref = args[count - 1]; - errorHandler = args[count - 2]; - callback = args[count - 3]; - args.length -= 3; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'function' && - typeof(args[count - 3]) == 'function') { - resultMode = args[count - 1]; - errorHandler = args[count - 2]; - callback = args[count - 3]; - args.length -= 3; - } - else if (typeof(args[count - 1]) == 'function' && - typeof(args[count - 2]) == 'function') { - errorHandler = args[count - 1]; - callback = args[count - 2]; - args.length -= 2; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'boolean' && - typeof(args[count - 3]) == 'function') { - resultMode = args[count - 1]; - byref = args[count - 2]; - callback = args[count - 3]; - args.length -= 3; - } - else if (typeof(args[count - 1]) == 'boolean' && - typeof(args[count - 2]) == 'function') { - byref = args[count - 1]; - callback = args[count - 2]; - args.length -= 2; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'function') { - resultMode = args[count - 1]; - callback = args[count - 2]; - args.length -= 2; - } - else if (typeof(args[count - 1]) == 'function') { - callback = args[count - 1]; - args.length--; - } - return new HproseHttpInvoker(url, header, func, args, byref, callback, errorHandler, progressHandler, dispatcher, timeout, resultMode, filter); - } - - public function toString():String { - return '[HproseHttpClient uri="' + url + '"]'; - } - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseHttpClient.as * + * * + * hprose http client class for ActionScript 3.0. * + * * + * LastModified: Nov 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +package hprose.client { + import hprose.io.HproseException; + import flash.events.Event; + import flash.events.IEventDispatcher; + import flash.events.EventDispatcher; + import flash.utils.Proxy; + import flash.utils.flash_proxy; + + [Event(name="error",type="hprose.client.HproseErrorEvent")] + public dynamic class HproseHttpClient extends Proxy implements IEventDispatcher { + private var url:String = null; + private const header:Object = { }; + public var byref:Boolean = false; + public var timeout:uint = 30000; + public var filter:IHproseFilter = new HproseFilter(); + private var dispatcher:EventDispatcher; + public function HproseHttpClient(url:String = "") { + dispatcher = new EventDispatcher(this); + if (url != "") { + useService(url); + } + } + + flash_proxy override function callProperty(name:*, ...rest):* { + rest.unshift(name); + return invoke.apply(this, rest); + } + + flash_proxy override function getProperty(name:*):* { + return new HproseHttpProxy(this, name); + } + + public function useService(url:String = ""):HproseHttpProxy { + if (url != "") { + this.url = url; + } + if (this.url == null) { + throw new HproseException("You should set server url first!"); + } + return new HproseHttpProxy(this, ''); + } + + public function set uri(value:String):void { + this.useService(value); + } + + public function get uri():String { + return this.url; + } + + public function setHeader(name:String, value:String):void { + if (name.toLowerCase() != 'content-type' && + name.toLowerCase() != 'content-length') { + if (value) { + header[name] = value; + } + else { + delete header[name]; + } + } + } + + public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void { + dispatcher.addEventListener(type, listener, useCapture, priority); + } + + public function dispatchEvent(evt:Event):Boolean { + return dispatcher.dispatchEvent(evt); + } + + public function hasEventListener(type:String):Boolean { + return dispatcher.hasEventListener(type); + } + + public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void { + dispatcher.removeEventListener(type, listener, useCapture); + } + + public function willTrigger(type:String):Boolean { + return dispatcher.willTrigger(type); + } + + public function invoke(func:String, ...rest):HproseHttpInvoker { + var args:Array = rest; + var byref:Boolean = this.byref; + var resultMode:int = HproseResultMode.Normal; + var callback:Function = null; + var errorHandler:Function = null; + var progressHandler:Function = null; + var count = args.length; + if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'boolean' && + typeof(args[count - 3]) == 'function' && + typeof(args[count - 4]) == 'function' && + typeof(args[count - 5]) == 'function') { + resultMode = args[count - 1]; + byref = args[count - 2]; + progressHandler = args[count - 3]; + errorHandler = args[count - 4]; + callback = args[count - 5]; + args.length -= 5; + } + else if (typeof(args[count - 1]) == 'boolean' && + typeof(args[count - 2]) == 'function' && + typeof(args[count - 3]) == 'function' && + typeof(args[count - 4]) == 'function') { + byref = args[count - 1]; + progressHandler = args[count - 2]; + errorHandler = args[count - 3]; + callback = args[count - 4]; + args.length -= 4; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'function' && + typeof(args[count - 3]) == 'function' && + typeof(args[count - 4]) == 'function') { + resultMode = args[count - 1]; + progressHandler = args[count - 2]; + errorHandler = args[count - 3]; + callback = args[count - 4]; + args.length -= 4; + } + else if (typeof(args[count - 1]) == 'function' && + typeof(args[count - 2]) == 'function' && + typeof(args[count - 3]) == 'function') { + progressHandler = args[count - 1]; + errorHandler = args[count - 2]; + callback = args[count - 3]; + args.length -= 3; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'boolean' && + typeof(args[count - 3]) == 'function' && + typeof(args[count - 4]) == 'function') { + resultMode = args[count - 1]; + byref = args[count - 2]; + errorHandler = args[count - 3]; + callback = args[count - 4]; + args.length -= 4; + } + else if (typeof(args[count - 1]) == 'boolean' && + typeof(args[count - 2]) == 'function' && + typeof(args[count - 3]) == 'function') { + byref = args[count - 1]; + errorHandler = args[count - 2]; + callback = args[count - 3]; + args.length -= 3; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'function' && + typeof(args[count - 3]) == 'function') { + resultMode = args[count - 1]; + errorHandler = args[count - 2]; + callback = args[count - 3]; + args.length -= 3; + } + else if (typeof(args[count - 1]) == 'function' && + typeof(args[count - 2]) == 'function') { + errorHandler = args[count - 1]; + callback = args[count - 2]; + args.length -= 2; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'boolean' && + typeof(args[count - 3]) == 'function') { + resultMode = args[count - 1]; + byref = args[count - 2]; + callback = args[count - 3]; + args.length -= 3; + } + else if (typeof(args[count - 1]) == 'boolean' && + typeof(args[count - 2]) == 'function') { + byref = args[count - 1]; + callback = args[count - 2]; + args.length -= 2; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'function') { + resultMode = args[count - 1]; + callback = args[count - 2]; + args.length -= 2; + } + else if (typeof(args[count - 1]) == 'function') { + callback = args[count - 1]; + args.length--; + } + return new HproseHttpInvoker(url, header, func, args, byref, callback, errorHandler, progressHandler, dispatcher, timeout, resultMode, filter); + } + + public function toString():String { + return '[HproseHttpClient uri="' + url + '"]'; + } + } } \ No newline at end of file diff --git a/src/actionscript/as3/hprose/client/HproseHttpInvoker.as b/src/actionscript/as3/hprose/client/HproseHttpInvoker.as index 5278162..be4f386 100644 --- a/src/actionscript/as3/hprose/client/HproseHttpInvoker.as +++ b/src/actionscript/as3/hprose/client/HproseHttpInvoker.as @@ -1,188 +1,188 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseHttpInvoker.as * - * * - * hprose http invoker class for ActionScript 3.0. * - * * - * LastModified: Nov 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -package hprose.client { - import flash.events.Event; - import flash.events.EventDispatcher; - import flash.events.ProgressEvent; - import flash.display.Sprite; - import flash.net.URLStream; - import flash.utils.ByteArray; - import flash.utils.IDataInput; - - import hprose.io.HproseException; - import hprose.io.HproseReader; - import hprose.io.HproseTags; - import hprose.io.HproseWriter; - - [Event(name="error", type="hprose.client.HproseErrorEvent")] - [Event(name="success", type="hprose.client.HproseSuccessEvent")] - [Event(name="progress", type="flash.events.ProgressEvent")] - public class HproseHttpInvoker extends Sprite { - private var url:String; - private var header:Object; - private var func:String; - private var args:Array; - private var byref:Boolean = false; - private var dispatcher:EventDispatcher; - private var progressId:Number; - private var result:*; - private var success:Boolean; - private var completed:Boolean; - private var timeout:uint; - private var resultMode:int; - private var filter:IHproseFilter; - private var httpRequest:HproseHttpRequest = null; - - public function HproseHttpInvoker(url:String, header:Object, func:String, args:Array, byref:Boolean, callback:Function, errorHandler:Function, progressHandler:Function, dispatcher:EventDispatcher, timeout:uint, resultMode:int, filter:IHproseFilter) { - this.url = url; - this.header = header; - this.func = func; - this.args = args; - this.byref = byref; - this.dispatcher = dispatcher; - this.timeout = timeout; - this.resultMode = resultMode; - this.filter = filter; - if (callback != null) { - start(callback, errorHandler, progressHandler); - } - } - - public function get byRef():Boolean { - return byref; - } - - public function set byRef(value:Boolean):void { - byref = value; - } - - public function isSuccess():Boolean { - return success; - } - - public function isCompleted():Boolean { - return completed; - } - - public function getResult():* { - return result; - } - - public function getArguments():Array { - return args; - } - - public function start(callback:Function = null, errorHandler:Function = null, progressHandler:Function = null):HproseHttpInvoker { - var stream:ByteArray = new ByteArray(); - stream.writeByte(HproseTags.TagCall); - var writer:HproseWriter = new HproseWriter(stream); - writer.writeString(func); - if (args.length > 0) { - writer.reset(); - writer.writeList(args); - } - if (byref) { - writer.writeBoolean(true); - } - stream.writeByte(HproseTags.TagEnd); - stream.position = 0; - completed = false; - var invoker:HproseHttpInvoker = this; - httpRequest = HproseHttpRequest.post(url, header, stream, - function(stream:ByteArray):void { - if (invoker.resultMode == HproseResultMode.RawWithEndTag || - invoker.resultMode == HproseResultMode.Raw) { - if (invoker.resultMode == HproseResultMode.Raw) { - stream.length = stream.length - 1; - } - invoker.result = stream; - } - else { - var reader:HproseReader = new HproseReader(stream); - var tag:int; - var error:Error = null; - try { - while ((tag = stream.readByte()) !== HproseTags.TagEnd) { - switch (tag) { - case HproseTags.TagResult: - if (invoker.resultMode == HproseResultMode.Serialized) { - invoker.result = reader.readRaw(); - } - else { - invoker.result = reader.unserialize(); - } - break; - case HproseTags.TagArgument: - reader.reset(); - invoker.args = reader.readList(); - break; - case HproseTags.TagError: - reader.reset(); - error = new HproseException(reader.readString()); - break; - default: - throw reader.unexpectedTag(tag); - } - } - } - catch (e:Error) { - error = e; - } - } - invoker.completed = true; - invoker.success = (error == null); - if (invoker.success) { - if (callback != null) { - callback(invoker.result, invoker.args); - } - else if (invoker.hasEventListener(HproseSuccessEvent.SUCCESS)) { - invoker.dispatchEvent(new HproseSuccessEvent(invoker.result, invoker.args)); - } - } - else { - if (errorHandler != null) { - errorHandler(invoker.func, error); - } - else if (invoker.hasEventListener(HproseErrorEvent.ERROR)) { - invoker.dispatchEvent(new HproseErrorEvent(invoker.func, error)); - } - else { - invoker.dispatcher.dispatchEvent(new HproseErrorEvent(invoker.func, error)); - } - } - }, - function progress(event:ProgressEvent):void { - if (progressHandler != null) { - progressHandler(event.bytesLoaded, event.bytesTotal); - } - else if (invoker.hasEventListener(ProgressEvent.PROGRESS)) { - invoker.dispatchEvent(event); - } - }, timeout, filter); - return this; - } - - public function stop():void { - if (httpRequest) { - httpRequest.stop(); - } - } - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseHttpInvoker.as * + * * + * hprose http invoker class for ActionScript 3.0. * + * * + * LastModified: Nov 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +package hprose.client { + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.ProgressEvent; + import flash.display.Sprite; + import flash.net.URLStream; + import flash.utils.ByteArray; + import flash.utils.IDataInput; + + import hprose.io.HproseException; + import hprose.io.HproseReader; + import hprose.io.HproseTags; + import hprose.io.HproseWriter; + + [Event(name="error", type="hprose.client.HproseErrorEvent")] + [Event(name="success", type="hprose.client.HproseSuccessEvent")] + [Event(name="progress", type="flash.events.ProgressEvent")] + public class HproseHttpInvoker extends Sprite { + private var url:String; + private var header:Object; + private var func:String; + private var args:Array; + private var byref:Boolean = false; + private var dispatcher:EventDispatcher; + private var progressId:Number; + private var result:*; + private var success:Boolean; + private var completed:Boolean; + private var timeout:uint; + private var resultMode:int; + private var filter:IHproseFilter; + private var httpRequest:HproseHttpRequest = null; + + public function HproseHttpInvoker(url:String, header:Object, func:String, args:Array, byref:Boolean, callback:Function, errorHandler:Function, progressHandler:Function, dispatcher:EventDispatcher, timeout:uint, resultMode:int, filter:IHproseFilter) { + this.url = url; + this.header = header; + this.func = func; + this.args = args; + this.byref = byref; + this.dispatcher = dispatcher; + this.timeout = timeout; + this.resultMode = resultMode; + this.filter = filter; + if (callback != null) { + start(callback, errorHandler, progressHandler); + } + } + + public function get byRef():Boolean { + return byref; + } + + public function set byRef(value:Boolean):void { + byref = value; + } + + public function isSuccess():Boolean { + return success; + } + + public function isCompleted():Boolean { + return completed; + } + + public function getResult():* { + return result; + } + + public function getArguments():Array { + return args; + } + + public function start(callback:Function = null, errorHandler:Function = null, progressHandler:Function = null):HproseHttpInvoker { + var stream:ByteArray = new ByteArray(); + stream.writeByte(HproseTags.TagCall); + var writer:HproseWriter = new HproseWriter(stream); + writer.writeString(func); + if (args.length > 0) { + writer.reset(); + writer.writeList(args); + } + if (byref) { + writer.writeBoolean(true); + } + stream.writeByte(HproseTags.TagEnd); + stream.position = 0; + completed = false; + var invoker:HproseHttpInvoker = this; + httpRequest = HproseHttpRequest.post(url, header, stream, + function(stream:ByteArray):void { + if (invoker.resultMode == HproseResultMode.RawWithEndTag || + invoker.resultMode == HproseResultMode.Raw) { + if (invoker.resultMode == HproseResultMode.Raw) { + stream.length = stream.length - 1; + } + invoker.result = stream; + } + else { + var reader:HproseReader = new HproseReader(stream); + var tag:int; + var error:Error = null; + try { + while ((tag = stream.readByte()) !== HproseTags.TagEnd) { + switch (tag) { + case HproseTags.TagResult: + if (invoker.resultMode == HproseResultMode.Serialized) { + invoker.result = reader.readRaw(); + } + else { + invoker.result = reader.unserialize(); + } + break; + case HproseTags.TagArgument: + reader.reset(); + invoker.args = reader.readList(); + break; + case HproseTags.TagError: + reader.reset(); + error = new HproseException(reader.readString()); + break; + default: + throw reader.unexpectedTag(tag); + } + } + } + catch (e:Error) { + error = e; + } + } + invoker.completed = true; + invoker.success = (error == null); + if (invoker.success) { + if (callback != null) { + callback(invoker.result, invoker.args); + } + else if (invoker.hasEventListener(HproseSuccessEvent.SUCCESS)) { + invoker.dispatchEvent(new HproseSuccessEvent(invoker.result, invoker.args)); + } + } + else { + if (errorHandler != null) { + errorHandler(invoker.func, error); + } + else if (invoker.hasEventListener(HproseErrorEvent.ERROR)) { + invoker.dispatchEvent(new HproseErrorEvent(invoker.func, error)); + } + else { + invoker.dispatcher.dispatchEvent(new HproseErrorEvent(invoker.func, error)); + } + } + }, + function progress(event:ProgressEvent):void { + if (progressHandler != null) { + progressHandler(event.bytesLoaded, event.bytesTotal); + } + else if (invoker.hasEventListener(ProgressEvent.PROGRESS)) { + invoker.dispatchEvent(event); + } + }, timeout, filter); + return this; + } + + public function stop():void { + if (httpRequest) { + httpRequest.stop(); + } + } + } } \ No newline at end of file diff --git a/src/actionscript/as3/hprose/client/HproseHttpRequest.as b/src/actionscript/as3/hprose/client/HproseHttpRequest.as index 9017147..b9ff533 100644 --- a/src/actionscript/as3/hprose/client/HproseHttpRequest.as +++ b/src/actionscript/as3/hprose/client/HproseHttpRequest.as @@ -1,186 +1,186 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseHttpRequest.as * - * * - * hprose http request class for ActionScript 3.0. * - * * - * LastModified: Nov 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -package hprose.client { - import hprose.io.HproseTags; - import hprose.io.HproseWriter; - import flash.events.Event; - import flash.events.HTTPStatusEvent; - import flash.events.IOErrorEvent; - import flash.events.SecurityErrorEvent; - import flash.events.ProgressEvent; - import flash.events.TimerEvent; - import flash.net.URLRequest; - import flash.net.URLRequestHeader; - import flash.net.URLRequestMethod; - import flash.net.URLStream; - import flash.utils.ByteArray; - import flash.utils.Timer; - - public final class HproseHttpRequest { - public static function post(url:String, header:Object, data:ByteArray, callback:Function, progress:Function, timeout:uint, filter:IHproseFilter):HproseHttpRequest { - var request:URLRequest = new URLRequest(url); - request.method = URLRequestMethod.POST; - request.contentType = "application/hprose"; - request.data = filter.outputFilter(data); - for (var name:String in header) { - request.requestHeaders.push(new URLRequestHeader(name, header[name])); - } - return new HproseHttpRequest(request, callback, progress, timeout, filter); - } - private const stream:URLStream = new URLStream(); - private var callback:Function; - private var progress:Function; - private var timer:Timer; - private var complete:Boolean = false; - private var filter:IHproseFilter; - public function HproseHttpRequest(request:URLRequest, callback:Function, progress:Function, timeout:uint, filter:IHproseFilter) { - this.callback = callback; - this.progress = progress; - this.filter = filter; - timer = new Timer(timeout); - stream.addEventListener(Event.COMPLETE, completeHandler); - stream.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler); - stream.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); - stream.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); - stream.addEventListener(ProgressEvent.PROGRESS, progressHandler); - stream.load(request); - timer.addEventListener(TimerEvent.TIMER, timeoutHandler); - timer.start(); - } - private function completeHandler(event:Event):void { - if (!complete) { - complete = true; - timer.stop(); - var data:ByteArray = new ByteArray(); - stream.readBytes(data); - data.position = 0; - data = filter.inputFilter(data); - callback(stream); - } - } - private function httpStatusHandler(event:HTTPStatusEvent):void { - if (!complete && (event.status != 200) && (event.status != 100) && (event.status != 0)) { - complete = true; - timer.stop(); - var Status:Object = {}; - Status[101] = 'Switching Protocols', - Status[201] = 'Created', - Status[202] = 'Accepted', - Status[203] = 'Non-Authoritative Information', - Status[204] = 'No Content', - Status[205] = 'Reset Content', - Status[206] = 'Partial Content', - Status[300] = 'Multiple Choices', - Status[301] = 'Moved Permanently', - Status[302] = 'Found', - Status[303] = 'See Other', - Status[304] = 'Not Modified', - Status[305] = 'Use Proxy', - Status[306] = 'No Longer Used', - Status[307] = 'Temporary Redirect', - Status[400] = 'Bad Request', - Status[401] = 'Not Authorised', - Status[402] = 'Payment Required', - Status[403] = 'Forbidden', - Status[404] = 'Not Found', - Status[405] = 'Method Not Allowed', - Status[406] = 'Not Acceptable', - Status[407] = 'Proxy Authentication Required', - Status[408] = 'Request Timeout', - Status[409] = 'Conflict', - Status[410] = 'Gone', - Status[411] = 'Length Required', - Status[412] = 'Precondition Failed', - Status[413] = 'Request Entity Too Large', - Status[414] = 'Request URI Too Long', - Status[415] = 'Unsupported Media Type', - Status[416] = 'Requested Range Not Satisfiable', - Status[417] = 'Expectation Failed', - Status[500] = 'Internal Server Error', - Status[501] = 'Not Implemented', - Status[502] = 'Bad Gateway', - Status[503] = 'Service Unavailable', - Status[504] = 'Gateway Timeout', - Status[505] = 'HTTP Version Not Supported'; - var error:String = '[' + event.status + ':' + (Status[event.status] || "Unknown Error") + ']'; - var data:ByteArray = new ByteArray(); - var writer:HproseWriter = new HproseWriter(data); - data.writeByte(HproseTags.TagError); - writer.writeString(error); - data.writeByte(HproseTags.TagEnd); - data.position = 0; - callback(data); - } - } - private function ioErrorHandler(event:IOErrorEvent):void { - if (!complete) { - complete = true; - timer.stop(); - var data:ByteArray = new ByteArray(); - var writer:HproseWriter = new HproseWriter(data); - data.writeByte(HproseTags.TagError); - writer.writeString(event.text); - data.writeByte(HproseTags.TagEnd); - data.position = 0; - callback(data); - } - } - private function securityErrorHandler(event:SecurityErrorEvent):void { - if (!complete) { - complete = true; - timer.stop(); - var data:ByteArray = new ByteArray(); - var writer:HproseWriter = new HproseWriter(data); - data.writeByte(HproseTags.TagError); - writer.writeString(event.text); - data.writeByte(HproseTags.TagEnd); - data.position = 0; - callback(data); - } - } - private function progressHandler(event:ProgressEvent):void { - try { - progress(event); - } - catch (e:Error) {} - } - private function timeoutHandler(event:TimerEvent):void { - if (!complete) { - complete = true; - Timer(event.target).stop(); - stream.close(); - var data:ByteArray = new ByteArray(); - var writer:HproseWriter = new HproseWriter(data); - data.writeByte(HproseTags.TagError); - writer.writeString('timeout'); - data.writeByte(HproseTags.TagEnd); - data.position = 0; - callback(data); - } - } - public function stop() { - if (!complete) { - complete = true; - timer.stop(); - stream.close(); - } - } - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseHttpRequest.as * + * * + * hprose http request class for ActionScript 3.0. * + * * + * LastModified: Nov 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +package hprose.client { + import hprose.io.HproseTags; + import hprose.io.HproseWriter; + import flash.events.Event; + import flash.events.HTTPStatusEvent; + import flash.events.IOErrorEvent; + import flash.events.SecurityErrorEvent; + import flash.events.ProgressEvent; + import flash.events.TimerEvent; + import flash.net.URLRequest; + import flash.net.URLRequestHeader; + import flash.net.URLRequestMethod; + import flash.net.URLStream; + import flash.utils.ByteArray; + import flash.utils.Timer; + + public final class HproseHttpRequest { + public static function post(url:String, header:Object, data:ByteArray, callback:Function, progress:Function, timeout:uint, filter:IHproseFilter):HproseHttpRequest { + var request:URLRequest = new URLRequest(url); + request.method = URLRequestMethod.POST; + request.contentType = "application/hprose"; + request.data = filter.outputFilter(data); + for (var name:String in header) { + request.requestHeaders.push(new URLRequestHeader(name, header[name])); + } + return new HproseHttpRequest(request, callback, progress, timeout, filter); + } + private const stream:URLStream = new URLStream(); + private var callback:Function; + private var progress:Function; + private var timer:Timer; + private var complete:Boolean = false; + private var filter:IHproseFilter; + public function HproseHttpRequest(request:URLRequest, callback:Function, progress:Function, timeout:uint, filter:IHproseFilter) { + this.callback = callback; + this.progress = progress; + this.filter = filter; + timer = new Timer(timeout); + stream.addEventListener(Event.COMPLETE, completeHandler); + stream.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler); + stream.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); + stream.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); + stream.addEventListener(ProgressEvent.PROGRESS, progressHandler); + stream.load(request); + timer.addEventListener(TimerEvent.TIMER, timeoutHandler); + timer.start(); + } + private function completeHandler(event:Event):void { + if (!complete) { + complete = true; + timer.stop(); + var data:ByteArray = new ByteArray(); + stream.readBytes(data); + data.position = 0; + data = filter.inputFilter(data); + callback(stream); + } + } + private function httpStatusHandler(event:HTTPStatusEvent):void { + if (!complete && (event.status != 200) && (event.status != 100) && (event.status != 0)) { + complete = true; + timer.stop(); + var Status:Object = {}; + Status[101] = 'Switching Protocols', + Status[201] = 'Created', + Status[202] = 'Accepted', + Status[203] = 'Non-Authoritative Information', + Status[204] = 'No Content', + Status[205] = 'Reset Content', + Status[206] = 'Partial Content', + Status[300] = 'Multiple Choices', + Status[301] = 'Moved Permanently', + Status[302] = 'Found', + Status[303] = 'See Other', + Status[304] = 'Not Modified', + Status[305] = 'Use Proxy', + Status[306] = 'No Longer Used', + Status[307] = 'Temporary Redirect', + Status[400] = 'Bad Request', + Status[401] = 'Not Authorised', + Status[402] = 'Payment Required', + Status[403] = 'Forbidden', + Status[404] = 'Not Found', + Status[405] = 'Method Not Allowed', + Status[406] = 'Not Acceptable', + Status[407] = 'Proxy Authentication Required', + Status[408] = 'Request Timeout', + Status[409] = 'Conflict', + Status[410] = 'Gone', + Status[411] = 'Length Required', + Status[412] = 'Precondition Failed', + Status[413] = 'Request Entity Too Large', + Status[414] = 'Request URI Too Long', + Status[415] = 'Unsupported Media Type', + Status[416] = 'Requested Range Not Satisfiable', + Status[417] = 'Expectation Failed', + Status[500] = 'Internal Server Error', + Status[501] = 'Not Implemented', + Status[502] = 'Bad Gateway', + Status[503] = 'Service Unavailable', + Status[504] = 'Gateway Timeout', + Status[505] = 'HTTP Version Not Supported'; + var error:String = '[' + event.status + ':' + (Status[event.status] || "Unknown Error") + ']'; + var data:ByteArray = new ByteArray(); + var writer:HproseWriter = new HproseWriter(data); + data.writeByte(HproseTags.TagError); + writer.writeString(error); + data.writeByte(HproseTags.TagEnd); + data.position = 0; + callback(data); + } + } + private function ioErrorHandler(event:IOErrorEvent):void { + if (!complete) { + complete = true; + timer.stop(); + var data:ByteArray = new ByteArray(); + var writer:HproseWriter = new HproseWriter(data); + data.writeByte(HproseTags.TagError); + writer.writeString(event.text); + data.writeByte(HproseTags.TagEnd); + data.position = 0; + callback(data); + } + } + private function securityErrorHandler(event:SecurityErrorEvent):void { + if (!complete) { + complete = true; + timer.stop(); + var data:ByteArray = new ByteArray(); + var writer:HproseWriter = new HproseWriter(data); + data.writeByte(HproseTags.TagError); + writer.writeString(event.text); + data.writeByte(HproseTags.TagEnd); + data.position = 0; + callback(data); + } + } + private function progressHandler(event:ProgressEvent):void { + try { + progress(event); + } + catch (e:Error) {} + } + private function timeoutHandler(event:TimerEvent):void { + if (!complete) { + complete = true; + Timer(event.target).stop(); + stream.close(); + var data:ByteArray = new ByteArray(); + var writer:HproseWriter = new HproseWriter(data); + data.writeByte(HproseTags.TagError); + writer.writeString('timeout'); + data.writeByte(HproseTags.TagEnd); + data.position = 0; + callback(data); + } + } + public function stop() { + if (!complete) { + complete = true; + timer.stop(); + stream.close(); + } + } + } } \ No newline at end of file diff --git a/src/actionscript/as3/hprose/client/IHproseFilter.as b/src/actionscript/as3/hprose/client/IHproseFilter.as index cf278a4..e2feb89 100644 --- a/src/actionscript/as3/hprose/client/IHproseFilter.as +++ b/src/actionscript/as3/hprose/client/IHproseFilter.as @@ -1,27 +1,27 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * IHproseFilter.as * - * * - * hprose filter interface for ActionScript 3.0. * - * * - * LastModified: Jun 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -package hprose.client { - import flash.utils.ByteArray; - - public interface IHproseFilter { - function inputFilter(data: ByteArray):ByteArray; - function outputFilter(data: ByteArray):ByteArray; - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * IHproseFilter.as * + * * + * hprose filter interface for ActionScript 3.0. * + * * + * LastModified: Jun 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +package hprose.client { + import flash.utils.ByteArray; + + public interface IHproseFilter { + function inputFilter(data: ByteArray):ByteArray; + function outputFilter(data: ByteArray):ByteArray; + } } \ No newline at end of file diff --git a/src/actionscript/as3/hprose/io/ClassManager.as b/src/actionscript/as3/hprose/io/ClassManager.as index 83916f1..e8e2856 100644 --- a/src/actionscript/as3/hprose/io/ClassManager.as +++ b/src/actionscript/as3/hprose/io/ClassManager.as @@ -1,109 +1,109 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * ClassManager.as * - * * - * hprose ClassManager for ActionScript 3.0. * - * * - * LastModified: Dec 12, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ - -package hprose.io { - import flash.utils.getDefinitionByName; - import flash.utils.getQualifiedClassName; - - public final class ClassManager { - private static const classCache1:Object = {}; - private static const classCache2:Object = {}; - - public static function register(classReference:*, alias:String):void { - classCache1[classReference] = alias; - classCache2[alias] = classReference; - } - - public static function getClassAlias(o:*):String { - var classReference:* = o.constructor; - var alias:String = classCache1[classReference]; - if (alias) { - return alias; - } - alias = getQualifiedClassName(o); - if (alias == 'Object') { - if (o.getClassName) { - alias = o.getClassName(); - } - } - if (alias == 'flash.utils::Dictionary') { - alias = 'Object'; - } - alias = alias.replace(/\./g, '_').replace(/\:\:/g, '_'); - ClassManager.register(classReference, alias); - return alias; - } - - private static function findClass(cn:Array, poslist:Array, i:uint, c:String):Class { - if (i < poslist.length) { - var pos:uint = poslist[i]; - cn[pos] = c; - var classReference:Class = findClass(cn, poslist, i + 1, '.'); - if (i + 1 < poslist.length) { - if (classReference == null) { - classReference = findClass(cn, poslist, i + 1, '_'); - } - } - return classReference; - } - var alias:String = cn.join(''); - try { - return getDefinitionByName(alias) as Class; - } - catch (e:ReferenceError) {}; - return null; - } - - public static function getClass(alias:String):* { - var classReference:* = classCache2[alias]; - if (classReference) { - return classReference; - } - try { - classReference = getDefinitionByName(alias) as Class; - register(classReference, alias); - return classReference; - } - catch (e:ReferenceError) {} - var poslist:Array = []; - var pos:int = alias.indexOf("_"); - while (pos > -1) { - poslist[poslist.length] = pos; - pos = alias.indexOf("_", pos + 1); - } - if (poslist.length > 0) { - var cn:Array = alias.split(''); - classReference = findClass(cn, poslist, 0, '.'); - if (classReference == null) { - classReference = findClass(cn, poslist, 0, '_'); - } - } - if (classReference == null) { - classReference = function ():void { - this.getClassName = function ():String { - return alias; - } - } - } - register(classReference, alias); - return classReference; - } - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * ClassManager.as * + * * + * hprose ClassManager for ActionScript 3.0. * + * * + * LastModified: Dec 12, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +package hprose.io { + import flash.utils.getDefinitionByName; + import flash.utils.getQualifiedClassName; + + public final class ClassManager { + private static const classCache1:Object = {}; + private static const classCache2:Object = {}; + + public static function register(classReference:*, alias:String):void { + classCache1[classReference] = alias; + classCache2[alias] = classReference; + } + + public static function getClassAlias(o:*):String { + var classReference:* = o.constructor; + var alias:String = classCache1[classReference]; + if (alias) { + return alias; + } + alias = getQualifiedClassName(o); + if (alias == 'Object') { + if (o.getClassName) { + alias = o.getClassName(); + } + } + if (alias == 'flash.utils::Dictionary') { + alias = 'Object'; + } + alias = alias.replace(/\./g, '_').replace(/\:\:/g, '_'); + ClassManager.register(classReference, alias); + return alias; + } + + private static function findClass(cn:Array, poslist:Array, i:uint, c:String):Class { + if (i < poslist.length) { + var pos:uint = poslist[i]; + cn[pos] = c; + var classReference:Class = findClass(cn, poslist, i + 1, '.'); + if (i + 1 < poslist.length) { + if (classReference == null) { + classReference = findClass(cn, poslist, i + 1, '_'); + } + } + return classReference; + } + var alias:String = cn.join(''); + try { + return getDefinitionByName(alias) as Class; + } + catch (e:ReferenceError) {}; + return null; + } + + public static function getClass(alias:String):* { + var classReference:* = classCache2[alias]; + if (classReference) { + return classReference; + } + try { + classReference = getDefinitionByName(alias) as Class; + register(classReference, alias); + return classReference; + } + catch (e:ReferenceError) {} + var poslist:Array = []; + var pos:int = alias.indexOf("_"); + while (pos > -1) { + poslist[poslist.length] = pos; + pos = alias.indexOf("_", pos + 1); + } + if (poslist.length > 0) { + var cn:Array = alias.split(''); + classReference = findClass(cn, poslist, 0, '.'); + if (classReference == null) { + classReference = findClass(cn, poslist, 0, '_'); + } + } + if (classReference == null) { + classReference = function ():void { + this.getClassName = function ():String { + return alias; + } + } + } + register(classReference, alias); + return classReference; + } + } } \ No newline at end of file diff --git a/src/actionscript/as3/hprose/io/HproseReader.as b/src/actionscript/as3/hprose/io/HproseReader.as index 331150b..59bc0dc 100644 --- a/src/actionscript/as3/hprose/io/HproseReader.as +++ b/src/actionscript/as3/hprose/io/HproseReader.as @@ -1,786 +1,786 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseReader.as * - * * - * hprose reader class for ActionScript 3.0. * - * * - * LastModified: Dec 13, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -package hprose.io { - import flash.utils.ByteArray; - import flash.utils.Dictionary; - import flash.utils.IDataInput; - - public final class HproseReader { - private const ref:Array = []; - private const classref:Array = []; - private var stream:IDataInput; - - public function HproseReader(stream:IDataInput) { - this.stream = stream; - } - - public function get inputStream():IDataInput { - return stream; - } - - public function unserialize():* { - var tag:int = stream.readByte(); - switch (tag) { - case 48: return 0; - case 49: return 1; - case 50: return 2; - case 51: return 3; - case 52: return 4; - case 53: return 5; - case 54: return 6; - case 55: return 7; - case 56: return 8; - case 57: return 9; - case HproseTags.TagInteger: return readIntegerWithoutTag(); - case HproseTags.TagLong: return readLongWithoutTag(); - case HproseTags.TagDouble: return readDoubleWithoutTag(); - case HproseTags.TagNull: return null; - case HproseTags.TagEmpty: return ""; - case HproseTags.TagTrue: return true; - case HproseTags.TagFalse: return false; - case HproseTags.TagNaN: return NaN; - case HproseTags.TagInfinity: return readInfinityWithoutTag(); - case HproseTags.TagDate: return readDateWithoutTag(); - case HproseTags.TagTime: return readTimeWithoutTag(); - case HproseTags.TagBytes: return readBytesWithoutTag(); - case HproseTags.TagUTF8Char: return readUTF8CharWithoutTag(); - case HproseTags.TagString: return readStringWithoutTag(); - case HproseTags.TagGuid: return readGuidWithoutTag(); - case HproseTags.TagList: return readListWithoutTag(); - case HproseTags.TagMap: return readMapWithoutTag(); - case HproseTags.TagClass: readClass(); return readObject(); - case HproseTags.TagObject: return readObjectWithoutTag(); - case HproseTags.TagRef: return readRef(); - case HproseTags.TagError: throw new HproseException(readString()); - default: throw unexpectedTag(tag); - } - } - - public function unexpectedTag(tag:int, expectTags:* = null):HproseException { - if (expectTags == null) { - return new HproseException("Unexpected serialize tag 0x" + tag.toString(16) + " in stream"); - } - var expectTag:String = ""; - if (expectTags is Array) { - for (var t:String in expectTags) { - expectTag += String.fromCharCode(t); - } - } - else { - expectTag = expectTags; - } - return new HproseException("Tag '" + String.fromCharCode(expectTag) + "' expected, " + - "but 0x" + tag.toString(16) + " found in stream"); - } - - public function checkTag(expectTag:int, tag:int = -1):void { - if (tag == -1) tag = stream.readByte(); - if (tag != expectTag) unexpectedTag(tag, expectTag); - } - - public function checkTags(expectTags:Array, tag:int = -1):int { - if (tag == -1) tag = stream.readByte(); - if (expectTags.indexOf(tag) < 0) unexpectedTag(tag, expectTags); - return tag; - } - - public function readUntil(tag:int):String { - var s:Array = []; - var i:int = 0; - var c:int = stream.readByte(); - while (c != tag) { - s[i++] = String.fromCharCode(c); - c = stream.readByte(); - } - return s.join(''); - } - - public function readInt(tag:int):int { - var s:String = readUntil(tag); - if (s.length == 0) return 0; - return int(parseInt(s)); - } - - public function readIntegerWithoutTag():int { - return readInt(HproseTags.TagSemicolon); - } - - public function readInteger():int { - var tag:int = stream.readByte(); - switch (tag) { - case 48: return 0; - case 49: return 1; - case 50: return 2; - case 51: return 3; - case 52: return 4; - case 53: return 5; - case 54: return 6; - case 55: return 7; - case 56: return 8; - case 57: return 9; - case HproseTags.TagInteger: return readIntegerWithoutTag(); - default: throw unexpectedTag(tag); - } - } - - public function readLongWithoutTag():* { - return readUntil(HproseTags.TagSemicolon); - } - - public function readLong():* { - var tag:int = stream.readByte(); - switch (tag) { - case 48: return 0; - case 49: return 1; - case 50: return 2; - case 51: return 3; - case 52: return 4; - case 53: return 5; - case 54: return 6; - case 55: return 7; - case 56: return 8; - case 57: return 9; - case HproseTags.TagInteger: return readLongWithoutTag(); - case HproseTags.TagLong: return readLongWithoutTag(); - default: throw unexpectedTag(tag); - } - } - - public function readDoubleWithoutTag():Number { - return parseFloat(readUntil(HproseTags.TagSemicolon)); - } - - public function readDouble():Number { - var tag:int = stream.readByte(); - switch (tag) { - case 48: return 0; - case 49: return 1; - case 50: return 2; - case 51: return 3; - case 52: return 4; - case 53: return 5; - case 54: return 6; - case 55: return 7; - case 56: return 8; - case 57: return 9; - case HproseTags.TagInteger: return readDoubleWithoutTag(); - case HproseTags.TagLong: return readDoubleWithoutTag(); - case HproseTags.TagDouble: return readDoubleWithoutTag(); - case HproseTags.TagNaN: return NaN; - case HproseTags.TagInfinity: return readInfinityWithoutTag(); - default: throw unexpectedTag(tag); - } - } - - public function readNaN():Number { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagNaN: return NaN; - default: throw unexpectedTag(tag); - } - } - - public function readInfinityWithoutTag():Number { - return ((stream.readByte() == HproseTags.TagPos) ? Infinity : -Infinity); - } - - public function readInfinity():Number { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagInfinity: return readInfinityWithoutTag(); - default: throw unexpectedTag(tag); - } - } - - public function readNull():Object { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagNull: return null; - default: throw unexpectedTag(tag); - } - } - - public function readEmpty():String { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagEmpty: return ""; - default: throw unexpectedTag(tag); - } - } - - public function readBoolean():Boolean { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagTrue: return true; - case HproseTags.TagFalse: return false; - default: throw unexpectedTag(tag); - } - } - - public function readDateWithoutTag():Date { - var year:Number = parseInt(stream.readUTFBytes(4)); - var month:Number = parseInt(stream.readUTFBytes(2)) - 1; - var day:Number = parseInt(stream.readUTFBytes(2)); - var date:Date; - var tag:int = stream.readByte(); - if (tag == HproseTags.TagTime) { - var hour:Number = parseInt(stream.readUTFBytes(2)); - var minute:Number = parseInt(stream.readUTFBytes(2)); - var second:Number = parseInt(stream.readUTFBytes(2)); - var millisecond:Number = 0; - tag = stream.readByte(); - if (tag == HproseTags.TagPoint) { - millisecond = parseInt(stream.readUTFBytes(3)); - tag = stream.readByte(); - } - tag = stream.readByte(); - if (tag == HproseTags.TagPoint) { - millisecond = parseInt(stream.readUTFBytes(3)); - tag = stream.readByte(); - if ((tag >= 48) && (tag <= 57)) { - stream.readByte(); - stream.readByte(); - tag = stream.readByte(); - if ((tag >= 48) && (tag <= 57)) { - stream.readByte(); - stream.readByte(); - tag = stream.readByte(); - } - } - } - if (tag == HproseTags.TagUTC) { - date = new Date(Date.UTC(year, month, day, hour, minute, second, millisecond)); - } - else { - date = new Date(year, month, day, hour, minute, second, millisecond); - } - } - else if (tag == HproseTags.TagUTC) { - date = new Date(Date.UTC(year, month, day)); - } - else { - date = new Date(year, month, day); - } - return ref[ref.length] = date; - } - - public function readDate():Date { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagDate: return readDateWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: throw unexpectedTag(tag); - } - } - - public function readTimeWithoutTag():Date { - var time:Date; - var hour:Number = parseInt(stream.readUTFBytes(2)); - var minute:Number = parseInt(stream.readUTFBytes(2)); - var second:Number = parseInt(stream.readUTFBytes(2)); - var millisecond:Number = 0; - var tag:int = stream.readByte(); - if (tag == HproseTags.TagPoint) { - millisecond = parseInt(stream.readUTFBytes(3)); - tag = stream.readByte(); - if ((tag >= 48) && (tag <= 57)) { - stream.readByte(); - stream.readByte(); - tag = stream.readByte(); - if ((tag >= 48) && (tag <= 57)) { - stream.readByte(); - stream.readByte(); - tag = stream.readByte(); - } - } - } - if (tag == HproseTags.TagUTC) { - time = new Date(Date.UTC(1970, 0, 1, hour, minute, second, millisecond)); - } - else { - time = new Date(1970, 0, 1, hour, minute, second, millisecond); - } - return ref[ref.length] = time; - } - - public function readTime():Date { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagTime: return readTimeWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: throw unexpectedTag(tag); - } - } - - public function readBytesWithoutTag():ByteArray { - var count:int = readInt(HproseTags.TagQuote); - var bytes:ByteArray = new ByteArray(); - stream.readBytes(bytes, 0, count); - bytes.position = 0; - stream.readByte(); - return ref[ref.length] = bytes; - } - - public function readBytes():ByteArray { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagBytes: return readBytesWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: throw unexpectedTag(tag); - } - } - - public function readUTF8CharWithoutTag():String { - var u: String; - var c:uint, c2:uint, c3:uint; - c = stream.readUnsignedByte(); - switch (c >>> 4) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - // 0xxx xxxx - u = String.fromCharCode(c); - break; - case 12: - case 13: - // 110x xxxx 10xx xxxx - c2 = stream.readUnsignedByte(); - u = String.fromCharCode(((c & 0x1f) << 6) | - (c2 & 0x3f)); - break; - case 14: - // 1110 xxxx 10xx xxxx 10xx xxxx - c2 = stream.readUnsignedByte(); - c3 = stream.readUnsignedByte(); - u = String.fromCharCode(((c & 0x0f) << 12) | - ((c2 & 0x3f) << 6) | - (c3 & 0x3f)); - break; - default: - throw new HproseException("bad utf-8 encoding at 0x" + c.toString(16)); - } - return u; - } - - public function readUTF8Char():String { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagUTF8Char: return readUTF8CharWithoutTag(); - default: throw unexpectedTag(tag); - } - } - - private function _readString():String { - var len:int = readInt(HproseTags.TagQuote); - var buf:Array = []; - var c:uint, c2:uint, c3:uint, c4:uint; - for (var i:int = 0; i < len; i++) { - c = stream.readUnsignedByte(); - switch (c >>> 4) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - // 0xxx xxxx - buf[i] = String.fromCharCode(c); - break; - case 12: - case 13: - // 110x xxxx 10xx xxxx - c2 = stream.readUnsignedByte(); - buf[i] = String.fromCharCode(((c & 0x1f) << 6) | - (c2 & 0x3f)); - break; - case 14: - // 1110 xxxx 10xx xxxx 10xx xxxx - c2 = stream.readUnsignedByte(); - c3 = stream.readUnsignedByte(); - buf[i] = String.fromCharCode(((c & 0x0f) << 12) | - ((c2 & 0x3f) << 6) | - (c3 & 0x3f)); - break; - case 15: - // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx - if ((c & 0xf) <= 4) { - c2 = stream.readUnsignedByte(); - c3 = stream.readUnsignedByte(); - c4 = stream.readUnsignedByte(); - var s:uint = ((c & 0x07) << 18) | - ((c2 & 0x3f) << 12) | - ((c3 & 0x3f) << 6) | - (c4 & 0x3f) - 0x10000; - if (0 <= s && s <= 0xfffff) { - buf[i++] = String.fromCharCode(((s >>> 10) & 0x03ff) | 0xd800); - buf[i] = String.fromCharCode((s & 0x03ff) | 0xdc00); - break; - } - } - // no break here!! here need throw exception. - default: - throw new HproseException("bad utf-8 encoding at 0x" + c.toString(16)); - } - } - stream.readByte(); - return buf.join(''); - } - - public function readStringWithoutTag():String { - return ref[ref.length] = _readString(); - } - - public function readString():String { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagString: return readStringWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: throw unexpectedTag(tag); - } - } - - public function readGuidWithoutTag():String { - stream.readByte(); - var guid:String = stream.readUTFBytes(36); - stream.readByte(); - ref[ref.length] = guid; - return guid; - } - - public function readGuid():String { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagGuid: return readGuidWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: throw unexpectedTag(tag); - } - } - - public function readListWithoutTag():Array { - var list:Array = []; - ref[ref.length] = list; - var count:int = readInt(HproseTags.TagOpenbrace); - for (var i:int = 0; i < count; i++) { - list[i] = unserialize(); - } - stream.readByte(); - return list; - } - - public function readList():Array { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagList: return readListWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: throw unexpectedTag(tag); - } - } - - public function readMapWithoutTag():Dictionary { - var map:Dictionary = new Dictionary(); - ref[ref.length] = map; - var count:int = readInt(HproseTags.TagOpenbrace); - for (var i:int = 0; i < count; i++) { - var key:* = unserialize(); - var value:* = unserialize(); - map[key] = value; - } - stream.readByte(); - return map; - } - - public function readMap():Dictionary { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagMap: return readMapWithoutTag(); - case HproseTags.TagRef: return readRef(); - default: throw unexpectedTag(tag); - } - } - - public function readObjectWithoutTag():* { - var type:Object = classref[readInt(HproseTags.TagOpenbrace)]; - var object:* = new type['class']; - var properties:Array = type['properties']; - var count:int = type['count']; - ref[ref.length] = object; - for (var i:int = 0; i < count; i++) { - object[properties[i]] = unserialize(); - } - stream.readByte(); - return object; - } - - public function readObject():* { - var tag:int = stream.readByte(); - switch (tag) { - case HproseTags.TagObject: return readObjectWithoutTag(); - case HproseTags.TagClass: readClass(); return readObject(); - case HproseTags.TagRef: return readRef(); - default: throw unexpectedTag(tag); - } - } - - private function readClass():void { - var classname:String = _readString(); - var count:int = readInt(HproseTags.TagOpenbrace); - var properties:Array = []; - for (var i:uint = 0; i < count; i++) { - properties[i] = readString(); - } - stream.readByte(); - classref[classref.length] = {'class': ClassManager.getClass(classname), - 'count': count, - 'properties': properties}; - } - - private function readRef():* { - return ref[readInt(HproseTags.TagSemicolon)]; - } - - public function readRaw():ByteArray { - var ostream:ByteArray = new ByteArray(); - _readRaw(ostream, stream.readByte()); - ostream.position = 0; - return ostream; - } - - private function _readRaw(ostream:ByteArray, tag:int):void { - switch (tag) { - case 48: - case 49: - case 50: - case 51: - case 52: - case 53: - case 54: - case 55: - case 56: - case 57: - case HproseTags.TagNull: - case HproseTags.TagEmpty: - case HproseTags.TagTrue: - case HproseTags.TagFalse: - case HproseTags.TagNaN: - ostream.writeByte(tag); - break; - case HproseTags.TagInfinity: - ostream.writeByte(tag); - ostream.writeByte(stream.readByte()); - break; - case HproseTags.TagInteger: - case HproseTags.TagLong: - case HproseTags.TagDouble: - case HproseTags.TagRef: - readNumberRaw(ostream, tag); - break; - case HproseTags.TagDate: - case HproseTags.TagTime: - readDateTimeRaw(ostream, tag); - break; - case HproseTags.TagUTF8Char: - readUTF8CharRaw(ostream, tag); - break; - case HproseTags.TagBytes: - readBytesRaw(ostream, tag); - break; - case HproseTags.TagString: - readStringRaw(ostream, tag); - break; - case HproseTags.TagGuid: - readGuidRaw(ostream, tag); - break; - case HproseTags.TagList: - case HproseTags.TagMap: - case HproseTags.TagObject: - readComplexRaw(ostream, tag); - break; - case HproseTags.TagClass: - readComplexRaw(ostream, tag); - _readRaw(ostream, stream.readByte()); - break; - case HproseTags.TagError: - ostream.writeByte(tag); - _readRaw(ostream, stream.readByte()); - break; - default: - throw unexpectedTag(tag); - } - } - - private function readNumberRaw(ostream:ByteArray, tag:int):void { - ostream.writeByte(tag); - do { - tag = stream.readByte(); - ostream.writeByte(tag); - } while (tag != HproseTags.TagSemicolon); - } - - private function readDateTimeRaw(ostream:ByteArray, tag:int):void { - ostream.writeByte(tag); - do { - tag = stream.readByte(); - ostream.writeByte(tag); - } while (tag != HproseTags.TagSemicolon && - tag != HproseTags.TagUTC); - } - - private function readUTF8CharRaw(ostream:ByteArray, tag:int):void { - ostream.writeByte(tag); - tag = stream.readByte(); - switch ((tag & 0xff) >>> 4) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: { - // 0xxx xxxx - ostream.writeByte(tag); - break; - } - case 12: - case 13: { - // 110x xxxx 10xx xxxx - ostream.writeByte(tag); - ostream.writeByte(stream.readByte()); - break; - } - case 14: { - // 1110 xxxx 10xx xxxx 10xx xxxx - ostream.writeByte(tag); - ostream.writeByte(stream.readByte()); - ostream.writeByte(stream.readByte()); - break; - } - default: - throw new HproseException("bad utf-8 encoding at " + - ((tag < 0) ? "end of stream" : - "0x" + (tag & 0xff).toString(16))); - } - } - - private function readBytesRaw(ostream:ByteArray, tag:int):void { - ostream.writeByte(tag); - var count:int = 0; - tag = 48; - do { - count *= 10; - count += tag - 48; - tag = stream.readByte(); - ostream.writeByte(tag); - } while (tag != HproseTags.TagQuote); - stream.readBytes(ostream, ostream.position, count); - ostream.position = ostream.length; - ostream.writeByte(stream.readByte()); - } - - private function readStringRaw(ostream:ByteArray, tag:int):void { - ostream.writeByte(tag); - var count:int = 0; - tag = 48; - do { - count *= 10; - count += tag - 48; - tag = stream.readByte(); - ostream.writeByte(tag); - } while (tag != HproseTags.TagQuote); - for (var i:int = 0; i < count; i++) { - tag = stream.readByte(); - switch ((tag & 0xff) >>> 4) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: { - // 0xxx xxxx - ostream.writeByte(tag); - break; - } - case 12: - case 13: { - // 110x xxxx 10xx xxxx - ostream.writeByte(tag); - ostream.writeByte(stream.readByte()); - break; - } - case 14: { - // 1110 xxxx 10xx xxxx 10xx xxxx - ostream.writeByte(tag); - ostream.writeByte(stream.readByte()); - ostream.writeByte(stream.readByte()); - break; - } - case 15: { - // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx - if ((tag & 0xf) <= 4) { - ostream.writeByte(tag); - ostream.writeByte(stream.readByte()); - ostream.writeByte(stream.readByte()); - ostream.writeByte(stream.readByte()); - break; - } - // no break here!! here need throw exception. - } - default: - throw new HproseException("bad utf-8 encoding at " + - ((tag < 0) ? "end of stream" : - "0x" + (tag & 0xff).toString(16))); - } - } - ostream.writeByte(stream.readByte()); - } - - private function readGuidRaw(ostream:ByteArray, tag:int):void { - ostream.writeByte(tag); - stream.readBytes(ostream, ostream.position, 38); - ostream.position = ostream.length; - } - - private function readComplexRaw(ostream:ByteArray, tag:int):void { - ostream.writeByte(tag); - do { - tag = stream.readByte(); - ostream.writeByte(tag); - } while (tag != HproseTags.TagOpenbrace); - while ((tag = stream.readByte()) != HproseTags.TagClosebrace) { - _readRaw(ostream, tag); - } - ostream.writeByte(tag); - } - - public function reset():void { - ref.length = 0; - classref.length = 0; - } - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseReader.as * + * * + * hprose reader class for ActionScript 3.0. * + * * + * LastModified: Dec 13, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +package hprose.io { + import flash.utils.ByteArray; + import flash.utils.Dictionary; + import flash.utils.IDataInput; + + public final class HproseReader { + private const ref:Array = []; + private const classref:Array = []; + private var stream:IDataInput; + + public function HproseReader(stream:IDataInput) { + this.stream = stream; + } + + public function get inputStream():IDataInput { + return stream; + } + + public function unserialize():* { + var tag:int = stream.readByte(); + switch (tag) { + case 48: return 0; + case 49: return 1; + case 50: return 2; + case 51: return 3; + case 52: return 4; + case 53: return 5; + case 54: return 6; + case 55: return 7; + case 56: return 8; + case 57: return 9; + case HproseTags.TagInteger: return readIntegerWithoutTag(); + case HproseTags.TagLong: return readLongWithoutTag(); + case HproseTags.TagDouble: return readDoubleWithoutTag(); + case HproseTags.TagNull: return null; + case HproseTags.TagEmpty: return ""; + case HproseTags.TagTrue: return true; + case HproseTags.TagFalse: return false; + case HproseTags.TagNaN: return NaN; + case HproseTags.TagInfinity: return readInfinityWithoutTag(); + case HproseTags.TagDate: return readDateWithoutTag(); + case HproseTags.TagTime: return readTimeWithoutTag(); + case HproseTags.TagBytes: return readBytesWithoutTag(); + case HproseTags.TagUTF8Char: return readUTF8CharWithoutTag(); + case HproseTags.TagString: return readStringWithoutTag(); + case HproseTags.TagGuid: return readGuidWithoutTag(); + case HproseTags.TagList: return readListWithoutTag(); + case HproseTags.TagMap: return readMapWithoutTag(); + case HproseTags.TagClass: readClass(); return readObject(); + case HproseTags.TagObject: return readObjectWithoutTag(); + case HproseTags.TagRef: return readRef(); + case HproseTags.TagError: throw new HproseException(readString()); + default: throw unexpectedTag(tag); + } + } + + public function unexpectedTag(tag:int, expectTags:* = null):HproseException { + if (expectTags == null) { + return new HproseException("Unexpected serialize tag 0x" + tag.toString(16) + " in stream"); + } + var expectTag:String = ""; + if (expectTags is Array) { + for (var t:String in expectTags) { + expectTag += String.fromCharCode(t); + } + } + else { + expectTag = expectTags; + } + return new HproseException("Tag '" + String.fromCharCode(expectTag) + "' expected, " + + "but 0x" + tag.toString(16) + " found in stream"); + } + + public function checkTag(expectTag:int, tag:int = -1):void { + if (tag == -1) tag = stream.readByte(); + if (tag != expectTag) unexpectedTag(tag, expectTag); + } + + public function checkTags(expectTags:Array, tag:int = -1):int { + if (tag == -1) tag = stream.readByte(); + if (expectTags.indexOf(tag) < 0) unexpectedTag(tag, expectTags); + return tag; + } + + public function readUntil(tag:int):String { + var s:Array = []; + var i:int = 0; + var c:int = stream.readByte(); + while (c != tag) { + s[i++] = String.fromCharCode(c); + c = stream.readByte(); + } + return s.join(''); + } + + public function readInt(tag:int):int { + var s:String = readUntil(tag); + if (s.length == 0) return 0; + return int(parseInt(s)); + } + + public function readIntegerWithoutTag():int { + return readInt(HproseTags.TagSemicolon); + } + + public function readInteger():int { + var tag:int = stream.readByte(); + switch (tag) { + case 48: return 0; + case 49: return 1; + case 50: return 2; + case 51: return 3; + case 52: return 4; + case 53: return 5; + case 54: return 6; + case 55: return 7; + case 56: return 8; + case 57: return 9; + case HproseTags.TagInteger: return readIntegerWithoutTag(); + default: throw unexpectedTag(tag); + } + } + + public function readLongWithoutTag():* { + return readUntil(HproseTags.TagSemicolon); + } + + public function readLong():* { + var tag:int = stream.readByte(); + switch (tag) { + case 48: return 0; + case 49: return 1; + case 50: return 2; + case 51: return 3; + case 52: return 4; + case 53: return 5; + case 54: return 6; + case 55: return 7; + case 56: return 8; + case 57: return 9; + case HproseTags.TagInteger: return readLongWithoutTag(); + case HproseTags.TagLong: return readLongWithoutTag(); + default: throw unexpectedTag(tag); + } + } + + public function readDoubleWithoutTag():Number { + return parseFloat(readUntil(HproseTags.TagSemicolon)); + } + + public function readDouble():Number { + var tag:int = stream.readByte(); + switch (tag) { + case 48: return 0; + case 49: return 1; + case 50: return 2; + case 51: return 3; + case 52: return 4; + case 53: return 5; + case 54: return 6; + case 55: return 7; + case 56: return 8; + case 57: return 9; + case HproseTags.TagInteger: return readDoubleWithoutTag(); + case HproseTags.TagLong: return readDoubleWithoutTag(); + case HproseTags.TagDouble: return readDoubleWithoutTag(); + case HproseTags.TagNaN: return NaN; + case HproseTags.TagInfinity: return readInfinityWithoutTag(); + default: throw unexpectedTag(tag); + } + } + + public function readNaN():Number { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagNaN: return NaN; + default: throw unexpectedTag(tag); + } + } + + public function readInfinityWithoutTag():Number { + return ((stream.readByte() == HproseTags.TagPos) ? Infinity : -Infinity); + } + + public function readInfinity():Number { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagInfinity: return readInfinityWithoutTag(); + default: throw unexpectedTag(tag); + } + } + + public function readNull():Object { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagNull: return null; + default: throw unexpectedTag(tag); + } + } + + public function readEmpty():String { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagEmpty: return ""; + default: throw unexpectedTag(tag); + } + } + + public function readBoolean():Boolean { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagTrue: return true; + case HproseTags.TagFalse: return false; + default: throw unexpectedTag(tag); + } + } + + public function readDateWithoutTag():Date { + var year:Number = parseInt(stream.readUTFBytes(4)); + var month:Number = parseInt(stream.readUTFBytes(2)) - 1; + var day:Number = parseInt(stream.readUTFBytes(2)); + var date:Date; + var tag:int = stream.readByte(); + if (tag == HproseTags.TagTime) { + var hour:Number = parseInt(stream.readUTFBytes(2)); + var minute:Number = parseInt(stream.readUTFBytes(2)); + var second:Number = parseInt(stream.readUTFBytes(2)); + var millisecond:Number = 0; + tag = stream.readByte(); + if (tag == HproseTags.TagPoint) { + millisecond = parseInt(stream.readUTFBytes(3)); + tag = stream.readByte(); + } + tag = stream.readByte(); + if (tag == HproseTags.TagPoint) { + millisecond = parseInt(stream.readUTFBytes(3)); + tag = stream.readByte(); + if ((tag >= 48) && (tag <= 57)) { + stream.readByte(); + stream.readByte(); + tag = stream.readByte(); + if ((tag >= 48) && (tag <= 57)) { + stream.readByte(); + stream.readByte(); + tag = stream.readByte(); + } + } + } + if (tag == HproseTags.TagUTC) { + date = new Date(Date.UTC(year, month, day, hour, minute, second, millisecond)); + } + else { + date = new Date(year, month, day, hour, minute, second, millisecond); + } + } + else if (tag == HproseTags.TagUTC) { + date = new Date(Date.UTC(year, month, day)); + } + else { + date = new Date(year, month, day); + } + return ref[ref.length] = date; + } + + public function readDate():Date { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagDate: return readDateWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: throw unexpectedTag(tag); + } + } + + public function readTimeWithoutTag():Date { + var time:Date; + var hour:Number = parseInt(stream.readUTFBytes(2)); + var minute:Number = parseInt(stream.readUTFBytes(2)); + var second:Number = parseInt(stream.readUTFBytes(2)); + var millisecond:Number = 0; + var tag:int = stream.readByte(); + if (tag == HproseTags.TagPoint) { + millisecond = parseInt(stream.readUTFBytes(3)); + tag = stream.readByte(); + if ((tag >= 48) && (tag <= 57)) { + stream.readByte(); + stream.readByte(); + tag = stream.readByte(); + if ((tag >= 48) && (tag <= 57)) { + stream.readByte(); + stream.readByte(); + tag = stream.readByte(); + } + } + } + if (tag == HproseTags.TagUTC) { + time = new Date(Date.UTC(1970, 0, 1, hour, minute, second, millisecond)); + } + else { + time = new Date(1970, 0, 1, hour, minute, second, millisecond); + } + return ref[ref.length] = time; + } + + public function readTime():Date { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagTime: return readTimeWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: throw unexpectedTag(tag); + } + } + + public function readBytesWithoutTag():ByteArray { + var count:int = readInt(HproseTags.TagQuote); + var bytes:ByteArray = new ByteArray(); + stream.readBytes(bytes, 0, count); + bytes.position = 0; + stream.readByte(); + return ref[ref.length] = bytes; + } + + public function readBytes():ByteArray { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagBytes: return readBytesWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: throw unexpectedTag(tag); + } + } + + public function readUTF8CharWithoutTag():String { + var u: String; + var c:uint, c2:uint, c3:uint; + c = stream.readUnsignedByte(); + switch (c >>> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + // 0xxx xxxx + u = String.fromCharCode(c); + break; + case 12: + case 13: + // 110x xxxx 10xx xxxx + c2 = stream.readUnsignedByte(); + u = String.fromCharCode(((c & 0x1f) << 6) | + (c2 & 0x3f)); + break; + case 14: + // 1110 xxxx 10xx xxxx 10xx xxxx + c2 = stream.readUnsignedByte(); + c3 = stream.readUnsignedByte(); + u = String.fromCharCode(((c & 0x0f) << 12) | + ((c2 & 0x3f) << 6) | + (c3 & 0x3f)); + break; + default: + throw new HproseException("bad utf-8 encoding at 0x" + c.toString(16)); + } + return u; + } + + public function readUTF8Char():String { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagUTF8Char: return readUTF8CharWithoutTag(); + default: throw unexpectedTag(tag); + } + } + + private function _readString():String { + var len:int = readInt(HproseTags.TagQuote); + var buf:Array = []; + var c:uint, c2:uint, c3:uint, c4:uint; + for (var i:int = 0; i < len; i++) { + c = stream.readUnsignedByte(); + switch (c >>> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + // 0xxx xxxx + buf[i] = String.fromCharCode(c); + break; + case 12: + case 13: + // 110x xxxx 10xx xxxx + c2 = stream.readUnsignedByte(); + buf[i] = String.fromCharCode(((c & 0x1f) << 6) | + (c2 & 0x3f)); + break; + case 14: + // 1110 xxxx 10xx xxxx 10xx xxxx + c2 = stream.readUnsignedByte(); + c3 = stream.readUnsignedByte(); + buf[i] = String.fromCharCode(((c & 0x0f) << 12) | + ((c2 & 0x3f) << 6) | + (c3 & 0x3f)); + break; + case 15: + // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx + if ((c & 0xf) <= 4) { + c2 = stream.readUnsignedByte(); + c3 = stream.readUnsignedByte(); + c4 = stream.readUnsignedByte(); + var s:uint = ((c & 0x07) << 18) | + ((c2 & 0x3f) << 12) | + ((c3 & 0x3f) << 6) | + (c4 & 0x3f) - 0x10000; + if (0 <= s && s <= 0xfffff) { + buf[i++] = String.fromCharCode(((s >>> 10) & 0x03ff) | 0xd800); + buf[i] = String.fromCharCode((s & 0x03ff) | 0xdc00); + break; + } + } + // no break here!! here need throw exception. + default: + throw new HproseException("bad utf-8 encoding at 0x" + c.toString(16)); + } + } + stream.readByte(); + return buf.join(''); + } + + public function readStringWithoutTag():String { + return ref[ref.length] = _readString(); + } + + public function readString():String { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagString: return readStringWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: throw unexpectedTag(tag); + } + } + + public function readGuidWithoutTag():String { + stream.readByte(); + var guid:String = stream.readUTFBytes(36); + stream.readByte(); + ref[ref.length] = guid; + return guid; + } + + public function readGuid():String { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagGuid: return readGuidWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: throw unexpectedTag(tag); + } + } + + public function readListWithoutTag():Array { + var list:Array = []; + ref[ref.length] = list; + var count:int = readInt(HproseTags.TagOpenbrace); + for (var i:int = 0; i < count; i++) { + list[i] = unserialize(); + } + stream.readByte(); + return list; + } + + public function readList():Array { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagList: return readListWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: throw unexpectedTag(tag); + } + } + + public function readMapWithoutTag():Dictionary { + var map:Dictionary = new Dictionary(); + ref[ref.length] = map; + var count:int = readInt(HproseTags.TagOpenbrace); + for (var i:int = 0; i < count; i++) { + var key:* = unserialize(); + var value:* = unserialize(); + map[key] = value; + } + stream.readByte(); + return map; + } + + public function readMap():Dictionary { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagMap: return readMapWithoutTag(); + case HproseTags.TagRef: return readRef(); + default: throw unexpectedTag(tag); + } + } + + public function readObjectWithoutTag():* { + var type:Object = classref[readInt(HproseTags.TagOpenbrace)]; + var object:* = new type['class']; + var properties:Array = type['properties']; + var count:int = type['count']; + ref[ref.length] = object; + for (var i:int = 0; i < count; i++) { + object[properties[i]] = unserialize(); + } + stream.readByte(); + return object; + } + + public function readObject():* { + var tag:int = stream.readByte(); + switch (tag) { + case HproseTags.TagObject: return readObjectWithoutTag(); + case HproseTags.TagClass: readClass(); return readObject(); + case HproseTags.TagRef: return readRef(); + default: throw unexpectedTag(tag); + } + } + + private function readClass():void { + var classname:String = _readString(); + var count:int = readInt(HproseTags.TagOpenbrace); + var properties:Array = []; + for (var i:uint = 0; i < count; i++) { + properties[i] = readString(); + } + stream.readByte(); + classref[classref.length] = {'class': ClassManager.getClass(classname), + 'count': count, + 'properties': properties}; + } + + private function readRef():* { + return ref[readInt(HproseTags.TagSemicolon)]; + } + + public function readRaw():ByteArray { + var ostream:ByteArray = new ByteArray(); + _readRaw(ostream, stream.readByte()); + ostream.position = 0; + return ostream; + } + + private function _readRaw(ostream:ByteArray, tag:int):void { + switch (tag) { + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case HproseTags.TagNull: + case HproseTags.TagEmpty: + case HproseTags.TagTrue: + case HproseTags.TagFalse: + case HproseTags.TagNaN: + ostream.writeByte(tag); + break; + case HproseTags.TagInfinity: + ostream.writeByte(tag); + ostream.writeByte(stream.readByte()); + break; + case HproseTags.TagInteger: + case HproseTags.TagLong: + case HproseTags.TagDouble: + case HproseTags.TagRef: + readNumberRaw(ostream, tag); + break; + case HproseTags.TagDate: + case HproseTags.TagTime: + readDateTimeRaw(ostream, tag); + break; + case HproseTags.TagUTF8Char: + readUTF8CharRaw(ostream, tag); + break; + case HproseTags.TagBytes: + readBytesRaw(ostream, tag); + break; + case HproseTags.TagString: + readStringRaw(ostream, tag); + break; + case HproseTags.TagGuid: + readGuidRaw(ostream, tag); + break; + case HproseTags.TagList: + case HproseTags.TagMap: + case HproseTags.TagObject: + readComplexRaw(ostream, tag); + break; + case HproseTags.TagClass: + readComplexRaw(ostream, tag); + _readRaw(ostream, stream.readByte()); + break; + case HproseTags.TagError: + ostream.writeByte(tag); + _readRaw(ostream, stream.readByte()); + break; + default: + throw unexpectedTag(tag); + } + } + + private function readNumberRaw(ostream:ByteArray, tag:int):void { + ostream.writeByte(tag); + do { + tag = stream.readByte(); + ostream.writeByte(tag); + } while (tag != HproseTags.TagSemicolon); + } + + private function readDateTimeRaw(ostream:ByteArray, tag:int):void { + ostream.writeByte(tag); + do { + tag = stream.readByte(); + ostream.writeByte(tag); + } while (tag != HproseTags.TagSemicolon && + tag != HproseTags.TagUTC); + } + + private function readUTF8CharRaw(ostream:ByteArray, tag:int):void { + ostream.writeByte(tag); + tag = stream.readByte(); + switch ((tag & 0xff) >>> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: { + // 0xxx xxxx + ostream.writeByte(tag); + break; + } + case 12: + case 13: { + // 110x xxxx 10xx xxxx + ostream.writeByte(tag); + ostream.writeByte(stream.readByte()); + break; + } + case 14: { + // 1110 xxxx 10xx xxxx 10xx xxxx + ostream.writeByte(tag); + ostream.writeByte(stream.readByte()); + ostream.writeByte(stream.readByte()); + break; + } + default: + throw new HproseException("bad utf-8 encoding at " + + ((tag < 0) ? "end of stream" : + "0x" + (tag & 0xff).toString(16))); + } + } + + private function readBytesRaw(ostream:ByteArray, tag:int):void { + ostream.writeByte(tag); + var count:int = 0; + tag = 48; + do { + count *= 10; + count += tag - 48; + tag = stream.readByte(); + ostream.writeByte(tag); + } while (tag != HproseTags.TagQuote); + stream.readBytes(ostream, ostream.position, count); + ostream.position = ostream.length; + ostream.writeByte(stream.readByte()); + } + + private function readStringRaw(ostream:ByteArray, tag:int):void { + ostream.writeByte(tag); + var count:int = 0; + tag = 48; + do { + count *= 10; + count += tag - 48; + tag = stream.readByte(); + ostream.writeByte(tag); + } while (tag != HproseTags.TagQuote); + for (var i:int = 0; i < count; i++) { + tag = stream.readByte(); + switch ((tag & 0xff) >>> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: { + // 0xxx xxxx + ostream.writeByte(tag); + break; + } + case 12: + case 13: { + // 110x xxxx 10xx xxxx + ostream.writeByte(tag); + ostream.writeByte(stream.readByte()); + break; + } + case 14: { + // 1110 xxxx 10xx xxxx 10xx xxxx + ostream.writeByte(tag); + ostream.writeByte(stream.readByte()); + ostream.writeByte(stream.readByte()); + break; + } + case 15: { + // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx + if ((tag & 0xf) <= 4) { + ostream.writeByte(tag); + ostream.writeByte(stream.readByte()); + ostream.writeByte(stream.readByte()); + ostream.writeByte(stream.readByte()); + break; + } + // no break here!! here need throw exception. + } + default: + throw new HproseException("bad utf-8 encoding at " + + ((tag < 0) ? "end of stream" : + "0x" + (tag & 0xff).toString(16))); + } + } + ostream.writeByte(stream.readByte()); + } + + private function readGuidRaw(ostream:ByteArray, tag:int):void { + ostream.writeByte(tag); + stream.readBytes(ostream, ostream.position, 38); + ostream.position = ostream.length; + } + + private function readComplexRaw(ostream:ByteArray, tag:int):void { + ostream.writeByte(tag); + do { + tag = stream.readByte(); + ostream.writeByte(tag); + } while (tag != HproseTags.TagOpenbrace); + while ((tag = stream.readByte()) != HproseTags.TagClosebrace) { + _readRaw(ostream, tag); + } + ostream.writeByte(tag); + } + + public function reset():void { + ref.length = 0; + classref.length = 0; + } + } } \ No newline at end of file diff --git a/src/actionscript/as3/hprose/io/HproseWriter.as b/src/actionscript/as3/hprose/io/HproseWriter.as index e1fb015..08c3ca7 100644 --- a/src/actionscript/as3/hprose/io/HproseWriter.as +++ b/src/actionscript/as3/hprose/io/HproseWriter.as @@ -1,447 +1,447 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ -/**********************************************************\ - * * - * HproseWriter.as * - * * - * hprose writer class for ActionScript 3.0. * - * * - * LastModified: Dec 12, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -package hprose.io { - import flash.utils.ByteArray; - import flash.utils.Dictionary; - import flash.utils.IDataOutput; - import flash.utils.describeType; - import flash.utils.getDefinitionByName; - import flash.utils.getQualifiedClassName; - - public final class HproseWriter { - private static var propertyCache:Object = {}; - - private static function getPropertyNames(target:*):Array { - var className:String = getQualifiedClassName(target); - if (className in propertyCache) return propertyCache[className]; - var propertyNames:Array = []; - var typeInfo:XML = describeType(target is Class ? target : getDefinitionByName(className) as Class); - var properties:XMLList = typeInfo.factory..accessor.(@access == "readwrite") + typeInfo..variable; - for each (var propertyInfo:XML in properties) propertyNames.push(propertyInfo.@name.toString()); - propertyCache[className] = propertyNames; - return propertyNames; - } - - private static function isDigit(value:String):Boolean { - switch (value) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': return true; - } - return false; - } - - private static function isInteger(s:String):Boolean { - var l:uint = s.length; - for (var i:uint = (s.charAt(0) == '-') ? 1 : 0; i < l; i++) { - if (!isDigit(s.charAt(i))) return false; - } - return (s != '-'); - } - - private static function isInt32(value:Number):Boolean { - var s:String = value.toString(); - return ((s.length < 12) && - isInteger(s) && - (value >= -2147483648) && - (value <= 2147483647)); - } - - private const ref:Dictionary = new Dictionary(); - private const classref:Object = {}; - private var refCount:int = 0; - private var classrefCount:int = 0; - private var stream:IDataOutput; - - public function HproseWriter(stream:IDataOutput) { - this.stream = stream; - } - - public function get outputStream():IDataOutput { - return stream; - } - - public function serialize(o:*):void { - if (o == null) { - writeNull(); - return; - } - switch (o.constructor) { - case Boolean: - writeBoolean(o); - break; - case int: - ((o >= 0) && (o <= 9)) ? - stream.writeByte(o + 48): - writeInteger(o); - break; - case uint: - (o <= 9) ? - stream.writeByte(int(o) + 48): - (o <= 2147483647) ? - writeInteger(int(o)) : - writeLong(o); - break; - case Number: - isDigit(o.toString()) ? - stream.writeByte(int(o) + 48): - isInt32(o) ? - writeInteger(int(o)) : - writeDouble(o); - break; - case String: - o.length == 0 ? - writeEmpty() : - o.length == 1 ? - writeUTF8Char(o) : - writeStringWithRef(o); - break; - case ByteArray: - writeBytesWithRef(o); - break; - case Date: - writeDateWithRef(o); - break; - case Array: - writeListWithRef(o); - break; - default: - var alias:String = ClassManager.getClassAlias(o); - (alias == "Object") ? writeMapWithRef(o) : - (alias == "mx_collections_ArrayCollection") ? writeListWithRef(o.source) : - _writeObjectWithRef(o, alias); - break; - } - } - - public function writeInteger(i:int):void { - stream.writeByte(HproseTags.TagInteger); - stream.writeUTFBytes(i.toString()); - stream.writeByte(HproseTags.TagSemicolon); - } - - public function writeLong(i:*):void { - stream.writeByte(HproseTags.TagLong); - stream.writeUTFBytes(i.toString()); - stream.writeByte(HproseTags.TagSemicolon); - } - - public function writeDouble(d:Number):void { - if (isNaN(d)) { - writeNaN(); - } - else if (isFinite(d)) { - stream.writeByte(HproseTags.TagDouble); - stream.writeUTFBytes(d.toString()); - stream.writeByte(HproseTags.TagSemicolon); - } - else { - writeInfinity(d > 0); - } - } - - public function writeNaN():void { - stream.writeByte(HproseTags.TagNaN); - } - - public function writeInfinity(positive:Boolean = true):void { - stream.writeByte(HproseTags.TagInfinity); - stream.writeByte(positive ? HproseTags.TagPos : HproseTags.TagNeg); - } - - public function writeNull():void { - stream.writeByte(HproseTags.TagNull); - } - - public function writeEmpty():void { - stream.writeByte(HproseTags.TagEmpty); - } - - public function writeBoolean(bool:Boolean):void { - stream.writeByte(bool ? HproseTags.TagTrue : HproseTags.TagFalse); - } - - public function writeUTCDate(date:Date):void { - ref[date] = refCount++; - var year:String = ('0000' + date.getUTCFullYear()).slice(-4); - var month:String = ('00' + (date.getUTCMonth() + 1)).slice(-2); - var day:String = ('00' + date.getUTCDate()).slice(-2); - var hour:String = ('00' + date.getUTCHours()).slice(-2); - var minute:String = ('00' + date.getUTCMinutes()).slice(-2); - var second:String = ('00' + date.getUTCSeconds()).slice(-2); - var millisecond:String = ('000' + date.getUTCMilliseconds()).slice(-3); - if ((hour == '00') && (minute == '00') && (second == '00') && (millisecond == '000')) { - stream.writeByte(HproseTags.TagDate); - stream.writeUTFBytes(year + month + day); - stream.writeByte(HproseTags.TagUTC); - } - else if ((year == '1970') && (month == '01') && (day == '01')) { - stream.writeByte(HproseTags.TagTime); - stream.writeUTFBytes(hour + minute + second); - if (millisecond != '000') { - stream.writeByte(HproseTags.TagPoint); - stream.writeUTFBytes(millisecond); - } - stream.writeByte(HproseTags.TagUTC); - } - else { - stream.writeByte(HproseTags.TagDate); - stream.writeUTFBytes(year + month + day); - stream.writeByte(HproseTags.TagTime); - stream.writeUTFBytes(hour + minute + second); - if (millisecond != '000') { - stream.writeByte(HproseTags.TagPoint); - stream.writeUTFBytes(millisecond); - } - stream.writeByte(HproseTags.TagUTC); - } - } - - public function writeUTCDateWithRef(date:Date):void { - var r:* = ref[date]; - (r != null) ? writeRef(r) : writeUTCDate(date); - } - - public function writeDate(date:Date):void { - ref[date] = refCount++; - var year:String = ('0000' + date.getFullYear()).slice(-4); - var month:String = ('00' + (date.getMonth() + 1)).slice(-2); - var day:String = ('00' + date.getDate()).slice(-2); - var hour:String = ('00' + date.getHours()).slice(-2); - var minute:String = ('00' + date.getMinutes()).slice(-2); - var second:String = ('00' + date.getSeconds()).slice(-2); - var millisecond:String = ('000' + date.getMilliseconds()).slice(-3); - if ((hour == '00') && (minute == '00') && (second == '00') && (millisecond == '000')) { - stream.writeByte(HproseTags.TagDate); - stream.writeUTFBytes(year + month + day); - stream.writeByte(HproseTags.TagSemicolon); - } - else if ((year == '1970') && (month == '01') && (day == '01')) { - stream.writeByte(HproseTags.TagTime); - stream.writeUTFBytes(hour + minute + second); - if (millisecond != '000') { - stream.writeByte(HproseTags.TagPoint); - stream.writeUTFBytes(millisecond); - } - stream.writeByte(HproseTags.TagSemicolon); - } - else { - stream.writeByte(HproseTags.TagDate); - stream.writeUTFBytes(year + month + day); - stream.writeByte(HproseTags.TagTime); - stream.writeUTFBytes(hour + minute + second); - if (millisecond != '000') { - stream.writeByte(HproseTags.TagPoint); - stream.writeUTFBytes(millisecond); - } - stream.writeByte(HproseTags.TagSemicolon); - } - } - - public function writeDateWithRef(date:Date):void { - var r:* = ref[date]; - (r != null) ? writeRef(r) : writeDate(date); - } - - public function writeTime(time:Date):void { - ref[time] = refCount++; - var hour:String = ('00' + time.getHours()).slice(-2); - var minute:String = ('00' + time.getMinutes()).slice(-2); - var second:String = ('00' + time.getSeconds()).slice(-2); - var millisecond:String = ('000' + time.getMilliseconds()).slice(-3); - stream.writeByte(HproseTags.TagTime); - stream.writeUTFBytes(hour + minute + second); - if (millisecond != '000') { - stream.writeByte(HproseTags.TagPoint) - stream.writeUTFBytes(millisecond); - } - stream.writeByte(HproseTags.TagSemicolon); - } - - public function writeTimeWithRef(time:Date):void { - var r:* = ref[time]; - (r != null) ? writeRef(r) : writeTime(time); - } - - public function writeBytes(b:ByteArray):void { - ref[b] = refCount++; - stream.writeByte(HproseTags.TagBytes); - if (b.length > 0) { - stream.writeUTFBytes(b.length.toString()); - } - stream.writeByte(HproseTags.TagQuote); - stream.writeBytes(b); - stream.writeByte(HproseTags.TagQuote); - } - - public function writeBytesWithRef(b:ByteArray):void { - var r:* = ref[b]; - (r != null) ? writeRef(r) : writeBytes(b); - } - - public function writeUTF8Char(c:String):void { - stream.writeByte(HproseTags.TagUTF8Char); - stream.writeUTFBytes(c); - } - - public function writeString(s:String):void { - ref[s] = refCount++; - stream.writeByte(HproseTags.TagString); - if (s.length > 0) { - stream.writeUTFBytes(s.length.toString()); - } - stream.writeByte(HproseTags.TagQuote); - stream.writeUTFBytes(s); - stream.writeByte(HproseTags.TagQuote); - } - - public function writeStringWithRef(s:String):void { - var r:* = ref[s]; - (r != null) ? writeRef(r) : writeString(s); - } - - public function writeList(list:Array):void { - ref[list] = refCount++; - var count:uint = list.length; - stream.writeByte(HproseTags.TagList); - if (count > 0) { - stream.writeUTFBytes(count.toString()); - } - stream.writeByte(HproseTags.TagOpenbrace); - for (var i:uint = 0; i < count; i++) { - serialize(list[i]); - } - stream.writeByte(HproseTags.TagClosebrace); - } - - public function writeListWithRef(list:Array):void { - var r:* = ref[list]; - (r != null) ? writeRef(r) : writeList(list); - } - - public function writeMap(map:*):void { - ref[map] = refCount++; - var fields:Array = []; - for (var key:* in map) { - if (typeof(map[key]) != 'function') { - fields[fields.length] = key; - } - } - var count:uint = fields.length; - stream.writeByte(HproseTags.TagMap); - if (count > 0) { - stream.writeUTFBytes(count.toString()); - } - stream.writeByte(HproseTags.TagOpenbrace); - for (var i:uint = 0; i < count; i++) { - serialize(fields[i]); - serialize(map[fields[i]]); - } - stream.writeByte(HproseTags.TagClosebrace); - } - - public function writeMapWithRef(map:*):void { - var r:* = ref[map]; - (r != null) ? writeRef(r) : writeMap(map); - } - - private function _writeObject(obj:*, alias:String):void { - var fields:Array = getPropertyNames(obj); - for (var key:String in obj) { - if (typeof(obj[key]) != 'function' && - fields.indexOf(key) < 0) { - fields.push(key); - } - } - var cr:uint; - classref[alias]; - if (alias in classref) { - cr = classref[alias]; - } - else { - cr = writeClass(alias, fields); - } - ref[obj] = refCount++; - var count:uint = fields.length; - stream.writeByte(HproseTags.TagObject); - stream.writeUTFBytes(cr.toString()); - stream.writeByte(HproseTags.TagOpenbrace); - for (var i:uint = 0; i < count; i++) { - serialize(obj[fields[i]]); - } - stream.writeByte(HproseTags.TagClosebrace); - } - - private function _writeObjectWithRef(obj:*, alias:String):void { - var r:* = ref[obj]; - (r != null) ? writeRef(r) : _writeObject(obj, alias); - } - - public function writeObject(obj:*):void { - _writeObject(obj, ClassManager.getClassAlias(obj)); - } - - public function writeObjectWithRef(obj:*):void { - var r:* = ref[obj]; - (r != null) ? writeRef(r) : writeObject(obj); - } - - private function writeClass(alias:String, fields:Array):uint { - var count:uint = fields.length; - stream.writeByte(HproseTags.TagClass); - stream.writeUTFBytes(alias.length.toString()); - stream.writeByte(HproseTags.TagQuote); - stream.writeUTFBytes(alias); - stream.writeByte(HproseTags.TagQuote); - if (count > 0) { - stream.writeUTFBytes(count.toString()); - } - stream.writeByte(HproseTags.TagOpenbrace); - for (var i:uint = 0; i < count; i++) { - writeString(fields[i]); - } - stream.writeByte(HproseTags.TagClosebrace); - var cr:* = classrefCount++; - classref[alias] = cr; - return cr; - } - - private function writeRef(ref:int):void { - stream.writeByte(HproseTags.TagRef); - stream.writeUTFBytes(ref.toString()); - stream.writeByte(HproseTags.TagSemicolon); - } - - public function reset():void { - var key:*; - for(key in ref) delete ref[key]; - for (key in classref) delete classref[key]; - refCount = 0; - classrefCount = 0; - } - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ +/**********************************************************\ + * * + * HproseWriter.as * + * * + * hprose writer class for ActionScript 3.0. * + * * + * LastModified: Dec 12, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +package hprose.io { + import flash.utils.ByteArray; + import flash.utils.Dictionary; + import flash.utils.IDataOutput; + import flash.utils.describeType; + import flash.utils.getDefinitionByName; + import flash.utils.getQualifiedClassName; + + public final class HproseWriter { + private static var propertyCache:Object = {}; + + private static function getPropertyNames(target:*):Array { + var className:String = getQualifiedClassName(target); + if (className in propertyCache) return propertyCache[className]; + var propertyNames:Array = []; + var typeInfo:XML = describeType(target is Class ? target : getDefinitionByName(className) as Class); + var properties:XMLList = typeInfo.factory..accessor.(@access == "readwrite") + typeInfo..variable; + for each (var propertyInfo:XML in properties) propertyNames.push(propertyInfo.@name.toString()); + propertyCache[className] = propertyNames; + return propertyNames; + } + + private static function isDigit(value:String):Boolean { + switch (value) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': return true; + } + return false; + } + + private static function isInteger(s:String):Boolean { + var l:uint = s.length; + for (var i:uint = (s.charAt(0) == '-') ? 1 : 0; i < l; i++) { + if (!isDigit(s.charAt(i))) return false; + } + return (s != '-'); + } + + private static function isInt32(value:Number):Boolean { + var s:String = value.toString(); + return ((s.length < 12) && + isInteger(s) && + (value >= -2147483648) && + (value <= 2147483647)); + } + + private const ref:Dictionary = new Dictionary(); + private const classref:Object = {}; + private var refCount:int = 0; + private var classrefCount:int = 0; + private var stream:IDataOutput; + + public function HproseWriter(stream:IDataOutput) { + this.stream = stream; + } + + public function get outputStream():IDataOutput { + return stream; + } + + public function serialize(o:*):void { + if (o == null) { + writeNull(); + return; + } + switch (o.constructor) { + case Boolean: + writeBoolean(o); + break; + case int: + ((o >= 0) && (o <= 9)) ? + stream.writeByte(o + 48): + writeInteger(o); + break; + case uint: + (o <= 9) ? + stream.writeByte(int(o) + 48): + (o <= 2147483647) ? + writeInteger(int(o)) : + writeLong(o); + break; + case Number: + isDigit(o.toString()) ? + stream.writeByte(int(o) + 48): + isInt32(o) ? + writeInteger(int(o)) : + writeDouble(o); + break; + case String: + o.length == 0 ? + writeEmpty() : + o.length == 1 ? + writeUTF8Char(o) : + writeStringWithRef(o); + break; + case ByteArray: + writeBytesWithRef(o); + break; + case Date: + writeDateWithRef(o); + break; + case Array: + writeListWithRef(o); + break; + default: + var alias:String = ClassManager.getClassAlias(o); + (alias == "Object") ? writeMapWithRef(o) : + (alias == "mx_collections_ArrayCollection") ? writeListWithRef(o.source) : + _writeObjectWithRef(o, alias); + break; + } + } + + public function writeInteger(i:int):void { + stream.writeByte(HproseTags.TagInteger); + stream.writeUTFBytes(i.toString()); + stream.writeByte(HproseTags.TagSemicolon); + } + + public function writeLong(i:*):void { + stream.writeByte(HproseTags.TagLong); + stream.writeUTFBytes(i.toString()); + stream.writeByte(HproseTags.TagSemicolon); + } + + public function writeDouble(d:Number):void { + if (isNaN(d)) { + writeNaN(); + } + else if (isFinite(d)) { + stream.writeByte(HproseTags.TagDouble); + stream.writeUTFBytes(d.toString()); + stream.writeByte(HproseTags.TagSemicolon); + } + else { + writeInfinity(d > 0); + } + } + + public function writeNaN():void { + stream.writeByte(HproseTags.TagNaN); + } + + public function writeInfinity(positive:Boolean = true):void { + stream.writeByte(HproseTags.TagInfinity); + stream.writeByte(positive ? HproseTags.TagPos : HproseTags.TagNeg); + } + + public function writeNull():void { + stream.writeByte(HproseTags.TagNull); + } + + public function writeEmpty():void { + stream.writeByte(HproseTags.TagEmpty); + } + + public function writeBoolean(bool:Boolean):void { + stream.writeByte(bool ? HproseTags.TagTrue : HproseTags.TagFalse); + } + + public function writeUTCDate(date:Date):void { + ref[date] = refCount++; + var year:String = ('0000' + date.getUTCFullYear()).slice(-4); + var month:String = ('00' + (date.getUTCMonth() + 1)).slice(-2); + var day:String = ('00' + date.getUTCDate()).slice(-2); + var hour:String = ('00' + date.getUTCHours()).slice(-2); + var minute:String = ('00' + date.getUTCMinutes()).slice(-2); + var second:String = ('00' + date.getUTCSeconds()).slice(-2); + var millisecond:String = ('000' + date.getUTCMilliseconds()).slice(-3); + if ((hour == '00') && (minute == '00') && (second == '00') && (millisecond == '000')) { + stream.writeByte(HproseTags.TagDate); + stream.writeUTFBytes(year + month + day); + stream.writeByte(HproseTags.TagUTC); + } + else if ((year == '1970') && (month == '01') && (day == '01')) { + stream.writeByte(HproseTags.TagTime); + stream.writeUTFBytes(hour + minute + second); + if (millisecond != '000') { + stream.writeByte(HproseTags.TagPoint); + stream.writeUTFBytes(millisecond); + } + stream.writeByte(HproseTags.TagUTC); + } + else { + stream.writeByte(HproseTags.TagDate); + stream.writeUTFBytes(year + month + day); + stream.writeByte(HproseTags.TagTime); + stream.writeUTFBytes(hour + minute + second); + if (millisecond != '000') { + stream.writeByte(HproseTags.TagPoint); + stream.writeUTFBytes(millisecond); + } + stream.writeByte(HproseTags.TagUTC); + } + } + + public function writeUTCDateWithRef(date:Date):void { + var r:* = ref[date]; + (r != null) ? writeRef(r) : writeUTCDate(date); + } + + public function writeDate(date:Date):void { + ref[date] = refCount++; + var year:String = ('0000' + date.getFullYear()).slice(-4); + var month:String = ('00' + (date.getMonth() + 1)).slice(-2); + var day:String = ('00' + date.getDate()).slice(-2); + var hour:String = ('00' + date.getHours()).slice(-2); + var minute:String = ('00' + date.getMinutes()).slice(-2); + var second:String = ('00' + date.getSeconds()).slice(-2); + var millisecond:String = ('000' + date.getMilliseconds()).slice(-3); + if ((hour == '00') && (minute == '00') && (second == '00') && (millisecond == '000')) { + stream.writeByte(HproseTags.TagDate); + stream.writeUTFBytes(year + month + day); + stream.writeByte(HproseTags.TagSemicolon); + } + else if ((year == '1970') && (month == '01') && (day == '01')) { + stream.writeByte(HproseTags.TagTime); + stream.writeUTFBytes(hour + minute + second); + if (millisecond != '000') { + stream.writeByte(HproseTags.TagPoint); + stream.writeUTFBytes(millisecond); + } + stream.writeByte(HproseTags.TagSemicolon); + } + else { + stream.writeByte(HproseTags.TagDate); + stream.writeUTFBytes(year + month + day); + stream.writeByte(HproseTags.TagTime); + stream.writeUTFBytes(hour + minute + second); + if (millisecond != '000') { + stream.writeByte(HproseTags.TagPoint); + stream.writeUTFBytes(millisecond); + } + stream.writeByte(HproseTags.TagSemicolon); + } + } + + public function writeDateWithRef(date:Date):void { + var r:* = ref[date]; + (r != null) ? writeRef(r) : writeDate(date); + } + + public function writeTime(time:Date):void { + ref[time] = refCount++; + var hour:String = ('00' + time.getHours()).slice(-2); + var minute:String = ('00' + time.getMinutes()).slice(-2); + var second:String = ('00' + time.getSeconds()).slice(-2); + var millisecond:String = ('000' + time.getMilliseconds()).slice(-3); + stream.writeByte(HproseTags.TagTime); + stream.writeUTFBytes(hour + minute + second); + if (millisecond != '000') { + stream.writeByte(HproseTags.TagPoint) + stream.writeUTFBytes(millisecond); + } + stream.writeByte(HproseTags.TagSemicolon); + } + + public function writeTimeWithRef(time:Date):void { + var r:* = ref[time]; + (r != null) ? writeRef(r) : writeTime(time); + } + + public function writeBytes(b:ByteArray):void { + ref[b] = refCount++; + stream.writeByte(HproseTags.TagBytes); + if (b.length > 0) { + stream.writeUTFBytes(b.length.toString()); + } + stream.writeByte(HproseTags.TagQuote); + stream.writeBytes(b); + stream.writeByte(HproseTags.TagQuote); + } + + public function writeBytesWithRef(b:ByteArray):void { + var r:* = ref[b]; + (r != null) ? writeRef(r) : writeBytes(b); + } + + public function writeUTF8Char(c:String):void { + stream.writeByte(HproseTags.TagUTF8Char); + stream.writeUTFBytes(c); + } + + public function writeString(s:String):void { + ref[s] = refCount++; + stream.writeByte(HproseTags.TagString); + if (s.length > 0) { + stream.writeUTFBytes(s.length.toString()); + } + stream.writeByte(HproseTags.TagQuote); + stream.writeUTFBytes(s); + stream.writeByte(HproseTags.TagQuote); + } + + public function writeStringWithRef(s:String):void { + var r:* = ref[s]; + (r != null) ? writeRef(r) : writeString(s); + } + + public function writeList(list:Array):void { + ref[list] = refCount++; + var count:uint = list.length; + stream.writeByte(HproseTags.TagList); + if (count > 0) { + stream.writeUTFBytes(count.toString()); + } + stream.writeByte(HproseTags.TagOpenbrace); + for (var i:uint = 0; i < count; i++) { + serialize(list[i]); + } + stream.writeByte(HproseTags.TagClosebrace); + } + + public function writeListWithRef(list:Array):void { + var r:* = ref[list]; + (r != null) ? writeRef(r) : writeList(list); + } + + public function writeMap(map:*):void { + ref[map] = refCount++; + var fields:Array = []; + for (var key:* in map) { + if (typeof(map[key]) != 'function') { + fields[fields.length] = key; + } + } + var count:uint = fields.length; + stream.writeByte(HproseTags.TagMap); + if (count > 0) { + stream.writeUTFBytes(count.toString()); + } + stream.writeByte(HproseTags.TagOpenbrace); + for (var i:uint = 0; i < count; i++) { + serialize(fields[i]); + serialize(map[fields[i]]); + } + stream.writeByte(HproseTags.TagClosebrace); + } + + public function writeMapWithRef(map:*):void { + var r:* = ref[map]; + (r != null) ? writeRef(r) : writeMap(map); + } + + private function _writeObject(obj:*, alias:String):void { + var fields:Array = getPropertyNames(obj); + for (var key:String in obj) { + if (typeof(obj[key]) != 'function' && + fields.indexOf(key) < 0) { + fields.push(key); + } + } + var cr:uint; + classref[alias]; + if (alias in classref) { + cr = classref[alias]; + } + else { + cr = writeClass(alias, fields); + } + ref[obj] = refCount++; + var count:uint = fields.length; + stream.writeByte(HproseTags.TagObject); + stream.writeUTFBytes(cr.toString()); + stream.writeByte(HproseTags.TagOpenbrace); + for (var i:uint = 0; i < count; i++) { + serialize(obj[fields[i]]); + } + stream.writeByte(HproseTags.TagClosebrace); + } + + private function _writeObjectWithRef(obj:*, alias:String):void { + var r:* = ref[obj]; + (r != null) ? writeRef(r) : _writeObject(obj, alias); + } + + public function writeObject(obj:*):void { + _writeObject(obj, ClassManager.getClassAlias(obj)); + } + + public function writeObjectWithRef(obj:*):void { + var r:* = ref[obj]; + (r != null) ? writeRef(r) : writeObject(obj); + } + + private function writeClass(alias:String, fields:Array):uint { + var count:uint = fields.length; + stream.writeByte(HproseTags.TagClass); + stream.writeUTFBytes(alias.length.toString()); + stream.writeByte(HproseTags.TagQuote); + stream.writeUTFBytes(alias); + stream.writeByte(HproseTags.TagQuote); + if (count > 0) { + stream.writeUTFBytes(count.toString()); + } + stream.writeByte(HproseTags.TagOpenbrace); + for (var i:uint = 0; i < count; i++) { + writeString(fields[i]); + } + stream.writeByte(HproseTags.TagClosebrace); + var cr:* = classrefCount++; + classref[alias] = cr; + return cr; + } + + private function writeRef(ref:int):void { + stream.writeByte(HproseTags.TagRef); + stream.writeUTFBytes(ref.toString()); + stream.writeByte(HproseTags.TagSemicolon); + } + + public function reset():void { + var key:*; + for(key in ref) delete ref[key]; + for (key in classref) delete classref[key]; + refCount = 0; + classrefCount = 0; + } + } } \ No newline at end of file diff --git a/src/asp/jscript/hproseCommon.js b/src/asp/jscript/hproseCommon.js index dfccfa9..3a60195 100644 --- a/src/asp/jscript/hproseCommon.js +++ b/src/asp/jscript/hproseCommon.js @@ -1,149 +1,149 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ - -/**********************************************************\ - * * - * hproseCommon.js * - * * - * hprose common library for ASP. * - * * - * LastModified: Nov 26, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ - -var HproseResultMode = { - Normal: 0, - Serialized: 1, - Raw: 2, - RawWithEndTag: 3 -} - -function HproseException(message) { - this.message = message; - this.description = message; -}; -HproseException.prototype = new Error; -HproseException.prototype.name = 'HproseException'; - -function HproseFilter() { - this.inputFilter = function(value) { return value; }; - this.outputFilter = function(value) { return value; }; -} - -var HproseUtil = { - isDictionary: function(o) { - return ((o != null) && - (typeof(o) == "object") && - (o instanceof ActiveXObject) && - (typeof(o.Add) == "unknown") && - (typeof(o.Exists) == "unknown") && - (typeof(o.Items) == "unknown") && - (typeof(o.Keys) == "unknown") && - (typeof(o.Remove) == "unknown") && - (typeof(o.RemoveAll) == "unknown") && - (typeof(o.Count) == "number") && - (typeof(o.Item) == "unknown") && - (typeof(o.Key) == "unknown")); - }, - - isVBArray: function(o) { - return ((o != null) && - (typeof(o) == "unknown") && - (o.constructor == VBArray) && - (typeof(o.dimensions) == "function") && - (typeof(o.getItem) == "function") && - (typeof(o.lbound) == "function") && - (typeof(o.toArray) == "function") && - (typeof(o.ubound) == "function")); - }, - - toObject: function(dict) { - var array = (new VBArray(dict.Keys())).toArray(); - var result = {}; - for (var i = 0; i < array.length; i++) { - if (this.isDictionary(dict(array[i]))) { - result[array[i]] = this.toObject(dict(array[i])); - } - else if (this.isVBArray(dict(array[i]))) { - result[array[i]] = this.toJSArray(dict(array[i])); - } - else { - result[array[i]] = dict(array[i]); - } - } - return result; - }, - - toDictionary: function(object) { - var key, result; - result = new ActiveXObject("Scripting.Dictionary"); - for (key in object) { - result.Add(key, object[key]); - } - return result; - }, - - toJSArray: function(vbArray) { - function toArray(vbarray, dimension, indices) { - var rank = vbarray.dimensions(); - if (rank > dimension) { - indices[dimension] = 0; - dimension++; - } - var lb = vbarray.lbound(dimension); - var ub = vbarray.ubound(dimension); - var jsarray = []; - for (var i = lb; i <= ub; i++) { - indices[dimension - 1] = i; - if (rank == dimension) { - jsarray[i] = vbarray.getItem.apply(vbarray, indices); - } - else { - jsarray[i] = toArray(vbarray, dimension, indices); - } - } - return jsarray; - } - - var vbarray = new VBArray(vbArray); - if (vbarray.dimensions() == 1 && vbarray.lbound() == 0) { - return vbarray.toArray(); - } - return toArray(vbarray, 0, []); - }, - - toVBArray: function(jsarray) { - return this.toDictionary(jsarray).Items(); - }, - - binaryToString: function(binary, charSet) { - try { - var adTypeText = 2; - var adTypeBinary = 1; - var binaryStream = new ActiveXObject("ADODB.Stream"); - binaryStream.Type = adTypeBinary; - binaryStream.Open(); - binaryStream.Write(binary); - binaryStream.Position = 0; - binaryStream.Type = adTypeText; - if (charSet) { - binaryStream.CharSet = charSet; - } - else { - binaryStream.CharSet = "UTF-8"; - } - return binaryStream.ReadText(); - } - catch (e) { - return ""; - } - } +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * hproseCommon.js * + * * + * hprose common library for ASP. * + * * + * LastModified: Nov 26, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +var HproseResultMode = { + Normal: 0, + Serialized: 1, + Raw: 2, + RawWithEndTag: 3 +} + +function HproseException(message) { + this.message = message; + this.description = message; +}; +HproseException.prototype = new Error; +HproseException.prototype.name = 'HproseException'; + +function HproseFilter() { + this.inputFilter = function(value) { return value; }; + this.outputFilter = function(value) { return value; }; +} + +var HproseUtil = { + isDictionary: function(o) { + return ((o != null) && + (typeof(o) == "object") && + (o instanceof ActiveXObject) && + (typeof(o.Add) == "unknown") && + (typeof(o.Exists) == "unknown") && + (typeof(o.Items) == "unknown") && + (typeof(o.Keys) == "unknown") && + (typeof(o.Remove) == "unknown") && + (typeof(o.RemoveAll) == "unknown") && + (typeof(o.Count) == "number") && + (typeof(o.Item) == "unknown") && + (typeof(o.Key) == "unknown")); + }, + + isVBArray: function(o) { + return ((o != null) && + (typeof(o) == "unknown") && + (o.constructor == VBArray) && + (typeof(o.dimensions) == "function") && + (typeof(o.getItem) == "function") && + (typeof(o.lbound) == "function") && + (typeof(o.toArray) == "function") && + (typeof(o.ubound) == "function")); + }, + + toObject: function(dict) { + var array = (new VBArray(dict.Keys())).toArray(); + var result = {}; + for (var i = 0; i < array.length; i++) { + if (this.isDictionary(dict(array[i]))) { + result[array[i]] = this.toObject(dict(array[i])); + } + else if (this.isVBArray(dict(array[i]))) { + result[array[i]] = this.toJSArray(dict(array[i])); + } + else { + result[array[i]] = dict(array[i]); + } + } + return result; + }, + + toDictionary: function(object) { + var key, result; + result = new ActiveXObject("Scripting.Dictionary"); + for (key in object) { + result.Add(key, object[key]); + } + return result; + }, + + toJSArray: function(vbArray) { + function toArray(vbarray, dimension, indices) { + var rank = vbarray.dimensions(); + if (rank > dimension) { + indices[dimension] = 0; + dimension++; + } + var lb = vbarray.lbound(dimension); + var ub = vbarray.ubound(dimension); + var jsarray = []; + for (var i = lb; i <= ub; i++) { + indices[dimension - 1] = i; + if (rank == dimension) { + jsarray[i] = vbarray.getItem.apply(vbarray, indices); + } + else { + jsarray[i] = toArray(vbarray, dimension, indices); + } + } + return jsarray; + } + + var vbarray = new VBArray(vbArray); + if (vbarray.dimensions() == 1 && vbarray.lbound() == 0) { + return vbarray.toArray(); + } + return toArray(vbarray, 0, []); + }, + + toVBArray: function(jsarray) { + return this.toDictionary(jsarray).Items(); + }, + + binaryToString: function(binary, charSet) { + try { + var adTypeText = 2; + var adTypeBinary = 1; + var binaryStream = new ActiveXObject("ADODB.Stream"); + binaryStream.Type = adTypeBinary; + binaryStream.Open(); + binaryStream.Write(binary); + binaryStream.Position = 0; + binaryStream.Type = adTypeText; + if (charSet) { + binaryStream.CharSet = charSet; + } + else { + binaryStream.CharSet = "UTF-8"; + } + return binaryStream.ReadText(); + } + catch (e) { + return ""; + } + } } \ No newline at end of file diff --git a/src/asp/jscript/hproseHttpClient.js b/src/asp/jscript/hproseHttpClient.js index c4e9c32..68fc2bc 100644 --- a/src/asp/jscript/hproseHttpClient.js +++ b/src/asp/jscript/hproseHttpClient.js @@ -1,632 +1,632 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ - -/**********************************************************\ - * * - * hproseHttpClient.js * - * * - * hprose http client for ASP. * - * * - * LastModified: Nov 27, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ - -var HproseHttpClient = (function () { - /* Reference of global Class */ - var r_HproseResultMode = HproseResultMode; - var r_HproseException = HproseException; - var r_HproseFilter = HproseFilter; - var r_HproseStringInputStream = HproseStringInputStream; - var r_HproseStringOutputStream = HproseStringOutputStream; - var r_HproseReader = HproseReader; - var r_HproseWriter = HproseWriter; - var r_HproseTags = HproseTags; - var r_HproseFormatter = HproseFormatter; - - /* static private members */ - var s_keepSession = false; - - var s_cookieManager = {}; - - var s_XMLHttpNameCache = null; - - function createXMLHttp() { - if (s_XMLHttpNameCache != null) { - // Use the cache name first. - return new ActiveXObject(s_XMLHttpNameCache); - } - else { - var MSXML = ['MSXML2.ServerXMLHTTP.6.0', - 'MSXML2.ServerXMLHTTP.5.0', - 'MSXML2.ServerXMLHTTP.4.0', - 'MSXML2.ServerXMLHTTP.3.0', - 'MSXML2.ServerXMLHTTP']; - var n = MSXML.length; - var objXMLHttp; - for(var i = 0; i < n; i++) { - try { - objXMLHttp = new ActiveXObject(MSXML[i]); - // Cache the XMLHttp ActiveX object name. - s_XMLHttpNameCache = MSXML[i]; - return objXMLHttp; - } - catch(e) {} - } - return null; - } - } - - function setCookie(headers, host) { - for (var i = 0; i < headers.length; i++) { - var header = headers[i].split(':', 2); - var name = header[0].toLowerCase(); - var value = header[1]; - if ((name == 'set-cookie') || (name == 'set-cookie2')) { - var cookies = value.replace(/(^\s*)|(\s*$)/g, "").split(';'); - var cookie = {}; - value = cookies[0].replace(/(^\s*)|(\s*$)/g, "").split('=', 2); - if (value[1] === undefined) value[1] = null; - cookie['name'] = value[0]; - cookie['value'] = value[1]; - for (var j = 1; j < cookies.length; j++) { - value = cookies[j].replace(/(^\s*)|(\s*$)/g, "").split('=', 2); - if (value[1] === undefined) value[1] = null; - cookie[value[0].toUpperCase()] = value[1]; - } - // Tomcat can return SetCookie2 with path wrapped in " - if (cookie['PATH']) { - if (cookie['PATH'].charAt(0) == '"') { - cookie['PATH'] = cookie['PATH'].substr(1); - } - if (cookie['PATH'].charAt(cookie['PATH'].length - 1) == '"') { - cookie['PATH'] = cookie['PATH'].substr(0, cookie['PATH'].length - 1); - } - } - else { - cookie['PATH'] = '/' - } - if (cookie['EXPIRES']) { - cookie['EXPIRES'] = Date.parse(cookie['EXPIRES']); - } - if (cookie['DOMAIN']) { - cookie['DOMAIN'] = cookie['DOMAIN'].toLowerCase(); - } - else { - cookie['DOMAIN'] = host; - } - cookie['SECURE'] = (cookie['SECURE'] !== undefined); - if (s_cookieManager[cookie['DOMAIN']] === undefined) { - s_cookieManager[cookie['DOMAIN']] = {}; - } - s_cookieManager[cookie['DOMAIN']][cookie['name']] = cookie; - if (s_keepSession) { - Session("HPROSE_COOKIE_MANAGER") = s_cookieManager; - } - } - } - } - - function getCookie(host, path, secure) { - var cookies = []; - for (var domain in s_cookieManager) { - if (host.indexOf(domain) > -1) { - var names = []; - for (var name in s_cookieManager[domain]) { - var cookie = s_cookieManager[domain][name]; - if (cookie['EXPIRES'] && ((new Date()).getTime() > cookie['EXPIRES'])) { - names.push(name); - } - else if (path.indexOf(cookie['PATH']) === 0) { - if (((secure && cookie['SECURE']) || - !cookie['SECURE']) && (cookie['value'] !== null)) { - cookies.push(cookie['name'] + '=' + cookie['value']); - } - } - } - for (var i in names) { - delete s_cookieManager[domain][names[i]]; - } - } - } - if (cookies.length > 0) { - return cookies.join('; '); - } - return ''; - } - - function getResponse(xmlhttp, host, filter) { - if (xmlhttp.status == 200) { - var headers = xmlhttp.getAllResponseHeaders().split("\r\n"); - setCookie(headers, host); - return filter.intputFilter(xmlhttp.responseText); - } - else { - var error = xmlhttp.status + ':' + xmlhttp.statusText; - return r_HproseTags.TagError + - r_HproseFormatter.serialize(error) + - r_HproseTags.TagEnd; - } - } - - function post(url, header, data, proxy, proxyUsername, proxyPassword, timeout, filter, callback) { - var host, path, secure, p; - if (url.substr(0, 7).toLowerCase() == 'http://') { - secure = false; - p = 7; - } - else if (url.substr(0, 8).toLowerCase() == 'https://') { - secure = true; - p = 8; - } - if (p > 0) { - host = url.substring(p, url.indexOf('/', p)); - var m = host.match(/^([^:]*):([^@]*)@(.*)$/); - if (m != null) { - host = m[3]; - } - path = url.substr(url.indexOf('/', p)); - } - else { - throw new r_HproseException('Url must be an absolute path.'); - } - var xmlhttp = createXMLHttp(); - xmlhttp.setTimeouts(timeout, timeout, timeout, timeout); - if (proxy) { - try { - xmlhttp.setProxy(2, proxy); - if (proxyUsername) { - xmlhttp.setProxyCredentials(proxyUsername, proxyPassword); - } - } - catch(e) {} - } - if (callback) { - xmlhttp.open('POST', url, true); - xmlhttp.onreadystatechange = function() { - if (xmlhttp.readyState == 4) { - callback(getResponse(xmlhttp, host, filter)); - } - } - } - else { - xmlhttp.open('POST', url, false); - } - for (var name in header) { - xmlhttp.setRequestHeader(name, header[name]); - } - var cookie = getCookie(host, path, secure); - if (cookie != '') { - xmlhttp.setRequestHeader('Cookie', cookie); - } - xmlhttp.send(filter.outputFilter(data)); - if (callback) { - return xmlhttp; - } - else { - return getResponse(xmlhttp, host, filter); - } - } - - function HproseHttpClient(url, functions, vbs) { - // private members - var m_header = {'Content-Type': 'application/hprose; charset=utf-8'}; - var m_url; - var m_proxy; - var m_proxyUsername; - var m_proxyPassword; - var m_timeout = 30000; - var m_byref = false; - var m_xhrs = []; - var m_filter = new r_HproseFilter(); - var self = this; - // public methods - this.useService = function(url, functions, create) { - if (typeof(functions) == 'boolean' && create === undefined) { - create = functions; - } - var serviceProxy = this; - if (create) { - serviceProxy = {}; - } - if (url === undefined) { - return new r_HproseException("You should set server url first!"); - } - m_url = url; - if (typeof(functions) == 'string' || - (functions && functions.constructor == Object)) { - functions = [functions]; - } - if (Object.prototype.toString.apply(functions) === '[object Array]') { - setFunctions.call(serviceProxy, functions); - } - else { - useService.apply(serviceProxy); - } - return serviceProxy; - } - - this.invoke = function() { - var args = arguments; - var func = Array.prototype.shift.apply(args); - return invoke.call(this, func, args); - } - - this.setHeader = function(name, value) { - var lname = name.toLowerCase(); - if (lname != 'content-type' && - lname != 'content-length' && - lname != 'host') { - if (value) { - m_header[name] = value; - } - else { - delete m_header[name]; - } - } - } - - this.setProxy = function(host, port, username, password) { - if (!host) { - m_proxy = null; - } - else if (port === undefined) { - var p1 = 0; - if (host.substr(0, 7).toLowerCase() == 'http://') { - p1 = 7; - } - else if (host.substr(0, 6).toLowerCase() == 'tcp://') { - p1 = 6; - } - var p2 = host.indexOf('/', p1); - if (p2 > 0) { - host = host.substring(p1, p2); - var m = host.match(/^([^:]*):([^@]*)@(.*)$/); - if (m != null) { - m_proxyUsername = decodeURIComponent(m[1]); - m_proxyPassword = decodeURIComponent(m[2]); - host = m[3]; - } - } - m_proxy = host; - } - else { - m_proxy = host + ":" + port; - if (username !== undefined && password !== undefined) { - m_proxyUsername = username; - m_proxyPassword = password; - } - } - } - - this.setTimeout = function(value) { - m_timeout = value; - } - - this.getTimeout = function() { - return m_timeout; - } - - this.getByRef = function() { - return m_byref; - } - - this.setByRef = function(value) { - if (value === undefined) value = true; - m_byref = value; - } - - this.setFilter = function(filter) { - m_filter = filter; - } - - // events - this.onError = function(name, error) { - // your code for asynchronous invoke - } - - this.waitForResponse = function(timeout) { - for (var i = 0, l = m_xhrs.length; i < l; i++) { - if (m_xhrs[i]) { - var xhr = m_xhrs[i]; - if (timeout === undefined) { - xhr.waitForResponse(); - } - else { - if (timeout < 0) return; - var s = new Date(); - xhr.waitForResponse(timeout / 1000); - var e = new Date(); - timeout -= e.getTime() - s.getTime(); - } - } - } - } - - // private methods - function useService() { - var response = post(m_url, m_header, r_HproseTags.TagEnd, - m_proxy, m_proxyUsername, m_proxyPassword, - m_timeout, m_filter); - var stream = new r_HproseStringInputStream(response); - var hproseReader = new r_HproseReader(stream); - var tag = hproseReader.checkTags([r_HproseTags.TagFunctions, - r_HproseTags.TagError]); - switch (tag) { - case r_HproseTags.TagFunctions: - var functions = hproseReader.readList(); - hproseReader.checkTag(r_HproseTags.TagEnd); - setFunctions.call(this, functions); - break; - case r_HproseTags.TagError: - throw new r_HproseException(hproseReader.readString()); - break; - } - } - - function setFunction(func) { - var serverProxy = this; - return function() { - return invoke.call(serverProxy, func, arguments); - } - } - - function setMethods(obj, namespace, name, methods) { - if (obj[name] !== undefined) return; - obj[name] = {}; - if (typeof(methods) == 'string' || methods.constructor == Object) { - methods = [methods] - } - if (Object.prototype.toString.apply(methods) === '[object Array]') { - for (var i = 0; i < methods.length; i++) { - var m = methods[i]; - if (typeof(m) == 'string') { - obj[name][m] = setFunction.call(this, namespace + name + '_' + m); - } - else { - for (var n in m) { - setMethods.call(this, obj[name], name + '_', n, m[n]); - } - } - } - } - } - - function setFunctions(functions) { - for (var i = 0; i < functions.length; i++) { - var f = functions[i]; - if (typeof(f) == 'string') { - if (this[f] === undefined) { - this[f] = setFunction(f); - } - } - else { - for (var name in f) { - setMethods.call(this, this, '', name, f[name]); - } - } - } - } - - function getResult(response, func, args, resultMode) { - var result = null; - if (resultMode == r_HproseResultMode.RawWithEndTag) { - result = response; - } - else if (resultMode == r_HproseResultMode.Raw) { - result = response.substr(0, response.length - 1); - } - else { - var stream = new r_HproseStringInputStream(response); - var hproseReader = new r_HproseReader(stream, vbs); - var tag; - var error = null; - while ((tag = hproseReader.checkTags( - [r_HproseTags.TagResult, - r_HproseTags.TagArgument, - r_HproseTags.TagError, - r_HproseTags.TagEnd])) !== r_HproseTags.TagEnd) { - switch (tag) { - case r_HproseTags.TagResult: - if (resultMode == r_HproseResultMode.Serialized) { - result = hproseReader.readRaw().toString(); - } - else { - result = hproseReader.unserialize(); - } - break; - case r_HproseTags.TagArgument: - hproseReader.reset(); - var a = hproseReader.readList(); - for (var i = 0; i < a.length; i++) { - args[i] = a[i]; - } - break; - case r_HproseTags.TagError: - hproseReader.reset(); - error = new r_HproseException(hproseReader.readString()); - break; - } - } - if (error != null) throw error; - } - return result; - } - - function invoke(func, args) { - var resultMode = r_HproseResultMode.Normal; - var byref = m_byref; - var lowerCaseFunc = func.toLowerCase(); - var errorHandler = this[func + '_OnError'] || - this[func + '_onError'] || - this[func + '_onerror'] || - this[lowerCaseFunc + '_OnError'] || - this[lowerCaseFunc + '_onError'] || - this[lowerCaseFunc + '_onerror'] || - self[func + '_OnError'] || - self[func + '_onError'] || - self[func + '_onerror'] || - self[lowerCaseFunc + '_OnError'] || - self[lowerCaseFunc + '_onError'] || - self[lowerCaseFunc + '_onerror']; - var callback = this[func + '_Callback'] || - this[func + '_callback'] || - this[func + '_OnSuccess'] || - this[func + '_onSuccess'] || - this[func + '_onsuccess'] || - this[lowerCaseFunc + '_Callback'] || - this[lowerCaseFunc + '_callback'] || - this[lowerCaseFunc + '_OnSuccess'] || - this[lowerCaseFunc + '_onSuccess'] || - this[lowerCaseFunc + '_onsuccess'] || - self[func + '_Callback'] || - self[func + '_callback'] || - self[func + '_OnSuccess'] || - self[func + '_onSuccess'] || - self[func + '_onsuccess'] || - self[lowerCaseFunc + '_Callback'] || - self[lowerCaseFunc + '_callback'] || - self[lowerCaseFunc + '_OnSuccess'] || - self[lowerCaseFunc + '_onSuccess'] || - self[lowerCaseFunc + '_onsuccess']; - var count = args.length; - if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'boolean' && - typeof(args[count - 3]) == 'function' && - typeof(args[count - 4]) == 'function') { - resultMode = args[count - 1]; - byref = args[count - 2]; - errorHandler = args[count - 3]; - callback = args[count - 4]; - delete args[count - 1]; - delete args[count - 2]; - delete args[count - 3]; - delete args[count - 4]; - args.length -= 4; - } - else if (typeof(args[count - 1]) == 'boolean' && - typeof(args[count - 2]) == 'function' && - typeof(args[count - 3]) == 'function') { - byref = args[count - 1]; - errorHandler = args[count - 2]; - callback = args[count - 3]; - delete args[count - 1]; - delete args[count - 2]; - delete args[count - 3]; - args.length -= 3; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'function' && - typeof(args[count - 3]) == 'function') { - resultMode = args[count - 1]; - errorHandler = args[count - 2]; - callback = args[count - 3]; - delete args[count - 1]; - delete args[count - 2]; - delete args[count - 3]; - args.length -= 3; - } - else if (typeof(args[count - 1]) == 'function' && - typeof(args[count - 2]) == 'function') { - errorHandler = args[count - 1]; - callback = args[count - 2]; - delete args[count - 1]; - delete args[count - 2]; - args.length -= 2; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'boolean' && - typeof(args[count - 3]) == 'function') { - resultMode = args[count - 1]; - byref = args[count - 2]; - callback = args[count - 3]; - delete args[count - 1]; - delete args[count - 2]; - delete args[count - 3]; - args.length -= 3; - } - else if (typeof(args[count - 1]) == 'boolean' && - typeof(args[count - 2]) == 'function') { - byref = args[count - 1]; - callback = args[count - 2]; - delete args[count - 1]; - delete args[count - 2]; - args.length -= 2; - } - else if (typeof(args[count - 1]) == 'number' && - typeof(args[count - 2]) == 'function') { - resultMode = args[count - 1]; - callback = args[count - 2]; - delete args[count - 1]; - delete args[count - 2]; - args.length -= 2; - } - else if (typeof(args[count - 1]) == 'function') { - callback = args[count - 1]; - delete args[count - 1]; - args.length--; - } - var stream = new r_HproseStringOutputStream(r_HproseTags.TagCall); - var hproseWriter = new r_HproseWriter(stream); - hproseWriter.writeString(func, false); - if (args.length > 0 || byref) { - hproseWriter.reset(); - hproseWriter.writeList(args, false); - if (byref) { - hproseWriter.writeBoolean(true); - } - } - stream.write(r_HproseTags.TagEnd); - var request = stream.toString(); - if (callback) { - var xhr_index = m_xhrs.length; - return m_xhrs[xhr_index] = post(m_url, m_header, request, - m_proxy, m_proxyUsername, m_proxyPassword, - m_timeout, m_filter, function(response) { - try { - var result = getResult(response, func, args, resultMode); - } - catch (e) { - if (errorHandler) { - errorHandler(func, e); - } - else { - self.onError(func, e); - } - return; - } - callback(result, args); - delete m_xhrs[xhr_index]; - }); - } - else { - var response = post(m_url, m_header, request, - m_proxy, m_proxyUsername, m_proxyPassword, - m_timeout, m_filter); - return getResult(response, func, args, resultMode); - } - } - /* constructor */ { - if (typeof(url) == "string") { - this.useService(url, functions); - } - } - } - HproseHttpClient.create = function(url, functions) { - return new HproseHttpClient(url, functions, true); - } - HproseHttpClient.keepSession = function() { - s_keepSession = true; - if (Session("HPROSE_COOKIE_MANAGER")) { - s_cookieManager = Session("HPROSE_COOKIE_MANAGER"); - } - } - return HproseHttpClient; +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * hproseHttpClient.js * + * * + * hprose http client for ASP. * + * * + * LastModified: Nov 27, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +var HproseHttpClient = (function () { + /* Reference of global Class */ + var r_HproseResultMode = HproseResultMode; + var r_HproseException = HproseException; + var r_HproseFilter = HproseFilter; + var r_HproseStringInputStream = HproseStringInputStream; + var r_HproseStringOutputStream = HproseStringOutputStream; + var r_HproseReader = HproseReader; + var r_HproseWriter = HproseWriter; + var r_HproseTags = HproseTags; + var r_HproseFormatter = HproseFormatter; + + /* static private members */ + var s_keepSession = false; + + var s_cookieManager = {}; + + var s_XMLHttpNameCache = null; + + function createXMLHttp() { + if (s_XMLHttpNameCache != null) { + // Use the cache name first. + return new ActiveXObject(s_XMLHttpNameCache); + } + else { + var MSXML = ['MSXML2.ServerXMLHTTP.6.0', + 'MSXML2.ServerXMLHTTP.5.0', + 'MSXML2.ServerXMLHTTP.4.0', + 'MSXML2.ServerXMLHTTP.3.0', + 'MSXML2.ServerXMLHTTP']; + var n = MSXML.length; + var objXMLHttp; + for(var i = 0; i < n; i++) { + try { + objXMLHttp = new ActiveXObject(MSXML[i]); + // Cache the XMLHttp ActiveX object name. + s_XMLHttpNameCache = MSXML[i]; + return objXMLHttp; + } + catch(e) {} + } + return null; + } + } + + function setCookie(headers, host) { + for (var i = 0; i < headers.length; i++) { + var header = headers[i].split(':', 2); + var name = header[0].toLowerCase(); + var value = header[1]; + if ((name == 'set-cookie') || (name == 'set-cookie2')) { + var cookies = value.replace(/(^\s*)|(\s*$)/g, "").split(';'); + var cookie = {}; + value = cookies[0].replace(/(^\s*)|(\s*$)/g, "").split('=', 2); + if (value[1] === undefined) value[1] = null; + cookie['name'] = value[0]; + cookie['value'] = value[1]; + for (var j = 1; j < cookies.length; j++) { + value = cookies[j].replace(/(^\s*)|(\s*$)/g, "").split('=', 2); + if (value[1] === undefined) value[1] = null; + cookie[value[0].toUpperCase()] = value[1]; + } + // Tomcat can return SetCookie2 with path wrapped in " + if (cookie['PATH']) { + if (cookie['PATH'].charAt(0) == '"') { + cookie['PATH'] = cookie['PATH'].substr(1); + } + if (cookie['PATH'].charAt(cookie['PATH'].length - 1) == '"') { + cookie['PATH'] = cookie['PATH'].substr(0, cookie['PATH'].length - 1); + } + } + else { + cookie['PATH'] = '/' + } + if (cookie['EXPIRES']) { + cookie['EXPIRES'] = Date.parse(cookie['EXPIRES']); + } + if (cookie['DOMAIN']) { + cookie['DOMAIN'] = cookie['DOMAIN'].toLowerCase(); + } + else { + cookie['DOMAIN'] = host; + } + cookie['SECURE'] = (cookie['SECURE'] !== undefined); + if (s_cookieManager[cookie['DOMAIN']] === undefined) { + s_cookieManager[cookie['DOMAIN']] = {}; + } + s_cookieManager[cookie['DOMAIN']][cookie['name']] = cookie; + if (s_keepSession) { + Session("HPROSE_COOKIE_MANAGER") = s_cookieManager; + } + } + } + } + + function getCookie(host, path, secure) { + var cookies = []; + for (var domain in s_cookieManager) { + if (host.indexOf(domain) > -1) { + var names = []; + for (var name in s_cookieManager[domain]) { + var cookie = s_cookieManager[domain][name]; + if (cookie['EXPIRES'] && ((new Date()).getTime() > cookie['EXPIRES'])) { + names.push(name); + } + else if (path.indexOf(cookie['PATH']) === 0) { + if (((secure && cookie['SECURE']) || + !cookie['SECURE']) && (cookie['value'] !== null)) { + cookies.push(cookie['name'] + '=' + cookie['value']); + } + } + } + for (var i in names) { + delete s_cookieManager[domain][names[i]]; + } + } + } + if (cookies.length > 0) { + return cookies.join('; '); + } + return ''; + } + + function getResponse(xmlhttp, host, filter) { + if (xmlhttp.status == 200) { + var headers = xmlhttp.getAllResponseHeaders().split("\r\n"); + setCookie(headers, host); + return filter.intputFilter(xmlhttp.responseText); + } + else { + var error = xmlhttp.status + ':' + xmlhttp.statusText; + return r_HproseTags.TagError + + r_HproseFormatter.serialize(error) + + r_HproseTags.TagEnd; + } + } + + function post(url, header, data, proxy, proxyUsername, proxyPassword, timeout, filter, callback) { + var host, path, secure, p; + if (url.substr(0, 7).toLowerCase() == 'http://') { + secure = false; + p = 7; + } + else if (url.substr(0, 8).toLowerCase() == 'https://') { + secure = true; + p = 8; + } + if (p > 0) { + host = url.substring(p, url.indexOf('/', p)); + var m = host.match(/^([^:]*):([^@]*)@(.*)$/); + if (m != null) { + host = m[3]; + } + path = url.substr(url.indexOf('/', p)); + } + else { + throw new r_HproseException('Url must be an absolute path.'); + } + var xmlhttp = createXMLHttp(); + xmlhttp.setTimeouts(timeout, timeout, timeout, timeout); + if (proxy) { + try { + xmlhttp.setProxy(2, proxy); + if (proxyUsername) { + xmlhttp.setProxyCredentials(proxyUsername, proxyPassword); + } + } + catch(e) {} + } + if (callback) { + xmlhttp.open('POST', url, true); + xmlhttp.onreadystatechange = function() { + if (xmlhttp.readyState == 4) { + callback(getResponse(xmlhttp, host, filter)); + } + } + } + else { + xmlhttp.open('POST', url, false); + } + for (var name in header) { + xmlhttp.setRequestHeader(name, header[name]); + } + var cookie = getCookie(host, path, secure); + if (cookie != '') { + xmlhttp.setRequestHeader('Cookie', cookie); + } + xmlhttp.send(filter.outputFilter(data)); + if (callback) { + return xmlhttp; + } + else { + return getResponse(xmlhttp, host, filter); + } + } + + function HproseHttpClient(url, functions, vbs) { + // private members + var m_header = {'Content-Type': 'application/hprose; charset=utf-8'}; + var m_url; + var m_proxy; + var m_proxyUsername; + var m_proxyPassword; + var m_timeout = 30000; + var m_byref = false; + var m_xhrs = []; + var m_filter = new r_HproseFilter(); + var self = this; + // public methods + this.useService = function(url, functions, create) { + if (typeof(functions) == 'boolean' && create === undefined) { + create = functions; + } + var serviceProxy = this; + if (create) { + serviceProxy = {}; + } + if (url === undefined) { + return new r_HproseException("You should set server url first!"); + } + m_url = url; + if (typeof(functions) == 'string' || + (functions && functions.constructor == Object)) { + functions = [functions]; + } + if (Object.prototype.toString.apply(functions) === '[object Array]') { + setFunctions.call(serviceProxy, functions); + } + else { + useService.apply(serviceProxy); + } + return serviceProxy; + } + + this.invoke = function() { + var args = arguments; + var func = Array.prototype.shift.apply(args); + return invoke.call(this, func, args); + } + + this.setHeader = function(name, value) { + var lname = name.toLowerCase(); + if (lname != 'content-type' && + lname != 'content-length' && + lname != 'host') { + if (value) { + m_header[name] = value; + } + else { + delete m_header[name]; + } + } + } + + this.setProxy = function(host, port, username, password) { + if (!host) { + m_proxy = null; + } + else if (port === undefined) { + var p1 = 0; + if (host.substr(0, 7).toLowerCase() == 'http://') { + p1 = 7; + } + else if (host.substr(0, 6).toLowerCase() == 'tcp://') { + p1 = 6; + } + var p2 = host.indexOf('/', p1); + if (p2 > 0) { + host = host.substring(p1, p2); + var m = host.match(/^([^:]*):([^@]*)@(.*)$/); + if (m != null) { + m_proxyUsername = decodeURIComponent(m[1]); + m_proxyPassword = decodeURIComponent(m[2]); + host = m[3]; + } + } + m_proxy = host; + } + else { + m_proxy = host + ":" + port; + if (username !== undefined && password !== undefined) { + m_proxyUsername = username; + m_proxyPassword = password; + } + } + } + + this.setTimeout = function(value) { + m_timeout = value; + } + + this.getTimeout = function() { + return m_timeout; + } + + this.getByRef = function() { + return m_byref; + } + + this.setByRef = function(value) { + if (value === undefined) value = true; + m_byref = value; + } + + this.setFilter = function(filter) { + m_filter = filter; + } + + // events + this.onError = function(name, error) { + // your code for asynchronous invoke + } + + this.waitForResponse = function(timeout) { + for (var i = 0, l = m_xhrs.length; i < l; i++) { + if (m_xhrs[i]) { + var xhr = m_xhrs[i]; + if (timeout === undefined) { + xhr.waitForResponse(); + } + else { + if (timeout < 0) return; + var s = new Date(); + xhr.waitForResponse(timeout / 1000); + var e = new Date(); + timeout -= e.getTime() - s.getTime(); + } + } + } + } + + // private methods + function useService() { + var response = post(m_url, m_header, r_HproseTags.TagEnd, + m_proxy, m_proxyUsername, m_proxyPassword, + m_timeout, m_filter); + var stream = new r_HproseStringInputStream(response); + var hproseReader = new r_HproseReader(stream); + var tag = hproseReader.checkTags([r_HproseTags.TagFunctions, + r_HproseTags.TagError]); + switch (tag) { + case r_HproseTags.TagFunctions: + var functions = hproseReader.readList(); + hproseReader.checkTag(r_HproseTags.TagEnd); + setFunctions.call(this, functions); + break; + case r_HproseTags.TagError: + throw new r_HproseException(hproseReader.readString()); + break; + } + } + + function setFunction(func) { + var serverProxy = this; + return function() { + return invoke.call(serverProxy, func, arguments); + } + } + + function setMethods(obj, namespace, name, methods) { + if (obj[name] !== undefined) return; + obj[name] = {}; + if (typeof(methods) == 'string' || methods.constructor == Object) { + methods = [methods] + } + if (Object.prototype.toString.apply(methods) === '[object Array]') { + for (var i = 0; i < methods.length; i++) { + var m = methods[i]; + if (typeof(m) == 'string') { + obj[name][m] = setFunction.call(this, namespace + name + '_' + m); + } + else { + for (var n in m) { + setMethods.call(this, obj[name], name + '_', n, m[n]); + } + } + } + } + } + + function setFunctions(functions) { + for (var i = 0; i < functions.length; i++) { + var f = functions[i]; + if (typeof(f) == 'string') { + if (this[f] === undefined) { + this[f] = setFunction(f); + } + } + else { + for (var name in f) { + setMethods.call(this, this, '', name, f[name]); + } + } + } + } + + function getResult(response, func, args, resultMode) { + var result = null; + if (resultMode == r_HproseResultMode.RawWithEndTag) { + result = response; + } + else if (resultMode == r_HproseResultMode.Raw) { + result = response.substr(0, response.length - 1); + } + else { + var stream = new r_HproseStringInputStream(response); + var hproseReader = new r_HproseReader(stream, vbs); + var tag; + var error = null; + while ((tag = hproseReader.checkTags( + [r_HproseTags.TagResult, + r_HproseTags.TagArgument, + r_HproseTags.TagError, + r_HproseTags.TagEnd])) !== r_HproseTags.TagEnd) { + switch (tag) { + case r_HproseTags.TagResult: + if (resultMode == r_HproseResultMode.Serialized) { + result = hproseReader.readRaw().toString(); + } + else { + result = hproseReader.unserialize(); + } + break; + case r_HproseTags.TagArgument: + hproseReader.reset(); + var a = hproseReader.readList(); + for (var i = 0; i < a.length; i++) { + args[i] = a[i]; + } + break; + case r_HproseTags.TagError: + hproseReader.reset(); + error = new r_HproseException(hproseReader.readString()); + break; + } + } + if (error != null) throw error; + } + return result; + } + + function invoke(func, args) { + var resultMode = r_HproseResultMode.Normal; + var byref = m_byref; + var lowerCaseFunc = func.toLowerCase(); + var errorHandler = this[func + '_OnError'] || + this[func + '_onError'] || + this[func + '_onerror'] || + this[lowerCaseFunc + '_OnError'] || + this[lowerCaseFunc + '_onError'] || + this[lowerCaseFunc + '_onerror'] || + self[func + '_OnError'] || + self[func + '_onError'] || + self[func + '_onerror'] || + self[lowerCaseFunc + '_OnError'] || + self[lowerCaseFunc + '_onError'] || + self[lowerCaseFunc + '_onerror']; + var callback = this[func + '_Callback'] || + this[func + '_callback'] || + this[func + '_OnSuccess'] || + this[func + '_onSuccess'] || + this[func + '_onsuccess'] || + this[lowerCaseFunc + '_Callback'] || + this[lowerCaseFunc + '_callback'] || + this[lowerCaseFunc + '_OnSuccess'] || + this[lowerCaseFunc + '_onSuccess'] || + this[lowerCaseFunc + '_onsuccess'] || + self[func + '_Callback'] || + self[func + '_callback'] || + self[func + '_OnSuccess'] || + self[func + '_onSuccess'] || + self[func + '_onsuccess'] || + self[lowerCaseFunc + '_Callback'] || + self[lowerCaseFunc + '_callback'] || + self[lowerCaseFunc + '_OnSuccess'] || + self[lowerCaseFunc + '_onSuccess'] || + self[lowerCaseFunc + '_onsuccess']; + var count = args.length; + if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'boolean' && + typeof(args[count - 3]) == 'function' && + typeof(args[count - 4]) == 'function') { + resultMode = args[count - 1]; + byref = args[count - 2]; + errorHandler = args[count - 3]; + callback = args[count - 4]; + delete args[count - 1]; + delete args[count - 2]; + delete args[count - 3]; + delete args[count - 4]; + args.length -= 4; + } + else if (typeof(args[count - 1]) == 'boolean' && + typeof(args[count - 2]) == 'function' && + typeof(args[count - 3]) == 'function') { + byref = args[count - 1]; + errorHandler = args[count - 2]; + callback = args[count - 3]; + delete args[count - 1]; + delete args[count - 2]; + delete args[count - 3]; + args.length -= 3; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'function' && + typeof(args[count - 3]) == 'function') { + resultMode = args[count - 1]; + errorHandler = args[count - 2]; + callback = args[count - 3]; + delete args[count - 1]; + delete args[count - 2]; + delete args[count - 3]; + args.length -= 3; + } + else if (typeof(args[count - 1]) == 'function' && + typeof(args[count - 2]) == 'function') { + errorHandler = args[count - 1]; + callback = args[count - 2]; + delete args[count - 1]; + delete args[count - 2]; + args.length -= 2; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'boolean' && + typeof(args[count - 3]) == 'function') { + resultMode = args[count - 1]; + byref = args[count - 2]; + callback = args[count - 3]; + delete args[count - 1]; + delete args[count - 2]; + delete args[count - 3]; + args.length -= 3; + } + else if (typeof(args[count - 1]) == 'boolean' && + typeof(args[count - 2]) == 'function') { + byref = args[count - 1]; + callback = args[count - 2]; + delete args[count - 1]; + delete args[count - 2]; + args.length -= 2; + } + else if (typeof(args[count - 1]) == 'number' && + typeof(args[count - 2]) == 'function') { + resultMode = args[count - 1]; + callback = args[count - 2]; + delete args[count - 1]; + delete args[count - 2]; + args.length -= 2; + } + else if (typeof(args[count - 1]) == 'function') { + callback = args[count - 1]; + delete args[count - 1]; + args.length--; + } + var stream = new r_HproseStringOutputStream(r_HproseTags.TagCall); + var hproseWriter = new r_HproseWriter(stream); + hproseWriter.writeString(func, false); + if (args.length > 0 || byref) { + hproseWriter.reset(); + hproseWriter.writeList(args, false); + if (byref) { + hproseWriter.writeBoolean(true); + } + } + stream.write(r_HproseTags.TagEnd); + var request = stream.toString(); + if (callback) { + var xhr_index = m_xhrs.length; + return m_xhrs[xhr_index] = post(m_url, m_header, request, + m_proxy, m_proxyUsername, m_proxyPassword, + m_timeout, m_filter, function(response) { + try { + var result = getResult(response, func, args, resultMode); + } + catch (e) { + if (errorHandler) { + errorHandler(func, e); + } + else { + self.onError(func, e); + } + return; + } + callback(result, args); + delete m_xhrs[xhr_index]; + }); + } + else { + var response = post(m_url, m_header, request, + m_proxy, m_proxyUsername, m_proxyPassword, + m_timeout, m_filter); + return getResult(response, func, args, resultMode); + } + } + /* constructor */ { + if (typeof(url) == "string") { + this.useService(url, functions); + } + } + } + HproseHttpClient.create = function(url, functions) { + return new HproseHttpClient(url, functions, true); + } + HproseHttpClient.keepSession = function() { + s_keepSession = true; + if (Session("HPROSE_COOKIE_MANAGER")) { + s_cookieManager = Session("HPROSE_COOKIE_MANAGER"); + } + } + return HproseHttpClient; })(); \ No newline at end of file diff --git a/src/asp/jscript/hproseHttpServer.js b/src/asp/jscript/hproseHttpServer.js index 90af4af..9258c05 100644 --- a/src/asp/jscript/hproseHttpServer.js +++ b/src/asp/jscript/hproseHttpServer.js @@ -1,444 +1,444 @@ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ - -/**********************************************************\ - * * - * hproseHttpServer.js * - * * - * hprose http server library for ASP. * - * * - * LastModified: Oct 28, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ - -var HproseHttpServer = (function() { - function callService(method, obj, context, args) { - var result; - if (typeof(method) == "function") { - result = method.apply(context, args); - } - else if (obj && typeof(obj[method]) == "function") { - result = obj[method].apply(context, args); - } - else { - var a = []; - for (var i = 0, n = args.length; i < n; i++) { - a[i] = 'args[' + i + ']'; - } - if (obj == null) { - if (typeof(method) == "string") { - result = eval(method + "(" + a.join(', ') + ")"); - } - else { - result = eval("method(" + a.join(', ') + ")"); - } - } - else { - result = eval("obj[method](" + a.join(', ') + ")"); - } - } - return result; - } - return (function() { - /* Reference of global Class */ - var r_HproseResultMode = HproseResultMode; - var r_HproseException = HproseException; - var r_HproseUtil = HproseUtil; - var r_HproseStringInputStream = HproseStringInputStream; - var r_HproseStringOutputStream = HproseStringOutputStream; - var r_HproseReader = HproseReader; - var r_HproseWriter = HproseWriter; - var r_HproseTags = HproseTags; - var r_HproseFormatter = HproseFormatter; - var prototypePropertyOfArray = function() { - var result = {}; - for (var p in []) { - result[p] = true; - } - return result; - }(); - var prototypePropertyOfObject = function() { - var result = {}; - for (var p in {}) { - result[p] = true; - } - return result; - }(); - - function arrayValues(obj) { - var result = []; - for (var key in obj) { - if (!prototypePropertyOfObject[key] && - !prototypePropertyOfArray[key]) { - result[result.length] = obj[key]; - } - } - return result; - } - - function getRefName(ref) { - for (var name in ref) return name; - } - - function getFuncName(func) { - var f = func.toString(); - return f.substr(0, f.indexOf('(')).replace(/(^\s*function\s*)|(\s*$)/ig, ''); - } - - function HproseHttpServer(vbs) { - var m_functions = {}; - var m_funcNames = {}; - var m_resultMode = {}; - var m_debug = false; - var m_crossDomain = false; - var m_P3P = false; - var m_get = true; - var m_filter = null; - var m_input; - var m_output; - var m_reader; - var m_writer; - this.onBeforeInvoke = null; - this.onAfterInvoke = null; - this.onSendHeader = null; - this.onSendError = null; - - function constructor() { - var count = Request.totalBytes; - var bytes = Request.binaryRead(count); - var str = ""; - if (count > 0) { - str = r_HproseUtil.binaryToString(bytes); - } - Session.CodePage = 65001; - Response.CodePage = 65001; - Response.Buffer = true; - if (m_filter) { - str = m_filter.inputFilter(str); - } - m_input = new r_HproseStringInputStream(str); - m_reader = new r_HproseReader(m_input, vbs); - if (m_filter) { - m_output = r_HproseStringOutputStream(); - } - else { - m_output = Response; - } - m_writer = new r_HproseWriter(m_output); - } - - function sendHeader() { - if (this.onSendHeader != null) { - this.onSendHeader(); - } - Response.addHeader('Content-Type', "text/plain"); - if (m_P3P) { - Response.addHeader('P3P', - 'CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi ' + - 'CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL ' + - 'UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"'); - } - if (m_crossDomain) { - var origin = Request.ServerVariables("HTTP_ORIGIN"); - if (origin && origin != "null") { - Response.addHeader('Access-Control-Allow-Origin', origin); - Response.addHeader('Access-Control-Allow-Credentials', 'true'); - } - else { - Response.addHeader('Access-Control-Allow-Origin', '*'); - } - } - } - - function sendError(error) { - if (this.onSendError != null) { - this.onSendError(error); - } - m_output.clear(); - m_writer.reset(); - m_output.write(r_HproseTags.TagError); - m_writer.writeString(error, false); - m_output.write(r_HproseTags.TagEnd); - } - - function doInvoke() { - do { - m_reader.reset(); - var functionName = m_reader.readString(); - var aliasName = functionName.toLowerCase(); - var functionArgs = []; - var byref = false; - var tag = m_reader.checkTags([r_HproseTags.TagList, - r_HproseTags.TagEnd, - r_HproseTags.TagCall]); - if (tag == r_HproseTags.TagList) { - m_reader.reset(); - functionArgs = m_reader.readList(false); - if (vbs) functionArgs = r_HproseUtil.toJSArray(functionArgs); - tag = m_reader.checkTags([r_HproseTags.TagTrue, - r_HproseTags.TagEnd, - r_HproseTags.TagCall]); - if (tag == r_HproseTags.TagTrue) { - byref = true; - tag = m_reader.checkTags([r_HproseTags.TagEnd, - r_HproseTags.TagCall]); - } - } - if (this.onBeforeInvoke != null) { - this.onBeforeInvoke(functionName, functionArgs, byref); - } - var func, resultMode, result; - if (func = m_functions[aliasName]) { - resultMode = m_resultMode[aliasName]; - result = callService(func.method, func.obj, func.context, functionArgs); - } - else if (func = m_functions['*']) { - resultMode = m_resultMode['*']; - var args = [functionName, functionArgs]; - result = callService(func.method, func.obj, func.context, args); - } - else { - throw new r_HproseException("Can't find this function " + functionName + "()."); - } - if (this.onAfterInvoke != null) { - this.onAfterInvoke(functionName, functionArgs, byref, result); - } - if (resultMode == r_HproseResultMode.RawWithEndTag) { - m_output.write(result); - return; - } - else if (resultMode == r_HproseResultMode.Raw) { - m_output.write(result); - } - else { - m_output.write(r_HproseTags.TagResult); - if (resultMode == r_HproseResultMode.Serialized) { - m_output.write(result); - } - else { - m_writer.reset(); - m_writer.serialize(result); - } - if (byref) { - m_output.write(r_HproseTags.TagArgument); - m_writer.reset(); - m_writer.writeList(functionArgs, false); - } - } - } while (tag == r_HproseTags.TagCall); - m_output.write(r_HproseTags.TagEnd); - } - - function doFunctionList() { - var functions = arrayValues(m_funcNames); - m_output.write(r_HproseTags.TagFunctions); - m_writer.writeList(functions, false); - m_output.write(r_HproseTags.TagEnd); - } - - function handle() { - try { - var exceptTags = [r_HproseTags.TagCall, r_HproseTags.TagEnd]; - var tag = m_reader.checkTags(exceptTags); - switch (tag) { - case r_HproseTags.TagCall: doInvoke.apply(this); break; - case r_HproseTags.TagEnd: doFunctionList(); break; - } - } - catch (e) { - sendError.call(this, e.description); - } - } - - this.addMissingFunction = function(func, resultMode) { - this.addFunction(func, "*", resultMode); - } - - this.addMissingMethod = function(method, obj, context, resultMode) { - this.addMethod(method, obj, "*", context, resultMode); - } - - this.addFunction = function(func, alias, resultMode) { - if (resultMode === undefined) { - resultMode = r_HproseResultMode.Normal; - } - if (alias === undefined || alias == null) { - switch(typeof(func)) { - case "string": - alias = func; - break; - case "object": - alias = getRefName(func); - break; - case "function": - alias = getFuncName(func); - if (alias != "") break; - default: - throw new r_HproseException('Need an alias'); - } - } - if (typeof(alias) == "string") { - var aliasName = alias.toLowerCase(); - m_functions[aliasName] = {method: func, obj: null, context: null}; - m_funcNames[aliasName] = alias; - m_resultMode[aliasName] = resultMode; - } - else { - throw new r_HproseException('Argument alias is not a string'); - } - } - - this.addFunctions = function(functions, aliases, resultMode) { - if (r_HproseUtil.isVBArray(functions)) { - functions = r_HproseUtil.toJSArray(functions); - } - var count = functions.length; - var i; - if (aliases === undefined || aliases == null) { - for (i = 0; i < count; i++) this.addFunction(functions[i], null, resultMode); - return; - } - else if (r_HproseUtil.isVBArray(aliases)) { - aliases = r_HproseUtil.toJSArray(aliases); - } - if (count != aliases.length) { - throw new r_HproseException('The count of functions is not matched with aliases'); - } - for (i = 0; i < count; i++) this.addFunction(functions[i], aliases[i], resultMode); - } - - this.addMethod = function(method, obj, alias, context, resultMode) { - if (obj === undefined || obj == null) { - this.addFunction(method, alias, resultMode); - return; - } - if (context === undefined) { - context = obj; - } - if (resultMode === undefined) { - resultMode = r_HproseResultMode.Normal; - } - if (alias === undefined || alias == null) { - switch(typeof(method)) { - case "string": - alias = method; - break; - case "object": - alias = getRefName(method); - break; - case "function": - alias = getFuncName(method); - if (alias != "") break; - default: - throw new r_HproseException('Need an alias'); - } - } - if (typeof(alias) == "string") { - var aliasName = alias.toLowerCase(); - m_functions[aliasName] = {method: method, obj: obj, context: context}; - m_funcNames[aliasName] = alias; - m_resultMode[aliasName] = resultMode; - } - else { - throw new r_HproseException('Argument alias is not a string'); - } - } - - this.addMethods = function(methods, obj, aliases, context, resultMode) { - if (r_HproseUtil.isVBArray(methods)) { - methods = r_HproseUtil.toJSArray(methods); - } - var count = methods.length; - var i; - if (aliases === undefined || aliases == null) { - for (i = 0; i < count; i++) { - this.addMethod(methods[i], obj, null, context, resultMode); - } - return; - } - else if (r_HproseUtil.isVBArray(aliases)) { - aliases = r_HproseUtil.toJSArray(aliases); - } - if (count != aliases.length) { - throw new r_HproseException('The count of methods is not matched with aliases'); - } - for (i = 0; i < count; i++) { - this.addMethod(methods[i], obj, aliases[i], context, resultMode); - } - } - - this.addInstanceMethods = function(obj, aliasPrefix, context, resultMode) { - var alias; - for (var name in obj) { - if (!prototypePropertyOfObject[name] && - !prototypePropertyOfArray[name]) { - alias = (aliasPrefix ? aliasPrefix + "_" + name : name); - if (typeof(obj[name]) == 'function') { - this.addMethod(obj[name], obj, alias, context, resultMode); - } - else if (typeof(obj[name]) == 'unknown') { - this.addFunction(obj[name], alias, resultMode); - } - } - } - } - - this.isDebugEnabled = function() { - return m_debug; - } - this.setDebugEnabled = function(enable) { - if (enable === undefined) enable = true; - m_debug = enable; - } - this.isCrossDomainEnabled = function() { - return m_crossDomain; - } - this.setCrossDomainEnabled = function(enable) { - if (enable === undefined) enable = true; - m_crossDomain = enable; - } - this.isP3PEnabled = function() { - return m_P3P; - } - this.setP3PEnabled = function(enable) { - if (enable === undefined) enable = true; - m_P3P = enable; - } - this.isGetEnabled = function() { - return m_get; - } - this.setGetEnabled = function(enable) { - if (enable === undefined) enable = true; - m_get = enable; - } - this.handle = function() { - Response.clear(); - sendHeader.apply(this); - if ((Request.ServerVariables("REQUEST_METHOD") == 'GET') && m_get) { - doFunctionList(); - } - else if (Request.ServerVariables("REQUEST_METHOD") == 'POST') { - handle.apply(this); - } - if (m_filter) { - Response.write(m_filter.outputFilter(m_output.toString())); - } - Response.end(); - } - this.start = this.handle; - constructor(); - } - HproseHttpServer.create = function() { - return new HproseHttpServer(true); - } - return HproseHttpServer; - })(); +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * hproseHttpServer.js * + * * + * hprose http server library for ASP. * + * * + * LastModified: Oct 28, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ + +var HproseHttpServer = (function() { + function callService(method, obj, context, args) { + var result; + if (typeof(method) == "function") { + result = method.apply(context, args); + } + else if (obj && typeof(obj[method]) == "function") { + result = obj[method].apply(context, args); + } + else { + var a = []; + for (var i = 0, n = args.length; i < n; i++) { + a[i] = 'args[' + i + ']'; + } + if (obj == null) { + if (typeof(method) == "string") { + result = eval(method + "(" + a.join(', ') + ")"); + } + else { + result = eval("method(" + a.join(', ') + ")"); + } + } + else { + result = eval("obj[method](" + a.join(', ') + ")"); + } + } + return result; + } + return (function() { + /* Reference of global Class */ + var r_HproseResultMode = HproseResultMode; + var r_HproseException = HproseException; + var r_HproseUtil = HproseUtil; + var r_HproseStringInputStream = HproseStringInputStream; + var r_HproseStringOutputStream = HproseStringOutputStream; + var r_HproseReader = HproseReader; + var r_HproseWriter = HproseWriter; + var r_HproseTags = HproseTags; + var r_HproseFormatter = HproseFormatter; + var prototypePropertyOfArray = function() { + var result = {}; + for (var p in []) { + result[p] = true; + } + return result; + }(); + var prototypePropertyOfObject = function() { + var result = {}; + for (var p in {}) { + result[p] = true; + } + return result; + }(); + + function arrayValues(obj) { + var result = []; + for (var key in obj) { + if (!prototypePropertyOfObject[key] && + !prototypePropertyOfArray[key]) { + result[result.length] = obj[key]; + } + } + return result; + } + + function getRefName(ref) { + for (var name in ref) return name; + } + + function getFuncName(func) { + var f = func.toString(); + return f.substr(0, f.indexOf('(')).replace(/(^\s*function\s*)|(\s*$)/ig, ''); + } + + function HproseHttpServer(vbs) { + var m_functions = {}; + var m_funcNames = {}; + var m_resultMode = {}; + var m_debug = false; + var m_crossDomain = false; + var m_P3P = false; + var m_get = true; + var m_filter = null; + var m_input; + var m_output; + var m_reader; + var m_writer; + this.onBeforeInvoke = null; + this.onAfterInvoke = null; + this.onSendHeader = null; + this.onSendError = null; + + function constructor() { + var count = Request.totalBytes; + var bytes = Request.binaryRead(count); + var str = ""; + if (count > 0) { + str = r_HproseUtil.binaryToString(bytes); + } + Session.CodePage = 65001; + Response.CodePage = 65001; + Response.Buffer = true; + if (m_filter) { + str = m_filter.inputFilter(str); + } + m_input = new r_HproseStringInputStream(str); + m_reader = new r_HproseReader(m_input, vbs); + if (m_filter) { + m_output = r_HproseStringOutputStream(); + } + else { + m_output = Response; + } + m_writer = new r_HproseWriter(m_output); + } + + function sendHeader() { + if (this.onSendHeader != null) { + this.onSendHeader(); + } + Response.addHeader('Content-Type', "text/plain"); + if (m_P3P) { + Response.addHeader('P3P', + 'CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi ' + + 'CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL ' + + 'UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"'); + } + if (m_crossDomain) { + var origin = Request.ServerVariables("HTTP_ORIGIN"); + if (origin && origin != "null") { + Response.addHeader('Access-Control-Allow-Origin', origin); + Response.addHeader('Access-Control-Allow-Credentials', 'true'); + } + else { + Response.addHeader('Access-Control-Allow-Origin', '*'); + } + } + } + + function sendError(error) { + if (this.onSendError != null) { + this.onSendError(error); + } + m_output.clear(); + m_writer.reset(); + m_output.write(r_HproseTags.TagError); + m_writer.writeString(error, false); + m_output.write(r_HproseTags.TagEnd); + } + + function doInvoke() { + do { + m_reader.reset(); + var functionName = m_reader.readString(); + var aliasName = functionName.toLowerCase(); + var functionArgs = []; + var byref = false; + var tag = m_reader.checkTags([r_HproseTags.TagList, + r_HproseTags.TagEnd, + r_HproseTags.TagCall]); + if (tag == r_HproseTags.TagList) { + m_reader.reset(); + functionArgs = m_reader.readList(false); + if (vbs) functionArgs = r_HproseUtil.toJSArray(functionArgs); + tag = m_reader.checkTags([r_HproseTags.TagTrue, + r_HproseTags.TagEnd, + r_HproseTags.TagCall]); + if (tag == r_HproseTags.TagTrue) { + byref = true; + tag = m_reader.checkTags([r_HproseTags.TagEnd, + r_HproseTags.TagCall]); + } + } + if (this.onBeforeInvoke != null) { + this.onBeforeInvoke(functionName, functionArgs, byref); + } + var func, resultMode, result; + if (func = m_functions[aliasName]) { + resultMode = m_resultMode[aliasName]; + result = callService(func.method, func.obj, func.context, functionArgs); + } + else if (func = m_functions['*']) { + resultMode = m_resultMode['*']; + var args = [functionName, functionArgs]; + result = callService(func.method, func.obj, func.context, args); + } + else { + throw new r_HproseException("Can't find this function " + functionName + "()."); + } + if (this.onAfterInvoke != null) { + this.onAfterInvoke(functionName, functionArgs, byref, result); + } + if (resultMode == r_HproseResultMode.RawWithEndTag) { + m_output.write(result); + return; + } + else if (resultMode == r_HproseResultMode.Raw) { + m_output.write(result); + } + else { + m_output.write(r_HproseTags.TagResult); + if (resultMode == r_HproseResultMode.Serialized) { + m_output.write(result); + } + else { + m_writer.reset(); + m_writer.serialize(result); + } + if (byref) { + m_output.write(r_HproseTags.TagArgument); + m_writer.reset(); + m_writer.writeList(functionArgs, false); + } + } + } while (tag == r_HproseTags.TagCall); + m_output.write(r_HproseTags.TagEnd); + } + + function doFunctionList() { + var functions = arrayValues(m_funcNames); + m_output.write(r_HproseTags.TagFunctions); + m_writer.writeList(functions, false); + m_output.write(r_HproseTags.TagEnd); + } + + function handle() { + try { + var exceptTags = [r_HproseTags.TagCall, r_HproseTags.TagEnd]; + var tag = m_reader.checkTags(exceptTags); + switch (tag) { + case r_HproseTags.TagCall: doInvoke.apply(this); break; + case r_HproseTags.TagEnd: doFunctionList(); break; + } + } + catch (e) { + sendError.call(this, e.description); + } + } + + this.addMissingFunction = function(func, resultMode) { + this.addFunction(func, "*", resultMode); + } + + this.addMissingMethod = function(method, obj, context, resultMode) { + this.addMethod(method, obj, "*", context, resultMode); + } + + this.addFunction = function(func, alias, resultMode) { + if (resultMode === undefined) { + resultMode = r_HproseResultMode.Normal; + } + if (alias === undefined || alias == null) { + switch(typeof(func)) { + case "string": + alias = func; + break; + case "object": + alias = getRefName(func); + break; + case "function": + alias = getFuncName(func); + if (alias != "") break; + default: + throw new r_HproseException('Need an alias'); + } + } + if (typeof(alias) == "string") { + var aliasName = alias.toLowerCase(); + m_functions[aliasName] = {method: func, obj: null, context: null}; + m_funcNames[aliasName] = alias; + m_resultMode[aliasName] = resultMode; + } + else { + throw new r_HproseException('Argument alias is not a string'); + } + } + + this.addFunctions = function(functions, aliases, resultMode) { + if (r_HproseUtil.isVBArray(functions)) { + functions = r_HproseUtil.toJSArray(functions); + } + var count = functions.length; + var i; + if (aliases === undefined || aliases == null) { + for (i = 0; i < count; i++) this.addFunction(functions[i], null, resultMode); + return; + } + else if (r_HproseUtil.isVBArray(aliases)) { + aliases = r_HproseUtil.toJSArray(aliases); + } + if (count != aliases.length) { + throw new r_HproseException('The count of functions is not matched with aliases'); + } + for (i = 0; i < count; i++) this.addFunction(functions[i], aliases[i], resultMode); + } + + this.addMethod = function(method, obj, alias, context, resultMode) { + if (obj === undefined || obj == null) { + this.addFunction(method, alias, resultMode); + return; + } + if (context === undefined) { + context = obj; + } + if (resultMode === undefined) { + resultMode = r_HproseResultMode.Normal; + } + if (alias === undefined || alias == null) { + switch(typeof(method)) { + case "string": + alias = method; + break; + case "object": + alias = getRefName(method); + break; + case "function": + alias = getFuncName(method); + if (alias != "") break; + default: + throw new r_HproseException('Need an alias'); + } + } + if (typeof(alias) == "string") { + var aliasName = alias.toLowerCase(); + m_functions[aliasName] = {method: method, obj: obj, context: context}; + m_funcNames[aliasName] = alias; + m_resultMode[aliasName] = resultMode; + } + else { + throw new r_HproseException('Argument alias is not a string'); + } + } + + this.addMethods = function(methods, obj, aliases, context, resultMode) { + if (r_HproseUtil.isVBArray(methods)) { + methods = r_HproseUtil.toJSArray(methods); + } + var count = methods.length; + var i; + if (aliases === undefined || aliases == null) { + for (i = 0; i < count; i++) { + this.addMethod(methods[i], obj, null, context, resultMode); + } + return; + } + else if (r_HproseUtil.isVBArray(aliases)) { + aliases = r_HproseUtil.toJSArray(aliases); + } + if (count != aliases.length) { + throw new r_HproseException('The count of methods is not matched with aliases'); + } + for (i = 0; i < count; i++) { + this.addMethod(methods[i], obj, aliases[i], context, resultMode); + } + } + + this.addInstanceMethods = function(obj, aliasPrefix, context, resultMode) { + var alias; + for (var name in obj) { + if (!prototypePropertyOfObject[name] && + !prototypePropertyOfArray[name]) { + alias = (aliasPrefix ? aliasPrefix + "_" + name : name); + if (typeof(obj[name]) == 'function') { + this.addMethod(obj[name], obj, alias, context, resultMode); + } + else if (typeof(obj[name]) == 'unknown') { + this.addFunction(obj[name], alias, resultMode); + } + } + } + } + + this.isDebugEnabled = function() { + return m_debug; + } + this.setDebugEnabled = function(enable) { + if (enable === undefined) enable = true; + m_debug = enable; + } + this.isCrossDomainEnabled = function() { + return m_crossDomain; + } + this.setCrossDomainEnabled = function(enable) { + if (enable === undefined) enable = true; + m_crossDomain = enable; + } + this.isP3PEnabled = function() { + return m_P3P; + } + this.setP3PEnabled = function(enable) { + if (enable === undefined) enable = true; + m_P3P = enable; + } + this.isGetEnabled = function() { + return m_get; + } + this.setGetEnabled = function(enable) { + if (enable === undefined) enable = true; + m_get = enable; + } + this.handle = function() { + Response.clear(); + sendHeader.apply(this); + if ((Request.ServerVariables("REQUEST_METHOD") == 'GET') && m_get) { + doFunctionList(); + } + else if (Request.ServerVariables("REQUEST_METHOD") == 'POST') { + handle.apply(this); + } + if (m_filter) { + Response.write(m_filter.outputFilter(m_output.toString())); + } + Response.end(); + } + this.start = this.handle; + constructor(); + } + HproseHttpServer.create = function() { + return new HproseHttpServer(true); + } + return HproseHttpServer; + })(); })(); \ No newline at end of file diff --git a/src/delphi/Hprose.inc b/src/delphi/Hprose.inc index a465b30..2241c86 100644 --- a/src/delphi/Hprose.inc +++ b/src/delphi/Hprose.inc @@ -1,117 +1,117 @@ -// Delphi version - -{$ifdef VER140} - {$define DELPHI6} - {$define DELPHI6_UP} -{$endif} - -{$ifdef VER150} - {$define DELPHI7} - {$define DELPHI7_UP} -{$endif} - -{$ifdef VER160} - {$define DELPHI8} - {$define DELPHI8_UP} -{$endif} - -{$ifdef VER170} - {$define DELPHI2005} - {$define DELPHI2005_UP} -{$endif} - -{$ifdef VER180} - {$define DELPHI2006} - {$define DELPHI2006_UP} -{$endif} - -{$ifdef VER185} - {$define DELPHI2007} - {$define DELPHI2007_UP} -{$endif} - -{$ifdef VER200} - {$define DELPHI2009} - {$define DELPHI2009_UP} -{$endif} - -{$ifdef VER210} - {$define DELPHI2010} - {$define DELPHI2010_UP} -{$endif} - -{$ifdef VER220} - {$define DELPHI2011} - {$define DELPHI2011_UP} -{$endif} - -{$ifdef VER230} - {$define DELPHI2012} - {$define DELPHI2012_UP} -{$endif} - -{$ifdef DELPHI2012_UP} - {$define DELPHI2011_UP} -{$endif} - -{$ifdef DELPHI2011_UP} - {$define DELPHI2010_UP} -{$endif} - -{$ifdef DELPHI2010_UP} - {$define DELPHI2009_UP} -{$endif} - -{$ifdef DELPHI2009_UP} - {$define DELPHI2007_UP} -{$endif} - -{$ifdef DELPHI2007_UP} - {$define DELPHI2006_UP} -{$endif} - -{$ifdef DELPHI2006_UP} - {$define DELPHI2005_UP} -{$endif} - -{$ifdef DELPHI2005_UP} - {$define DELPHI8_UP} -{$endif} - -{$ifdef DELPHI8_UP} - {$define DELPHI7_UP} -{$endif} - -{$ifdef DELPHI7_UP} - {$define DELPHI6_UP} -{$endif} - -// Delphi features - -{$ifdef DELPHI2005_UP} - {$define Supports_For_In} - {$define Supports_Inline} - {$define Supports_Nested_Constants} - {$define Supports_Nested_Types} -{$endif} - -{$ifdef DELPHI2006_UP} - {$define Supports_Static} -{$endif} - -{$ifdef DELPHI2009_UP} - {$define Supports_Unicode} - {$define Supports_Generics} -{$endif} - -// Free Pascal - -{$ifdef FPC} - {$mode DELPHI} -{$endif} - -{$ifdef CPUX64} - {$define CPU64} -{$endif} - -{$H+} +// Delphi version + +{$ifdef VER140} + {$define DELPHI6} + {$define DELPHI6_UP} +{$endif} + +{$ifdef VER150} + {$define DELPHI7} + {$define DELPHI7_UP} +{$endif} + +{$ifdef VER160} + {$define DELPHI8} + {$define DELPHI8_UP} +{$endif} + +{$ifdef VER170} + {$define DELPHI2005} + {$define DELPHI2005_UP} +{$endif} + +{$ifdef VER180} + {$define DELPHI2006} + {$define DELPHI2006_UP} +{$endif} + +{$ifdef VER185} + {$define DELPHI2007} + {$define DELPHI2007_UP} +{$endif} + +{$ifdef VER200} + {$define DELPHI2009} + {$define DELPHI2009_UP} +{$endif} + +{$ifdef VER210} + {$define DELPHI2010} + {$define DELPHI2010_UP} +{$endif} + +{$ifdef VER220} + {$define DELPHI2011} + {$define DELPHI2011_UP} +{$endif} + +{$ifdef VER230} + {$define DELPHI2012} + {$define DELPHI2012_UP} +{$endif} + +{$ifdef DELPHI2012_UP} + {$define DELPHI2011_UP} +{$endif} + +{$ifdef DELPHI2011_UP} + {$define DELPHI2010_UP} +{$endif} + +{$ifdef DELPHI2010_UP} + {$define DELPHI2009_UP} +{$endif} + +{$ifdef DELPHI2009_UP} + {$define DELPHI2007_UP} +{$endif} + +{$ifdef DELPHI2007_UP} + {$define DELPHI2006_UP} +{$endif} + +{$ifdef DELPHI2006_UP} + {$define DELPHI2005_UP} +{$endif} + +{$ifdef DELPHI2005_UP} + {$define DELPHI8_UP} +{$endif} + +{$ifdef DELPHI8_UP} + {$define DELPHI7_UP} +{$endif} + +{$ifdef DELPHI7_UP} + {$define DELPHI6_UP} +{$endif} + +// Delphi features + +{$ifdef DELPHI2005_UP} + {$define Supports_For_In} + {$define Supports_Inline} + {$define Supports_Nested_Constants} + {$define Supports_Nested_Types} +{$endif} + +{$ifdef DELPHI2006_UP} + {$define Supports_Static} +{$endif} + +{$ifdef DELPHI2009_UP} + {$define Supports_Unicode} + {$define Supports_Generics} +{$endif} + +// Free Pascal + +{$ifdef FPC} + {$mode DELPHI} +{$endif} + +{$ifdef CPUX64} + {$define CPU64} +{$endif} + +{$H+} diff --git a/src/delphi/HproseClient.pas b/src/delphi/HproseClient.pas index 60e4541..a27a7a2 100644 --- a/src/delphi/HproseClient.pas +++ b/src/delphi/HproseClient.pas @@ -1,776 +1,776 @@ -{ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ - -/**********************************************************\ - * * - * HproseClient.pas * - * * - * hprose client unit for delphi. * - * * - * LastModified: Nov 27, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -} -unit HproseClient; - -{$I Hprose.inc} - -interface - -uses HproseCommon, Classes, SysUtils; - -type - - THproseCallback1 = procedure(Result: Variant) of object; - THproseCallback2 = procedure(Result: Variant; - const Args: TVariants) of object; - - THproseErrorEvent = procedure(const Name:string; - const Error: Exception) of object; - - THproseClient = class(TComponent) - private - FErrorEvent: THproseErrorEvent; - FFilter: IHproseFilter; - protected - FUri: string; - function GetInvokeContext: TObject; virtual; abstract; - function GetOutputStream(var Context: TObject): TStream; virtual; abstract; - procedure SendData(var Context: TObject); virtual; abstract; - function GetInputStream(var Context: TObject): TStream; virtual; abstract; - procedure EndInvoke(var Context: TObject); virtual; abstract; - function DoInput(var Args: TVariants; ReturnType: TVarType; - ReturnClass: TClass; ResultMode: THproseResultMode; - InStream: TStream): Variant; overload; - function DoInput(ReturnType: TVarType; - ReturnClass: TClass; ResultMode: THproseResultMode; - InStream: TStream): Variant; overload; - procedure DoOutput(const Name: string; const Args: array of const; - OutStream: TStream); overload; - procedure DoOutput(const Name: string; const Args: TVariants; - ByRef: Boolean; OutStream: TStream); overload; - public - constructor Create(AOwner: TComponent); override; - procedure UseService(const AUri: string); virtual; - // Synchronous invoke - function Invoke(const Name: string; - ResultMode: THproseResultMode = Normal): Variant; - overload; virtual; - function Invoke(const Name: string; const Args: array of const; - ResultMode: THproseResultMode): Variant; - overload; virtual; - function Invoke(const Name: string; const Args: array of const; - ReturnType: TVarType; - ResultMode: THproseResultMode): Variant; - overload; virtual; - function Invoke(const Name: string; const Args: array of const; - ReturnClass: TClass; - ResultMode: THproseResultMode = Normal): Variant; - overload; virtual; - function Invoke(const Name: string; const Args: array of const; - ReturnType: TVarType = varVariant; - ReturnClass: TClass = nil; - ResultMode: THproseResultMode = Normal): Variant; - overload; virtual; - // Synchronous invoke - function Invoke(const Name: string; var Args: TVariants; - ByRef: Boolean; - ResultMode: THproseResultMode = Normal): Variant; - overload; virtual; - function Invoke(const Name: string; var Args: TVariants; - ReturnType: TVarType; - ByRef: Boolean; - ResultMode: THproseResultMode = Normal): Variant; - overload; virtual; - function Invoke(const Name: string; var Args: TVariants; - ReturnClass: TClass; - ByRef: Boolean = True; - ResultMode: THproseResultMode = Normal): Variant; - overload; virtual; - function Invoke(const Name: string; var Args: TVariants; - ReturnType: TVarType = varVariant; - ReturnClass: TClass = nil; - ByRef: Boolean = True; - ResultMode: THproseResultMode = Normal): Variant; - overload; virtual; - // Asynchronous invoke - procedure Invoke(const Name: string; - Callback: THproseCallback1; - ResultMode: THproseResultMode = Normal); - overload; virtual; - procedure Invoke(const Name: string; - Callback: THproseCallback1; - ErrorEvent: THproseErrorEvent; - ResultMode: THproseResultMode = Normal); - overload; virtual; - procedure Invoke(const Name: string; const Args: array of const; - Callback: THproseCallback1; - ResultMode: THproseResultMode); - overload; virtual; - procedure Invoke(const Name: string; const Args: array of const; - Callback: THproseCallback1; - ErrorEvent: THproseErrorEvent; - ResultMode: THproseResultMode); - overload; virtual; - procedure Invoke(const Name: string; const Args: array of const; - Callback: THproseCallback1; - ReturnType: TVarType; - ResultMode: THproseResultMode); - overload; virtual; - procedure Invoke(const Name: string; const Args: array of const; - Callback: THproseCallback1; - ErrorEvent: THproseErrorEvent; - ReturnType: TVarType; - ResultMode: THproseResultMode); - overload; virtual; - procedure Invoke(const Name: string; const Args: array of const; - Callback: THproseCallback1; - ReturnClass: TClass; - ResultMode: THproseResultMode = Normal); - overload; virtual; - procedure Invoke(const Name: string; const Args: array of const; - Callback: THproseCallback1; - ErrorEvent: THproseErrorEvent; - ReturnClass: TClass; - ResultMode: THproseResultMode = Normal); - overload; virtual; - procedure Invoke(const Name: string; const Args: array of const; - Callback: THproseCallback1; - ReturnType: TVarType = varVariant; - ReturnClass: TClass = nil; - ResultMode: THproseResultMode = Normal); - overload; virtual; - procedure Invoke(const Name: string; const Args: array of const; - Callback: THproseCallback1; - ErrorEvent: THproseErrorEvent; - ReturnType: TVarType = varVariant; - ReturnClass: TClass = nil; - ResultMode: THproseResultMode = Normal); - overload; virtual; - // Asynchronous invoke - procedure Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; - ByRef: Boolean; - ResultMode: THproseResultMode = Normal); - overload; virtual; - procedure Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; - ErrorEvent: THproseErrorEvent; - ByRef: Boolean; - ResultMode: THproseResultMode = Normal); - overload; virtual; - procedure Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; - ReturnType: TVarType; - ByRef: Boolean; - ResultMode: THproseResultMode = Normal); - overload; virtual; - procedure Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; - ErrorEvent: THproseErrorEvent; - ReturnType: TVarType; - ByRef: Boolean; - ResultMode: THproseResultMode = Normal); - overload; virtual; - procedure Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; - ReturnClass: TClass; - ByRef: Boolean = True; - ResultMode: THproseResultMode = Normal); - overload; virtual; - procedure Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; - ErrorEvent: THproseErrorEvent; - ReturnClass: TClass; - ByRef: Boolean = True; - ResultMode: THproseResultMode = Normal); - overload; virtual; - procedure Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; - ReturnType: TVarType = varVariant; - ReturnClass: TClass = nil; - ByRef: Boolean = True; - ResultMode: THproseResultMode = Normal); - overload; virtual; - procedure Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; - ErrorEvent: THproseErrorEvent; - ReturnType: TVarType = varVariant; - ReturnClass: TClass = nil; - ByRef: Boolean = True; - ResultMode: THproseResultMode = Normal); - overload; virtual; - published - property Uri: string read FUri write UseService; - property Filter: IHproseFilter read FFilter write FFilter; - // This event OnError only for asynchronous invoke - property OnError: THproseErrorEvent read FErrorEvent write FErrorEvent; - end; - -implementation - -uses - HproseIO, Variants; - -type - - TAsyncInvokeThread1 = class(TThread) - private - FClient: THproseClient; - FName: string; - FArgs: TConstArray; - FCallback: THproseCallback1; - FErrorEvent: THproseErrorEvent; - FReturnType: TVarType; - FReturnClass: TClass; - FResultMode: THproseResultMode; - FResult: Variant; - FError: Exception; - protected - procedure Execute; override; - procedure DoCallback; - procedure DoError; - public - constructor Create(Client: THproseClient; const Name: string; - const Args: array of const; Callback: THproseCallback1; - ErrorEvent: THproseErrorEvent; ReturnType: TVarType; ReturnClass: TClass; - ResultMode: THproseResultMode); - end; - - TAsyncInvokeThread2 = class(TThread) - private - FClient: THproseClient; - FName: string; - FArgs: TVariants; - FCallback: THproseCallback2; - FErrorEvent: THproseErrorEvent; - FReturnType: TVarType; - FReturnClass: TClass; - FByRef: Boolean; - FResultMode: THproseResultMode; - FResult: Variant; - FError: Exception; - protected - procedure Execute; override; - procedure DoCallback; - procedure DoError; - public - constructor Create(Client: THproseClient; const Name: string; - const Args: TVariants; Callback: THproseCallback2; - ErrorEvent: THproseErrorEvent; ReturnType: TVarType; ReturnClass: TClass; - ByRef: Boolean; ResultMode: THproseResultMode); - end; - -{ THproseClient } - -constructor THproseClient.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FErrorEvent := nil; - FFilter := nil; -end; - -function THproseClient.DoInput(var Args: TVariants; - ReturnType: TVarType; ReturnClass: TClass; ResultMode: THproseResultMode; - InStream: TStream): Variant; -var - Tag: AnsiChar; - HproseReader: THproseReader; - Stream: TMemoryStream; -begin - if Assigned(FFilter) then InStream := FFilter.InputFilter(InStream); - Result := Null; - if (ResultMode = RawWithEndTag) or - (ResultMode = Raw) then begin - Stream := TMemoryStream.Create; - Stream.CopyFrom(InStream, 0); - Stream.Position := 0; - Result := ObjToVar(Stream); - if ResultMode = Raw then Stream.Size := Stream.Size - 1; - end - else begin - HproseReader := THproseReader.Create(InStream); - try - repeat - Tag := HproseReader.CheckTags(HproseTagResult + - HproseTagArgument + - HproseTagError + - HproseTagEnd); - if Tag = HproseTagResult then begin - if ResultMode = Serialized then begin - Stream := HproseReader.ReadRaw; - Stream.Position := 0; - Result := ObjToVar(Stream); - end - else begin - HproseReader.Reset; - Result := HproseReader.Unserialize(ReturnType, ReturnClass) - end; - end - else if Tag = HproseTagArgument then begin - HproseReader.Reset; - Args := VarToList(HproseReader.ReadList(varVariant)).ToArray - end - else if Tag = HproseTagError then begin - HproseReader.Reset; - Result := ObjToVar(EHproseException.Create(HproseReader.ReadString())); - end; - until Tag = HproseTagEnd; - finally - HproseReader.Free; - end; - end; -end; - -function THproseClient.DoInput(ReturnType: TVarType; - ReturnClass: TClass; ResultMode: THproseResultMode; - InStream: TStream): Variant; -var - Tag: AnsiChar; - HproseReader: THproseReader; - Stream: TMemoryStream; -begin - if Assigned(FFilter) then InStream := FFilter.InputFilter(InStream); - Result := Null; - if (ResultMode = RawWithEndTag) or - (ResultMode = Raw) then begin - Stream := TMemoryStream.Create; - Stream.CopyFrom(InStream, 0); - Stream.Position := 0; - Result := ObjToVar(Stream); - if ResultMode = Raw then Stream.Size := Stream.Size - 1; - end - else begin - HproseReader := THproseReader.Create(InStream); - try - repeat - Tag := HproseReader.CheckTags(HproseTagResult + - HproseTagError + - HproseTagEnd); - if Tag = HproseTagResult then begin - if ResultMode = Serialized then begin - Stream := HproseReader.ReadRaw; - Stream.Position := 0; - Result := ObjToVar(Stream); - end - else begin - HproseReader.Reset; - Result := HproseReader.Unserialize(ReturnType, ReturnClass) - end - end - else if Tag = HproseTagError then begin - HproseReader.Reset; - Result := ObjToVar(EHproseException.Create(HproseReader.ReadString())); - end; - until Tag = HproseTagEnd; - finally - HproseReader.Free; - end; - end; -end; - -procedure THproseClient.DoOutput(const Name: string; - const Args: array of const; OutStream: TStream); -var - HproseWriter: THproseWriter; -begin - if Assigned(FFilter) then OutStream := FFilter.OutputFilter(OutStream); - HproseWriter := THproseWriter.Create(OutStream); - try - OutStream.Write(HproseTagCall, 1); - HproseWriter.WriteString(Name, False); - if Length(Args) > 0 then begin - HproseWriter.Reset; - HproseWriter.WriteArray(Args); - end; - OutStream.Write(HproseTagEnd, 1); - finally - HproseWriter.Free; - end; -end; - -procedure THproseClient.DoOutput(const Name: string; - const Args: TVariants; ByRef: Boolean; OutStream: TStream); -var - HproseWriter: THproseWriter; -begin - if Assigned(FFilter) then OutStream := FFilter.OutputFilter(OutStream); - HproseWriter := THproseWriter.Create(OutStream); - try - OutStream.Write(HproseTagCall, 1); - HproseWriter.WriteString(Name, False); - if (Length(Args) > 0) or ByRef then begin - HproseWriter.Reset; - HproseWriter.WriteArray(Args, False); - if ByRef then HproseWriter.WriteBoolean(True); - end; - OutStream.Write(HproseTagEnd, 1); - finally - HproseWriter.Free; - end; -end; - -// Synchronous invoke -function THproseClient.Invoke(const Name: string; - ResultMode: THproseResultMode): Variant; -begin - Result := Invoke(Name, [], varVariant, TClass(nil), ResultMode); -end; - -function THproseClient.Invoke(const Name: string; - const Args: array of const; ResultMode: THproseResultMode): Variant; -begin - Result := Invoke(Name, Args, varVariant, TClass(nil), ResultMode); -end; - -function THproseClient.Invoke(const Name: string; - const Args: array of const; ReturnType: TVarType; - ResultMode: THproseResultMode): Variant; -begin - Result := Invoke(Name, Args, ReturnType, TClass(nil), ResultMode); -end; - -function THproseClient.Invoke(const Name: string; - const Args: array of const; ReturnClass: TClass; - ResultMode: THproseResultMode): Variant; -begin - Result := Invoke(Name, Args, varVariant, ReturnClass, ResultMode); -end; - -function THproseClient.Invoke(const Name: string; - const Args: array of const; ReturnType: TVarType; - ReturnClass: TClass; ResultMode: THproseResultMode): Variant; -var - Context: TObject; - InStream, OutStream: TStream; -begin - Context := GetInvokeContext; - try - OutStream := GetOutputStream(Context); - DoOutput(Name, Args, OutStream); - SendData(Context); - Result := Null; - InStream := GetInputStream(Context); - Result := DoInput(ReturnType, ReturnClass, ResultMode, InStream); - finally - EndInvoke(Context); - end; - if VarIsObj(Result, EHproseException) then - raise EHproseException(VarToObj(Result)) -end; - -// Synchronous invoke -function THproseClient.Invoke(const Name: string; var Args: TVariants; - ByRef: Boolean; ResultMode: THproseResultMode): Variant; -begin - Result := Invoke(Name, Args, varVariant, TClass(nil), ByRef, ResultMode); -end; - -function THproseClient.Invoke(const Name: string; var Args: TVariants; - ReturnType: TVarType; ByRef: Boolean; - ResultMode: THproseResultMode): Variant; -begin - Result := Invoke(Name, Args, ReturnType, TClass(nil), ByRef, ResultMode); -end; - -function THproseClient.Invoke(const Name: string; var Args: TVariants; - ReturnClass: TClass; ByRef: Boolean; - ResultMode: THproseResultMode): Variant; -begin - Result := Invoke(Name, Args, varVariant, ReturnClass, ByRef, ResultMode); -end; - -function THproseClient.Invoke(const Name: string; - var Args: TVariants; ReturnType: TVarType; - ReturnClass: TClass; ByRef: Boolean; ResultMode: THproseResultMode): Variant; -var - Context: TObject; - InStream, OutStream: TStream; -begin - Context := GetInvokeContext; - try - OutStream := GetOutputStream(Context); - DoOutput(Name, Args, Byref, OutStream); - SendData(Context); - Result := Null; - InStream := GetInputStream(Context); - Result := DoInput(Args, ReturnType, ReturnClass, ResultMode, InStream); - finally - EndInvoke(Context); - end; - if VarIsObj(Result, EHproseException) then - raise EHproseException(VarToObj(Result)); -end; - -// Asynchronous invoke -procedure THproseClient.Invoke(const Name: string; - Callback: THproseCallback1; ResultMode: THproseResultMode); -begin - TAsyncInvokeThread1.Create(Self, Name, [], Callback, nil, varVariant, - TClass(nil), ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; - Callback: THproseCallback1; ErrorEvent: THproseErrorEvent; - ResultMode: THproseResultMode); -begin - TAsyncInvokeThread1.Create(Self, Name, [], Callback, ErrorEvent, varVariant, - TClass(nil), ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; - const Args: array of const; Callback: THproseCallback1; - ResultMode: THproseResultMode); -begin - TAsyncInvokeThread1.Create(Self, Name, Args, Callback, nil, varVariant, - TClass(nil), ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; - const Args: array of const; Callback: THproseCallback1; - ErrorEvent: THproseErrorEvent; ResultMode: THproseResultMode); -begin - TAsyncInvokeThread1.Create(Self, Name, Args, Callback, ErrorEvent, varVariant, - TClass(nil), ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; - const Args: array of const; Callback: THproseCallback1; - ReturnType: TVarType; ResultMode: THproseResultMode); -begin - TAsyncInvokeThread1.Create(Self, Name, Args, Callback, nil, ReturnType, - TClass(nil), ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; - const Args: array of const; Callback: THproseCallback1; - ErrorEvent: THproseErrorEvent; ReturnType: TVarType; - ResultMode: THproseResultMode); -begin - TAsyncInvokeThread1.Create(Self, Name, Args, Callback, ErrorEvent, ReturnType, - TClass(nil), ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; - const Args: array of const; Callback: THproseCallback1; - ReturnClass: TClass; ResultMode: THproseResultMode); -begin - TAsyncInvokeThread1.Create(Self, Name, Args, Callback, nil, varVariant, - ReturnClass, ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; - const Args: array of const; Callback: THproseCallback1; - ErrorEvent: THproseErrorEvent; ReturnClass: TClass; - ResultMode: THproseResultMode); -begin - TAsyncInvokeThread1.Create(Self, Name, Args, Callback, ErrorEvent, varVariant, - ReturnClass, ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; - const Args: array of const; Callback: THproseCallback1; - ReturnType: TVarType; ReturnClass: TClass; - ResultMode: THproseResultMode); -begin - TAsyncInvokeThread1.Create(Self, Name, Args, Callback, nil, ReturnType, - ReturnClass, ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; - const Args: array of const; Callback: THproseCallback1; - ErrorEvent: THproseErrorEvent; ReturnType: TVarType; ReturnClass: TClass; - ResultMode: THproseResultMode); -begin - TAsyncInvokeThread1.Create(Self, Name, Args, Callback, ErrorEvent, ReturnType, - ReturnClass, ResultMode); -end; - -// Asynchronous invoke -procedure THproseClient.Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; ByRef: Boolean; - ResultMode: THproseResultMode); -begin - TAsyncInvokeThread2.Create(Self, Name, Args, Callback, nil, varVariant, - TClass(nil), ByRef, ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; ErrorEvent: THproseErrorEvent; - ByRef: Boolean; ResultMode: THproseResultMode); -begin - TAsyncInvokeThread2.Create(Self, Name, Args, Callback, ErrorEvent, varVariant, - TClass(nil), ByRef, ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; ReturnClass: TClass; ByRef: Boolean; - ResultMode: THproseResultMode); -begin - TAsyncInvokeThread2.Create(Self, Name, Args, Callback, nil, varVariant, - ReturnClass, ByRef, ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; ErrorEvent: THproseErrorEvent; - ReturnClass: TClass; ByRef: Boolean; ResultMode: THproseResultMode); -begin - TAsyncInvokeThread2.Create(Self, Name, Args, Callback, ErrorEvent, varVariant, - ReturnClass, ByRef, ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; ReturnType: TVarType; ByRef: Boolean; - ResultMode: THproseResultMode); -begin - TAsyncInvokeThread2.Create(Self, Name, Args, Callback, nil, ReturnType, - TClass(nil), ByRef, ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; ErrorEvent: THproseErrorEvent; - ReturnType: TVarType; ByRef: Boolean; ResultMode: THproseResultMode); -begin - TAsyncInvokeThread2.Create(Self, Name, Args, Callback, ErrorEvent, ReturnType, - TClass(nil), ByRef, ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; var Args: TVariants; - Callback: THproseCallback2; ReturnType: TVarType; ReturnClass: TClass; - ByRef: Boolean; ResultMode: THproseResultMode); -begin - TAsyncInvokeThread2.Create(Self, Name, Args, Callback, nil, ReturnType, - ReturnClass, ByRef, ResultMode); -end; - -procedure THproseClient.Invoke(const Name: string; - var Args: TVariants; Callback: THproseCallback2; - ErrorEvent: THproseErrorEvent; ReturnType: TVarType; ReturnClass: TClass; - ByRef: Boolean; ResultMode: THproseResultMode); -begin - TAsyncInvokeThread2.Create(Self, Name, Args, Callback, ErrorEvent, ReturnType, - ReturnClass, ByRef, ResultMode); -end; - -procedure THproseClient.UseService(const AUri: string); -begin - if AUri <> '' then FUri := AUri; -end; - -{ TAsyncInvokeThread1 } - -constructor TAsyncInvokeThread1.Create(Client: THproseClient; - const Name: string; const Args: array of const; - Callback: THproseCallback1; ErrorEvent: THproseErrorEvent; - ReturnType: TVarType; ReturnClass: TClass; ResultMode: THproseResultMode); -begin - inherited Create(False); - FreeOnTerminate := True; - FClient := Client; - FName := Name; - FArgs := CreateConstArray(Args); - FCallback := Callback; - FErrorEvent := ErrorEvent; - FReturnType := ReturnType; - FReturnClass := ReturnClass; - FResultMode := ResultMode; - FError := nil; -end; - -procedure TAsyncInvokeThread1.DoCallback; -begin - if FError = nil then FCallback(FResult); -end; - -procedure TAsyncInvokeThread1.DoError; -begin - if Assigned(FErrorEvent) then - FErrorEvent(FName, FError) - else if Assigned(FClient.FErrorEvent) then - FClient.FErrorEvent(FName, FError); -end; - -procedure TAsyncInvokeThread1.Execute; -begin - try - try - FResult := FClient.Invoke(FName, - FArgs, - FReturnType, - FReturnClass, - FResultMode); - except - on E: Exception do begin - FError := E; - Synchronize(DoError); - end; - end; - finally - FinalizeConstArray(FArgs); - end; - Synchronize(DoCallback); -end; - -{ TAsyncInvokeThread2 } - -constructor TAsyncInvokeThread2.Create(Client: THproseClient; - const Name: string; const Args: TVariants; - Callback: THproseCallback2; ErrorEvent: THproseErrorEvent; - ReturnType: TVarType; ReturnClass: TClass; ByRef: Boolean; - ResultMode: THproseResultMode); -begin - inherited Create(False); - FreeOnTerminate := True; - FClient := Client; - FName := Name; - FArgs := Args; - FCallback := Callback; - FErrorEvent := ErrorEvent; - FReturnType := ReturnType; - FReturnClass := ReturnClass; - FByRef := ByRef; - FResultMode := ResultMode; - FError := nil; -end; - -procedure TAsyncInvokeThread2.DoCallback; -begin - if FError = nil then FCallback(FResult, FArgs); -end; - -procedure TAsyncInvokeThread2.DoError; -begin - if Assigned(FErrorEvent) then - FErrorEvent(FName, FError) - else if Assigned(FClient.FErrorEvent) then - FClient.FErrorEvent(FName, FError); -end; - -procedure TAsyncInvokeThread2.Execute; -begin - try - FResult := FClient.Invoke(FName, - FArgs, - FReturnType, - FReturnClass, - FByRef, - FResultMode); - except - on E: Exception do begin - FError := E; - Synchronize(DoError); - end; - end; - Synchronize(DoCallback); -end; - -end. +{ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * HproseClient.pas * + * * + * hprose client unit for delphi. * + * * + * LastModified: Nov 27, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +} +unit HproseClient; + +{$I Hprose.inc} + +interface + +uses HproseCommon, Classes, SysUtils; + +type + + THproseCallback1 = procedure(Result: Variant) of object; + THproseCallback2 = procedure(Result: Variant; + const Args: TVariants) of object; + + THproseErrorEvent = procedure(const Name:string; + const Error: Exception) of object; + + THproseClient = class(TComponent) + private + FErrorEvent: THproseErrorEvent; + FFilter: IHproseFilter; + protected + FUri: string; + function GetInvokeContext: TObject; virtual; abstract; + function GetOutputStream(var Context: TObject): TStream; virtual; abstract; + procedure SendData(var Context: TObject); virtual; abstract; + function GetInputStream(var Context: TObject): TStream; virtual; abstract; + procedure EndInvoke(var Context: TObject); virtual; abstract; + function DoInput(var Args: TVariants; ReturnType: TVarType; + ReturnClass: TClass; ResultMode: THproseResultMode; + InStream: TStream): Variant; overload; + function DoInput(ReturnType: TVarType; + ReturnClass: TClass; ResultMode: THproseResultMode; + InStream: TStream): Variant; overload; + procedure DoOutput(const Name: string; const Args: array of const; + OutStream: TStream); overload; + procedure DoOutput(const Name: string; const Args: TVariants; + ByRef: Boolean; OutStream: TStream); overload; + public + constructor Create(AOwner: TComponent); override; + procedure UseService(const AUri: string); virtual; + // Synchronous invoke + function Invoke(const Name: string; + ResultMode: THproseResultMode = Normal): Variant; + overload; virtual; + function Invoke(const Name: string; const Args: array of const; + ResultMode: THproseResultMode): Variant; + overload; virtual; + function Invoke(const Name: string; const Args: array of const; + ReturnType: TVarType; + ResultMode: THproseResultMode): Variant; + overload; virtual; + function Invoke(const Name: string; const Args: array of const; + ReturnClass: TClass; + ResultMode: THproseResultMode = Normal): Variant; + overload; virtual; + function Invoke(const Name: string; const Args: array of const; + ReturnType: TVarType = varVariant; + ReturnClass: TClass = nil; + ResultMode: THproseResultMode = Normal): Variant; + overload; virtual; + // Synchronous invoke + function Invoke(const Name: string; var Args: TVariants; + ByRef: Boolean; + ResultMode: THproseResultMode = Normal): Variant; + overload; virtual; + function Invoke(const Name: string; var Args: TVariants; + ReturnType: TVarType; + ByRef: Boolean; + ResultMode: THproseResultMode = Normal): Variant; + overload; virtual; + function Invoke(const Name: string; var Args: TVariants; + ReturnClass: TClass; + ByRef: Boolean = True; + ResultMode: THproseResultMode = Normal): Variant; + overload; virtual; + function Invoke(const Name: string; var Args: TVariants; + ReturnType: TVarType = varVariant; + ReturnClass: TClass = nil; + ByRef: Boolean = True; + ResultMode: THproseResultMode = Normal): Variant; + overload; virtual; + // Asynchronous invoke + procedure Invoke(const Name: string; + Callback: THproseCallback1; + ResultMode: THproseResultMode = Normal); + overload; virtual; + procedure Invoke(const Name: string; + Callback: THproseCallback1; + ErrorEvent: THproseErrorEvent; + ResultMode: THproseResultMode = Normal); + overload; virtual; + procedure Invoke(const Name: string; const Args: array of const; + Callback: THproseCallback1; + ResultMode: THproseResultMode); + overload; virtual; + procedure Invoke(const Name: string; const Args: array of const; + Callback: THproseCallback1; + ErrorEvent: THproseErrorEvent; + ResultMode: THproseResultMode); + overload; virtual; + procedure Invoke(const Name: string; const Args: array of const; + Callback: THproseCallback1; + ReturnType: TVarType; + ResultMode: THproseResultMode); + overload; virtual; + procedure Invoke(const Name: string; const Args: array of const; + Callback: THproseCallback1; + ErrorEvent: THproseErrorEvent; + ReturnType: TVarType; + ResultMode: THproseResultMode); + overload; virtual; + procedure Invoke(const Name: string; const Args: array of const; + Callback: THproseCallback1; + ReturnClass: TClass; + ResultMode: THproseResultMode = Normal); + overload; virtual; + procedure Invoke(const Name: string; const Args: array of const; + Callback: THproseCallback1; + ErrorEvent: THproseErrorEvent; + ReturnClass: TClass; + ResultMode: THproseResultMode = Normal); + overload; virtual; + procedure Invoke(const Name: string; const Args: array of const; + Callback: THproseCallback1; + ReturnType: TVarType = varVariant; + ReturnClass: TClass = nil; + ResultMode: THproseResultMode = Normal); + overload; virtual; + procedure Invoke(const Name: string; const Args: array of const; + Callback: THproseCallback1; + ErrorEvent: THproseErrorEvent; + ReturnType: TVarType = varVariant; + ReturnClass: TClass = nil; + ResultMode: THproseResultMode = Normal); + overload; virtual; + // Asynchronous invoke + procedure Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; + ByRef: Boolean; + ResultMode: THproseResultMode = Normal); + overload; virtual; + procedure Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; + ErrorEvent: THproseErrorEvent; + ByRef: Boolean; + ResultMode: THproseResultMode = Normal); + overload; virtual; + procedure Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; + ReturnType: TVarType; + ByRef: Boolean; + ResultMode: THproseResultMode = Normal); + overload; virtual; + procedure Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; + ErrorEvent: THproseErrorEvent; + ReturnType: TVarType; + ByRef: Boolean; + ResultMode: THproseResultMode = Normal); + overload; virtual; + procedure Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; + ReturnClass: TClass; + ByRef: Boolean = True; + ResultMode: THproseResultMode = Normal); + overload; virtual; + procedure Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; + ErrorEvent: THproseErrorEvent; + ReturnClass: TClass; + ByRef: Boolean = True; + ResultMode: THproseResultMode = Normal); + overload; virtual; + procedure Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; + ReturnType: TVarType = varVariant; + ReturnClass: TClass = nil; + ByRef: Boolean = True; + ResultMode: THproseResultMode = Normal); + overload; virtual; + procedure Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; + ErrorEvent: THproseErrorEvent; + ReturnType: TVarType = varVariant; + ReturnClass: TClass = nil; + ByRef: Boolean = True; + ResultMode: THproseResultMode = Normal); + overload; virtual; + published + property Uri: string read FUri write UseService; + property Filter: IHproseFilter read FFilter write FFilter; + // This event OnError only for asynchronous invoke + property OnError: THproseErrorEvent read FErrorEvent write FErrorEvent; + end; + +implementation + +uses + HproseIO, Variants; + +type + + TAsyncInvokeThread1 = class(TThread) + private + FClient: THproseClient; + FName: string; + FArgs: TConstArray; + FCallback: THproseCallback1; + FErrorEvent: THproseErrorEvent; + FReturnType: TVarType; + FReturnClass: TClass; + FResultMode: THproseResultMode; + FResult: Variant; + FError: Exception; + protected + procedure Execute; override; + procedure DoCallback; + procedure DoError; + public + constructor Create(Client: THproseClient; const Name: string; + const Args: array of const; Callback: THproseCallback1; + ErrorEvent: THproseErrorEvent; ReturnType: TVarType; ReturnClass: TClass; + ResultMode: THproseResultMode); + end; + + TAsyncInvokeThread2 = class(TThread) + private + FClient: THproseClient; + FName: string; + FArgs: TVariants; + FCallback: THproseCallback2; + FErrorEvent: THproseErrorEvent; + FReturnType: TVarType; + FReturnClass: TClass; + FByRef: Boolean; + FResultMode: THproseResultMode; + FResult: Variant; + FError: Exception; + protected + procedure Execute; override; + procedure DoCallback; + procedure DoError; + public + constructor Create(Client: THproseClient; const Name: string; + const Args: TVariants; Callback: THproseCallback2; + ErrorEvent: THproseErrorEvent; ReturnType: TVarType; ReturnClass: TClass; + ByRef: Boolean; ResultMode: THproseResultMode); + end; + +{ THproseClient } + +constructor THproseClient.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FErrorEvent := nil; + FFilter := nil; +end; + +function THproseClient.DoInput(var Args: TVariants; + ReturnType: TVarType; ReturnClass: TClass; ResultMode: THproseResultMode; + InStream: TStream): Variant; +var + Tag: AnsiChar; + HproseReader: THproseReader; + Stream: TMemoryStream; +begin + if Assigned(FFilter) then InStream := FFilter.InputFilter(InStream); + Result := Null; + if (ResultMode = RawWithEndTag) or + (ResultMode = Raw) then begin + Stream := TMemoryStream.Create; + Stream.CopyFrom(InStream, 0); + Stream.Position := 0; + Result := ObjToVar(Stream); + if ResultMode = Raw then Stream.Size := Stream.Size - 1; + end + else begin + HproseReader := THproseReader.Create(InStream); + try + repeat + Tag := HproseReader.CheckTags(HproseTagResult + + HproseTagArgument + + HproseTagError + + HproseTagEnd); + if Tag = HproseTagResult then begin + if ResultMode = Serialized then begin + Stream := HproseReader.ReadRaw; + Stream.Position := 0; + Result := ObjToVar(Stream); + end + else begin + HproseReader.Reset; + Result := HproseReader.Unserialize(ReturnType, ReturnClass) + end; + end + else if Tag = HproseTagArgument then begin + HproseReader.Reset; + Args := VarToList(HproseReader.ReadList(varVariant)).ToArray + end + else if Tag = HproseTagError then begin + HproseReader.Reset; + Result := ObjToVar(EHproseException.Create(HproseReader.ReadString())); + end; + until Tag = HproseTagEnd; + finally + HproseReader.Free; + end; + end; +end; + +function THproseClient.DoInput(ReturnType: TVarType; + ReturnClass: TClass; ResultMode: THproseResultMode; + InStream: TStream): Variant; +var + Tag: AnsiChar; + HproseReader: THproseReader; + Stream: TMemoryStream; +begin + if Assigned(FFilter) then InStream := FFilter.InputFilter(InStream); + Result := Null; + if (ResultMode = RawWithEndTag) or + (ResultMode = Raw) then begin + Stream := TMemoryStream.Create; + Stream.CopyFrom(InStream, 0); + Stream.Position := 0; + Result := ObjToVar(Stream); + if ResultMode = Raw then Stream.Size := Stream.Size - 1; + end + else begin + HproseReader := THproseReader.Create(InStream); + try + repeat + Tag := HproseReader.CheckTags(HproseTagResult + + HproseTagError + + HproseTagEnd); + if Tag = HproseTagResult then begin + if ResultMode = Serialized then begin + Stream := HproseReader.ReadRaw; + Stream.Position := 0; + Result := ObjToVar(Stream); + end + else begin + HproseReader.Reset; + Result := HproseReader.Unserialize(ReturnType, ReturnClass) + end + end + else if Tag = HproseTagError then begin + HproseReader.Reset; + Result := ObjToVar(EHproseException.Create(HproseReader.ReadString())); + end; + until Tag = HproseTagEnd; + finally + HproseReader.Free; + end; + end; +end; + +procedure THproseClient.DoOutput(const Name: string; + const Args: array of const; OutStream: TStream); +var + HproseWriter: THproseWriter; +begin + if Assigned(FFilter) then OutStream := FFilter.OutputFilter(OutStream); + HproseWriter := THproseWriter.Create(OutStream); + try + OutStream.Write(HproseTagCall, 1); + HproseWriter.WriteString(Name, False); + if Length(Args) > 0 then begin + HproseWriter.Reset; + HproseWriter.WriteArray(Args); + end; + OutStream.Write(HproseTagEnd, 1); + finally + HproseWriter.Free; + end; +end; + +procedure THproseClient.DoOutput(const Name: string; + const Args: TVariants; ByRef: Boolean; OutStream: TStream); +var + HproseWriter: THproseWriter; +begin + if Assigned(FFilter) then OutStream := FFilter.OutputFilter(OutStream); + HproseWriter := THproseWriter.Create(OutStream); + try + OutStream.Write(HproseTagCall, 1); + HproseWriter.WriteString(Name, False); + if (Length(Args) > 0) or ByRef then begin + HproseWriter.Reset; + HproseWriter.WriteArray(Args, False); + if ByRef then HproseWriter.WriteBoolean(True); + end; + OutStream.Write(HproseTagEnd, 1); + finally + HproseWriter.Free; + end; +end; + +// Synchronous invoke +function THproseClient.Invoke(const Name: string; + ResultMode: THproseResultMode): Variant; +begin + Result := Invoke(Name, [], varVariant, TClass(nil), ResultMode); +end; + +function THproseClient.Invoke(const Name: string; + const Args: array of const; ResultMode: THproseResultMode): Variant; +begin + Result := Invoke(Name, Args, varVariant, TClass(nil), ResultMode); +end; + +function THproseClient.Invoke(const Name: string; + const Args: array of const; ReturnType: TVarType; + ResultMode: THproseResultMode): Variant; +begin + Result := Invoke(Name, Args, ReturnType, TClass(nil), ResultMode); +end; + +function THproseClient.Invoke(const Name: string; + const Args: array of const; ReturnClass: TClass; + ResultMode: THproseResultMode): Variant; +begin + Result := Invoke(Name, Args, varVariant, ReturnClass, ResultMode); +end; + +function THproseClient.Invoke(const Name: string; + const Args: array of const; ReturnType: TVarType; + ReturnClass: TClass; ResultMode: THproseResultMode): Variant; +var + Context: TObject; + InStream, OutStream: TStream; +begin + Context := GetInvokeContext; + try + OutStream := GetOutputStream(Context); + DoOutput(Name, Args, OutStream); + SendData(Context); + Result := Null; + InStream := GetInputStream(Context); + Result := DoInput(ReturnType, ReturnClass, ResultMode, InStream); + finally + EndInvoke(Context); + end; + if VarIsObj(Result, EHproseException) then + raise EHproseException(VarToObj(Result)) +end; + +// Synchronous invoke +function THproseClient.Invoke(const Name: string; var Args: TVariants; + ByRef: Boolean; ResultMode: THproseResultMode): Variant; +begin + Result := Invoke(Name, Args, varVariant, TClass(nil), ByRef, ResultMode); +end; + +function THproseClient.Invoke(const Name: string; var Args: TVariants; + ReturnType: TVarType; ByRef: Boolean; + ResultMode: THproseResultMode): Variant; +begin + Result := Invoke(Name, Args, ReturnType, TClass(nil), ByRef, ResultMode); +end; + +function THproseClient.Invoke(const Name: string; var Args: TVariants; + ReturnClass: TClass; ByRef: Boolean; + ResultMode: THproseResultMode): Variant; +begin + Result := Invoke(Name, Args, varVariant, ReturnClass, ByRef, ResultMode); +end; + +function THproseClient.Invoke(const Name: string; + var Args: TVariants; ReturnType: TVarType; + ReturnClass: TClass; ByRef: Boolean; ResultMode: THproseResultMode): Variant; +var + Context: TObject; + InStream, OutStream: TStream; +begin + Context := GetInvokeContext; + try + OutStream := GetOutputStream(Context); + DoOutput(Name, Args, Byref, OutStream); + SendData(Context); + Result := Null; + InStream := GetInputStream(Context); + Result := DoInput(Args, ReturnType, ReturnClass, ResultMode, InStream); + finally + EndInvoke(Context); + end; + if VarIsObj(Result, EHproseException) then + raise EHproseException(VarToObj(Result)); +end; + +// Asynchronous invoke +procedure THproseClient.Invoke(const Name: string; + Callback: THproseCallback1; ResultMode: THproseResultMode); +begin + TAsyncInvokeThread1.Create(Self, Name, [], Callback, nil, varVariant, + TClass(nil), ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; + Callback: THproseCallback1; ErrorEvent: THproseErrorEvent; + ResultMode: THproseResultMode); +begin + TAsyncInvokeThread1.Create(Self, Name, [], Callback, ErrorEvent, varVariant, + TClass(nil), ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; + const Args: array of const; Callback: THproseCallback1; + ResultMode: THproseResultMode); +begin + TAsyncInvokeThread1.Create(Self, Name, Args, Callback, nil, varVariant, + TClass(nil), ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; + const Args: array of const; Callback: THproseCallback1; + ErrorEvent: THproseErrorEvent; ResultMode: THproseResultMode); +begin + TAsyncInvokeThread1.Create(Self, Name, Args, Callback, ErrorEvent, varVariant, + TClass(nil), ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; + const Args: array of const; Callback: THproseCallback1; + ReturnType: TVarType; ResultMode: THproseResultMode); +begin + TAsyncInvokeThread1.Create(Self, Name, Args, Callback, nil, ReturnType, + TClass(nil), ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; + const Args: array of const; Callback: THproseCallback1; + ErrorEvent: THproseErrorEvent; ReturnType: TVarType; + ResultMode: THproseResultMode); +begin + TAsyncInvokeThread1.Create(Self, Name, Args, Callback, ErrorEvent, ReturnType, + TClass(nil), ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; + const Args: array of const; Callback: THproseCallback1; + ReturnClass: TClass; ResultMode: THproseResultMode); +begin + TAsyncInvokeThread1.Create(Self, Name, Args, Callback, nil, varVariant, + ReturnClass, ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; + const Args: array of const; Callback: THproseCallback1; + ErrorEvent: THproseErrorEvent; ReturnClass: TClass; + ResultMode: THproseResultMode); +begin + TAsyncInvokeThread1.Create(Self, Name, Args, Callback, ErrorEvent, varVariant, + ReturnClass, ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; + const Args: array of const; Callback: THproseCallback1; + ReturnType: TVarType; ReturnClass: TClass; + ResultMode: THproseResultMode); +begin + TAsyncInvokeThread1.Create(Self, Name, Args, Callback, nil, ReturnType, + ReturnClass, ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; + const Args: array of const; Callback: THproseCallback1; + ErrorEvent: THproseErrorEvent; ReturnType: TVarType; ReturnClass: TClass; + ResultMode: THproseResultMode); +begin + TAsyncInvokeThread1.Create(Self, Name, Args, Callback, ErrorEvent, ReturnType, + ReturnClass, ResultMode); +end; + +// Asynchronous invoke +procedure THproseClient.Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; ByRef: Boolean; + ResultMode: THproseResultMode); +begin + TAsyncInvokeThread2.Create(Self, Name, Args, Callback, nil, varVariant, + TClass(nil), ByRef, ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; ErrorEvent: THproseErrorEvent; + ByRef: Boolean; ResultMode: THproseResultMode); +begin + TAsyncInvokeThread2.Create(Self, Name, Args, Callback, ErrorEvent, varVariant, + TClass(nil), ByRef, ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; ReturnClass: TClass; ByRef: Boolean; + ResultMode: THproseResultMode); +begin + TAsyncInvokeThread2.Create(Self, Name, Args, Callback, nil, varVariant, + ReturnClass, ByRef, ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; ErrorEvent: THproseErrorEvent; + ReturnClass: TClass; ByRef: Boolean; ResultMode: THproseResultMode); +begin + TAsyncInvokeThread2.Create(Self, Name, Args, Callback, ErrorEvent, varVariant, + ReturnClass, ByRef, ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; ReturnType: TVarType; ByRef: Boolean; + ResultMode: THproseResultMode); +begin + TAsyncInvokeThread2.Create(Self, Name, Args, Callback, nil, ReturnType, + TClass(nil), ByRef, ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; ErrorEvent: THproseErrorEvent; + ReturnType: TVarType; ByRef: Boolean; ResultMode: THproseResultMode); +begin + TAsyncInvokeThread2.Create(Self, Name, Args, Callback, ErrorEvent, ReturnType, + TClass(nil), ByRef, ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; var Args: TVariants; + Callback: THproseCallback2; ReturnType: TVarType; ReturnClass: TClass; + ByRef: Boolean; ResultMode: THproseResultMode); +begin + TAsyncInvokeThread2.Create(Self, Name, Args, Callback, nil, ReturnType, + ReturnClass, ByRef, ResultMode); +end; + +procedure THproseClient.Invoke(const Name: string; + var Args: TVariants; Callback: THproseCallback2; + ErrorEvent: THproseErrorEvent; ReturnType: TVarType; ReturnClass: TClass; + ByRef: Boolean; ResultMode: THproseResultMode); +begin + TAsyncInvokeThread2.Create(Self, Name, Args, Callback, ErrorEvent, ReturnType, + ReturnClass, ByRef, ResultMode); +end; + +procedure THproseClient.UseService(const AUri: string); +begin + if AUri <> '' then FUri := AUri; +end; + +{ TAsyncInvokeThread1 } + +constructor TAsyncInvokeThread1.Create(Client: THproseClient; + const Name: string; const Args: array of const; + Callback: THproseCallback1; ErrorEvent: THproseErrorEvent; + ReturnType: TVarType; ReturnClass: TClass; ResultMode: THproseResultMode); +begin + inherited Create(False); + FreeOnTerminate := True; + FClient := Client; + FName := Name; + FArgs := CreateConstArray(Args); + FCallback := Callback; + FErrorEvent := ErrorEvent; + FReturnType := ReturnType; + FReturnClass := ReturnClass; + FResultMode := ResultMode; + FError := nil; +end; + +procedure TAsyncInvokeThread1.DoCallback; +begin + if FError = nil then FCallback(FResult); +end; + +procedure TAsyncInvokeThread1.DoError; +begin + if Assigned(FErrorEvent) then + FErrorEvent(FName, FError) + else if Assigned(FClient.FErrorEvent) then + FClient.FErrorEvent(FName, FError); +end; + +procedure TAsyncInvokeThread1.Execute; +begin + try + try + FResult := FClient.Invoke(FName, + FArgs, + FReturnType, + FReturnClass, + FResultMode); + except + on E: Exception do begin + FError := E; + Synchronize(DoError); + end; + end; + finally + FinalizeConstArray(FArgs); + end; + Synchronize(DoCallback); +end; + +{ TAsyncInvokeThread2 } + +constructor TAsyncInvokeThread2.Create(Client: THproseClient; + const Name: string; const Args: TVariants; + Callback: THproseCallback2; ErrorEvent: THproseErrorEvent; + ReturnType: TVarType; ReturnClass: TClass; ByRef: Boolean; + ResultMode: THproseResultMode); +begin + inherited Create(False); + FreeOnTerminate := True; + FClient := Client; + FName := Name; + FArgs := Args; + FCallback := Callback; + FErrorEvent := ErrorEvent; + FReturnType := ReturnType; + FReturnClass := ReturnClass; + FByRef := ByRef; + FResultMode := ResultMode; + FError := nil; +end; + +procedure TAsyncInvokeThread2.DoCallback; +begin + if FError = nil then FCallback(FResult, FArgs); +end; + +procedure TAsyncInvokeThread2.DoError; +begin + if Assigned(FErrorEvent) then + FErrorEvent(FName, FError) + else if Assigned(FClient.FErrorEvent) then + FClient.FErrorEvent(FName, FError); +end; + +procedure TAsyncInvokeThread2.Execute; +begin + try + FResult := FClient.Invoke(FName, + FArgs, + FReturnType, + FReturnClass, + FByRef, + FResultMode); + except + on E: Exception do begin + FError := E; + Synchronize(DoError); + end; + end; + Synchronize(DoCallback); +end; + +end. diff --git a/src/delphi/HproseCommon.pas b/src/delphi/HproseCommon.pas index 33a8347..36b58a2 100644 --- a/src/delphi/HproseCommon.pas +++ b/src/delphi/HproseCommon.pas @@ -1,2647 +1,2647 @@ -{ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ - -/**********************************************************\ - * * - * HproseCommon.pas * - * * - * hprose common unit for delphi. * - * * - * LastModified: Dec 28, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -} -unit HproseCommon; - -{$I Hprose.inc} - -interface - -uses Classes, SyncObjs, SysUtils; - -type - -{$IFNDEF DELPHI2009_UP} - RawByteString = type AnsiString; -{$ENDIF} - - THproseResultMode = (Normal, Serialized, Raw, RawWithEndTag); - - TVariants = array of Variant; - PVariants = ^TVariants; - - TConstArray = array of TVarRec; - - EHproseException = class(Exception); - EHashBucketError = class(Exception); - EArrayListError = class(Exception); - - IHproseFilter = interface - ['{4AD7CCF2-1121-4CA4-92A7-5704C5956BA4}'] - function InputFilter(const data: TStream): TStream; - function OutputFilter(const data: TStream): TStream; - end; - - IListEnumerator = interface - ['{767477EC-A143-4DC6-9962-A6837A7AEC01}'] - function GetCurrent: Variant; - function MoveNext: Boolean; - property Current: Variant read GetCurrent; - end; - - IList = interface(IReadWriteSync) - ['{DE925411-42B8-4DB3-A00C-B585C087EC4C}'] - function Get(Index: Integer): Variant; - procedure Put(Index: Integer; const Value: Variant); - function GetCapacity: Integer; - function GetCount: Integer; - procedure SetCapacity(NewCapacity: Integer); - procedure SetCount(NewCount: Integer); - function Add(const Value: Variant): Integer; - procedure AddAll(const ArrayList: IList); overload; - procedure AddAll(const Container: Variant); overload; - procedure Assign(const Source: IList); - procedure Clear; - function Contains(const Value: Variant): Boolean; - function Delete(Index: Integer): Variant; - procedure Exchange(Index1, Index2: Integer); - function GetEnumerator: IListEnumerator; - function IndexOf(const Value: Variant): Integer; - procedure Insert(Index: Integer; const Value: Variant); - function Join(const Glue: string = ','; - const LeftPad: string = ''; - const RightPad: string = ''): string; - procedure InitLock; - procedure InitReadWriteLock; - procedure Lock; - procedure Unlock; - procedure Move(CurIndex, NewIndex: Integer); - function Remove(const Value: Variant): Integer; - function ToArray: TVariants; overload; - function ToArray(VarType: TVarType): Variant; overload; - property Item[Index: Integer]: Variant read Get write Put; default; - property Capacity: Integer read GetCapacity write SetCapacity; - property Count: Integer read GetCount write SetCount; - end; - - TAbstractList = class(TInterfacedObject, IList) - private - FLock: TCriticalSection; - FReadWriteLock: TMultiReadExclusiveWriteSynchronizer; - protected - function Get(Index: Integer): Variant; virtual; abstract; - procedure Put(Index: Integer; const Value: Variant); virtual; abstract; - function GetCapacity: Integer; virtual; abstract; - function GetCount: Integer; virtual; abstract; - procedure SetCapacity(NewCapacity: Integer); virtual; abstract; - procedure SetCount(NewCount: Integer); virtual; abstract; - public - constructor Create(Capacity: Integer = 4; Sync: Boolean = True; - ReadWriteSync: Boolean = False); overload; virtual; abstract; - constructor Create(Sync: Boolean; - ReadWriteSync: Boolean = False); overload; virtual; abstract; - destructor Destroy; override; - function Add(const Value: Variant): Integer; virtual; abstract; - procedure AddAll(const ArrayList: IList); overload; virtual; abstract; - procedure AddAll(const Container: Variant); overload; virtual; abstract; - procedure Assign(const Source: IList); virtual; - procedure Clear; virtual; abstract; - function Contains(const Value: Variant): Boolean; virtual; abstract; - function Delete(Index: Integer): Variant; virtual; abstract; - procedure Exchange(Index1, Index2: Integer); virtual; abstract; - function GetEnumerator: IListEnumerator; virtual; - function IndexOf(const Value: Variant): Integer; virtual; abstract; - procedure Insert(Index: Integer; const Value: Variant); virtual; abstract; - function Join(const Glue, LeftPad, RightPad: string): string; virtual; - class function Split(Str: string; const Separator: string = ','; - Limit: Integer = 0; TrimItem: Boolean = False; - SkipEmptyItem: Boolean = False; Sync: Boolean = True; - ReadWriteSync: Boolean = False): IList; virtual; - procedure InitLock; - procedure InitReadWriteLock; - procedure Lock; - procedure Unlock; - procedure BeginRead; - procedure EndRead; - function BeginWrite: Boolean; - procedure EndWrite; - procedure Move(CurIndex, NewIndex: Integer); virtual; abstract; - function Remove(const Value: Variant): Integer; virtual; abstract; - function ToArray: TVariants; overload; virtual; abstract; - function ToArray(VarType: TVarType): Variant; overload; virtual; abstract; - property Item[Index: Integer]: Variant read Get write Put; default; - property Capacity: Integer read GetCapacity write SetCapacity; - property Count: Integer read GetCount write SetCount; - end; - - TListClass = class of TAbstractList; - - IArrayList = interface(IList) - ['{0D12803C-6B0B-476B-A9E3-C219BF651BD1}'] - end; - - TArrayList = class(TAbstractList, IArrayList) - private - FCount: Integer; - FCapacity: Integer; - FList: TVariants; - protected - function Get(Index: Integer): Variant; override; - procedure Grow; virtual; - procedure Put(Index: Integer; const Value: Variant); override; - function GetCapacity: Integer; override; - function GetCount: Integer; override; - procedure SetCapacity(NewCapacity: Integer); override; - procedure SetCount(NewCount: Integer); override; - public - constructor Create(Capacity: Integer = 4; Sync: Boolean = True; - ReadWriteSync: Boolean = False); overload; override; - constructor Create(Sync: Boolean; - ReadWriteSync: Boolean = False); overload; override; -{$IFDEF BCB} - constructor Create0; virtual; // for C++ Builder - constructor Create1(Capacity: Integer); virtual; // for C++ Builder - constructor Create2(Capacity: Integer; Sync: Boolean); virtual; // for C++ Builder - constructor CreateS(Sync: Boolean); virtual; // for C++ Builder -{$ENDIF} - function Add(const Value: Variant): Integer; override; - procedure AddAll(const AList: IList); overload; override; - procedure AddAll(const Container: Variant); overload; override; - procedure Clear; override; - function Contains(const Value: Variant): Boolean; override; - function Delete(Index: Integer): Variant; override; - procedure Exchange(Index1, Index2: Integer); override; - function IndexOf(const Value: Variant): Integer; override; - procedure Insert(Index: Integer; const Value: Variant); override; - procedure Move(CurIndex, NewIndex: Integer); override; - function Remove(const Value: Variant): Integer; override; - function ToArray: TVariants; overload; override; - function ToArray(VarType: TVarType): Variant; overload; override; - property Item[Index: Integer]: Variant read Get write Put; default; - property Count: Integer read GetCount write SetCount; - property Capacity: Integer read GetCapacity write SetCapacity; - end; - - PHashItem = ^THashItem; - - THashItem = record - Next: PHashItem; - Index: Integer; - HashCode: Integer; - end; - - THashItemDynArray = array of PHashItem; - - TIndexCompareMethod = function (Index: Integer; - const Value: Variant): Boolean of object; - - THashBucket = class(TObject) - private - FCount: Integer; - FFactor: Single; - FCapacity: Integer; - FIndices: THashItemDynArray; - procedure Grow; - procedure SetCapacity(NewCapacity: Integer); - public - constructor Create(Capacity: Integer = 16; Factor: Single = 0.75); - destructor Destroy; override; - function Add(HashCode, Index: Integer): PHashItem; - procedure Clear; - procedure Delete(HashCode, Index: Integer); - function IndexOf(HashCode: Integer; const Value: Variant; - CompareProc: TIndexCompareMethod): Integer; - function Modify(OldHashCode, NewHashCode, Index: Integer): PHashItem; - property Count: Integer read FCount; - property Capacity: Integer read FCapacity write SetCapacity; - end; - - IHashedList = interface(IArrayList) - ['{D2392014-7451-40EF-809E-D25BFB0FA661}'] - end; - - THashedList = class(TArrayList, IHashedList) - private - FHashBucket: THashBucket; - protected - function HashOf(const Value: Variant): Integer; virtual; - function IndexCompare(Index: Integer; const Value: Variant): - Boolean; virtual; - procedure Put(Index: Integer; const Value: Variant); override; - public - constructor Create(Capacity: Integer = 4; Sync: Boolean = True; - ReadWriteSync: Boolean = False); overload; override; - constructor Create(Capacity: Integer; Factor: Single; Sync: Boolean = True; - ReadWriteSync: Boolean = False); reintroduce; overload; virtual; -{$IFDEF BCB} - constructor Create3(Capacity: Integer; Factor: Single; - Sync: Boolean); virtual; // for C++ Builder -{$ENDIF} - destructor Destroy; override; - function Add(const Value: Variant): Integer; override; - procedure Clear; override; - function Delete(Index: Integer): Variant; override; - procedure Exchange(Index1, Index2: Integer); override; - function IndexOf(const Value: Variant): Integer; override; - procedure Insert(Index: Integer; const Value: Variant); override; - end; - - ICaseInsensitiveHashedList = interface(IHashedList) - ['{9ECA15EC-9486-4BF6-AADD-BBD88890FAF8}'] - end; - - TCaseInsensitiveHashedList = class(THashedList, ICaseInsensitiveHashedList) - protected - function HashOf(const Value: Variant): Integer; override; - function IndexCompare(Index: Integer; const Value: Variant): - Boolean; override; -{$IFDEF BCB} - public - constructor Create4(Capacity: Integer; Factor: Single; Sync, - ReadWriteSync: Boolean); virtual; // for C++ Builder -{$ENDIF} - end; - - TMapEntry = record - Key: Variant; - Value: Variant; - end; - - IMapEnumerator = interface - ['{5DE7A194-4476-42A6-A1E7-CB1D20AA7B0A}'] - function GetCurrent: TMapEntry; - function MoveNext: Boolean; - property Current: TMapEntry read GetCurrent; - end; - - IMap = interface(IReadWriteSync) - ['{28B78387-CB07-4C28-B642-09716DAA2170}'] - procedure Assign(const Source: IMap); - function GetCount: Integer; - function GetKeys: IList; - function GetValues: IList; - function GetKey(const Value: Variant): Variant; - function Get(const Key: Variant): Variant; - procedure Put(const Key, Value: Variant); - procedure Clear; - function ContainsKey(const Key: Variant): Boolean; - function ContainsValue(const Value: Variant): Boolean; - function Delete(const Key: Variant): Variant; - function GetEnumerator: IMapEnumerator; - function Join(const ItemGlue: string = ';'; - const KeyValueGlue: string = '='; - const LeftPad: string = ''; - const RightPad: string = ''): string; - procedure InitLock; - procedure InitReadWriteLock; - procedure Lock; - procedure Unlock; - procedure PutAll(const AList: IList); overload; - procedure PutAll(const AMap: IMap); overload; - procedure PutAll(const Container: Variant); overload; - function ToList(ListClass: TListClass; Sync: Boolean = True; - ReadWriteSync: Boolean = False): IList; - property Count: Integer read GetCount; - property Key[const Value: Variant]: Variant read GetKey; - property Value[const Key: Variant]: Variant read Get write Put; default; - property Keys: IList read GetKeys; - property Values: IList read GetValues; - end; - - TAbstractMap = class(TInterfacedObject, IMap) - private - FLock: TCriticalSection; - FReadWriteLock: TMultiReadExclusiveWriteSynchronizer; - protected - procedure Assign(const Source: IMap); - function GetCount: Integer; virtual; abstract; - function GetKeys: IList; virtual; abstract; - function GetValues: IList; virtual; abstract; - function GetKey(const Value: Variant): Variant; virtual; abstract; - function Get(const Key: Variant): Variant; virtual; abstract; - procedure Put(const Key, Value: Variant); virtual; abstract; - public - constructor Create(Capacity: Integer = 16; Factor: Single = 0.75; - Sync: Boolean = True; ReadWriteSync: Boolean = False); overload; virtual; abstract; - constructor Create(Sync: Boolean; - ReadWriteSync: Boolean = False); overload; virtual; abstract; - destructor Destroy; override; - procedure Clear; virtual; abstract; - function ContainsKey(const Key: Variant): Boolean; virtual; abstract; - function ContainsValue(const Value: Variant): Boolean; virtual; abstract; - function Delete(const Key: Variant): Variant; virtual; abstract; - function GetEnumerator: IMapEnumerator; virtual; - function Join(const ItemGlue, KeyValueGlue, LeftPad, RightPad: string): - string; virtual; - class function Split(Str: string; const ItemSeparator: string = ';'; - const KeyValueSeparator: string = '='; Limit: Integer = 0; - TrimKey: Boolean = False; TrimValue: Boolean = False; - SkipEmptyKey: Boolean = False; SkipEmptyValue: Boolean = False; - Sync: Boolean = True; ReadWriteSync: Boolean = False): IMap; virtual; - procedure InitLock; - procedure InitReadWriteLock; - procedure Lock; - procedure Unlock; - procedure BeginRead; - procedure EndRead; - function BeginWrite: Boolean; - procedure EndWrite; - procedure PutAll(const AList: IList); overload; virtual; abstract; - procedure PutAll(const AMap: IMap); overload; virtual; abstract; - procedure PutAll(const Container: Variant); overload; virtual; abstract; - function ToList(ListClass: TListClass; Sync: Boolean = True; - ReadWriteSync: Boolean = False): IList; virtual; abstract; - property Count: Integer read GetCount; - property Key[const Value: Variant]: Variant read GetKey; - property Value[const Key: Variant]: Variant read Get write Put; default; - property Keys: IList read GetKeys; - property Values: IList read GetValues; - end; - - TMapClass = class of TAbstractMap; - { function ContainsValue is an O(n) operation in THashMap, - and property Key is also an O(n) operation. They perform - a linear search. THashedMap is faster than THashMap when - do those operations. But THashMap needs less memory than - THashedMap. } - - IHashMap = interface(IMap) - ['{B66C3C4F-3FBB-41FF-B0FA-5E73D87CBE56}'] - end; - - THashMap = class(TAbstractMap, IHashMap) - private - FKeys: IList; - FValues: IList; - protected - function GetCount: Integer; override; - function GetKeys: IList; override; - function GetValues: IList; override; - function GetKey(const Value: Variant): Variant; override; - function Get(const Key: Variant): Variant; override; - procedure Put(const Key, Value: Variant); override; - procedure InitData(Keys, Values: IList); - public - constructor Create(Capacity: Integer = 16; Factor: Single = 0.75; - Sync: Boolean = True; ReadWriteSync: Boolean = False); overload; override; - constructor Create(Sync: Boolean; - ReadWriteSync: Boolean = False); overload; override; -{$IFDEF BCB} - constructor Create0; virtual; - constructor Create1(Capacity: Integer); virtual; - constructor Create2(Capacity: Integer; Factor: Single); virtual; - constructor Create3(Capacity: Integer; Factor: Single; Sync: Boolean); virtual; - constructor CreateS(Sync: Boolean); virtual; -{$ENDIF} - procedure Clear; override; - function ContainsKey(const Key: Variant): Boolean; override; - function ContainsValue(const Value: Variant): Boolean; override; - function Delete(const Key: Variant): Variant; override; - procedure PutAll(const AList: IList); overload; override; - procedure PutAll(const AMap: IMap); overload; override; - procedure PutAll(const Container: Variant); overload; override; - function ToList(ListClass: TListClass; Sync: Boolean = True; - ReadWriteSync: Boolean = False): IList; override; - function ToArrayList(Sync: Boolean = True; - ReadWriteSync: Boolean = False): TArrayList; virtual; - property Key[const Value: Variant]: Variant read GetKey; - property Value[const Key: Variant]: Variant read Get write Put; default; - property Count: Integer read GetCount; - property Keys: IList read GetKeys; - property Values: IList read GetValues; - end; - - { function ContainsValue is an O(1) operation in THashedMap, - and property Key is also an O(1) operation. } - - IHashedMap = interface(IHashMap) - ['{D2598919-07DA-401A-A971-7DB8624E2660}'] - end; - - THashedMap = class(THashMap, IHashedMap) - public - constructor Create(Capacity: Integer = 16; Factor: Single = 0.75; - Sync: Boolean = True; ReadWriteSync: Boolean = False); override; - end; - - ICaseInsensitiveHashMap = interface(IHashMap) - ['{B8F8E5E7-53ED-48BE-B171-2EA2548FCAC7}'] - end; - - TCaseInsensitiveHashMap = class(THashMap, ICaseInsensitiveHashMap) - public - constructor Create(Capacity: Integer = 16; Factor: Single = 0.75; - Sync: Boolean = True; ReadWriteSync: Boolean = False); override; - end; - - ICaseInsensitiveHashedMap = interface(IHashMap) - ['{839DCE08-95DE-462F-B59D-16BA89D3DC6B}'] - end; - - TCaseInsensitiveHashedMap = class(THashMap, ICaseInsensitiveHashedMap) - public - constructor Create(Capacity: Integer = 16; Factor: Single = 0.75; - Sync: Boolean = True; ReadWriteSync: Boolean = False); override; - end; - - TStringBuffer = class(TObject) - private - FDataString: RawByteString; - FPosition: Integer; - FCapacity: Integer; - FLength: Integer; - procedure Grow; - procedure SetPosition(NewPosition: Integer); - procedure SetCapacity(NewCapacity: Integer); - public - constructor Create(Capacity: Integer = 255); overload; - constructor Create(const AString: string); overload; - function Read(var Buffer; Count: Longint): Longint; - function ReadString(Count: Longint): string; - function Write(const Buffer; Count: Longint): Longint; - procedure WriteString(const AString: string); - function Insert(const Buffer; Count: Longint): Longint; - procedure InsertString(const AString: string); - function Seek(Offset: Longint; Origin: Word): Longint; - function ToString: string; {$IFDEF DELPHI2009_UP}override;{$ENDIF}{$IFDEF FPC}override;{$ENDIF} - property Position: Integer read FPosition write SetPosition; - property Length: Integer read FLength; - property Capacity: Integer read FCapacity write SetCapacity; - property DataString: RawByteString read FDataString; - end; -{$IFDEF FPC} -const - varObject = 23; {23 is not used by FreePascal and Delphi, so it's safe.} -{$ELSE} -var - varObject: TVarType; -{$ENDIF} -{$IFDEF DELPHI6} -function FindVarData(const Value: Variant): PVarData; -function VarIsType(const V: Variant; AVarType: TVarType): Boolean; overload; -function VarIsType(const V: Variant; const AVarTypes: array of TVarType): - Boolean; overload; -function VarIsCustom(const V: Variant): Boolean; -function VarIsOrdinal(const V: Variant): Boolean; -function VarIsFloat(const V: Variant): Boolean; -function VarIsNumeric(const V: Variant): Boolean; -function VarIsStr(const V: Variant): Boolean; -function VarIsEmpty(const V: Variant): Boolean; -function VarIsNull(const V: Variant): Boolean; -{$ENDIF} -function VarIsObj(const Value: Variant): Boolean; overload; -function VarIsObj(const Value: Variant; AClass: TClass): Boolean; overload; -function VarToObj(const Value: Variant): TObject; overload; -function VarToObj(const Value: Variant; AClass: TClass): - TObject; overload; -function VarToObj(const Value: Variant; AClass: TClass; out AObject): - Boolean; overload; -function ObjToVar(const Value: TObject): Variant; -function VarEquals(const Left, Right: Variant): Boolean; -function VarRef(const Value: Variant): Variant; -function VarUnref(const Value: Variant): Variant; -function VarIsList(const Value: Variant): Boolean; -function VarIsMap(const Value: Variant): Boolean; -function VarToList(const Value: Variant): IList; -function VarToMap(const Value: Variant): IMap; -function VarIsIntf(const Value: Variant): Boolean; overload; -function VarIsIntf(const Value: Variant; const IID: TGUID): Boolean; overload; -function VarToIntf(const Value: Variant; const IID: TGUID; out AIntf): Boolean; -function IntfToObj(const Intf: IInterface): TObject; - -function CopyVarRec(const Item: TVarRec): TVarRec; -function CreateConstArray(const Elements: array of const): TConstArray; -procedure FinalizeVarRec(var Item: TVarRec); -procedure FinalizeConstArray(var Arr: TConstArray); - -procedure RegisterClass(const AClass: TClass; const Alias: string); overload; -procedure RegisterClass(const AClass: TInterfacedClass; const IID: TGUID; const Alias: string); overload; -function GetClassByAlias(const Alias: string): TClass; -function GetClassAlias(const AClass: TClass): string; -function GetClassByInterface(const IID: TGUID): TClass; -function GetInterfaceByClass(const AClass: TClass): TGUID; - -function ListSplit(ListClass: TListClass; Str: string; - const Separator: string = ','; Limit: Integer = 0; TrimItem: Boolean = False; - SkipEmptyItem: Boolean = False): IList; -function MapSplit(MapClass: TMapClass; Str: string; - const ItemSeparator: string = ';'; const KeyValueSeparator: string = '='; - Limit: Integer = 0; TrimKey: Boolean = False; TrimValue: Boolean = False; - SkipEmptyKey: Boolean = False; SkipEmptyValue: Boolean = False): IMap; - -implementation - -uses RTLConsts, Variants; -{$IFNDEF FPC} -type - - TVarObjectType = class(TCustomVariantType) - public - procedure CastTo(var Dest: TVarData; const Source: TVarData; - const AVarType: TVarType); override; - procedure Clear(var V: TVarData); override; - function CompareOp(const Left, Right: TVarData; - const Operation: TVarOp): Boolean; override; - procedure Copy(var Dest: TVarData; const Source: TVarData; - const Indirect: Boolean); override; - function IsClear(const V: TVarData): Boolean; override; - end; - -var - VarObjectType: TVarObjectType; -{$ENDIF} - -{$IFDEF DELPHI2012_UP} -const -{ Maximum TList size } - MaxListSize = Maxint div 16; -{$ENDIF} - -{$IFDEF DELPHI6} -function FindVarData(const Value: Variant): PVarData; -begin - Result := @TVarData(Value); - while Result.VType = varByRef or varVariant do - Result := PVarData(Result.VPointer); -end; - -function VarIsType(const V: Variant; AVarType: TVarType): Boolean; -begin - Result := FindVarData(V)^.VType = AVarType; -end; - -function VarIsType(const V: Variant; const AVarTypes: array of TVarType): Boolean; -var - I: Integer; -begin - Result := False; - with FindVarData(V)^ do - for I := Low(AVarTypes) to High(AVarTypes) do - if VType = AVarTypes[I] then - begin - Result := True; - Break; - end; -end; - -function VarTypeIsCustom(const AVarType: TVarType): Boolean; -var - LHandler: TCustomVariantType; -begin - Result := FindCustomVariantType(AVarType, LHandler); -end; - -function VarIsCustom(const V: Variant): Boolean; -begin - Result := VarTypeIsCustom(FindVarData(V)^.VType); -end; - -function VarTypeIsOrdinal(const AVarType: TVarType): Boolean; -begin - Result := AVarType in [varSmallInt, varInteger, varBoolean, varShortInt, - varByte, varWord, varLongWord, varInt64]; -end; - -function VarIsOrdinal(const V: Variant): Boolean; -begin - Result := VarTypeIsOrdinal(FindVarData(V)^.VType); -end; - -function VarTypeIsFloat(const AVarType: TVarType): Boolean; -begin - Result := AVarType in [varSingle, varDouble, varCurrency]; -end; - -function VarIsFloat(const V: Variant): Boolean; -begin - Result := VarTypeIsFloat(FindVarData(V)^.VType); -end; - -function VarTypeIsNumeric(const AVarType: TVarType): Boolean; -begin - Result := VarTypeIsOrdinal(AVarType) or VarTypeIsFloat(AVarType); -end; - -function VarIsNumeric(const V: Variant): Boolean; -begin - Result := VarTypeIsNumeric(FindVarData(V)^.VType); -end; - -function VarTypeIsStr(const AVarType: TVarType): Boolean; -begin - Result := (AVarType = varOleStr) or (AVarType = varString); -end; - -function VarIsStr(const V: Variant): Boolean; -begin - Result := VarTypeIsStr(FindVarData(V)^.VType); -end; - -function VarIsEmpty(const V: Variant): Boolean; -begin - Result := FindVarData(V)^.VType = varEmpty; -end; - -function VarIsNull(const V: Variant): Boolean; -begin - Result := FindVarData(V)^.VType = varNull; -end; -{$ENDIF} - -function VarToObj(const Value: Variant): TObject; -begin - Result := nil; - try - with FindVarData(Value)^ do - if VType = varObject then begin - Result := TObject(VPointer); - end - else if VType <> varNull then Error(reInvalidCast); - except - Error(reInvalidCast); - end; -end; - -function VarToObj(const Value: Variant; AClass: TClass): TObject; -begin - Result := nil; - try - with FindVarData(Value)^ do - if VType = varObject then begin - Result := TObject(VPointer); - if not (Result is AClass) then Error(reInvalidCast); - end - else if VType <> varNull then Error(reInvalidCast); - except - Error(reInvalidCast); - end; -end; - -function VarToObj(const Value: Variant; AClass: TClass; out AObject): - Boolean; -var - Obj: TObject absolute AObject; -begin - Obj := nil; - Result := True; - try - with FindVarData(Value)^ do - if VType = varObject then begin - Obj := TObject(VPointer) as AClass; - Result := (Obj <> nil) or (VPointer = nil); - end - else if VType <> varNull then - Result := False; - except - Result := False; - end; -end; - -function ObjToVar(const Value: TObject): Variant; -begin - VarClear(Result); - TVarData(Result).VPointer := Pointer(Value); - TVarData(Result).VType := varObject; -end; - -function VarEquals(const Left, Right: Variant): Boolean; -var - L, R: PVarData; - LA, RA: PVarArray; -begin - Result := False; - L := FindVarData(Left); - R := FindVarData(Right); - if VarIsArray(Left) and VarIsArray(Right) then begin - if (L.VType and varByRef) <> 0 then - LA := PVarArray(L.VPointer^) - else - LA := L.VArray; - if (R.VType and varByRef) <> 0 then - RA := PVarArray(R.VPointer^) - else - RA := R.VArray; - if LA = RA then Result := True; - end - else begin - if (L.VType = varUnknown) and - (R.VType = varUnknown) then - Result := L.VUnknown = R.VUnknown - else if (L.VType = varUnknown or varByRef) and - (R.VType = varUnknown) then - Result := Pointer(L.VPointer^) = R.VUnknown - else if (L.VType = varUnknown) and - (R.VType = varUnknown or varByRef) then - Result := L.VUnknown = Pointer(R.VPointer^) - else if (L.VType = varUnknown or varByRef) and - (R.VType = varUnknown or varByRef) then - Result := Pointer(L.VPointer^) = Pointer(R.VPointer^) - else - try - Result := Left = Right; - except - Result := False; - end; - end; -end; - -function VarRef(const Value: Variant): Variant; -var - VType: TVarType; -begin - if VarIsByRef(Value) then - Result := Value - else if VarIsArray(Value, False) then - Result := VarArrayRef(Value) - else begin - VarClear(Result); - VType := VarType(Value); - if VType in [varSmallint, varInteger, varSingle, varDouble, - varCurrency, varDate, varOleStr, varDispatch, - varError, varBoolean, varUnknown, varShortInt, - varByte ,varWord, varLongWord, varInt64 - {$IFDEF DELPHI2009_UP}, varUInt64{$ENDIF}] then begin - TVarData(Result).VType := VType or varByRef; - TVarData(Result).VPointer := @TVarData(Value).VPointer; - end -{$IFDEF DELPHI6} - else if VType <> varVariant then begin - TVarData(Result).VType := VType or varByRef; - TVarData(Result).VPointer := @TVarData(Value).VPointer; - end -{$ENDIF} - else begin - TVarData(Result).VType := varByRef or varVariant; - TVarData(Result).VPointer := @TVarData(Value); - end; - end; -end; - -function VarUnref(const Value: Variant): Variant; -begin - if not VarIsByRef(Value) then - Result := Value - else begin - VarClear(Result); - with FindVarData(Value)^ do - if (VType and varByRef) = 0 then begin - TVarData(Result).VType := VType; - TVarData(Result).VInt64 := VInt64; - end - else begin - TVarData(Result).VType := VType and (not varByRef); - TVarData(Result).VInt64 := Int64(VPointer^); - end; - end; -end; - -function VarIsObj(const Value: Variant): Boolean; -begin - Result := VarIsObj(Value, TObject); -end; - -function VarIsObj(const Value: Variant; AClass: TClass): Boolean; -begin - Result := True; - try - with FindVarData(Value)^ do - if VType = varObject then - Result := TObject(VPointer) is AClass - else if VType <> varNull then - Result := False; - except - Result := False; - end; -end; - -function VarIsList(const Value: Variant): Boolean; -begin - Result := (FindVarData(Value)^.VType = varUnknown) and - Supports(IInterface(Value), IList) or - VarIsObj(Value, TAbstractList); -end; - -function VarToList(const Value: Variant): IList; -begin - if FindVarData(Value)^.VType = varUnknown then - Supports(IInterface(Value), IList, Result) - else if VarIsObj(Value, TAbstractList) then - VarToObj(Value, TAbstractList, Result) - else - Error(reInvalidCast); -end; - -function VarIsMap(const Value: Variant): Boolean; -begin - Result := (FindVarData(Value)^.VType = varUnknown) and - Supports(IInterface(Value), IMap) or - VarIsObj(Value, TAbstractMap); -end; - -function VarToMap(const Value: Variant): IMap; -begin - if FindVarData(Value)^.VType = varUnknown then - Supports(IInterface(Value), IMap, Result) - else if VarIsObj(Value, TAbstractMap) then - VarToObj(Value, TAbstractMap, Result) - else - Error(reInvalidCast); -end; - -function VarIsIntf(const Value: Variant): Boolean; -begin - Result := (FindVarData(Value)^.VType = varUnknown); -end; - -function VarIsIntf(const Value: Variant; const IID: TGUID): Boolean; -begin - Result := (FindVarData(Value)^.VType = varUnknown) and - Supports(IInterface(Value), IID); -end; - -function VarToIntf(const Value: Variant; const IID: TGUID; out AIntf): Boolean; -begin - if FindVarData(Value)^.VType = varUnknown then - Result := Supports(IInterface(Value), IID, AIntf) - else - Result := false; -end; - -{$ifndef DELPHI2010_UP} -type - TObjectFromInterfaceStub = packed record - Stub: cardinal; - case integer of - 0: (ShortJmp: ShortInt); - 1: (LongJmp: LongInt) - end; - PObjectFromInterfaceStub = ^TObjectFromInterfaceStub; -{$endif} - -function IntfToObj(const Intf: IInterface): TObject; {$ifdef Supports_Inline}inline;{$endif} -begin - if Intf = nil then - result := nil - else begin -{$ifdef DELPHI2010_UP} - result := Intf as TObject; // slower but always working -{$else} - with PObjectFromInterfaceStub(PPointer(PPointer(Intf)^)^)^ do - case Stub of - $04244483: result := Pointer(Integer(Intf) + ShortJmp); - $04244481: result := Pointer(Integer(Intf) + LongJmp); - else result := nil; - end; -{$endif} - end; -end; - -const - htNull = $00000000; - htBoolean = $10000000; - htInteger = $20000000; - htInt64 = $30000000; - htDouble = $40000000; - htOleStr = $50000000; - htDate = $60000000; - htObject = $70000000; - htArray = $80000000; - -function HashOfString(const Value: WideString): Integer; -var - I, N: Integer; -begin - N := Length(Value); - Result := 0; - for I := 1 to N do - Result := ((Result shl 2) or (Result shr 30)) xor Ord(Value[I]); - Result := htOleStr or (Result and $0FFFFFFF); -end; - -function GetHashType(VType: Word): Integer; -begin - case VType of - varEmpty: Result := htNull; - varNull: Result := htNull; - varBoolean: Result := htBoolean; - varByte: Result := htInteger; - varWord: Result := htInteger; - varShortInt: Result := htInteger; - varSmallint: Result := htInteger; - varInteger: Result := htInteger; - varLongWord: Result := htInt64; - varInt64: Result := htInt64; -{$IFDEF DELPHI2009_UP} - varUInt64: Result := htInt64; -{$ENDIF} - varSingle: Result := htDouble; - varDouble: Result := htDouble; - varCurrency: Result := htDouble; - varOleStr: Result := htOleStr; - varDate: Result := htDate; - varUnknown: Result := htObject; - varVariant: Result := htObject; - else - if VType = varObject then - Result := htObject - else - Result := htNull; - end; -end; - -function HashOfVariant(const Value: Variant): Integer; -var - P: PVarData; -begin - P := FindVarData(Value); - case P.VType of - varEmpty: Result := 0; - varNull: Result := 1; - varBoolean: Result := htBoolean or Abs(Integer(P.VBoolean)); - varByte: Result := htInteger or P.VByte; - varWord: Result := htInteger or P.VWord; - varShortInt: Result := htInteger or (P.VShortInt and $FF); - varSmallint: Result := htInteger or (P.VSmallInt and $FFFF); - varInteger: Result := htInteger or (P.VInteger and $0FFFFFFF); - varLongWord: Result := htInt64 or (P.VLongWord and $0FFFFFFF) - xor (not (P.VLongWord shr 3) and $10000000); - varInt64: Result := htInt64 or (P.VInt64 and $0FFFFFFF) - xor (not (P.VInt64 shr 3) and $10000000); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := htInt64 or (P.VUInt64 and $0FFFFFFF) - xor (not (P.VUInt64 shr 3) and $10000000); -{$ENDIF} - varSingle: Result := htDouble or (P.VInteger and $0FFFFFFF); - varDouble: Result := htDouble or ((P.VInteger xor (P.VInt64 shr 32)) - and $0FFFFFFF); - varCurrency: Result := htDouble or ((P.VInteger xor (P.VInt64 shr 32)) - and $0FFFFFFF); - varDate: Result := htDate or ((P.VInteger xor (P.VInt64 shr 32)) - and $0FFFFFFF); - varUnknown: Result := htObject or (P.VInteger and $0FFFFFFF); - varVariant: Result := htObject or (P.VInteger and $0FFFFFFF); - else - if P.VType and varByRef <> 0 then - case P.VType and not varByRef of - varBoolean: Result := htBoolean - or Abs(Integer(PWordBool(P.VPointer)^)); - varByte: Result := htInteger or PByte(P.VPointer)^; - varWord: Result := htInteger or PWord(P.VPointer)^; - varShortInt: Result := htInteger or (PShortInt(P.VPointer)^ and $FF); - varSmallInt: Result := htInteger or (PSmallInt(P.VPointer)^ and $FFFF); - varInteger: Result := htInteger or (PInteger(P.VPointer)^ - and $0FFFFFFF); - varLongWord: Result := htInt64 or (PLongWord(P.VPointer)^ and $0FFFFFFF) - xor (not (PLongWord(P.VPointer)^ shr 3) - and $10000000); - varInt64: Result := htInt64 or (PInt64(P.VPointer)^ and $0FFFFFFF) - xor (not (PInt64(P.VPointer)^ shr 3) - and $10000000); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := htInt64 or (PUInt64(P.VPointer)^ and $0FFFFFFF) - xor (not (PUInt64(P.VPointer)^ shr 3) - and $10000000); -{$ENDIF} - varSingle: Result := htDouble or (PInteger(P.VPointer)^ - and $0FFFFFFF); - varDouble: Result := htDouble or ((PInteger(P.VPointer)^ - xor (PInt64(P.VPointer)^ shr 32)) and $0FFFFFFF); - varCurrency: Result := htDouble or ((PInteger(P.VPointer)^ - xor (PInt64(P.VPointer)^ shr 32)) and $0FFFFFFF); - varDate: Result := htDate or ((PInteger(P.VPointer)^ - xor (PInt64(P.VPointer)^ shr 32)) and $0FFFFFFF); - varUnknown: Result := htObject or (PInteger(P.VPointer)^ - and $0FFFFFFF); - else - if VarIsArray(Value) then - Result := Integer(htArray) or GetHashType(P.VType and varTypeMask) - or (PInteger(P.VPointer)^ and $0FFFFFFF) - else - Result := 0; - end - else if VarIsArray(Value) then - Result := Integer(htArray) or GetHashType(P.VType and varTypeMask) - or (P.VInteger and $0FFFFFFF) - else if P.VType = varObject then - Result := htObject or (P.VInteger and $0FFFFFFF) - else - Result := (P.VInteger xor (P.VInt64 shr 32)) and $0FFFFFFF; - end; -end; - -// Copies a TVarRec and its contents. If the content is referenced -// the value will be copied to a new location and the reference -// updated. -function CopyVarRec(const Item: TVarRec): TVarRec; -var - W: WideString; -begin - // Copy entire TVarRec first - Result := Item; - - // Now handle special cases - case Item.VType of - vtExtended: - begin - New(Result.VExtended); - Result.VExtended^ := Item.VExtended^; - end; - vtString: - begin - New(Result.VString); - Result.VString^ := Item.VString^; - end; - vtPChar: - Result.VPChar := StrNew(Item.VPChar); - // there is no StrNew for PWideChar - vtPWideChar: - begin - W := Item.VPWideChar; - GetMem(Result.VPWideChar, - (Length(W) + 1) * SizeOf(WideChar)); - Move(PWideChar(W)^, Result.VPWideChar^, - (Length(W) + 1) * SizeOf(WideChar)); - end; - // a little trickier: casting to AnsiString will ensure - // reference counting is done properly - vtAnsiString: - begin - // nil out first, so no attempt to decrement - // reference count - Result.VAnsiString := nil; - AnsiString(Result.VAnsiString) := AnsiString(Item.VAnsiString); - end; - vtCurrency: - begin - New(Result.VCurrency); - Result.VCurrency^ := Item.VCurrency^; - end; - vtVariant: - begin - New(Result.VVariant); - Result.VVariant^ := Item.VVariant^; - end; - // casting ensures proper reference counting - vtInterface: - begin - Result.VInterface := nil; - IInterface(Result.VInterface) := IInterface(Item.VInterface); - end; - // casting ensures a proper copy is created - vtWideString: - begin - Result.VWideString := nil; - WideString(Result.VWideString) := WideString(Item.VWideString); - end; - vtInt64: - begin - New(Result.VInt64); - Result.VInt64^ := Item.VInt64^; - end; -{$IFDEF DELPHI2009_UP} - vtUnicodeString: - begin - // nil out first, so no attempt to decrement - // reference count - Result.VUnicodeString := nil; - UnicodeString(Result.VUnicodeString) := UnicodeString(Item.VUnicodeString); - end; -{$ENDIF} -{$IFDEF FPC} - vtQWord: - begin - New(Result.VQWord); - Result.VQWord^ := Item.VQWord^; - end; -{$ENDIF} - // VPointer and VObject don't have proper copy semantics so it - // is impossible to write generic code that copies the contents - end; -end; - -// Creates a TConstArray out of the values given. Uses CopyVarRec -// to make copies of the original elements. -function CreateConstArray(const Elements: array of const): TConstArray; -var - I: Integer; -begin - SetLength(Result, Length(Elements)); - for I := Low(Elements) to High(Elements) do - Result[I] := CopyVarRec(Elements[I]); -end; - - -// TVarRecs created by CopyVarRec must be finalized with this function. -// You should not use it on other TVarRecs. -// use this function on copied TVarRecs only! -procedure FinalizeVarRec(var Item: TVarRec); -begin - case Item.VType of - vtExtended: Dispose(Item.VExtended); - vtString: Dispose(Item.VString); - vtPChar: StrDispose(Item.VPChar); - vtPWideChar: FreeMem(Item.VPWideChar); - vtAnsiString: AnsiString(Item.VAnsiString) := ''; - vtCurrency: Dispose(Item.VCurrency); - vtVariant: Dispose(Item.VVariant); - vtInterface: IInterface(Item.VInterface) := nil; - vtWideString: WideString(Item.VWideString) := ''; - vtInt64: Dispose(Item.VInt64); - {$IFDEF DELPHI2009_UP} - vtUnicodeString: UnicodeString(Item.VUnicodeString) := ''; - {$ENDIF} - {$IFDEF FPC} - vtQWord: Dispose(Item.VQWord); - {$ENDIF} - end; - Item.VPointer := nil; -end; - -// A TConstArray contains TVarRecs that must be finalized. This function -// does that for all items in the array. -procedure FinalizeConstArray(var Arr: TConstArray); -var - I: Integer; -begin - for I := Low(Arr) to High(Arr) do - FinalizeVarRec(Arr[I]); - Finalize(Arr); - Arr := nil; -end; - -type - - TListEnumerator = class(TInterfacedObject, IListEnumerator) - private - FList: IList; - FIndex: Integer; - function GetCurrent: Variant; - public - constructor Create(AList: IList); - function MoveNext: Boolean; - property Current: Variant read GetCurrent; - end; - -{ TListEnumerator } - -constructor TListEnumerator.Create(AList: IList); -begin - FList := AList; - FIndex := -1; -end; - -function TListEnumerator.GetCurrent: Variant; -begin - Result := FList[FIndex]; -end; - -function TListEnumerator.MoveNext: Boolean; -begin - if FIndex < FList.Count - 1 then begin - Inc(FIndex); - Result := True; - end - else - Result := False; -end; - -{ TAbstractList } - -destructor TAbstractList.Destroy; -begin - Clear; - FreeAndNil(FLock); - FreeAndNil(FReadWriteLock); - inherited Destroy; -end; - -procedure TAbstractList.InitLock; -begin - if FLock = nil then - FLock := TCriticalSection.Create; -end; - -procedure TAbstractList.InitReadWriteLock; -begin - if FReadWriteLock = nil then - FReadWriteLock := TMultiReadExclusiveWriteSynchronizer.Create; -end; - -procedure TAbstractList.Lock; -begin - FLock.Acquire; -end; - -procedure TAbstractList.Unlock; -begin - FLock.Release; -end; - -procedure TAbstractList.BeginRead; -begin - FReadWriteLock.BeginRead; -end; - -function TAbstractList.BeginWrite: Boolean; -begin - Result := FReadWriteLock.BeginWrite; -end; - -procedure TAbstractList.EndRead; -begin - FReadWriteLock.EndRead; -end; - -procedure TAbstractList.EndWrite; -begin - FReadWriteLock.EndWrite; -end; - -procedure TAbstractList.Assign(const Source: IList); -var - I: Integer; -begin - Clear; - Capacity := Source.Capacity; - for I := 0 to Source.Count - 1 do Add(Source[I]); -end; - -function TAbstractList.GetEnumerator: IListEnumerator; -begin - Result := TListEnumerator.Create(Self); -end; - -function TAbstractList.Join(const Glue, LeftPad, RightPad: string): string; -var - Buffer: TStringBuffer; - E: IListEnumerator; -begin - if Count = 0 then begin - Result := LeftPad + RightPad; - Exit; - end; - E := GetEnumerator; - Buffer := TStringBuffer.Create(LeftPad); - E.MoveNext; - while True do begin - Buffer.WriteString(VarToStr(E.Current)); - if not E.MoveNext then Break; - Buffer.WriteString(Glue); - end; - Buffer.WriteString(RightPad); - Result := Buffer.ToString; - Buffer.Free; -end; - -class function TAbstractList.Split(Str: string; const Separator: string; - Limit: Integer; TrimItem: Boolean; SkipEmptyItem: Boolean; Sync: Boolean; - ReadWriteSync: Boolean): IList; -var - I, N, L: Integer; - S: string; -begin - if Str = '' then begin - Result := nil; - Exit; - end; - Result := Self.Create(Sync, ReadWriteSync); - L := Length(Separator); - N := 0; - I := L; - while (I > 0) and ((Limit = 0) or (N < Limit - 1)) do begin - I := AnsiPos(Separator, Str); - if I > 0 then begin - S := Copy(Str, 1, I - 1); - if TrimItem then S := Trim(S); - if not SkipEmptyItem or (S <> '') then Result.Add(S); - Str := Copy(Str, I + L, MaxInt); - Inc(N); - end - end; - if TrimItem then Str := Trim(Str); - if not SkipEmptyItem or (Str <> '') then Result.Add(Str); -end; - -{ TArrayList } - -function TArrayList.Add(const Value: Variant): Integer; -begin - Result := FCount; - if FCount = FCapacity then Grow; - FList[Result] := Value; - Inc(FCount); -end; - -procedure TArrayList.AddAll(const AList: IList); -var - TotalCount, I: Integer; -begin - TotalCount := FCount + AList.Count; - if TotalCount > FCapacity then begin - FCapacity := TotalCount; - Grow; - end; - for I := 0 to AList.Count - 1 do Add(AList[I]); -end; - -procedure TArrayList.AddAll(const Container: Variant); -var - I: Integer; -begin - if VarIsList(Container) then begin - AddAll(VarToList(Container)); - end - else if VarIsArray(Container) then begin - for I := VarArrayLowBound(Container, 1) to - VarArrayHighBound(Container, 1) do - Add(Container[I]); - end; -end; - -procedure TArrayList.Clear; -begin - SetLength(FList, 0); - FCount := 0; - FCapacity := 0; -end; - -function TArrayList.Contains(const Value: Variant): Boolean; -begin - Result := IndexOf(Value) > -1; -end; - - -constructor TArrayList.Create(Capacity: Integer; Sync, ReadWriteSync: Boolean); -begin - if Sync then InitLock; - if ReadWriteSync then InitReadWriteLock; - FCapacity := Capacity; - FCount := 0; - SetLength(FList, FCapacity); -end; - -constructor TArrayList.Create(Sync, ReadWriteSync: Boolean); -begin - Create(4, Sync, ReadWriteSync); -end; - -{$IFDEF BCB} -constructor TArrayList.Create0; -begin - Create; -end; -constructor TArrayList.Create1(Capacity: Integer); -begin - Create(Capacity); -end; -constructor TArrayList.Create2(Capacity: Integer; Sync: Boolean); -begin - Create(Capacity, Sync); -end; - -constructor TArrayList.CreateS(Sync: Boolean); -begin - Create(Sync); -end; -{$ENDIF} - -function TArrayList.Delete(Index: Integer): Variant; -begin - if (Index >= 0) and (Index < FCount) then begin - Result := FList[Index]; - Dec(FCount); - - VarClear(FList[Index]); - - if Index < FCount then begin - System.Move(FList[Index + 1], FList[Index], - (FCount - Index) * SizeOf(Variant)); - FillChar(FList[FCount], SizeOf(Variant), 0); - end; - end; -end; - -procedure TArrayList.Exchange(Index1, Index2: Integer); -var - Item: Variant; -begin - if (Index1 < 0) or (Index1 >= FCount) then - raise EArrayListError.CreateResFmt(@SListIndexError, [Index1]); - if (Index2 < 0) or (Index2 >= FCount) then - raise EArrayListError.CreateResFmt(@SListIndexError, [Index2]); - - Item := FList[Index1]; - FList[Index1] := FList[Index2]; - FList[Index2] := Item; -end; - -function TArrayList.Get(Index: Integer): Variant; -begin - if (Index >= 0) and (Index < FCount) then - Result := FList[Index] - else - Result := Unassigned; -end; - -function TArrayList.GetCapacity: Integer; -begin - Result := FCapacity; -end; - -function TArrayList.GetCount: Integer; -begin - Result := FCount; -end; - -procedure TArrayList.Grow; -var - Delta: Integer; -begin - if FCapacity > 64 then - Delta := FCapacity div 4 - else - if FCapacity > 8 then - Delta := 16 - else - Delta := 4; - SetCapacity(FCapacity + Delta); -end; - -function TArrayList.IndexOf(const Value: Variant): Integer; -var - I: Integer; -begin - for I := 0 to FCount - 1 do - if VarEquals(FList[I], Value) then begin - Result := I; - Exit; - end; - Result := -1; -end; - -procedure TArrayList.Insert(Index: Integer; const Value: Variant); -begin - if (Index < 0) or (Index > FCount) then - raise EArrayListError.CreateResFmt(@SListIndexError, [Index]); - if FCount = FCapacity then Grow; - if Index < FCount then begin - System.Move(FList[Index], FList[Index + 1], - (FCount - Index) * SizeOf(Variant)); - FillChar(FList[Index], SizeOf(Variant), 0); - end; - FList[Index] := Value; - Inc(FCount); -end; - -procedure TArrayList.Move(CurIndex, NewIndex: Integer); -var - Value: Variant; -begin - if CurIndex <> NewIndex then begin - if (NewIndex < 0) or (NewIndex >= FCount) then - raise EArrayListError.CreateResFmt(@SListIndexError, [NewIndex]); - Value := Get(CurIndex); - Delete(CurIndex); - Insert(NewIndex, Value); - end; -end; - -procedure TArrayList.Put(Index: Integer; const Value: Variant); -begin - if (Index < 0) or (Index > MaxListSize) then - raise EArrayListError.CreateResFmt(@SListIndexError, [Index]); - - if Index >= FCapacity then begin - FCapacity := Index; - Grow; - end; - if Index >= FCount then FCount := Index + 1; - - FList[Index] := Value; -end; - -function TArrayList.Remove(const Value: Variant): Integer; -begin - Result := IndexOf(Value); - if Result >= 0 then Delete(Result); -end; - -function TArrayList.ToArray: TVariants; -begin - Result := Copy(FList, 0, FCount); -end; - -function TArrayList.ToArray(VarType: TVarType): Variant; -var - I: Integer; -begin - Result := VarArrayCreate([0, FCount - 1], VarType); - for I := 0 to FCount - 1 do Result[I] := FList[I]; -end; - -procedure TArrayList.SetCapacity(NewCapacity: Integer); -begin - if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then - raise EArrayListError.CreateResFmt(@SListCapacityError, [NewCapacity]); - if NewCapacity <> FCapacity then begin - SetLength(FList, NewCapacity); - FCapacity := NewCapacity; - end; -end; - -procedure TArrayList.SetCount(NewCount: Integer); -var - I: Integer; -begin - if (NewCount < 0) or (NewCount > MaxListSize) then - raise EArrayListError.CreateResFmt(@SListCountError, [NewCount]); - - if NewCount > FCapacity then begin - FCapacity := NewCount; - Grow; - end - else if NewCount < FCount then - for I := FCount - 1 downto NewCount do - Delete(I); - - FCount := NewCount; -end; - -{ THashBucket } - -function THashBucket.Add(HashCode, Index: Integer): PHashItem; -var - HashIndex: Integer; -begin - if FCount * FFactor >= FCapacity then Grow; - HashIndex := (HashCode and $7FFFFFFF) mod FCapacity; - System.New(Result); - Result.HashCode := HashCode; - Result.Index := Index; - Result.Next := FIndices[HashIndex]; - FIndices[HashIndex] := Result; - Inc(FCount); -end; - -procedure THashBucket.Clear; -var - I: Integer; - HashItem: PHashItem; -begin - for I := 0 to FCapacity - 1 do begin - while FIndices[I] <> nil do begin - HashItem := FIndices[I].Next; - Dispose(FIndices[I]); - FIndices[I] := HashItem; - end; - end; - FCount := 0; -end; - -constructor THashBucket.Create(Capacity: Integer; Factor: Single); -begin - FCount := 0; - FFactor := Factor; - FCapacity := Capacity; - SetLength(FIndices, FCapacity); -end; - -procedure THashBucket.Delete(HashCode, Index: Integer); -var - HashIndex: Integer; - HashItem, Prev: PHashItem; -begin - HashIndex := (HashCode and $7FFFFFFF) mod FCapacity; - HashItem := FIndices[HashIndex]; - Prev := nil; - while HashItem <> nil do begin - if HashItem.Index = Index then begin - if Prev <> nil then - Prev.Next := HashItem.Next - else - FIndices[HashIndex] := HashItem.Next; - Dispose(HashItem); - Dec(FCount); - Exit; - end; - Prev := HashItem; - HashItem := HashItem.Next; - end; -end; - -destructor THashBucket.Destroy; -begin - Clear; - inherited; -end; - -procedure THashBucket.Grow; -var - Delta: Integer; -begin - if FCapacity > 64 then - Delta := FCapacity div 4 - else - if FCapacity > 8 then - Delta := 16 - else - Delta := 4; - SetCapacity(FCapacity + Delta); -end; - -function THashBucket.IndexOf(HashCode: Integer; const Value: Variant; - CompareProc: TIndexCompareMethod): Integer; -var - HashIndex: Integer; - HashItem: PHashItem; -begin - Result := -1; - HashIndex := (HashCode and $7FFFFFFF) mod FCapacity; - HashItem := FIndices[HashIndex]; - while HashItem <> nil do - if (HashItem.HashCode = HashCode) and - CompareProc(HashItem.Index, Value) then begin - Result := HashItem.Index; - Exit; - end - else - HashItem := HashItem.Next; -end; - -function THashBucket.Modify(OldHashCode, NewHashCode, - Index: Integer): PHashItem; -var - HashIndex: Integer; - Prev: PHashItem; -begin - if OldHashCode = NewHashCode then - Result := nil - else begin - HashIndex := (OldHashCode and $7FFFFFFF) mod FCapacity; - Result := FIndices[HashIndex]; - Prev := nil; - while Result <> nil do begin - if Result.Index = Index then begin - if Prev <> nil then - Prev.Next := Result.Next - else - FIndices[HashIndex] := Result.Next; - Result.HashCode := NewHashCode; - HashIndex := (NewHashCode and $7FFFFFFF) mod FCapacity; - Result.Next := FIndices[HashIndex]; - FIndices[HashIndex] := Result; - Exit; - end; - Prev := Result; - Result := Result.Next; - end; - end; -end; - -procedure THashBucket.SetCapacity(NewCapacity: Integer); -var - HashIndex, I: Integer; - NewIndices: THashItemDynArray; - HashItem, NewHashItem: PHashItem; -begin - if (NewCapacity < 0) or (NewCapacity > MaxListSize) then - raise EHashBucketError.CreateResFmt(@SListCapacityError, [NewCapacity]); - if FCapacity = NewCapacity then Exit; - if NewCapacity = 0 then begin - Clear; - SetLength(FIndices, 0); - FCapacity := 0; - end - else begin - SetLength(NewIndices, NewCapacity); - for I := 0 to FCapacity - 1 do begin - HashItem := FIndices[I]; - while HashItem <> nil do begin - NewHashItem := HashItem; - HashItem := HashItem.Next; - HashIndex := (NewHashItem.HashCode and $7FFFFFFF) mod NewCapacity; - NewHashItem.Next := NewIndices[HashIndex]; - NewIndices[HashIndex] := NewHashItem; - end; - end; - FIndices := NewIndices; - FCapacity := NewCapacity; - end; -end; - -{ THashedList } - -function THashedList.Add(const Value: Variant): Integer; -begin - Result := inherited Add(Value); - FHashBucket.Add(HashOf(Value), Result); -end; - -procedure THashedList.Clear; -begin - inherited; - if FHashBucket <> nil then FHashBucket.Clear; -end; - -constructor THashedList.Create(Capacity: Integer; Sync, ReadWriteSync: Boolean); -begin - Create(Capacity, 0.75, Sync, ReadWriteSync); -end; - -constructor THashedList.Create(Capacity: Integer; Factor: Single; Sync, - ReadWriteSync: Boolean); -begin - inherited Create(Capacity, Sync, ReadWriteSync); - FHashBucket := THashBucket.Create(Capacity, Factor); -end; - -{$IFDEF BCB} -constructor THashedList.Create3(Capacity: Integer; Factor: Single; - Sync: Boolean); -begin - Create(Capacity, Factor, Sync); -end; -{$ENDIF} - -function THashedList.Delete(Index: Integer): Variant; -var - OldHashCode, NewHashCode, I, OldCount: Integer; -begin - OldCount := Count; - Result := inherited Delete(Index); - if (Index >= 0) and (Index < OldCount) then begin - if Index < Count then begin - OldHashCode := HashOf(Result); - for I := Index to Count - 1 do begin - NewHashCode := HashOf(FList[I]); - FHashBucket.Modify(OldHashCode, NewHashCode, I); - OldHashCode := NewHashCode; - end; - end; - FHashBucket.Delete(HashOf(Result), Count); - end; -end; - -destructor THashedList.Destroy; -begin - FreeAndNil(FHashBucket); - inherited; -end; - -procedure THashedList.Exchange(Index1, Index2: Integer); -var - HashCode1, HashCode2: Integer; -begin - HashCode1 := HashOf(Get(Index1)); - HashCode2 := HashOf(Get(Index2)); - if HashCode1 <> HashCode2 then begin - FHashBucket.Modify(HashCode1, HashCode2, Index1); - FHashBucket.Modify(HashCode2, HashCode1, Index2); - end; - - inherited Exchange(Index1, Index2); -end; - -function THashedList.HashOf(const Value: Variant): Integer; -begin - if VarIsStr(Value) then - Result := HashOfString(WideString(Value)) - else - Result := HashOfVariant(Value); -end; - -function THashedList.IndexCompare(Index: Integer; - const Value: Variant): Boolean; -var - Item: Variant; -begin - Item := Get(Index); - if VarIsStr(Item) and VarIsStr(Value) then - Result := WideCompareStr(Item, Value) = 0 - else - Result := VarEquals(Item, Value) -end; - -function THashedList.IndexOf(const Value: Variant): Integer; -begin - Result := FHashBucket.IndexOf(HashOf(Value), Value, IndexCompare); -end; - -procedure THashedList.Insert(Index: Integer; const Value: Variant); -var - NewHashCode, OldHashCode, I, LastIndex: Integer; -begin - LastIndex := Count; - inherited Insert(Index, Value); - - NewHashCode := HashOf(Value); - - if Index < LastIndex then begin - for I := Index to LastIndex - 1 do begin - OldHashCode := HashOf(Get(I + 1)); - FHashBucket.Modify(OldHashCode, NewHashCode, I); - NewHashCode := OldHashCode; - end; - end; - - FHashBucket.Add(NewHashCode, LastIndex); -end; - -procedure THashedList.Put(Index: Integer; const Value: Variant); -var - OldHashCode, NewHashCode: Integer; -begin - OldHashCode := HashOf(Get(Index)); - NewHashCode := HashOf(Value); - - inherited Put(Index, Value); - - if (OldHashCode <> NewHashCode) and - (FHashBucket.Modify(OldHashCode, NewHashCode, Index) = nil) then - FHashBucket.Add(NewHashCode, Index); -end; - -{ TCaseInsensitiveHashedList } -{$IFDEF BCB} -constructor TCaseInsensitiveHashedList.Create4(Capacity: Integer; - Factor: Single; Sync, ReadWriteSync: Boolean); -begin - Create(Capacity, Factor, Sync, ReadWriteSync); -end; -{$ENDIF} - -function TCaseInsensitiveHashedList.HashOf(const Value: Variant): Integer; -begin - if VarIsStr(Value) then - Result := HashOfString(WideLowerCase(Value)) - else - Result := HashOfVariant(Value); -end; - -function TCaseInsensitiveHashedList.IndexCompare(Index: Integer; - const Value: Variant): Boolean; -var - Item: Variant; -begin - Item := Get(Index); - if VarIsStr(Item) and VarIsStr(Value) then - Result := WideCompareText(Item, Value) = 0 - else - Result := VarEquals(Item, Value) -end; - -type - - TMapEnumerator = class(TInterfacedObject, IMapEnumerator) - private - FMap: IMap; - FIndex: Integer; - function GetCurrent: TMapEntry; - public - constructor Create(AMap: IMap); - function MoveNext: Boolean; - property Current: TMapEntry read GetCurrent; - end; - -{ TMapEnumerator } - -constructor TMapEnumerator.Create(AMap: IMap); -begin - FMap := AMap; - FIndex := -1; -end; - -function TMapEnumerator.GetCurrent: TMapEntry; -begin - Result.Key := FMap.Keys[FIndex]; - Result.Value := FMap.Values[FIndex]; -end; - -function TMapEnumerator.MoveNext: Boolean; -begin - if FIndex < FMap.Count - 1 then begin - Inc(FIndex); - Result := True; - end - else - Result := False; -end; - -{ TAbstractMap } - -destructor TAbstractMap.Destroy; -begin - FreeAndNil(FLock); - FreeAndNil(FReadWriteLock); - inherited Destroy; -end; - -function TAbstractMap.GetEnumerator: IMapEnumerator; -begin - Result := TMapEnumerator.Create(Self); -end; - -procedure TAbstractMap.InitLock; -begin - if FLock = nil then - FLock := TCriticalSection.Create; -end; - -procedure TAbstractMap.InitReadWriteLock; -begin - if FReadWriteLock = nil then - FReadWriteLock := TMultiReadExclusiveWriteSynchronizer.Create; -end; - -procedure TAbstractMap.Lock; -begin - FLock.Acquire; -end; - -procedure TAbstractMap.Unlock; -begin - FLock.Release; -end; - -procedure TAbstractMap.BeginRead; -begin - FReadWriteLock.BeginRead; -end; - -function TAbstractMap.BeginWrite: Boolean; -begin - Result := FReadWriteLock.BeginWrite; -end; - -procedure TAbstractMap.EndRead; -begin - FReadWriteLock.EndRead; -end; - -procedure TAbstractMap.EndWrite; -begin - FReadWriteLock.EndWrite; -end; - -procedure TAbstractMap.Assign(const Source: IMap); -begin - Keys.Assign(Source.Keys); - Values.Assign(Source.Values); -end; - -function TAbstractMap.Join(const ItemGlue, KeyValueGlue, LeftPad, - RightPad: string): string; -var - Buffer: TStringBuffer; - E: IMapEnumerator; - Entry: TMapEntry; -begin - if Count = 0 then begin - Result := LeftPad + RightPad; - Exit; - end; - E := GetEnumerator; - Buffer := TStringBuffer.Create(LeftPad); - E.MoveNext; - while True do begin - Entry := E.Current; - Buffer.WriteString(VarToStr(Entry.Key)); - Buffer.WriteString(KeyValueGlue); - Buffer.WriteString(VarToStr(Entry.Value)); - if not E.MoveNext then Break; - Buffer.WriteString(ItemGlue); - end; - Buffer.WriteString(RightPad); - Result := Buffer.ToString; - Buffer.Free; -end; - -class function TAbstractMap.Split(Str: string; const ItemSeparator, - KeyValueSeparator: string; Limit: Integer; TrimKey, TrimValue, - SkipEmptyKey, SkipEmptyValue: Boolean; Sync, ReadWriteSync: Boolean): IMap; - -var - I, L, L2, N: Integer; - -procedure SetKeyValue(const AMap: IMap; const S: string); -var - J: Integer; - Key, Value: string; -begin - if (SkipEmptyKey or SkipEmptyValue) and (S = '') then Exit; - J := AnsiPos(KeyValueSeparator, S); - if J > 0 then begin - Key := Copy(S, 1, J - 1); - if TrimKey then Key := Trim(Key); - Value := Copy(S, J + L2, MaxInt); - if TrimValue then Value := Trim(Value); - if SkipEmptyKey and (Key = '') then Exit; - if SkipEmptyValue and (Value = '') then Exit; - AMap[Key] := Value; - end - else if SkipEmptyValue then - Exit - else if TrimKey then begin - Key := Trim(S); - if SkipEmptyKey and (Key = '') then Exit; - AMap[Key] := ''; - end - else - AMap[S] := ''; -end; - -begin - if Str = '' then begin - Result := nil; - Exit; - end; - Result := Self.Create(Sync, ReadWriteSync); - L := Length(ItemSeparator); - L2 := Length(KeyValueSeparator); - N := 0; - I := L; - while (I > 0) and ((Limit = 0) or (N < Limit - 1)) do begin - I := AnsiPos(ItemSeparator, Str); - if I > 0 then begin - SetKeyValue(Result, Copy(Str, 1, I - 1)); - Str := Copy(Str, I + L, MaxInt); - Inc(N); - end - end; - SetKeyValue(Result, Str); -end; - -{ THashMap } - -procedure THashMap.Clear; -begin - FKeys.Clear; - FValues.Clear; -end; - -function THashMap.ContainsKey(const Key: Variant): Boolean; -begin - Result := FKeys.Contains(Key); -end; - -function THashMap.ContainsValue(const Value: Variant): Boolean; -begin - Result := FValues.Contains(Value); -end; - -constructor THashMap.Create(Capacity: Integer; Factor: Single; Sync, - ReadWriteSync: Boolean); -begin - if Sync then InitLock; - if ReadWriteSync then InitReadWriteLock; - InitData(THashedList.Create(Capacity, Factor, False), - TArrayList.Create(Capacity, False)); -end; - -constructor THashMap.Create(Sync, ReadWriteSync: Boolean); -begin - Create(16, 0.75, Sync, ReadWriteSync); -end; - -{$IFDEF BCB} -constructor THashMap.Create0; -begin - Create; -end; - -constructor THashMap.Create1(Capacity: Integer); -begin - Create(Capacity); -end; - -constructor THashMap.Create2(Capacity: Integer; Factor: Single); -begin - Create(Capacity, Factor); -end; - -constructor THashMap.Create3(Capacity: Integer; Factor: Single; Sync: Boolean); -begin - Create(Capacity, Factor, Sync); -end; - -constructor THashMap.CreateS(Sync: Boolean); -begin - Create(Sync); -end; -{$ENDIF} - -function THashMap.Delete(const Key: Variant): Variant; -begin - Result := FValues.Delete(FKeys.Remove(Key)); -end; - -function THashMap.GetCount: Integer; -begin - Result := FKeys.Count; -end; - -function THashMap.Get(const Key: Variant): Variant; -begin - Result := FValues[FKeys.IndexOf(Key)]; -end; - -function THashMap.GetKey(const Value: Variant): Variant; -begin - Result := FKeys[FValues.IndexOf(Value)]; -end; - -procedure THashMap.InitData(Keys, Values: IList); -begin - FKeys := Keys; - FValues := Values; -end; - -procedure THashMap.PutAll(const AMap: IMap); -var - I: Integer; - K, V: IList; -begin - K := AMap.Keys; - V := AMap.Values; - for I := 0 to AMap.Count - 1 do - Put(K[I], V[I]); -end; - -procedure THashMap.PutAll(const Container: Variant); -var - I: Integer; -begin - if VarIsList(Container) then - PutAll(VarToList(Container)) - else if VarIsMap(Container) then - PutAll(VarToMap(Container)) - else if VarIsArray(Container) then begin - for I := VarArrayLowBound(Container, 1) to - VarArrayHighBound(Container, 1) do - Put(I, Container[I]); - end; -end; - -procedure THashMap.PutAll(const AList: IList); -var - I: Integer; -begin - for I := 0 to AList.Count - 1 do - Put(I, AList[I]); -end; - -procedure THashMap.Put(const Key, Value: Variant); -var - Index: Integer; -begin - Index := FKeys.IndexOf(Key); - if Index > -1 then - FValues[Index] := Value - else - FValues[FKeys.Add(Key)] := Value; -end; - -function THashMap.ToList(ListClass: TListClass; Sync, - ReadWriteSync: Boolean): IList; -var - I: Integer; -begin - Result := ListClass.Create(Count, Sync, ReadWriteSync) as IList; - for I := 0 to Count - 1 do - if (VarIsOrdinal(FKeys[I])) and (FKeys[I] >= 0) - and (FKeys[I] <= MaxListSize) then Result.Put(FKeys[I], FValues[I]); -end; - -function THashMap.ToArrayList(Sync, ReadWriteSync: Boolean): TArrayList; -var - I: Integer; -begin - Result := TArrayList.Create(Count, Sync, ReadWriteSync); - for I := 0 to Count - 1 do - if (VarIsOrdinal(FKeys[I])) and (FKeys[I] >= 0) - and (FKeys[I] <= MaxListSize) then Result.Put(FKeys[I], FValues[I]); -end; - -function THashMap.GetKeys: IList; -begin - Result := FKeys; -end; - -function THashMap.GetValues: IList; -begin - Result := FValues; -end; - -{ THashedMap } - -constructor THashedMap.Create(Capacity: Integer; Factor: Single; - Sync, ReadWriteSync: Boolean); -begin - if Sync then InitLock; - if ReadWriteSync then InitReadWriteLock; - InitData(THashedList.Create(Capacity, Factor, False), - THashedList.Create(Capacity, Factor, False)); -end; - -{ TCaseInsensitiveHashMap } - -constructor TCaseInsensitiveHashMap.Create(Capacity: Integer; Factor: Single; - Sync, ReadWriteSync: Boolean); -begin - if Sync then InitLock; - if ReadWriteSync then InitReadWriteLock; - InitData(TCaseInsensitiveHashedList.Create(Capacity, Factor, False), - TArrayList.Create(Capacity, False)); -end; - -{ TCaseInsensitiveHashedMap } - -constructor TCaseInsensitiveHashedMap.Create(Capacity: Integer; Factor: Single; - Sync, ReadWriteSync: Boolean); -begin - if Sync then InitLock; - if ReadWriteSync then InitReadWriteLock; - InitData(TCaseInsensitiveHashedList.Create(Capacity, Factor, False), - THashedList.Create(Capacity, Factor, False)); -end; - -{ TStringBuffer } - -constructor TStringBuffer.Create(const AString: string); -begin -{$IFDEF DELPHI2009_UP} - FDataString := RawByteString(AString); -{$ELSE} - FDataString := AString; -{$ENDIF} - FLength := System.Length(FDataString); - FCapacity := FLength; - FPosition := FLength; -end; - -constructor TStringBuffer.Create(Capacity: Integer); -begin - FLength := 0; - FPosition := 0; - FCapacity := Capacity; - SetLength(FDataString, Capacity); -end; - -procedure TStringBuffer.Grow; -var - Delta: Integer; -begin - if FCapacity > 64 then - Delta := FCapacity div 4 - else - if FCapacity > 8 then - Delta := 16 - else - Delta := 4; - SetCapacity(FCapacity + Delta); -end; - -function TStringBuffer.Insert(const Buffer; Count: Integer): Longint; -begin - if FPosition = FLength then - Result := Write(Buffer, Count) - else begin - Result := Count; - if (FLength + Result > FCapacity) then begin - FCapacity := FLength + Result; - Grow; - end; - Move(PAnsiChar(@FDataString[FPosition + 1])^, - PAnsiChar(@FDataString[FPosition + Result + 1])^, FLength - FPosition); - Move(Buffer, PAnsiChar(@FDataString[FPosition + 1])^, Result); - Inc(FPosition, Result); - Inc(FLength, Result); - end; -end; - -procedure TStringBuffer.InsertString(const AString: string); -{$IFDEF DELPHI2009_UP} -var - S: RawByteString; -begin - S := RawByteString(AString); - Insert(PAnsiChar(S)^, System.Length(S)); -end; -{$ELSE} -begin - Insert(PAnsiChar(AString)^, System.Length(AString)); -end; -{$ENDIF} - -function TStringBuffer.Read(var Buffer; Count: Integer): Longint; -begin - Result := FLength - FPosition; - if Result > Count then Result := Count; - if Result > 0 then begin - Move(PAnsiChar(@FDataString[FPosition + 1])^, Buffer, Result); - Inc(FPosition, Result); - end - else Result := 0; -end; - -function TStringBuffer.ReadString(Count: Integer): string; -var - Len: Integer; -begin - Len := FLength - FPosition; - if Len > Count then Len := Count; - if Len > 0 then begin - SetString(Result, PAnsiChar(@FDataString[FPosition + 1]), Len); - Inc(FPosition, Len); - end; -end; - -function TStringBuffer.Seek(Offset: Integer; Origin: Word): Longint; -begin - case Origin of - soFromBeginning: FPosition := Offset; - soFromCurrent: FPosition := FPosition + Offset; - soFromEnd: FPosition := FLength - Offset; - end; - if FPosition > FLength then - FPosition := FLength - else if FPosition < 0 then FPosition := 0; - Result := FPosition; -end; - -procedure TStringBuffer.SetCapacity(NewCapacity: Integer); -begin - FCapacity := NewCapacity; - if FLength > NewCapacity then FLength := NewCapacity; - if FPosition > NewCapacity then FPosition := NewCapacity; - SetLength(FDataString, NewCapacity); -end; - -procedure TStringBuffer.SetPosition(NewPosition: Integer); -begin - if NewPosition < 0 then FPosition := 0 - else if NewPosition > FLength then FPosition := FLength - else FPosition := NewPosition; -end; - -function TStringBuffer.ToString: string; -begin - SetString(Result, PAnsiChar(FDataString), FLength); -end; - -function TStringBuffer.Write(const Buffer; Count: Integer): Longint; -begin - Result := Count; - if (FPosition + Result > FCapacity) then begin - FCapacity := FPosition + Result; - Grow; - end; - Move(Buffer, PAnsiChar(@FDataString[FPosition + 1])^, Result); - Inc(FPosition, Result); - if FPosition > FLength then FLength := FPosition; -end; - -procedure TStringBuffer.WriteString(const AString: string); -{$IFDEF DELPHI2009_UP} -var - S: RawByteString; -begin - S := RawByteString(AString); - Write(PAnsiChar(S)^, System.Length(S)); -end; -{$ELSE} -begin - Write(PAnsiChar(AString)^, System.Length(AString)); -end; -{$ENDIF} - -{$IFNDEF FPC} -{ TVarObjectType } - -procedure TVarObjectType.CastTo(var Dest: TVarData; const Source: TVarData; - const AVarType: TVarType); -begin - if (AVarType = varNull) and IsClear(Source) then - Variant(Dest) := Null - else if AVarType = varInteger then - Variant(Dest) := FindVarData(Variant(Source)).VInteger - else if AVarType = varInt64 then - Variant(Dest) := FindVarData(Variant(Source)).VInt64 - else if AVarType = varString then - Variant(Dest) := AnsiString(TObject(FindVarData(Variant(Source)).VPointer).ClassName) -{$IFDEF DELPHI2009_UP} - else if AVarType = varUString then - Variant(Dest) := UnicodeString(TObject(FindVarData(Variant(Source)).VPointer).ClassName) -{$ENDIF} - else if AVarType = varOleStr then - Variant(Dest) := WideString(TObject(FindVarData(Variant(Source)).VPointer).ClassName) - else - RaiseCastError; -end; - -procedure TVarObjectType.Clear(var V: TVarData); -begin - V.VType := varEmpty; - V.VPointer := nil; -end; - -function TVarObjectType.CompareOp(const Left, Right: TVarData; - const Operation: TVarOp): Boolean; -begin - Result := False; - if (Left.VType = varObject) and (Right.VType = varObject) then - case Operation of - opCmpEQ: - Result := Left.VPointer = Right.VPointer; - opCmpNE: - Result := Left.VPointer <> Right.VPointer; - else - RaiseInvalidOp; - end -{$IFDEF DELPHI6} - else if (Left.VType = varObject or varByRef) and - (Right.VType = varObject) then - case Operation of - opCmpEQ: - Result := PPointer(Left.VPointer)^ = Right.VPointer; - opCmpNE: - Result := PPointer(Left.VPointer)^ <> Right.VPointer; - else - RaiseInvalidOp; - end - else if (Left.VType = varObject) and - (Right.VType = varObject or varByRef) then - case Operation of - opCmpEQ: - Result := Left.VPointer = PPointer(Right.VPointer)^; - opCmpNE: - Result := Left.VPointer <> PPointer(Right.VPointer)^; - else - RaiseInvalidOp; - end - else if (Left.VType = varObject or varByRef) and - (Right.VType = varObject or varByRef) then - case Operation of - opCmpEQ: - Result := PPointer(Left.VPointer)^ = PPointer(Right.VPointer)^; - opCmpNE: - Result := PPointer(Left.VPointer)^ <> PPointer(Right.VPointer)^; - else - RaiseInvalidOp; - end -{$ENDIF} - else - case Operation of - opCmpEQ: - Result := False; - opCmpNE: - Result := True; - else - RaiseInvalidOp; - end -end; - -procedure TVarObjectType.Copy(var Dest: TVarData; const Source: TVarData; - const Indirect: Boolean); -begin - if Indirect and VarDataIsByRef(Source) then - VarDataCopyNoInd(Dest, Source) - else - VarDataClear(Dest); - with Dest do - begin - VType := Source.VType; - VPointer := Source.VPointer; - end; -end; - -function TVarObjectType.IsClear(const V: TVarData): Boolean; -begin - Result := V.VPointer = nil; -end; -{$ENDIF} - -var - HproseClassMap: IMap; - HproseInterfaceMap: IMap; - -procedure RegisterClass(const AClass: TClass; const Alias: string); -begin - HproseClassMap.BeginWrite; - try -{$IFDEF CPU64} - HproseClassMap[Alias] := Int64(AClass); -{$ELSE} - HproseClassMap[Alias] := Integer(AClass); -{$ENDIF} - finally - HproseClassMap.EndWrite; - end; -end; - -procedure RegisterClass(const AClass: TInterfacedClass; const IID: TGUID; const Alias: string); -begin - HproseInterfaceMap.BeginWrite; - RegisterClass(AClass, Alias); - try - HproseInterfaceMap[Alias] := GuidToString(IID); - finally - HproseInterfaceMap.EndWrite; - end; -end; - -function GetClassByAlias(const Alias: string): TClass; -begin - HproseClassMap.BeginRead; - try -{$IFDEF CPU64} - Result := TClass(Int64(HproseClassMap[Alias])); -{$ELSE} - Result := TClass(Integer(HproseClassMap[Alias])); -{$ENDIF} - finally - HproseClassMap.EndRead; - end; -end; - -function GetClassAlias(const AClass: TClass): string; -begin - HproseClassMap.BeginRead; - try -{$IFDEF CPU64} - Result := HproseClassMap.Key[Int64(AClass)]; -{$ELSE} - Result := HproseClassMap.Key[Integer(AClass)]; -{$ENDIF} - finally - HproseClassMap.EndRead; - end; -end; - -function GetClassByInterface(const IID: TGUID): TClass; -begin - HproseInterfaceMap.BeginRead; - try - Result := GetClassByAlias(HproseInterfaceMap.Key[GuidToString(IID)]); - finally - HproseInterfaceMap.EndRead; - end; -end; - -function GetInterfaceByClass(const AClass: TClass): TGUID; -begin - HproseInterfaceMap.BeginRead; - try - Result := StringToGuid(HproseInterfaceMap[GetClassAlias(AClass)]); - finally - HproseInterfaceMap.EndRead; - end; -end; - -function ListSplit(ListClass: TListClass; Str: string; - const Separator: string; Limit: Integer; TrimItem: Boolean; - SkipEmptyItem: Boolean): IList; -begin - Result := ListClass.Split(Str, Separator, Limit, TrimItem, SkipEmptyItem); -end; - -function MapSplit(MapClass: TMapClass; Str: string; - const ItemSeparator: string; const KeyValueSeparator: string; - Limit: Integer; TrimKey: Boolean; TrimValue: Boolean; - SkipEmptyKey: Boolean; SkipEmptyValue: Boolean): IMap; -begin - Result := MapClass.Split(Str, ItemSeparator, KeyValueSeparator, Limit, - TrimKey, TrimValue, SkipEmptyKey, SkipEmptyValue); -end; - -initialization - - HproseClassMap := TCaseInsensitiveHashedMap.Create(False, True); - HproseInterfaceMap := TCaseInsensitiveHashedMap.Create(False, True); - RegisterClass(TArrayList, IList, '!List'); - RegisterClass(TArrayList, IArrayList, '!ArrayList'); - RegisterClass(THashedList, IHashedList, '!HashedList'); - RegisterClass(TCaseInsensitiveHashedList, ICaseInsensitiveHashedList, '!CaseInsensitiveHashedList'); - RegisterClass(THashMap, IMap, '!Map'); - RegisterClass(THashMap, IHashMap, '!HashMap'); - RegisterClass(THashedMap, IHashedMap, '!HashedMap'); - RegisterClass(TCaseInsensitiveHashMap, ICaseInsensitiveHashMap, '!CaseInsensitiveHashMap'); - RegisterClass(TCaseInsensitiveHashedMap, ICaseInsensitiveHashedMap, '!CaseInsensitiveHashedMap'); -{$IFNDEF FPC} - VarObjectType := TVarObjectType.Create; - varObject := VarObjectType.VarType; - -finalization - FreeAndNil(VarObjectType); -{$ENDIF} - -end. +{ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * HproseCommon.pas * + * * + * hprose common unit for delphi. * + * * + * LastModified: Dec 28, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +} +unit HproseCommon; + +{$I Hprose.inc} + +interface + +uses Classes, SyncObjs, SysUtils; + +type + +{$IFNDEF DELPHI2009_UP} + RawByteString = type AnsiString; +{$ENDIF} + + THproseResultMode = (Normal, Serialized, Raw, RawWithEndTag); + + TVariants = array of Variant; + PVariants = ^TVariants; + + TConstArray = array of TVarRec; + + EHproseException = class(Exception); + EHashBucketError = class(Exception); + EArrayListError = class(Exception); + + IHproseFilter = interface + ['{4AD7CCF2-1121-4CA4-92A7-5704C5956BA4}'] + function InputFilter(const data: TStream): TStream; + function OutputFilter(const data: TStream): TStream; + end; + + IListEnumerator = interface + ['{767477EC-A143-4DC6-9962-A6837A7AEC01}'] + function GetCurrent: Variant; + function MoveNext: Boolean; + property Current: Variant read GetCurrent; + end; + + IList = interface(IReadWriteSync) + ['{DE925411-42B8-4DB3-A00C-B585C087EC4C}'] + function Get(Index: Integer): Variant; + procedure Put(Index: Integer; const Value: Variant); + function GetCapacity: Integer; + function GetCount: Integer; + procedure SetCapacity(NewCapacity: Integer); + procedure SetCount(NewCount: Integer); + function Add(const Value: Variant): Integer; + procedure AddAll(const ArrayList: IList); overload; + procedure AddAll(const Container: Variant); overload; + procedure Assign(const Source: IList); + procedure Clear; + function Contains(const Value: Variant): Boolean; + function Delete(Index: Integer): Variant; + procedure Exchange(Index1, Index2: Integer); + function GetEnumerator: IListEnumerator; + function IndexOf(const Value: Variant): Integer; + procedure Insert(Index: Integer; const Value: Variant); + function Join(const Glue: string = ','; + const LeftPad: string = ''; + const RightPad: string = ''): string; + procedure InitLock; + procedure InitReadWriteLock; + procedure Lock; + procedure Unlock; + procedure Move(CurIndex, NewIndex: Integer); + function Remove(const Value: Variant): Integer; + function ToArray: TVariants; overload; + function ToArray(VarType: TVarType): Variant; overload; + property Item[Index: Integer]: Variant read Get write Put; default; + property Capacity: Integer read GetCapacity write SetCapacity; + property Count: Integer read GetCount write SetCount; + end; + + TAbstractList = class(TInterfacedObject, IList) + private + FLock: TCriticalSection; + FReadWriteLock: TMultiReadExclusiveWriteSynchronizer; + protected + function Get(Index: Integer): Variant; virtual; abstract; + procedure Put(Index: Integer; const Value: Variant); virtual; abstract; + function GetCapacity: Integer; virtual; abstract; + function GetCount: Integer; virtual; abstract; + procedure SetCapacity(NewCapacity: Integer); virtual; abstract; + procedure SetCount(NewCount: Integer); virtual; abstract; + public + constructor Create(Capacity: Integer = 4; Sync: Boolean = True; + ReadWriteSync: Boolean = False); overload; virtual; abstract; + constructor Create(Sync: Boolean; + ReadWriteSync: Boolean = False); overload; virtual; abstract; + destructor Destroy; override; + function Add(const Value: Variant): Integer; virtual; abstract; + procedure AddAll(const ArrayList: IList); overload; virtual; abstract; + procedure AddAll(const Container: Variant); overload; virtual; abstract; + procedure Assign(const Source: IList); virtual; + procedure Clear; virtual; abstract; + function Contains(const Value: Variant): Boolean; virtual; abstract; + function Delete(Index: Integer): Variant; virtual; abstract; + procedure Exchange(Index1, Index2: Integer); virtual; abstract; + function GetEnumerator: IListEnumerator; virtual; + function IndexOf(const Value: Variant): Integer; virtual; abstract; + procedure Insert(Index: Integer; const Value: Variant); virtual; abstract; + function Join(const Glue, LeftPad, RightPad: string): string; virtual; + class function Split(Str: string; const Separator: string = ','; + Limit: Integer = 0; TrimItem: Boolean = False; + SkipEmptyItem: Boolean = False; Sync: Boolean = True; + ReadWriteSync: Boolean = False): IList; virtual; + procedure InitLock; + procedure InitReadWriteLock; + procedure Lock; + procedure Unlock; + procedure BeginRead; + procedure EndRead; + function BeginWrite: Boolean; + procedure EndWrite; + procedure Move(CurIndex, NewIndex: Integer); virtual; abstract; + function Remove(const Value: Variant): Integer; virtual; abstract; + function ToArray: TVariants; overload; virtual; abstract; + function ToArray(VarType: TVarType): Variant; overload; virtual; abstract; + property Item[Index: Integer]: Variant read Get write Put; default; + property Capacity: Integer read GetCapacity write SetCapacity; + property Count: Integer read GetCount write SetCount; + end; + + TListClass = class of TAbstractList; + + IArrayList = interface(IList) + ['{0D12803C-6B0B-476B-A9E3-C219BF651BD1}'] + end; + + TArrayList = class(TAbstractList, IArrayList) + private + FCount: Integer; + FCapacity: Integer; + FList: TVariants; + protected + function Get(Index: Integer): Variant; override; + procedure Grow; virtual; + procedure Put(Index: Integer; const Value: Variant); override; + function GetCapacity: Integer; override; + function GetCount: Integer; override; + procedure SetCapacity(NewCapacity: Integer); override; + procedure SetCount(NewCount: Integer); override; + public + constructor Create(Capacity: Integer = 4; Sync: Boolean = True; + ReadWriteSync: Boolean = False); overload; override; + constructor Create(Sync: Boolean; + ReadWriteSync: Boolean = False); overload; override; +{$IFDEF BCB} + constructor Create0; virtual; // for C++ Builder + constructor Create1(Capacity: Integer); virtual; // for C++ Builder + constructor Create2(Capacity: Integer; Sync: Boolean); virtual; // for C++ Builder + constructor CreateS(Sync: Boolean); virtual; // for C++ Builder +{$ENDIF} + function Add(const Value: Variant): Integer; override; + procedure AddAll(const AList: IList); overload; override; + procedure AddAll(const Container: Variant); overload; override; + procedure Clear; override; + function Contains(const Value: Variant): Boolean; override; + function Delete(Index: Integer): Variant; override; + procedure Exchange(Index1, Index2: Integer); override; + function IndexOf(const Value: Variant): Integer; override; + procedure Insert(Index: Integer; const Value: Variant); override; + procedure Move(CurIndex, NewIndex: Integer); override; + function Remove(const Value: Variant): Integer; override; + function ToArray: TVariants; overload; override; + function ToArray(VarType: TVarType): Variant; overload; override; + property Item[Index: Integer]: Variant read Get write Put; default; + property Count: Integer read GetCount write SetCount; + property Capacity: Integer read GetCapacity write SetCapacity; + end; + + PHashItem = ^THashItem; + + THashItem = record + Next: PHashItem; + Index: Integer; + HashCode: Integer; + end; + + THashItemDynArray = array of PHashItem; + + TIndexCompareMethod = function (Index: Integer; + const Value: Variant): Boolean of object; + + THashBucket = class(TObject) + private + FCount: Integer; + FFactor: Single; + FCapacity: Integer; + FIndices: THashItemDynArray; + procedure Grow; + procedure SetCapacity(NewCapacity: Integer); + public + constructor Create(Capacity: Integer = 16; Factor: Single = 0.75); + destructor Destroy; override; + function Add(HashCode, Index: Integer): PHashItem; + procedure Clear; + procedure Delete(HashCode, Index: Integer); + function IndexOf(HashCode: Integer; const Value: Variant; + CompareProc: TIndexCompareMethod): Integer; + function Modify(OldHashCode, NewHashCode, Index: Integer): PHashItem; + property Count: Integer read FCount; + property Capacity: Integer read FCapacity write SetCapacity; + end; + + IHashedList = interface(IArrayList) + ['{D2392014-7451-40EF-809E-D25BFB0FA661}'] + end; + + THashedList = class(TArrayList, IHashedList) + private + FHashBucket: THashBucket; + protected + function HashOf(const Value: Variant): Integer; virtual; + function IndexCompare(Index: Integer; const Value: Variant): + Boolean; virtual; + procedure Put(Index: Integer; const Value: Variant); override; + public + constructor Create(Capacity: Integer = 4; Sync: Boolean = True; + ReadWriteSync: Boolean = False); overload; override; + constructor Create(Capacity: Integer; Factor: Single; Sync: Boolean = True; + ReadWriteSync: Boolean = False); reintroduce; overload; virtual; +{$IFDEF BCB} + constructor Create3(Capacity: Integer; Factor: Single; + Sync: Boolean); virtual; // for C++ Builder +{$ENDIF} + destructor Destroy; override; + function Add(const Value: Variant): Integer; override; + procedure Clear; override; + function Delete(Index: Integer): Variant; override; + procedure Exchange(Index1, Index2: Integer); override; + function IndexOf(const Value: Variant): Integer; override; + procedure Insert(Index: Integer; const Value: Variant); override; + end; + + ICaseInsensitiveHashedList = interface(IHashedList) + ['{9ECA15EC-9486-4BF6-AADD-BBD88890FAF8}'] + end; + + TCaseInsensitiveHashedList = class(THashedList, ICaseInsensitiveHashedList) + protected + function HashOf(const Value: Variant): Integer; override; + function IndexCompare(Index: Integer; const Value: Variant): + Boolean; override; +{$IFDEF BCB} + public + constructor Create4(Capacity: Integer; Factor: Single; Sync, + ReadWriteSync: Boolean); virtual; // for C++ Builder +{$ENDIF} + end; + + TMapEntry = record + Key: Variant; + Value: Variant; + end; + + IMapEnumerator = interface + ['{5DE7A194-4476-42A6-A1E7-CB1D20AA7B0A}'] + function GetCurrent: TMapEntry; + function MoveNext: Boolean; + property Current: TMapEntry read GetCurrent; + end; + + IMap = interface(IReadWriteSync) + ['{28B78387-CB07-4C28-B642-09716DAA2170}'] + procedure Assign(const Source: IMap); + function GetCount: Integer; + function GetKeys: IList; + function GetValues: IList; + function GetKey(const Value: Variant): Variant; + function Get(const Key: Variant): Variant; + procedure Put(const Key, Value: Variant); + procedure Clear; + function ContainsKey(const Key: Variant): Boolean; + function ContainsValue(const Value: Variant): Boolean; + function Delete(const Key: Variant): Variant; + function GetEnumerator: IMapEnumerator; + function Join(const ItemGlue: string = ';'; + const KeyValueGlue: string = '='; + const LeftPad: string = ''; + const RightPad: string = ''): string; + procedure InitLock; + procedure InitReadWriteLock; + procedure Lock; + procedure Unlock; + procedure PutAll(const AList: IList); overload; + procedure PutAll(const AMap: IMap); overload; + procedure PutAll(const Container: Variant); overload; + function ToList(ListClass: TListClass; Sync: Boolean = True; + ReadWriteSync: Boolean = False): IList; + property Count: Integer read GetCount; + property Key[const Value: Variant]: Variant read GetKey; + property Value[const Key: Variant]: Variant read Get write Put; default; + property Keys: IList read GetKeys; + property Values: IList read GetValues; + end; + + TAbstractMap = class(TInterfacedObject, IMap) + private + FLock: TCriticalSection; + FReadWriteLock: TMultiReadExclusiveWriteSynchronizer; + protected + procedure Assign(const Source: IMap); + function GetCount: Integer; virtual; abstract; + function GetKeys: IList; virtual; abstract; + function GetValues: IList; virtual; abstract; + function GetKey(const Value: Variant): Variant; virtual; abstract; + function Get(const Key: Variant): Variant; virtual; abstract; + procedure Put(const Key, Value: Variant); virtual; abstract; + public + constructor Create(Capacity: Integer = 16; Factor: Single = 0.75; + Sync: Boolean = True; ReadWriteSync: Boolean = False); overload; virtual; abstract; + constructor Create(Sync: Boolean; + ReadWriteSync: Boolean = False); overload; virtual; abstract; + destructor Destroy; override; + procedure Clear; virtual; abstract; + function ContainsKey(const Key: Variant): Boolean; virtual; abstract; + function ContainsValue(const Value: Variant): Boolean; virtual; abstract; + function Delete(const Key: Variant): Variant; virtual; abstract; + function GetEnumerator: IMapEnumerator; virtual; + function Join(const ItemGlue, KeyValueGlue, LeftPad, RightPad: string): + string; virtual; + class function Split(Str: string; const ItemSeparator: string = ';'; + const KeyValueSeparator: string = '='; Limit: Integer = 0; + TrimKey: Boolean = False; TrimValue: Boolean = False; + SkipEmptyKey: Boolean = False; SkipEmptyValue: Boolean = False; + Sync: Boolean = True; ReadWriteSync: Boolean = False): IMap; virtual; + procedure InitLock; + procedure InitReadWriteLock; + procedure Lock; + procedure Unlock; + procedure BeginRead; + procedure EndRead; + function BeginWrite: Boolean; + procedure EndWrite; + procedure PutAll(const AList: IList); overload; virtual; abstract; + procedure PutAll(const AMap: IMap); overload; virtual; abstract; + procedure PutAll(const Container: Variant); overload; virtual; abstract; + function ToList(ListClass: TListClass; Sync: Boolean = True; + ReadWriteSync: Boolean = False): IList; virtual; abstract; + property Count: Integer read GetCount; + property Key[const Value: Variant]: Variant read GetKey; + property Value[const Key: Variant]: Variant read Get write Put; default; + property Keys: IList read GetKeys; + property Values: IList read GetValues; + end; + + TMapClass = class of TAbstractMap; + { function ContainsValue is an O(n) operation in THashMap, + and property Key is also an O(n) operation. They perform + a linear search. THashedMap is faster than THashMap when + do those operations. But THashMap needs less memory than + THashedMap. } + + IHashMap = interface(IMap) + ['{B66C3C4F-3FBB-41FF-B0FA-5E73D87CBE56}'] + end; + + THashMap = class(TAbstractMap, IHashMap) + private + FKeys: IList; + FValues: IList; + protected + function GetCount: Integer; override; + function GetKeys: IList; override; + function GetValues: IList; override; + function GetKey(const Value: Variant): Variant; override; + function Get(const Key: Variant): Variant; override; + procedure Put(const Key, Value: Variant); override; + procedure InitData(Keys, Values: IList); + public + constructor Create(Capacity: Integer = 16; Factor: Single = 0.75; + Sync: Boolean = True; ReadWriteSync: Boolean = False); overload; override; + constructor Create(Sync: Boolean; + ReadWriteSync: Boolean = False); overload; override; +{$IFDEF BCB} + constructor Create0; virtual; + constructor Create1(Capacity: Integer); virtual; + constructor Create2(Capacity: Integer; Factor: Single); virtual; + constructor Create3(Capacity: Integer; Factor: Single; Sync: Boolean); virtual; + constructor CreateS(Sync: Boolean); virtual; +{$ENDIF} + procedure Clear; override; + function ContainsKey(const Key: Variant): Boolean; override; + function ContainsValue(const Value: Variant): Boolean; override; + function Delete(const Key: Variant): Variant; override; + procedure PutAll(const AList: IList); overload; override; + procedure PutAll(const AMap: IMap); overload; override; + procedure PutAll(const Container: Variant); overload; override; + function ToList(ListClass: TListClass; Sync: Boolean = True; + ReadWriteSync: Boolean = False): IList; override; + function ToArrayList(Sync: Boolean = True; + ReadWriteSync: Boolean = False): TArrayList; virtual; + property Key[const Value: Variant]: Variant read GetKey; + property Value[const Key: Variant]: Variant read Get write Put; default; + property Count: Integer read GetCount; + property Keys: IList read GetKeys; + property Values: IList read GetValues; + end; + + { function ContainsValue is an O(1) operation in THashedMap, + and property Key is also an O(1) operation. } + + IHashedMap = interface(IHashMap) + ['{D2598919-07DA-401A-A971-7DB8624E2660}'] + end; + + THashedMap = class(THashMap, IHashedMap) + public + constructor Create(Capacity: Integer = 16; Factor: Single = 0.75; + Sync: Boolean = True; ReadWriteSync: Boolean = False); override; + end; + + ICaseInsensitiveHashMap = interface(IHashMap) + ['{B8F8E5E7-53ED-48BE-B171-2EA2548FCAC7}'] + end; + + TCaseInsensitiveHashMap = class(THashMap, ICaseInsensitiveHashMap) + public + constructor Create(Capacity: Integer = 16; Factor: Single = 0.75; + Sync: Boolean = True; ReadWriteSync: Boolean = False); override; + end; + + ICaseInsensitiveHashedMap = interface(IHashMap) + ['{839DCE08-95DE-462F-B59D-16BA89D3DC6B}'] + end; + + TCaseInsensitiveHashedMap = class(THashMap, ICaseInsensitiveHashedMap) + public + constructor Create(Capacity: Integer = 16; Factor: Single = 0.75; + Sync: Boolean = True; ReadWriteSync: Boolean = False); override; + end; + + TStringBuffer = class(TObject) + private + FDataString: RawByteString; + FPosition: Integer; + FCapacity: Integer; + FLength: Integer; + procedure Grow; + procedure SetPosition(NewPosition: Integer); + procedure SetCapacity(NewCapacity: Integer); + public + constructor Create(Capacity: Integer = 255); overload; + constructor Create(const AString: string); overload; + function Read(var Buffer; Count: Longint): Longint; + function ReadString(Count: Longint): string; + function Write(const Buffer; Count: Longint): Longint; + procedure WriteString(const AString: string); + function Insert(const Buffer; Count: Longint): Longint; + procedure InsertString(const AString: string); + function Seek(Offset: Longint; Origin: Word): Longint; + function ToString: string; {$IFDEF DELPHI2009_UP}override;{$ENDIF}{$IFDEF FPC}override;{$ENDIF} + property Position: Integer read FPosition write SetPosition; + property Length: Integer read FLength; + property Capacity: Integer read FCapacity write SetCapacity; + property DataString: RawByteString read FDataString; + end; +{$IFDEF FPC} +const + varObject = 23; {23 is not used by FreePascal and Delphi, so it's safe.} +{$ELSE} +var + varObject: TVarType; +{$ENDIF} +{$IFDEF DELPHI6} +function FindVarData(const Value: Variant): PVarData; +function VarIsType(const V: Variant; AVarType: TVarType): Boolean; overload; +function VarIsType(const V: Variant; const AVarTypes: array of TVarType): + Boolean; overload; +function VarIsCustom(const V: Variant): Boolean; +function VarIsOrdinal(const V: Variant): Boolean; +function VarIsFloat(const V: Variant): Boolean; +function VarIsNumeric(const V: Variant): Boolean; +function VarIsStr(const V: Variant): Boolean; +function VarIsEmpty(const V: Variant): Boolean; +function VarIsNull(const V: Variant): Boolean; +{$ENDIF} +function VarIsObj(const Value: Variant): Boolean; overload; +function VarIsObj(const Value: Variant; AClass: TClass): Boolean; overload; +function VarToObj(const Value: Variant): TObject; overload; +function VarToObj(const Value: Variant; AClass: TClass): + TObject; overload; +function VarToObj(const Value: Variant; AClass: TClass; out AObject): + Boolean; overload; +function ObjToVar(const Value: TObject): Variant; +function VarEquals(const Left, Right: Variant): Boolean; +function VarRef(const Value: Variant): Variant; +function VarUnref(const Value: Variant): Variant; +function VarIsList(const Value: Variant): Boolean; +function VarIsMap(const Value: Variant): Boolean; +function VarToList(const Value: Variant): IList; +function VarToMap(const Value: Variant): IMap; +function VarIsIntf(const Value: Variant): Boolean; overload; +function VarIsIntf(const Value: Variant; const IID: TGUID): Boolean; overload; +function VarToIntf(const Value: Variant; const IID: TGUID; out AIntf): Boolean; +function IntfToObj(const Intf: IInterface): TObject; + +function CopyVarRec(const Item: TVarRec): TVarRec; +function CreateConstArray(const Elements: array of const): TConstArray; +procedure FinalizeVarRec(var Item: TVarRec); +procedure FinalizeConstArray(var Arr: TConstArray); + +procedure RegisterClass(const AClass: TClass; const Alias: string); overload; +procedure RegisterClass(const AClass: TInterfacedClass; const IID: TGUID; const Alias: string); overload; +function GetClassByAlias(const Alias: string): TClass; +function GetClassAlias(const AClass: TClass): string; +function GetClassByInterface(const IID: TGUID): TClass; +function GetInterfaceByClass(const AClass: TClass): TGUID; + +function ListSplit(ListClass: TListClass; Str: string; + const Separator: string = ','; Limit: Integer = 0; TrimItem: Boolean = False; + SkipEmptyItem: Boolean = False): IList; +function MapSplit(MapClass: TMapClass; Str: string; + const ItemSeparator: string = ';'; const KeyValueSeparator: string = '='; + Limit: Integer = 0; TrimKey: Boolean = False; TrimValue: Boolean = False; + SkipEmptyKey: Boolean = False; SkipEmptyValue: Boolean = False): IMap; + +implementation + +uses RTLConsts, Variants; +{$IFNDEF FPC} +type + + TVarObjectType = class(TCustomVariantType) + public + procedure CastTo(var Dest: TVarData; const Source: TVarData; + const AVarType: TVarType); override; + procedure Clear(var V: TVarData); override; + function CompareOp(const Left, Right: TVarData; + const Operation: TVarOp): Boolean; override; + procedure Copy(var Dest: TVarData; const Source: TVarData; + const Indirect: Boolean); override; + function IsClear(const V: TVarData): Boolean; override; + end; + +var + VarObjectType: TVarObjectType; +{$ENDIF} + +{$IFDEF DELPHI2012_UP} +const +{ Maximum TList size } + MaxListSize = Maxint div 16; +{$ENDIF} + +{$IFDEF DELPHI6} +function FindVarData(const Value: Variant): PVarData; +begin + Result := @TVarData(Value); + while Result.VType = varByRef or varVariant do + Result := PVarData(Result.VPointer); +end; + +function VarIsType(const V: Variant; AVarType: TVarType): Boolean; +begin + Result := FindVarData(V)^.VType = AVarType; +end; + +function VarIsType(const V: Variant; const AVarTypes: array of TVarType): Boolean; +var + I: Integer; +begin + Result := False; + with FindVarData(V)^ do + for I := Low(AVarTypes) to High(AVarTypes) do + if VType = AVarTypes[I] then + begin + Result := True; + Break; + end; +end; + +function VarTypeIsCustom(const AVarType: TVarType): Boolean; +var + LHandler: TCustomVariantType; +begin + Result := FindCustomVariantType(AVarType, LHandler); +end; + +function VarIsCustom(const V: Variant): Boolean; +begin + Result := VarTypeIsCustom(FindVarData(V)^.VType); +end; + +function VarTypeIsOrdinal(const AVarType: TVarType): Boolean; +begin + Result := AVarType in [varSmallInt, varInteger, varBoolean, varShortInt, + varByte, varWord, varLongWord, varInt64]; +end; + +function VarIsOrdinal(const V: Variant): Boolean; +begin + Result := VarTypeIsOrdinal(FindVarData(V)^.VType); +end; + +function VarTypeIsFloat(const AVarType: TVarType): Boolean; +begin + Result := AVarType in [varSingle, varDouble, varCurrency]; +end; + +function VarIsFloat(const V: Variant): Boolean; +begin + Result := VarTypeIsFloat(FindVarData(V)^.VType); +end; + +function VarTypeIsNumeric(const AVarType: TVarType): Boolean; +begin + Result := VarTypeIsOrdinal(AVarType) or VarTypeIsFloat(AVarType); +end; + +function VarIsNumeric(const V: Variant): Boolean; +begin + Result := VarTypeIsNumeric(FindVarData(V)^.VType); +end; + +function VarTypeIsStr(const AVarType: TVarType): Boolean; +begin + Result := (AVarType = varOleStr) or (AVarType = varString); +end; + +function VarIsStr(const V: Variant): Boolean; +begin + Result := VarTypeIsStr(FindVarData(V)^.VType); +end; + +function VarIsEmpty(const V: Variant): Boolean; +begin + Result := FindVarData(V)^.VType = varEmpty; +end; + +function VarIsNull(const V: Variant): Boolean; +begin + Result := FindVarData(V)^.VType = varNull; +end; +{$ENDIF} + +function VarToObj(const Value: Variant): TObject; +begin + Result := nil; + try + with FindVarData(Value)^ do + if VType = varObject then begin + Result := TObject(VPointer); + end + else if VType <> varNull then Error(reInvalidCast); + except + Error(reInvalidCast); + end; +end; + +function VarToObj(const Value: Variant; AClass: TClass): TObject; +begin + Result := nil; + try + with FindVarData(Value)^ do + if VType = varObject then begin + Result := TObject(VPointer); + if not (Result is AClass) then Error(reInvalidCast); + end + else if VType <> varNull then Error(reInvalidCast); + except + Error(reInvalidCast); + end; +end; + +function VarToObj(const Value: Variant; AClass: TClass; out AObject): + Boolean; +var + Obj: TObject absolute AObject; +begin + Obj := nil; + Result := True; + try + with FindVarData(Value)^ do + if VType = varObject then begin + Obj := TObject(VPointer) as AClass; + Result := (Obj <> nil) or (VPointer = nil); + end + else if VType <> varNull then + Result := False; + except + Result := False; + end; +end; + +function ObjToVar(const Value: TObject): Variant; +begin + VarClear(Result); + TVarData(Result).VPointer := Pointer(Value); + TVarData(Result).VType := varObject; +end; + +function VarEquals(const Left, Right: Variant): Boolean; +var + L, R: PVarData; + LA, RA: PVarArray; +begin + Result := False; + L := FindVarData(Left); + R := FindVarData(Right); + if VarIsArray(Left) and VarIsArray(Right) then begin + if (L.VType and varByRef) <> 0 then + LA := PVarArray(L.VPointer^) + else + LA := L.VArray; + if (R.VType and varByRef) <> 0 then + RA := PVarArray(R.VPointer^) + else + RA := R.VArray; + if LA = RA then Result := True; + end + else begin + if (L.VType = varUnknown) and + (R.VType = varUnknown) then + Result := L.VUnknown = R.VUnknown + else if (L.VType = varUnknown or varByRef) and + (R.VType = varUnknown) then + Result := Pointer(L.VPointer^) = R.VUnknown + else if (L.VType = varUnknown) and + (R.VType = varUnknown or varByRef) then + Result := L.VUnknown = Pointer(R.VPointer^) + else if (L.VType = varUnknown or varByRef) and + (R.VType = varUnknown or varByRef) then + Result := Pointer(L.VPointer^) = Pointer(R.VPointer^) + else + try + Result := Left = Right; + except + Result := False; + end; + end; +end; + +function VarRef(const Value: Variant): Variant; +var + VType: TVarType; +begin + if VarIsByRef(Value) then + Result := Value + else if VarIsArray(Value, False) then + Result := VarArrayRef(Value) + else begin + VarClear(Result); + VType := VarType(Value); + if VType in [varSmallint, varInteger, varSingle, varDouble, + varCurrency, varDate, varOleStr, varDispatch, + varError, varBoolean, varUnknown, varShortInt, + varByte ,varWord, varLongWord, varInt64 + {$IFDEF DELPHI2009_UP}, varUInt64{$ENDIF}] then begin + TVarData(Result).VType := VType or varByRef; + TVarData(Result).VPointer := @TVarData(Value).VPointer; + end +{$IFDEF DELPHI6} + else if VType <> varVariant then begin + TVarData(Result).VType := VType or varByRef; + TVarData(Result).VPointer := @TVarData(Value).VPointer; + end +{$ENDIF} + else begin + TVarData(Result).VType := varByRef or varVariant; + TVarData(Result).VPointer := @TVarData(Value); + end; + end; +end; + +function VarUnref(const Value: Variant): Variant; +begin + if not VarIsByRef(Value) then + Result := Value + else begin + VarClear(Result); + with FindVarData(Value)^ do + if (VType and varByRef) = 0 then begin + TVarData(Result).VType := VType; + TVarData(Result).VInt64 := VInt64; + end + else begin + TVarData(Result).VType := VType and (not varByRef); + TVarData(Result).VInt64 := Int64(VPointer^); + end; + end; +end; + +function VarIsObj(const Value: Variant): Boolean; +begin + Result := VarIsObj(Value, TObject); +end; + +function VarIsObj(const Value: Variant; AClass: TClass): Boolean; +begin + Result := True; + try + with FindVarData(Value)^ do + if VType = varObject then + Result := TObject(VPointer) is AClass + else if VType <> varNull then + Result := False; + except + Result := False; + end; +end; + +function VarIsList(const Value: Variant): Boolean; +begin + Result := (FindVarData(Value)^.VType = varUnknown) and + Supports(IInterface(Value), IList) or + VarIsObj(Value, TAbstractList); +end; + +function VarToList(const Value: Variant): IList; +begin + if FindVarData(Value)^.VType = varUnknown then + Supports(IInterface(Value), IList, Result) + else if VarIsObj(Value, TAbstractList) then + VarToObj(Value, TAbstractList, Result) + else + Error(reInvalidCast); +end; + +function VarIsMap(const Value: Variant): Boolean; +begin + Result := (FindVarData(Value)^.VType = varUnknown) and + Supports(IInterface(Value), IMap) or + VarIsObj(Value, TAbstractMap); +end; + +function VarToMap(const Value: Variant): IMap; +begin + if FindVarData(Value)^.VType = varUnknown then + Supports(IInterface(Value), IMap, Result) + else if VarIsObj(Value, TAbstractMap) then + VarToObj(Value, TAbstractMap, Result) + else + Error(reInvalidCast); +end; + +function VarIsIntf(const Value: Variant): Boolean; +begin + Result := (FindVarData(Value)^.VType = varUnknown); +end; + +function VarIsIntf(const Value: Variant; const IID: TGUID): Boolean; +begin + Result := (FindVarData(Value)^.VType = varUnknown) and + Supports(IInterface(Value), IID); +end; + +function VarToIntf(const Value: Variant; const IID: TGUID; out AIntf): Boolean; +begin + if FindVarData(Value)^.VType = varUnknown then + Result := Supports(IInterface(Value), IID, AIntf) + else + Result := false; +end; + +{$ifndef DELPHI2010_UP} +type + TObjectFromInterfaceStub = packed record + Stub: cardinal; + case integer of + 0: (ShortJmp: ShortInt); + 1: (LongJmp: LongInt) + end; + PObjectFromInterfaceStub = ^TObjectFromInterfaceStub; +{$endif} + +function IntfToObj(const Intf: IInterface): TObject; {$ifdef Supports_Inline}inline;{$endif} +begin + if Intf = nil then + result := nil + else begin +{$ifdef DELPHI2010_UP} + result := Intf as TObject; // slower but always working +{$else} + with PObjectFromInterfaceStub(PPointer(PPointer(Intf)^)^)^ do + case Stub of + $04244483: result := Pointer(Integer(Intf) + ShortJmp); + $04244481: result := Pointer(Integer(Intf) + LongJmp); + else result := nil; + end; +{$endif} + end; +end; + +const + htNull = $00000000; + htBoolean = $10000000; + htInteger = $20000000; + htInt64 = $30000000; + htDouble = $40000000; + htOleStr = $50000000; + htDate = $60000000; + htObject = $70000000; + htArray = $80000000; + +function HashOfString(const Value: WideString): Integer; +var + I, N: Integer; +begin + N := Length(Value); + Result := 0; + for I := 1 to N do + Result := ((Result shl 2) or (Result shr 30)) xor Ord(Value[I]); + Result := htOleStr or (Result and $0FFFFFFF); +end; + +function GetHashType(VType: Word): Integer; +begin + case VType of + varEmpty: Result := htNull; + varNull: Result := htNull; + varBoolean: Result := htBoolean; + varByte: Result := htInteger; + varWord: Result := htInteger; + varShortInt: Result := htInteger; + varSmallint: Result := htInteger; + varInteger: Result := htInteger; + varLongWord: Result := htInt64; + varInt64: Result := htInt64; +{$IFDEF DELPHI2009_UP} + varUInt64: Result := htInt64; +{$ENDIF} + varSingle: Result := htDouble; + varDouble: Result := htDouble; + varCurrency: Result := htDouble; + varOleStr: Result := htOleStr; + varDate: Result := htDate; + varUnknown: Result := htObject; + varVariant: Result := htObject; + else + if VType = varObject then + Result := htObject + else + Result := htNull; + end; +end; + +function HashOfVariant(const Value: Variant): Integer; +var + P: PVarData; +begin + P := FindVarData(Value); + case P.VType of + varEmpty: Result := 0; + varNull: Result := 1; + varBoolean: Result := htBoolean or Abs(Integer(P.VBoolean)); + varByte: Result := htInteger or P.VByte; + varWord: Result := htInteger or P.VWord; + varShortInt: Result := htInteger or (P.VShortInt and $FF); + varSmallint: Result := htInteger or (P.VSmallInt and $FFFF); + varInteger: Result := htInteger or (P.VInteger and $0FFFFFFF); + varLongWord: Result := htInt64 or (P.VLongWord and $0FFFFFFF) + xor (not (P.VLongWord shr 3) and $10000000); + varInt64: Result := htInt64 or (P.VInt64 and $0FFFFFFF) + xor (not (P.VInt64 shr 3) and $10000000); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := htInt64 or (P.VUInt64 and $0FFFFFFF) + xor (not (P.VUInt64 shr 3) and $10000000); +{$ENDIF} + varSingle: Result := htDouble or (P.VInteger and $0FFFFFFF); + varDouble: Result := htDouble or ((P.VInteger xor (P.VInt64 shr 32)) + and $0FFFFFFF); + varCurrency: Result := htDouble or ((P.VInteger xor (P.VInt64 shr 32)) + and $0FFFFFFF); + varDate: Result := htDate or ((P.VInteger xor (P.VInt64 shr 32)) + and $0FFFFFFF); + varUnknown: Result := htObject or (P.VInteger and $0FFFFFFF); + varVariant: Result := htObject or (P.VInteger and $0FFFFFFF); + else + if P.VType and varByRef <> 0 then + case P.VType and not varByRef of + varBoolean: Result := htBoolean + or Abs(Integer(PWordBool(P.VPointer)^)); + varByte: Result := htInteger or PByte(P.VPointer)^; + varWord: Result := htInteger or PWord(P.VPointer)^; + varShortInt: Result := htInteger or (PShortInt(P.VPointer)^ and $FF); + varSmallInt: Result := htInteger or (PSmallInt(P.VPointer)^ and $FFFF); + varInteger: Result := htInteger or (PInteger(P.VPointer)^ + and $0FFFFFFF); + varLongWord: Result := htInt64 or (PLongWord(P.VPointer)^ and $0FFFFFFF) + xor (not (PLongWord(P.VPointer)^ shr 3) + and $10000000); + varInt64: Result := htInt64 or (PInt64(P.VPointer)^ and $0FFFFFFF) + xor (not (PInt64(P.VPointer)^ shr 3) + and $10000000); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := htInt64 or (PUInt64(P.VPointer)^ and $0FFFFFFF) + xor (not (PUInt64(P.VPointer)^ shr 3) + and $10000000); +{$ENDIF} + varSingle: Result := htDouble or (PInteger(P.VPointer)^ + and $0FFFFFFF); + varDouble: Result := htDouble or ((PInteger(P.VPointer)^ + xor (PInt64(P.VPointer)^ shr 32)) and $0FFFFFFF); + varCurrency: Result := htDouble or ((PInteger(P.VPointer)^ + xor (PInt64(P.VPointer)^ shr 32)) and $0FFFFFFF); + varDate: Result := htDate or ((PInteger(P.VPointer)^ + xor (PInt64(P.VPointer)^ shr 32)) and $0FFFFFFF); + varUnknown: Result := htObject or (PInteger(P.VPointer)^ + and $0FFFFFFF); + else + if VarIsArray(Value) then + Result := Integer(htArray) or GetHashType(P.VType and varTypeMask) + or (PInteger(P.VPointer)^ and $0FFFFFFF) + else + Result := 0; + end + else if VarIsArray(Value) then + Result := Integer(htArray) or GetHashType(P.VType and varTypeMask) + or (P.VInteger and $0FFFFFFF) + else if P.VType = varObject then + Result := htObject or (P.VInteger and $0FFFFFFF) + else + Result := (P.VInteger xor (P.VInt64 shr 32)) and $0FFFFFFF; + end; +end; + +// Copies a TVarRec and its contents. If the content is referenced +// the value will be copied to a new location and the reference +// updated. +function CopyVarRec(const Item: TVarRec): TVarRec; +var + W: WideString; +begin + // Copy entire TVarRec first + Result := Item; + + // Now handle special cases + case Item.VType of + vtExtended: + begin + New(Result.VExtended); + Result.VExtended^ := Item.VExtended^; + end; + vtString: + begin + New(Result.VString); + Result.VString^ := Item.VString^; + end; + vtPChar: + Result.VPChar := StrNew(Item.VPChar); + // there is no StrNew for PWideChar + vtPWideChar: + begin + W := Item.VPWideChar; + GetMem(Result.VPWideChar, + (Length(W) + 1) * SizeOf(WideChar)); + Move(PWideChar(W)^, Result.VPWideChar^, + (Length(W) + 1) * SizeOf(WideChar)); + end; + // a little trickier: casting to AnsiString will ensure + // reference counting is done properly + vtAnsiString: + begin + // nil out first, so no attempt to decrement + // reference count + Result.VAnsiString := nil; + AnsiString(Result.VAnsiString) := AnsiString(Item.VAnsiString); + end; + vtCurrency: + begin + New(Result.VCurrency); + Result.VCurrency^ := Item.VCurrency^; + end; + vtVariant: + begin + New(Result.VVariant); + Result.VVariant^ := Item.VVariant^; + end; + // casting ensures proper reference counting + vtInterface: + begin + Result.VInterface := nil; + IInterface(Result.VInterface) := IInterface(Item.VInterface); + end; + // casting ensures a proper copy is created + vtWideString: + begin + Result.VWideString := nil; + WideString(Result.VWideString) := WideString(Item.VWideString); + end; + vtInt64: + begin + New(Result.VInt64); + Result.VInt64^ := Item.VInt64^; + end; +{$IFDEF DELPHI2009_UP} + vtUnicodeString: + begin + // nil out first, so no attempt to decrement + // reference count + Result.VUnicodeString := nil; + UnicodeString(Result.VUnicodeString) := UnicodeString(Item.VUnicodeString); + end; +{$ENDIF} +{$IFDEF FPC} + vtQWord: + begin + New(Result.VQWord); + Result.VQWord^ := Item.VQWord^; + end; +{$ENDIF} + // VPointer and VObject don't have proper copy semantics so it + // is impossible to write generic code that copies the contents + end; +end; + +// Creates a TConstArray out of the values given. Uses CopyVarRec +// to make copies of the original elements. +function CreateConstArray(const Elements: array of const): TConstArray; +var + I: Integer; +begin + SetLength(Result, Length(Elements)); + for I := Low(Elements) to High(Elements) do + Result[I] := CopyVarRec(Elements[I]); +end; + + +// TVarRecs created by CopyVarRec must be finalized with this function. +// You should not use it on other TVarRecs. +// use this function on copied TVarRecs only! +procedure FinalizeVarRec(var Item: TVarRec); +begin + case Item.VType of + vtExtended: Dispose(Item.VExtended); + vtString: Dispose(Item.VString); + vtPChar: StrDispose(Item.VPChar); + vtPWideChar: FreeMem(Item.VPWideChar); + vtAnsiString: AnsiString(Item.VAnsiString) := ''; + vtCurrency: Dispose(Item.VCurrency); + vtVariant: Dispose(Item.VVariant); + vtInterface: IInterface(Item.VInterface) := nil; + vtWideString: WideString(Item.VWideString) := ''; + vtInt64: Dispose(Item.VInt64); + {$IFDEF DELPHI2009_UP} + vtUnicodeString: UnicodeString(Item.VUnicodeString) := ''; + {$ENDIF} + {$IFDEF FPC} + vtQWord: Dispose(Item.VQWord); + {$ENDIF} + end; + Item.VPointer := nil; +end; + +// A TConstArray contains TVarRecs that must be finalized. This function +// does that for all items in the array. +procedure FinalizeConstArray(var Arr: TConstArray); +var + I: Integer; +begin + for I := Low(Arr) to High(Arr) do + FinalizeVarRec(Arr[I]); + Finalize(Arr); + Arr := nil; +end; + +type + + TListEnumerator = class(TInterfacedObject, IListEnumerator) + private + FList: IList; + FIndex: Integer; + function GetCurrent: Variant; + public + constructor Create(AList: IList); + function MoveNext: Boolean; + property Current: Variant read GetCurrent; + end; + +{ TListEnumerator } + +constructor TListEnumerator.Create(AList: IList); +begin + FList := AList; + FIndex := -1; +end; + +function TListEnumerator.GetCurrent: Variant; +begin + Result := FList[FIndex]; +end; + +function TListEnumerator.MoveNext: Boolean; +begin + if FIndex < FList.Count - 1 then begin + Inc(FIndex); + Result := True; + end + else + Result := False; +end; + +{ TAbstractList } + +destructor TAbstractList.Destroy; +begin + Clear; + FreeAndNil(FLock); + FreeAndNil(FReadWriteLock); + inherited Destroy; +end; + +procedure TAbstractList.InitLock; +begin + if FLock = nil then + FLock := TCriticalSection.Create; +end; + +procedure TAbstractList.InitReadWriteLock; +begin + if FReadWriteLock = nil then + FReadWriteLock := TMultiReadExclusiveWriteSynchronizer.Create; +end; + +procedure TAbstractList.Lock; +begin + FLock.Acquire; +end; + +procedure TAbstractList.Unlock; +begin + FLock.Release; +end; + +procedure TAbstractList.BeginRead; +begin + FReadWriteLock.BeginRead; +end; + +function TAbstractList.BeginWrite: Boolean; +begin + Result := FReadWriteLock.BeginWrite; +end; + +procedure TAbstractList.EndRead; +begin + FReadWriteLock.EndRead; +end; + +procedure TAbstractList.EndWrite; +begin + FReadWriteLock.EndWrite; +end; + +procedure TAbstractList.Assign(const Source: IList); +var + I: Integer; +begin + Clear; + Capacity := Source.Capacity; + for I := 0 to Source.Count - 1 do Add(Source[I]); +end; + +function TAbstractList.GetEnumerator: IListEnumerator; +begin + Result := TListEnumerator.Create(Self); +end; + +function TAbstractList.Join(const Glue, LeftPad, RightPad: string): string; +var + Buffer: TStringBuffer; + E: IListEnumerator; +begin + if Count = 0 then begin + Result := LeftPad + RightPad; + Exit; + end; + E := GetEnumerator; + Buffer := TStringBuffer.Create(LeftPad); + E.MoveNext; + while True do begin + Buffer.WriteString(VarToStr(E.Current)); + if not E.MoveNext then Break; + Buffer.WriteString(Glue); + end; + Buffer.WriteString(RightPad); + Result := Buffer.ToString; + Buffer.Free; +end; + +class function TAbstractList.Split(Str: string; const Separator: string; + Limit: Integer; TrimItem: Boolean; SkipEmptyItem: Boolean; Sync: Boolean; + ReadWriteSync: Boolean): IList; +var + I, N, L: Integer; + S: string; +begin + if Str = '' then begin + Result := nil; + Exit; + end; + Result := Self.Create(Sync, ReadWriteSync); + L := Length(Separator); + N := 0; + I := L; + while (I > 0) and ((Limit = 0) or (N < Limit - 1)) do begin + I := AnsiPos(Separator, Str); + if I > 0 then begin + S := Copy(Str, 1, I - 1); + if TrimItem then S := Trim(S); + if not SkipEmptyItem or (S <> '') then Result.Add(S); + Str := Copy(Str, I + L, MaxInt); + Inc(N); + end + end; + if TrimItem then Str := Trim(Str); + if not SkipEmptyItem or (Str <> '') then Result.Add(Str); +end; + +{ TArrayList } + +function TArrayList.Add(const Value: Variant): Integer; +begin + Result := FCount; + if FCount = FCapacity then Grow; + FList[Result] := Value; + Inc(FCount); +end; + +procedure TArrayList.AddAll(const AList: IList); +var + TotalCount, I: Integer; +begin + TotalCount := FCount + AList.Count; + if TotalCount > FCapacity then begin + FCapacity := TotalCount; + Grow; + end; + for I := 0 to AList.Count - 1 do Add(AList[I]); +end; + +procedure TArrayList.AddAll(const Container: Variant); +var + I: Integer; +begin + if VarIsList(Container) then begin + AddAll(VarToList(Container)); + end + else if VarIsArray(Container) then begin + for I := VarArrayLowBound(Container, 1) to + VarArrayHighBound(Container, 1) do + Add(Container[I]); + end; +end; + +procedure TArrayList.Clear; +begin + SetLength(FList, 0); + FCount := 0; + FCapacity := 0; +end; + +function TArrayList.Contains(const Value: Variant): Boolean; +begin + Result := IndexOf(Value) > -1; +end; + + +constructor TArrayList.Create(Capacity: Integer; Sync, ReadWriteSync: Boolean); +begin + if Sync then InitLock; + if ReadWriteSync then InitReadWriteLock; + FCapacity := Capacity; + FCount := 0; + SetLength(FList, FCapacity); +end; + +constructor TArrayList.Create(Sync, ReadWriteSync: Boolean); +begin + Create(4, Sync, ReadWriteSync); +end; + +{$IFDEF BCB} +constructor TArrayList.Create0; +begin + Create; +end; +constructor TArrayList.Create1(Capacity: Integer); +begin + Create(Capacity); +end; +constructor TArrayList.Create2(Capacity: Integer; Sync: Boolean); +begin + Create(Capacity, Sync); +end; + +constructor TArrayList.CreateS(Sync: Boolean); +begin + Create(Sync); +end; +{$ENDIF} + +function TArrayList.Delete(Index: Integer): Variant; +begin + if (Index >= 0) and (Index < FCount) then begin + Result := FList[Index]; + Dec(FCount); + + VarClear(FList[Index]); + + if Index < FCount then begin + System.Move(FList[Index + 1], FList[Index], + (FCount - Index) * SizeOf(Variant)); + FillChar(FList[FCount], SizeOf(Variant), 0); + end; + end; +end; + +procedure TArrayList.Exchange(Index1, Index2: Integer); +var + Item: Variant; +begin + if (Index1 < 0) or (Index1 >= FCount) then + raise EArrayListError.CreateResFmt(@SListIndexError, [Index1]); + if (Index2 < 0) or (Index2 >= FCount) then + raise EArrayListError.CreateResFmt(@SListIndexError, [Index2]); + + Item := FList[Index1]; + FList[Index1] := FList[Index2]; + FList[Index2] := Item; +end; + +function TArrayList.Get(Index: Integer): Variant; +begin + if (Index >= 0) and (Index < FCount) then + Result := FList[Index] + else + Result := Unassigned; +end; + +function TArrayList.GetCapacity: Integer; +begin + Result := FCapacity; +end; + +function TArrayList.GetCount: Integer; +begin + Result := FCount; +end; + +procedure TArrayList.Grow; +var + Delta: Integer; +begin + if FCapacity > 64 then + Delta := FCapacity div 4 + else + if FCapacity > 8 then + Delta := 16 + else + Delta := 4; + SetCapacity(FCapacity + Delta); +end; + +function TArrayList.IndexOf(const Value: Variant): Integer; +var + I: Integer; +begin + for I := 0 to FCount - 1 do + if VarEquals(FList[I], Value) then begin + Result := I; + Exit; + end; + Result := -1; +end; + +procedure TArrayList.Insert(Index: Integer; const Value: Variant); +begin + if (Index < 0) or (Index > FCount) then + raise EArrayListError.CreateResFmt(@SListIndexError, [Index]); + if FCount = FCapacity then Grow; + if Index < FCount then begin + System.Move(FList[Index], FList[Index + 1], + (FCount - Index) * SizeOf(Variant)); + FillChar(FList[Index], SizeOf(Variant), 0); + end; + FList[Index] := Value; + Inc(FCount); +end; + +procedure TArrayList.Move(CurIndex, NewIndex: Integer); +var + Value: Variant; +begin + if CurIndex <> NewIndex then begin + if (NewIndex < 0) or (NewIndex >= FCount) then + raise EArrayListError.CreateResFmt(@SListIndexError, [NewIndex]); + Value := Get(CurIndex); + Delete(CurIndex); + Insert(NewIndex, Value); + end; +end; + +procedure TArrayList.Put(Index: Integer; const Value: Variant); +begin + if (Index < 0) or (Index > MaxListSize) then + raise EArrayListError.CreateResFmt(@SListIndexError, [Index]); + + if Index >= FCapacity then begin + FCapacity := Index; + Grow; + end; + if Index >= FCount then FCount := Index + 1; + + FList[Index] := Value; +end; + +function TArrayList.Remove(const Value: Variant): Integer; +begin + Result := IndexOf(Value); + if Result >= 0 then Delete(Result); +end; + +function TArrayList.ToArray: TVariants; +begin + Result := Copy(FList, 0, FCount); +end; + +function TArrayList.ToArray(VarType: TVarType): Variant; +var + I: Integer; +begin + Result := VarArrayCreate([0, FCount - 1], VarType); + for I := 0 to FCount - 1 do Result[I] := FList[I]; +end; + +procedure TArrayList.SetCapacity(NewCapacity: Integer); +begin + if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then + raise EArrayListError.CreateResFmt(@SListCapacityError, [NewCapacity]); + if NewCapacity <> FCapacity then begin + SetLength(FList, NewCapacity); + FCapacity := NewCapacity; + end; +end; + +procedure TArrayList.SetCount(NewCount: Integer); +var + I: Integer; +begin + if (NewCount < 0) or (NewCount > MaxListSize) then + raise EArrayListError.CreateResFmt(@SListCountError, [NewCount]); + + if NewCount > FCapacity then begin + FCapacity := NewCount; + Grow; + end + else if NewCount < FCount then + for I := FCount - 1 downto NewCount do + Delete(I); + + FCount := NewCount; +end; + +{ THashBucket } + +function THashBucket.Add(HashCode, Index: Integer): PHashItem; +var + HashIndex: Integer; +begin + if FCount * FFactor >= FCapacity then Grow; + HashIndex := (HashCode and $7FFFFFFF) mod FCapacity; + System.New(Result); + Result.HashCode := HashCode; + Result.Index := Index; + Result.Next := FIndices[HashIndex]; + FIndices[HashIndex] := Result; + Inc(FCount); +end; + +procedure THashBucket.Clear; +var + I: Integer; + HashItem: PHashItem; +begin + for I := 0 to FCapacity - 1 do begin + while FIndices[I] <> nil do begin + HashItem := FIndices[I].Next; + Dispose(FIndices[I]); + FIndices[I] := HashItem; + end; + end; + FCount := 0; +end; + +constructor THashBucket.Create(Capacity: Integer; Factor: Single); +begin + FCount := 0; + FFactor := Factor; + FCapacity := Capacity; + SetLength(FIndices, FCapacity); +end; + +procedure THashBucket.Delete(HashCode, Index: Integer); +var + HashIndex: Integer; + HashItem, Prev: PHashItem; +begin + HashIndex := (HashCode and $7FFFFFFF) mod FCapacity; + HashItem := FIndices[HashIndex]; + Prev := nil; + while HashItem <> nil do begin + if HashItem.Index = Index then begin + if Prev <> nil then + Prev.Next := HashItem.Next + else + FIndices[HashIndex] := HashItem.Next; + Dispose(HashItem); + Dec(FCount); + Exit; + end; + Prev := HashItem; + HashItem := HashItem.Next; + end; +end; + +destructor THashBucket.Destroy; +begin + Clear; + inherited; +end; + +procedure THashBucket.Grow; +var + Delta: Integer; +begin + if FCapacity > 64 then + Delta := FCapacity div 4 + else + if FCapacity > 8 then + Delta := 16 + else + Delta := 4; + SetCapacity(FCapacity + Delta); +end; + +function THashBucket.IndexOf(HashCode: Integer; const Value: Variant; + CompareProc: TIndexCompareMethod): Integer; +var + HashIndex: Integer; + HashItem: PHashItem; +begin + Result := -1; + HashIndex := (HashCode and $7FFFFFFF) mod FCapacity; + HashItem := FIndices[HashIndex]; + while HashItem <> nil do + if (HashItem.HashCode = HashCode) and + CompareProc(HashItem.Index, Value) then begin + Result := HashItem.Index; + Exit; + end + else + HashItem := HashItem.Next; +end; + +function THashBucket.Modify(OldHashCode, NewHashCode, + Index: Integer): PHashItem; +var + HashIndex: Integer; + Prev: PHashItem; +begin + if OldHashCode = NewHashCode then + Result := nil + else begin + HashIndex := (OldHashCode and $7FFFFFFF) mod FCapacity; + Result := FIndices[HashIndex]; + Prev := nil; + while Result <> nil do begin + if Result.Index = Index then begin + if Prev <> nil then + Prev.Next := Result.Next + else + FIndices[HashIndex] := Result.Next; + Result.HashCode := NewHashCode; + HashIndex := (NewHashCode and $7FFFFFFF) mod FCapacity; + Result.Next := FIndices[HashIndex]; + FIndices[HashIndex] := Result; + Exit; + end; + Prev := Result; + Result := Result.Next; + end; + end; +end; + +procedure THashBucket.SetCapacity(NewCapacity: Integer); +var + HashIndex, I: Integer; + NewIndices: THashItemDynArray; + HashItem, NewHashItem: PHashItem; +begin + if (NewCapacity < 0) or (NewCapacity > MaxListSize) then + raise EHashBucketError.CreateResFmt(@SListCapacityError, [NewCapacity]); + if FCapacity = NewCapacity then Exit; + if NewCapacity = 0 then begin + Clear; + SetLength(FIndices, 0); + FCapacity := 0; + end + else begin + SetLength(NewIndices, NewCapacity); + for I := 0 to FCapacity - 1 do begin + HashItem := FIndices[I]; + while HashItem <> nil do begin + NewHashItem := HashItem; + HashItem := HashItem.Next; + HashIndex := (NewHashItem.HashCode and $7FFFFFFF) mod NewCapacity; + NewHashItem.Next := NewIndices[HashIndex]; + NewIndices[HashIndex] := NewHashItem; + end; + end; + FIndices := NewIndices; + FCapacity := NewCapacity; + end; +end; + +{ THashedList } + +function THashedList.Add(const Value: Variant): Integer; +begin + Result := inherited Add(Value); + FHashBucket.Add(HashOf(Value), Result); +end; + +procedure THashedList.Clear; +begin + inherited; + if FHashBucket <> nil then FHashBucket.Clear; +end; + +constructor THashedList.Create(Capacity: Integer; Sync, ReadWriteSync: Boolean); +begin + Create(Capacity, 0.75, Sync, ReadWriteSync); +end; + +constructor THashedList.Create(Capacity: Integer; Factor: Single; Sync, + ReadWriteSync: Boolean); +begin + inherited Create(Capacity, Sync, ReadWriteSync); + FHashBucket := THashBucket.Create(Capacity, Factor); +end; + +{$IFDEF BCB} +constructor THashedList.Create3(Capacity: Integer; Factor: Single; + Sync: Boolean); +begin + Create(Capacity, Factor, Sync); +end; +{$ENDIF} + +function THashedList.Delete(Index: Integer): Variant; +var + OldHashCode, NewHashCode, I, OldCount: Integer; +begin + OldCount := Count; + Result := inherited Delete(Index); + if (Index >= 0) and (Index < OldCount) then begin + if Index < Count then begin + OldHashCode := HashOf(Result); + for I := Index to Count - 1 do begin + NewHashCode := HashOf(FList[I]); + FHashBucket.Modify(OldHashCode, NewHashCode, I); + OldHashCode := NewHashCode; + end; + end; + FHashBucket.Delete(HashOf(Result), Count); + end; +end; + +destructor THashedList.Destroy; +begin + FreeAndNil(FHashBucket); + inherited; +end; + +procedure THashedList.Exchange(Index1, Index2: Integer); +var + HashCode1, HashCode2: Integer; +begin + HashCode1 := HashOf(Get(Index1)); + HashCode2 := HashOf(Get(Index2)); + if HashCode1 <> HashCode2 then begin + FHashBucket.Modify(HashCode1, HashCode2, Index1); + FHashBucket.Modify(HashCode2, HashCode1, Index2); + end; + + inherited Exchange(Index1, Index2); +end; + +function THashedList.HashOf(const Value: Variant): Integer; +begin + if VarIsStr(Value) then + Result := HashOfString(WideString(Value)) + else + Result := HashOfVariant(Value); +end; + +function THashedList.IndexCompare(Index: Integer; + const Value: Variant): Boolean; +var + Item: Variant; +begin + Item := Get(Index); + if VarIsStr(Item) and VarIsStr(Value) then + Result := WideCompareStr(Item, Value) = 0 + else + Result := VarEquals(Item, Value) +end; + +function THashedList.IndexOf(const Value: Variant): Integer; +begin + Result := FHashBucket.IndexOf(HashOf(Value), Value, IndexCompare); +end; + +procedure THashedList.Insert(Index: Integer; const Value: Variant); +var + NewHashCode, OldHashCode, I, LastIndex: Integer; +begin + LastIndex := Count; + inherited Insert(Index, Value); + + NewHashCode := HashOf(Value); + + if Index < LastIndex then begin + for I := Index to LastIndex - 1 do begin + OldHashCode := HashOf(Get(I + 1)); + FHashBucket.Modify(OldHashCode, NewHashCode, I); + NewHashCode := OldHashCode; + end; + end; + + FHashBucket.Add(NewHashCode, LastIndex); +end; + +procedure THashedList.Put(Index: Integer; const Value: Variant); +var + OldHashCode, NewHashCode: Integer; +begin + OldHashCode := HashOf(Get(Index)); + NewHashCode := HashOf(Value); + + inherited Put(Index, Value); + + if (OldHashCode <> NewHashCode) and + (FHashBucket.Modify(OldHashCode, NewHashCode, Index) = nil) then + FHashBucket.Add(NewHashCode, Index); +end; + +{ TCaseInsensitiveHashedList } +{$IFDEF BCB} +constructor TCaseInsensitiveHashedList.Create4(Capacity: Integer; + Factor: Single; Sync, ReadWriteSync: Boolean); +begin + Create(Capacity, Factor, Sync, ReadWriteSync); +end; +{$ENDIF} + +function TCaseInsensitiveHashedList.HashOf(const Value: Variant): Integer; +begin + if VarIsStr(Value) then + Result := HashOfString(WideLowerCase(Value)) + else + Result := HashOfVariant(Value); +end; + +function TCaseInsensitiveHashedList.IndexCompare(Index: Integer; + const Value: Variant): Boolean; +var + Item: Variant; +begin + Item := Get(Index); + if VarIsStr(Item) and VarIsStr(Value) then + Result := WideCompareText(Item, Value) = 0 + else + Result := VarEquals(Item, Value) +end; + +type + + TMapEnumerator = class(TInterfacedObject, IMapEnumerator) + private + FMap: IMap; + FIndex: Integer; + function GetCurrent: TMapEntry; + public + constructor Create(AMap: IMap); + function MoveNext: Boolean; + property Current: TMapEntry read GetCurrent; + end; + +{ TMapEnumerator } + +constructor TMapEnumerator.Create(AMap: IMap); +begin + FMap := AMap; + FIndex := -1; +end; + +function TMapEnumerator.GetCurrent: TMapEntry; +begin + Result.Key := FMap.Keys[FIndex]; + Result.Value := FMap.Values[FIndex]; +end; + +function TMapEnumerator.MoveNext: Boolean; +begin + if FIndex < FMap.Count - 1 then begin + Inc(FIndex); + Result := True; + end + else + Result := False; +end; + +{ TAbstractMap } + +destructor TAbstractMap.Destroy; +begin + FreeAndNil(FLock); + FreeAndNil(FReadWriteLock); + inherited Destroy; +end; + +function TAbstractMap.GetEnumerator: IMapEnumerator; +begin + Result := TMapEnumerator.Create(Self); +end; + +procedure TAbstractMap.InitLock; +begin + if FLock = nil then + FLock := TCriticalSection.Create; +end; + +procedure TAbstractMap.InitReadWriteLock; +begin + if FReadWriteLock = nil then + FReadWriteLock := TMultiReadExclusiveWriteSynchronizer.Create; +end; + +procedure TAbstractMap.Lock; +begin + FLock.Acquire; +end; + +procedure TAbstractMap.Unlock; +begin + FLock.Release; +end; + +procedure TAbstractMap.BeginRead; +begin + FReadWriteLock.BeginRead; +end; + +function TAbstractMap.BeginWrite: Boolean; +begin + Result := FReadWriteLock.BeginWrite; +end; + +procedure TAbstractMap.EndRead; +begin + FReadWriteLock.EndRead; +end; + +procedure TAbstractMap.EndWrite; +begin + FReadWriteLock.EndWrite; +end; + +procedure TAbstractMap.Assign(const Source: IMap); +begin + Keys.Assign(Source.Keys); + Values.Assign(Source.Values); +end; + +function TAbstractMap.Join(const ItemGlue, KeyValueGlue, LeftPad, + RightPad: string): string; +var + Buffer: TStringBuffer; + E: IMapEnumerator; + Entry: TMapEntry; +begin + if Count = 0 then begin + Result := LeftPad + RightPad; + Exit; + end; + E := GetEnumerator; + Buffer := TStringBuffer.Create(LeftPad); + E.MoveNext; + while True do begin + Entry := E.Current; + Buffer.WriteString(VarToStr(Entry.Key)); + Buffer.WriteString(KeyValueGlue); + Buffer.WriteString(VarToStr(Entry.Value)); + if not E.MoveNext then Break; + Buffer.WriteString(ItemGlue); + end; + Buffer.WriteString(RightPad); + Result := Buffer.ToString; + Buffer.Free; +end; + +class function TAbstractMap.Split(Str: string; const ItemSeparator, + KeyValueSeparator: string; Limit: Integer; TrimKey, TrimValue, + SkipEmptyKey, SkipEmptyValue: Boolean; Sync, ReadWriteSync: Boolean): IMap; + +var + I, L, L2, N: Integer; + +procedure SetKeyValue(const AMap: IMap; const S: string); +var + J: Integer; + Key, Value: string; +begin + if (SkipEmptyKey or SkipEmptyValue) and (S = '') then Exit; + J := AnsiPos(KeyValueSeparator, S); + if J > 0 then begin + Key := Copy(S, 1, J - 1); + if TrimKey then Key := Trim(Key); + Value := Copy(S, J + L2, MaxInt); + if TrimValue then Value := Trim(Value); + if SkipEmptyKey and (Key = '') then Exit; + if SkipEmptyValue and (Value = '') then Exit; + AMap[Key] := Value; + end + else if SkipEmptyValue then + Exit + else if TrimKey then begin + Key := Trim(S); + if SkipEmptyKey and (Key = '') then Exit; + AMap[Key] := ''; + end + else + AMap[S] := ''; +end; + +begin + if Str = '' then begin + Result := nil; + Exit; + end; + Result := Self.Create(Sync, ReadWriteSync); + L := Length(ItemSeparator); + L2 := Length(KeyValueSeparator); + N := 0; + I := L; + while (I > 0) and ((Limit = 0) or (N < Limit - 1)) do begin + I := AnsiPos(ItemSeparator, Str); + if I > 0 then begin + SetKeyValue(Result, Copy(Str, 1, I - 1)); + Str := Copy(Str, I + L, MaxInt); + Inc(N); + end + end; + SetKeyValue(Result, Str); +end; + +{ THashMap } + +procedure THashMap.Clear; +begin + FKeys.Clear; + FValues.Clear; +end; + +function THashMap.ContainsKey(const Key: Variant): Boolean; +begin + Result := FKeys.Contains(Key); +end; + +function THashMap.ContainsValue(const Value: Variant): Boolean; +begin + Result := FValues.Contains(Value); +end; + +constructor THashMap.Create(Capacity: Integer; Factor: Single; Sync, + ReadWriteSync: Boolean); +begin + if Sync then InitLock; + if ReadWriteSync then InitReadWriteLock; + InitData(THashedList.Create(Capacity, Factor, False), + TArrayList.Create(Capacity, False)); +end; + +constructor THashMap.Create(Sync, ReadWriteSync: Boolean); +begin + Create(16, 0.75, Sync, ReadWriteSync); +end; + +{$IFDEF BCB} +constructor THashMap.Create0; +begin + Create; +end; + +constructor THashMap.Create1(Capacity: Integer); +begin + Create(Capacity); +end; + +constructor THashMap.Create2(Capacity: Integer; Factor: Single); +begin + Create(Capacity, Factor); +end; + +constructor THashMap.Create3(Capacity: Integer; Factor: Single; Sync: Boolean); +begin + Create(Capacity, Factor, Sync); +end; + +constructor THashMap.CreateS(Sync: Boolean); +begin + Create(Sync); +end; +{$ENDIF} + +function THashMap.Delete(const Key: Variant): Variant; +begin + Result := FValues.Delete(FKeys.Remove(Key)); +end; + +function THashMap.GetCount: Integer; +begin + Result := FKeys.Count; +end; + +function THashMap.Get(const Key: Variant): Variant; +begin + Result := FValues[FKeys.IndexOf(Key)]; +end; + +function THashMap.GetKey(const Value: Variant): Variant; +begin + Result := FKeys[FValues.IndexOf(Value)]; +end; + +procedure THashMap.InitData(Keys, Values: IList); +begin + FKeys := Keys; + FValues := Values; +end; + +procedure THashMap.PutAll(const AMap: IMap); +var + I: Integer; + K, V: IList; +begin + K := AMap.Keys; + V := AMap.Values; + for I := 0 to AMap.Count - 1 do + Put(K[I], V[I]); +end; + +procedure THashMap.PutAll(const Container: Variant); +var + I: Integer; +begin + if VarIsList(Container) then + PutAll(VarToList(Container)) + else if VarIsMap(Container) then + PutAll(VarToMap(Container)) + else if VarIsArray(Container) then begin + for I := VarArrayLowBound(Container, 1) to + VarArrayHighBound(Container, 1) do + Put(I, Container[I]); + end; +end; + +procedure THashMap.PutAll(const AList: IList); +var + I: Integer; +begin + for I := 0 to AList.Count - 1 do + Put(I, AList[I]); +end; + +procedure THashMap.Put(const Key, Value: Variant); +var + Index: Integer; +begin + Index := FKeys.IndexOf(Key); + if Index > -1 then + FValues[Index] := Value + else + FValues[FKeys.Add(Key)] := Value; +end; + +function THashMap.ToList(ListClass: TListClass; Sync, + ReadWriteSync: Boolean): IList; +var + I: Integer; +begin + Result := ListClass.Create(Count, Sync, ReadWriteSync) as IList; + for I := 0 to Count - 1 do + if (VarIsOrdinal(FKeys[I])) and (FKeys[I] >= 0) + and (FKeys[I] <= MaxListSize) then Result.Put(FKeys[I], FValues[I]); +end; + +function THashMap.ToArrayList(Sync, ReadWriteSync: Boolean): TArrayList; +var + I: Integer; +begin + Result := TArrayList.Create(Count, Sync, ReadWriteSync); + for I := 0 to Count - 1 do + if (VarIsOrdinal(FKeys[I])) and (FKeys[I] >= 0) + and (FKeys[I] <= MaxListSize) then Result.Put(FKeys[I], FValues[I]); +end; + +function THashMap.GetKeys: IList; +begin + Result := FKeys; +end; + +function THashMap.GetValues: IList; +begin + Result := FValues; +end; + +{ THashedMap } + +constructor THashedMap.Create(Capacity: Integer; Factor: Single; + Sync, ReadWriteSync: Boolean); +begin + if Sync then InitLock; + if ReadWriteSync then InitReadWriteLock; + InitData(THashedList.Create(Capacity, Factor, False), + THashedList.Create(Capacity, Factor, False)); +end; + +{ TCaseInsensitiveHashMap } + +constructor TCaseInsensitiveHashMap.Create(Capacity: Integer; Factor: Single; + Sync, ReadWriteSync: Boolean); +begin + if Sync then InitLock; + if ReadWriteSync then InitReadWriteLock; + InitData(TCaseInsensitiveHashedList.Create(Capacity, Factor, False), + TArrayList.Create(Capacity, False)); +end; + +{ TCaseInsensitiveHashedMap } + +constructor TCaseInsensitiveHashedMap.Create(Capacity: Integer; Factor: Single; + Sync, ReadWriteSync: Boolean); +begin + if Sync then InitLock; + if ReadWriteSync then InitReadWriteLock; + InitData(TCaseInsensitiveHashedList.Create(Capacity, Factor, False), + THashedList.Create(Capacity, Factor, False)); +end; + +{ TStringBuffer } + +constructor TStringBuffer.Create(const AString: string); +begin +{$IFDEF DELPHI2009_UP} + FDataString := RawByteString(AString); +{$ELSE} + FDataString := AString; +{$ENDIF} + FLength := System.Length(FDataString); + FCapacity := FLength; + FPosition := FLength; +end; + +constructor TStringBuffer.Create(Capacity: Integer); +begin + FLength := 0; + FPosition := 0; + FCapacity := Capacity; + SetLength(FDataString, Capacity); +end; + +procedure TStringBuffer.Grow; +var + Delta: Integer; +begin + if FCapacity > 64 then + Delta := FCapacity div 4 + else + if FCapacity > 8 then + Delta := 16 + else + Delta := 4; + SetCapacity(FCapacity + Delta); +end; + +function TStringBuffer.Insert(const Buffer; Count: Integer): Longint; +begin + if FPosition = FLength then + Result := Write(Buffer, Count) + else begin + Result := Count; + if (FLength + Result > FCapacity) then begin + FCapacity := FLength + Result; + Grow; + end; + Move(PAnsiChar(@FDataString[FPosition + 1])^, + PAnsiChar(@FDataString[FPosition + Result + 1])^, FLength - FPosition); + Move(Buffer, PAnsiChar(@FDataString[FPosition + 1])^, Result); + Inc(FPosition, Result); + Inc(FLength, Result); + end; +end; + +procedure TStringBuffer.InsertString(const AString: string); +{$IFDEF DELPHI2009_UP} +var + S: RawByteString; +begin + S := RawByteString(AString); + Insert(PAnsiChar(S)^, System.Length(S)); +end; +{$ELSE} +begin + Insert(PAnsiChar(AString)^, System.Length(AString)); +end; +{$ENDIF} + +function TStringBuffer.Read(var Buffer; Count: Integer): Longint; +begin + Result := FLength - FPosition; + if Result > Count then Result := Count; + if Result > 0 then begin + Move(PAnsiChar(@FDataString[FPosition + 1])^, Buffer, Result); + Inc(FPosition, Result); + end + else Result := 0; +end; + +function TStringBuffer.ReadString(Count: Integer): string; +var + Len: Integer; +begin + Len := FLength - FPosition; + if Len > Count then Len := Count; + if Len > 0 then begin + SetString(Result, PAnsiChar(@FDataString[FPosition + 1]), Len); + Inc(FPosition, Len); + end; +end; + +function TStringBuffer.Seek(Offset: Integer; Origin: Word): Longint; +begin + case Origin of + soFromBeginning: FPosition := Offset; + soFromCurrent: FPosition := FPosition + Offset; + soFromEnd: FPosition := FLength - Offset; + end; + if FPosition > FLength then + FPosition := FLength + else if FPosition < 0 then FPosition := 0; + Result := FPosition; +end; + +procedure TStringBuffer.SetCapacity(NewCapacity: Integer); +begin + FCapacity := NewCapacity; + if FLength > NewCapacity then FLength := NewCapacity; + if FPosition > NewCapacity then FPosition := NewCapacity; + SetLength(FDataString, NewCapacity); +end; + +procedure TStringBuffer.SetPosition(NewPosition: Integer); +begin + if NewPosition < 0 then FPosition := 0 + else if NewPosition > FLength then FPosition := FLength + else FPosition := NewPosition; +end; + +function TStringBuffer.ToString: string; +begin + SetString(Result, PAnsiChar(FDataString), FLength); +end; + +function TStringBuffer.Write(const Buffer; Count: Integer): Longint; +begin + Result := Count; + if (FPosition + Result > FCapacity) then begin + FCapacity := FPosition + Result; + Grow; + end; + Move(Buffer, PAnsiChar(@FDataString[FPosition + 1])^, Result); + Inc(FPosition, Result); + if FPosition > FLength then FLength := FPosition; +end; + +procedure TStringBuffer.WriteString(const AString: string); +{$IFDEF DELPHI2009_UP} +var + S: RawByteString; +begin + S := RawByteString(AString); + Write(PAnsiChar(S)^, System.Length(S)); +end; +{$ELSE} +begin + Write(PAnsiChar(AString)^, System.Length(AString)); +end; +{$ENDIF} + +{$IFNDEF FPC} +{ TVarObjectType } + +procedure TVarObjectType.CastTo(var Dest: TVarData; const Source: TVarData; + const AVarType: TVarType); +begin + if (AVarType = varNull) and IsClear(Source) then + Variant(Dest) := Null + else if AVarType = varInteger then + Variant(Dest) := FindVarData(Variant(Source)).VInteger + else if AVarType = varInt64 then + Variant(Dest) := FindVarData(Variant(Source)).VInt64 + else if AVarType = varString then + Variant(Dest) := AnsiString(TObject(FindVarData(Variant(Source)).VPointer).ClassName) +{$IFDEF DELPHI2009_UP} + else if AVarType = varUString then + Variant(Dest) := UnicodeString(TObject(FindVarData(Variant(Source)).VPointer).ClassName) +{$ENDIF} + else if AVarType = varOleStr then + Variant(Dest) := WideString(TObject(FindVarData(Variant(Source)).VPointer).ClassName) + else + RaiseCastError; +end; + +procedure TVarObjectType.Clear(var V: TVarData); +begin + V.VType := varEmpty; + V.VPointer := nil; +end; + +function TVarObjectType.CompareOp(const Left, Right: TVarData; + const Operation: TVarOp): Boolean; +begin + Result := False; + if (Left.VType = varObject) and (Right.VType = varObject) then + case Operation of + opCmpEQ: + Result := Left.VPointer = Right.VPointer; + opCmpNE: + Result := Left.VPointer <> Right.VPointer; + else + RaiseInvalidOp; + end +{$IFDEF DELPHI6} + else if (Left.VType = varObject or varByRef) and + (Right.VType = varObject) then + case Operation of + opCmpEQ: + Result := PPointer(Left.VPointer)^ = Right.VPointer; + opCmpNE: + Result := PPointer(Left.VPointer)^ <> Right.VPointer; + else + RaiseInvalidOp; + end + else if (Left.VType = varObject) and + (Right.VType = varObject or varByRef) then + case Operation of + opCmpEQ: + Result := Left.VPointer = PPointer(Right.VPointer)^; + opCmpNE: + Result := Left.VPointer <> PPointer(Right.VPointer)^; + else + RaiseInvalidOp; + end + else if (Left.VType = varObject or varByRef) and + (Right.VType = varObject or varByRef) then + case Operation of + opCmpEQ: + Result := PPointer(Left.VPointer)^ = PPointer(Right.VPointer)^; + opCmpNE: + Result := PPointer(Left.VPointer)^ <> PPointer(Right.VPointer)^; + else + RaiseInvalidOp; + end +{$ENDIF} + else + case Operation of + opCmpEQ: + Result := False; + opCmpNE: + Result := True; + else + RaiseInvalidOp; + end +end; + +procedure TVarObjectType.Copy(var Dest: TVarData; const Source: TVarData; + const Indirect: Boolean); +begin + if Indirect and VarDataIsByRef(Source) then + VarDataCopyNoInd(Dest, Source) + else + VarDataClear(Dest); + with Dest do + begin + VType := Source.VType; + VPointer := Source.VPointer; + end; +end; + +function TVarObjectType.IsClear(const V: TVarData): Boolean; +begin + Result := V.VPointer = nil; +end; +{$ENDIF} + +var + HproseClassMap: IMap; + HproseInterfaceMap: IMap; + +procedure RegisterClass(const AClass: TClass; const Alias: string); +begin + HproseClassMap.BeginWrite; + try +{$IFDEF CPU64} + HproseClassMap[Alias] := Int64(AClass); +{$ELSE} + HproseClassMap[Alias] := Integer(AClass); +{$ENDIF} + finally + HproseClassMap.EndWrite; + end; +end; + +procedure RegisterClass(const AClass: TInterfacedClass; const IID: TGUID; const Alias: string); +begin + HproseInterfaceMap.BeginWrite; + RegisterClass(AClass, Alias); + try + HproseInterfaceMap[Alias] := GuidToString(IID); + finally + HproseInterfaceMap.EndWrite; + end; +end; + +function GetClassByAlias(const Alias: string): TClass; +begin + HproseClassMap.BeginRead; + try +{$IFDEF CPU64} + Result := TClass(Int64(HproseClassMap[Alias])); +{$ELSE} + Result := TClass(Integer(HproseClassMap[Alias])); +{$ENDIF} + finally + HproseClassMap.EndRead; + end; +end; + +function GetClassAlias(const AClass: TClass): string; +begin + HproseClassMap.BeginRead; + try +{$IFDEF CPU64} + Result := HproseClassMap.Key[Int64(AClass)]; +{$ELSE} + Result := HproseClassMap.Key[Integer(AClass)]; +{$ENDIF} + finally + HproseClassMap.EndRead; + end; +end; + +function GetClassByInterface(const IID: TGUID): TClass; +begin + HproseInterfaceMap.BeginRead; + try + Result := GetClassByAlias(HproseInterfaceMap.Key[GuidToString(IID)]); + finally + HproseInterfaceMap.EndRead; + end; +end; + +function GetInterfaceByClass(const AClass: TClass): TGUID; +begin + HproseInterfaceMap.BeginRead; + try + Result := StringToGuid(HproseInterfaceMap[GetClassAlias(AClass)]); + finally + HproseInterfaceMap.EndRead; + end; +end; + +function ListSplit(ListClass: TListClass; Str: string; + const Separator: string; Limit: Integer; TrimItem: Boolean; + SkipEmptyItem: Boolean): IList; +begin + Result := ListClass.Split(Str, Separator, Limit, TrimItem, SkipEmptyItem); +end; + +function MapSplit(MapClass: TMapClass; Str: string; + const ItemSeparator: string; const KeyValueSeparator: string; + Limit: Integer; TrimKey: Boolean; TrimValue: Boolean; + SkipEmptyKey: Boolean; SkipEmptyValue: Boolean): IMap; +begin + Result := MapClass.Split(Str, ItemSeparator, KeyValueSeparator, Limit, + TrimKey, TrimValue, SkipEmptyKey, SkipEmptyValue); +end; + +initialization + + HproseClassMap := TCaseInsensitiveHashedMap.Create(False, True); + HproseInterfaceMap := TCaseInsensitiveHashedMap.Create(False, True); + RegisterClass(TArrayList, IList, '!List'); + RegisterClass(TArrayList, IArrayList, '!ArrayList'); + RegisterClass(THashedList, IHashedList, '!HashedList'); + RegisterClass(TCaseInsensitiveHashedList, ICaseInsensitiveHashedList, '!CaseInsensitiveHashedList'); + RegisterClass(THashMap, IMap, '!Map'); + RegisterClass(THashMap, IHashMap, '!HashMap'); + RegisterClass(THashedMap, IHashedMap, '!HashedMap'); + RegisterClass(TCaseInsensitiveHashMap, ICaseInsensitiveHashMap, '!CaseInsensitiveHashMap'); + RegisterClass(TCaseInsensitiveHashedMap, ICaseInsensitiveHashedMap, '!CaseInsensitiveHashedMap'); +{$IFNDEF FPC} + VarObjectType := TVarObjectType.Create; + varObject := VarObjectType.VarType; + +finalization + FreeAndNil(VarObjectType); +{$ENDIF} + +end. diff --git a/src/delphi/HproseIO.pas b/src/delphi/HproseIO.pas index c2b0c13..1a560ff 100644 --- a/src/delphi/HproseIO.pas +++ b/src/delphi/HproseIO.pas @@ -1,3050 +1,3050 @@ -{ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ - -/**********************************************************\ - * * - * HproseIO.pas * - * * - * hprose io unit for delphi. * - * * - * LastModified: Dec 28, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -} -unit HproseIO; - -{$I Hprose.inc} - -interface - -uses Classes, HproseCommon; - -const - { Hprose Serialize Tags } - HproseTagInteger :AnsiChar = 'i'; - HproseTagLong :AnsiChar = 'l'; - HproseTagDouble :AnsiChar = 'd'; - HproseTagNull :AnsiChar = 'n'; - HproseTagEmpty :AnsiChar = 'e'; - HproseTagTrue :AnsiChar = 't'; - HproseTagFalse :AnsiChar = 'f'; - HproseTagNaN :AnsiChar = 'N'; - HproseTagInfinity :AnsiChar = 'I'; - HproseTagDate :AnsiChar = 'D'; - HproseTagTime :AnsiChar = 'T'; - HproseTagUTC :AnsiChar = 'Z'; - HproseTagBytes :AnsiChar = 'b'; - HproseTagUTF8Char :AnsiChar = 'u'; - HproseTagString :AnsiChar = 's'; - HproseTagGuid :AnsiChar = 'g'; - HproseTagList :AnsiChar = 'a'; - HproseTagMap :AnsiChar = 'm'; - HproseTagClass :AnsiChar = 'c'; - HproseTagObject :AnsiChar = 'o'; - HproseTagRef :AnsiChar = 'r'; - { Hprose Serialize Marks } - HproseTagPos :AnsiChar = '+'; - HproseTagNeg :AnsiChar = '-'; - HproseTagSemicolon :AnsiChar = ';'; - HproseTagOpenbrace :AnsiChar = '{'; - HproseTagClosebrace :AnsiChar = '}'; - HproseTagQuote :AnsiChar = '"'; - HproseTagPoint :AnsiChar = '.'; - { Hprose Protocol Tags } - HproseTagFunctions :AnsiChar = 'F'; - HproseTagCall :AnsiChar = 'C'; - HproseTagResult :AnsiChar = 'R'; - HproseTagArgument :AnsiChar = 'A'; - HproseTagError :AnsiChar = 'E'; - HproseTagEnd :AnsiChar = 'z'; - -type - - THproseReader = class - private - FStream: TStream; - FRefList: IList; - FClassRefList: IList; - FAttrRefMap: IMap; - function Unserialize(Tag: AnsiChar; VType: TVarType; - AClass: TClass): Variant; overload; - function ReadByte: Byte; - function ReadInt64(Tag: AnsiChar): Int64; -{$IF Defined(DELPHI2009_UP) or Defined(FPC)} - function ReadUInt64(Tag: AnsiChar): UInt64; -{$IFEND} - function ReadShortIntArray(Count: Integer): Variant; - function ReadSmallIntArray(Count: Integer): Variant; - function ReadWordArray(Count: Integer): Variant; - function ReadIntegerArray(Count: Integer): Variant; - function ReadCurrencyArray(Count: Integer): Variant; - function ReadLongWordArray(Count: Integer): Variant; - function ReadInt64Array(Count: Integer): Variant; -{$IFDEF DELPHI2009_UP} - function ReadUInt64Array(Count: Integer): Variant; -{$ENDIF} -{$IFDEF FPC} - function ReadQWordArray(Count: Integer): Variant; -{$ENDIF} - function ReadSingleArray(Count: Integer): Variant; - function ReadDoubleArray(Count: Integer): Variant; - function ReadBooleanArray(Count: Integer): Variant; - function ReadWideStringArray(Count: Integer): Variant; - function ReadDateTimeArray(Count: Integer): Variant; - function ReadList(AClass: TClass; Count: Integer): Variant; overload; - function ReadRef: Variant; - procedure ReadClass; - procedure ReadRaw(const OStream: TStream; Tag: AnsiChar); overload; - procedure ReadInfinityRaw(const OStream: TStream; Tag: AnsiChar); - procedure ReadNumberRaw(const OStream: TStream; Tag: AnsiChar); - procedure ReadDateTimeRaw(const OStream: TStream; Tag: AnsiChar); - procedure ReadUTF8CharRaw(const OStream: TStream; Tag: AnsiChar); - procedure ReadBytesRaw(const OStream: TStream; Tag: AnsiChar); - procedure ReadStringRaw(const OStream: TStream; Tag: AnsiChar); - procedure ReadGuidRaw(const OStream: TStream; Tag: AnsiChar); - procedure ReadComplexRaw(const OStream: TStream; Tag: AnsiChar); - public - constructor Create(AStream: TStream); - function Unserialize(VType: TVarType = varVariant; - AClass: TClass = nil): Variant; overload; - procedure CheckTag(expectTag: AnsiChar); - function CheckTags(const expectTags: RawByteString): AnsiChar; - function ReadUntil(Tag: AnsiChar): string; - function ReadInt(Tag: AnsiChar): Integer; - function ReadInteger(IncludeTag:Boolean = True): Integer; - function ReadLong(IncludeTag:Boolean = True): Variant; - function ReadDouble(IncludeTag:Boolean = True): Extended; - function ReadCurrency(IncludeTag:Boolean = True): Currency; - function ReadNull(): Variant; - function ReadEmpty(): Variant; - function ReadBoolean(): Boolean; - function ReadNaN(): Extended; - function ReadInfinity(IncludeTag:Boolean = True): Extended; - function ReadDate(IncludeTag:Boolean = True): TDateTime; - function ReadTime(IncludeTag:Boolean = True): TDateTime; - function ReadBytes(IncludeTag:Boolean = True): Variant; - function ReadUTF8Char(IncludeTag:Boolean = True): WideChar; - function ReadString(IncludeTag:Boolean = True; - IncludeRef:Boolean = True): WideString; - function ReadGuid(IncludeTag:Boolean = True): AnsiString; - function ReadList(ElementType: TVarType; AClass: TClass = nil; - IncludeTag:Boolean = True): Variant; overload; - function ReadMap(AClass: TClass = nil; IncludeTag:Boolean = True): Variant; - function ReadObject(AClass: TClass = nil; IncludeTag:Boolean = True): Variant; - procedure Reset; - function ReadRaw: TMemoryStream; overload; - procedure ReadRaw(const OStream: TStream); overload; - property Stream: TStream read FStream; - end; - - THproseWriter = class - private - FStream: TStream; - FRefList: IList; - FClassRefList: IList; - function WriteRef(const Value: Variant; CheckRef: Boolean): - Boolean; overload; - procedure WriteRef(Value: Integer); overload; - function WriteClass(Instance: TObject): Integer; - procedure WriteRawByteString(const S: RawByteString); - procedure WriteShortIntArray(var P; Count: Integer); - procedure WriteSmallIntArray(var P; Count: Integer); - procedure WriteWordArray(var P; Count: Integer); - procedure WriteIntegerArray(var P; Count: Integer); - procedure WriteCurrencyArray(var P; Count: Integer); - procedure WriteLongWordArray(var P; Count: Integer); - procedure WriteInt64Array(var P; Count: Integer); -{$IFDEF DELPHI2009_UP} - procedure WriteUInt64Array(var P; Count: Integer); -{$ENDIF} -{$IFDEF FPC} - procedure WriteQWordArray(var P; Count: Integer); -{$ENDIF} - procedure WriteSingleArray(var P; Count: Integer); - procedure WriteDoubleArray(var P; Count: Integer); - procedure WriteBooleanArray(var P; Count: Integer); - procedure WriteWideStringArray(var P; Count: Integer); - procedure WriteDateTimeArray(var P; Count: Integer); - procedure WriteVariantArray(var P; Count: Integer); - public - constructor Create(AStream: TStream); - procedure Serialize(const Value: Variant); overload; - procedure Serialize(const Value: array of const); overload; - procedure WriteInteger(I: Integer); - procedure WriteLong(L: Int64); overload; -{$IFDEF DELPHI2009_UP} - procedure WriteLong(L: UInt64); overload; -{$ENDIF} -{$IFDEF FPC} - procedure WriteLong(L: QWord); overload; -{$ENDIF} - procedure WriteLong(const L: RawByteString); overload; - procedure WriteDouble(D: Extended); - procedure WriteCurrency(C: Currency); - procedure WriteNull(); - procedure WriteEmpty(); - procedure WriteBoolean(B: Boolean); - procedure WriteNaN(); - procedure WriteInfinity(Positive: Boolean); - procedure WriteUTF8Char(C: WideChar); - procedure WriteDateTime(const ADateTime: TDateTime; CheckRef: Boolean = True); - procedure WriteBytes(const Bytes: Variant; CheckRef: Boolean = True); - procedure WriteString(const S: WideString; CheckRef: Boolean = True); - procedure WriteArray(const Value: Variant; CheckRef: Boolean = True); overload; - procedure WriteArray(const Value: array of const); overload; - procedure WriteList(AList: IList; CheckRef: Boolean = True); - procedure WriteMap(AMap: IMap; CheckRef: Boolean = True); - procedure WriteObject(AObject: TObject; CheckRef: Boolean = True); - procedure WriteInterface(Intf: IInterface; CheckRef: Boolean = True); - procedure Reset; - property Stream: TStream read FStream; - end; - - THproseFormatter = class - public - class function Serialize(Value: TObject): RawByteString; overload; - class function Serialize(const Value: Variant): RawByteString; overload; - class function Serialize(const Value: array of const): RawByteString; overload; - class function Unserialize(const Data:RawByteString; VType: TVarType = varVariant; - AClass: TClass = nil): Variant; - end; - -function HproseSerialize(Value: TObject): RawByteString; overload; -function HproseSerialize(const Value: Variant): RawByteString; overload; -function HproseSerialize(const Value: array of const): RawByteString; overload; -function HproseUnserialize(const Data:RawByteString; VType: TVarType = varVariant; - AClass: TClass = nil): Variant; - -implementation - -uses DateUtils, Math, RTLConsts, SysConst, SysUtils, TypInfo, Variants; - -type - - PSmallIntArray = ^TSmallIntArray; - TSmallIntArray = array[0..MaxInt div Sizeof(SmallInt) - 1] of SmallInt; - - PShortIntArray = ^TShortIntArray; - TShortIntArray = array[0..MaxInt div Sizeof(ShortInt) - 1] of ShortInt; - - PInt64Array = ^TInt64Array; - TInt64Array = array[0..MaxInt div Sizeof(Int64) - 1] of Int64; - -{$IFDEF DELPHI2009_UP} - PUInt64Array = ^TUInt64Array; - TUInt64Array = array[0..MaxInt div Sizeof(UInt64) - 1] of UInt64; -{$ENDIF} - -{$IFDEF FPC} - PQWordArray = ^TQWordArray; - TQWordArray = array[0..MaxInt div Sizeof(QWord) - 1] of QWord; -{$ENDIF} - - PLongWordArray = ^TLongWordArray; - TLongWordArray = array[0..MaxInt div Sizeof(LongWord) - 1] of LongWord; - - PSingleArray = ^TSingleArray; - TSingleArray = array[0..MaxInt div Sizeof(Single) - 1] of Single; - - PDoubleArray = ^TDoubleArray; - TDoubleArray = array[0..MaxInt div Sizeof(Double) - 1] of Double; - - PCurrencyArray = ^TCurrencyArray; - TCurrencyArray = array[0..MaxInt div Sizeof(Currency) - 1] of Currency; - - PWordBoolArray = ^TWordBoolArray; - TWordBoolArray = array[0..MaxInt div Sizeof(WordBool) - 1] of WordBool; - - PWideStringArray = ^TWideStringArray; - TWideStringArray = array[0..MaxInt div Sizeof(WideString) - 1] of WideString; - - PDateTimeArray = ^TDateTimeArray; - TDateTimeArray = array[0..MaxInt div Sizeof(TDateTime) - 1] of TDateTime; - - PVariantArray = ^TVariantArray; - TVariantArray = array[0..MaxInt div Sizeof(Variant) - 1] of Variant; - - SerializeCache = record - RefCount: Integer; - Data: RawByteString; - end; - PSerializeCache = ^SerializeCache; - -var - PropertiesCache: IMap; - -const - htInteger = 'i'; - htLong = 'l'; - htDouble = 'd'; - htNull = 'n'; - htEmpty = 'e'; - htTrue = 't'; - htFalse = 'f'; - htNaN = 'N'; - htInfinity = 'I'; - htDate = 'D'; - htTime = 'T'; - htBytes = 'b'; - htUTF8Char = 'u'; - htString = 's'; - htGuid = 'g'; - htList = 'a'; - htMap = 'm'; - htClass = 'c'; - htObject = 'o'; - htRef = 'r'; - htError = 'E'; - - HproseTagBoolean :array[Boolean] of AnsiChar = ('f', 't'); - HproseTagSign :array[Boolean] of AnsiChar = ('-', '+'); - -function GetStoredPropList(Instance: TObject; out PropList: PPropList): Integer; -var - I, Count: Integer; - TempList: PPropList; -begin - Count := GetPropList(PTypeInfo(Instance.ClassInfo), TempList); - PropList := nil; - Result := 0; - if Count > 0 then - try - for I := 0 to Count - 1 do - if IsStoredProp(Instance, TempList^[I]) then - Inc(Result); - GetMem(PropList, Result * SizeOf(Pointer)); - for I := 0 to Result - 1 do - if IsStoredProp(Instance, TempList^[I]) then - PropList^[I] := TempList^[I]; - finally - FreeMem(TempList); - end; -end; - -{ GetPropValue/SetPropValue } - -procedure PropertyNotFound(const Name: string); -begin - raise EPropertyError.CreateResFmt(@SUnknownProperty, [Name]); -end; - -procedure PropertyConvertError(const Name: AnsiString); -begin - raise EPropertyConvertError.CreateResFmt(@SInvalidPropertyType, [Name]); -end; - -{$IFNDEF FPC} -{$IFNDEF DELPHI2007_UP} -type - TAccessStyle = (asFieldData, asAccessor, asIndexedAccessor); - -function GetAccessToProperty(Instance: TObject; PropInfo: PPropInfo; - AccessorProc: Longint; out FieldData: Pointer; - out Accessor: TMethod): TAccessStyle; -begin - if (AccessorProc and $FF000000) = $FF000000 then - begin // field - Getter is the field's offset in the instance data - FieldData := Pointer(Integer(Instance) + (AccessorProc and $00FFFFFF)); - Result := asFieldData; - end - else - begin - if (AccessorProc and $FF000000) = $FE000000 then - // virtual method - Getter is a signed 2 byte integer VMT offset - Accessor.Code := Pointer(PInteger(PInteger(Instance)^ + SmallInt(AccessorProc))^) - else - // static method - Getter is the actual address - Accessor.Code := Pointer(AccessorProc); - - Accessor.Data := Instance; - if PropInfo^.Index = Integer($80000000) then // no index - Result := asAccessor - else - Result := asIndexedAccessor; - end; -end; - -function GetDynArrayProp(Instance: TObject; PropInfo: PPropInfo): Pointer; -type - { Need a(ny) dynamic array type to force correct call setup. - (Address of result passed in EDX) } - TDynamicArray = array of Byte; -type - TDynArrayGetProc = function: TDynamicArray of object; - TDynArrayIndexedGetProc = function (Index: Integer): TDynamicArray of object; -var - M: TMethod; -begin - case GetAccessToProperty(Instance, PropInfo, Longint(PropInfo^.GetProc), - Result, M) of - asFieldData: - Result := PPointer(Result)^; - asAccessor: - Result := Pointer(TDynArrayGetProc(M)()); - asIndexedAccessor: - Result := Pointer(TDynArrayIndexedGetProc(M)(PropInfo^.Index)); - end; -end; - -procedure SetDynArrayProp(Instance: TObject; PropInfo: PPropInfo; - const Value: Pointer); -type - TDynArraySetProc = procedure (const Value: Pointer) of object; - TDynArrayIndexedSetProc = procedure (Index: Integer; - const Value: Pointer) of object; -var - P: Pointer; - M: TMethod; -begin - case GetAccessToProperty(Instance, PropInfo, Longint(PropInfo^.SetProc), - P, M) of - asFieldData: - asm - MOV ECX, PropInfo - MOV ECX, [ECX].TPropInfo.PropType - MOV ECX, [ECX] - - MOV EAX, [P] - MOV EDX, Value - CALL System.@DynArrayAsg - end; - asAccessor: - TDynArraySetProc(M)(Value); - asIndexedAccessor: - TDynArrayIndexedSetProc(M)(PropInfo^.Index, Value); - end; -end; -{$ENDIF} -{$ELSE} -function GetDynArrayProp(Instance: TObject; PropInfo: PPropInfo): Pointer; -type - { Need a(ny) dynamic array type to force correct call setup. - (Address of result passed in EDX) } - TDynamicArray = array of Byte; -type - TDynArrayGetProc = function: TDynamicArray of object; - TDynArrayIndexedGetProc = function (Index: Integer): TDynamicArray of object; -var - AMethod: TMethod; -begin - case (PropInfo^.PropProcs) and 3 of - ptfield: - Result := PPointer(Pointer(Instance) + PtrUInt(PropInfo^.GetProc))^; - ptstatic, - ptvirtual: - begin - if (PropInfo^.PropProcs and 3) = ptStatic then - AMethod.Code := PropInfo^.GetProc - else - AMethod.Code := PPointer(Pointer(Instance.ClassType) + PtrUInt(PropInfo^.GetProc))^; - AMethod.Data := Instance; - if ((PropInfo^.PropProcs shr 6) and 1) <> 0 then - Result := TDynArrayIndexedGetProc(AMethod)(PropInfo^.Index) - else - Result := TDynArrayGetProc(AMethod)(); - end; - end; -end; - -procedure SetDynArrayProp(Instance: TObject; PropInfo: PPropInfo; - const Value: Pointer); -type - TDynArraySetProc = procedure (const Value: Pointer) of object; - TDynArrayIndexedSetProc = procedure (Index: Integer; - const Value: Pointer) of object; -var - AMethod: TMethod; -begin - case (PropInfo^.PropProcs shr 2) and 3 of - ptfield: - PPointer(Pointer(Instance) + PtrUInt(PropInfo^.SetProc))^ := Value; - ptstatic, - ptvirtual: - begin - if ((PropInfo^.PropProcs shr 2) and 3) = ptStatic then - AMethod.Code := PropInfo^.SetProc - else - AMethod.Code := PPointer(Pointer(Instance.ClassType) + PtrUInt(PropInfo^.SetProc))^; - AMethod.Data := Instance; - if ((PropInfo^.PropProcs shr 6) and 1) <> 0 then - TDynArrayIndexedSetProc(AMethod)(PropInfo^.Index, Value) - else - TDynArraySetProc(AMethod)(Value); - end; - end; -end; -function GetInterfaceProp(Instance: TObject; PropInfo: PPropInfo): IInterface; -type - TInterfaceGetProc = function: IInterface of object; - TInterfaceIndexedGetProc = function (Index: Integer): IInterface of object; -var - P: ^IInterface; - AMethod: TMethod; -begin - case (PropInfo^.PropProcs) and 3 of - ptfield: - begin - P := Pointer(Pointer(Instance) + PtrUInt(PropInfo^.GetProc)); - Result := P^; // auto ref count - end; - ptstatic, - ptvirtual: - begin - if (PropInfo^.PropProcs and 3) = ptStatic then - AMethod.Code := PropInfo^.GetProc - else - AMethod.Code := PPointer(Pointer(Instance.ClassType) + PtrUInt(PropInfo^.GetProc))^; - AMethod.Data := Instance; - if ((PropInfo^.PropProcs shr 6) and 1) <> 0 then - Result := TInterfaceIndexedGetProc(AMethod)(PropInfo^.Index) - else - Result := TInterfaceGetProc(AMethod)(); - end; - end; -end; - -procedure SetInterfaceProp(Instance: TObject; PropInfo: PPropInfo; - const Value: IInterface); -type - TInterfaceSetProc = procedure (const Value: IInterface) of object; - TInterfaceIndexedSetProc = procedure (Index: Integer; - const Value: IInterface) of object; -var - P: ^IInterface; - AMethod: TMethod; -begin - case (PropInfo^.PropProcs shr 2) and 3 of - ptfield: - begin - P := Pointer(Pointer(Instance) + PtrUInt(PropInfo^.SetProc)); - P^ := Value; // auto ref count - end; - ptstatic, - ptvirtual: - begin - if ((PropInfo^.PropProcs shr 2) and 3) = ptStatic then - AMethod.Code := PropInfo^.SetProc - else - AMethod.Code := PPointer(Pointer(Instance.ClassType) + PtrUInt(PropInfo^.SetProc))^; - AMethod.Data := Instance; - if ((PropInfo^.PropProcs shr 6) and 1) <> 0 then - TInterfaceIndexedSetProc(AMethod)(PropInfo^.Index, Value) - else - TInterfaceSetProc(AMethod)(Value); - end; - end; -end; -{$ENDIF} - -function GetPropValue(Instance: TObject; PropInfo: PPropInfo): Variant; -var - PropType: PTypeInfo; - DynArray: Pointer; -begin - // assume failure - Result := Null; - PropType := PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF}; - case PropType^.Kind of - tkInteger: - Result := GetOrdProp(Instance, PropInfo); - tkWChar: - Result := WideString(WideChar(GetOrdProp(Instance, PropInfo))); - tkChar: - Result := AnsiChar(GetOrdProp(Instance, PropInfo)); - tkEnumeration: - if GetTypeData(PropType)^.BaseType{$IFNDEF FPC}^{$ENDIF} = TypeInfo(Boolean) then - Result := Boolean(GetOrdProp(Instance, PropInfo)) - else - Result := GetOrdProp(Instance, PropInfo); - tkSet: - Result := GetOrdProp(Instance, PropInfo); - tkFloat: - if (LowerCase(string(PropType^.Name)) = 'tdatetime') then - Result := VarAsType(GetFloatProp(Instance, PropInfo), varDate) - else - Result := GetFloatProp(Instance, PropInfo); - tkString, {$IFDEF FPC}tkAString, {$ENDIF}tkLString: - Result := GetStrProp(Instance, PropInfo); - tkWString: - Result := GetWideStrProp(Instance, PropInfo); -{$IFDEF DELPHI2009_UP} - tkUString: - Result := GetUnicodeStrProp(Instance, PropInfo); -{$ENDIF} - tkVariant: - Result := GetVariantProp(Instance, PropInfo); - tkInt64: -{$IFDEF DELPHI2009_UP} - if (LowerCase(string(PropType^.Name)) = 'uint64') then - Result := UInt64(GetInt64Prop(Instance, PropInfo)) - else -{$ENDIF} - Result := GetInt64Prop(Instance, PropInfo); -{$IFDEF FPC} - tkBool: - Result := Boolean(GetOrdProp(Instance, PropInfo)); - tkQWord: - Result := QWord(GetInt64Prop(Instance, PropInfo)); -{$ENDIF} - tkInterface: - Result := GetInterfaceProp(Instance, PropInfo); - tkDynArray: - begin - DynArray := GetDynArrayProp(Instance, PropInfo); - DynArrayToVariant(Result, DynArray, PropType); - end; - tkClass: - Result := ObjToVar(GetObjectProp(Instance, PropInfo)); - else - PropertyConvertError(PropType^.Name); - end; -end; - -procedure SetPropValue(Instance: TObject; PropInfo: PPropInfo; - const Value: Variant); -var - PropType: PTypeInfo; - TypeData: PTypeData; - Obj: TObject; - DynArray: Pointer; -begin - PropType := PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF}; - TypeData := GetTypeData(PropType); - // set the right type - case PropType^.Kind of - tkInteger, tkChar, tkWChar, tkEnumeration, tkSet: - SetOrdProp(Instance, PropInfo, Value); -{$IFDEF FPC} - tkBool: - SetOrdProp(Instance, PropInfo, Value); - tkQWord: - SetInt64Prop(Instance, PropInfo, QWord(Value)); -{$ENDIF} - tkFloat: - SetFloatProp(Instance, PropInfo, Value); - tkString, {$IFDEF FPC}tkAString, {$ENDIF}tkLString: - SetStrProp(Instance, PropInfo, VarToStr(Value)); - tkWString: - SetWideStrProp(Instance, PropInfo, VarToWideStr(Value)); -{$IFDEF DELPHI2009_UP} - tkUString: - SetUnicodeStrProp(Instance, PropInfo, VarToStr(Value)); //SB: ?? - tkInt64: - SetInt64Prop(Instance, PropInfo, Value); -{$ELSE} - tkInt64: - SetInt64Prop(Instance, PropInfo, TVarData(VarAsType(Value, varInt64)).VInt64); -{$ENDIF} - tkVariant: - SetVariantProp(Instance, PropInfo, Value); - tkInterface: - begin - SetInterfaceProp(Instance, PropInfo, Value); - end; - tkDynArray: - begin - DynArray := nil; // "nil array" - if VarIsNull(Value) or (VarArrayHighBound(Value, 1) >= 0) then begin - DynArrayFromVariant(DynArray, Value, PropType); - end; - SetDynArrayProp(Instance, PropInfo, DynArray); -{$IFNDEF FPC} - DynArrayClear(DynArray, PropType); -{$ENDIF} - end; - tkClass: - if VarIsNull(Value) then - SetOrdProp(Instance, PropInfo, 0) - else if VarIsObj(Value) then begin - Obj := VarToObj(Value); - if (Obj.ClassType.InheritsFrom(TypeData^.ClassType)) then - SetObjectProp(Instance, PropInfo, Obj) - else - PropertyConvertError(PropType^.Name); - end - else - PropertyConvertError(PropType^.Name); - else - PropertyConvertError(PropType^.Name); - end; -end; - -function GetVarTypeAndClass(TypeInfo: PTypeInfo; out AClass: TClass): TVarType; -var - TypeData: PTypeData; - TypeName: string; -begin - Result := varVariant; - AClass := nil; - TypeName := LowerCase(string(TypeInfo^.Name)); - if TypeName = 'boolean' then - Result := varBoolean - else if TypeName = 'tdatetime' then - Result := varDate -{$IFDEF DELPHI2009_UP} - else if TypeName = 'uint64' then - Result := varUInt64 -{$ENDIF} - else begin - TypeData := GetTypeData(TypeInfo); - case TypeInfo^.Kind of - tkInteger, tkEnumeration, tkSet: - case TypeData^.OrdType of - otSByte: - Result := varShortInt; - otUByte: - Result := varByte; - otSWord: - Result := varSmallInt; - otUWord: - Result := varWord; - otSLong: - Result := varInteger; - otULong: - Result := varLongWord; - end; - tkChar: begin - AClass := TObject; - Result := varByte; - end; - tkWChar: begin - AClass := TObject; - Result := varWord; - end; -{$IFDEF FPC} - tkBool: - Result := varBoolean; - tkQWord: - Result := varQWord; -{$ENDIF} - tkFloat: - case TypeData^.FloatType of - ftSingle: - Result := varSingle; - ftDouble: - Result := varDouble; - ftCurr: - Result := varCurrency; - end; - tkString, {$IFDEF FPC}tkAString, {$ENDIF}tkLString: - Result := varString; - tkWString: - Result := varOleStr; -{$IFDEF DELPHI2009_UP} - tkUString: - Result := varUString; -{$ENDIF} - tkInt64: - Result := varInt64; - tkInterface: begin - Result := varUnknown; - AClass := GetClassByInterface(TypeData.Guid); - end; - tkDynArray: - Result := TypeData.varType; - tkClass: - AClass := TypeData.ClassType; - end; - end; -end; - -function StrToByte(const S:string): Byte; overload; -begin - if Length(S) = 1 then - Result := Ord(S[1]) - else - Result := Byte(StrToInt(S)); -end; - -function OleStrToWord(const S:WideString): Word; overload; -begin - if Length(S) = 1 then - Result := Ord(S[1]) - else - Result := Word(StrToInt(S)); -end; - -type - TAnsiCharSet = set of AnsiChar; - -function CharInSet(C: WideChar; const CharSet: TAnsiCharSet): Boolean; -begin - Result := (C < #$0100) and (AnsiChar(C) in CharSet); -end; - -{ THproseReader } - -procedure THproseReader.CheckTag(ExpectTag: AnsiChar); -var - Tag: AnsiChar; -begin - FStream.ReadBuffer(Tag, 1); - if Tag <> expectTag then - raise EHproseException.Create('Tag "' + ExpectTag + '" expected, but "' + - string(Tag) + '" found in stream'); -end; - -function THproseReader.CheckTags(const ExpectTags: RawByteString): AnsiChar; -var - Tag: AnsiChar; -begin - FStream.ReadBuffer(Tag, 1); - if Pos(Tag, ExpectTags) = 0 then - raise EHproseException.Create('Tags "' + string(ExpectTags) + '" expected, but "' + - string(Tag) + '" found in stream'); - Result := Tag; -end; - -constructor THproseReader.Create(AStream: TStream); -begin - FStream := AStream; - FRefList := TArrayList.Create(False); - FClassRefList := TArrayList.Create(False); - FAttrRefMap := THashMap.Create(False); -end; - -function THproseReader.ReadBoolean: Boolean; -begin - Result := CheckTags(HproseTagTrue + HproseTagFalse) = HproseTagTrue; -end; - - -function THproseReader.ReadByte: Byte; -begin - FStream.ReadBuffer(Result, 1); -end; - -function THproseReader.ReadBytes(IncludeTag: Boolean): Variant; -var - Len: Integer; - P: PByteArray; -begin - if IncludeTag and - (CheckTags(HproseTagBytes + HproseTagRef) = HproseTagRef) then begin - Result := ReadRef(); - Exit; - end; - Len := ReadInt(HproseTagQuote); - Result := VarArrayCreate([0, Len - 1], varByte); - P := VarArrayLock(Result); - FStream.ReadBuffer(P^[0], Len); - VarArrayUnLock(Result); - CheckTag(HproseTagQuote); -{$IFDEF FPC} - FRefList.Add(Result); -{$ELSE} - FRefList.Add(VarArrayRef(Result)); -{$ENDIF} -end; - -procedure THproseReader.ReadBytesRaw(const OStream: TStream; Tag: AnsiChar); -var - Len: Integer; -begin - OStream.WriteBuffer(Tag, 1); - Len := 0; - Tag := '0'; - repeat - Len := Len * 10 + (Ord(Tag) - Ord('0')); - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - until (Tag = HproseTagQuote); - OStream.CopyFrom(FStream, Len + 1); -end; - -function THproseReader.ReadCurrency(IncludeTag: Boolean): Currency; -begin - if IncludeTag then - CheckTags(HproseTagInteger + HproseTagLong + HproseTagDouble); - Result := StrToCurr(ReadUntil(HproseTagSemicolon)); -end; - -function THproseReader.ReadDate(IncludeTag: Boolean): TDateTime; -var - Tag, Year, Month, Day, Hour, Minute, Second, Millisecond: Integer; -begin - if IncludeTag and - (CheckTags(HproseTagDate + HproseTagRef) = HproseTagRef) then begin - Result := ReadRef; - Exit; - end; - Year := ReadByte - Ord('0'); - Year := Year * 10 + ReadByte - Ord('0'); - Year := Year * 10 + ReadByte - Ord('0'); - Year := Year * 10 + ReadByte - Ord('0'); - Month := ReadByte - Ord('0'); - Month := Month * 10 + ReadByte - Ord('0'); - Day := ReadByte - Ord('0'); - Day := Day * 10 + ReadByte - Ord('0'); - Tag := ReadByte; - if Tag = Ord(HproseTagTime) then begin - Hour := ReadByte - Ord('0'); - Hour := Hour * 10 + ReadByte - Ord('0'); - Minute := ReadByte - Ord('0'); - Minute := Minute * 10 + ReadByte - Ord('0'); - Second := ReadByte - Ord('0'); - Second := Second * 10 + ReadByte - Ord('0'); - Millisecond := 0; - if ReadByte = Ord(HproseTagPoint) then begin - Millisecond := ReadByte - Ord('0'); - Millisecond := Millisecond * 10 + ReadByte - Ord('0'); - Millisecond := Millisecond * 10 + ReadByte - Ord('0'); - Tag := ReadByte; - if (Tag >= Ord('0')) and (Tag <= Ord('9')) then begin - ReadByte; - ReadByte; - Tag := ReadByte; - if (Tag >= Ord('0')) and (Tag <= Ord('9')) then begin - ReadByte; - ReadByte; - ReadByte; - end; - end; - end; - Result := EncodeDateTime(Year, Month, Day, Hour, Minute, Second, Millisecond); - end - else - Result := EncodeDate(Year, Month, Day); - FRefList.Add(Result); -end; - -function THproseReader.ReadDouble(IncludeTag: Boolean): Extended; -var - Tag: AnsiChar; -begin - if IncludeTag then begin - Tag := CheckTags(HproseTagInteger + - HproseTagLong + - HproseTagDouble + - HproseTagNaN + - HproseTagInfinity); - if Tag = HproseTagNaN then begin - Result := NaN; - Exit; - end; - if Tag = HproseTagInfinity then begin - Result := ReadInfinity(False); - Exit; - end; - end; - Result := StrToFloat(ReadUntil(HproseTagSemicolon)); -end; - -function THproseReader.ReadInfinity(IncludeTag: Boolean): Extended; -begin - if IncludeTag then CheckTag(HproseTagInfinity); - if ReadByte = Ord(HproseTagNeg) then - Result := NegInfinity - else - Result := Infinity; -end; - -procedure THproseReader.ReadInfinityRaw(const OStream: TStream; Tag: AnsiChar); -begin - OStream.WriteBuffer(Tag, 1); - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); -end; - -function THproseReader.ReadInteger(IncludeTag: Boolean): Integer; -begin - if IncludeTag then CheckTag(HproseTagInteger); - Result := ReadInt(HproseTagSemicolon); -end; - -function THproseReader.ReadLong(IncludeTag: Boolean): Variant; -begin - if IncludeTag then CheckTags(HproseTagInteger + HproseTagLong); - Result := ReadUntil(HproseTagSemicolon); -end; - -function THproseReader.ReadNaN: Extended; -begin - CheckTag(HproseTagNaN); - Result := NaN; -end; - -function THproseReader.ReadNull: Variant; -begin - CheckTag(HproseTagNull); - Result := Null; -end; - -procedure THproseReader.ReadNumberRaw(const OStream: TStream; Tag: AnsiChar); -begin - OStream.WriteBuffer(Tag, 1); - repeat - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - until (Tag = HproseTagSemicolon); -end; - -function THproseReader.ReadEmpty: Variant; -begin - CheckTag(HproseTagEmpty); - Result := ''; -end; - -function THproseReader.ReadString(IncludeTag, IncludeRef: Boolean): WideString; -var - Count, I: Integer; - C, C2, C3, C4: LongWord; -begin - if IncludeTag and - (CheckTags(HproseTagString + HproseTagRef) = HproseTagRef) then begin - Result := ReadRef; - Exit; - end; - Count := ReadInt(HproseTagQuote); - SetLength(Result, Count); - I := 0; - while I < Count do begin - Inc(I); - C := ReadByte; - case C shr 4 of - 0..7: { 0xxx xxxx } Result[I] := WideChar(C); - 12,13: begin - { 110x xxxx 10xx xxxx } - C2 := ReadByte; - Result[I] := WideChar(((C and $1F) shl 6) or - (C2 and $3F)); - end; - 14: begin - { 1110 xxxx 10xx xxxx 10xx xxxx } - C2 := ReadByte; - C3 := ReadByte; - Result[I] := WideChar(((C and $0F) shl 12) or - ((C2 and $3F) shl 6) or - (C3 and $3F)); - end; - 15: begin - { 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx } - if (C and $F) <= 4 then begin - C2 := ReadByte; - C3 := ReadByte; - C4 := ReadByte; - C := ((C and $07) shl 18) or - ((C2 and $3F) shl 12) or - ((C3 and $3F) shl 6) or - (C4 and $3F) - $10000; - if C <= $FFFFF then begin - Result[I] := WideChar(((C shr 10) and $03FF) or $D800); - Inc(I); - Result[I] := WideChar((C and $03FF) or $DC00); - Continue; - end; - end; - raise EHproseException.Create('bad unicode encoding at $' + IntToHex(C, 4)); - end; - else - raise EHproseException.Create('bad unicode encoding at $' + IntToHex(C, 4)); - end; - end; - CheckTag(HproseTagQuote); - if IncludeRef then FRefList.Add(Result); -end; - -procedure THproseReader.ReadStringRaw(const OStream: TStream; Tag: AnsiChar); -var - Len, I: Integer; -begin - OStream.WriteBuffer(Tag, 1); - Len := 0; - Tag := '0'; - repeat - Len := Len * 10 + (Ord(Tag) - Ord('0')); - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - until (Tag = HproseTagQuote); - { When I = Len, Read & Write HproseTagQuote } - for I := 0 to Len do begin - FStream.ReadBuffer(Tag, 1); - case Ord(Tag) shr 4 of - 0..7: OStream.WriteBuffer(Tag, 1); - 12,13: begin - OStream.WriteBuffer(Tag, 1); - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - end; - 14: begin - OStream.WriteBuffer(Tag, 1); - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - end; - 15: begin - if (Ord(Tag) and $F) <= 4 then begin - OStream.WriteBuffer(Tag, 1); - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - Continue; - end; - raise EHproseException.Create('bad unicode encoding at $' + - IntToHex(Ord(Tag), 4)); - end; - else - raise EHproseException.Create('bad unicode encoding at $' + - IntToHex(Ord(Tag), 4)); - end; - end; -end; - -function THproseReader.ReadTime(IncludeTag: Boolean): TDateTime; -var - Tag, Hour, Minute, Second, Millisecond: Integer; -begin - if IncludeTag and - (CheckTags(HproseTagTime + HproseTagRef) = HproseTagRef) then begin - Result := ReadRef; - Exit; - end; - Hour := ReadByte - Ord('0'); - Hour := Hour * 10 + ReadByte - Ord('0'); - Minute := ReadByte - Ord('0'); - Minute := Minute * 10 + ReadByte - Ord('0'); - Second := ReadByte - Ord('0'); - Second := Second * 10 + ReadByte - Ord('0'); - Millisecond := 0; - if ReadByte = Ord(HproseTagPoint) then begin - Millisecond := ReadByte - Ord('0'); - Millisecond := Millisecond * 10 + ReadByte - Ord('0'); - Millisecond := Millisecond * 10 + ReadByte - Ord('0'); - Tag := ReadByte; - if (Tag >= Ord('0')) and (Tag <= Ord('9')) then begin - ReadByte; - ReadByte; - Tag := ReadByte; - if (Tag >= Ord('0')) and (Tag <= Ord('9')) then begin - ReadByte; - ReadByte; - ReadByte; - end; - end; - end; - Result := EncodeTime(Hour, Minute, Second, Millisecond); - FRefList.Add(Result); -end; - -function THproseReader.ReadUntil(Tag: AnsiChar): string; -var - S: TStringBuffer; - C: AnsiChar; -begin - S := TStringBuffer.Create(); - try - while (FStream.Read(C, 1) = 1) and (C <> Tag) do S.Write(C, 1); - Result := S.ToString; - finally - S.Free; - end; -end; - -function THproseReader.ReadUTF8Char(IncludeTag: Boolean): WideChar; -var - C, C2, C3: LongWord; -begin - if IncludeTag then CheckTag(HproseTagUTF8Char); - C := ReadByte; - case C shr 4 of - 0..7: { 0xxx xxxx } Result := WideChar(C); - 12,13: begin - { 110x xxxx 10xx xxxx } - C2 := ReadByte; - Result := WideChar(((C and $1F) shl 6) or - (C2 and $3F)); - end; - 14: begin - { 1110 xxxx 10xx xxxx 10xx xxxx } - C2 := ReadByte; - C3 := ReadByte; - Result := WideChar(((C and $0F) shl 12) or - ((C2 and $3F) shl 6) or - (C3 and $3F)); - end; - else - raise EHproseException.Create('bad unicode encoding at $' + IntToHex(C, 4)); - end; -end; - -procedure THproseReader.ReadUTF8CharRaw(const OStream: TStream; Tag: AnsiChar); -begin - OStream.WriteBuffer(Tag, 1); - FStream.ReadBuffer(Tag, 1); - case Ord(Tag) shr 4 of - 0..7: OStream.WriteBuffer(Tag, 1); - 12,13: begin - OStream.WriteBuffer(Tag, 1); - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - end; - 14: begin - OStream.WriteBuffer(Tag, 1); - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - end; - else - raise EHproseException.Create('bad unicode encoding at $' + - IntToHex(Ord(Tag), 4)); - end; -end; - -function THproseReader.ReadInt(Tag: AnsiChar): Integer; -var - S: Integer; - I: Integer; - C: AnsiChar; -begin - Result := 0; - S := 1; - I := FStream.Read(C, 1); - if I = 1 then - if C = '+' then - I := FStream.Read(C, 1) - else if C = '-' then begin - S := -1; - I := FStream.Read(C, 1); - end; - while (I = 1) and (C <> Tag) do begin - Result := Result * 10 + (Ord(C) - Ord('0')) * S; - I := FStream.Read(C, 1); - end -end; - -function THproseReader.ReadInt64(Tag: AnsiChar): Int64; -var - S: Int64; - I: Integer; - C: AnsiChar; -begin - Result := 0; - S := 1; - I := FStream.Read(C, 1); - if I = 1 then - if C = '+' then - I := FStream.Read(C, 1) - else if C = '-' then begin - S := -1; - I := FStream.Read(C, 1); - end; - while (I = 1) and (C <> Tag) do begin - Result := Result * 10 + Int64(Ord(C) - Ord('0')) * S; - I := FStream.Read(C, 1); - end -end; - -{$IF Defined(DELPHI2009_UP) or Defined(FPC)} -function THproseReader.ReadUInt64(Tag: AnsiChar): UInt64; -var - I: Integer; - C: AnsiChar; -begin - Result := 0; - I := FStream.Read(C, 1); - if (I = 1) and (C = '+') then I := FStream.Read(C, 1); - while (I = 1) and (C <> Tag) do begin - Result := Result * 10 + UInt64(Ord(C) - Ord('0')); - I := FStream.Read(C, 1); - end -end; -{$IFEND} - -function THproseReader.Unserialize(VType: TVarType; - AClass: TClass): Variant; -var - Tag: AnsiChar; -begin - if FStream.Read(Tag, 1) < 1 then - raise EHproseException.Create('No byte found in stream'); - Result := Unserialize(Tag, VType, AClass); -end; - -function THproseReader.Unserialize(Tag: AnsiChar; VType: TVarType; - AClass: TClass): Variant; -begin - case Tag of - '0'..'9': begin - case VType of - varInteger, varVariant: Result := Ord(Tag) - Ord('0'); - varByte: Result := Byte(Ord(Tag) - Ord('0')); - varShortInt: Result := ShortInt(Ord(Tag) - Ord('0')); - varWord: Result := Word(Ord(Tag) - Ord('0')); - varSmallint: Result := Smallint(Ord(Tag) - Ord('0')); - varLongWord: Result := LongWord(Ord(Tag) - Ord('0')); - varSingle: Result := VarAsType(Ord(Tag) - Ord('0'), varSingle); - varDouble: Result := VarAsType(Ord(Tag) - Ord('0'), varDouble); - varCurrency: Result := StrToCurr(string(Tag)); - varInt64: Result := Int64(Ord(Tag) - Ord('0')); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := UInt64(Ord(Tag) - Ord('0')); -{$ENDIF} -{$IFDEF FPC} - varQWord: Result := QWord(Ord(Tag) - Ord('0')); -{$ENDIF} - varString: Result := AnsiString(Tag); -{$IFDEF DELPHI2009_UP} - varUString: Result := UnicodeString(Tag); -{$ENDIF} - varOleStr: Result := WideString(Tag); - varBoolean: Result := Tag <> '0'; - varDate: Result := TimeStampToDateTime(MSecsToTimeStamp( - Ord(Tag) - Ord('0'))); - else - Error(reInvalidCast); - end; - end; - htInteger: begin - case VType of - varInteger, varVariant: Result := ReadInteger(False); - varByte: Result := Byte(ReadInteger(False)); - varShortInt: Result := ShortInt(ReadInteger(False)); - varWord: Result := Word(ReadInteger(False)); - varSmallint: Result := Smallint(ReadInteger(False)); - varLongWord: Result := LongWord(ReadInteger(False)); - varSingle: Result := VarAsType(ReadInteger(False), varSingle); - varDouble: Result := VarAsType(ReadInteger(False), varDouble); - varCurrency: Result := StrToCurr(ReadUntil(HproseTagSemicolon)); - varInt64: Result := ReadInt64(HproseTagSemicolon); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := ReadUInt64(HproseTagSemicolon); -{$ENDIF} -{$IFDEF FPC} - varQWord: Result := ReadUInt64(HproseTagSemicolon); -{$ENDIF} - varString: Result := ReadUntil(HproseTagSemicolon); -{$IFDEF DELPHI2009_UP} - varUString: Result := ReadUntil(HproseTagSemicolon); -{$ENDIF} - varOleStr: Result := WideString(ReadUntil(HproseTagSemicolon)); - varBoolean: Result := ReadInteger(False) <> 0; - varDate: Result := TimeStampToDateTime(MSecsToTimeStamp( - ReadInteger(False))); - else - Error(reInvalidCast); - end; - end; - htLong: begin - case VType of - varString, varVariant: Result := ReadLong(False); -{$IFDEF DELPHI2009_UP} - varUString: Result := ReadLong(False); -{$ENDIF} - varInteger: Result := ReadInteger(False); - varByte: Result := Byte(ReadInteger(False)); - varShortInt: Result := ShortInt(ReadInteger(False)); - varWord: Result := Word(ReadInteger(False)); - varSmallint: Result := Smallint(ReadInteger(False)); - varLongWord: Result := LongWord(ReadInt64(HproseTagSemicolon)); - varSingle: Result := VarAsType(StrToFloat(ReadLong(False)), varSingle); - varDouble: Result := VarAsType(StrToFloat(ReadLong(False)), varDouble); - varCurrency: Result := StrToCurr(ReadUntil(HproseTagSemicolon)); - varInt64: Result := ReadInt64(HproseTagSemicolon); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := ReadUInt64(HproseTagSemicolon); -{$ENDIF} -{$IFDEF FPC} - varQWord: Result := ReadUInt64(HproseTagSemicolon); -{$ENDIF} - varOleStr: Result := WideString(ReadUntil(HproseTagSemicolon)); - varBoolean: Result := ReadLong(False) <> '0'; - varDate: Result := TimeStampToDateTime(MSecsToTimeStamp( - StrToInt64(ReadLong(False)))); - else - Error(reInvalidCast); - end; - end; - htDouble: begin - case VType of - varDouble, varVariant: Result := VarAsType(ReadDouble(False), varDouble); - varSingle: Result := VarAsType(ReadDouble(False), varSingle); - varCurrency: Result := ReadCurrency(False); - varInteger: Result := ReadInteger(False); - varByte: Result := Byte(ReadInteger(False)); - varShortInt: Result := ShortInt(ReadInteger(False)); - varWord: Result := Word(ReadInteger(False)); - varSmallint: Result := Smallint(ReadInteger(False)); - varLongWord: Result := LongWord(ReadInt64(HproseTagSemicolon)); - varInt64: Result := ReadInt64(HproseTagSemicolon); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := ReadUInt64(HproseTagSemicolon); -{$ENDIF} -{$IFDEF FPC} - varQWord: Result := ReadUInt64(HproseTagSemicolon); -{$ENDIF} - varString: Result := ReadUntil(HproseTagSemicolon); -{$IFDEF DELPHI2009_UP} - varUString: Result := ReadUntil(HproseTagSemicolon); -{$ENDIF} - varOleStr: Result := WideString(ReadUntil(HproseTagSemicolon)); - varBoolean: Result := ReadDouble(False) <> 0.0; - varDate: Result := TimeStampToDateTime(MSecsToTimeStamp( - StrToInt64(ReadLong(False)))); - else - Error(reInvalidCast); - end; - end; - htNull: begin - case VType of - varEmpty: Result := Unassigned; - varBoolean: Result := False; - varSingle: Result := VarAsType(0, varSingle); - varDouble: Result := VarAsType(0, varDouble); - varCurrency: Result := VarAsType(0, varCurrency); - varInteger: Result := 0; - varByte: Result := Byte(0); - varShortInt: Result := ShortInt(0); - varWord: Result := Word(0); - varSmallint: Result := Smallint(0); - varLongWord: Result := LongWord(0); - varInt64: Result := Int64(0); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := UInt64(0); -{$ENDIF} -{$IFDEF FPC} - varQWord: Result := QWord(0); -{$ENDIF} - varString: Result := ''; -{$IFDEF DELPHI2009_UP} - varUString: Result := ''; -{$ENDIF} - varOleStr: Result := WideString(''); - else - Result := Null; - end; - end; - htEmpty: begin - case VType of - varEmpty: Result := Unassigned; - varBoolean: Result := False; - varSingle: Result := VarAsType(0, varSingle); - varDouble: Result := VarAsType(0, varDouble); - varCurrency: Result := VarAsType(0, varCurrency); - varInteger: Result := 0; - varByte: Result := Byte(0); - varShortInt: Result := ShortInt(0); - varWord: Result := Word(0); - varSmallint: Result := Smallint(0); - varLongWord: Result := LongWord(0); - varInt64: Result := Int64(0); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := UInt64(0); -{$ENDIF} -{$IFDEF FPC} - varQWord: Result := QWord(0); -{$ENDIF} - varString: Result := ''; -{$IFDEF DELPHI2009_UP} - varUString: Result := ''; -{$ENDIF} - varOleStr: Result := WideString(''); - else - Result := ''; - end; - end; - htTrue: begin - case VType of - varBoolean, varVariant: Result := True; - varSingle: Result := VarAsType(1, varSingle); - varDouble: Result := VarAsType(1, varDouble); - varCurrency: Result := VarAsType(1, varCurrency); - varInteger: Result := 1; - varByte: Result := Byte(1); - varShortInt: Result := ShortInt(1); - varWord: Result := Word(1); - varSmallint: Result := Smallint(1); - varLongWord: Result := LongWord(1); - varInt64: Result := Int64(1); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := UInt64(1); -{$ENDIF} -{$IFDEF FPC} - varQWord: Result := QWord(1); -{$ENDIF} - varString: Result := 'True'; -{$IFDEF DELPHI2009_UP} - varUString: Result := 'True'; -{$ENDIF} - varOleStr: Result := WideString('True'); - else - Error(reInvalidCast); - end; - end; - htFalse: begin - case VType of - varBoolean, varVariant: Result := False; - varSingle: Result := VarAsType(0, varSingle); - varDouble: Result := VarAsType(0, varDouble); - varCurrency: Result := VarAsType(0, varCurrency); - varInteger: Result := 0; - varByte: Result := Byte(0); - varShortInt: Result := ShortInt(0); - varWord: Result := Word(0); - varSmallint: Result := Smallint(0); - varLongWord: Result := LongWord(0); - varInt64: Result := Int64(0); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := UInt64(0); -{$ENDIF} -{$IFDEF FPC} - varQWord: Result := QWord(0); -{$ENDIF} - varString: Result := 'False'; -{$IFDEF DELPHI2009_UP} - varUString: Result := 'False'; -{$ENDIF} - varOleStr: Result := WideString('False'); - else - Error(reInvalidCast); - end; - end; - htNaN: begin - case VType of - varDouble, varVariant: Result := VarAsType(NaN, varDouble); - varSingle: Result := VarAsType(NaN, varSingle); - varString: Result := 'NaN'; -{$IFDEF DELPHI2009_UP} - varUString: Result := 'NaN'; -{$ENDIF} - varOleStr: Result := WideString('NaN'); - else - Error(reInvalidCast); - end; - end; - htInfinity: begin - case VType of - varDouble, varVariant: - if ReadByte = Ord(HproseTagNeg) then - Result := VarAsType(NegInfinity, varDouble) - else - Result := VarAsType(Infinity, varDouble); - varSingle: - if ReadByte = Ord(HproseTagNeg) then - Result := VarAsType(NegInfinity, varSingle) - else - Result := VarAsType(Infinity, varSingle); - varString: - if ReadByte = Ord(HproseTagNeg) then - Result := '-Infinity' - else - Result := 'Infinity'; -{$IFDEF DELPHI2009_UP} - varUString: - if ReadByte = Ord(HproseTagNeg) then - Result := '-Infinity' - else - Result := 'Infinity'; -{$ENDIF} - varOleStr: - if ReadByte = Ord(HproseTagNeg) then - Result := WideString('-Infinity') - else - Result := WideString('Infinity'); - else - Error(reInvalidCast); - end; - end; - htUTF8Char: begin - case VType of - varOleStr, varVariant: Result := WideString(ReadUTF8Char(False)); - varString: Result := AnsiString(ReadUTF8Char(False)); -{$IFDEF DELPHI2009_UP} - varUString: Result := UnicodeString(ReadUTF8Char(False)); -{$ENDIF} - varInteger: Result := Ord(ReadUTF8Char(False)); - varByte: Result := Byte(Ord(AnsiString(ReadUTF8Char(False))[1])); - varWord: Result := Word(Ord(ReadUTF8Char(False))); - varShortInt: Result := VarAsType(Ord(ReadUTF8Char(False)), varShortInt); - varSmallint: Result := VarAsType(Ord(ReadUTF8Char(False)), varSmallint); - varLongWord: Result := VarAsType(Ord(ReadUTF8Char(False)), varLongWord); - varSingle: Result := VarAsType(Ord(ReadUTF8Char(False)), varSingle); - varDouble: Result := VarAsType(Ord(ReadUTF8Char(False)), varDouble); - varCurrency: Result := VarAsType(Ord(ReadUTF8Char(False)), varCurrency); - varInt64: Result := Int64(Ord(ReadUTF8Char(False))); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := UInt64(Ord(ReadUTF8Char(False))); -{$ENDIF} -{$IFDEF FPC} - varQWord: Result := UInt64(Ord(ReadUTF8Char(False))); -{$ENDIF} - varBoolean: Result := not CharInSet(ReadUTF8Char(False), [#0, '0', 'F', 'f']); - else - Error(reInvalidCast); - end; - end; - htString : begin - case VType of - varOleStr, varVariant: Result := ReadString(False); - varString: Result := AnsiString(ReadString(False)); -{$IFDEF DELPHI2009_UP} - varUString: Result := UnicodeString(ReadString(False)); -{$ENDIF} - varInteger: Result := StrToInt(ReadString(False)); - varByte: - if AClass = nil then - Result := VarAsType(ReadString(False), varByte) - else - Result := StrToByte(ReadString(False)); - varWord: - if AClass = nil then - Result := VarAsType(ReadString(False), varWord) - else - Result := OleStrToWord(ReadString(False)); - varShortInt: Result := VarAsType(ReadString(False), varShortInt); - varSmallint: Result := VarAsType(ReadString(False), varSmallint); - varLongWord: Result := VarAsType(ReadString(False), varLongWord); - varSingle: Result := VarAsType(ReadString(False), varSingle); - varDouble: Result := VarAsType(ReadString(False), varDouble); - varCurrency: Result := StrToCurr(ReadString(False)); - varInt64: Result := StrToInt64(ReadString(False)); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := VarAsType(ReadString(False), varUInt64); -{$ENDIF} -{$IFDEF FPC} - varQWord: Result := VarAsType(ReadString(False), varQWord); -{$ENDIF} - varBoolean: Result := VarAsType(ReadInteger(False), varBoolean); - else - Error(reInvalidCast); - end; - end; - htGuid : begin - case VType of - varString, varVariant: Result := ReadGuid(False); - varOleStr: Result := WideString(ReadGuid(False)); -{$IFDEF DELPHI2009_UP} - varUString: Result := UnicodeString(ReadGuid(False)); -{$ENDIF} - else - Error(reInvalidCast); - end; - end; - htDate : Result := ReadDate(False); - htTime : Result := ReadTime(False); - htBytes : Result := ReadBytes(False); - htList : Result := ReadList(VType and varTypeMask, AClass, False); - htMap : Result := ReadMap(AClass, False); - htClass : begin - ReadClass; - Result := Unserialize(VType, AClass); - end; - htObject : Result := ReadObject(AClass, False); - htRef : Result := ReadRef; - htError : raise EHproseException.Create(ReadString()); - else - raise EHproseException.Create('Unexpected serialize tag "' + - Tag + '" in stream'); - end; -end; - -function THproseReader.ReadBooleanArray(Count: Integer): Variant; -var - P: PWordBoolArray; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varBoolean); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varBoolean); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; - -function THproseReader.ReadDoubleArray(Count: Integer): Variant; -var - P: PDoubleArray; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varDouble); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varDouble); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; - -function THproseReader.ReadInt64Array(Count: Integer): Variant; -var - P: PInt64Array; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varInt64); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varInt64); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; - -function THproseReader.ReadIntegerArray(Count: Integer): Variant; -var - P: PIntegerArray; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varInteger); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varInteger); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; - -function THproseReader.ReadList(ElementType: TVarType; - AClass: TClass; IncludeTag: Boolean): Variant; -var - Count: Integer; -begin - if IncludeTag and - (CheckTags(HproseTagList + HproseTagRef) = HproseTagRef) then begin - Result := ReadRef; - Exit; - end; - Count := ReadInt(HproseTagOpenbrace); - if AClass = nil then - case ElementType of - varInteger: Result := ReadIntegerArray(Count); - varShortInt: Result := ReadShortIntArray(Count); - varWord: Result := ReadWordArray(Count); - varSmallint: Result := ReadSmallintArray(Count); - varLongWord: Result := ReadLongWordArray(Count); - varSingle: Result := ReadSingleArray(Count); - varDouble: Result := ReadDoubleArray(Count); - varCurrency: Result := ReadCurrencyArray(Count); - varInt64: Result := ReadInt64Array(Count); -{$IFDEF DELPHI2009_UP} - varUInt64: Result := ReadUInt64Array(Count); -{$ENDIF} -{$IFDEF FPC} - varQWord: Result := ReadQWordArray(Count); -{$ENDIF} - varOleStr: Result := ReadWideStringArray(Count); - varBoolean: Result := ReadBooleanArray(Count); - varDate: Result := ReadDateTimeArray(Count); - varVariant: Result := ReadList(TArrayList, Count); - end - else if AClass.InheritsFrom(TAbstractList) then begin - Result := ReadList(AClass, Count); - end - else - raise EHproseException.Create(AClass.ClassName + ' is not an IList class'); - CheckTag(HproseTagClosebrace); -end; - -function THproseReader.ReadList(AClass: TClass; Count: Integer): Variant; -var - I: Integer; - AList: IList; -begin - AList := TListClass(AClass).Create(Count) as IList; - Result := AList; - FRefList.Add(Result); - for I := 0 to Count - 1 do AList[I] := Unserialize; -end; - -function THproseReader.ReadLongWordArray(Count: Integer): Variant; -var - P: PLongWordArray; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varLongWord); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varLongWord); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; - -function THproseReader.ReadMap(AClass: TClass; IncludeTag: Boolean): Variant; -var - I, Count: Integer; - Key: Variant; - AMap: IMap; - Instance: TObject; - PropInfo: PPropInfo; - VType: TVarType; - PropClass: TClass; -begin - if IncludeTag and - (CheckTags(HproseTagMap + HproseTagRef) = HproseTagRef) then begin - Result := ReadRef; - Exit; - end; - Count := ReadInt(HproseTagOpenbrace); - if AClass = nil then AClass := THashMap; - if AClass.InheritsFrom(TAbstractMap) then begin - AMap := TMapClass(AClass).Create(Count) as IMap; - Result := AMap; - FRefList.Add(Result); - for I := 0 to Count - 1 do begin - Key := Unserialize; - AMap[Key] := Unserialize; - end; - end - else begin - Instance := AClass.Create; - if AClass.InheritsFrom(TInterfacedObject) then - Result := IInterface(TInterfacedObject(Instance)) - else - Result := ObjToVar(Instance); - FRefList.Add(Result); - for I := 0 to Count - 1 do begin - Key := ReadString; - PropInfo := GetPropInfo(AClass, Key); - if (PropInfo <> nil) then begin - VType := GetVarTypeAndClass(PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF}, PropClass); - SetPropValue(Instance, PropInfo, Unserialize(VType, PropClass)); - end - else Unserialize; - end; - end; - CheckTag(HproseTagClosebrace); -end; - -function THproseReader.ReadObject(AClass: TClass; IncludeTag: Boolean): Variant; -var - Tag: AnsiChar; - C: Variant; - AttrNames: IList; - I, Count: Integer; - Cls: TClass; - IID: TGUID; - AMap: IMap; - Intf: IInterface; - Instance: TObject; - PropInfo: PPropInfo; - VType: TVarType; - PropClass: TClass; -begin - if IncludeTag then repeat - Tag := CheckTags(HproseTagObject + HproseTagClass + HproseTagRef); - if Tag = HproseTagRef then begin - Result := ReadRef; - Exit; - end; - if Tag = HproseTagClass then ReadClass; - until Tag = HproseTagObject; - C := FClassRefList[ReadInt(HproseTagOpenbrace)]; - AttrNames := VarToList(FAttrRefMap[C]); - Count := AttrNames.Count; - if {$IFDEF CPU64}VarType(C) = varInt64{$ELSE}VarType(C) = varInteger{$ENDIF} then begin -{$IFDEF CPU64} - Cls := TClass(Int64(C)); -{$ELSE} - Cls := TClass(Integer(C)); -{$ENDIF} - if (AClass = nil) or Cls.InheritsFrom(AClass) then AClass := Cls; - end; - if AClass <> nil then begin - if AClass.InheritsFrom(TInterfacedObject) then begin - IID := GetInterfaceByClass(AClass); - Supports(TInterfacedClass(AClass).Create, IID, Intf); - Result := Intf; - Instance := IntfToObj(Intf); - end - else begin - Instance := AClass.Create; - Result := ObjToVar(Instance); - end; - FRefList.Add(Result); - for I := 0 to Count - 1 do begin - PropInfo := GetPropInfo(Instance, AttrNames[I]); - if (PropInfo <> nil) then begin - VType := GetVarTypeAndClass(PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF}, PropClass); - SetPropValue(Instance, PropInfo, Unserialize(VType, PropClass)); - end - else Unserialize; - end; - end - else begin - AMap := TCaseInsensitiveHashMap.Create(Count); - Result := AMap; - FRefList.Add(Result); - for I := 0 to Count - 1 do AMap[AttrNames[I]] := Unserialize; - end; - CheckTag(HproseTagClosebrace); -end; - -function THproseReader.ReadShortIntArray(Count: Integer): Variant; -var - P: PShortIntArray; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varShortInt); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varShortInt); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; - -function THproseReader.ReadSingleArray(Count: Integer): Variant; -var - P: PSingleArray; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varSingle); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varSingle); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; - -function THproseReader.ReadSmallIntArray(Count: Integer): Variant; -var - P: PSmallIntArray; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varSmallInt); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varSmallInt); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; - -function THproseReader.ReadWideStringArray(Count: Integer): Variant; -var - P: PWideStringArray; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varOleStr); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varOleStr); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; - -function THproseReader.ReadWordArray(Count: Integer): Variant; -var - P: PWordArray; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varWord); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varWord); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; - -function THproseReader.ReadCurrencyArray(Count: Integer): Variant; -var - P: PCurrencyArray; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varCurrency); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varCurrency); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; - -function THproseReader.ReadDateTimeArray(Count: Integer): Variant; -var - P: PDateTimeArray; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varDate); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varDate); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; - -procedure THproseReader.ReadDateTimeRaw(const OStream: TStream; Tag: AnsiChar); -begin - OStream.WriteBuffer(Tag, 1); - repeat - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - until (Tag = HproseTagSemicolon) or - (Tag = HproseTagUTC); -end; - -{$IFDEF DELPHI2009_UP} -function THproseReader.ReadUInt64Array(Count: Integer): Variant; -var - P: PUInt64Array; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varUInt64); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varUInt64); - VarArrayUnlock(Result); -{$IFDEF FPC} - FRefList[N] := Result; -{$ELSE} - FRefList[N] := VarArrayRef(Result); -{$ENDIF} -end; -{$ENDIF} - -{$IFDEF FPC} -function THproseReader.ReadQWordArray(Count: Integer): Variant; -var - P: PQWordArray; - I, N: Integer; -begin - Result := VarArrayCreate([0, Count - 1], varQWord); - N := FRefList.Add(Null); - P := VarArrayLock(Result); - for I := 0 to Count - 1 do P^[I] := Unserialize(varQWord); - VarArrayUnlock(Result); - FRefList[N] := Result; -end; -{$ENDIF} - -function THproseReader.ReadRaw: TMemoryStream; -begin - Result := TMemoryStream.Create; - ReadRaw(Result); -end; - -procedure THproseReader.ReadRaw(const OStream: TStream); -var - Tag: AnsiChar; -begin - FStream.ReadBuffer(Tag, 1); - ReadRaw(OStream, Tag); -end; - -procedure THproseReader.ReadRaw(const OStream: TStream; Tag: AnsiChar); -begin - case Tag of - '0'..'9', htNull, htEmpty, htTrue, htFalse, htNaN: OStream.WriteBuffer(Tag, 1); - htInfinity: ReadInfinityRaw(OStream, Tag); - htInteger, htLong, htDouble, htRef: ReadNumberRaw(OStream, Tag); - htDate, htTime: ReadDateTimeRaw(OStream, Tag); - htUTF8Char: ReadUTF8CharRaw(OStream, Tag); - htBytes: ReadBytesRaw(OStream, Tag); - htString: ReadStringRaw(OStream, Tag); - htGuid: ReadGuidRaw(OStream, Tag); - htList, htMap, htObject: ReadComplexRaw(OStream, Tag); - htClass: begin - ReadComplexRaw(OStream, Tag); - ReadRaw(OStream); - end; - htError: begin - OStream.WriteBuffer(Tag, 1); - ReadRaw(OStream); - end; - else - raise EHproseException.Create('Unexpected serialize tag "' + - Tag + '" in stream'); - end; -end; - -function THproseReader.ReadRef: Variant; -begin - Result := FRefList[ReadInt(HproseTagSemicolon)]; -end; - -procedure THproseReader.ReadClass; -var - ClassName: string; - I, Count: Integer; - AttrNames: IList; - AClass: TClass; - Key: Variant; -begin - ClassName := ReadString(False, False); - Count := ReadInt(HproseTagOpenbrace); - AttrNames := TArrayList.Create(Count, False); - for I := 0 to Count - 1 do AttrNames[I] := ReadString(); - CheckTag(HproseTagClosebrace); - AClass := GetClassByAlias(ClassName); - if AClass = nil then begin - Key := IInterface(TInterfacedObject.Create()); - FClassRefList.Add(Key); - FAttrRefMap[Key] := AttrNames; - end - else begin -{$IFDEF CPU64} - Key := Int64(AClass); -{$ELSE} - Key := Integer(AClass); -{$ENDIF} - FClassRefList.Add(Key); - FAttrRefMap[Key] := AttrNames; - end; -end; - -procedure THproseReader.ReadComplexRaw(const OStream: TStream; Tag: AnsiChar); -begin - OStream.WriteBuffer(Tag, 1); - repeat - FStream.ReadBuffer(Tag, 1); - OStream.WriteBuffer(Tag, 1); - until (Tag = HproseTagOpenbrace); - FStream.ReadBuffer(Tag, 1); - while (Tag <> HproseTagClosebrace) do begin - ReadRaw(OStream, Tag); - FStream.ReadBuffer(Tag, 1); - end; - OStream.WriteBuffer(Tag, 1); -end; - -function THproseReader.ReadGuid(IncludeTag: Boolean): AnsiString; -begin - if IncludeTag and - (CheckTags(HproseTagGuid + HproseTagRef) = HproseTagRef) then begin - Result := AnsiString(ReadRef()); - Exit; - end; - SetLength(Result, 38); - FStream.ReadBuffer(Result[1], 38); - FRefList.Add(Result); -end; - -procedure THproseReader.ReadGuidRaw(const OStream: TStream; Tag: AnsiChar); -begin - OStream.WriteBuffer(Tag, 1); - OStream.CopyFrom(FStream, 38); -end; - -procedure THproseReader.Reset; -begin - FRefList.Clear; - FClassRefList.Clear; - FAttrRefMap.Clear; -end; - -{ THproseWriter } - -constructor THproseWriter.Create(AStream: TStream); -begin - FStream := AStream; - FRefList := THashedList.Create(False); - FClassRefList := THashedList.Create(False); -end; - -procedure THproseWriter.Serialize(const Value: Variant); -var - AList: IList; - AMap: IMap; - Obj: TObject; -begin - with FindVarData(Value)^ do begin - case VType and not varByRef of - varEmpty, varNull : - WriteNull; - varBoolean : - WriteBoolean(Value); - varByte, varWord, varShortInt, varSmallint, varInteger: - WriteInteger(Value); -{$IFDEF DELPHI2009_UP} - varUInt64: - WriteLong(RawByteString(UIntToStr(Value))); -{$ENDIF} - {$IFDEF FPC}varQWord, {$ENDIF} - varLongWord, varInt64: - WriteLong(RawByteString(VarToStr(Value))); - varSingle, varDouble: - WriteDouble(Value); - varCurrency: - WriteCurrency(Value); - varString, {$IFDEF DELPHI2009_UP}varUString, {$ENDIF}varOleStr: - if Length(Value) = 0 then - WriteEmpty - else if Length(Value) = 1 then - WriteUTF8Char(VarToWideStr(Value)[1]) - else - WriteString(Value); - varDate: - WriteDateTime(Value); - varUnknown: - if (IInterface(Value) = nil) then - WriteNull - else if Supports(IInterface(Value), IList, AList) then - WriteList(AList) - else if Supports(IInterface(Value), IMap, AMap) then - WriteMap(AMap) - else - WriteInterface(IInterface(Value)); - else - if VType and varArray = varArray then - if (VType and varTypeMask = varByte) and - (VarArrayDimCount(Value) = 1) then - WriteBytes(Value) - else - WriteArray(Value) - else if VType and not varByRef = varObject then begin - Obj := VarToObj(Value); - if Obj = nil then WriteNull - else if Obj is TAbstractList then WriteList(TAbstractList(Obj)) - else if Obj is TAbstractMap then WriteMap(TAbstractMap(Obj)) - else WriteObject(Obj); - end - end; - end; -end; - -procedure THproseWriter.Serialize(const Value: array of const); -begin - WriteArray(Value); -end; - -procedure THproseWriter.WriteRawByteString(const S: RawByteString); -begin - FStream.WriteBuffer(S[1], Length(S)); -end; - - -procedure THproseWriter.WriteArray(const Value: array of const); -var - I, N: Integer; - AList: IList; - AMap: IMap; -begin - FRefList.Add(Null); - N := Length(Value); - FStream.WriteBuffer(HproseTagList, 1); - if N > 0 then WriteRawByteString(RawByteString(IntToStr(N))); - FStream.WriteBuffer(HproseTagOpenbrace, 1); - for I := 0 to N - 1 do - with Value[I] do - case VType of - vtInteger: WriteInteger(VInteger); - vtBoolean: WriteBoolean(VBoolean); - vtChar: WriteUTF8Char(WideString(VChar)[1]); - vtExtended: WriteDouble(VExtended^); - vtString: WriteString(WideString(VString^)); - vtPChar: WriteString(WideString(AnsiString(VPChar))); - vtObject: - if VObject = nil then - WriteNull - else if Supports(VObject, IList, AList) then - WriteList(AList) - else if Supports(VObject, IMap, AMap) then - WriteMap(AMap) - else - WriteObject(VObject); - vtWideChar: WriteUTF8Char(VWideChar); - vtPWideChar: WriteString(WideString(VPWideChar)); - vtAnsiString: WriteString(WideString(AnsiString(VAnsiString))); - vtCurrency: WriteCurrency(VCurrency^); - vtVariant: Serialize(VVariant^); - vtInterface: - if IInterface(VInterface) = nil then - WriteNull - else if Supports(IInterface(VInterface), IList, AList) then - WriteList(AList) - else if Supports(IInterface(VInterface), IMap, AMap) then - WriteMap(AMap) - else - WriteInterface(IInterface(VInterface)); - vtWideString: WriteString(WideString(VWideString)); - vtInt64: WriteLong(VInt64^); -{$IFDEF FPC} - vtQWord: WriteLong(VQWord^); -{$ENDIF} -{$IFDEF DELPHI2009_UP} - vtUnicodeString: WriteString(UnicodeString(VUnicodeString)); -{$ENDIF} - else - WriteNull; - end; - FStream.WriteBuffer(HproseTagClosebrace, 1); -end; - -procedure THproseWriter.WriteArray(const Value: Variant; - CheckRef: Boolean); -var - PVar: PVarData; - P: Pointer; - Rank, Count, MaxRank, I, N: Integer; - Des: array of array[0..1] of Integer; - Loc, Len: array of Integer; -begin - if WriteRef(Value, CheckRef) then begin - PVar := FindVarData(Value); - Rank := VarArrayDimCount(Value); - if Rank = 1 then begin - Count := VarArrayHighBound(Value, 1) - VarArrayLowBound(Value, 1) + 1; - FStream.WriteBuffer(HproseTagList, 1); - if Count > 0 then WriteRawByteString(RawByteString(IntToStr(Count))); - FStream.WriteBuffer(HproseTagOpenbrace, 1); - P := VarArrayLock(Value); - case PVar.VType and varTypeMask of - varInteger: WriteIntegerArray(P, Count); - varShortInt: WriteShortIntArray(P, Count); - varWord: WriteWordArray(P, Count); - varSmallint: WriteSmallintArray(P, Count); - varLongWord: WriteLongWordArray(P, Count); - varSingle: WriteSingleArray(P, Count); - varDouble: WriteDoubleArray(P, Count); - varCurrency: WriteCurrencyArray(P, Count); - varInt64: WriteInt64Array(P, Count); -{$IFDEF DELPHI2009_UP} - varUInt64: WriteUInt64Array(P, Count); -{$ENDIF} -{$IFDEF FPC} - varQWord: WriteQWordArray(P, Count); -{$ENDIF} - varOleStr: WriteWideStringArray(P, Count); - varBoolean: WriteBooleanArray(P, Count); - varDate: WriteDateTimeArray(P, Count); - varVariant: WriteVariantArray(P, Count); - end; - VarArrayUnLock(Value); - FStream.WriteBuffer(HproseTagClosebrace, 1); - end - else begin - SetLength(Des, Rank); - SetLength(Loc, Rank); - SetLength(Len, Rank); - MaxRank := Rank - 1; - for I := 0 to MaxRank do begin - Des[I, 0] := VarArrayLowBound(Value, I + 1); - Des[I, 1] := VarArrayHighBound(Value, I + 1); - Loc[I] := Des[I, 0]; - Len[I] := Des[I, 1] - Des[I, 0] + 1; - end; - FStream.WriteBuffer(HproseTagList, 1); - if Len[0] > 0 then WriteRawByteString(RawByteString(IntToStr(Len[0]))); - FStream.WriteBuffer(HproseTagOpenbrace, 1); - while Loc[0] <= Des[0, 1] do begin - N := 0; - for I := Maxrank downto 1 do - if Loc[I] = Des[I, 0] then Inc(N) else Break; - for I := Rank - N to MaxRank do begin - FRefList.Add(Null); - FStream.WriteBuffer(HproseTagList, 1); - if Len[I] > 0 then WriteRawByteString(RawByteString(IntToStr(Len[I]))); - FStream.WriteBuffer(HproseTagOpenbrace, 1); - end; - for I := Des[MaxRank, 0] to Des[MaxRank, 1] do begin - Loc[MaxRank] := I; - Serialize(VarArrayGet(Value, Loc)); - end; - Inc(Loc[MaxRank]); - for I := MaxRank downto 1 do - if Loc[I] > Des[I, 1] then begin - Loc[I] := Des[I, 0]; - Inc(Loc[I - 1]); - FStream.WriteBuffer(HproseTagClosebrace, 1); - end; - end; - FStream.WriteBuffer(HproseTagClosebrace, 1); - end; - end; -end; - -procedure THproseWriter.WriteBoolean(B: Boolean); -begin - FStream.WriteBuffer(HproseTagBoolean[B], 1); -end; - -procedure THproseWriter.WriteBooleanArray(var P; Count: Integer); -var - AP: PWordBoolArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteBoolean(AP^[I]); -end; - -procedure THproseWriter.WriteBytes(const Bytes: Variant; - CheckRef: Boolean); -var - N: Integer; -begin - if WriteRef(Bytes, CheckRef) then begin - N := VarArrayHighBound(Bytes, 1) - VarArrayLowBound(Bytes, 1) + 1; - FStream.WriteBuffer(HproseTagBytes, 1); - WriteRawByteString(RawByteString(IntToStr(N))); - FStream.WriteBuffer(HproseTagQuote, 1); - FStream.WriteBuffer(VarArrayLock(Bytes)^, N); - VarArrayUnLock(Bytes); - FStream.WriteBuffer(HproseTagQuote, 1); - end; -end; - -function THproseWriter.WriteClass(Instance: TObject): Integer; -var - ClassAlias: string; - PropName: ShortString; - PropList: PPropList; - PropCount, I: Integer; - CachePointer: PSerializeCache; - CacheStream: TMemoryStream; - TempData: RawByteString; - TempWStr: WideString; -begin - ClassAlias := GetClassAlias(Instance.ClassType); - if ClassAlias = '' then - raise EHproseException.Create(Instance.ClassName + ' has not registered'); - PropertiesCache.Lock; - try -{$IFDEF CPU64} - CachePointer := PSerializeCache(Int64(PropertiesCache[ClassAlias])); -{$ELSE} - CachePointer := PSerializeCache(Integer(PropertiesCache[ClassAlias])); -{$ENDIF} - if CachePointer = nil then begin - New(CachePointer); - try - CachePointer^.RefCount := 0; - CachePointer^.Data := ''; - CacheStream := TMemoryStream.Create; - try - PropCount := GetStoredPropList(Instance, PropList); - try - CacheStream.WriteBuffer(HproseTagClass, 1); - TempData := RawByteString(IntToStr(Length(ClassAlias))); - CacheStream.WriteBuffer(TempData[1], Length(TempData)); - CacheStream.WriteBuffer(HproseTagQuote, 1); - Tempdata := RawByteString(ClassAlias); - CacheStream.WriteBuffer(TempData[1], Length(TempData)); - CacheStream.WriteBuffer(HproseTagQuote, 1); - if PropCount > 0 then begin - Tempdata := RawByteString(IntToStr(PropCount)); - CacheStream.WriteBuffer(TempData[1], Length(TempData)); - end; - CacheStream.WriteBuffer(HproseTagOpenbrace, 1); - for I := 0 to PropCount - 1 do begin - PropName := PropList^[I]^.Name; - if PropName[1] in ['A'..'Z'] then - PropName[1] := AnsiChar(Integer(PropName[1]) + 32); - TempWStr := WideString(PropName); - CacheStream.WriteBuffer(HproseTagString, 1); - Tempdata := RawByteString(IntToStr(Length(TempWStr))); - CacheStream.WriteBuffer(TempData[1], Length(TempData)); - CacheStream.WriteBuffer(HproseTagQuote, 1); - Tempdata := UTF8Encode(TempWStr); - CacheStream.WriteBuffer(TempData[1], Length(TempData)); - CacheStream.WriteBuffer(HproseTagQuote, 1); - Inc(CachePointer^.RefCount); - end; - CacheStream.WriteBuffer(HproseTagClosebrace, 1); - finally - FreeMem(PropList); - end; - CacheStream.Position := 0; - SetLength(CachePointer^.Data, CacheStream.Size); - Move(CacheStream.Memory^, PAnsiChar(CachePointer^.Data)^, CacheStream.Size); - finally - CacheStream.Free; - end; - except - Dispose(CachePointer); - end; -{$IFDEF CPU64} - PropertiesCache[ClassAlias] := Int64(CachePointer); -{$ELSE} - PropertiesCache[ClassAlias] := Integer(CachePointer); -{$ENDIF} - end; - finally - PropertiesCache.UnLock; - end; - FStream.WriteBuffer(CachePointer^.Data[1], Length(CachePointer^.Data)); - if CachePointer^.RefCount > 0 then - FRefList.Count := FRefList.Count + CachePointer^.RefCount; - Result := FClassRefList.Add(Instance.ClassName); -end; - -procedure THproseWriter.WriteCurrency(C: Currency); -begin - stream.WriteBuffer(HproseTagDouble, 1); - WriteRawByteString(RawByteString(CurrToStr(C))); - stream.WriteBuffer(HproseTagSemicolon, 1); -end; - -procedure THproseWriter.WriteCurrencyArray(var P; Count: Integer); -var - AP: PCurrencyArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteCurrency(AP^[I]); -end; - -procedure THproseWriter.WriteDateTimeArray(var P; Count: Integer); -var - AP: PDateTimeArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteDateTime(AP^[I]); -end; - -procedure THproseWriter.WriteDateTime(const ADateTime: TDateTime; - CheckRef: Boolean); -var - ADate, ATime, AMillisecond: RawByteString; -begin - if WriteRef(ADateTime, CheckRef) then begin - ADate := RawByteString(FormatDateTime('yyyymmdd', ADateTime)); - ATime := RawByteString(FormatDateTime('hhnnss', ADateTime)); - AMillisecond := RawByteString(FormatDateTime('zzz', ADateTime)); - if (ATime = '000000') and (AMillisecond = '000') then begin - FStream.WriteBuffer(HproseTagDate, 1); - WriteRawByteString(ADate); - end - else if ADate = '18991230' then begin - FStream.WriteBuffer(HproseTagTime, 1); - WriteRawByteString(ATime); - if AMillisecond <> '000' then begin - FStream.WriteBuffer(HproseTagPoint, 1); - WriteRawByteString(AMillisecond); - end; - end - else begin - FStream.WriteBuffer(HproseTagDate, 1); - WriteRawByteString(ADate); - FStream.WriteBuffer(HproseTagTime, 1); - WriteRawByteString(ATime); - if AMillisecond <> '000' then begin - FStream.WriteBuffer(HproseTagPoint, 1); - WriteRawByteString(AMillisecond); - end; - end; - FStream.WriteBuffer(HproseTagSemicolon, 1); - end; -end; - -procedure THproseWriter.WriteDouble(D: Extended); -begin - if IsNaN(D) then - WriteNaN - else if IsInfinite(D) then - WriteInfinity(Sign(D) = 1) - else begin - stream.WriteBuffer(HproseTagDouble, 1); - WriteRawByteString(RawByteString(FloatToStr(D))); - stream.WriteBuffer(HproseTagSemicolon, 1); - end; -end; - -procedure THproseWriter.WriteDoubleArray(var P; Count: Integer); -var - AP: PDoubleArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteDouble(AP^[I]); -end; - -procedure THproseWriter.WriteInfinity(Positive: Boolean); -begin - FStream.WriteBuffer(HproseTagInfinity, 1); - FStream.WriteBuffer(HproseTagSign[Positive], 1); -end; - -procedure THproseWriter.WriteInt64Array(var P; Count: Integer); -var - AP: PInt64Array absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteLong(AP^[I]); -end; - -{$IFDEF DELPHI2009_UP} -procedure THproseWriter.WriteUInt64Array(var P; Count: Integer); -var - AP: PUInt64Array absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteLong(AP^[I]); -end; -{$ENDIF} - -{$IFDEF FPC} -procedure THproseWriter.WriteQWordArray(var P; Count: Integer); -var - AP: PQWordArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteLong(AP^[I]); -end; -{$ENDIF} - -procedure THproseWriter.WriteInteger(I: Integer); -var - C: AnsiChar; -begin - if (I >= 0) and (I <= 9) then begin - C := AnsiChar(I + Ord('0')); - FStream.WriteBuffer(C, 1); - end - else begin - FStream.WriteBuffer(HproseTagInteger, 1); - WriteRawByteString(RawByteString(IntToStr(I))); - FStream.WriteBuffer(HproseTagSemicolon, 1); - end; -end; - -procedure THproseWriter.WriteIntegerArray(var P; Count: Integer); -var - AP: PIntegerArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteInteger(AP^[I]); -end; - -procedure THproseWriter.WriteList(AList: IList; CheckRef: Boolean); -var - Count, I: Integer; -begin - if WriteRef(AList, CheckRef) then begin - Count := AList.Count; - FStream.WriteBuffer(HproseTagList, 1); - if Count > 0 then WriteRawByteString(RawByteString(IntToStr(Count))); - FStream.WriteBuffer(HproseTagOpenbrace, 1); - for I := 0 to Count - 1 do Serialize(AList[I]); - FStream.WriteBuffer(HproseTagClosebrace, 1); - end; -end; - -procedure THproseWriter.WriteLong(const L: RawByteString); -begin - if (Length(L) = 1) and (L[1] in ['0'..'9']) then - FStream.WriteBuffer(L[1], 1) - else begin - FStream.WriteBuffer(HproseTagLong, 1); - WriteRawByteString(L); - FStream.WriteBuffer(HproseTagSemicolon, 1); - end; -end; - -procedure THproseWriter.WriteLong(L: Int64); -var - C: AnsiChar; -begin - if (L >= 0) and (L <= 9) then begin - C := AnsiChar(L + Ord('0')); - FStream.WriteBuffer(C, 1); - end - else begin - FStream.WriteBuffer(HproseTagLong, 1); - WriteRawByteString(RawByteString(IntToStr(L))); - FStream.WriteBuffer(HproseTagSemicolon, 1); - end; -end; - -{$IFDEF DELPHI2009_UP} -procedure THproseWriter.WriteLong(L: UInt64); -var - C: AnsiChar; -begin - if L <= 9 then begin - C := AnsiChar(L + Ord('0')); - FStream.WriteBuffer(C, 1); - end - else begin - FStream.WriteBuffer(HproseTagLong, 1); - WriteRawByteString(RawByteString(UIntToStr(L))); - FStream.WriteBuffer(HproseTagSemicolon, 1); - end; -end; -{$ENDIF} - -{$IFDEF FPC} -procedure THproseWriter.WriteLong(L: QWord); -var - C: AnsiChar; -begin - if L <= 9 then begin - C := AnsiChar(L + Ord('0')); - FStream.WriteBuffer(C, 1); - end - else begin - FStream.WriteBuffer(HproseTagLong, 1); - WriteRawByteString(RawByteString(IntToStr(L))); - FStream.WriteBuffer(HproseTagSemicolon, 1); - end; -end; -{$ENDIF} - -procedure THproseWriter.WriteLongWordArray(var P; Count: Integer); -var - AP: PLongWordArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteLong(AP^[I]); -end; - -procedure THproseWriter.WriteMap(AMap: IMap; CheckRef: Boolean); -var - Count, I: Integer; -begin - if WriteRef(AMap, CheckRef) then begin - Count := AMap.Count; - FStream.WriteBuffer(HproseTagMap, 1); - if Count > 0 then WriteRawByteString(RawByteString(IntToStr(Count))); - FStream.WriteBuffer(HproseTagOpenbrace, 1); - for I := 0 to Count - 1 do begin - Serialize(AMap.Keys[I]); - Serialize(AMap.Values[I]); - end; - FStream.WriteBuffer(HproseTagClosebrace, 1); - end; -end; - -procedure THproseWriter.WriteNaN; -begin - FStream.WriteBuffer(HproseTagNaN, 1); -end; - -procedure THproseWriter.WriteNull; -begin - FStream.WriteBuffer(HproseTagNull, 1); -end; - -procedure THproseWriter.WriteEmpty; -begin - FStream.WriteBuffer(HproseTagEmpty, 1); -end; - -procedure THproseWriter.WriteObject(AObject: TObject; CheckRef: Boolean); -var - Ref, ClassRef: Integer; - Value: Variant; - PropList: PPropList; - PropCount, I: Integer; -begin - Value := ObjToVar(AObject); - if CheckRef then begin - Ref := FRefList.IndexOf(Value); - if Ref > -1 then begin - WriteRef(Ref); - Exit; - end; - end; - ClassRef := FClassRefList.IndexOf(AObject.ClassName); - if ClassRef < 0 then ClassRef := WriteClass(AObject); - FRefList.Add(Value); - FStream.WriteBuffer(HproseTagObject, 1); - WriteRawByteString(RawByteString(IntToStr(ClassRef))); - FStream.WriteBuffer(HproseTagOpenbrace, 1); - PropCount := GetStoredPropList(AObject, PropList); - try - for I := 0 to PropCount - 1 do - Serialize(GetPropValue(AObject, PropList^[I])); - finally - FreeMem(PropList); - end; - FStream.WriteBuffer(HproseTagClosebrace, 1); -end; - -procedure THproseWriter.WriteInterface(Intf: IInterface; - CheckRef: Boolean); -var - Ref, ClassRef: Integer; - Value: Variant; - AObject: TObject; - PropList: PPropList; - PropCount, I: Integer; -begin - Value := Intf; - if CheckRef then begin - Ref := FRefList.IndexOf(Value); - if Ref > -1 then begin - WriteRef(Ref); - Exit; - end; - end; - AObject := IntfToObj(Intf); - ClassRef := FClassRefList.IndexOf(AObject.ClassName); - if ClassRef < 0 then ClassRef := WriteClass(AObject); - FRefList.Add(Value); - FStream.WriteBuffer(HproseTagObject, 1); - WriteRawByteString(RawByteString(IntToStr(ClassRef))); - FStream.WriteBuffer(HproseTagOpenbrace, 1); - PropCount := GetStoredPropList(AObject, PropList); - try - for I := 0 to PropCount - 1 do - Serialize(GetPropValue(AObject, PropList^[I])); - finally - FreeMem(PropList); - end; - FStream.WriteBuffer(HproseTagClosebrace, 1); -end; - -function THproseWriter.WriteRef(const Value: Variant; - CheckRef: Boolean): Boolean; -var - Ref: Integer; -begin - if CheckRef then begin - Ref := FRefList.IndexOf(Value); - if Ref > -1 then begin - WriteRef(Ref); - Result := False; - Exit; - end; - end; - FRefList.Add(Value); - Result := True; -end; - -procedure THproseWriter.WriteRef(Value: Integer); -begin - FStream.WriteBuffer(HproseTagRef, 1); - WriteRawByteString(RawByteString(IntToStr(Value))); - FStream.WriteBuffer(HproseTagSemicolon, 1); -end; - -procedure THproseWriter.WriteShortIntArray(var P; Count: Integer); -var - AP: PShortIntArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteInteger(AP^[I]); -end; - -procedure THproseWriter.WriteSingleArray(var P; Count: Integer); -var - AP: PSingleArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteDouble(AP^[I]); -end; - -procedure THproseWriter.WriteSmallIntArray(var P; Count: Integer); -var - AP: PSmallIntArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteInteger(AP^[I]); -end; - -procedure THproseWriter.WriteUTF8Char(C: WideChar); -begin - FStream.WriteBuffer(HproseTagUTF8Char, 1); - WriteRawByteString(UTF8Encode(WideString(C))); -end; - -procedure THproseWriter.WriteString(const S: WideString; - CheckRef: Boolean); -begin - if WriteRef(S, CheckRef) then begin - FStream.WriteBuffer(HproseTagString, 1); - WriteRawByteString(RawByteString(IntToStr(Length(S)))); - FStream.WriteBuffer(HproseTagQuote, 1); - WriteRawByteString(UTF8Encode(S)); - FStream.WriteBuffer(HproseTagQuote, 1); - end; -end; - -procedure THproseWriter.WriteVariantArray(var P; Count: Integer); -var - AP: PVariantArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do Serialize(AP^[I]); -end; - -procedure THproseWriter.WriteWideStringArray(var P; Count: Integer); -var - AP: PWideStringArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteString(AP^[I]); -end; - -procedure THproseWriter.WriteWordArray(var P; Count: Integer); -var - AP: PWordArray absolute P; - I: Integer; -begin - for I := 0 to Count - 1 do WriteInteger(AP^[I]); -end; - -procedure THproseWriter.Reset; -begin - FRefList.Clear; - FClassRefList.Clear; -end; - -{ HproseSerialize } - -function HproseSerialize(Value: TObject): RawByteString; -begin - Result := HproseSerialize(ObjToVar(Value)); -end; - -function HproseSerialize(const Value: Variant): RawByteString; -var - Writer: THproseWriter; - Stream: TMemoryStream; -begin - Stream := TMemoryStream.Create; - try - Writer := THproseWriter.Create(Stream); - try - Writer.Serialize(Value); - Stream.Position := 0; - SetLength(Result, Stream.Size); - Move(Stream.Memory^, PAnsiChar(Result)^, Stream.Size); - finally - Writer.Free; - end; - finally - Stream.Free; - end; -end; - -function HproseSerialize(const Value: array of const): RawByteString; -var - Writer: THproseWriter; - Stream: TMemoryStream; -begin - Stream := TMemoryStream.Create; - try - Writer := THproseWriter.Create(Stream); - try - Writer.Serialize(Value); - Stream.Position := 0; - SetLength(Result, Stream.Size); - Move(Stream.Memory^, PAnsiChar(Result)^, Stream.Size); - finally - Writer.Free; - end; - finally - Stream.Free; - end; -end; - -{ HproseUnserialize } - -function HproseUnserialize(const Data: RawByteString; VType: TVarType; - AClass: TClass): Variant; -var - Reader: THproseReader; - Stream: TMemoryStream; -begin - Stream := TMemoryStream.Create; - try - Stream.SetSize(Length(Data)); - Move(PAnsiChar(Data)^, Stream.Memory^, Stream.Size); - Reader := THproseReader.Create(Stream); - try - Result := Reader.Unserialize(VType, AClass); - finally - Reader.Free; - end; - finally - Stream.Free; - end; -end; - -{ THproseFormatter } - -class function THproseFormatter.Serialize( - Value: TObject): RawByteString; -begin - Result := HproseSerialize(Value); -end; - -class function THproseFormatter.Serialize( - const Value: Variant): RawByteString; -begin - Result := HproseSerialize(Value); -end; - -class function THproseFormatter.Serialize( - const Value: array of const): RawByteString; -begin - Result := HproseSerialize(Value); -end; - -class function THproseFormatter.Unserialize(const Data: RawByteString; - VType: TVarType; AClass: TClass): Variant; -begin - Result := HproseUnserialize(Data, VType, AClass); -end; - -procedure FreePropertiesCache; -var - I: Integer; - CacheValues: IList; - CachePointer: PSerializeCache; -begin - PropertiesCache.Lock; - try - CacheValues := PropertiesCache.Values; - for I := 0 to CacheValues.Count - 1 do begin -{$IFDEF CPU64} - CachePointer := PSerializeCache(Int64(CacheValues[I])); -{$ELSE} - CachePointer := PSerializeCache(Integer(CacheValues[I])); -{$ENDIF} - Dispose(CachePointer); - end; - finally - PropertiesCache.Unlock; - end; -end; - -initialization - PropertiesCache := THashMap.Create; - -finalization - FreePropertiesCache; - -end. +{ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * HproseIO.pas * + * * + * hprose io unit for delphi. * + * * + * LastModified: Dec 28, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +} +unit HproseIO; + +{$I Hprose.inc} + +interface + +uses Classes, HproseCommon; + +const + { Hprose Serialize Tags } + HproseTagInteger :AnsiChar = 'i'; + HproseTagLong :AnsiChar = 'l'; + HproseTagDouble :AnsiChar = 'd'; + HproseTagNull :AnsiChar = 'n'; + HproseTagEmpty :AnsiChar = 'e'; + HproseTagTrue :AnsiChar = 't'; + HproseTagFalse :AnsiChar = 'f'; + HproseTagNaN :AnsiChar = 'N'; + HproseTagInfinity :AnsiChar = 'I'; + HproseTagDate :AnsiChar = 'D'; + HproseTagTime :AnsiChar = 'T'; + HproseTagUTC :AnsiChar = 'Z'; + HproseTagBytes :AnsiChar = 'b'; + HproseTagUTF8Char :AnsiChar = 'u'; + HproseTagString :AnsiChar = 's'; + HproseTagGuid :AnsiChar = 'g'; + HproseTagList :AnsiChar = 'a'; + HproseTagMap :AnsiChar = 'm'; + HproseTagClass :AnsiChar = 'c'; + HproseTagObject :AnsiChar = 'o'; + HproseTagRef :AnsiChar = 'r'; + { Hprose Serialize Marks } + HproseTagPos :AnsiChar = '+'; + HproseTagNeg :AnsiChar = '-'; + HproseTagSemicolon :AnsiChar = ';'; + HproseTagOpenbrace :AnsiChar = '{'; + HproseTagClosebrace :AnsiChar = '}'; + HproseTagQuote :AnsiChar = '"'; + HproseTagPoint :AnsiChar = '.'; + { Hprose Protocol Tags } + HproseTagFunctions :AnsiChar = 'F'; + HproseTagCall :AnsiChar = 'C'; + HproseTagResult :AnsiChar = 'R'; + HproseTagArgument :AnsiChar = 'A'; + HproseTagError :AnsiChar = 'E'; + HproseTagEnd :AnsiChar = 'z'; + +type + + THproseReader = class + private + FStream: TStream; + FRefList: IList; + FClassRefList: IList; + FAttrRefMap: IMap; + function Unserialize(Tag: AnsiChar; VType: TVarType; + AClass: TClass): Variant; overload; + function ReadByte: Byte; + function ReadInt64(Tag: AnsiChar): Int64; +{$IF Defined(DELPHI2009_UP) or Defined(FPC)} + function ReadUInt64(Tag: AnsiChar): UInt64; +{$IFEND} + function ReadShortIntArray(Count: Integer): Variant; + function ReadSmallIntArray(Count: Integer): Variant; + function ReadWordArray(Count: Integer): Variant; + function ReadIntegerArray(Count: Integer): Variant; + function ReadCurrencyArray(Count: Integer): Variant; + function ReadLongWordArray(Count: Integer): Variant; + function ReadInt64Array(Count: Integer): Variant; +{$IFDEF DELPHI2009_UP} + function ReadUInt64Array(Count: Integer): Variant; +{$ENDIF} +{$IFDEF FPC} + function ReadQWordArray(Count: Integer): Variant; +{$ENDIF} + function ReadSingleArray(Count: Integer): Variant; + function ReadDoubleArray(Count: Integer): Variant; + function ReadBooleanArray(Count: Integer): Variant; + function ReadWideStringArray(Count: Integer): Variant; + function ReadDateTimeArray(Count: Integer): Variant; + function ReadList(AClass: TClass; Count: Integer): Variant; overload; + function ReadRef: Variant; + procedure ReadClass; + procedure ReadRaw(const OStream: TStream; Tag: AnsiChar); overload; + procedure ReadInfinityRaw(const OStream: TStream; Tag: AnsiChar); + procedure ReadNumberRaw(const OStream: TStream; Tag: AnsiChar); + procedure ReadDateTimeRaw(const OStream: TStream; Tag: AnsiChar); + procedure ReadUTF8CharRaw(const OStream: TStream; Tag: AnsiChar); + procedure ReadBytesRaw(const OStream: TStream; Tag: AnsiChar); + procedure ReadStringRaw(const OStream: TStream; Tag: AnsiChar); + procedure ReadGuidRaw(const OStream: TStream; Tag: AnsiChar); + procedure ReadComplexRaw(const OStream: TStream; Tag: AnsiChar); + public + constructor Create(AStream: TStream); + function Unserialize(VType: TVarType = varVariant; + AClass: TClass = nil): Variant; overload; + procedure CheckTag(expectTag: AnsiChar); + function CheckTags(const expectTags: RawByteString): AnsiChar; + function ReadUntil(Tag: AnsiChar): string; + function ReadInt(Tag: AnsiChar): Integer; + function ReadInteger(IncludeTag:Boolean = True): Integer; + function ReadLong(IncludeTag:Boolean = True): Variant; + function ReadDouble(IncludeTag:Boolean = True): Extended; + function ReadCurrency(IncludeTag:Boolean = True): Currency; + function ReadNull(): Variant; + function ReadEmpty(): Variant; + function ReadBoolean(): Boolean; + function ReadNaN(): Extended; + function ReadInfinity(IncludeTag:Boolean = True): Extended; + function ReadDate(IncludeTag:Boolean = True): TDateTime; + function ReadTime(IncludeTag:Boolean = True): TDateTime; + function ReadBytes(IncludeTag:Boolean = True): Variant; + function ReadUTF8Char(IncludeTag:Boolean = True): WideChar; + function ReadString(IncludeTag:Boolean = True; + IncludeRef:Boolean = True): WideString; + function ReadGuid(IncludeTag:Boolean = True): AnsiString; + function ReadList(ElementType: TVarType; AClass: TClass = nil; + IncludeTag:Boolean = True): Variant; overload; + function ReadMap(AClass: TClass = nil; IncludeTag:Boolean = True): Variant; + function ReadObject(AClass: TClass = nil; IncludeTag:Boolean = True): Variant; + procedure Reset; + function ReadRaw: TMemoryStream; overload; + procedure ReadRaw(const OStream: TStream); overload; + property Stream: TStream read FStream; + end; + + THproseWriter = class + private + FStream: TStream; + FRefList: IList; + FClassRefList: IList; + function WriteRef(const Value: Variant; CheckRef: Boolean): + Boolean; overload; + procedure WriteRef(Value: Integer); overload; + function WriteClass(Instance: TObject): Integer; + procedure WriteRawByteString(const S: RawByteString); + procedure WriteShortIntArray(var P; Count: Integer); + procedure WriteSmallIntArray(var P; Count: Integer); + procedure WriteWordArray(var P; Count: Integer); + procedure WriteIntegerArray(var P; Count: Integer); + procedure WriteCurrencyArray(var P; Count: Integer); + procedure WriteLongWordArray(var P; Count: Integer); + procedure WriteInt64Array(var P; Count: Integer); +{$IFDEF DELPHI2009_UP} + procedure WriteUInt64Array(var P; Count: Integer); +{$ENDIF} +{$IFDEF FPC} + procedure WriteQWordArray(var P; Count: Integer); +{$ENDIF} + procedure WriteSingleArray(var P; Count: Integer); + procedure WriteDoubleArray(var P; Count: Integer); + procedure WriteBooleanArray(var P; Count: Integer); + procedure WriteWideStringArray(var P; Count: Integer); + procedure WriteDateTimeArray(var P; Count: Integer); + procedure WriteVariantArray(var P; Count: Integer); + public + constructor Create(AStream: TStream); + procedure Serialize(const Value: Variant); overload; + procedure Serialize(const Value: array of const); overload; + procedure WriteInteger(I: Integer); + procedure WriteLong(L: Int64); overload; +{$IFDEF DELPHI2009_UP} + procedure WriteLong(L: UInt64); overload; +{$ENDIF} +{$IFDEF FPC} + procedure WriteLong(L: QWord); overload; +{$ENDIF} + procedure WriteLong(const L: RawByteString); overload; + procedure WriteDouble(D: Extended); + procedure WriteCurrency(C: Currency); + procedure WriteNull(); + procedure WriteEmpty(); + procedure WriteBoolean(B: Boolean); + procedure WriteNaN(); + procedure WriteInfinity(Positive: Boolean); + procedure WriteUTF8Char(C: WideChar); + procedure WriteDateTime(const ADateTime: TDateTime; CheckRef: Boolean = True); + procedure WriteBytes(const Bytes: Variant; CheckRef: Boolean = True); + procedure WriteString(const S: WideString; CheckRef: Boolean = True); + procedure WriteArray(const Value: Variant; CheckRef: Boolean = True); overload; + procedure WriteArray(const Value: array of const); overload; + procedure WriteList(AList: IList; CheckRef: Boolean = True); + procedure WriteMap(AMap: IMap; CheckRef: Boolean = True); + procedure WriteObject(AObject: TObject; CheckRef: Boolean = True); + procedure WriteInterface(Intf: IInterface; CheckRef: Boolean = True); + procedure Reset; + property Stream: TStream read FStream; + end; + + THproseFormatter = class + public + class function Serialize(Value: TObject): RawByteString; overload; + class function Serialize(const Value: Variant): RawByteString; overload; + class function Serialize(const Value: array of const): RawByteString; overload; + class function Unserialize(const Data:RawByteString; VType: TVarType = varVariant; + AClass: TClass = nil): Variant; + end; + +function HproseSerialize(Value: TObject): RawByteString; overload; +function HproseSerialize(const Value: Variant): RawByteString; overload; +function HproseSerialize(const Value: array of const): RawByteString; overload; +function HproseUnserialize(const Data:RawByteString; VType: TVarType = varVariant; + AClass: TClass = nil): Variant; + +implementation + +uses DateUtils, Math, RTLConsts, SysConst, SysUtils, TypInfo, Variants; + +type + + PSmallIntArray = ^TSmallIntArray; + TSmallIntArray = array[0..MaxInt div Sizeof(SmallInt) - 1] of SmallInt; + + PShortIntArray = ^TShortIntArray; + TShortIntArray = array[0..MaxInt div Sizeof(ShortInt) - 1] of ShortInt; + + PInt64Array = ^TInt64Array; + TInt64Array = array[0..MaxInt div Sizeof(Int64) - 1] of Int64; + +{$IFDEF DELPHI2009_UP} + PUInt64Array = ^TUInt64Array; + TUInt64Array = array[0..MaxInt div Sizeof(UInt64) - 1] of UInt64; +{$ENDIF} + +{$IFDEF FPC} + PQWordArray = ^TQWordArray; + TQWordArray = array[0..MaxInt div Sizeof(QWord) - 1] of QWord; +{$ENDIF} + + PLongWordArray = ^TLongWordArray; + TLongWordArray = array[0..MaxInt div Sizeof(LongWord) - 1] of LongWord; + + PSingleArray = ^TSingleArray; + TSingleArray = array[0..MaxInt div Sizeof(Single) - 1] of Single; + + PDoubleArray = ^TDoubleArray; + TDoubleArray = array[0..MaxInt div Sizeof(Double) - 1] of Double; + + PCurrencyArray = ^TCurrencyArray; + TCurrencyArray = array[0..MaxInt div Sizeof(Currency) - 1] of Currency; + + PWordBoolArray = ^TWordBoolArray; + TWordBoolArray = array[0..MaxInt div Sizeof(WordBool) - 1] of WordBool; + + PWideStringArray = ^TWideStringArray; + TWideStringArray = array[0..MaxInt div Sizeof(WideString) - 1] of WideString; + + PDateTimeArray = ^TDateTimeArray; + TDateTimeArray = array[0..MaxInt div Sizeof(TDateTime) - 1] of TDateTime; + + PVariantArray = ^TVariantArray; + TVariantArray = array[0..MaxInt div Sizeof(Variant) - 1] of Variant; + + SerializeCache = record + RefCount: Integer; + Data: RawByteString; + end; + PSerializeCache = ^SerializeCache; + +var + PropertiesCache: IMap; + +const + htInteger = 'i'; + htLong = 'l'; + htDouble = 'd'; + htNull = 'n'; + htEmpty = 'e'; + htTrue = 't'; + htFalse = 'f'; + htNaN = 'N'; + htInfinity = 'I'; + htDate = 'D'; + htTime = 'T'; + htBytes = 'b'; + htUTF8Char = 'u'; + htString = 's'; + htGuid = 'g'; + htList = 'a'; + htMap = 'm'; + htClass = 'c'; + htObject = 'o'; + htRef = 'r'; + htError = 'E'; + + HproseTagBoolean :array[Boolean] of AnsiChar = ('f', 't'); + HproseTagSign :array[Boolean] of AnsiChar = ('-', '+'); + +function GetStoredPropList(Instance: TObject; out PropList: PPropList): Integer; +var + I, Count: Integer; + TempList: PPropList; +begin + Count := GetPropList(PTypeInfo(Instance.ClassInfo), TempList); + PropList := nil; + Result := 0; + if Count > 0 then + try + for I := 0 to Count - 1 do + if IsStoredProp(Instance, TempList^[I]) then + Inc(Result); + GetMem(PropList, Result * SizeOf(Pointer)); + for I := 0 to Result - 1 do + if IsStoredProp(Instance, TempList^[I]) then + PropList^[I] := TempList^[I]; + finally + FreeMem(TempList); + end; +end; + +{ GetPropValue/SetPropValue } + +procedure PropertyNotFound(const Name: string); +begin + raise EPropertyError.CreateResFmt(@SUnknownProperty, [Name]); +end; + +procedure PropertyConvertError(const Name: AnsiString); +begin + raise EPropertyConvertError.CreateResFmt(@SInvalidPropertyType, [Name]); +end; + +{$IFNDEF FPC} +{$IFNDEF DELPHI2007_UP} +type + TAccessStyle = (asFieldData, asAccessor, asIndexedAccessor); + +function GetAccessToProperty(Instance: TObject; PropInfo: PPropInfo; + AccessorProc: Longint; out FieldData: Pointer; + out Accessor: TMethod): TAccessStyle; +begin + if (AccessorProc and $FF000000) = $FF000000 then + begin // field - Getter is the field's offset in the instance data + FieldData := Pointer(Integer(Instance) + (AccessorProc and $00FFFFFF)); + Result := asFieldData; + end + else + begin + if (AccessorProc and $FF000000) = $FE000000 then + // virtual method - Getter is a signed 2 byte integer VMT offset + Accessor.Code := Pointer(PInteger(PInteger(Instance)^ + SmallInt(AccessorProc))^) + else + // static method - Getter is the actual address + Accessor.Code := Pointer(AccessorProc); + + Accessor.Data := Instance; + if PropInfo^.Index = Integer($80000000) then // no index + Result := asAccessor + else + Result := asIndexedAccessor; + end; +end; + +function GetDynArrayProp(Instance: TObject; PropInfo: PPropInfo): Pointer; +type + { Need a(ny) dynamic array type to force correct call setup. + (Address of result passed in EDX) } + TDynamicArray = array of Byte; +type + TDynArrayGetProc = function: TDynamicArray of object; + TDynArrayIndexedGetProc = function (Index: Integer): TDynamicArray of object; +var + M: TMethod; +begin + case GetAccessToProperty(Instance, PropInfo, Longint(PropInfo^.GetProc), + Result, M) of + asFieldData: + Result := PPointer(Result)^; + asAccessor: + Result := Pointer(TDynArrayGetProc(M)()); + asIndexedAccessor: + Result := Pointer(TDynArrayIndexedGetProc(M)(PropInfo^.Index)); + end; +end; + +procedure SetDynArrayProp(Instance: TObject; PropInfo: PPropInfo; + const Value: Pointer); +type + TDynArraySetProc = procedure (const Value: Pointer) of object; + TDynArrayIndexedSetProc = procedure (Index: Integer; + const Value: Pointer) of object; +var + P: Pointer; + M: TMethod; +begin + case GetAccessToProperty(Instance, PropInfo, Longint(PropInfo^.SetProc), + P, M) of + asFieldData: + asm + MOV ECX, PropInfo + MOV ECX, [ECX].TPropInfo.PropType + MOV ECX, [ECX] + + MOV EAX, [P] + MOV EDX, Value + CALL System.@DynArrayAsg + end; + asAccessor: + TDynArraySetProc(M)(Value); + asIndexedAccessor: + TDynArrayIndexedSetProc(M)(PropInfo^.Index, Value); + end; +end; +{$ENDIF} +{$ELSE} +function GetDynArrayProp(Instance: TObject; PropInfo: PPropInfo): Pointer; +type + { Need a(ny) dynamic array type to force correct call setup. + (Address of result passed in EDX) } + TDynamicArray = array of Byte; +type + TDynArrayGetProc = function: TDynamicArray of object; + TDynArrayIndexedGetProc = function (Index: Integer): TDynamicArray of object; +var + AMethod: TMethod; +begin + case (PropInfo^.PropProcs) and 3 of + ptfield: + Result := PPointer(Pointer(Instance) + PtrUInt(PropInfo^.GetProc))^; + ptstatic, + ptvirtual: + begin + if (PropInfo^.PropProcs and 3) = ptStatic then + AMethod.Code := PropInfo^.GetProc + else + AMethod.Code := PPointer(Pointer(Instance.ClassType) + PtrUInt(PropInfo^.GetProc))^; + AMethod.Data := Instance; + if ((PropInfo^.PropProcs shr 6) and 1) <> 0 then + Result := TDynArrayIndexedGetProc(AMethod)(PropInfo^.Index) + else + Result := TDynArrayGetProc(AMethod)(); + end; + end; +end; + +procedure SetDynArrayProp(Instance: TObject; PropInfo: PPropInfo; + const Value: Pointer); +type + TDynArraySetProc = procedure (const Value: Pointer) of object; + TDynArrayIndexedSetProc = procedure (Index: Integer; + const Value: Pointer) of object; +var + AMethod: TMethod; +begin + case (PropInfo^.PropProcs shr 2) and 3 of + ptfield: + PPointer(Pointer(Instance) + PtrUInt(PropInfo^.SetProc))^ := Value; + ptstatic, + ptvirtual: + begin + if ((PropInfo^.PropProcs shr 2) and 3) = ptStatic then + AMethod.Code := PropInfo^.SetProc + else + AMethod.Code := PPointer(Pointer(Instance.ClassType) + PtrUInt(PropInfo^.SetProc))^; + AMethod.Data := Instance; + if ((PropInfo^.PropProcs shr 6) and 1) <> 0 then + TDynArrayIndexedSetProc(AMethod)(PropInfo^.Index, Value) + else + TDynArraySetProc(AMethod)(Value); + end; + end; +end; +function GetInterfaceProp(Instance: TObject; PropInfo: PPropInfo): IInterface; +type + TInterfaceGetProc = function: IInterface of object; + TInterfaceIndexedGetProc = function (Index: Integer): IInterface of object; +var + P: ^IInterface; + AMethod: TMethod; +begin + case (PropInfo^.PropProcs) and 3 of + ptfield: + begin + P := Pointer(Pointer(Instance) + PtrUInt(PropInfo^.GetProc)); + Result := P^; // auto ref count + end; + ptstatic, + ptvirtual: + begin + if (PropInfo^.PropProcs and 3) = ptStatic then + AMethod.Code := PropInfo^.GetProc + else + AMethod.Code := PPointer(Pointer(Instance.ClassType) + PtrUInt(PropInfo^.GetProc))^; + AMethod.Data := Instance; + if ((PropInfo^.PropProcs shr 6) and 1) <> 0 then + Result := TInterfaceIndexedGetProc(AMethod)(PropInfo^.Index) + else + Result := TInterfaceGetProc(AMethod)(); + end; + end; +end; + +procedure SetInterfaceProp(Instance: TObject; PropInfo: PPropInfo; + const Value: IInterface); +type + TInterfaceSetProc = procedure (const Value: IInterface) of object; + TInterfaceIndexedSetProc = procedure (Index: Integer; + const Value: IInterface) of object; +var + P: ^IInterface; + AMethod: TMethod; +begin + case (PropInfo^.PropProcs shr 2) and 3 of + ptfield: + begin + P := Pointer(Pointer(Instance) + PtrUInt(PropInfo^.SetProc)); + P^ := Value; // auto ref count + end; + ptstatic, + ptvirtual: + begin + if ((PropInfo^.PropProcs shr 2) and 3) = ptStatic then + AMethod.Code := PropInfo^.SetProc + else + AMethod.Code := PPointer(Pointer(Instance.ClassType) + PtrUInt(PropInfo^.SetProc))^; + AMethod.Data := Instance; + if ((PropInfo^.PropProcs shr 6) and 1) <> 0 then + TInterfaceIndexedSetProc(AMethod)(PropInfo^.Index, Value) + else + TInterfaceSetProc(AMethod)(Value); + end; + end; +end; +{$ENDIF} + +function GetPropValue(Instance: TObject; PropInfo: PPropInfo): Variant; +var + PropType: PTypeInfo; + DynArray: Pointer; +begin + // assume failure + Result := Null; + PropType := PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF}; + case PropType^.Kind of + tkInteger: + Result := GetOrdProp(Instance, PropInfo); + tkWChar: + Result := WideString(WideChar(GetOrdProp(Instance, PropInfo))); + tkChar: + Result := AnsiChar(GetOrdProp(Instance, PropInfo)); + tkEnumeration: + if GetTypeData(PropType)^.BaseType{$IFNDEF FPC}^{$ENDIF} = TypeInfo(Boolean) then + Result := Boolean(GetOrdProp(Instance, PropInfo)) + else + Result := GetOrdProp(Instance, PropInfo); + tkSet: + Result := GetOrdProp(Instance, PropInfo); + tkFloat: + if (LowerCase(string(PropType^.Name)) = 'tdatetime') then + Result := VarAsType(GetFloatProp(Instance, PropInfo), varDate) + else + Result := GetFloatProp(Instance, PropInfo); + tkString, {$IFDEF FPC}tkAString, {$ENDIF}tkLString: + Result := GetStrProp(Instance, PropInfo); + tkWString: + Result := GetWideStrProp(Instance, PropInfo); +{$IFDEF DELPHI2009_UP} + tkUString: + Result := GetUnicodeStrProp(Instance, PropInfo); +{$ENDIF} + tkVariant: + Result := GetVariantProp(Instance, PropInfo); + tkInt64: +{$IFDEF DELPHI2009_UP} + if (LowerCase(string(PropType^.Name)) = 'uint64') then + Result := UInt64(GetInt64Prop(Instance, PropInfo)) + else +{$ENDIF} + Result := GetInt64Prop(Instance, PropInfo); +{$IFDEF FPC} + tkBool: + Result := Boolean(GetOrdProp(Instance, PropInfo)); + tkQWord: + Result := QWord(GetInt64Prop(Instance, PropInfo)); +{$ENDIF} + tkInterface: + Result := GetInterfaceProp(Instance, PropInfo); + tkDynArray: + begin + DynArray := GetDynArrayProp(Instance, PropInfo); + DynArrayToVariant(Result, DynArray, PropType); + end; + tkClass: + Result := ObjToVar(GetObjectProp(Instance, PropInfo)); + else + PropertyConvertError(PropType^.Name); + end; +end; + +procedure SetPropValue(Instance: TObject; PropInfo: PPropInfo; + const Value: Variant); +var + PropType: PTypeInfo; + TypeData: PTypeData; + Obj: TObject; + DynArray: Pointer; +begin + PropType := PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF}; + TypeData := GetTypeData(PropType); + // set the right type + case PropType^.Kind of + tkInteger, tkChar, tkWChar, tkEnumeration, tkSet: + SetOrdProp(Instance, PropInfo, Value); +{$IFDEF FPC} + tkBool: + SetOrdProp(Instance, PropInfo, Value); + tkQWord: + SetInt64Prop(Instance, PropInfo, QWord(Value)); +{$ENDIF} + tkFloat: + SetFloatProp(Instance, PropInfo, Value); + tkString, {$IFDEF FPC}tkAString, {$ENDIF}tkLString: + SetStrProp(Instance, PropInfo, VarToStr(Value)); + tkWString: + SetWideStrProp(Instance, PropInfo, VarToWideStr(Value)); +{$IFDEF DELPHI2009_UP} + tkUString: + SetUnicodeStrProp(Instance, PropInfo, VarToStr(Value)); //SB: ?? + tkInt64: + SetInt64Prop(Instance, PropInfo, Value); +{$ELSE} + tkInt64: + SetInt64Prop(Instance, PropInfo, TVarData(VarAsType(Value, varInt64)).VInt64); +{$ENDIF} + tkVariant: + SetVariantProp(Instance, PropInfo, Value); + tkInterface: + begin + SetInterfaceProp(Instance, PropInfo, Value); + end; + tkDynArray: + begin + DynArray := nil; // "nil array" + if VarIsNull(Value) or (VarArrayHighBound(Value, 1) >= 0) then begin + DynArrayFromVariant(DynArray, Value, PropType); + end; + SetDynArrayProp(Instance, PropInfo, DynArray); +{$IFNDEF FPC} + DynArrayClear(DynArray, PropType); +{$ENDIF} + end; + tkClass: + if VarIsNull(Value) then + SetOrdProp(Instance, PropInfo, 0) + else if VarIsObj(Value) then begin + Obj := VarToObj(Value); + if (Obj.ClassType.InheritsFrom(TypeData^.ClassType)) then + SetObjectProp(Instance, PropInfo, Obj) + else + PropertyConvertError(PropType^.Name); + end + else + PropertyConvertError(PropType^.Name); + else + PropertyConvertError(PropType^.Name); + end; +end; + +function GetVarTypeAndClass(TypeInfo: PTypeInfo; out AClass: TClass): TVarType; +var + TypeData: PTypeData; + TypeName: string; +begin + Result := varVariant; + AClass := nil; + TypeName := LowerCase(string(TypeInfo^.Name)); + if TypeName = 'boolean' then + Result := varBoolean + else if TypeName = 'tdatetime' then + Result := varDate +{$IFDEF DELPHI2009_UP} + else if TypeName = 'uint64' then + Result := varUInt64 +{$ENDIF} + else begin + TypeData := GetTypeData(TypeInfo); + case TypeInfo^.Kind of + tkInteger, tkEnumeration, tkSet: + case TypeData^.OrdType of + otSByte: + Result := varShortInt; + otUByte: + Result := varByte; + otSWord: + Result := varSmallInt; + otUWord: + Result := varWord; + otSLong: + Result := varInteger; + otULong: + Result := varLongWord; + end; + tkChar: begin + AClass := TObject; + Result := varByte; + end; + tkWChar: begin + AClass := TObject; + Result := varWord; + end; +{$IFDEF FPC} + tkBool: + Result := varBoolean; + tkQWord: + Result := varQWord; +{$ENDIF} + tkFloat: + case TypeData^.FloatType of + ftSingle: + Result := varSingle; + ftDouble: + Result := varDouble; + ftCurr: + Result := varCurrency; + end; + tkString, {$IFDEF FPC}tkAString, {$ENDIF}tkLString: + Result := varString; + tkWString: + Result := varOleStr; +{$IFDEF DELPHI2009_UP} + tkUString: + Result := varUString; +{$ENDIF} + tkInt64: + Result := varInt64; + tkInterface: begin + Result := varUnknown; + AClass := GetClassByInterface(TypeData.Guid); + end; + tkDynArray: + Result := TypeData.varType; + tkClass: + AClass := TypeData.ClassType; + end; + end; +end; + +function StrToByte(const S:string): Byte; overload; +begin + if Length(S) = 1 then + Result := Ord(S[1]) + else + Result := Byte(StrToInt(S)); +end; + +function OleStrToWord(const S:WideString): Word; overload; +begin + if Length(S) = 1 then + Result := Ord(S[1]) + else + Result := Word(StrToInt(S)); +end; + +type + TAnsiCharSet = set of AnsiChar; + +function CharInSet(C: WideChar; const CharSet: TAnsiCharSet): Boolean; +begin + Result := (C < #$0100) and (AnsiChar(C) in CharSet); +end; + +{ THproseReader } + +procedure THproseReader.CheckTag(ExpectTag: AnsiChar); +var + Tag: AnsiChar; +begin + FStream.ReadBuffer(Tag, 1); + if Tag <> expectTag then + raise EHproseException.Create('Tag "' + ExpectTag + '" expected, but "' + + string(Tag) + '" found in stream'); +end; + +function THproseReader.CheckTags(const ExpectTags: RawByteString): AnsiChar; +var + Tag: AnsiChar; +begin + FStream.ReadBuffer(Tag, 1); + if Pos(Tag, ExpectTags) = 0 then + raise EHproseException.Create('Tags "' + string(ExpectTags) + '" expected, but "' + + string(Tag) + '" found in stream'); + Result := Tag; +end; + +constructor THproseReader.Create(AStream: TStream); +begin + FStream := AStream; + FRefList := TArrayList.Create(False); + FClassRefList := TArrayList.Create(False); + FAttrRefMap := THashMap.Create(False); +end; + +function THproseReader.ReadBoolean: Boolean; +begin + Result := CheckTags(HproseTagTrue + HproseTagFalse) = HproseTagTrue; +end; + + +function THproseReader.ReadByte: Byte; +begin + FStream.ReadBuffer(Result, 1); +end; + +function THproseReader.ReadBytes(IncludeTag: Boolean): Variant; +var + Len: Integer; + P: PByteArray; +begin + if IncludeTag and + (CheckTags(HproseTagBytes + HproseTagRef) = HproseTagRef) then begin + Result := ReadRef(); + Exit; + end; + Len := ReadInt(HproseTagQuote); + Result := VarArrayCreate([0, Len - 1], varByte); + P := VarArrayLock(Result); + FStream.ReadBuffer(P^[0], Len); + VarArrayUnLock(Result); + CheckTag(HproseTagQuote); +{$IFDEF FPC} + FRefList.Add(Result); +{$ELSE} + FRefList.Add(VarArrayRef(Result)); +{$ENDIF} +end; + +procedure THproseReader.ReadBytesRaw(const OStream: TStream; Tag: AnsiChar); +var + Len: Integer; +begin + OStream.WriteBuffer(Tag, 1); + Len := 0; + Tag := '0'; + repeat + Len := Len * 10 + (Ord(Tag) - Ord('0')); + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + until (Tag = HproseTagQuote); + OStream.CopyFrom(FStream, Len + 1); +end; + +function THproseReader.ReadCurrency(IncludeTag: Boolean): Currency; +begin + if IncludeTag then + CheckTags(HproseTagInteger + HproseTagLong + HproseTagDouble); + Result := StrToCurr(ReadUntil(HproseTagSemicolon)); +end; + +function THproseReader.ReadDate(IncludeTag: Boolean): TDateTime; +var + Tag, Year, Month, Day, Hour, Minute, Second, Millisecond: Integer; +begin + if IncludeTag and + (CheckTags(HproseTagDate + HproseTagRef) = HproseTagRef) then begin + Result := ReadRef; + Exit; + end; + Year := ReadByte - Ord('0'); + Year := Year * 10 + ReadByte - Ord('0'); + Year := Year * 10 + ReadByte - Ord('0'); + Year := Year * 10 + ReadByte - Ord('0'); + Month := ReadByte - Ord('0'); + Month := Month * 10 + ReadByte - Ord('0'); + Day := ReadByte - Ord('0'); + Day := Day * 10 + ReadByte - Ord('0'); + Tag := ReadByte; + if Tag = Ord(HproseTagTime) then begin + Hour := ReadByte - Ord('0'); + Hour := Hour * 10 + ReadByte - Ord('0'); + Minute := ReadByte - Ord('0'); + Minute := Minute * 10 + ReadByte - Ord('0'); + Second := ReadByte - Ord('0'); + Second := Second * 10 + ReadByte - Ord('0'); + Millisecond := 0; + if ReadByte = Ord(HproseTagPoint) then begin + Millisecond := ReadByte - Ord('0'); + Millisecond := Millisecond * 10 + ReadByte - Ord('0'); + Millisecond := Millisecond * 10 + ReadByte - Ord('0'); + Tag := ReadByte; + if (Tag >= Ord('0')) and (Tag <= Ord('9')) then begin + ReadByte; + ReadByte; + Tag := ReadByte; + if (Tag >= Ord('0')) and (Tag <= Ord('9')) then begin + ReadByte; + ReadByte; + ReadByte; + end; + end; + end; + Result := EncodeDateTime(Year, Month, Day, Hour, Minute, Second, Millisecond); + end + else + Result := EncodeDate(Year, Month, Day); + FRefList.Add(Result); +end; + +function THproseReader.ReadDouble(IncludeTag: Boolean): Extended; +var + Tag: AnsiChar; +begin + if IncludeTag then begin + Tag := CheckTags(HproseTagInteger + + HproseTagLong + + HproseTagDouble + + HproseTagNaN + + HproseTagInfinity); + if Tag = HproseTagNaN then begin + Result := NaN; + Exit; + end; + if Tag = HproseTagInfinity then begin + Result := ReadInfinity(False); + Exit; + end; + end; + Result := StrToFloat(ReadUntil(HproseTagSemicolon)); +end; + +function THproseReader.ReadInfinity(IncludeTag: Boolean): Extended; +begin + if IncludeTag then CheckTag(HproseTagInfinity); + if ReadByte = Ord(HproseTagNeg) then + Result := NegInfinity + else + Result := Infinity; +end; + +procedure THproseReader.ReadInfinityRaw(const OStream: TStream; Tag: AnsiChar); +begin + OStream.WriteBuffer(Tag, 1); + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); +end; + +function THproseReader.ReadInteger(IncludeTag: Boolean): Integer; +begin + if IncludeTag then CheckTag(HproseTagInteger); + Result := ReadInt(HproseTagSemicolon); +end; + +function THproseReader.ReadLong(IncludeTag: Boolean): Variant; +begin + if IncludeTag then CheckTags(HproseTagInteger + HproseTagLong); + Result := ReadUntil(HproseTagSemicolon); +end; + +function THproseReader.ReadNaN: Extended; +begin + CheckTag(HproseTagNaN); + Result := NaN; +end; + +function THproseReader.ReadNull: Variant; +begin + CheckTag(HproseTagNull); + Result := Null; +end; + +procedure THproseReader.ReadNumberRaw(const OStream: TStream; Tag: AnsiChar); +begin + OStream.WriteBuffer(Tag, 1); + repeat + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + until (Tag = HproseTagSemicolon); +end; + +function THproseReader.ReadEmpty: Variant; +begin + CheckTag(HproseTagEmpty); + Result := ''; +end; + +function THproseReader.ReadString(IncludeTag, IncludeRef: Boolean): WideString; +var + Count, I: Integer; + C, C2, C3, C4: LongWord; +begin + if IncludeTag and + (CheckTags(HproseTagString + HproseTagRef) = HproseTagRef) then begin + Result := ReadRef; + Exit; + end; + Count := ReadInt(HproseTagQuote); + SetLength(Result, Count); + I := 0; + while I < Count do begin + Inc(I); + C := ReadByte; + case C shr 4 of + 0..7: { 0xxx xxxx } Result[I] := WideChar(C); + 12,13: begin + { 110x xxxx 10xx xxxx } + C2 := ReadByte; + Result[I] := WideChar(((C and $1F) shl 6) or + (C2 and $3F)); + end; + 14: begin + { 1110 xxxx 10xx xxxx 10xx xxxx } + C2 := ReadByte; + C3 := ReadByte; + Result[I] := WideChar(((C and $0F) shl 12) or + ((C2 and $3F) shl 6) or + (C3 and $3F)); + end; + 15: begin + { 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx } + if (C and $F) <= 4 then begin + C2 := ReadByte; + C3 := ReadByte; + C4 := ReadByte; + C := ((C and $07) shl 18) or + ((C2 and $3F) shl 12) or + ((C3 and $3F) shl 6) or + (C4 and $3F) - $10000; + if C <= $FFFFF then begin + Result[I] := WideChar(((C shr 10) and $03FF) or $D800); + Inc(I); + Result[I] := WideChar((C and $03FF) or $DC00); + Continue; + end; + end; + raise EHproseException.Create('bad unicode encoding at $' + IntToHex(C, 4)); + end; + else + raise EHproseException.Create('bad unicode encoding at $' + IntToHex(C, 4)); + end; + end; + CheckTag(HproseTagQuote); + if IncludeRef then FRefList.Add(Result); +end; + +procedure THproseReader.ReadStringRaw(const OStream: TStream; Tag: AnsiChar); +var + Len, I: Integer; +begin + OStream.WriteBuffer(Tag, 1); + Len := 0; + Tag := '0'; + repeat + Len := Len * 10 + (Ord(Tag) - Ord('0')); + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + until (Tag = HproseTagQuote); + { When I = Len, Read & Write HproseTagQuote } + for I := 0 to Len do begin + FStream.ReadBuffer(Tag, 1); + case Ord(Tag) shr 4 of + 0..7: OStream.WriteBuffer(Tag, 1); + 12,13: begin + OStream.WriteBuffer(Tag, 1); + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + end; + 14: begin + OStream.WriteBuffer(Tag, 1); + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + end; + 15: begin + if (Ord(Tag) and $F) <= 4 then begin + OStream.WriteBuffer(Tag, 1); + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + Continue; + end; + raise EHproseException.Create('bad unicode encoding at $' + + IntToHex(Ord(Tag), 4)); + end; + else + raise EHproseException.Create('bad unicode encoding at $' + + IntToHex(Ord(Tag), 4)); + end; + end; +end; + +function THproseReader.ReadTime(IncludeTag: Boolean): TDateTime; +var + Tag, Hour, Minute, Second, Millisecond: Integer; +begin + if IncludeTag and + (CheckTags(HproseTagTime + HproseTagRef) = HproseTagRef) then begin + Result := ReadRef; + Exit; + end; + Hour := ReadByte - Ord('0'); + Hour := Hour * 10 + ReadByte - Ord('0'); + Minute := ReadByte - Ord('0'); + Minute := Minute * 10 + ReadByte - Ord('0'); + Second := ReadByte - Ord('0'); + Second := Second * 10 + ReadByte - Ord('0'); + Millisecond := 0; + if ReadByte = Ord(HproseTagPoint) then begin + Millisecond := ReadByte - Ord('0'); + Millisecond := Millisecond * 10 + ReadByte - Ord('0'); + Millisecond := Millisecond * 10 + ReadByte - Ord('0'); + Tag := ReadByte; + if (Tag >= Ord('0')) and (Tag <= Ord('9')) then begin + ReadByte; + ReadByte; + Tag := ReadByte; + if (Tag >= Ord('0')) and (Tag <= Ord('9')) then begin + ReadByte; + ReadByte; + ReadByte; + end; + end; + end; + Result := EncodeTime(Hour, Minute, Second, Millisecond); + FRefList.Add(Result); +end; + +function THproseReader.ReadUntil(Tag: AnsiChar): string; +var + S: TStringBuffer; + C: AnsiChar; +begin + S := TStringBuffer.Create(); + try + while (FStream.Read(C, 1) = 1) and (C <> Tag) do S.Write(C, 1); + Result := S.ToString; + finally + S.Free; + end; +end; + +function THproseReader.ReadUTF8Char(IncludeTag: Boolean): WideChar; +var + C, C2, C3: LongWord; +begin + if IncludeTag then CheckTag(HproseTagUTF8Char); + C := ReadByte; + case C shr 4 of + 0..7: { 0xxx xxxx } Result := WideChar(C); + 12,13: begin + { 110x xxxx 10xx xxxx } + C2 := ReadByte; + Result := WideChar(((C and $1F) shl 6) or + (C2 and $3F)); + end; + 14: begin + { 1110 xxxx 10xx xxxx 10xx xxxx } + C2 := ReadByte; + C3 := ReadByte; + Result := WideChar(((C and $0F) shl 12) or + ((C2 and $3F) shl 6) or + (C3 and $3F)); + end; + else + raise EHproseException.Create('bad unicode encoding at $' + IntToHex(C, 4)); + end; +end; + +procedure THproseReader.ReadUTF8CharRaw(const OStream: TStream; Tag: AnsiChar); +begin + OStream.WriteBuffer(Tag, 1); + FStream.ReadBuffer(Tag, 1); + case Ord(Tag) shr 4 of + 0..7: OStream.WriteBuffer(Tag, 1); + 12,13: begin + OStream.WriteBuffer(Tag, 1); + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + end; + 14: begin + OStream.WriteBuffer(Tag, 1); + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + end; + else + raise EHproseException.Create('bad unicode encoding at $' + + IntToHex(Ord(Tag), 4)); + end; +end; + +function THproseReader.ReadInt(Tag: AnsiChar): Integer; +var + S: Integer; + I: Integer; + C: AnsiChar; +begin + Result := 0; + S := 1; + I := FStream.Read(C, 1); + if I = 1 then + if C = '+' then + I := FStream.Read(C, 1) + else if C = '-' then begin + S := -1; + I := FStream.Read(C, 1); + end; + while (I = 1) and (C <> Tag) do begin + Result := Result * 10 + (Ord(C) - Ord('0')) * S; + I := FStream.Read(C, 1); + end +end; + +function THproseReader.ReadInt64(Tag: AnsiChar): Int64; +var + S: Int64; + I: Integer; + C: AnsiChar; +begin + Result := 0; + S := 1; + I := FStream.Read(C, 1); + if I = 1 then + if C = '+' then + I := FStream.Read(C, 1) + else if C = '-' then begin + S := -1; + I := FStream.Read(C, 1); + end; + while (I = 1) and (C <> Tag) do begin + Result := Result * 10 + Int64(Ord(C) - Ord('0')) * S; + I := FStream.Read(C, 1); + end +end; + +{$IF Defined(DELPHI2009_UP) or Defined(FPC)} +function THproseReader.ReadUInt64(Tag: AnsiChar): UInt64; +var + I: Integer; + C: AnsiChar; +begin + Result := 0; + I := FStream.Read(C, 1); + if (I = 1) and (C = '+') then I := FStream.Read(C, 1); + while (I = 1) and (C <> Tag) do begin + Result := Result * 10 + UInt64(Ord(C) - Ord('0')); + I := FStream.Read(C, 1); + end +end; +{$IFEND} + +function THproseReader.Unserialize(VType: TVarType; + AClass: TClass): Variant; +var + Tag: AnsiChar; +begin + if FStream.Read(Tag, 1) < 1 then + raise EHproseException.Create('No byte found in stream'); + Result := Unserialize(Tag, VType, AClass); +end; + +function THproseReader.Unserialize(Tag: AnsiChar; VType: TVarType; + AClass: TClass): Variant; +begin + case Tag of + '0'..'9': begin + case VType of + varInteger, varVariant: Result := Ord(Tag) - Ord('0'); + varByte: Result := Byte(Ord(Tag) - Ord('0')); + varShortInt: Result := ShortInt(Ord(Tag) - Ord('0')); + varWord: Result := Word(Ord(Tag) - Ord('0')); + varSmallint: Result := Smallint(Ord(Tag) - Ord('0')); + varLongWord: Result := LongWord(Ord(Tag) - Ord('0')); + varSingle: Result := VarAsType(Ord(Tag) - Ord('0'), varSingle); + varDouble: Result := VarAsType(Ord(Tag) - Ord('0'), varDouble); + varCurrency: Result := StrToCurr(string(Tag)); + varInt64: Result := Int64(Ord(Tag) - Ord('0')); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := UInt64(Ord(Tag) - Ord('0')); +{$ENDIF} +{$IFDEF FPC} + varQWord: Result := QWord(Ord(Tag) - Ord('0')); +{$ENDIF} + varString: Result := AnsiString(Tag); +{$IFDEF DELPHI2009_UP} + varUString: Result := UnicodeString(Tag); +{$ENDIF} + varOleStr: Result := WideString(Tag); + varBoolean: Result := Tag <> '0'; + varDate: Result := TimeStampToDateTime(MSecsToTimeStamp( + Ord(Tag) - Ord('0'))); + else + Error(reInvalidCast); + end; + end; + htInteger: begin + case VType of + varInteger, varVariant: Result := ReadInteger(False); + varByte: Result := Byte(ReadInteger(False)); + varShortInt: Result := ShortInt(ReadInteger(False)); + varWord: Result := Word(ReadInteger(False)); + varSmallint: Result := Smallint(ReadInteger(False)); + varLongWord: Result := LongWord(ReadInteger(False)); + varSingle: Result := VarAsType(ReadInteger(False), varSingle); + varDouble: Result := VarAsType(ReadInteger(False), varDouble); + varCurrency: Result := StrToCurr(ReadUntil(HproseTagSemicolon)); + varInt64: Result := ReadInt64(HproseTagSemicolon); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := ReadUInt64(HproseTagSemicolon); +{$ENDIF} +{$IFDEF FPC} + varQWord: Result := ReadUInt64(HproseTagSemicolon); +{$ENDIF} + varString: Result := ReadUntil(HproseTagSemicolon); +{$IFDEF DELPHI2009_UP} + varUString: Result := ReadUntil(HproseTagSemicolon); +{$ENDIF} + varOleStr: Result := WideString(ReadUntil(HproseTagSemicolon)); + varBoolean: Result := ReadInteger(False) <> 0; + varDate: Result := TimeStampToDateTime(MSecsToTimeStamp( + ReadInteger(False))); + else + Error(reInvalidCast); + end; + end; + htLong: begin + case VType of + varString, varVariant: Result := ReadLong(False); +{$IFDEF DELPHI2009_UP} + varUString: Result := ReadLong(False); +{$ENDIF} + varInteger: Result := ReadInteger(False); + varByte: Result := Byte(ReadInteger(False)); + varShortInt: Result := ShortInt(ReadInteger(False)); + varWord: Result := Word(ReadInteger(False)); + varSmallint: Result := Smallint(ReadInteger(False)); + varLongWord: Result := LongWord(ReadInt64(HproseTagSemicolon)); + varSingle: Result := VarAsType(StrToFloat(ReadLong(False)), varSingle); + varDouble: Result := VarAsType(StrToFloat(ReadLong(False)), varDouble); + varCurrency: Result := StrToCurr(ReadUntil(HproseTagSemicolon)); + varInt64: Result := ReadInt64(HproseTagSemicolon); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := ReadUInt64(HproseTagSemicolon); +{$ENDIF} +{$IFDEF FPC} + varQWord: Result := ReadUInt64(HproseTagSemicolon); +{$ENDIF} + varOleStr: Result := WideString(ReadUntil(HproseTagSemicolon)); + varBoolean: Result := ReadLong(False) <> '0'; + varDate: Result := TimeStampToDateTime(MSecsToTimeStamp( + StrToInt64(ReadLong(False)))); + else + Error(reInvalidCast); + end; + end; + htDouble: begin + case VType of + varDouble, varVariant: Result := VarAsType(ReadDouble(False), varDouble); + varSingle: Result := VarAsType(ReadDouble(False), varSingle); + varCurrency: Result := ReadCurrency(False); + varInteger: Result := ReadInteger(False); + varByte: Result := Byte(ReadInteger(False)); + varShortInt: Result := ShortInt(ReadInteger(False)); + varWord: Result := Word(ReadInteger(False)); + varSmallint: Result := Smallint(ReadInteger(False)); + varLongWord: Result := LongWord(ReadInt64(HproseTagSemicolon)); + varInt64: Result := ReadInt64(HproseTagSemicolon); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := ReadUInt64(HproseTagSemicolon); +{$ENDIF} +{$IFDEF FPC} + varQWord: Result := ReadUInt64(HproseTagSemicolon); +{$ENDIF} + varString: Result := ReadUntil(HproseTagSemicolon); +{$IFDEF DELPHI2009_UP} + varUString: Result := ReadUntil(HproseTagSemicolon); +{$ENDIF} + varOleStr: Result := WideString(ReadUntil(HproseTagSemicolon)); + varBoolean: Result := ReadDouble(False) <> 0.0; + varDate: Result := TimeStampToDateTime(MSecsToTimeStamp( + StrToInt64(ReadLong(False)))); + else + Error(reInvalidCast); + end; + end; + htNull: begin + case VType of + varEmpty: Result := Unassigned; + varBoolean: Result := False; + varSingle: Result := VarAsType(0, varSingle); + varDouble: Result := VarAsType(0, varDouble); + varCurrency: Result := VarAsType(0, varCurrency); + varInteger: Result := 0; + varByte: Result := Byte(0); + varShortInt: Result := ShortInt(0); + varWord: Result := Word(0); + varSmallint: Result := Smallint(0); + varLongWord: Result := LongWord(0); + varInt64: Result := Int64(0); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := UInt64(0); +{$ENDIF} +{$IFDEF FPC} + varQWord: Result := QWord(0); +{$ENDIF} + varString: Result := ''; +{$IFDEF DELPHI2009_UP} + varUString: Result := ''; +{$ENDIF} + varOleStr: Result := WideString(''); + else + Result := Null; + end; + end; + htEmpty: begin + case VType of + varEmpty: Result := Unassigned; + varBoolean: Result := False; + varSingle: Result := VarAsType(0, varSingle); + varDouble: Result := VarAsType(0, varDouble); + varCurrency: Result := VarAsType(0, varCurrency); + varInteger: Result := 0; + varByte: Result := Byte(0); + varShortInt: Result := ShortInt(0); + varWord: Result := Word(0); + varSmallint: Result := Smallint(0); + varLongWord: Result := LongWord(0); + varInt64: Result := Int64(0); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := UInt64(0); +{$ENDIF} +{$IFDEF FPC} + varQWord: Result := QWord(0); +{$ENDIF} + varString: Result := ''; +{$IFDEF DELPHI2009_UP} + varUString: Result := ''; +{$ENDIF} + varOleStr: Result := WideString(''); + else + Result := ''; + end; + end; + htTrue: begin + case VType of + varBoolean, varVariant: Result := True; + varSingle: Result := VarAsType(1, varSingle); + varDouble: Result := VarAsType(1, varDouble); + varCurrency: Result := VarAsType(1, varCurrency); + varInteger: Result := 1; + varByte: Result := Byte(1); + varShortInt: Result := ShortInt(1); + varWord: Result := Word(1); + varSmallint: Result := Smallint(1); + varLongWord: Result := LongWord(1); + varInt64: Result := Int64(1); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := UInt64(1); +{$ENDIF} +{$IFDEF FPC} + varQWord: Result := QWord(1); +{$ENDIF} + varString: Result := 'True'; +{$IFDEF DELPHI2009_UP} + varUString: Result := 'True'; +{$ENDIF} + varOleStr: Result := WideString('True'); + else + Error(reInvalidCast); + end; + end; + htFalse: begin + case VType of + varBoolean, varVariant: Result := False; + varSingle: Result := VarAsType(0, varSingle); + varDouble: Result := VarAsType(0, varDouble); + varCurrency: Result := VarAsType(0, varCurrency); + varInteger: Result := 0; + varByte: Result := Byte(0); + varShortInt: Result := ShortInt(0); + varWord: Result := Word(0); + varSmallint: Result := Smallint(0); + varLongWord: Result := LongWord(0); + varInt64: Result := Int64(0); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := UInt64(0); +{$ENDIF} +{$IFDEF FPC} + varQWord: Result := QWord(0); +{$ENDIF} + varString: Result := 'False'; +{$IFDEF DELPHI2009_UP} + varUString: Result := 'False'; +{$ENDIF} + varOleStr: Result := WideString('False'); + else + Error(reInvalidCast); + end; + end; + htNaN: begin + case VType of + varDouble, varVariant: Result := VarAsType(NaN, varDouble); + varSingle: Result := VarAsType(NaN, varSingle); + varString: Result := 'NaN'; +{$IFDEF DELPHI2009_UP} + varUString: Result := 'NaN'; +{$ENDIF} + varOleStr: Result := WideString('NaN'); + else + Error(reInvalidCast); + end; + end; + htInfinity: begin + case VType of + varDouble, varVariant: + if ReadByte = Ord(HproseTagNeg) then + Result := VarAsType(NegInfinity, varDouble) + else + Result := VarAsType(Infinity, varDouble); + varSingle: + if ReadByte = Ord(HproseTagNeg) then + Result := VarAsType(NegInfinity, varSingle) + else + Result := VarAsType(Infinity, varSingle); + varString: + if ReadByte = Ord(HproseTagNeg) then + Result := '-Infinity' + else + Result := 'Infinity'; +{$IFDEF DELPHI2009_UP} + varUString: + if ReadByte = Ord(HproseTagNeg) then + Result := '-Infinity' + else + Result := 'Infinity'; +{$ENDIF} + varOleStr: + if ReadByte = Ord(HproseTagNeg) then + Result := WideString('-Infinity') + else + Result := WideString('Infinity'); + else + Error(reInvalidCast); + end; + end; + htUTF8Char: begin + case VType of + varOleStr, varVariant: Result := WideString(ReadUTF8Char(False)); + varString: Result := AnsiString(ReadUTF8Char(False)); +{$IFDEF DELPHI2009_UP} + varUString: Result := UnicodeString(ReadUTF8Char(False)); +{$ENDIF} + varInteger: Result := Ord(ReadUTF8Char(False)); + varByte: Result := Byte(Ord(AnsiString(ReadUTF8Char(False))[1])); + varWord: Result := Word(Ord(ReadUTF8Char(False))); + varShortInt: Result := VarAsType(Ord(ReadUTF8Char(False)), varShortInt); + varSmallint: Result := VarAsType(Ord(ReadUTF8Char(False)), varSmallint); + varLongWord: Result := VarAsType(Ord(ReadUTF8Char(False)), varLongWord); + varSingle: Result := VarAsType(Ord(ReadUTF8Char(False)), varSingle); + varDouble: Result := VarAsType(Ord(ReadUTF8Char(False)), varDouble); + varCurrency: Result := VarAsType(Ord(ReadUTF8Char(False)), varCurrency); + varInt64: Result := Int64(Ord(ReadUTF8Char(False))); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := UInt64(Ord(ReadUTF8Char(False))); +{$ENDIF} +{$IFDEF FPC} + varQWord: Result := UInt64(Ord(ReadUTF8Char(False))); +{$ENDIF} + varBoolean: Result := not CharInSet(ReadUTF8Char(False), [#0, '0', 'F', 'f']); + else + Error(reInvalidCast); + end; + end; + htString : begin + case VType of + varOleStr, varVariant: Result := ReadString(False); + varString: Result := AnsiString(ReadString(False)); +{$IFDEF DELPHI2009_UP} + varUString: Result := UnicodeString(ReadString(False)); +{$ENDIF} + varInteger: Result := StrToInt(ReadString(False)); + varByte: + if AClass = nil then + Result := VarAsType(ReadString(False), varByte) + else + Result := StrToByte(ReadString(False)); + varWord: + if AClass = nil then + Result := VarAsType(ReadString(False), varWord) + else + Result := OleStrToWord(ReadString(False)); + varShortInt: Result := VarAsType(ReadString(False), varShortInt); + varSmallint: Result := VarAsType(ReadString(False), varSmallint); + varLongWord: Result := VarAsType(ReadString(False), varLongWord); + varSingle: Result := VarAsType(ReadString(False), varSingle); + varDouble: Result := VarAsType(ReadString(False), varDouble); + varCurrency: Result := StrToCurr(ReadString(False)); + varInt64: Result := StrToInt64(ReadString(False)); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := VarAsType(ReadString(False), varUInt64); +{$ENDIF} +{$IFDEF FPC} + varQWord: Result := VarAsType(ReadString(False), varQWord); +{$ENDIF} + varBoolean: Result := VarAsType(ReadInteger(False), varBoolean); + else + Error(reInvalidCast); + end; + end; + htGuid : begin + case VType of + varString, varVariant: Result := ReadGuid(False); + varOleStr: Result := WideString(ReadGuid(False)); +{$IFDEF DELPHI2009_UP} + varUString: Result := UnicodeString(ReadGuid(False)); +{$ENDIF} + else + Error(reInvalidCast); + end; + end; + htDate : Result := ReadDate(False); + htTime : Result := ReadTime(False); + htBytes : Result := ReadBytes(False); + htList : Result := ReadList(VType and varTypeMask, AClass, False); + htMap : Result := ReadMap(AClass, False); + htClass : begin + ReadClass; + Result := Unserialize(VType, AClass); + end; + htObject : Result := ReadObject(AClass, False); + htRef : Result := ReadRef; + htError : raise EHproseException.Create(ReadString()); + else + raise EHproseException.Create('Unexpected serialize tag "' + + Tag + '" in stream'); + end; +end; + +function THproseReader.ReadBooleanArray(Count: Integer): Variant; +var + P: PWordBoolArray; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varBoolean); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varBoolean); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; + +function THproseReader.ReadDoubleArray(Count: Integer): Variant; +var + P: PDoubleArray; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varDouble); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varDouble); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; + +function THproseReader.ReadInt64Array(Count: Integer): Variant; +var + P: PInt64Array; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varInt64); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varInt64); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; + +function THproseReader.ReadIntegerArray(Count: Integer): Variant; +var + P: PIntegerArray; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varInteger); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varInteger); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; + +function THproseReader.ReadList(ElementType: TVarType; + AClass: TClass; IncludeTag: Boolean): Variant; +var + Count: Integer; +begin + if IncludeTag and + (CheckTags(HproseTagList + HproseTagRef) = HproseTagRef) then begin + Result := ReadRef; + Exit; + end; + Count := ReadInt(HproseTagOpenbrace); + if AClass = nil then + case ElementType of + varInteger: Result := ReadIntegerArray(Count); + varShortInt: Result := ReadShortIntArray(Count); + varWord: Result := ReadWordArray(Count); + varSmallint: Result := ReadSmallintArray(Count); + varLongWord: Result := ReadLongWordArray(Count); + varSingle: Result := ReadSingleArray(Count); + varDouble: Result := ReadDoubleArray(Count); + varCurrency: Result := ReadCurrencyArray(Count); + varInt64: Result := ReadInt64Array(Count); +{$IFDEF DELPHI2009_UP} + varUInt64: Result := ReadUInt64Array(Count); +{$ENDIF} +{$IFDEF FPC} + varQWord: Result := ReadQWordArray(Count); +{$ENDIF} + varOleStr: Result := ReadWideStringArray(Count); + varBoolean: Result := ReadBooleanArray(Count); + varDate: Result := ReadDateTimeArray(Count); + varVariant: Result := ReadList(TArrayList, Count); + end + else if AClass.InheritsFrom(TAbstractList) then begin + Result := ReadList(AClass, Count); + end + else + raise EHproseException.Create(AClass.ClassName + ' is not an IList class'); + CheckTag(HproseTagClosebrace); +end; + +function THproseReader.ReadList(AClass: TClass; Count: Integer): Variant; +var + I: Integer; + AList: IList; +begin + AList := TListClass(AClass).Create(Count) as IList; + Result := AList; + FRefList.Add(Result); + for I := 0 to Count - 1 do AList[I] := Unserialize; +end; + +function THproseReader.ReadLongWordArray(Count: Integer): Variant; +var + P: PLongWordArray; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varLongWord); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varLongWord); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; + +function THproseReader.ReadMap(AClass: TClass; IncludeTag: Boolean): Variant; +var + I, Count: Integer; + Key: Variant; + AMap: IMap; + Instance: TObject; + PropInfo: PPropInfo; + VType: TVarType; + PropClass: TClass; +begin + if IncludeTag and + (CheckTags(HproseTagMap + HproseTagRef) = HproseTagRef) then begin + Result := ReadRef; + Exit; + end; + Count := ReadInt(HproseTagOpenbrace); + if AClass = nil then AClass := THashMap; + if AClass.InheritsFrom(TAbstractMap) then begin + AMap := TMapClass(AClass).Create(Count) as IMap; + Result := AMap; + FRefList.Add(Result); + for I := 0 to Count - 1 do begin + Key := Unserialize; + AMap[Key] := Unserialize; + end; + end + else begin + Instance := AClass.Create; + if AClass.InheritsFrom(TInterfacedObject) then + Result := IInterface(TInterfacedObject(Instance)) + else + Result := ObjToVar(Instance); + FRefList.Add(Result); + for I := 0 to Count - 1 do begin + Key := ReadString; + PropInfo := GetPropInfo(AClass, Key); + if (PropInfo <> nil) then begin + VType := GetVarTypeAndClass(PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF}, PropClass); + SetPropValue(Instance, PropInfo, Unserialize(VType, PropClass)); + end + else Unserialize; + end; + end; + CheckTag(HproseTagClosebrace); +end; + +function THproseReader.ReadObject(AClass: TClass; IncludeTag: Boolean): Variant; +var + Tag: AnsiChar; + C: Variant; + AttrNames: IList; + I, Count: Integer; + Cls: TClass; + IID: TGUID; + AMap: IMap; + Intf: IInterface; + Instance: TObject; + PropInfo: PPropInfo; + VType: TVarType; + PropClass: TClass; +begin + if IncludeTag then repeat + Tag := CheckTags(HproseTagObject + HproseTagClass + HproseTagRef); + if Tag = HproseTagRef then begin + Result := ReadRef; + Exit; + end; + if Tag = HproseTagClass then ReadClass; + until Tag = HproseTagObject; + C := FClassRefList[ReadInt(HproseTagOpenbrace)]; + AttrNames := VarToList(FAttrRefMap[C]); + Count := AttrNames.Count; + if {$IFDEF CPU64}VarType(C) = varInt64{$ELSE}VarType(C) = varInteger{$ENDIF} then begin +{$IFDEF CPU64} + Cls := TClass(Int64(C)); +{$ELSE} + Cls := TClass(Integer(C)); +{$ENDIF} + if (AClass = nil) or Cls.InheritsFrom(AClass) then AClass := Cls; + end; + if AClass <> nil then begin + if AClass.InheritsFrom(TInterfacedObject) then begin + IID := GetInterfaceByClass(AClass); + Supports(TInterfacedClass(AClass).Create, IID, Intf); + Result := Intf; + Instance := IntfToObj(Intf); + end + else begin + Instance := AClass.Create; + Result := ObjToVar(Instance); + end; + FRefList.Add(Result); + for I := 0 to Count - 1 do begin + PropInfo := GetPropInfo(Instance, AttrNames[I]); + if (PropInfo <> nil) then begin + VType := GetVarTypeAndClass(PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF}, PropClass); + SetPropValue(Instance, PropInfo, Unserialize(VType, PropClass)); + end + else Unserialize; + end; + end + else begin + AMap := TCaseInsensitiveHashMap.Create(Count); + Result := AMap; + FRefList.Add(Result); + for I := 0 to Count - 1 do AMap[AttrNames[I]] := Unserialize; + end; + CheckTag(HproseTagClosebrace); +end; + +function THproseReader.ReadShortIntArray(Count: Integer): Variant; +var + P: PShortIntArray; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varShortInt); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varShortInt); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; + +function THproseReader.ReadSingleArray(Count: Integer): Variant; +var + P: PSingleArray; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varSingle); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varSingle); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; + +function THproseReader.ReadSmallIntArray(Count: Integer): Variant; +var + P: PSmallIntArray; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varSmallInt); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varSmallInt); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; + +function THproseReader.ReadWideStringArray(Count: Integer): Variant; +var + P: PWideStringArray; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varOleStr); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varOleStr); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; + +function THproseReader.ReadWordArray(Count: Integer): Variant; +var + P: PWordArray; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varWord); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varWord); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; + +function THproseReader.ReadCurrencyArray(Count: Integer): Variant; +var + P: PCurrencyArray; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varCurrency); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varCurrency); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; + +function THproseReader.ReadDateTimeArray(Count: Integer): Variant; +var + P: PDateTimeArray; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varDate); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varDate); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; + +procedure THproseReader.ReadDateTimeRaw(const OStream: TStream; Tag: AnsiChar); +begin + OStream.WriteBuffer(Tag, 1); + repeat + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + until (Tag = HproseTagSemicolon) or + (Tag = HproseTagUTC); +end; + +{$IFDEF DELPHI2009_UP} +function THproseReader.ReadUInt64Array(Count: Integer): Variant; +var + P: PUInt64Array; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varUInt64); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varUInt64); + VarArrayUnlock(Result); +{$IFDEF FPC} + FRefList[N] := Result; +{$ELSE} + FRefList[N] := VarArrayRef(Result); +{$ENDIF} +end; +{$ENDIF} + +{$IFDEF FPC} +function THproseReader.ReadQWordArray(Count: Integer): Variant; +var + P: PQWordArray; + I, N: Integer; +begin + Result := VarArrayCreate([0, Count - 1], varQWord); + N := FRefList.Add(Null); + P := VarArrayLock(Result); + for I := 0 to Count - 1 do P^[I] := Unserialize(varQWord); + VarArrayUnlock(Result); + FRefList[N] := Result; +end; +{$ENDIF} + +function THproseReader.ReadRaw: TMemoryStream; +begin + Result := TMemoryStream.Create; + ReadRaw(Result); +end; + +procedure THproseReader.ReadRaw(const OStream: TStream); +var + Tag: AnsiChar; +begin + FStream.ReadBuffer(Tag, 1); + ReadRaw(OStream, Tag); +end; + +procedure THproseReader.ReadRaw(const OStream: TStream; Tag: AnsiChar); +begin + case Tag of + '0'..'9', htNull, htEmpty, htTrue, htFalse, htNaN: OStream.WriteBuffer(Tag, 1); + htInfinity: ReadInfinityRaw(OStream, Tag); + htInteger, htLong, htDouble, htRef: ReadNumberRaw(OStream, Tag); + htDate, htTime: ReadDateTimeRaw(OStream, Tag); + htUTF8Char: ReadUTF8CharRaw(OStream, Tag); + htBytes: ReadBytesRaw(OStream, Tag); + htString: ReadStringRaw(OStream, Tag); + htGuid: ReadGuidRaw(OStream, Tag); + htList, htMap, htObject: ReadComplexRaw(OStream, Tag); + htClass: begin + ReadComplexRaw(OStream, Tag); + ReadRaw(OStream); + end; + htError: begin + OStream.WriteBuffer(Tag, 1); + ReadRaw(OStream); + end; + else + raise EHproseException.Create('Unexpected serialize tag "' + + Tag + '" in stream'); + end; +end; + +function THproseReader.ReadRef: Variant; +begin + Result := FRefList[ReadInt(HproseTagSemicolon)]; +end; + +procedure THproseReader.ReadClass; +var + ClassName: string; + I, Count: Integer; + AttrNames: IList; + AClass: TClass; + Key: Variant; +begin + ClassName := ReadString(False, False); + Count := ReadInt(HproseTagOpenbrace); + AttrNames := TArrayList.Create(Count, False); + for I := 0 to Count - 1 do AttrNames[I] := ReadString(); + CheckTag(HproseTagClosebrace); + AClass := GetClassByAlias(ClassName); + if AClass = nil then begin + Key := IInterface(TInterfacedObject.Create()); + FClassRefList.Add(Key); + FAttrRefMap[Key] := AttrNames; + end + else begin +{$IFDEF CPU64} + Key := Int64(AClass); +{$ELSE} + Key := Integer(AClass); +{$ENDIF} + FClassRefList.Add(Key); + FAttrRefMap[Key] := AttrNames; + end; +end; + +procedure THproseReader.ReadComplexRaw(const OStream: TStream; Tag: AnsiChar); +begin + OStream.WriteBuffer(Tag, 1); + repeat + FStream.ReadBuffer(Tag, 1); + OStream.WriteBuffer(Tag, 1); + until (Tag = HproseTagOpenbrace); + FStream.ReadBuffer(Tag, 1); + while (Tag <> HproseTagClosebrace) do begin + ReadRaw(OStream, Tag); + FStream.ReadBuffer(Tag, 1); + end; + OStream.WriteBuffer(Tag, 1); +end; + +function THproseReader.ReadGuid(IncludeTag: Boolean): AnsiString; +begin + if IncludeTag and + (CheckTags(HproseTagGuid + HproseTagRef) = HproseTagRef) then begin + Result := AnsiString(ReadRef()); + Exit; + end; + SetLength(Result, 38); + FStream.ReadBuffer(Result[1], 38); + FRefList.Add(Result); +end; + +procedure THproseReader.ReadGuidRaw(const OStream: TStream; Tag: AnsiChar); +begin + OStream.WriteBuffer(Tag, 1); + OStream.CopyFrom(FStream, 38); +end; + +procedure THproseReader.Reset; +begin + FRefList.Clear; + FClassRefList.Clear; + FAttrRefMap.Clear; +end; + +{ THproseWriter } + +constructor THproseWriter.Create(AStream: TStream); +begin + FStream := AStream; + FRefList := THashedList.Create(False); + FClassRefList := THashedList.Create(False); +end; + +procedure THproseWriter.Serialize(const Value: Variant); +var + AList: IList; + AMap: IMap; + Obj: TObject; +begin + with FindVarData(Value)^ do begin + case VType and not varByRef of + varEmpty, varNull : + WriteNull; + varBoolean : + WriteBoolean(Value); + varByte, varWord, varShortInt, varSmallint, varInteger: + WriteInteger(Value); +{$IFDEF DELPHI2009_UP} + varUInt64: + WriteLong(RawByteString(UIntToStr(Value))); +{$ENDIF} + {$IFDEF FPC}varQWord, {$ENDIF} + varLongWord, varInt64: + WriteLong(RawByteString(VarToStr(Value))); + varSingle, varDouble: + WriteDouble(Value); + varCurrency: + WriteCurrency(Value); + varString, {$IFDEF DELPHI2009_UP}varUString, {$ENDIF}varOleStr: + if Length(Value) = 0 then + WriteEmpty + else if Length(Value) = 1 then + WriteUTF8Char(VarToWideStr(Value)[1]) + else + WriteString(Value); + varDate: + WriteDateTime(Value); + varUnknown: + if (IInterface(Value) = nil) then + WriteNull + else if Supports(IInterface(Value), IList, AList) then + WriteList(AList) + else if Supports(IInterface(Value), IMap, AMap) then + WriteMap(AMap) + else + WriteInterface(IInterface(Value)); + else + if VType and varArray = varArray then + if (VType and varTypeMask = varByte) and + (VarArrayDimCount(Value) = 1) then + WriteBytes(Value) + else + WriteArray(Value) + else if VType and not varByRef = varObject then begin + Obj := VarToObj(Value); + if Obj = nil then WriteNull + else if Obj is TAbstractList then WriteList(TAbstractList(Obj)) + else if Obj is TAbstractMap then WriteMap(TAbstractMap(Obj)) + else WriteObject(Obj); + end + end; + end; +end; + +procedure THproseWriter.Serialize(const Value: array of const); +begin + WriteArray(Value); +end; + +procedure THproseWriter.WriteRawByteString(const S: RawByteString); +begin + FStream.WriteBuffer(S[1], Length(S)); +end; + + +procedure THproseWriter.WriteArray(const Value: array of const); +var + I, N: Integer; + AList: IList; + AMap: IMap; +begin + FRefList.Add(Null); + N := Length(Value); + FStream.WriteBuffer(HproseTagList, 1); + if N > 0 then WriteRawByteString(RawByteString(IntToStr(N))); + FStream.WriteBuffer(HproseTagOpenbrace, 1); + for I := 0 to N - 1 do + with Value[I] do + case VType of + vtInteger: WriteInteger(VInteger); + vtBoolean: WriteBoolean(VBoolean); + vtChar: WriteUTF8Char(WideString(VChar)[1]); + vtExtended: WriteDouble(VExtended^); + vtString: WriteString(WideString(VString^)); + vtPChar: WriteString(WideString(AnsiString(VPChar))); + vtObject: + if VObject = nil then + WriteNull + else if Supports(VObject, IList, AList) then + WriteList(AList) + else if Supports(VObject, IMap, AMap) then + WriteMap(AMap) + else + WriteObject(VObject); + vtWideChar: WriteUTF8Char(VWideChar); + vtPWideChar: WriteString(WideString(VPWideChar)); + vtAnsiString: WriteString(WideString(AnsiString(VAnsiString))); + vtCurrency: WriteCurrency(VCurrency^); + vtVariant: Serialize(VVariant^); + vtInterface: + if IInterface(VInterface) = nil then + WriteNull + else if Supports(IInterface(VInterface), IList, AList) then + WriteList(AList) + else if Supports(IInterface(VInterface), IMap, AMap) then + WriteMap(AMap) + else + WriteInterface(IInterface(VInterface)); + vtWideString: WriteString(WideString(VWideString)); + vtInt64: WriteLong(VInt64^); +{$IFDEF FPC} + vtQWord: WriteLong(VQWord^); +{$ENDIF} +{$IFDEF DELPHI2009_UP} + vtUnicodeString: WriteString(UnicodeString(VUnicodeString)); +{$ENDIF} + else + WriteNull; + end; + FStream.WriteBuffer(HproseTagClosebrace, 1); +end; + +procedure THproseWriter.WriteArray(const Value: Variant; + CheckRef: Boolean); +var + PVar: PVarData; + P: Pointer; + Rank, Count, MaxRank, I, N: Integer; + Des: array of array[0..1] of Integer; + Loc, Len: array of Integer; +begin + if WriteRef(Value, CheckRef) then begin + PVar := FindVarData(Value); + Rank := VarArrayDimCount(Value); + if Rank = 1 then begin + Count := VarArrayHighBound(Value, 1) - VarArrayLowBound(Value, 1) + 1; + FStream.WriteBuffer(HproseTagList, 1); + if Count > 0 then WriteRawByteString(RawByteString(IntToStr(Count))); + FStream.WriteBuffer(HproseTagOpenbrace, 1); + P := VarArrayLock(Value); + case PVar.VType and varTypeMask of + varInteger: WriteIntegerArray(P, Count); + varShortInt: WriteShortIntArray(P, Count); + varWord: WriteWordArray(P, Count); + varSmallint: WriteSmallintArray(P, Count); + varLongWord: WriteLongWordArray(P, Count); + varSingle: WriteSingleArray(P, Count); + varDouble: WriteDoubleArray(P, Count); + varCurrency: WriteCurrencyArray(P, Count); + varInt64: WriteInt64Array(P, Count); +{$IFDEF DELPHI2009_UP} + varUInt64: WriteUInt64Array(P, Count); +{$ENDIF} +{$IFDEF FPC} + varQWord: WriteQWordArray(P, Count); +{$ENDIF} + varOleStr: WriteWideStringArray(P, Count); + varBoolean: WriteBooleanArray(P, Count); + varDate: WriteDateTimeArray(P, Count); + varVariant: WriteVariantArray(P, Count); + end; + VarArrayUnLock(Value); + FStream.WriteBuffer(HproseTagClosebrace, 1); + end + else begin + SetLength(Des, Rank); + SetLength(Loc, Rank); + SetLength(Len, Rank); + MaxRank := Rank - 1; + for I := 0 to MaxRank do begin + Des[I, 0] := VarArrayLowBound(Value, I + 1); + Des[I, 1] := VarArrayHighBound(Value, I + 1); + Loc[I] := Des[I, 0]; + Len[I] := Des[I, 1] - Des[I, 0] + 1; + end; + FStream.WriteBuffer(HproseTagList, 1); + if Len[0] > 0 then WriteRawByteString(RawByteString(IntToStr(Len[0]))); + FStream.WriteBuffer(HproseTagOpenbrace, 1); + while Loc[0] <= Des[0, 1] do begin + N := 0; + for I := Maxrank downto 1 do + if Loc[I] = Des[I, 0] then Inc(N) else Break; + for I := Rank - N to MaxRank do begin + FRefList.Add(Null); + FStream.WriteBuffer(HproseTagList, 1); + if Len[I] > 0 then WriteRawByteString(RawByteString(IntToStr(Len[I]))); + FStream.WriteBuffer(HproseTagOpenbrace, 1); + end; + for I := Des[MaxRank, 0] to Des[MaxRank, 1] do begin + Loc[MaxRank] := I; + Serialize(VarArrayGet(Value, Loc)); + end; + Inc(Loc[MaxRank]); + for I := MaxRank downto 1 do + if Loc[I] > Des[I, 1] then begin + Loc[I] := Des[I, 0]; + Inc(Loc[I - 1]); + FStream.WriteBuffer(HproseTagClosebrace, 1); + end; + end; + FStream.WriteBuffer(HproseTagClosebrace, 1); + end; + end; +end; + +procedure THproseWriter.WriteBoolean(B: Boolean); +begin + FStream.WriteBuffer(HproseTagBoolean[B], 1); +end; + +procedure THproseWriter.WriteBooleanArray(var P; Count: Integer); +var + AP: PWordBoolArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteBoolean(AP^[I]); +end; + +procedure THproseWriter.WriteBytes(const Bytes: Variant; + CheckRef: Boolean); +var + N: Integer; +begin + if WriteRef(Bytes, CheckRef) then begin + N := VarArrayHighBound(Bytes, 1) - VarArrayLowBound(Bytes, 1) + 1; + FStream.WriteBuffer(HproseTagBytes, 1); + WriteRawByteString(RawByteString(IntToStr(N))); + FStream.WriteBuffer(HproseTagQuote, 1); + FStream.WriteBuffer(VarArrayLock(Bytes)^, N); + VarArrayUnLock(Bytes); + FStream.WriteBuffer(HproseTagQuote, 1); + end; +end; + +function THproseWriter.WriteClass(Instance: TObject): Integer; +var + ClassAlias: string; + PropName: ShortString; + PropList: PPropList; + PropCount, I: Integer; + CachePointer: PSerializeCache; + CacheStream: TMemoryStream; + TempData: RawByteString; + TempWStr: WideString; +begin + ClassAlias := GetClassAlias(Instance.ClassType); + if ClassAlias = '' then + raise EHproseException.Create(Instance.ClassName + ' has not registered'); + PropertiesCache.Lock; + try +{$IFDEF CPU64} + CachePointer := PSerializeCache(Int64(PropertiesCache[ClassAlias])); +{$ELSE} + CachePointer := PSerializeCache(Integer(PropertiesCache[ClassAlias])); +{$ENDIF} + if CachePointer = nil then begin + New(CachePointer); + try + CachePointer^.RefCount := 0; + CachePointer^.Data := ''; + CacheStream := TMemoryStream.Create; + try + PropCount := GetStoredPropList(Instance, PropList); + try + CacheStream.WriteBuffer(HproseTagClass, 1); + TempData := RawByteString(IntToStr(Length(ClassAlias))); + CacheStream.WriteBuffer(TempData[1], Length(TempData)); + CacheStream.WriteBuffer(HproseTagQuote, 1); + Tempdata := RawByteString(ClassAlias); + CacheStream.WriteBuffer(TempData[1], Length(TempData)); + CacheStream.WriteBuffer(HproseTagQuote, 1); + if PropCount > 0 then begin + Tempdata := RawByteString(IntToStr(PropCount)); + CacheStream.WriteBuffer(TempData[1], Length(TempData)); + end; + CacheStream.WriteBuffer(HproseTagOpenbrace, 1); + for I := 0 to PropCount - 1 do begin + PropName := PropList^[I]^.Name; + if PropName[1] in ['A'..'Z'] then + PropName[1] := AnsiChar(Integer(PropName[1]) + 32); + TempWStr := WideString(PropName); + CacheStream.WriteBuffer(HproseTagString, 1); + Tempdata := RawByteString(IntToStr(Length(TempWStr))); + CacheStream.WriteBuffer(TempData[1], Length(TempData)); + CacheStream.WriteBuffer(HproseTagQuote, 1); + Tempdata := UTF8Encode(TempWStr); + CacheStream.WriteBuffer(TempData[1], Length(TempData)); + CacheStream.WriteBuffer(HproseTagQuote, 1); + Inc(CachePointer^.RefCount); + end; + CacheStream.WriteBuffer(HproseTagClosebrace, 1); + finally + FreeMem(PropList); + end; + CacheStream.Position := 0; + SetLength(CachePointer^.Data, CacheStream.Size); + Move(CacheStream.Memory^, PAnsiChar(CachePointer^.Data)^, CacheStream.Size); + finally + CacheStream.Free; + end; + except + Dispose(CachePointer); + end; +{$IFDEF CPU64} + PropertiesCache[ClassAlias] := Int64(CachePointer); +{$ELSE} + PropertiesCache[ClassAlias] := Integer(CachePointer); +{$ENDIF} + end; + finally + PropertiesCache.UnLock; + end; + FStream.WriteBuffer(CachePointer^.Data[1], Length(CachePointer^.Data)); + if CachePointer^.RefCount > 0 then + FRefList.Count := FRefList.Count + CachePointer^.RefCount; + Result := FClassRefList.Add(Instance.ClassName); +end; + +procedure THproseWriter.WriteCurrency(C: Currency); +begin + stream.WriteBuffer(HproseTagDouble, 1); + WriteRawByteString(RawByteString(CurrToStr(C))); + stream.WriteBuffer(HproseTagSemicolon, 1); +end; + +procedure THproseWriter.WriteCurrencyArray(var P; Count: Integer); +var + AP: PCurrencyArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteCurrency(AP^[I]); +end; + +procedure THproseWriter.WriteDateTimeArray(var P; Count: Integer); +var + AP: PDateTimeArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteDateTime(AP^[I]); +end; + +procedure THproseWriter.WriteDateTime(const ADateTime: TDateTime; + CheckRef: Boolean); +var + ADate, ATime, AMillisecond: RawByteString; +begin + if WriteRef(ADateTime, CheckRef) then begin + ADate := RawByteString(FormatDateTime('yyyymmdd', ADateTime)); + ATime := RawByteString(FormatDateTime('hhnnss', ADateTime)); + AMillisecond := RawByteString(FormatDateTime('zzz', ADateTime)); + if (ATime = '000000') and (AMillisecond = '000') then begin + FStream.WriteBuffer(HproseTagDate, 1); + WriteRawByteString(ADate); + end + else if ADate = '18991230' then begin + FStream.WriteBuffer(HproseTagTime, 1); + WriteRawByteString(ATime); + if AMillisecond <> '000' then begin + FStream.WriteBuffer(HproseTagPoint, 1); + WriteRawByteString(AMillisecond); + end; + end + else begin + FStream.WriteBuffer(HproseTagDate, 1); + WriteRawByteString(ADate); + FStream.WriteBuffer(HproseTagTime, 1); + WriteRawByteString(ATime); + if AMillisecond <> '000' then begin + FStream.WriteBuffer(HproseTagPoint, 1); + WriteRawByteString(AMillisecond); + end; + end; + FStream.WriteBuffer(HproseTagSemicolon, 1); + end; +end; + +procedure THproseWriter.WriteDouble(D: Extended); +begin + if IsNaN(D) then + WriteNaN + else if IsInfinite(D) then + WriteInfinity(Sign(D) = 1) + else begin + stream.WriteBuffer(HproseTagDouble, 1); + WriteRawByteString(RawByteString(FloatToStr(D))); + stream.WriteBuffer(HproseTagSemicolon, 1); + end; +end; + +procedure THproseWriter.WriteDoubleArray(var P; Count: Integer); +var + AP: PDoubleArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteDouble(AP^[I]); +end; + +procedure THproseWriter.WriteInfinity(Positive: Boolean); +begin + FStream.WriteBuffer(HproseTagInfinity, 1); + FStream.WriteBuffer(HproseTagSign[Positive], 1); +end; + +procedure THproseWriter.WriteInt64Array(var P; Count: Integer); +var + AP: PInt64Array absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteLong(AP^[I]); +end; + +{$IFDEF DELPHI2009_UP} +procedure THproseWriter.WriteUInt64Array(var P; Count: Integer); +var + AP: PUInt64Array absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteLong(AP^[I]); +end; +{$ENDIF} + +{$IFDEF FPC} +procedure THproseWriter.WriteQWordArray(var P; Count: Integer); +var + AP: PQWordArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteLong(AP^[I]); +end; +{$ENDIF} + +procedure THproseWriter.WriteInteger(I: Integer); +var + C: AnsiChar; +begin + if (I >= 0) and (I <= 9) then begin + C := AnsiChar(I + Ord('0')); + FStream.WriteBuffer(C, 1); + end + else begin + FStream.WriteBuffer(HproseTagInteger, 1); + WriteRawByteString(RawByteString(IntToStr(I))); + FStream.WriteBuffer(HproseTagSemicolon, 1); + end; +end; + +procedure THproseWriter.WriteIntegerArray(var P; Count: Integer); +var + AP: PIntegerArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteInteger(AP^[I]); +end; + +procedure THproseWriter.WriteList(AList: IList; CheckRef: Boolean); +var + Count, I: Integer; +begin + if WriteRef(AList, CheckRef) then begin + Count := AList.Count; + FStream.WriteBuffer(HproseTagList, 1); + if Count > 0 then WriteRawByteString(RawByteString(IntToStr(Count))); + FStream.WriteBuffer(HproseTagOpenbrace, 1); + for I := 0 to Count - 1 do Serialize(AList[I]); + FStream.WriteBuffer(HproseTagClosebrace, 1); + end; +end; + +procedure THproseWriter.WriteLong(const L: RawByteString); +begin + if (Length(L) = 1) and (L[1] in ['0'..'9']) then + FStream.WriteBuffer(L[1], 1) + else begin + FStream.WriteBuffer(HproseTagLong, 1); + WriteRawByteString(L); + FStream.WriteBuffer(HproseTagSemicolon, 1); + end; +end; + +procedure THproseWriter.WriteLong(L: Int64); +var + C: AnsiChar; +begin + if (L >= 0) and (L <= 9) then begin + C := AnsiChar(L + Ord('0')); + FStream.WriteBuffer(C, 1); + end + else begin + FStream.WriteBuffer(HproseTagLong, 1); + WriteRawByteString(RawByteString(IntToStr(L))); + FStream.WriteBuffer(HproseTagSemicolon, 1); + end; +end; + +{$IFDEF DELPHI2009_UP} +procedure THproseWriter.WriteLong(L: UInt64); +var + C: AnsiChar; +begin + if L <= 9 then begin + C := AnsiChar(L + Ord('0')); + FStream.WriteBuffer(C, 1); + end + else begin + FStream.WriteBuffer(HproseTagLong, 1); + WriteRawByteString(RawByteString(UIntToStr(L))); + FStream.WriteBuffer(HproseTagSemicolon, 1); + end; +end; +{$ENDIF} + +{$IFDEF FPC} +procedure THproseWriter.WriteLong(L: QWord); +var + C: AnsiChar; +begin + if L <= 9 then begin + C := AnsiChar(L + Ord('0')); + FStream.WriteBuffer(C, 1); + end + else begin + FStream.WriteBuffer(HproseTagLong, 1); + WriteRawByteString(RawByteString(IntToStr(L))); + FStream.WriteBuffer(HproseTagSemicolon, 1); + end; +end; +{$ENDIF} + +procedure THproseWriter.WriteLongWordArray(var P; Count: Integer); +var + AP: PLongWordArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteLong(AP^[I]); +end; + +procedure THproseWriter.WriteMap(AMap: IMap; CheckRef: Boolean); +var + Count, I: Integer; +begin + if WriteRef(AMap, CheckRef) then begin + Count := AMap.Count; + FStream.WriteBuffer(HproseTagMap, 1); + if Count > 0 then WriteRawByteString(RawByteString(IntToStr(Count))); + FStream.WriteBuffer(HproseTagOpenbrace, 1); + for I := 0 to Count - 1 do begin + Serialize(AMap.Keys[I]); + Serialize(AMap.Values[I]); + end; + FStream.WriteBuffer(HproseTagClosebrace, 1); + end; +end; + +procedure THproseWriter.WriteNaN; +begin + FStream.WriteBuffer(HproseTagNaN, 1); +end; + +procedure THproseWriter.WriteNull; +begin + FStream.WriteBuffer(HproseTagNull, 1); +end; + +procedure THproseWriter.WriteEmpty; +begin + FStream.WriteBuffer(HproseTagEmpty, 1); +end; + +procedure THproseWriter.WriteObject(AObject: TObject; CheckRef: Boolean); +var + Ref, ClassRef: Integer; + Value: Variant; + PropList: PPropList; + PropCount, I: Integer; +begin + Value := ObjToVar(AObject); + if CheckRef then begin + Ref := FRefList.IndexOf(Value); + if Ref > -1 then begin + WriteRef(Ref); + Exit; + end; + end; + ClassRef := FClassRefList.IndexOf(AObject.ClassName); + if ClassRef < 0 then ClassRef := WriteClass(AObject); + FRefList.Add(Value); + FStream.WriteBuffer(HproseTagObject, 1); + WriteRawByteString(RawByteString(IntToStr(ClassRef))); + FStream.WriteBuffer(HproseTagOpenbrace, 1); + PropCount := GetStoredPropList(AObject, PropList); + try + for I := 0 to PropCount - 1 do + Serialize(GetPropValue(AObject, PropList^[I])); + finally + FreeMem(PropList); + end; + FStream.WriteBuffer(HproseTagClosebrace, 1); +end; + +procedure THproseWriter.WriteInterface(Intf: IInterface; + CheckRef: Boolean); +var + Ref, ClassRef: Integer; + Value: Variant; + AObject: TObject; + PropList: PPropList; + PropCount, I: Integer; +begin + Value := Intf; + if CheckRef then begin + Ref := FRefList.IndexOf(Value); + if Ref > -1 then begin + WriteRef(Ref); + Exit; + end; + end; + AObject := IntfToObj(Intf); + ClassRef := FClassRefList.IndexOf(AObject.ClassName); + if ClassRef < 0 then ClassRef := WriteClass(AObject); + FRefList.Add(Value); + FStream.WriteBuffer(HproseTagObject, 1); + WriteRawByteString(RawByteString(IntToStr(ClassRef))); + FStream.WriteBuffer(HproseTagOpenbrace, 1); + PropCount := GetStoredPropList(AObject, PropList); + try + for I := 0 to PropCount - 1 do + Serialize(GetPropValue(AObject, PropList^[I])); + finally + FreeMem(PropList); + end; + FStream.WriteBuffer(HproseTagClosebrace, 1); +end; + +function THproseWriter.WriteRef(const Value: Variant; + CheckRef: Boolean): Boolean; +var + Ref: Integer; +begin + if CheckRef then begin + Ref := FRefList.IndexOf(Value); + if Ref > -1 then begin + WriteRef(Ref); + Result := False; + Exit; + end; + end; + FRefList.Add(Value); + Result := True; +end; + +procedure THproseWriter.WriteRef(Value: Integer); +begin + FStream.WriteBuffer(HproseTagRef, 1); + WriteRawByteString(RawByteString(IntToStr(Value))); + FStream.WriteBuffer(HproseTagSemicolon, 1); +end; + +procedure THproseWriter.WriteShortIntArray(var P; Count: Integer); +var + AP: PShortIntArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteInteger(AP^[I]); +end; + +procedure THproseWriter.WriteSingleArray(var P; Count: Integer); +var + AP: PSingleArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteDouble(AP^[I]); +end; + +procedure THproseWriter.WriteSmallIntArray(var P; Count: Integer); +var + AP: PSmallIntArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteInteger(AP^[I]); +end; + +procedure THproseWriter.WriteUTF8Char(C: WideChar); +begin + FStream.WriteBuffer(HproseTagUTF8Char, 1); + WriteRawByteString(UTF8Encode(WideString(C))); +end; + +procedure THproseWriter.WriteString(const S: WideString; + CheckRef: Boolean); +begin + if WriteRef(S, CheckRef) then begin + FStream.WriteBuffer(HproseTagString, 1); + WriteRawByteString(RawByteString(IntToStr(Length(S)))); + FStream.WriteBuffer(HproseTagQuote, 1); + WriteRawByteString(UTF8Encode(S)); + FStream.WriteBuffer(HproseTagQuote, 1); + end; +end; + +procedure THproseWriter.WriteVariantArray(var P; Count: Integer); +var + AP: PVariantArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do Serialize(AP^[I]); +end; + +procedure THproseWriter.WriteWideStringArray(var P; Count: Integer); +var + AP: PWideStringArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteString(AP^[I]); +end; + +procedure THproseWriter.WriteWordArray(var P; Count: Integer); +var + AP: PWordArray absolute P; + I: Integer; +begin + for I := 0 to Count - 1 do WriteInteger(AP^[I]); +end; + +procedure THproseWriter.Reset; +begin + FRefList.Clear; + FClassRefList.Clear; +end; + +{ HproseSerialize } + +function HproseSerialize(Value: TObject): RawByteString; +begin + Result := HproseSerialize(ObjToVar(Value)); +end; + +function HproseSerialize(const Value: Variant): RawByteString; +var + Writer: THproseWriter; + Stream: TMemoryStream; +begin + Stream := TMemoryStream.Create; + try + Writer := THproseWriter.Create(Stream); + try + Writer.Serialize(Value); + Stream.Position := 0; + SetLength(Result, Stream.Size); + Move(Stream.Memory^, PAnsiChar(Result)^, Stream.Size); + finally + Writer.Free; + end; + finally + Stream.Free; + end; +end; + +function HproseSerialize(const Value: array of const): RawByteString; +var + Writer: THproseWriter; + Stream: TMemoryStream; +begin + Stream := TMemoryStream.Create; + try + Writer := THproseWriter.Create(Stream); + try + Writer.Serialize(Value); + Stream.Position := 0; + SetLength(Result, Stream.Size); + Move(Stream.Memory^, PAnsiChar(Result)^, Stream.Size); + finally + Writer.Free; + end; + finally + Stream.Free; + end; +end; + +{ HproseUnserialize } + +function HproseUnserialize(const Data: RawByteString; VType: TVarType; + AClass: TClass): Variant; +var + Reader: THproseReader; + Stream: TMemoryStream; +begin + Stream := TMemoryStream.Create; + try + Stream.SetSize(Length(Data)); + Move(PAnsiChar(Data)^, Stream.Memory^, Stream.Size); + Reader := THproseReader.Create(Stream); + try + Result := Reader.Unserialize(VType, AClass); + finally + Reader.Free; + end; + finally + Stream.Free; + end; +end; + +{ THproseFormatter } + +class function THproseFormatter.Serialize( + Value: TObject): RawByteString; +begin + Result := HproseSerialize(Value); +end; + +class function THproseFormatter.Serialize( + const Value: Variant): RawByteString; +begin + Result := HproseSerialize(Value); +end; + +class function THproseFormatter.Serialize( + const Value: array of const): RawByteString; +begin + Result := HproseSerialize(Value); +end; + +class function THproseFormatter.Unserialize(const Data: RawByteString; + VType: TVarType; AClass: TClass): Variant; +begin + Result := HproseUnserialize(Data, VType, AClass); +end; + +procedure FreePropertiesCache; +var + I: Integer; + CacheValues: IList; + CachePointer: PSerializeCache; +begin + PropertiesCache.Lock; + try + CacheValues := PropertiesCache.Values; + for I := 0 to CacheValues.Count - 1 do begin +{$IFDEF CPU64} + CachePointer := PSerializeCache(Int64(CacheValues[I])); +{$ELSE} + CachePointer := PSerializeCache(Integer(CacheValues[I])); +{$ENDIF} + Dispose(CachePointer); + end; + finally + PropertiesCache.Unlock; + end; +end; + +initialization + PropertiesCache := THashMap.Create; + +finalization + FreePropertiesCache; + +end. diff --git a/src/delphi/HproseSynaHttpClient.pas b/src/delphi/HproseSynaHttpClient.pas index aec3b41..5a3c719 100644 --- a/src/delphi/HproseSynaHttpClient.pas +++ b/src/delphi/HproseSynaHttpClient.pas @@ -1,342 +1,342 @@ -{ -/**********************************************************\ -| | -| hprose | -| | -| Official WebSite: http://www.hprose.com/ | -| http://www.hprose.net/ | -| http://www.hprose.org/ | -| | -\**********************************************************/ - -/**********************************************************\ - * * - * HproseSynaHttpClient.pas * - * * - * hprose synapse http client unit for delphi. * - * * - * LastModified: Dec 29, 2012 * - * Author: Ma Bingyao * - * * -\**********************************************************/ -} -unit HproseSynaHttpClient; - -{$I Hprose.inc} - -interface - -uses Classes, HproseCommon, HproseClient; - -type - - { THproseSynaHttpClient } - - THproseSynaHttpClient = class(THproseClient) - private - FHttpPool: IList; - FProtocol: string; - FUser: string; - FPassword: string; - FHost: string; - FPort: string; - FPath: string; - FPara: string; - FHeaders: TStringList; - FKeepAlive: Boolean; - FKeepAliveTimeout: integer; - FStatus100: Boolean; - FProxyHost: string; - FProxyPort: Integer; - FProxyUser: string; - FProxyPass: string; - FUserAgent: string; - FTimeout: Integer; - protected - function GetInvokeContext: TObject; override; - function GetOutputStream(var Context: TObject): TStream; override; - procedure SendData(var Context: TObject); override; - function GetInputStream(var Context: TObject): TStream; override; - procedure EndInvoke(var Context: TObject); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure UseService(const AUri: string); override; - published - {:Before HTTP operation you may define any non-standard headers for HTTP - request, except of: 'Expect: 100-continue', 'Content-Length', 'Content-Type', - 'Connection', 'Authorization', 'Proxy-Authorization' and 'Host' headers.} - property Headers: TStringList read FHeaders; - - {:If @true (default value is @false), keepalives in HTTP protocol 1.1 is enabled.} - property KeepAlive: Boolean read FKeepAlive write FKeepAlive; - - {:Define timeout for keepalives in seconds! Default value is 300.} - property KeepAliveTimeout: integer read FKeepAliveTimeout write FKeepAliveTimeout; - - {:if @true, then server is requested for 100status capability when uploading - data. Default is @true (on).} - property Status100: Boolean read FStatus100 write FStatus100; - - {:Address of proxy server (IP address or domain name).} - property ProxyHost: string read FProxyHost write FProxyHost; - - {:Port number for proxy connection. Default value is 8080.} - property ProxyPort: Integer read FProxyPort write FProxyPort; - - {:Username for connect to proxy server.} - property ProxyUser: string read FProxyUser write FProxyUser; - - {:Password for connect to proxy server.} - property ProxyPass: string read FProxyPass write FProxyPass; - - {:Here you can specify custom User-Agent indentification. By default is - used: 'Hprose Http Client for Delphi (Synapse)'} - property UserAgent: string read FUserAgent write FUserAgent; - - {:UserName for user authorization.} - property UserName: string read FUser write FUser; - - {:Password for user authorization.} - property Password: string read FPassword write FPassword; - - {:Specify default timeout for socket operations.} - property Timeout: Integer read FTimeout write FTimeout; - end; - -procedure Register; - -implementation - -uses httpsend, synautil, SysUtils, Variants; - -var - cookieManager: IMap; - -procedure SetCookie(Header: TStringList; const Host: string); -var - I, Pos: Integer; - Name, Value, CookieString, Path: string; - Cookie: IMap; -begin - for I := 0 to Header.Count - 1 do begin - Value := Header.Strings[I]; - Pos := AnsiPos(':', Value); - Name := LowerCase(Copy(Value, 1, Pos - 1)); - if (Name = 'set-cookie') or (Name = 'set-cookie2') then begin - Value := Trim(Copy(Value, Pos + 1, MaxInt)); - Pos := AnsiPos(';', Value); - CookieString := Copy(Value, 1, Pos - 1); - Value := Copy(Value, Pos + 1, MaxInt); - Cookie := TCaseInsensitiveHashMap.Split(Value, ';', '=', 0, True, False, True); - Pos := AnsiPos('=', CookieString); - Cookie['name'] := Copy(CookieString, 1, Pos - 1); - Cookie['value'] := Copy(CookieString, Pos + 1, MaxInt); - if Cookie.ContainsKey('path') then begin - Path := Cookie['path']; - if (Length(Path) > 0) then begin - if (Path[1] = '"') then Delete(Path, 1, 1); - if (Path[Length(Path)] = '"') then SetLength(Path, Length(Path) - 1); - end; - if (Length(Path) > 0) then - Cookie['path'] := Path - else - Cookie['path'] := '/'; - end - else - Cookie['path'] := '/'; - if Cookie.ContainsKey('expires') then begin - Cookie['expires'] := DecodeRfcDateTime(Cookie['expires']); - end; - if Cookie.ContainsKey('domain') then - Cookie['domain'] := LowerCase(Cookie['domain']) - else - Cookie['domain'] := Host; - Cookie['secure'] := Cookie.ContainsKey('secure'); - CookieManager.BeginWrite; - try - if not CookieManager.ContainsKey(Cookie['domain']) then - CookieManager[Cookie['domain']] := THashMap.Create(False, True) as IMap; - VarToMap(CookieManager[Cookie['domain']])[Cookie['name']] := Cookie; - finally - CookieManager.EndWrite; - end; - end; - end; -end; - -function GetCookie(const Host, Path: string; Secure: Boolean): string; -var - Cookies, CookieMap, Cookie: IMap; - Names: IList; - Domain: string; - I, J: Integer; -begin - Cookies := THashMap.Create(False); - CookieManager.BeginRead; - try - for I := 0 to CookieManager.Count - 1 do begin - Domain := VarToStr(CookieManager.Keys[I]); - if AnsiPos(Domain, Host) <> 0 then begin - CookieMap := VarToMap(CookieManager.Values[I]); - CookieMap.BeginRead; - try - Names := TArrayList.Create(False); - for J := 0 to CookieMap.Count - 1 do begin - Cookie := VarToMap(CookieMap.Values[J]); - if Cookie.ContainsKey('expires') and (Cookie['expires'] < Now) then - Names.Add(Cookie['name']) - else if AnsiPos(Cookie['path'], Path) = 1 then begin - if ((Secure and Cookie['secure']) or not Cookie['secure']) and - (Cookie['value'] <> '') then - Cookies[Cookie['name']] := Cookie['value']; - end; - end; - finally - CookieMap.EndRead; - end; - if Names.Count > 0 then begin - CookieMap.BeginWrite; - try - for J := 0 to Names.Count - 1 do CookieMap.Delete(Names[J]); - finally - CookieMap.EndWrite; - end; - end; - end; - end; - Result := Cookies.Join('; '); - finally - CookieManager.EndRead; - end; -end; - -{ THproseSynaHttpClient } - -function THproseSynaHttpClient.GetInvokeContext: TObject; -begin - FHttpPool.Lock; - try - if FHttpPool.Count > 0 then - Result := VarToObj(FHttpPool.Delete(FHttpPool.Count - 1)) - else - Result := THttpSend.Create; - finally - FHttpPool.Unlock; - end; -end; - -function THproseSynaHttpClient.GetOutputStream(var Context: TObject): TStream; -begin - if Context <> nil then - Result := THTTPSend(Context).Document - else - raise EHproseException.Create('Can''t get output stream.'); -end; - -procedure THproseSynaHttpClient.SendData(var Context: TObject); -var - Cookie: string; -begin - if Context <> nil then - with THTTPSend(Context) do begin - Headers.Assign(FHeaders); - KeepAlive := FKeepAlive; - KeepAliveTimeout := FKeepAliveTimeout; - Status100 := FStatus100; - UserName := FUser; - Password := FPassword; - ProxyHost := FProxyHost; - if FProxyPort = 0 then - ProxyPort := '' - else - ProxyPort := IntToStr(FProxyPort); - ProxyUser := FProxyUser; - ProxyPass := FProxyPass; - UserAgent := FUserAgent; - Timeout := FTimeout; - Protocol := '1.1'; - MimeType := 'application/hprose'; - Cookie := GetCookie(FHost, - FPath, - LowerCase(FProtocol) = 'https'); - if Cookie <> '' then Headers.Add('Cookie: ' + Cookie); - HTTPMethod('POST', FUri); - SetCookie(Headers, FHost); - end - else - raise EHproseException.Create('Can''t send data.'); -end; - -function THproseSynaHttpClient.GetInputStream(var Context: TObject): TStream; -begin - if Context <> nil then - Result := THTTPSend(Context).Document - else - raise EHproseException.Create('Can''t get input stream.'); -end; - -procedure THproseSynaHttpClient.EndInvoke(var Context: TObject); -begin - if Context <> nil then begin - FHttpPool.Lock; - try - with THTTPSend(Context) do begin - Clear; - Cookies.Clear; - end; - FHttpPool.Add(ObjToVar(Context)); - finally - FHttpPool.Unlock; - end; - end; -end; - -constructor THproseSynaHttpClient.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FHttpPool := TArrayList.Create(10); - FHeaders := TStringList.Create; - FUser := ''; - FPassword := ''; - FKeepAlive := False; - FKeepAliveTimeout := 300; - FStatus100 := False; - FProxyHost := ''; - FProxyPort := 8080; - FProxyUser := ''; - FProxyPass := ''; - FUserAgent := 'Hprose Http Client for Delphi (Synapse)'; - FTimeout := 30000; -end; - -destructor THproseSynaHttpClient.Destroy; -var - I: Integer; -begin - FHttpPool.Lock; - try - for I := FHttpPool.Count - 1 downto 0 do - THTTPSend(VarToObj(FHttpPool.Delete(I))).Free; - finally - FHttpPool.Unlock; - end; - FreeAndNil(FHeaders); - inherited; -end; - -procedure THproseSynaHttpClient.UseService(const AUri: string); -begin - inherited UseService(AUri); - ParseURL(FUri, FProtocol, FUser, FPassword, FHost, FPort, FPath, FPara); -end; - -procedure Register; -begin - RegisterComponents('Hprose',[THproseSynaHttpClient]); -end; - -initialization - CookieManager := TCaseInsensitiveHashMap.Create(False, True); - -end. +{ +/**********************************************************\ +| | +| hprose | +| | +| Official WebSite: http://www.hprose.com/ | +| http://www.hprose.net/ | +| http://www.hprose.org/ | +| | +\**********************************************************/ + +/**********************************************************\ + * * + * HproseSynaHttpClient.pas * + * * + * hprose synapse http client unit for delphi. * + * * + * LastModified: Dec 29, 2012 * + * Author: Ma Bingyao * + * * +\**********************************************************/ +} +unit HproseSynaHttpClient; + +{$I Hprose.inc} + +interface + +uses Classes, HproseCommon, HproseClient; + +type + + { THproseSynaHttpClient } + + THproseSynaHttpClient = class(THproseClient) + private + FHttpPool: IList; + FProtocol: string; + FUser: string; + FPassword: string; + FHost: string; + FPort: string; + FPath: string; + FPara: string; + FHeaders: TStringList; + FKeepAlive: Boolean; + FKeepAliveTimeout: integer; + FStatus100: Boolean; + FProxyHost: string; + FProxyPort: Integer; + FProxyUser: string; + FProxyPass: string; + FUserAgent: string; + FTimeout: Integer; + protected + function GetInvokeContext: TObject; override; + function GetOutputStream(var Context: TObject): TStream; override; + procedure SendData(var Context: TObject); override; + function GetInputStream(var Context: TObject): TStream; override; + procedure EndInvoke(var Context: TObject); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure UseService(const AUri: string); override; + published + {:Before HTTP operation you may define any non-standard headers for HTTP + request, except of: 'Expect: 100-continue', 'Content-Length', 'Content-Type', + 'Connection', 'Authorization', 'Proxy-Authorization' and 'Host' headers.} + property Headers: TStringList read FHeaders; + + {:If @true (default value is @false), keepalives in HTTP protocol 1.1 is enabled.} + property KeepAlive: Boolean read FKeepAlive write FKeepAlive; + + {:Define timeout for keepalives in seconds! Default value is 300.} + property KeepAliveTimeout: integer read FKeepAliveTimeout write FKeepAliveTimeout; + + {:if @true, then server is requested for 100status capability when uploading + data. Default is @true (on).} + property Status100: Boolean read FStatus100 write FStatus100; + + {:Address of proxy server (IP address or domain name).} + property ProxyHost: string read FProxyHost write FProxyHost; + + {:Port number for proxy connection. Default value is 8080.} + property ProxyPort: Integer read FProxyPort write FProxyPort; + + {:Username for connect to proxy server.} + property ProxyUser: string read FProxyUser write FProxyUser; + + {:Password for connect to proxy server.} + property ProxyPass: string read FProxyPass write FProxyPass; + + {:Here you can specify custom User-Agent indentification. By default is + used: 'Hprose Http Client for Delphi (Synapse)'} + property UserAgent: string read FUserAgent write FUserAgent; + + {:UserName for user authorization.} + property UserName: string read FUser write FUser; + + {:Password for user authorization.} + property Password: string read FPassword write FPassword; + + {:Specify default timeout for socket operations.} + property Timeout: Integer read FTimeout write FTimeout; + end; + +procedure Register; + +implementation + +uses httpsend, synautil, SysUtils, Variants; + +var + cookieManager: IMap; + +procedure SetCookie(Header: TStringList; const Host: string); +var + I, Pos: Integer; + Name, Value, CookieString, Path: string; + Cookie: IMap; +begin + for I := 0 to Header.Count - 1 do begin + Value := Header.Strings[I]; + Pos := AnsiPos(':', Value); + Name := LowerCase(Copy(Value, 1, Pos - 1)); + if (Name = 'set-cookie') or (Name = 'set-cookie2') then begin + Value := Trim(Copy(Value, Pos + 1, MaxInt)); + Pos := AnsiPos(';', Value); + CookieString := Copy(Value, 1, Pos - 1); + Value := Copy(Value, Pos + 1, MaxInt); + Cookie := TCaseInsensitiveHashMap.Split(Value, ';', '=', 0, True, False, True); + Pos := AnsiPos('=', CookieString); + Cookie['name'] := Copy(CookieString, 1, Pos - 1); + Cookie['value'] := Copy(CookieString, Pos + 1, MaxInt); + if Cookie.ContainsKey('path') then begin + Path := Cookie['path']; + if (Length(Path) > 0) then begin + if (Path[1] = '"') then Delete(Path, 1, 1); + if (Path[Length(Path)] = '"') then SetLength(Path, Length(Path) - 1); + end; + if (Length(Path) > 0) then + Cookie['path'] := Path + else + Cookie['path'] := '/'; + end + else + Cookie['path'] := '/'; + if Cookie.ContainsKey('expires') then begin + Cookie['expires'] := DecodeRfcDateTime(Cookie['expires']); + end; + if Cookie.ContainsKey('domain') then + Cookie['domain'] := LowerCase(Cookie['domain']) + else + Cookie['domain'] := Host; + Cookie['secure'] := Cookie.ContainsKey('secure'); + CookieManager.BeginWrite; + try + if not CookieManager.ContainsKey(Cookie['domain']) then + CookieManager[Cookie['domain']] := THashMap.Create(False, True) as IMap; + VarToMap(CookieManager[Cookie['domain']])[Cookie['name']] := Cookie; + finally + CookieManager.EndWrite; + end; + end; + end; +end; + +function GetCookie(const Host, Path: string; Secure: Boolean): string; +var + Cookies, CookieMap, Cookie: IMap; + Names: IList; + Domain: string; + I, J: Integer; +begin + Cookies := THashMap.Create(False); + CookieManager.BeginRead; + try + for I := 0 to CookieManager.Count - 1 do begin + Domain := VarToStr(CookieManager.Keys[I]); + if AnsiPos(Domain, Host) <> 0 then begin + CookieMap := VarToMap(CookieManager.Values[I]); + CookieMap.BeginRead; + try + Names := TArrayList.Create(False); + for J := 0 to CookieMap.Count - 1 do begin + Cookie := VarToMap(CookieMap.Values[J]); + if Cookie.ContainsKey('expires') and (Cookie['expires'] < Now) then + Names.Add(Cookie['name']) + else if AnsiPos(Cookie['path'], Path) = 1 then begin + if ((Secure and Cookie['secure']) or not Cookie['secure']) and + (Cookie['value'] <> '') then + Cookies[Cookie['name']] := Cookie['value']; + end; + end; + finally + CookieMap.EndRead; + end; + if Names.Count > 0 then begin + CookieMap.BeginWrite; + try + for J := 0 to Names.Count - 1 do CookieMap.Delete(Names[J]); + finally + CookieMap.EndWrite; + end; + end; + end; + end; + Result := Cookies.Join('; '); + finally + CookieManager.EndRead; + end; +end; + +{ THproseSynaHttpClient } + +function THproseSynaHttpClient.GetInvokeContext: TObject; +begin + FHttpPool.Lock; + try + if FHttpPool.Count > 0 then + Result := VarToObj(FHttpPool.Delete(FHttpPool.Count - 1)) + else + Result := THttpSend.Create; + finally + FHttpPool.Unlock; + end; +end; + +function THproseSynaHttpClient.GetOutputStream(var Context: TObject): TStream; +begin + if Context <> nil then + Result := THTTPSend(Context).Document + else + raise EHproseException.Create('Can''t get output stream.'); +end; + +procedure THproseSynaHttpClient.SendData(var Context: TObject); +var + Cookie: string; +begin + if Context <> nil then + with THTTPSend(Context) do begin + Headers.Assign(FHeaders); + KeepAlive := FKeepAlive; + KeepAliveTimeout := FKeepAliveTimeout; + Status100 := FStatus100; + UserName := FUser; + Password := FPassword; + ProxyHost := FProxyHost; + if FProxyPort = 0 then + ProxyPort := '' + else + ProxyPort := IntToStr(FProxyPort); + ProxyUser := FProxyUser; + ProxyPass := FProxyPass; + UserAgent := FUserAgent; + Timeout := FTimeout; + Protocol := '1.1'; + MimeType := 'application/hprose'; + Cookie := GetCookie(FHost, + FPath, + LowerCase(FProtocol) = 'https'); + if Cookie <> '' then Headers.Add('Cookie: ' + Cookie); + HTTPMethod('POST', FUri); + SetCookie(Headers, FHost); + end + else + raise EHproseException.Create('Can''t send data.'); +end; + +function THproseSynaHttpClient.GetInputStream(var Context: TObject): TStream; +begin + if Context <> nil then + Result := THTTPSend(Context).Document + else + raise EHproseException.Create('Can''t get input stream.'); +end; + +procedure THproseSynaHttpClient.EndInvoke(var Context: TObject); +begin + if Context <> nil then begin + FHttpPool.Lock; + try + with THTTPSend(Context) do begin + Clear; + Cookies.Clear; + end; + FHttpPool.Add(ObjToVar(Context)); + finally + FHttpPool.Unlock; + end; + end; +end; + +constructor THproseSynaHttpClient.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FHttpPool := TArrayList.Create(10); + FHeaders := TStringList.Create; + FUser := ''; + FPassword := ''; + FKeepAlive := False; + FKeepAliveTimeout := 300; + FStatus100 := False; + FProxyHost := ''; + FProxyPort := 8080; + FProxyUser := ''; + FProxyPass := ''; + FUserAgent := 'Hprose Http Client for Delphi (Synapse)'; + FTimeout := 30000; +end; + +destructor THproseSynaHttpClient.Destroy; +var + I: Integer; +begin + FHttpPool.Lock; + try + for I := FHttpPool.Count - 1 downto 0 do + THTTPSend(VarToObj(FHttpPool.Delete(I))).Free; + finally + FHttpPool.Unlock; + end; + FreeAndNil(FHeaders); + inherited; +end; + +procedure THproseSynaHttpClient.UseService(const AUri: string); +begin + inherited UseService(AUri); + ParseURL(FUri, FProtocol, FUser, FPassword, FHost, FPort, FPath, FPara); +end; + +procedure Register; +begin + RegisterComponents('Hprose',[THproseSynaHttpClient]); +end; + +initialization + CookieManager := TCaseInsensitiveHashMap.Create(False, True); + +end. diff --git a/src/dotnet/examples/HproseTest/HproseClient/App.config b/src/dotnet/examples/HproseTest/HproseClient/App.config index fad249e..8e15646 100644 --- a/src/dotnet/examples/HproseTest/HproseClient/App.config +++ b/src/dotnet/examples/HproseTest/HproseClient/App.config @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/src/dotnet/examples/HproseTest/HproseClient/HproseClient.csproj b/src/dotnet/examples/HproseTest/HproseClient/HproseClient.csproj index 74a9bb3..c2845ff 100644 --- a/src/dotnet/examples/HproseTest/HproseClient/HproseClient.csproj +++ b/src/dotnet/examples/HproseTest/HproseClient/HproseClient.csproj @@ -1,61 +1,61 @@ - - - - - Debug - AnyCPU - {5335C949-D135-4BED-9170-08345AA50170} - Exe - Properties - HproseClient - HproseClient - v4.5 - 512 - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - .\Hprose.Client.dll - - - - - - - - - - - - - - - - - - + + + + + Debug + AnyCPU + {5335C949-D135-4BED-9170-08345AA50170} + Exe + Properties + HproseClient + HproseClient + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + .\Hprose.Client.dll + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/dotnet/examples/HproseTest/HproseClient/Program.cs b/src/dotnet/examples/HproseTest/HproseClient/Program.cs index d88a8a0..d3c8f2d 100644 --- a/src/dotnet/examples/HproseTest/HproseClient/Program.cs +++ b/src/dotnet/examples/HproseTest/HproseClient/Program.cs @@ -1,48 +1,48 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Hprose.Client; -using Hprose.IO; - -namespace HproseClient -{ - [Serializable] - public class User - { - public string name; - public int age; - public bool male; - public List friends; - } - class Program - { - static void Main(string[] args) - { - ClassManager.Register(typeof(User), "User"); - HproseHttpClient client = new HproseHttpClient("http://localhost:2012/"); - List users = new List(); - User user1 = new User(); - user1.name = "李雷"; - user1.age = 32; - user1.male = true; - user1.friends = new List(); - User user2 = new User(); - user2.name = "韩梅梅"; - user2.age = 31; - user2.male = false; - user2.friends = new List(); - user1.friends.Add(user2); - user2.friends.Add(user1); - users.Add(user1); - users.Add(user2); - Func, List> SendUsers = userList => client.Invoke>("sendUsers", new object[] { userList }); - - MemoryStream stream = (MemoryStream)HproseFormatter.Serialize(SendUsers(users)); - Console.WriteLine(Encoding.UTF8.GetString(stream.ToArray())); - Console.ReadLine(); - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Hprose.Client; +using Hprose.IO; + +namespace HproseClient +{ + [Serializable] + public class User + { + public string name; + public int age; + public bool male; + public List friends; + } + class Program + { + static void Main(string[] args) + { + ClassManager.Register(typeof(User), "User"); + HproseHttpClient client = new HproseHttpClient("http://localhost:2012/"); + List users = new List(); + User user1 = new User(); + user1.name = "李雷"; + user1.age = 32; + user1.male = true; + user1.friends = new List(); + User user2 = new User(); + user2.name = "韩梅梅"; + user2.age = 31; + user2.male = false; + user2.friends = new List(); + user1.friends.Add(user2); + user2.friends.Add(user1); + users.Add(user1); + users.Add(user2); + Func, List> SendUsers = userList => client.Invoke>("sendUsers", new object[] { userList }); + + MemoryStream stream = (MemoryStream)HproseFormatter.Serialize(SendUsers(users)); + Console.WriteLine(Encoding.UTF8.GetString(stream.ToArray())); + Console.ReadLine(); + } + } +} diff --git a/src/dotnet/examples/HproseTest/HproseServer/App.config b/src/dotnet/examples/HproseTest/HproseServer/App.config index fad249e..8e15646 100644 --- a/src/dotnet/examples/HproseTest/HproseServer/App.config +++ b/src/dotnet/examples/HproseTest/HproseServer/App.config @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/src/dotnet/examples/HproseTest/HproseServer/HproseServer.csproj b/src/dotnet/examples/HproseTest/HproseServer/HproseServer.csproj index 24a4001..c0fe37f 100644 --- a/src/dotnet/examples/HproseTest/HproseServer/HproseServer.csproj +++ b/src/dotnet/examples/HproseTest/HproseServer/HproseServer.csproj @@ -1,61 +1,61 @@ - - - - - Debug - AnyCPU - {614BEEC8-86A2-4BBB-BC30-33174D41B4C4} - Exe - Properties - HproseServer - HproseServer - v4.5 - 512 - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - .\Hprose.dll - - - - - - - - - - - - - - - - - - + + + + + Debug + AnyCPU + {614BEEC8-86A2-4BBB-BC30-33174D41B4C4} + Exe + Properties + HproseServer + HproseServer + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + .\Hprose.dll + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/dotnet/examples/HproseTest/HproseServer/Program.cs b/src/dotnet/examples/HproseTest/HproseServer/Program.cs index 657a81e..96d69d1 100644 --- a/src/dotnet/examples/HproseTest/HproseServer/Program.cs +++ b/src/dotnet/examples/HproseTest/HproseServer/Program.cs @@ -1,45 +1,45 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Hprose.Server; -using Hprose.IO; - -namespace HproseServer -{ - [Serializable] - public class User - { - public string name; - public int age; - public bool male; - public List friends; - } - class TestService - { - public List SendUsers(List users) - { - foreach (User user in users) - { - Console.WriteLine("name={0}, age={1}, male={2}", user.name, user.age, user.male); - } - return users; - } - } - class Program - { - static void Main(string[] args) - { - ClassManager.Register(typeof(User), "User"); - HproseHttpListenerServer server = new HproseHttpListenerServer("http://localhost:2012/"); - server.Methods.AddInstanceMethods(new TestService()); - server.IsCrossDomainEnabled = true; - server.CrossDomainXmlFile = "crossdomain.xml"; - server.Start(); - Console.WriteLine("Server started."); - Console.ReadLine(); - Console.WriteLine("Server stopped."); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Hprose.Server; +using Hprose.IO; + +namespace HproseServer +{ + [Serializable] + public class User + { + public string name; + public int age; + public bool male; + public List friends; + } + class TestService + { + public List SendUsers(List users) + { + foreach (User user in users) + { + Console.WriteLine("name={0}, age={1}, male={2}", user.name, user.age, user.male); + } + return users; + } + } + class Program + { + static void Main(string[] args) + { + ClassManager.Register(typeof(User), "User"); + HproseHttpListenerServer server = new HproseHttpListenerServer("http://localhost:2012/"); + server.Methods.AddInstanceMethods(new TestService()); + server.IsCrossDomainEnabled = true; + server.CrossDomainXmlFile = "crossdomain.xml"; + server.Start(); + Console.WriteLine("Server started."); + Console.ReadLine(); + Console.WriteLine("Server stopped."); + } + } +} diff --git a/src/dotnet/examples/HproseTest/HproseServer/bin/Debug/crossdomain.xml b/src/dotnet/examples/HproseTest/HproseServer/bin/Debug/crossdomain.xml index c1a1d5b..bb9ee5c 100644 --- a/src/dotnet/examples/HproseTest/HproseServer/bin/Debug/crossdomain.xml +++ b/src/dotnet/examples/HproseTest/HproseServer/bin/Debug/crossdomain.xml @@ -1,15 +1,15 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/src/dotnet/examples/HproseTest/HproseServer/bin/Release/crossdomain.xml b/src/dotnet/examples/HproseTest/HproseServer/bin/Release/crossdomain.xml index c1a1d5b..bb9ee5c 100644 --- a/src/dotnet/examples/HproseTest/HproseServer/bin/Release/crossdomain.xml +++ b/src/dotnet/examples/HproseTest/HproseServer/bin/Release/crossdomain.xml @@ -1,15 +1,15 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/src/dotnet/examples/HproseTest/HproseTest.sln b/src/dotnet/examples/HproseTest/HproseTest.sln index f20a943..6256b97 100644 --- a/src/dotnet/examples/HproseTest/HproseTest.sln +++ b/src/dotnet/examples/HproseTest/HproseTest.sln @@ -1,80 +1,80 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HproseServer", "HproseServer\HproseServer.csproj", "{614BEEC8-86A2-4BBB-BC30-33174D41B4C4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HproseClient", "HproseClient\HproseClient.csproj", "{5335C949-D135-4BED-9170-08345AA50170}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightHproseClient", "SilverlightHproseClient\SilverlightHproseClient.csproj", "{CF994370-D58E-40CF-9F81-1DD3D75CCEFE}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestSerialize", "TestSerialize\TestSerialize.csproj", "{1B196BC0-4075-4D9B-AC63-9555D6221024}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestHashMap", "TestHashMap\TestHashMap.csproj", "{8BFF425C-6D25-4948-8578-41729CA0E19C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|ARM = Debug|ARM - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|ARM = Release|ARM - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Debug|ARM.ActiveCfg = Debug|Any CPU - {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Debug|x64.ActiveCfg = Debug|Any CPU - {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Debug|x86.ActiveCfg = Debug|Any CPU - {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Release|Any CPU.Build.0 = Release|Any CPU - {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Release|ARM.ActiveCfg = Release|Any CPU - {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Release|x64.ActiveCfg = Release|Any CPU - {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Release|x86.ActiveCfg = Release|Any CPU - {5335C949-D135-4BED-9170-08345AA50170}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5335C949-D135-4BED-9170-08345AA50170}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5335C949-D135-4BED-9170-08345AA50170}.Debug|ARM.ActiveCfg = Debug|Any CPU - {5335C949-D135-4BED-9170-08345AA50170}.Debug|x64.ActiveCfg = Debug|Any CPU - {5335C949-D135-4BED-9170-08345AA50170}.Debug|x86.ActiveCfg = Debug|Any CPU - {5335C949-D135-4BED-9170-08345AA50170}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5335C949-D135-4BED-9170-08345AA50170}.Release|Any CPU.Build.0 = Release|Any CPU - {5335C949-D135-4BED-9170-08345AA50170}.Release|ARM.ActiveCfg = Release|Any CPU - {5335C949-D135-4BED-9170-08345AA50170}.Release|x64.ActiveCfg = Release|Any CPU - {5335C949-D135-4BED-9170-08345AA50170}.Release|x86.ActiveCfg = Release|Any CPU - {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Debug|ARM.ActiveCfg = Debug|Any CPU - {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Debug|x64.ActiveCfg = Debug|Any CPU - {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Debug|x86.ActiveCfg = Debug|Any CPU - {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Release|Any CPU.Build.0 = Release|Any CPU - {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Release|ARM.ActiveCfg = Release|Any CPU - {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Release|x64.ActiveCfg = Release|Any CPU - {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Release|x86.ActiveCfg = Release|Any CPU - {1B196BC0-4075-4D9B-AC63-9555D6221024}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1B196BC0-4075-4D9B-AC63-9555D6221024}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1B196BC0-4075-4D9B-AC63-9555D6221024}.Debug|ARM.ActiveCfg = Debug|Any CPU - {1B196BC0-4075-4D9B-AC63-9555D6221024}.Debug|x64.ActiveCfg = Debug|Any CPU - {1B196BC0-4075-4D9B-AC63-9555D6221024}.Debug|x86.ActiveCfg = Debug|Any CPU - {1B196BC0-4075-4D9B-AC63-9555D6221024}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1B196BC0-4075-4D9B-AC63-9555D6221024}.Release|Any CPU.Build.0 = Release|Any CPU - {1B196BC0-4075-4D9B-AC63-9555D6221024}.Release|ARM.ActiveCfg = Release|Any CPU - {1B196BC0-4075-4D9B-AC63-9555D6221024}.Release|x64.ActiveCfg = Release|Any CPU - {1B196BC0-4075-4D9B-AC63-9555D6221024}.Release|x86.ActiveCfg = Release|Any CPU - {8BFF425C-6D25-4948-8578-41729CA0E19C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8BFF425C-6D25-4948-8578-41729CA0E19C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8BFF425C-6D25-4948-8578-41729CA0E19C}.Debug|ARM.ActiveCfg = Debug|Any CPU - {8BFF425C-6D25-4948-8578-41729CA0E19C}.Debug|x64.ActiveCfg = Debug|Any CPU - {8BFF425C-6D25-4948-8578-41729CA0E19C}.Debug|x86.ActiveCfg = Debug|Any CPU - {8BFF425C-6D25-4948-8578-41729CA0E19C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8BFF425C-6D25-4948-8578-41729CA0E19C}.Release|Any CPU.Build.0 = Release|Any CPU - {8BFF425C-6D25-4948-8578-41729CA0E19C}.Release|ARM.ActiveCfg = Release|Any CPU - {8BFF425C-6D25-4948-8578-41729CA0E19C}.Release|x64.ActiveCfg = Release|Any CPU - {8BFF425C-6D25-4948-8578-41729CA0E19C}.Release|x86.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HproseServer", "HproseServer\HproseServer.csproj", "{614BEEC8-86A2-4BBB-BC30-33174D41B4C4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HproseClient", "HproseClient\HproseClient.csproj", "{5335C949-D135-4BED-9170-08345AA50170}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightHproseClient", "SilverlightHproseClient\SilverlightHproseClient.csproj", "{CF994370-D58E-40CF-9F81-1DD3D75CCEFE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestSerialize", "TestSerialize\TestSerialize.csproj", "{1B196BC0-4075-4D9B-AC63-9555D6221024}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestHashMap", "TestHashMap\TestHashMap.csproj", "{8BFF425C-6D25-4948-8578-41729CA0E19C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Debug|ARM.ActiveCfg = Debug|Any CPU + {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Debug|x64.ActiveCfg = Debug|Any CPU + {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Debug|x86.ActiveCfg = Debug|Any CPU + {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Release|Any CPU.Build.0 = Release|Any CPU + {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Release|ARM.ActiveCfg = Release|Any CPU + {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Release|x64.ActiveCfg = Release|Any CPU + {614BEEC8-86A2-4BBB-BC30-33174D41B4C4}.Release|x86.ActiveCfg = Release|Any CPU + {5335C949-D135-4BED-9170-08345AA50170}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5335C949-D135-4BED-9170-08345AA50170}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5335C949-D135-4BED-9170-08345AA50170}.Debug|ARM.ActiveCfg = Debug|Any CPU + {5335C949-D135-4BED-9170-08345AA50170}.Debug|x64.ActiveCfg = Debug|Any CPU + {5335C949-D135-4BED-9170-08345AA50170}.Debug|x86.ActiveCfg = Debug|Any CPU + {5335C949-D135-4BED-9170-08345AA50170}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5335C949-D135-4BED-9170-08345AA50170}.Release|Any CPU.Build.0 = Release|Any CPU + {5335C949-D135-4BED-9170-08345AA50170}.Release|ARM.ActiveCfg = Release|Any CPU + {5335C949-D135-4BED-9170-08345AA50170}.Release|x64.ActiveCfg = Release|Any CPU + {5335C949-D135-4BED-9170-08345AA50170}.Release|x86.ActiveCfg = Release|Any CPU + {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Debug|ARM.ActiveCfg = Debug|Any CPU + {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Debug|x64.ActiveCfg = Debug|Any CPU + {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Debug|x86.ActiveCfg = Debug|Any CPU + {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Release|Any CPU.Build.0 = Release|Any CPU + {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Release|ARM.ActiveCfg = Release|Any CPU + {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Release|x64.ActiveCfg = Release|Any CPU + {CF994370-D58E-40CF-9F81-1DD3D75CCEFE}.Release|x86.ActiveCfg = Release|Any CPU + {1B196BC0-4075-4D9B-AC63-9555D6221024}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B196BC0-4075-4D9B-AC63-9555D6221024}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B196BC0-4075-4D9B-AC63-9555D6221024}.Debug|ARM.ActiveCfg = Debug|Any CPU + {1B196BC0-4075-4D9B-AC63-9555D6221024}.Debug|x64.ActiveCfg = Debug|Any CPU + {1B196BC0-4075-4D9B-AC63-9555D6221024}.Debug|x86.ActiveCfg = Debug|Any CPU + {1B196BC0-4075-4D9B-AC63-9555D6221024}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B196BC0-4075-4D9B-AC63-9555D6221024}.Release|Any CPU.Build.0 = Release|Any CPU + {1B196BC0-4075-4D9B-AC63-9555D6221024}.Release|ARM.ActiveCfg = Release|Any CPU + {1B196BC0-4075-4D9B-AC63-9555D6221024}.Release|x64.ActiveCfg = Release|Any CPU + {1B196BC0-4075-4D9B-AC63-9555D6221024}.Release|x86.ActiveCfg = Release|Any CPU + {8BFF425C-6D25-4948-8578-41729CA0E19C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8BFF425C-6D25-4948-8578-41729CA0E19C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8BFF425C-6D25-4948-8578-41729CA0E19C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {8BFF425C-6D25-4948-8578-41729CA0E19C}.Debug|x64.ActiveCfg = Debug|Any CPU + {8BFF425C-6D25-4948-8578-41729CA0E19C}.Debug|x86.ActiveCfg = Debug|Any CPU + {8BFF425C-6D25-4948-8578-41729CA0E19C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8BFF425C-6D25-4948-8578-41729CA0E19C}.Release|Any CPU.Build.0 = Release|Any CPU + {8BFF425C-6D25-4948-8578-41729CA0E19C}.Release|ARM.ActiveCfg = Release|Any CPU + {8BFF425C-6D25-4948-8578-41729CA0E19C}.Release|x64.ActiveCfg = Release|Any CPU + {8BFF425C-6D25-4948-8578-41729CA0E19C}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/dotnet/examples/HproseTest/SilverlightHproseClient/App.xaml b/src/dotnet/examples/HproseTest/SilverlightHproseClient/App.xaml index 6609b02..fa57a13 100644 --- a/src/dotnet/examples/HproseTest/SilverlightHproseClient/App.xaml +++ b/src/dotnet/examples/HproseTest/SilverlightHproseClient/App.xaml @@ -1,8 +1,8 @@ - - - - - + + + + + diff --git a/src/dotnet/examples/HproseTest/SilverlightHproseClient/MainPage.xaml b/src/dotnet/examples/HproseTest/SilverlightHproseClient/MainPage.xaml index ae2b01a..c1b5f0d 100644 --- a/src/dotnet/examples/HproseTest/SilverlightHproseClient/MainPage.xaml +++ b/src/dotnet/examples/HproseTest/SilverlightHproseClient/MainPage.xaml @@ -1,13 +1,13 @@ - - - -