From 4b380f75e54206007001f87b94343850a2b258ff Mon Sep 17 00:00:00 2001 From: Joshua Sigona Date: Sat, 20 Jun 2020 13:20:11 +0900 Subject: [PATCH] Create Enemy Randomizer for Rabi-Ribi --- RandomizeRabiEnemies.bat | 1 + RandomizeRabiEnemies.jar | Bin 0 -> 76519 bytes bin/org/json/CDL.class | Bin 0 -> 4450 bytes bin/org/json/Cookie.class | Bin 0 -> 3154 bytes bin/org/json/CookieList.class | Bin 0 -> 1985 bytes bin/org/json/HTTP.class | Bin 0 -> 2690 bytes bin/org/json/HTTPTokener.class | Bin 0 -> 1106 bytes bin/org/json/JSONArray.class | Bin 0 -> 16018 bytes bin/org/json/JSONException.class | Bin 0 -> 772 bytes bin/org/json/JSONML.class | Bin 0 -> 7376 bytes bin/org/json/JSONObject$Null.class | Bin 0 -> 793 bytes bin/org/json/JSONObject.class | Bin 0 -> 27200 bytes bin/org/json/JSONPointer$Builder.class | Bin 0 -> 1233 bytes bin/org/json/JSONPointer.class | Bin 0 -> 4937 bytes bin/org/json/JSONPointerException.class | Bin 0 -> 611 bytes bin/org/json/JSONString.class | Bin 0 -> 156 bytes bin/org/json/JSONStringer.class | Bin 0 -> 616 bytes bin/org/json/JSONTokener.class | Bin 0 -> 6401 bytes bin/org/json/JSONWriter.class | Bin 0 -> 4224 bytes bin/org/json/Property.class | Bin 0 -> 1747 bytes bin/org/json/XML$1$1.class | Bin 0 -> 1377 bytes bin/org/json/XML$1.class | Bin 0 -> 829 bytes bin/org/json/XML.class | Bin 0 -> 9320 bytes bin/org/json/XMLTokener.class | Bin 0 -> 4797 bytes bin/sig/ReadFile.class | Bin 0 -> 12316 bytes bin/sig/utils/DebugUtils.class | Bin 0 -> 1384 bytes bin/sig/utils/DrawUtils.class | Bin 0 -> 8107 bytes bin/sig/utils/FileUtils.class | Bin 0 -> 9244 bytes bin/sig/utils/GithubUtils.class | Bin 0 -> 1787 bytes bin/sig/utils/JavaUtils.class | Bin 0 -> 2341 bytes bin/sig/utils/MemoryUtils.class | Bin 0 -> 1150 bytes bin/sig/utils/ReflectUtils.class | Bin 0 -> 542 bytes bin/sig/utils/SoundUtils.class | Bin 0 -> 1448 bytes bin/sig/utils/TextUtils.class | Bin 0 -> 4293 bytes bin/sig/utils/TimeUtils.class | Bin 0 -> 1763 bytes projectBuilder.xml | 18 + src/org/json/CDL.java | 284 ++++ src/org/json/Cookie.java | 169 ++ src/org/json/CookieList.java | 89 ++ src/org/json/HTTP.java | 164 ++ src/org/json/HTTPTokener.java | 77 + src/org/json/JSONArray.java | 1200 ++++++++++++++ src/org/json/JSONException.java | 45 + src/org/json/JSONML.java | 552 +++++++ src/org/json/JSONObject.java | 1938 +++++++++++++++++++++++ src/org/json/JSONPointer.java | 267 ++++ src/org/json/JSONPointerException.java | 45 + src/org/json/JSONString.java | 18 + src/org/json/JSONStringer.java | 78 + src/org/json/JSONTokener.java | 475 ++++++ src/org/json/JSONWriter.java | 326 ++++ src/org/json/Property.java | 72 + src/org/json/XML.java | 621 ++++++++ src/org/json/XMLTokener.java | 365 +++++ src/sig/ReadFile.java | 378 +++++ src/sig/utils/DebugUtils.java | 17 + src/sig/utils/DrawUtils.java | 146 ++ src/sig/utils/FileUtils.java | 348 ++++ src/sig/utils/GithubUtils.java | 35 + src/sig/utils/JavaUtils.java | 48 + src/sig/utils/MemoryUtils.java | 37 + src/sig/utils/ReflectUtils.java | 10 + src/sig/utils/SoundUtils.java | 30 + src/sig/utils/TextUtils.java | 137 ++ src/sig/utils/TimeUtils.java | 32 + 65 files changed, 8022 insertions(+) create mode 100644 RandomizeRabiEnemies.bat create mode 100644 RandomizeRabiEnemies.jar create mode 100644 bin/org/json/CDL.class create mode 100644 bin/org/json/Cookie.class create mode 100644 bin/org/json/CookieList.class create mode 100644 bin/org/json/HTTP.class create mode 100644 bin/org/json/HTTPTokener.class create mode 100644 bin/org/json/JSONArray.class create mode 100644 bin/org/json/JSONException.class create mode 100644 bin/org/json/JSONML.class create mode 100644 bin/org/json/JSONObject$Null.class create mode 100644 bin/org/json/JSONObject.class create mode 100644 bin/org/json/JSONPointer$Builder.class create mode 100644 bin/org/json/JSONPointer.class create mode 100644 bin/org/json/JSONPointerException.class create mode 100644 bin/org/json/JSONString.class create mode 100644 bin/org/json/JSONStringer.class create mode 100644 bin/org/json/JSONTokener.class create mode 100644 bin/org/json/JSONWriter.class create mode 100644 bin/org/json/Property.class create mode 100644 bin/org/json/XML$1$1.class create mode 100644 bin/org/json/XML$1.class create mode 100644 bin/org/json/XML.class create mode 100644 bin/org/json/XMLTokener.class create mode 100644 bin/sig/ReadFile.class create mode 100644 bin/sig/utils/DebugUtils.class create mode 100644 bin/sig/utils/DrawUtils.class create mode 100644 bin/sig/utils/FileUtils.class create mode 100644 bin/sig/utils/GithubUtils.class create mode 100644 bin/sig/utils/JavaUtils.class create mode 100644 bin/sig/utils/MemoryUtils.class create mode 100644 bin/sig/utils/ReflectUtils.class create mode 100644 bin/sig/utils/SoundUtils.class create mode 100644 bin/sig/utils/TextUtils.class create mode 100644 bin/sig/utils/TimeUtils.class create mode 100644 projectBuilder.xml create mode 100644 src/org/json/CDL.java create mode 100644 src/org/json/Cookie.java create mode 100644 src/org/json/CookieList.java create mode 100644 src/org/json/HTTP.java create mode 100644 src/org/json/HTTPTokener.java create mode 100644 src/org/json/JSONArray.java create mode 100644 src/org/json/JSONException.java create mode 100644 src/org/json/JSONML.java create mode 100644 src/org/json/JSONObject.java create mode 100644 src/org/json/JSONPointer.java create mode 100644 src/org/json/JSONPointerException.java create mode 100644 src/org/json/JSONString.java create mode 100644 src/org/json/JSONStringer.java create mode 100644 src/org/json/JSONTokener.java create mode 100644 src/org/json/JSONWriter.java create mode 100644 src/org/json/Property.java create mode 100644 src/org/json/XML.java create mode 100644 src/org/json/XMLTokener.java create mode 100644 src/sig/ReadFile.java create mode 100644 src/sig/utils/DebugUtils.java create mode 100644 src/sig/utils/DrawUtils.java create mode 100644 src/sig/utils/FileUtils.java create mode 100644 src/sig/utils/GithubUtils.java create mode 100644 src/sig/utils/JavaUtils.java create mode 100644 src/sig/utils/MemoryUtils.java create mode 100644 src/sig/utils/ReflectUtils.java create mode 100644 src/sig/utils/SoundUtils.java create mode 100644 src/sig/utils/TextUtils.java create mode 100644 src/sig/utils/TimeUtils.java diff --git a/RandomizeRabiEnemies.bat b/RandomizeRabiEnemies.bat new file mode 100644 index 0000000..7a0a784 --- /dev/null +++ b/RandomizeRabiEnemies.bat @@ -0,0 +1 @@ +java -jar .\RandomizeRabiEnemies.jar area*.json \ No newline at end of file diff --git a/RandomizeRabiEnemies.jar b/RandomizeRabiEnemies.jar new file mode 100644 index 0000000000000000000000000000000000000000..1fe441009bc577dd09c9806d9198e8cd4d2e53a8 GIT binary patch literal 76519 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 NTo4}80<$LQe*omcQ@Q{E literal 0 HcmV?d00001 diff --git a/bin/org/json/CDL.class b/bin/org/json/CDL.class new file mode 100644 index 0000000000000000000000000000000000000000..f96910c5d3c7471b18dd2784621737bef43ba5e5 GIT binary patch literal 4450 zcmZ`+TX0j?625pWI}>E7tb7}tgBmmfaXeWsC=*zpiz}Dr9=cG0^%}ea6?qe~v2|2p1B;3q<1CdGwrSYNV5>LW zJ9hlIk#xa_5*aa|<33rttv@<&QbSOnvT#LgWY9=DQ6u2(jHOacJ2)_sNEyM?V~Mm8 ztaD)#HcJpc%Ng~BH8%9h8Ff19(LfraqoYQAP@t;5tq_pCV`{e+C&B`jx-D{Lqg=T~ zps`r&g6)ZyyO*&!XP4wyuH*JwnY}4@&ngvQz=i=$;`2J)vkrap&-7}AY z97PP{!*-eM=LP)5tCQ%fd0U;>DFC_iZXFL}50R1N^&}*SMUbIX#5fr(E-gMB;HQnB z(*!QnFR-BqG-`VRcXyh6cSc9EnqHGkob5?Sy|pHj(Q~Toyc(AkoOfHzZqd-eUMYOw z!a=DrfkQghV6D77qT?vKS?Y)pA4;E4N^N)HaU9XWo?OwjCSP*R7jzuM6P!9aMrqft zB*biO_Eq8LRL~dM(|e1mQIk%$NRs!}jX6Kg`U{2cB=FnZTqSjRgVd9t{`W}#HOO~*n)X|Q|Bt)ll#6jWc zX+`4FHsPY%tU@arkTt}krwn=!RbQTm=Tf**RmV~zk%+umW(|cvQtg|h3=ZO~j&V?2 z*2E}@^yZ_UtILY5QV?I!@l`x4pvB^Y#`vM*^e8S+TKSreuj3mOktDX2q2v=P-&X+s z5{c}J7(eY?lgOS1E1Akc;7BP~=G0*tfeB`|Bl2`-Vo+RnvZFUkdcLRQ1xb&<%W`yC zU{6uV@?pFO?IyYcJBx={ZQA!rP2g1>CqOVP!_sK-_s(%}5U=aFifeQVawUDid_+@` ztmW~ZTXY)Nb&TRodK5i2Z;qM0gkn-h3Ta93w2rs%HVIa(BMGi8+S&!B$uRFqV}I|S za1`0Rs4!3ChNR~G!XtZ0%|#+fm%k~k*ke9`YdO8IJWW0 zIvGYh#j%ZdJ`ByGe5cJ^?O{CDDivTQwW6aVAHX(>Rb3s)hueuI4d%X zrdd4r(?J_`MI0 z;s84F2+x#uJV}Rn1|8_fAtZ4aFY@jy*pDBe2iMSx3G`u_C&{~bLLnD2F+nT#GQJ%d z#@t8D_VD?Bjx3CRl<^;79*=THC9|1Fix3Ma5gL5HwLa%v*c>R4E?fY5br$qz@8BRo z>+A^KMpviAYjy87Vpwx@WV{Ir(gmk!cn<&G|#bq6{Mn zP7^vWobzyMIJkgn4UY?9cX~w)fuj?x22L%P%}^e`jp0sWRT^P2BN@KcFN?y(Wnkyp z@m-ZsQ1wqa^EY^(i&bv2m)5Au=#9cZUX0hHu?Pgb%Z%`sZljYZZ)d(*{o`? zMhz}_YNpU0_SDFLDnPT{+U&?+v(M&r%;G|`=G8pGX{_UqY^tzVlT$A`gxBG@hyCt9M$vtc~WfSE)TK2o+Cpkgz+7Y9Nf{XRHG@js!_54 zw}wr^wSaaFR!V097Keu2`XAaBjZ7?lhI1pz{C7pS{;fCm7AH9vOOUad!-<;R@Nt+L291E+=3c~$H zgeNp{tQ3Y2KsVd-q{GO*C7kD^+N^e+1qp+ytP2XtBYS)1V zl_+1?safeIrf)dGgd0uI;A=-gn!jX{cJ8xp75wV7?6mIAAQ+}WUy-&khjkI3jXj%T z?z8xy@1j)%xacgRmV1S x{~QVXR7HHj<2!^r!YuTGdex0q(o(Lfw5cw0!(PfGjYRl_Pb&R~EX0Bz{U5m2)#U&H literal 0 HcmV?d00001 diff --git a/bin/org/json/Cookie.class b/bin/org/json/Cookie.class new file mode 100644 index 0000000000000000000000000000000000000000..d2dbe9ba6bcc6c0b335a541e93ee9731411b3f4c GIT binary patch literal 3154 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 literal 0 HcmV?d00001 diff --git a/bin/org/json/HTTPTokener.class b/bin/org/json/HTTPTokener.class new file mode 100644 index 0000000000000000000000000000000000000000..1498ff3119cfeaed71968f51b53d40a861307e15 GIT binary patch literal 1106 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 OAAy30Kei3}pZ^9Rb-oq= literal 0 HcmV?d00001 diff --git a/bin/org/json/JSONException.class b/bin/org/json/JSONException.class new file mode 100644 index 0000000000000000000000000000000000000000..6562934d6b97370235042601ad6e044cfbd07581 GIT binary patch literal 772 zcmZvZPfr?A6vfX)VC;xhkwK-l1>L~V$i^Lph1w<>w24^uPx>-G0&mRx(S9vAHF4nw z@Iy7dZyXVoS=^U<=iJ{p^XBp2{R4nqY+J|>%6{OrhM})p$GxAY-~SBcRiu1vAxo$X z#kFXSg!Wozv5wSOPTmuiLm4PB>dPQx{jZ}#0v!_;4}2X)LPvcuie-+Sl82DrQ(8qG zf>ZClaC=dpwAXI*3E2bxx3n>bj|JFRAS`v2mZ$OfLI&sJVk8O0u0LQ)!N%OD!)$b^ zLc)4?_LsB?)>ww2@Dji~Yl1r?&{V|p%fP=eew@<8TQl(-LT(`9keSX*EeD#$zJ_e# zi-pgG)t59AK>=S;CD@*fPM%|z>WwLr^v+n*^W$J3f2ibcUj4rvLq-k6fx)$c9P)fx z++{G&Q(ngc*8)#EJj?Kzcbj)uyiGJqTG2fA0d_Z$5rad9s M3D3l=F(HGk|1(mWqW}N^ literal 0 HcmV?d00001 diff --git a/bin/org/json/JSONML.class b/bin/org/json/JSONML.class new file mode 100644 index 0000000000000000000000000000000000000000..aeeb0669a4a4af36d9d286675fcc4b2838f9dda9 GIT binary patch literal 7376 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 ak~qmESX9)yi)$5^ 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 literal 0 HcmV?d00001 diff --git a/bin/org/json/JSONPointer$Builder.class b/bin/org/json/JSONPointer$Builder.class new file mode 100644 index 0000000000000000000000000000000000000000..ce00912d2e740d55813ccf91c9e8623a87f9ad22 GIT binary patch literal 1233 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 N;&@Qa|9?l-{{fR*+T#EK literal 0 HcmV?d00001 diff --git a/bin/org/json/JSONPointerException.class b/bin/org/json/JSONPointerException.class new file mode 100644 index 0000000000000000000000000000000000000000..781217bcf92df6c50c705e72e433ec5abfb5eed2 GIT binary patch literal 611 zcmZvYO-=$q5QSeMFa$&p1^=VQ#Gk>)#+}9uYN8=(0SKoWxpWp8v01mP0AVgR*UZc?RjV@f4udi;5(t-5Op6c>GP)0il z6LNnfqkn|7FFhsNRq6Sxy}dXk&?O;RG};e@4yvNvm67MIn45fi`65J*l~%zCA-h{@ zi3d?=3*9J`15fG3(O#7hE}A2?*|lT)&c5nx1*Iwj9=`T(Bv#gh*X3Vf}uIvStCcX244TDV(Q^9o^5k&cPxCoJFUW>{8s$hu%h>*=`p{T_1TFqfC|eb~l8Hi9`r7_VXxOKfFh H+qf$~lzW7U literal 0 HcmV?d00001 diff --git a/bin/org/json/JSONString.class b/bin/org/json/JSONString.class new file mode 100644 index 0000000000000000000000000000000000000000..41b164a954a7aefb834e79005f733289606a1d80 GIT binary patch literal 156 zcmX^0Z`VEs1_l!bPId++Mh4;hqICVN;`}^)uV8<_;F6-uymWR37Dfhvti-ZJ{hY+S zbbbG%tkmQZMh2dee1sxK1`!QSAA}-^R%=EEuHgLAqU2P!%$!t427ZJFJ&;;9Mg~R( YW}y8H42(caSQ*$rECzNU$;7|`0GDAVBLDyZ literal 0 HcmV?d00001 diff --git a/bin/org/json/JSONStringer.class b/bin/org/json/JSONStringer.class new file mode 100644 index 0000000000000000000000000000000000000000..783d607409d99fe51c4e54a216151357b437c503 GIT binary patch literal 616 zcmY*X%TB^T6g>lIu@pfbBEInzaA7yD#25&P3sYfHqj6baf`izSQuKG+xz)sIqKO~i zM;Y(X8p~#S@0rsx=ggh&pN}s9huBjPVaPjfPw$T$TR$^fP1AFQ-Q%u;7(;ey>&g`# zcNu1ng)O`jhG@BR$q;KeU9Mn`A=kI=EnPUeFXHo6#F5Z2gIN_(BxN}3kfo045woaE-hEcJ^*9hjTkW$j46|U{;Lde&+$8Q zR<4B3^U>-Y7#1}YutXv5CLvY|JDM!$mI8F($e|e*YEuboUWSDvEDdd!k41 fOynq}pga~ZLSp$qtVB4yrEE>X7Lj(SjbQf|^#p)z literal 0 HcmV?d00001 diff --git a/bin/org/json/JSONTokener.class b/bin/org/json/JSONTokener.class new file mode 100644 index 0000000000000000000000000000000000000000..5bd21b76a8701fca5ad776c3d28954ab95bd265e GIT binary patch literal 6401 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 literal 0 HcmV?d00001 diff --git a/bin/org/json/Property.class b/bin/org/json/Property.class new file mode 100644 index 0000000000000000000000000000000000000000..a07c92de9205352e5e4d21f29f044e6a73bb5886 GIT binary patch literal 1747 zcmZ`(-Ez}L6#h0b2s;V^?2WJj!Ao?e(C^4nq!4qntKB_&&iQ_{??3+aH-JSvF)*ZX)b+MX+a1>_ zJ@nkR_WYiKl){m1>vyZvw4ANd`sTK7_zDM?Y{&MO6^3W>8w#lv_cxuvFw!Ot;Gn`- z)pm5P+uGFLV{5ai6^>QihSl7#JX_Y`X3BqRcNDVKeTB;krtjXbuh*iI#hGf*N7uKT zQGd4Xl=JcBIGoormFErJ_HEbc7&xYIe7A;#?H(G)v4K5j{fZf6khL^v?}0%F&2f+%~a-JM8zF?g=lE_`!vHzBtMCXrxvAXy7gZ z#YT!wP23X~rNl*&@_~t}I3i6)#6GEs%;9IOZ+fk{%wJ_$l}~sBVqr z=+*>fQ9~pv`CmudONla}|Af~}-R*h}y=u#gG8$6ao0t0Z6Mf0Y3>=lbLL3dQN}Ltv z1BF*O^pYP#$Z(Wn@ShstX!Zj*k8+j9VT>{A2)|Q2IU1yS$L|z(%5RYU%VO5f_?(bktU_BfRYnfGUu$7x+ z?iO;m&8Kh$d46A_En--U0T_Wb7XTEdrx;mhcc=Hk>YqJM!pa#KH?SJOQuvu@hp_QK DO|78d literal 0 HcmV?d00001 diff --git a/bin/org/json/XML$1$1.class b/bin/org/json/XML$1$1.class new file mode 100644 index 0000000000000000000000000000000000000000..7cedf61f5291d1198574e04a141be2a696afd90d GIT binary patch literal 1377 zcmZuxU31e`5Ixs+BF8APNs1{AAAvf>76B9bU8kYJBvh@F(1vCTEi)*}t*umCc_cZL z-_vIv$_xn|m?`i5QB2R36>I~VvF~c{?%A`u$Num2i+=%phL(YhKq&~@^}Q%i^PT-UfUMPHG^F_ z0m7Lm;Dok5Fkxb{fGo-;rf^yyTdi&Dn=>X1LQ`Oo~pSFr+TZRqI_=<@ITopLsvf;adr{WdH=c;ziE}#xB@VdavV5H5C6FM&U zW#Wd;n{er920axQsDdvHd@gWu5T2GY@g=?@TP~_6H~$bQv%q^8aZ{m;dOj)8cpU6Y z14{yz2Y|n*sMqZVVJvqyyIM6~pjHoD+0{k?4V1a5k#75vW3vL^nW&;h!E6P+(3NYR zo_U^9y`~GWnJuraoVXX#-58>mLi9Z&id`CtIv(pX_flL{t{+5HP zHDTii*7x41zkE!5qz2(kTPYbfeJ6@!ggLg7I znL?4#C0ai-F3a<*b>$Ezt%XC(SkH0F${ylFYvBkV9pb`M-e+);-_yhg?lS);%rJMB z_9c2uq7efhqr#IvDtwaS-(se|D_YM8_zV~R!dUJ}_6c3t1adsN-X4M}rZAV27%|BJ z?kL53z_bi6&J$}!V;;d;vhLHE{Rh_`ku}dx|7Jv=@l?{?Z)Es8&fsBErrbwJ%b4uy zYfg%PFZc$h(>ga&-uahk+<%U5U%f%>6W$pjobMx*R>*TX&7V*3IBn|)HwSe3$s$SC gZRD_$0N+A0Id5Y%@vh-}{77q>G}d_PM~{)u|3zpLS^xk5 literal 0 HcmV?d00001 diff --git a/bin/org/json/XML$1.class b/bin/org/json/XML$1.class new file mode 100644 index 0000000000000000000000000000000000000000..7858d66661ac64e12541652e17cde29f3e9a7a0a GIT binary patch literal 829 zcmZuv?`zXQ7=EseO&im#i#n}8r*@ikU>FE~=-8K`P)K!98S`VB9odz5fy;G&mx3}- z@DK2h65qSFG}8v|a`)uP`#$gcyubha_yyoKLKiiLjY4J7v@B$FHi~-(E*yr=G`UQo zJds)SVKU{ZcF|x6R_IW3l}vKZ;9VwpuhdG&j2Q8XGPc-&p>Zgr&_@h+!v8<-oiaGb z#W`<*q3y#((?cDbK3eE7)I&qqjD_UyXP+lreVk_v;v!A*(?kh#Ux1Fj5G9F^uUAA8 zn!@PSg<{wa_vR{QTI7+fgK*-s#v+r6o+&D7e=X^-B7Z0~&$t>K4P4x(oYzzK4m@=6 z&=m2AVK@9&Q6io+`?_T(G+2u{<}-(8t&Oh zZ{S!?`zN}e`u%V4ukhfDC9Hy-RD!h^!5loctS5_bJ9tWW2hY&MOF9LV!U!=>cmDbd DGy%OO literal 0 HcmV?d00001 diff --git a/bin/org/json/XML.class b/bin/org/json/XML.class new file mode 100644 index 0000000000000000000000000000000000000000..18a42b59c61cca6c573f4cb22569babb4a8271f8 GIT binary patch literal 9320 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 V4S;z8 literal 0 HcmV?d00001 diff --git a/bin/sig/utils/DebugUtils.class b/bin/sig/utils/DebugUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..30f9fd36b922f353c30ba0bfce2395a52eda0fbc GIT binary patch literal 1384 zcmaJ=+foxj5IvIwHdz*fK)8$Xo&+I^C`teo6b&SR27)M3wS+NQ-0b3JBjvk4;*+o9 zL!h+E5AX~87pu^oi7_CQ*-Fp$Y|rU)x_iDKeE9}o1nUYs4DBT&A1}LxS&Bd48|D16 zcvawIXxY-=>Ty%I^6`a@EuM238pjRGa3>kOk!Y5|H*Ifn6l{2ZD=PtcA40PQj)P@#}^&Lax<>O^Z>Ob(X0xFGaCAFmZ3S%DMO7S)iDx1endc?({LUaD2u+m&8 z6Pm6wgd@=xM~KwqJv4cdTW-RS8`RP?4MDghw1-{MA7{*un+!}ZQ`WUgUm^(>RTVV=;j-so|~&X`+xB!{pV7`_$)HEGz=1H9V*_A0-h*Xq>-!(O6zVx!&77k ztY}ya4UuFrnq*LAO=L+J`u|@^IwhkSx{p-+&}`C0U5{ z)ZfDs6d``ypAr0u&}wVv9=i9@S3$Ufixpg{1F8fpV7n-*02N+9TpR)yJbnV$ zuCDH3sDk*Mgd8Twly~AIW(TA{LVm1oxPn`hr8PlDdK1FCSM#QX_ps(Ys$fp?39r2O zu)Y>G_H7^YAAao)(C#Nn>Xn*%h#u&ziJlOt?IFGEw3-M?%3+FY!YeFcnc_lNLl!GU gzmxoDSS3l%X+H?h0eTd?P!M82F+%}swC%ym-_5o;pa1{> literal 0 HcmV?d00001 diff --git a/bin/sig/utils/DrawUtils.class b/bin/sig/utils/DrawUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..d20a00f595285bf3723cda37292918ef9dc49822 GIT binary patch literal 8107 zcmbVR349dSef}OgM!OmbA+%Uyj3W#-I)Jsnr{vh^W_5I(>&dwsRY54s# z`{vD?|NH*m|D4Aczw`NL0oQCj~V}x=SE^ zO~~XdRS^DsHMLHB$anY6rE4}UN%U5#qb|Q1G zxWZU)ayffW+ofb(j|+tp*QNjWt9`xbc#@`%pGgx2X)o&I&xLU-b{M#=%=uh+CR))( z4@^1fx%|BLz?gv!g&VaZ!b7wtPpi%><(-84P8jXjC9b)f&gSV>Zv7B$#~uTn3Y&fA z1!h$I&KGB5FT(|ugQJJW6}FUUUc0ng_Poo)-MEMB+lhoPL}Ac_a0S-Bc{^*z^G-I# zKRchvZuj5uJU9@8^jN{%WujXk83zZB9Eu$plDSu#xE~MDC%n0nqlbKV(-LCoyff!y zyJc~YiCz&t|EtHIBI}g zZ}6>B3>Fg;IL2*rPF_1XRSbBo>-TLF2B!F6&C7fG!Rzp+;Z+ZvD{LS)?Pc8 zj1z6<3=2&j=Omh$5-VE=C3R2Y5fiV&>lH#2>Mj!mCAHi+o#!WUG=#_SCIfF&xWU)S zWuC=ge=?oVnRpyOK+iomFmp?=B1b@>jMWbe0(skKxTG&f^KzyosLS zqXVVabs#nd*mujRCgm+A-io(zL*g$JtFR}aM%kmB-f^uwmyx%dSP_~lrHV>6dWVT0 z!aEgeX{BO{QD`f=;VWe$4fEY5-h=nj(jwG#9)+DAz*m$Ii%GX&Je--GrJ5Wq7f0)C zBE88~m5WS#7OTvtbdO`ngjZYptM}<-F6sQ!D44h?YeHPJ-$~BR6In=@_F56$ zhPbfHIKFZ#;!*f{6F-5i+)y|ZE)==~u3j`R8@iIBZeDlqgH%Yq_yYST?Hu~SKsKAn z*5H>E4jxTsom?h$)=9L)GYgAJGMvn$TNbk!mZF8OmT+if`LLaKQY~>iozCQ2W}FuP zjeMrXZaM4qt>G}9!!8!|B4pP%v8%x@f!5Z!J}so;y_*ggcRRT{*=N6Fr}FbNc2=SL zzyA$nobkHg)Q8(cbEk{jNifU8TeghFMpLU*2M3N^($%p zNm=-ZCjO{6F(nfhdf7<8^9U5`bs)xVbe71fo5L`3mS`mB?c>cS#1p3&SX zY`;oi2FjjZ)m?*cuutD9ZS6mqcoF|BIc71Hq}XDwQMT)ewH_YEzvABw{9CaX((AoW z&cuJU8Bp5h4Ekb9|QkgbO9}6#Lmx~_+R`V*|le+V6?{C^wMvc_%^=7 z>4jvPfN4CLe}Vj?N-1VRF{c>w1yvza{8luyh3RanTGbfJpm9neIkue3I}4@?sW64I z>G#ulG7~*aR)t%~Ug$QIS**+fT6&j~DK=0ws-9KrSdZ>^x3qcjCPL_Vn*2qw|vIzTO?=I?Hnw^zmrWc3R4%KF;)}jN6Ed7AB zL$$O127tM*>!+nXVj^KDtB7h3tL;n=yhKfPyW*Euz1Pip-}Ur>BB#O6eO=5Z)m~HG zqV7=G8`x3r)g27$t714FQg^9)40U(W$3%QjYH{A~V|B>nl6l8e_o^7mX#TrsaBu9 z=$*#cmpBZV$$&n7buR7ZqUz_r(wv+AO7~Yoq|1RiEC%H_;hlj^T!~UMUO~cfrl*J9 z(~zoV_qR5wv$Y1Ga7#d{i)l@cmNa(ERFnF2ffeqElaQ(7raB>0(iRP69Vac5)24bz zCJj#Z@)MS^%kDEgrcE%IlmoB&e#Wcr?siK=(K%x2G(Z1Rb}r}S3`IUmM-6M+dYXx! z6Na1=MRi0<5egh^yv$*Nq4;Td>vg?E7xK>-u$4Vog>LrhIpR4UuLkd<{8jv|YQKn@ z&vLMiy&&{sU=wONHr)mMt>ayYr)cZFm!ITFRyVbGv^H1P*H=cWEyJp@LYL4`k`<;* zpcxxsX?aIbBk%COiN7+6a3=xLgd4a{RyT2NGb;7yMrvDR;=_vgup&OJ2yXFUMX-${**KyB z3ap3*=*km-VS?r1qYH3dimNvPYJ*i@!1fQS+RJF4vg$8lXV-db{VJjz1>7lvdslIv zH{7?1K5sbGgael_%)550u7D%$U%+HngVn&dju-Gy*M<&DOHOn(T8*vE)$x_{&6UkH z{3+mc*G8*B6|iVETt5{}eX&7V4d5oZfnwi-m-C% zTKXzS@8^iFz>zo#ql6=I6uKHm;>o5Si6=9zI46!$&z-)F58#LC!^8L$>hPmzpq4*} zAEPcCsOx9&Av{A=OMLcWe1z*)@en@Bxh86N03YLA1V2vps-Rw?A|d$@^Fre?#d2Fj zt#HRB{A5?H4iT%ifKQ!k!p~%6^f^7cM$pvjByvABdw}fj(;Urei$#kZk?mqUM~fVB zt{BfzT=D`Z3W;nt2?-w(I8i@vqM8p0oE_Bu^V~@kDQ2GYyqC<=s1*q0oy%9|onErm zr*XP@r_smR=;LhkaW?um8#Ow~JB@zcY4r0>qedrr=NIs-M{Ya05pBYk@!VA7FJ8ni zKgYXZJ{{6HB)^4d+h6tG`&n8_Qbng_NIF1=P6vjhgBq*GO9$;%wS>A=BSEv$T)9%f z^QCaPQ76a|l68pcjS}!-y4`E&^kaI<{Tf)OuX?AidZ({?r>}Y^evRf3)jPGC2H)GF zow7zdRt41UMEvXc4NrrQP<$1aA82327X>C$(QmKt@&|JHvRwXnrLurOX}5Uw9#@{y z3-r&IThFXiCfsESF8TA46*pQ(CQdT_FzmY8}8=@mIt|B#dsi zk{rO_5PT)^ehq)?;eDP&iMRD?rmKYMYOC63S}t9>g_P*ZX>Xti8SodTD~qy6W}P1eScR>-c+DC$*CdiD!MXz40Fk_{ZUnXRDvVJ(uyqR7b_0OZb;d z_|Faa?j^j`QCWUlRd#z3-@VZBtnmzn{@<^5RF_Lq>n^OSs>`Z&YNM*VsMfa^RKrHq z#A`uqDySRP1;TaHeJ_(7FiREYm<;C`vPmj=n(5#S|GQ(JBrIS*kD-T=!3iw#$!oF9 zgXSkW_Y_ZzKf!b;HGGpxfs#}TO8XdIR4pV((qS#ueG9#Y+WHdxC&Yeqo97KL($yuG zOkY;pr#fh8b(_9+R9#fNBm@g;cUQ;?byQTSg4%P;3azR;3#!`+NlZR!g(@n7Zxz%7 zR;ZwQ8LK)_Mc}}(l0)C7gZ&X=eH|V1^-OP%QqMQwE*>t&@J2@Po7jsy9&nmz-)W}R zpc*1UCCFRId}&OK*wlby{^(tKM9_(p0daN2t-t)AnK8HiawMdPedC&x zTJAfdNijJ;s7a|KDdXy>=MN+F2cdYIL;z!kemjwHf2X|P2j%x79h}R83H}`#wA(Om fQzy9rpQ}^)YO5LkHu64>$COhUQnPAaokr+;-YUS0 literal 0 HcmV?d00001 diff --git a/bin/sig/utils/FileUtils.class b/bin/sig/utils/FileUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..fb2c170fd780b4b289eb133718ff83bfb78657fa GIT binary patch literal 9244 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 Kw6kaz!S4TMS*LaY literal 0 HcmV?d00001 diff --git a/bin/sig/utils/JavaUtils.class b/bin/sig/utils/JavaUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..ab11d652f550b0690bcaa183c6118f0fa9cc72a3 GIT binary patch literal 2341 zcmai0OH&(15dKE574l**Mt}$yjBPCO5+;N=Jj2tmBftiXgPqqREn@K^sic*i^A(dSGi$cEH6+*(IQou}4Pxm)H-Cxi0_rI?X0Sx1@0++zW zoRN&?EyK)3?`Ti7`%+Ti5vbqcGHPn6WOR9RM~_@TR9d$6Iv8BGrm(>Dne)#xIq6oJ#K1QJ+WZu zW`aO%;mD&hq^!PWG6hk4n}}_=q@Z1(>EsG4j)|Q>6&>glIA`Q$yyJ;(Eq1(kT^DyZo7~k+N1TE&g~dtHnu;8xmtkpz~df zcwEorN(kguN`IP3GxK6gAXFAoMG{C4L26tr+dnHPns!w&t2~!RwRXUZTE=Fl0;*ci zEm(DZYw-hW? z^qu3X;uGAa&wi}{}sO&h&=04*_ko+T6x)v`;m1&mYC15G`y?g9#&WeEtAnx z34#7<9%cEgxE4EN5^E~PF(D~8Aj@wcHV#l9>nY$u0l|$?@8O8YJ-LU$khgtkvF{b$`w5r(di!W_ zxq$0?XdLy0dc@Z&)lLt=y`thws)UFbYl?jv&rQ=!A5o4VfEOf0zZE`P{ZAG z+*k1dLz`e=Qw(j6dy9N|W$44a0>h()4Bd}g#H?lT9ek{Y>E+^|7bEzP7oM`Eo0LAH z?L53kXoXLK;4cKnQQ!zI$0`L~j*>flw-wwtqUR}d7d^>2CtEHzv*joB+c%hGwmy#a zO2J9l^efCA;7-G00m}ufa(v*PC}q=kIO27Wc=qsP$QSesEw%lODciZffcr(yb^7!> z>HVyT;F;LN-BBf^*m+)Xq`^Im+rABtc%THJV?z~hS)*g$K+*S^M+7}V@AISYdKfeco#xJJ@Bp zNV7Ok(TQ(K+3#_M2-k?wjTg91q%dCcbMcyff1)4%V8AZ(ij&t;ng7C9_?lS{<5y_d zWSOUlCkyT-zEg088Y$f*gI|<%FH1T}f_v~EVGN2*0{&l7V!@4)?j0J`B+K}4+S64( mO_s(PP=fHX6Lq_Ru2FKjuz=(~x5~SaA8K18d(W_?o&NxV6$vN+ literal 0 HcmV?d00001 diff --git a/bin/sig/utils/MemoryUtils.class b/bin/sig/utils/MemoryUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..36c327bde143bfd346e463c4cef905630c1eeb98 GIT binary patch literal 1150 zcmcgrO>fgc5Pj>WO>GKELrXa>x6%WafD^5d3MoRuq^O_bxON7!m9rbI9ZUIHoGO6? zcYXuE1u;%S!yz^0!ew`7=gr%BqkZ3he*OyJDegDn32f#%4M&B}^6)JUtQ((J=O!8g z?F&_^FjFQC5913;3W1e9ZFKQmU}^i|nLy*E?Nfjy_-k0kia;yUhI*qxOzuR*83}YE zo2cweIbFrG%SQ20=K@>N!pC<7Hpo=)F2$qtoztbxD5WOa{KCAc1Lv$;MMro)PK~47 zW+nAyVh2N=sX|*Lht4v~Ab%zU|Mh;a8y&nDAJGSLWD=5zGR77%CV5p{SgB+&9@4+# z_xq(9>L-sE&<6e+a)z>NlIPm=P8O8ONjK$ebb)_UT#v<a0p10J8)sk}Bh3V9d2FYjDp_0uFB@LHvT0JnHun*w;h&5@5g jSH(Ls%HRuH?>p<4xciL}9@qV5XipeCjs@;ba$COu8(C5z literal 0 HcmV?d00001 diff --git a/bin/sig/utils/ReflectUtils.class b/bin/sig/utils/ReflectUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..c0a41ac904f8077165230ae0d6a241ca908d1c21 GIT binary patch literal 542 zcmZ`#O;5r=5PeHq3Z=-0%7@^=8*s1}ZxAmeBql`@Q4ZcpyWnDJOEW~#|o#I=L}^#bRB=}L_*?i zQBCee%uuucpWbE2iMa2F0pEx;TlTM)Xyelw2=05`_ML$e_H~pQsymuY9N>__obhBB zdSWVgMAK=73kEi2sP9y#6&ImL&5T;}qr`C^hR)-53u6>6BbN_^+_Uuee5cX~PC!HG z)*g_#9h-eW-1c#Xd4_sz^Oxsw4X_9GD2fm1BUJ!J~ z5AdVJbxtd2jXIe*`&{;3XJzeu_P6h!zXDjm8x1jmp1>{}wa|6~W7n&>rF}Wo5En=t znjcNWG2ODUQ#iDWp}>u0+qJ_LftGaUKp?*6m8=9>(5|BuHw2P-+qJf9m4a2>GYgI- z(3SU!rgLCcZMkl2#>4k^AkdeOx;rP(?mOnOVk6L-&R_G`4Xd_W&SefX+!D~$f$bR^ zwnG{zbW0jZIqTKYhub7nw!+my;5oI>l3x6)bfym2h|47~fFTWo0;3Y|$OxniMqpNa z$0`}CwUX`a9tWXS(J_n>fo_Q@cQ;+X7Lt->RsCkE7{`4L69WBFgr$#;NjzYFJl}E!GIeUrV9ozPStWEv$CS)vYY>{% zFo7&)HOvTPqb`&A-ghaR?a2JD9~CV>v^`gcq3XeBz9^Ad{IFLwi%im-M0+GK7lpR( z1~uRJs-aa<;=*SC+OdvIm7e` zQd`+GJUl_0wDYF~Nb)_6vv7elrde{*&a-@4Ac@Q>3Q2l(p_|_zdg$Ma3AT(h`WZJs z??L(xVF@G3dxi8#3X6C`n`9$c;)H=X(TbWg|X}i>>$9ww&aDlj+5A6VjElp1}E6y*eqcz4f0@Z8I251 zouv&SZPU^{ZI%)sZQO;lX?u<#<(&5S{+K_fO-sKwGx7p*d)i-~-g|T3UB3I>`=0*x zuRs3}Z#*ZXq+!zP3*5`E2(| zy3Qande5N&1zYLmnuf!snK%8|CSm`noT(S{nFT!+P3E%&gZ7PlE?O}2bUfQ14F>3K z;^as)spWEcD>|!3%Ljr%gb)@OG%%_P9tyBjQ!iw+q&{kxMFw)Tg4kxE**S27b)#Fq z6~uNlDcG?gWsbOtW;`xIF>)#W%J{`iyh{iTQ5CzeTSA~%nl0M6OK50IBsMYFqT&hc zB_%R?E^W=(lt?IOlhC*Zuj9mU$;hO1Qy7VJKU>%)Lh@fDTie@cSi$~*EB>f0)W$($AQB{Qj);i!8w zK@x%&32s@U+D&qK?J49*bSXi93x=N5h2!?5M?&?4r6uQ&YX!F|YK-DgrZA`FN?F}B zlAGje#*bkM+s~iTI$s&;oY~j;?5?w&T?bot_jjC)N6*Du1k8t29L95mIjdR8Ih`(e z=n->k6j_}@yC3way7S=KRJ`qM7svL4_UA;-($hLc8!Et>XrB?4uSm3DohAqiiL~-tF_YkGmkjTwpWr+V}mc+ zq^&oI%UD!Ec(<-)#ZAA8S47+J7c{e|b1w)BOQOHM%G|OiBt%2=B=Z@jw1PRFoHEI4 zUMCWIEBNSmxZ1G~xiO1dsC&#PTD$}T6Gl3xStXO`9r-_0?0*!6LE`XMnS{2jA=A_r zg~1@M3aUu>rivQW2JvltN5MPH{win>-z6%(i|dS(37;}jZU;Q%$M>16s8IDo6+gm{ zSxLjDuFVTDhO84D$zXA_NErR^VL3sp;Zlj_TktM^rr@XL46jP7cn|M0Pg;u1-f%6I z`|OM$Z!yg}y=dRAwGSnROuOvFCLN;sltJEUi^uh1QA;x~p@-dLH#D`&+4A>*#c*A4 z{8{aaJ8jtbCRi+#-vuoX>DwfSzhdWFO^fp^nE9Wftf;#ZyrS-YEAG)dqB)WJY)*29 zoM9y6!o{|}s0A;?jD22=`*(H7uuHCF+_TJDI$F{-TMZ}2`s({*)sQU6!2 z)@!J>H3*pi8u6HW?sJ~=aqmDZzJkbL^9SgSd74+SvtN!ib8F9q7zeTT-bd?nM81di zyXfp#L081fVFf+MVxLig$98tRt*oA7nCk}A(bR54Fn}Gl`9a4R`tUT*&@7(eOayfR z&vI79?@yzj@*bXT$9}G4Tf+g)ycnb;0r?W5S>Pa^bHjL&CxsRzRyVYQkvp8OkA3Gl z^c0Lzl|bREtH+PI$3r668wkegjtDItp~nfVhQB}yv3`Q6x31F{a`g$<(t^%xnu9`xQEFPh3M5PsY!gh z_23J6&6CINe0R`HCq3yx6N$4IJ$&7C5|Ccov#4VfGj^mjk28c+;)c=&?ed9F}jOEi8wE zw@@7q%PY7rwTw{QBPQ-TUY8_ErkaI}8Yi!WNUbYkFI|ZyM}nBFm#~*)Vb2=F&XZ9f zYy9L(HJK7-I6KLc7BVQ#uzCo>Q%vjtgC52R5_}YmGexJE?iX={K_-x5e&#WTmvNl; z;R)V*<9Gwl;~F0_qRe`o@S#%+Xz5K{M4I4K<2B6L@P)AegEJ3pXK;x#*@mKqT6gD{%uTy=1;eVaqzG0tyQ!q^0!;t)3 z&)&yXvfvsULccfSjo-uDEBMy+K407QKE>_{UZ*G2eb4C!@rWE&?%@X;rNh3k^6`T& zMAKk}RY&BA_jCND3R4kT_$%A(qs#Vkmi{E!<5KKWI{BSun&+58gN1dGDZ9jE&f_Hl zBa(H*u7_EC;BtKyAL8eXiJs#IK4Me>OyeeQ(T0lCxJ@}PH6O*tOq-ATNAU~J6#SBB zM2B_cKXFsK162er*FcPF9GPyd?L@F^{N=ovWaE zmvJ~Oi=w`b;aDgtzW%1q7xq_HLre9<+cgech?BlGv+3aez1mGKH;eU%mP8UcEpa9M=+ zErNcHHS)F%^GTZwORF$1t-`#7PYJGI=8_Ghhqe~+JG&<8sYAf*rM+(a-UfV*etgCx j_*MZICqKm})FGN^E#!ZqQDT#SM*2JaUS`C(4gdIW@Gr)_ literal 0 HcmV?d00001 diff --git a/bin/sig/utils/TimeUtils.class b/bin/sig/utils/TimeUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..dcf11e9893ac754c2c1bb7c1f2d89e614f1d43b4 GIT binary patch literal 1763 zcmaJ>OLN;)6#lLsk!-7}aU8X71H}U_b|G;{3xPaJaZE~r(**J&z(%nZM@5!{EO+RJ z9n(L+x?8p|3{Iz+cFPPKmfbNd8CLuP!gpo4N%PWpe9t}ieCP3{fBbYM851QVWjAsnn zbZUmHA&o(SMBVh}oR()Wih!OE-1vTbroN*K8ZIKk5($vW%{dE}ZObyq#e5u>@v?#; zf&PO~GA|9UNR$$wq9mSQ`0qf#R8P35;Htod1J1iel-ibEGu=3Hh$$%aEIjjDuUIy# zR>QDon{LDKRJt9#pi*>fu16A%+BCIk@26mBY*eqnODRcQDCx5&ah!)}|4TLM=PXV#sr zlRKEhu#7&Vp^T3NRIl0fD3I>;>Tq?^_O`6;V}aqrF@ljetHwO$HGF~!YuxfFl?0x^ z3MW+EFj5hzg{qQf~yu^W)NN=OJ2tQ=NEiL&Ka^`8~uR{QQ{5e zzruZyD;tXFwOyz`QwXuS@Q(o%3Cdd6fa^K#V(7>DE;w|bE~M_?M@V*{U+dtKnZ}jI ztt+K$8rjBpRFC?rqAO{<))x$ft zWN4Dx$Rs+r{t#+v{6|Dn??1xiErsigeg-0=`H2uSM?e6}O4Qhy zC|SjeAem6Ic0jbE^i&za8#Jv~EwpTSiHmm~61kW=_-V4wbuD#JWfvC7{*BOg7L(C(>%sln6n l4^%uj9WPIbzqC&tjz;Llf1={a>3Dfce1-{r!SX`*@_)kKdoln3 literal 0 HcmV?d00001 diff --git a/projectBuilder.xml b/projectBuilder.xml new file mode 100644 index 0000000..c7c2b28 --- /dev/null +++ b/projectBuilder.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/org/json/CDL.java b/src/org/json/CDL.java new file mode 100644 index 0000000..6a82764 --- /dev/null +++ b/src/org/json/CDL.java @@ -0,0 +1,284 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * This provides static methods to convert comma delimited text into a + * JSONArray, and to convert a JSONArray into comma delimited text. Comma + * delimited text is a very popular format for data interchange. It is + * understood by most database, spreadsheet, and organizer programs. + *

+ * Each row of text represents a row in a table or a data record. Each row + * ends with a NEWLINE character. Each row contains one or more values. + * Values are separated by commas. A value can contain any character except + * for comma, unless is is wrapped in single quotes or double quotes. + *

+ * The first row usually contains the names of the columns. + *

+ * A comma delimited list can be converted into a JSONArray of JSONObjects. + * The names for the elements in the JSONObjects can be taken from the names + * in the first row. + * @author JSON.org + * @version 2016-05-01 + */ +public class CDL { + + /** + * Get the next value. The value can be wrapped in quotes. The value can + * be empty. + * @param x A JSONTokener of the source text. + * @return The value string, or null if empty. + * @throws JSONException if the quoted string is badly formed. + */ + private static String getValue(JSONTokener x) throws JSONException { + char c; + char q; + StringBuffer sb; + do { + c = x.next(); + } while (c == ' ' || c == '\t'); + switch (c) { + case 0: + return null; + case '"': + case '\'': + q = c; + sb = new StringBuffer(); + for (;;) { + c = x.next(); + if (c == q) { + //Handle escaped double-quote + if(x.next() != '\"') + { + x.back(); + break; + } + } + if (c == 0 || c == '\n' || c == '\r') { + throw x.syntaxError("Missing close quote '" + q + "'."); + } + sb.append(c); + } + return sb.toString(); + case ',': + x.back(); + return ""; + default: + x.back(); + return x.nextTo(','); + } + } + + /** + * Produce a JSONArray of strings from a row of comma delimited values. + * @param x A JSONTokener of the source text. + * @return A JSONArray of strings. + * @throws JSONException + */ + public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException { + JSONArray ja = new JSONArray(); + for (;;) { + String value = getValue(x); + char c = x.next(); + if (value == null || + (ja.length() == 0 && value.length() == 0 && c != ',')) { + return null; + } + ja.put(value); + for (;;) { + if (c == ',') { + break; + } + if (c != ' ') { + if (c == '\n' || c == '\r' || c == 0) { + return ja; + } + throw x.syntaxError("Bad character '" + c + "' (" + + (int)c + ")."); + } + c = x.next(); + } + } + } + + /** + * Produce a JSONObject from a row of comma delimited text, using a + * parallel JSONArray of strings to provides the names of the elements. + * @param names A JSONArray of names. This is commonly obtained from the + * first row of a comma delimited text file using the rowToJSONArray + * method. + * @param x A JSONTokener of the source text. + * @return A JSONObject combining the names and values. + * @throws JSONException + */ + public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) + throws JSONException { + JSONArray ja = rowToJSONArray(x); + return ja != null ? ja.toJSONObject(names) : null; + } + + /** + * Produce a comma delimited text row from a JSONArray. Values containing + * the comma character will be quoted. Troublesome characters may be + * removed. + * @param ja A JSONArray of strings. + * @return A string ending in NEWLINE. + */ + public static String rowToString(JSONArray ja) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < ja.length(); i += 1) { + if (i > 0) { + sb.append(','); + } + Object object = ja.opt(i); + if (object != null) { + String string = object.toString(); + if (string.length() > 0 && (string.indexOf(',') >= 0 || + string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 || + string.indexOf(0) >= 0 || string.charAt(0) == '"')) { + sb.append('"'); + int length = string.length(); + for (int j = 0; j < length; j += 1) { + char c = string.charAt(j); + if (c >= ' ' && c != '"') { + sb.append(c); + } + } + sb.append('"'); + } else { + sb.append(string); + } + } + } + sb.append('\n'); + return sb.toString(); + } + + /** + * Produce a JSONArray of JSONObjects from a comma delimited text string, + * using the first row as a source of names. + * @param string The comma delimited text. + * @return A JSONArray of JSONObjects. + * @throws JSONException + */ + public static JSONArray toJSONArray(String string) throws JSONException { + return toJSONArray(new JSONTokener(string)); + } + + /** + * Produce a JSONArray of JSONObjects from a comma delimited text string, + * using the first row as a source of names. + * @param x The JSONTokener containing the comma delimited text. + * @return A JSONArray of JSONObjects. + * @throws JSONException + */ + public static JSONArray toJSONArray(JSONTokener x) throws JSONException { + return toJSONArray(rowToJSONArray(x), x); + } + + /** + * Produce a JSONArray of JSONObjects from a comma delimited text string + * using a supplied JSONArray as the source of element names. + * @param names A JSONArray of strings. + * @param string The comma delimited text. + * @return A JSONArray of JSONObjects. + * @throws JSONException + */ + public static JSONArray toJSONArray(JSONArray names, String string) + throws JSONException { + return toJSONArray(names, new JSONTokener(string)); + } + + /** + * Produce a JSONArray of JSONObjects from a comma delimited text string + * using a supplied JSONArray as the source of element names. + * @param names A JSONArray of strings. + * @param x A JSONTokener of the source text. + * @return A JSONArray of JSONObjects. + * @throws JSONException + */ + public static JSONArray toJSONArray(JSONArray names, JSONTokener x) + throws JSONException { + if (names == null || names.length() == 0) { + return null; + } + JSONArray ja = new JSONArray(); + for (;;) { + JSONObject jo = rowToJSONObject(names, x); + if (jo == null) { + break; + } + ja.put(jo); + } + if (ja.length() == 0) { + return null; + } + return ja; + } + + + /** + * Produce a comma delimited text from a JSONArray of JSONObjects. The + * first row will be a list of names obtained by inspecting the first + * JSONObject. + * @param ja A JSONArray of JSONObjects. + * @return A comma delimited text. + * @throws JSONException + */ + public static String toString(JSONArray ja) throws JSONException { + JSONObject jo = ja.optJSONObject(0); + if (jo != null) { + JSONArray names = jo.names(); + if (names != null) { + return rowToString(names) + toString(names, ja); + } + } + return null; + } + + /** + * Produce a comma delimited text from a JSONArray of JSONObjects using + * a provided list of names. The list of names is not included in the + * output. + * @param names A JSONArray of strings. + * @param ja A JSONArray of JSONObjects. + * @return A comma delimited text. + * @throws JSONException + */ + public static String toString(JSONArray names, JSONArray ja) + throws JSONException { + if (names == null || names.length() == 0) { + return null; + } + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < ja.length(); i += 1) { + JSONObject jo = ja.optJSONObject(i); + if (jo != null) { + sb.append(rowToString(jo.toJSONArray(names))); + } + } + return sb.toString(); + } +} diff --git a/src/org/json/Cookie.java b/src/org/json/Cookie.java new file mode 100644 index 0000000..348dc68 --- /dev/null +++ b/src/org/json/Cookie.java @@ -0,0 +1,169 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * Convert a web browser cookie specification to a JSONObject and back. + * JSON and Cookies are both notations for name/value pairs. + * @author JSON.org + * @version 2015-12-09 + */ +public class Cookie { + + /** + * Produce a copy of a string in which the characters '+', '%', '=', ';' + * and control characters are replaced with "%hh". This is a gentle form + * of URL encoding, attempting to cause as little distortion to the + * string as possible. The characters '=' and ';' are meta characters in + * cookies. By convention, they are escaped using the URL-encoding. This is + * only a convention, not a standard. Often, cookies are expected to have + * encoded values. We encode '=' and ';' because we must. We encode '%' and + * '+' because they are meta characters in URL encoding. + * @param string The source string. + * @return The escaped result. + */ + public static String escape(String string) { + char c; + String s = string.trim(); + int length = s.length(); + StringBuilder sb = new StringBuilder(length); + for (int i = 0; i < length; i += 1) { + c = s.charAt(i); + if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') { + sb.append('%'); + sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16)); + sb.append(Character.forDigit((char)(c & 0x0f), 16)); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + + /** + * Convert a cookie specification string into a JSONObject. The string + * will contain a name value pair separated by '='. The name and the value + * will be unescaped, possibly converting '+' and '%' sequences. The + * cookie properties may follow, separated by ';', also represented as + * name=value (except the secure property, which does not have a value). + * The name will be stored under the key "name", and the value will be + * stored under the key "value". This method does not do checking or + * validation of the parameters. It only converts the cookie string into + * a JSONObject. + * @param string The cookie specification string. + * @return A JSONObject containing "name", "value", and possibly other + * members. + * @throws JSONException + */ + public static JSONObject toJSONObject(String string) throws JSONException { + String name; + JSONObject jo = new JSONObject(); + Object value; + JSONTokener x = new JSONTokener(string); + jo.put("name", x.nextTo('=')); + x.next('='); + jo.put("value", x.nextTo(';')); + x.next(); + while (x.more()) { + name = unescape(x.nextTo("=;")); + if (x.next() != '=') { + if (name.equals("secure")) { + value = Boolean.TRUE; + } else { + throw x.syntaxError("Missing '=' in cookie parameter."); + } + } else { + value = unescape(x.nextTo(';')); + x.next(); + } + jo.put(name, value); + } + return jo; + } + + + /** + * Convert a JSONObject into a cookie specification string. The JSONObject + * must contain "name" and "value" members. + * If the JSONObject contains "expires", "domain", "path", or "secure" + * members, they will be appended to the cookie specification string. + * All other members are ignored. + * @param jo A JSONObject + * @return A cookie specification string + * @throws JSONException + */ + public static String toString(JSONObject jo) throws JSONException { + StringBuilder sb = new StringBuilder(); + + sb.append(escape(jo.getString("name"))); + sb.append("="); + sb.append(escape(jo.getString("value"))); + if (jo.has("expires")) { + sb.append(";expires="); + sb.append(jo.getString("expires")); + } + if (jo.has("domain")) { + sb.append(";domain="); + sb.append(escape(jo.getString("domain"))); + } + if (jo.has("path")) { + sb.append(";path="); + sb.append(escape(jo.getString("path"))); + } + if (jo.optBoolean("secure")) { + sb.append(";secure"); + } + return sb.toString(); + } + + /** + * Convert %hh sequences to single characters, and + * convert plus to space. + * @param string A string that may contain + * + (plus) and + * %hh sequences. + * @return The unescaped string. + */ + public static String unescape(String string) { + int length = string.length(); + StringBuilder sb = new StringBuilder(length); + for (int i = 0; i < length; ++i) { + char c = string.charAt(i); + if (c == '+') { + c = ' '; + } else if (c == '%' && i + 2 < length) { + int d = JSONTokener.dehexchar(string.charAt(i + 1)); + int e = JSONTokener.dehexchar(string.charAt(i + 2)); + if (d >= 0 && e >= 0) { + c = (char)(d * 16 + e); + i += 2; + } + } + sb.append(c); + } + return sb.toString(); + } +} diff --git a/src/org/json/CookieList.java b/src/org/json/CookieList.java new file mode 100644 index 0000000..7a5628e --- /dev/null +++ b/src/org/json/CookieList.java @@ -0,0 +1,89 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import java.util.Iterator; + +/** + * Convert a web browser cookie list string to a JSONObject and back. + * @author JSON.org + * @version 2015-12-09 + */ +public class CookieList { + + /** + * Convert a cookie list into a JSONObject. A cookie list is a sequence + * of name/value pairs. The names are separated from the values by '='. + * The pairs are separated by ';'. The names and the values + * will be unescaped, possibly converting '+' and '%' sequences. + * + * To add a cookie to a cooklist, + * cookielistJSONObject.put(cookieJSONObject.getString("name"), + * cookieJSONObject.getString("value")); + * @param string A cookie list string + * @return A JSONObject + * @throws JSONException + */ + public static JSONObject toJSONObject(String string) throws JSONException { + JSONObject jo = new JSONObject(); + JSONTokener x = new JSONTokener(string); + while (x.more()) { + String name = Cookie.unescape(x.nextTo('=')); + x.next('='); + jo.put(name, Cookie.unescape(x.nextTo(';'))); + x.next(); + } + return jo; + } + + /** + * Convert a JSONObject into a cookie list. A cookie list is a sequence + * of name/value pairs. The names are separated from the values by '='. + * The pairs are separated by ';'. The characters '%', '+', '=', and ';' + * in the names and values are replaced by "%hh". + * @param jo A JSONObject + * @return A cookie list string + * @throws JSONException + */ + public static String toString(JSONObject jo) throws JSONException { + boolean b = false; + Iterator keys = jo.keys(); + String string; + StringBuilder sb = new StringBuilder(); + while (keys.hasNext()) { + string = keys.next(); + if (!jo.isNull(string)) { + if (b) { + sb.append(';'); + } + sb.append(Cookie.escape(string)); + sb.append("="); + sb.append(Cookie.escape(jo.getString(string))); + b = true; + } + } + return sb.toString(); + } +} diff --git a/src/org/json/HTTP.java b/src/org/json/HTTP.java new file mode 100644 index 0000000..fafdfad --- /dev/null +++ b/src/org/json/HTTP.java @@ -0,0 +1,164 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import java.util.Iterator; +import java.util.Locale; + +/** + * Convert an HTTP header to a JSONObject and back. + * @author JSON.org + * @version 2015-12-09 + */ +public class HTTP { + + /** Carriage return/line feed. */ + public static final String CRLF = "\r\n"; + + /** + * Convert an HTTP header string into a JSONObject. It can be a request + * header or a response header. A request header will contain + *

{
+     *    Method: "POST" (for example),
+     *    "Request-URI": "/" (for example),
+     *    "HTTP-Version": "HTTP/1.1" (for example)
+     * }
+ * A response header will contain + *
{
+     *    "HTTP-Version": "HTTP/1.1" (for example),
+     *    "Status-Code": "200" (for example),
+     *    "Reason-Phrase": "OK" (for example)
+     * }
+ * In addition, the other parameters in the header will be captured, using + * the HTTP field names as JSON names, so that
+     *    Date: Sun, 26 May 2002 18:06:04 GMT
+     *    Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
+     *    Cache-Control: no-cache
+ * become + *
{...
+     *    Date: "Sun, 26 May 2002 18:06:04 GMT",
+     *    Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
+     *    "Cache-Control": "no-cache",
+     * ...}
+ * It does no further checking or conversion. It does not parse dates. + * It does not do '%' transforms on URLs. + * @param string An HTTP header string. + * @return A JSONObject containing the elements and attributes + * of the XML string. + * @throws JSONException + */ + public static JSONObject toJSONObject(String string) throws JSONException { + JSONObject jo = new JSONObject(); + HTTPTokener x = new HTTPTokener(string); + String token; + + token = x.nextToken(); + if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) { + +// Response + + jo.put("HTTP-Version", token); + jo.put("Status-Code", x.nextToken()); + jo.put("Reason-Phrase", x.nextTo('\0')); + x.next(); + + } else { + +// Request + + jo.put("Method", token); + jo.put("Request-URI", x.nextToken()); + jo.put("HTTP-Version", x.nextToken()); + } + +// Fields + + while (x.more()) { + String name = x.nextTo(':'); + x.next(':'); + jo.put(name, x.nextTo('\0')); + x.next(); + } + return jo; + } + + + /** + * Convert a JSONObject into an HTTP header. A request header must contain + *
{
+     *    Method: "POST" (for example),
+     *    "Request-URI": "/" (for example),
+     *    "HTTP-Version": "HTTP/1.1" (for example)
+     * }
+ * A response header must contain + *
{
+     *    "HTTP-Version": "HTTP/1.1" (for example),
+     *    "Status-Code": "200" (for example),
+     *    "Reason-Phrase": "OK" (for example)
+     * }
+ * Any other members of the JSONObject will be output as HTTP fields. + * The result will end with two CRLF pairs. + * @param jo A JSONObject + * @return An HTTP header string. + * @throws JSONException if the object does not contain enough + * information. + */ + public static String toString(JSONObject jo) throws JSONException { + Iterator keys = jo.keys(); + String string; + StringBuilder sb = new StringBuilder(); + if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { + sb.append(jo.getString("HTTP-Version")); + sb.append(' '); + sb.append(jo.getString("Status-Code")); + sb.append(' '); + sb.append(jo.getString("Reason-Phrase")); + } else if (jo.has("Method") && jo.has("Request-URI")) { + sb.append(jo.getString("Method")); + sb.append(' '); + sb.append('"'); + sb.append(jo.getString("Request-URI")); + sb.append('"'); + sb.append(' '); + sb.append(jo.getString("HTTP-Version")); + } else { + throw new JSONException("Not enough material for an HTTP header."); + } + sb.append(CRLF); + while (keys.hasNext()) { + string = keys.next(); + if (!"HTTP-Version".equals(string) && !"Status-Code".equals(string) && + !"Reason-Phrase".equals(string) && !"Method".equals(string) && + !"Request-URI".equals(string) && !jo.isNull(string)) { + sb.append(string); + sb.append(": "); + sb.append(jo.getString(string)); + sb.append(CRLF); + } + } + sb.append(CRLF); + return sb.toString(); + } +} diff --git a/src/org/json/HTTPTokener.java b/src/org/json/HTTPTokener.java new file mode 100644 index 0000000..55f48ff --- /dev/null +++ b/src/org/json/HTTPTokener.java @@ -0,0 +1,77 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * The HTTPTokener extends the JSONTokener to provide additional methods + * for the parsing of HTTP headers. + * @author JSON.org + * @version 2015-12-09 + */ +public class HTTPTokener extends JSONTokener { + + /** + * Construct an HTTPTokener from a string. + * @param string A source string. + */ + public HTTPTokener(String string) { + super(string); + } + + + /** + * Get the next token or string. This is used in parsing HTTP headers. + * @throws JSONException + * @return A String. + */ + public String nextToken() throws JSONException { + char c; + char q; + StringBuilder sb = new StringBuilder(); + do { + c = next(); + } while (Character.isWhitespace(c)); + if (c == '"' || c == '\'') { + q = c; + for (;;) { + c = next(); + if (c < ' ') { + throw syntaxError("Unterminated string."); + } + if (c == q) { + return sb.toString(); + } + sb.append(c); + } + } + for (;;) { + if (c == 0 || Character.isWhitespace(c)) { + return sb.toString(); + } + sb.append(c); + c = next(); + } + } +} diff --git a/src/org/json/JSONArray.java b/src/org/json/JSONArray.java new file mode 100644 index 0000000..2446fd6 --- /dev/null +++ b/src/org/json/JSONArray.java @@ -0,0 +1,1200 @@ +package org.json; + +/* + Copyright (c) 2002 JSON.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + The Software shall be used for Good, not Evil. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Array; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * A JSONArray is an ordered sequence of values. Its external text form is a + * string wrapped in square brackets with commas separating the values. The + * internal form is an object having get and opt + * methods for accessing the values by index, and put methods for + * adding or replacing values. The values can be any of these types: + * Boolean, JSONArray, JSONObject, + * Number, String, or the + * JSONObject.NULL object. + *

+ * The constructor can convert a JSON text into a Java object. The + * toString method converts to JSON text. + *

+ * A get method returns a value if one can be found, and throws an + * exception if one cannot be found. An opt method returns a + * default value instead of throwing an exception, and so is useful for + * obtaining optional values. + *

+ * The generic get() and opt() methods return an + * object which you can cast or query for type. There are also typed + * get and opt methods that do type checking and type + * coercion for you. + *

+ * The texts produced by the toString methods strictly conform to + * JSON syntax rules. The constructors are more forgiving in the texts they will + * accept: + *

    + *
  • An extra , (comma) may appear just + * before the closing bracket.
  • + *
  • The null value will be inserted when there is , + *  (comma) elision.
  • + *
  • Strings may be quoted with ' (single + * quote).
  • + *
  • Strings do not need to be quoted at all if they do not begin with a quote + * or single quote, and if they do not contain leading or trailing spaces, and + * if they do not contain any of these characters: + * { } [ ] / \ : , # and if they do not look like numbers and + * if they are not the reserved words true, false, or + * null.
  • + *
+ * + * @author JSON.org + * @version 2016-08/15 + */ +public class JSONArray implements Iterable { + + /** + * The arrayList where the JSONArray's properties are kept. + */ + private final ArrayList myArrayList; + + /** + * Construct an empty JSONArray. + */ + public JSONArray() { + this.myArrayList = new ArrayList(); + } + + /** + * Construct a JSONArray from a JSONTokener. + * + * @param x + * A JSONTokener + * @throws JSONException + * If there is a syntax error. + */ + public JSONArray(JSONTokener x) throws JSONException { + this(); + if (x.nextClean() != '[') { + throw x.syntaxError("A JSONArray text must start with '['"); + } + if (x.nextClean() != ']') { + x.back(); + for (;;) { + if (x.nextClean() == ',') { + x.back(); + this.myArrayList.add(JSONObject.NULL); + } else { + x.back(); + this.myArrayList.add(x.nextValue()); + } + switch (x.nextClean()) { + case ',': + if (x.nextClean() == ']') { + return; + } + x.back(); + break; + case ']': + return; + default: + throw x.syntaxError("Expected a ',' or ']'"); + } + } + } + } + + /** + * Construct a JSONArray from a source JSON text. + * + * @param source + * A string that begins with [ (left + * bracket) and ends with ] + *  (right bracket). + * @throws JSONException + * If there is a syntax error. + */ + public JSONArray(String source) throws JSONException { + this(new JSONTokener(source)); + } + + /** + * Construct a JSONArray from a Collection. + * + * @param collection + * A Collection. + */ + public JSONArray(Collection collection) { + this.myArrayList = new ArrayList(); + if (collection != null) { + for (Object o: collection){ + this.myArrayList.add(JSONObject.wrap(o)); + } + } + } + + /** + * Construct a JSONArray from an array + * + * @throws JSONException + * If not an array. + */ + public JSONArray(Object array) throws JSONException { + this(); + if (array.getClass().isArray()) { + int length = Array.getLength(array); + for (int i = 0; i < length; i += 1) { + this.put(JSONObject.wrap(Array.get(array, i))); + } + } else { + throw new JSONException( + "JSONArray initial value should be a string or collection or array."); + } + } + + @Override + public Iterator iterator() { + return myArrayList.iterator(); + } + + /** + * Get the object value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return An object value. + * @throws JSONException + * If there is no value for the index. + */ + public Object get(int index) throws JSONException { + Object object = this.opt(index); + if (object == null) { + throw new JSONException("JSONArray[" + index + "] not found."); + } + return object; + } + + /** + * Get the boolean value associated with an index. The string values "true" + * and "false" are converted to boolean. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The truth. + * @throws JSONException + * If there is no value for the index or if the value is not + * convertible to boolean. + */ + public boolean getBoolean(int index) throws JSONException { + Object object = this.get(index); + if (object.equals(Boolean.FALSE) + || (object instanceof String && ((String) object) + .equalsIgnoreCase("false"))) { + return false; + } else if (object.equals(Boolean.TRUE) + || (object instanceof String && ((String) object) + .equalsIgnoreCase("true"))) { + return true; + } + throw new JSONException("JSONArray[" + index + "] is not a boolean."); + } + + /** + * Get the double value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value cannot be converted + * to a number. + */ + public double getDouble(int index) throws JSONException { + Object object = this.get(index); + try { + return object instanceof Number ? ((Number) object).doubleValue() + : Double.parseDouble((String) object); + } catch (Exception e) { + throw new JSONException("JSONArray[" + index + "] is not a number."); + } + } + + /** + * Get the enum value associated with an index. + * + * @param clazz + * The type of enum to retrieve. + * @param index + * The index must be between 0 and length() - 1. + * @return The enum value at the index location + * @throws JSONException + * if the key is not found or if the value cannot be converted + * to an enum. + */ + public > E getEnum(Class clazz, int index) throws JSONException { + E val = optEnum(clazz, index); + if(val==null) { + // JSONException should really take a throwable argument. + // If it did, I would re-implement this with the Enum.valueOf + // method and place any thrown exception in the JSONException + throw new JSONException("JSONObject[" + JSONObject.quote(Integer.toString(index)) + + "] is not an enum of type " + JSONObject.quote(clazz.getSimpleName()) + + "."); + } + return val; + } + + /** + * Get the BigDecimal value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value cannot be converted + * to a BigDecimal. + */ + public BigDecimal getBigDecimal (int index) throws JSONException { + Object object = this.get(index); + try { + return new BigDecimal(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONArray[" + index + + "] could not convert to BigDecimal."); + } + } + + /** + * Get the BigInteger value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value cannot be converted + * to a BigInteger. + */ + public BigInteger getBigInteger (int index) throws JSONException { + Object object = this.get(index); + try { + return new BigInteger(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONArray[" + index + + "] could not convert to BigInteger."); + } + } + + /** + * Get the int value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value is not a number. + */ + public int getInt(int index) throws JSONException { + Object object = this.get(index); + try { + return object instanceof Number ? ((Number) object).intValue() + : Integer.parseInt((String) object); + } catch (Exception e) { + throw new JSONException("JSONArray[" + index + "] is not a number."); + } + } + + /** + * Get the JSONArray associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return A JSONArray value. + * @throws JSONException + * If there is no value for the index. or if the value is not a + * JSONArray + */ + public JSONArray getJSONArray(int index) throws JSONException { + Object object = this.get(index); + if (object instanceof JSONArray) { + return (JSONArray) object; + } + throw new JSONException("JSONArray[" + index + "] is not a JSONArray."); + } + + /** + * Get the JSONObject associated with an index. + * + * @param index + * subscript + * @return A JSONObject value. + * @throws JSONException + * If there is no value for the index or if the value is not a + * JSONObject + */ + public JSONObject getJSONObject(int index) throws JSONException { + Object object = this.get(index); + if (object instanceof JSONObject) { + return (JSONObject) object; + } + throw new JSONException("JSONArray[" + index + "] is not a JSONObject."); + } + + /** + * Get the long value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value cannot be converted + * to a number. + */ + public long getLong(int index) throws JSONException { + Object object = this.get(index); + try { + return object instanceof Number ? ((Number) object).longValue() + : Long.parseLong((String) object); + } catch (Exception e) { + throw new JSONException("JSONArray[" + index + "] is not a number."); + } + } + + /** + * Get the string associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return A string value. + * @throws JSONException + * If there is no string value for the index. + */ + public String getString(int index) throws JSONException { + Object object = this.get(index); + if (object instanceof String) { + return (String) object; + } + throw new JSONException("JSONArray[" + index + "] not a string."); + } + + /** + * Determine if the value is null. + * + * @param index + * The index must be between 0 and length() - 1. + * @return true if the value at the index is null, or if there is no value. + */ + public boolean isNull(int index) { + return JSONObject.NULL.equals(this.opt(index)); + } + + /** + * Make a string from the contents of this JSONArray. The + * separator string is inserted between each element. Warning: + * This method assumes that the data structure is acyclical. + * + * @param separator + * A string that will be inserted between the elements. + * @return a string. + * @throws JSONException + * If the array contains an invalid number. + */ + public String join(String separator) throws JSONException { + int len = this.length(); + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < len; i += 1) { + if (i > 0) { + sb.append(separator); + } + sb.append(JSONObject.valueToString(this.myArrayList.get(i))); + } + return sb.toString(); + } + + /** + * Get the number of elements in the JSONArray, included nulls. + * + * @return The length (or size). + */ + public int length() { + return this.myArrayList.size(); + } + + /** + * Get the optional object value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return An object value, or null if there is no object at that index. + */ + public Object opt(int index) { + return (index < 0 || index >= this.length()) ? null : this.myArrayList + .get(index); + } + + /** + * Get the optional boolean value associated with an index. It returns false + * if there is no value at that index, or if the value is not Boolean.TRUE + * or the String "true". + * + * @param index + * The index must be between 0 and length() - 1. + * @return The truth. + */ + public boolean optBoolean(int index) { + return this.optBoolean(index, false); + } + + /** + * Get the optional boolean value associated with an index. It returns the + * defaultValue if there is no value at that index or if it is not a Boolean + * or the String "true" or "false" (case insensitive). + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * A boolean default. + * @return The truth. + */ + public boolean optBoolean(int index, boolean defaultValue) { + try { + return this.getBoolean(index); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get the optional double value associated with an index. NaN is returned + * if there is no value for the index, or if the value is not a number and + * cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + */ + public double optDouble(int index) { + return this.optDouble(index, Double.NaN); + } + + /** + * Get the optional double value associated with an index. The defaultValue + * is returned if there is no value for the index, or if the value is not a + * number and cannot be converted to a number. + * + * @param index + * subscript + * @param defaultValue + * The default value. + * @return The value. + */ + public double optDouble(int index, double defaultValue) { + try { + return this.getDouble(index); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get the optional int value associated with an index. Zero is returned if + * there is no value for the index, or if the value is not a number and + * cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + */ + public int optInt(int index) { + return this.optInt(index, 0); + } + + /** + * Get the optional int value associated with an index. The defaultValue is + * returned if there is no value for the index, or if the value is not a + * number and cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return The value. + */ + public int optInt(int index, int defaultValue) { + try { + return this.getInt(index); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get the enum value associated with a key. + * + * @param clazz + * The type of enum to retrieve. + * @param index + * The index must be between 0 and length() - 1. + * @return The enum value at the index location or null if not found + */ + public > E optEnum(Class clazz, int index) { + return this.optEnum(clazz, index, null); + } + + /** + * Get the enum value associated with a key. + * + * @param clazz + * The type of enum to retrieve. + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default in case the value is not found + * @return The enum value at the index location or defaultValue if + * the value is not found or cannot be assigned to clazz + */ + public > E optEnum(Class clazz, int index, E defaultValue) { + try { + Object val = this.opt(index); + if (JSONObject.NULL.equals(val)) { + return defaultValue; + } + if (clazz.isAssignableFrom(val.getClass())) { + // we just checked it! + @SuppressWarnings("unchecked") + E myE = (E) val; + return myE; + } + return Enum.valueOf(clazz, val.toString()); + } catch (IllegalArgumentException e) { + return defaultValue; + } catch (NullPointerException e) { + return defaultValue; + } + } + + + /** + * Get the optional BigInteger value associated with an index. The + * defaultValue is returned if there is no value for the index, or if the + * value is not a number and cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return The value. + */ + public BigInteger optBigInteger(int index, BigInteger defaultValue) { + try { + return this.getBigInteger(index); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get the optional BigDecimal value associated with an index. The + * defaultValue is returned if there is no value for the index, or if the + * value is not a number and cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return The value. + */ + public BigDecimal optBigDecimal(int index, BigDecimal defaultValue) { + try { + return this.getBigDecimal(index); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get the optional JSONArray associated with an index. + * + * @param index + * subscript + * @return A JSONArray value, or null if the index has no value, or if the + * value is not a JSONArray. + */ + public JSONArray optJSONArray(int index) { + Object o = this.opt(index); + return o instanceof JSONArray ? (JSONArray) o : null; + } + + /** + * Get the optional JSONObject associated with an index. Null is returned if + * the key is not found, or null if the index has no value, or if the value + * is not a JSONObject. + * + * @param index + * The index must be between 0 and length() - 1. + * @return A JSONObject value. + */ + public JSONObject optJSONObject(int index) { + Object o = this.opt(index); + return o instanceof JSONObject ? (JSONObject) o : null; + } + + /** + * Get the optional long value associated with an index. Zero is returned if + * there is no value for the index, or if the value is not a number and + * cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + */ + public long optLong(int index) { + return this.optLong(index, 0); + } + + /** + * Get the optional long value associated with an index. The defaultValue is + * returned if there is no value for the index, or if the value is not a + * number and cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return The value. + */ + public long optLong(int index, long defaultValue) { + try { + return this.getLong(index); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get the optional string value associated with an index. It returns an + * empty string if there is no value at that index. If the value is not a + * string and is not null, then it is coverted to a string. + * + * @param index + * The index must be between 0 and length() - 1. + * @return A String value. + */ + public String optString(int index) { + return this.optString(index, ""); + } + + /** + * Get the optional string associated with an index. The defaultValue is + * returned if the key is not found. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return A String value. + */ + public String optString(int index, String defaultValue) { + Object object = this.opt(index); + return JSONObject.NULL.equals(object) ? defaultValue : object + .toString(); + } + + /** + * Append a boolean value. This increases the array's length by one. + * + * @param value + * A boolean value. + * @return this. + */ + public JSONArray put(boolean value) { + this.put(value ? Boolean.TRUE : Boolean.FALSE); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONArray which + * is produced from a Collection. + * + * @param value + * A Collection value. + * @return this. + */ + public JSONArray put(Collection value) { + this.put(new JSONArray(value)); + return this; + } + + /** + * Append a double value. This increases the array's length by one. + * + * @param value + * A double value. + * @throws JSONException + * if the value is not finite. + * @return this. + */ + public JSONArray put(double value) throws JSONException { + Double d = new Double(value); + JSONObject.testValidity(d); + this.put(d); + return this; + } + + /** + * Append an int value. This increases the array's length by one. + * + * @param value + * An int value. + * @return this. + */ + public JSONArray put(int value) { + this.put(new Integer(value)); + return this; + } + + /** + * Append an long value. This increases the array's length by one. + * + * @param value + * A long value. + * @return this. + */ + public JSONArray put(long value) { + this.put(new Long(value)); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONObject which + * is produced from a Map. + * + * @param value + * A Map value. + * @return this. + */ + public JSONArray put(Map value) { + this.put(new JSONObject(value)); + return this; + } + + /** + * Append an object value. This increases the array's length by one. + * + * @param value + * An object value. The value should be a Boolean, Double, + * Integer, JSONArray, JSONObject, Long, or String, or the + * JSONObject.NULL object. + * @return this. + */ + public JSONArray put(Object value) { + this.myArrayList.add(value); + return this; + } + + /** + * Put or replace a boolean value in the JSONArray. If the index is greater + * than the length of the JSONArray, then null elements will be added as + * necessary to pad it out. + * + * @param index + * The subscript. + * @param value + * A boolean value. + * @return this. + * @throws JSONException + * If the index is negative. + */ + public JSONArray put(int index, boolean value) throws JSONException { + this.put(index, value ? Boolean.TRUE : Boolean.FALSE); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONArray which + * is produced from a Collection. + * + * @param index + * The subscript. + * @param value + * A Collection value. + * @return this. + * @throws JSONException + * If the index is negative or if the value is not finite. + */ + public JSONArray put(int index, Collection value) throws JSONException { + this.put(index, new JSONArray(value)); + return this; + } + + /** + * Put or replace a double value. If the index is greater than the length of + * the JSONArray, then null elements will be added as necessary to pad it + * out. + * + * @param index + * The subscript. + * @param value + * A double value. + * @return this. + * @throws JSONException + * If the index is negative or if the value is not finite. + */ + public JSONArray put(int index, double value) throws JSONException { + this.put(index, new Double(value)); + return this; + } + + /** + * Put or replace an int value. If the index is greater than the length of + * the JSONArray, then null elements will be added as necessary to pad it + * out. + * + * @param index + * The subscript. + * @param value + * An int value. + * @return this. + * @throws JSONException + * If the index is negative. + */ + public JSONArray put(int index, int value) throws JSONException { + this.put(index, new Integer(value)); + return this; + } + + /** + * Put or replace a long value. If the index is greater than the length of + * the JSONArray, then null elements will be added as necessary to pad it + * out. + * + * @param index + * The subscript. + * @param value + * A long value. + * @return this. + * @throws JSONException + * If the index is negative. + */ + public JSONArray put(int index, long value) throws JSONException { + this.put(index, new Long(value)); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONObject that + * is produced from a Map. + * + * @param index + * The subscript. + * @param value + * The Map value. + * @return this. + * @throws JSONException + * If the index is negative or if the the value is an invalid + * number. + */ + public JSONArray put(int index, Map value) throws JSONException { + this.put(index, new JSONObject(value)); + return this; + } + + /** + * Put or replace an object value in the JSONArray. If the index is greater + * than the length of the JSONArray, then null elements will be added as + * necessary to pad it out. + * + * @param index + * The subscript. + * @param value + * The value to put into the array. The value should be a + * Boolean, Double, Integer, JSONArray, JSONObject, Long, or + * String, or the JSONObject.NULL object. + * @return this. + * @throws JSONException + * If the index is negative or if the the value is an invalid + * number. + */ + public JSONArray put(int index, Object value) throws JSONException { + JSONObject.testValidity(value); + if (index < 0) { + throw new JSONException("JSONArray[" + index + "] not found."); + } + if (index < this.length()) { + this.myArrayList.set(index, value); + } else { + while (index != this.length()) { + this.put(JSONObject.NULL); + } + this.put(value); + } + return this; + } + + /** + * Creates a JSONPointer using an initialization string and tries to + * match it to an item within this JSONArray. For example, given a + * JSONArray initialized with this document: + *
+     * [
+     *     {"b":"c"}
+     * ]
+     * 
+ * and this JSONPointer string: + *
+     * "/0/b"
+     * 
+ * Then this method will return the String "c" + * A JSONPointerException may be thrown from code called by this method. + * + * @param jsonPointer string that can be used to create a JSONPointer + * @return the item matched by the JSONPointer, otherwise null + */ + public Object query(String jsonPointer) { + return new JSONPointer(jsonPointer).queryFrom(this); + } + + /** + * Queries and returns a value from this object using {@code jsonPointer}, or + * returns null if the query fails due to a missing key. + * + * @param jsonPointer the string representation of the JSON pointer + * @return the queried value or {@code null} + * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax + */ + public Object optQuery(String jsonPointer) { + JSONPointer pointer = new JSONPointer(jsonPointer); + try { + return pointer.queryFrom(this); + } catch (JSONPointerException e) { + return null; + } + } + + /** + * Remove an index and close the hole. + * + * @param index + * The index of the element to be removed. + * @return The value that was associated with the index, or null if there + * was no value. + */ + public Object remove(int index) { + return index >= 0 && index < this.length() + ? this.myArrayList.remove(index) + : null; + } + + /** + * Determine if two JSONArrays are similar. + * They must contain similar sequences. + * + * @param other The other JSONArray + * @return true if they are equal + */ + public boolean similar(Object other) { + if (!(other instanceof JSONArray)) { + return false; + } + int len = this.length(); + if (len != ((JSONArray)other).length()) { + return false; + } + for (int i = 0; i < len; i += 1) { + Object valueThis = this.get(i); + Object valueOther = ((JSONArray)other).get(i); + if (valueThis instanceof JSONObject) { + if (!((JSONObject)valueThis).similar(valueOther)) { + return false; + } + } else if (valueThis instanceof JSONArray) { + if (!((JSONArray)valueThis).similar(valueOther)) { + return false; + } + } else if (!valueThis.equals(valueOther)) { + return false; + } + } + return true; + } + + /** + * Produce a JSONObject by combining a JSONArray of names with the values of + * this JSONArray. + * + * @param names + * A JSONArray containing a list of key strings. These will be + * paired with the values. + * @return A JSONObject, or null if there are no names or if this JSONArray + * has no values. + * @throws JSONException + * If any of the names are null. + */ + public JSONObject toJSONObject(JSONArray names) throws JSONException { + if (names == null || names.length() == 0 || this.length() == 0) { + return null; + } + JSONObject jo = new JSONObject(); + for (int i = 0; i < names.length(); i += 1) { + jo.put(names.getString(i), this.opt(i)); + } + return jo; + } + + /** + * Make a JSON text of this JSONArray. For compactness, no unnecessary + * whitespace is added. If it is not possible to produce a syntactically + * correct JSON text then null will be returned instead. This could occur if + * the array contains an invalid number. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return a printable, displayable, transmittable representation of the + * array. + */ + public String toString() { + try { + return this.toString(0); + } catch (Exception e) { + return null; + } + } + + /** + * Make a prettyprinted JSON text of this JSONArray. Warning: This method + * assumes that the data structure is acyclical. + * + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @return a printable, displayable, transmittable representation of the + * object, beginning with [ (left + * bracket) and ending with ] + *  (right bracket). + * @throws JSONException + */ + public String toString(int indentFactor) throws JSONException { + StringWriter sw = new StringWriter(); + synchronized (sw.getBuffer()) { + return this.write(sw, indentFactor, 0).toString(); + } + } + + /** + * Write the contents of the JSONArray as JSON text to a writer. For + * compactness, no whitespace is added. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return The writer. + * @throws JSONException + */ + public Writer write(Writer writer) throws JSONException { + return this.write(writer, 0, 0); + } + + /** + * Write the contents of the JSONArray as JSON text to a writer. For + * compactness, no whitespace is added. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @param writer + * Writes the serialized JSON + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @param indent + * The indention of the top level. + * @return The writer. + * @throws JSONException + */ + public Writer write(Writer writer, int indentFactor, int indent) + throws JSONException { + try { + boolean commanate = false; + int length = this.length(); + writer.write('['); + + if (length == 1) { + JSONObject.writeValue(writer, this.myArrayList.get(0), + indentFactor, indent); + } else if (length != 0) { + final int newindent = indent + indentFactor; + + for (int i = 0; i < length; i += 1) { + if (commanate) { + writer.write(','); + } + if (indentFactor > 0) { + writer.write('\n'); + } + JSONObject.indent(writer, newindent); + JSONObject.writeValue(writer, this.myArrayList.get(i), + indentFactor, newindent); + commanate = true; + } + if (indentFactor > 0) { + writer.write('\n'); + } + JSONObject.indent(writer, indent); + } + writer.write(']'); + return writer; + } catch (IOException e) { + throw new JSONException(e); + } + } + + /** + * Returns a java.util.List containing all of the elements in this array. + * If an element in the array is a JSONArray or JSONObject it will also + * be converted. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return a java.util.List containing the elements of this array + */ + public List toList() { + List results = new ArrayList(this.myArrayList.size()); + for (Object element : this.myArrayList) { + if (element == null || JSONObject.NULL.equals(element)) { + results.add(null); + } else if (element instanceof JSONArray) { + results.add(((JSONArray) element).toList()); + } else if (element instanceof JSONObject) { + results.add(((JSONObject) element).toMap()); + } else { + results.add(element); + } + } + return results; + } +} diff --git a/src/org/json/JSONException.java b/src/org/json/JSONException.java new file mode 100644 index 0000000..72542df --- /dev/null +++ b/src/org/json/JSONException.java @@ -0,0 +1,45 @@ +package org.json; + +/** + * The JSONException is thrown by the JSON.org classes when things are amiss. + * + * @author JSON.org + * @version 2015-12-09 + */ +public class JSONException extends RuntimeException { + /** Serialization ID */ + private static final long serialVersionUID = 0; + + /** + * Constructs a JSONException with an explanatory message. + * + * @param message + * Detail about the reason for the exception. + */ + public JSONException(final String message) { + super(message); + } + + /** + * Constructs a JSONException with an explanatory message and cause. + * + * @param message + * Detail about the reason for the exception. + * @param cause + * The cause. + */ + public JSONException(final String message, final Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new JSONException with the specified cause. + * + * @param cause + * The cause. + */ + public JSONException(final Throwable cause) { + super(cause.getMessage(), cause); + } + +} diff --git a/src/org/json/JSONML.java b/src/org/json/JSONML.java new file mode 100644 index 0000000..82853a9 --- /dev/null +++ b/src/org/json/JSONML.java @@ -0,0 +1,552 @@ +package org.json; + +/* +Copyright (c) 2008 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import java.util.Iterator; + + +/** + * This provides static methods to convert an XML text into a JSONArray or + * JSONObject, and to covert a JSONArray or JSONObject into an XML text using + * the JsonML transform. + * + * @author JSON.org + * @version 2016-01-30 + */ +public class JSONML { + /** + * Parse XML values and store them in a JSONArray. + * @param x The XMLTokener containing the source string. + * @param arrayForm true if array form, false if object form. + * @param ja The JSONArray that is containing the current tag or null + * if we are at the outermost level. + * @param keepStrings Don't type-convert text nodes and attibute values + * @return A JSONArray if the value is the outermost tag, otherwise null. + * @throws JSONException + */ + private static Object parse( + XMLTokener x, + boolean arrayForm, + JSONArray ja, + boolean keepStrings + ) throws JSONException { + String attribute; + char c; + String closeTag = null; + int i; + JSONArray newja = null; + JSONObject newjo = null; + Object token; + String tagName = null; + +// Test for and skip past these forms: +// +// +// +// + + while (true) { + if (!x.more()) { + throw x.syntaxError("Bad XML"); + } + token = x.nextContent(); + if (token == XML.LT) { + token = x.nextToken(); + if (token instanceof Character) { + if (token == XML.SLASH) { + +// Close tag "); + } else { + x.back(); + } + } else if (c == '[') { + token = x.nextToken(); + if (token.equals("CDATA") && x.next() == '[') { + if (ja != null) { + ja.put(x.nextCDATA()); + } + } else { + throw x.syntaxError("Expected 'CDATA['"); + } + } else { + i = 1; + do { + token = x.nextMeta(); + if (token == null) { + throw x.syntaxError("Missing '>' after ' 0); + } + } else if (token == XML.QUEST) { + +// "); + } else { + throw x.syntaxError("Misshaped tag"); + } + +// Open tag < + + } else { + if (!(token instanceof String)) { + throw x.syntaxError("Bad tagName '" + token + "'."); + } + tagName = (String)token; + newja = new JSONArray(); + newjo = new JSONObject(); + if (arrayForm) { + newja.put(tagName); + if (ja != null) { + ja.put(newja); + } + } else { + newjo.put("tagName", tagName); + if (ja != null) { + ja.put(newjo); + } + } + token = null; + for (;;) { + if (token == null) { + token = x.nextToken(); + } + if (token == null) { + throw x.syntaxError("Misshaped tag"); + } + if (!(token instanceof String)) { + break; + } + +// attribute = value + + attribute = (String)token; + if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) { + throw x.syntaxError("Reserved attribute."); + } + token = x.nextToken(); + if (token == XML.EQ) { + token = x.nextToken(); + if (!(token instanceof String)) { + throw x.syntaxError("Missing value"); + } + newjo.accumulate(attribute, keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token)); + token = null; + } else { + newjo.accumulate(attribute, ""); + } + } + if (arrayForm && newjo.length() > 0) { + newja.put(newjo); + } + +// Empty tag <.../> + + if (token == XML.SLASH) { + if (x.nextToken() != XML.GT) { + throw x.syntaxError("Misshaped tag"); + } + if (ja == null) { + if (arrayForm) { + return newja; + } + return newjo; + } + +// Content, between <...> and + + } else { + if (token != XML.GT) { + throw x.syntaxError("Misshaped tag"); + } + closeTag = (String)parse(x, arrayForm, newja, keepStrings); + if (closeTag != null) { + if (!closeTag.equals(tagName)) { + throw x.syntaxError("Mismatched '" + tagName + + "' and '" + closeTag + "'"); + } + tagName = null; + if (!arrayForm && newja.length() > 0) { + newjo.put("childNodes", newja); + } + if (ja == null) { + if (arrayForm) { + return newja; + } + return newjo; + } + } + } + } + } else { + if (ja != null) { + ja.put(token instanceof String + ? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token) + : token); + } + } + } + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONArray using the JsonML transform. Each XML tag is represented as + * a JSONArray in which the first element is the tag name. If the tag has + * attributes, then the second element will be JSONObject containing the + * name/value pairs. If the tag contains children, then strings and + * JSONArrays will represent the child tags. + * Comments, prologs, DTDs, and <[ [ ]]> are ignored. + * @param string The source string. + * @return A JSONArray containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONArray + */ + public static JSONArray toJSONArray(String string) throws JSONException { + return (JSONArray)parse(new XMLTokener(string), true, null, false); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONArray using the JsonML transform. Each XML tag is represented as + * a JSONArray in which the first element is the tag name. If the tag has + * attributes, then the second element will be JSONObject containing the + * name/value pairs. If the tag contains children, then strings and + * JSONArrays will represent the child tags. + * As opposed to toJSONArray this method does not attempt to convert + * any text node or attribute value to any type + * but just leaves it as a string. + * Comments, prologs, DTDs, and <[ [ ]]> are ignored. + * @param string The source string. + * @param keepStrings If true, then values will not be coerced into boolean + * or numeric values and will instead be left as strings + * @return A JSONArray containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONArray + */ + public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { + return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONArray using the JsonML transform. Each XML tag is represented as + * a JSONArray in which the first element is the tag name. If the tag has + * attributes, then the second element will be JSONObject containing the + * name/value pairs. If the tag contains children, then strings and + * JSONArrays will represent the child content and tags. + * As opposed to toJSONArray this method does not attempt to convert + * any text node or attribute value to any type + * but just leaves it as a string. + * Comments, prologs, DTDs, and <[ [ ]]> are ignored. + * @param x An XMLTokener. + * @param keepStrings If true, then values will not be coerced into boolean + * or numeric values and will instead be left as strings + * @return A JSONArray containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONArray + */ + public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { + return (JSONArray)parse(x, true, null, keepStrings); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONArray using the JsonML transform. Each XML tag is represented as + * a JSONArray in which the first element is the tag name. If the tag has + * attributes, then the second element will be JSONObject containing the + * name/value pairs. If the tag contains children, then strings and + * JSONArrays will represent the child content and tags. + * Comments, prologs, DTDs, and <[ [ ]]> are ignored. + * @param x An XMLTokener. + * @return A JSONArray containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONArray + */ + public static JSONArray toJSONArray(XMLTokener x) throws JSONException { + return (JSONArray)parse(x, true, null, false); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject using the JsonML transform. Each XML tag is represented as + * a JSONObject with a "tagName" property. If the tag has attributes, then + * the attributes will be in the JSONObject as properties. If the tag + * contains children, the object will have a "childNodes" property which + * will be an array of strings and JsonML JSONObjects. + + * Comments, prologs, DTDs, and <[ [ ]]> are ignored. + * @param string The XML source text. + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONObject + */ + public static JSONObject toJSONObject(String string) throws JSONException { + return (JSONObject)parse(new XMLTokener(string), false, null, false); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject using the JsonML transform. Each XML tag is represented as + * a JSONObject with a "tagName" property. If the tag has attributes, then + * the attributes will be in the JSONObject as properties. If the tag + * contains children, the object will have a "childNodes" property which + * will be an array of strings and JsonML JSONObjects. + + * Comments, prologs, DTDs, and <[ [ ]]> are ignored. + * @param string The XML source text. + * @param keepStrings If true, then values will not be coerced into boolean + * or numeric values and will instead be left as strings + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONObject + */ + public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { + return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject using the JsonML transform. Each XML tag is represented as + * a JSONObject with a "tagName" property. If the tag has attributes, then + * the attributes will be in the JSONObject as properties. If the tag + * contains children, the object will have a "childNodes" property which + * will be an array of strings and JsonML JSONObjects. + + * Comments, prologs, DTDs, and <[ [ ]]> are ignored. + * @param x An XMLTokener of the XML source text. + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONObject + */ + public static JSONObject toJSONObject(XMLTokener x) throws JSONException { + return (JSONObject)parse(x, false, null, false); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject using the JsonML transform. Each XML tag is represented as + * a JSONObject with a "tagName" property. If the tag has attributes, then + * the attributes will be in the JSONObject as properties. If the tag + * contains children, the object will have a "childNodes" property which + * will be an array of strings and JsonML JSONObjects. + + * Comments, prologs, DTDs, and <[ [ ]]> are ignored. + * @param x An XMLTokener of the XML source text. + * @param keepStrings If true, then values will not be coerced into boolean + * or numeric values and will instead be left as strings + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown on error converting to a JSONObject + */ + public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { + return (JSONObject)parse(x, false, null, keepStrings); + } + + + /** + * Reverse the JSONML transformation, making an XML text from a JSONArray. + * @param ja A JSONArray. + * @return An XML string. + * @throws JSONException Thrown on error converting to a string + */ + public static String toString(JSONArray ja) throws JSONException { + int i; + JSONObject jo; + String key; + Iterator keys; + int length; + Object object; + StringBuilder sb = new StringBuilder(); + String tagName; + String value; + +// Emit = length) { + sb.append('/'); + sb.append('>'); + } else { + sb.append('>'); + do { + object = ja.get(i); + i += 1; + if (object != null) { + if (object instanceof String) { + sb.append(XML.escape(object.toString())); + } else if (object instanceof JSONObject) { + sb.append(toString((JSONObject)object)); + } else if (object instanceof JSONArray) { + sb.append(toString((JSONArray)object)); + } else { + sb.append(object.toString()); + } + } + } while (i < length); + sb.append('<'); + sb.append('/'); + sb.append(tagName); + sb.append('>'); + } + return sb.toString(); + } + + /** + * Reverse the JSONML transformation, making an XML text from a JSONObject. + * The JSONObject must contain a "tagName" property. If it has children, + * then it must have a "childNodes" property containing an array of objects. + * The other properties are attributes with string values. + * @param jo A JSONObject. + * @return An XML string. + * @throws JSONException Thrown on error converting to a string + */ + public static String toString(JSONObject jo) throws JSONException { + StringBuilder sb = new StringBuilder(); + int i; + JSONArray ja; + String key; + Iterator keys; + int length; + Object object; + String tagName; + String value; + +//Emit '); + } else { + sb.append('>'); + length = ja.length(); + for (i = 0; i < length; i += 1) { + object = ja.get(i); + if (object != null) { + if (object instanceof String) { + sb.append(XML.escape(object.toString())); + } else if (object instanceof JSONObject) { + sb.append(toString((JSONObject)object)); + } else if (object instanceof JSONArray) { + sb.append(toString((JSONArray)object)); + } else { + sb.append(object.toString()); + } + } + } + sb.append('<'); + sb.append('/'); + sb.append(tagName); + sb.append('>'); + } + return sb.toString(); + } +} diff --git a/src/org/json/JSONObject.java b/src/org/json/JSONObject.java new file mode 100644 index 0000000..1eab694 --- /dev/null +++ b/src/org/json/JSONObject.java @@ -0,0 +1,1938 @@ +package org.json; + +/* + Copyright (c) 2002 JSON.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + The Software shall be used for Good, not Evil. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.ResourceBundle; +import java.util.Set; + +/** + * A JSONObject is an unordered collection of name/value pairs. Its external + * form is a string wrapped in curly braces with colons between the names and + * values, and commas between the values and names. The internal form is an + * object having get and opt methods for accessing + * the values by name, and put methods for adding or replacing + * values by name. The values can be any of these types: Boolean, + * JSONArray, JSONObject, Number, + * String, or the JSONObject.NULL object. A + * JSONObject constructor can be used to convert an external form JSON text + * into an internal form whose values can be retrieved with the + * get and opt methods, or to convert values into a + * JSON text using the put and toString methods. A + * get method returns a value if one can be found, and throws an + * exception if one cannot be found. An opt method returns a + * default value instead of throwing an exception, and so is useful for + * obtaining optional values. + *

+ * The generic get() and opt() methods return an + * object, which you can cast or query for type. There are also typed + * get and opt methods that do type checking and type + * coercion for you. The opt methods differ from the get methods in that they + * do not throw. Instead, they return a specified value, such as null. + *

+ * The put methods add or replace values in an object. For + * example, + * + *

+ * myString = new JSONObject()
+ *         .put("JSON", "Hello, World!").toString();
+ * 
+ * + * produces the string {"JSON": "Hello, World"}. + *

+ * The texts produced by the toString methods strictly conform to + * the JSON syntax rules. The constructors are more forgiving in the texts they + * will accept: + *

    + *
  • An extra , (comma) may appear just + * before the closing brace.
  • + *
  • Strings may be quoted with ' (single + * quote).
  • + *
  • Strings do not need to be quoted at all if they do not begin with a + * quote or single quote, and if they do not contain leading or trailing + * spaces, and if they do not contain any of these characters: + * { } [ ] / \ : , # and if they do not look like numbers and + * if they are not the reserved words true, false, + * or null.
  • + *
+ * + * @author JSON.org + * @version 2016-08-15 + */ +public class JSONObject { + /** + * JSONObject.NULL is equivalent to the value that JavaScript calls null, + * whilst Java's null is equivalent to the value that JavaScript calls + * undefined. + */ + private static final class Null { + + /** + * There is only intended to be a single instance of the NULL object, + * so the clone method returns itself. + * + * @return NULL. + */ + @Override + protected final Object clone() { + return this; + } + + /** + * A Null object is equal to the null value and to itself. + * + * @param object + * An object to test for nullness. + * @return true if the object parameter is the JSONObject.NULL object or + * null. + */ + @Override + public boolean equals(Object object) { + return object == null || object == this; + } + + /** + * Get the "null" string value. + * + * @return The string "null". + */ + @Override + public String toString() { + return "null"; + } + } + + /** + * The map where the JSONObject's properties are kept. + */ + private final Map map; + + /** + * It is sometimes more convenient and less ambiguous to have a + * NULL object than to use Java's null value. + * JSONObject.NULL.equals(null) returns true. + * JSONObject.NULL.toString() returns "null". + */ + public static final Object NULL = new Null(); + + /** + * Construct an empty JSONObject. + */ + public JSONObject() { + this.map = new HashMap(); + } + + /** + * Construct a JSONObject from a subset of another JSONObject. An array of + * strings is used to identify the keys that should be copied. Missing keys + * are ignored. + * + * @param jo + * A JSONObject. + * @param names + * An array of strings. + */ + public JSONObject(JSONObject jo, String[] names) { + this(); + for (int i = 0; i < names.length; i += 1) { + try { + this.putOnce(names[i], jo.opt(names[i])); + } catch (Exception ignore) { + } + } + } + + /** + * Construct a JSONObject from a JSONTokener. + * + * @param x + * A JSONTokener object containing the source string. + * @throws JSONException + * If there is a syntax error in the source string or a + * duplicated key. + */ + public JSONObject(JSONTokener x) throws JSONException { + this(); + char c; + String key; + + if (x.nextClean() != '{') { + throw x.syntaxError("A JSONObject text must begin with '{'"); + } + for (;;) { + c = x.nextClean(); + switch (c) { + case 0: + throw x.syntaxError("A JSONObject text must end with '}'"); + case '}': + return; + default: + x.back(); + key = x.nextValue().toString(); + } + +// The key is followed by ':'. + + c = x.nextClean(); + if (c != ':') { + throw x.syntaxError("Expected a ':' after a key"); + } + this.putOnce(key, x.nextValue()); + +// Pairs are separated by ','. + + switch (x.nextClean()) { + case ';': + case ',': + if (x.nextClean() == '}') { + return; + } + x.back(); + break; + case '}': + return; + default: + throw x.syntaxError("Expected a ',' or '}'"); + } + } + } + + /** + * Construct a JSONObject from a Map. + * + * @param map + * A map object that can be used to initialize the contents of + * the JSONObject. + */ + public JSONObject(Map map) { + this.map = new HashMap(); + if (map != null) { + for (final Entry e : map.entrySet()) { + final Object value = e.getValue(); + if (value != null) { + this.map.put(String.valueOf(e.getKey()), wrap(value)); + } + } + } + } + + /** + * Construct a JSONObject from an Object using bean getters. It reflects on + * all of the public methods of the object. For each of the methods with no + * parameters and a name starting with "get" or + * "is" followed by an uppercase letter, the method is invoked, + * and a key and the value returned from the getter method are put into the + * new JSONObject. + * + * The key is formed by removing the "get" or "is" + * prefix. If the second remaining character is not upper case, then the + * first character is converted to lower case. + * + * For example, if an object has a method named "getName", and + * if the result of calling object.getName() is + * "Larry Fine", then the JSONObject will contain + * "name": "Larry Fine". + * + * @param bean + * An object that has getter methods that should be used to make + * a JSONObject. + */ + public JSONObject(Object bean) { + this(); + this.populateMap(bean); + } + + /** + * Construct a JSONObject from an Object, using reflection to find the + * public members. The resulting JSONObject's keys will be the strings from + * the names array, and the values will be the field values associated with + * those keys in the object. If a key is not found or not visible, then it + * will not be copied into the new JSONObject. + * + * @param object + * An object that has fields that should be used to make a + * JSONObject. + * @param names + * An array of strings, the names of the fields to be obtained + * from the object. + */ + public JSONObject(Object object, String names[]) { + this(); + Class c = object.getClass(); + for (int i = 0; i < names.length; i += 1) { + String name = names[i]; + try { + this.putOpt(name, c.getField(name).get(object)); + } catch (Exception ignore) { + } + } + } + + /** + * Construct a JSONObject from a source JSON text string. This is the most + * commonly used JSONObject constructor. + * + * @param source + * A string beginning with { (left + * brace) and ending with } + *  (right brace). + * @exception JSONException + * If there is a syntax error in the source string or a + * duplicated key. + */ + public JSONObject(String source) throws JSONException { + this(new JSONTokener(source)); + } + + /** + * Construct a JSONObject from a ResourceBundle. + * + * @param baseName + * The ResourceBundle base name. + * @param locale + * The Locale to load the ResourceBundle for. + * @throws JSONException + * If any JSONExceptions are detected. + */ + public JSONObject(String baseName, Locale locale) throws JSONException { + this(); + ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, + Thread.currentThread().getContextClassLoader()); + +// Iterate through the keys in the bundle. + + Enumeration keys = bundle.getKeys(); + while (keys.hasMoreElements()) { + Object key = keys.nextElement(); + if (key != null) { + +// Go through the path, ensuring that there is a nested JSONObject for each +// segment except the last. Add the value using the last segment's name into +// the deepest nested JSONObject. + + String[] path = ((String) key).split("\\."); + int last = path.length - 1; + JSONObject target = this; + for (int i = 0; i < last; i += 1) { + String segment = path[i]; + JSONObject nextTarget = target.optJSONObject(segment); + if (nextTarget == null) { + nextTarget = new JSONObject(); + target.put(segment, nextTarget); + } + target = nextTarget; + } + target.put(path[last], bundle.getString((String) key)); + } + } + } + + /** + * Accumulate values under a key. It is similar to the put method except + * that if there is already an object stored under the key then a JSONArray + * is stored under the key to hold all of the accumulated values. If there + * is already a JSONArray, then the new value is appended to it. In + * contrast, the put method replaces the previous value. + * + * If only one value is accumulated that is not a JSONArray, then the result + * will be the same as using put. But if multiple values are accumulated, + * then the result will be like append. + * + * @param key + * A key string. + * @param value + * An object to be accumulated under the key. + * @return this. + * @throws JSONException + * If the value is an invalid number or if the key is null. + */ + public JSONObject accumulate(String key, Object value) throws JSONException { + testValidity(value); + Object object = this.opt(key); + if (object == null) { + this.put(key, + value instanceof JSONArray ? new JSONArray().put(value) + : value); + } else if (object instanceof JSONArray) { + ((JSONArray) object).put(value); + } else { + this.put(key, new JSONArray().put(object).put(value)); + } + return this; + } + + /** + * Append values to the array under a key. If the key does not exist in the + * JSONObject, then the key is put in the JSONObject with its value being a + * JSONArray containing the value parameter. If the key was already + * associated with a JSONArray, then the value parameter is appended to it. + * + * @param key + * A key string. + * @param value + * An object to be accumulated under the key. + * @return this. + * @throws JSONException + * If the key is null or if the current value associated with + * the key is not a JSONArray. + */ + public JSONObject append(String key, Object value) throws JSONException { + testValidity(value); + Object object = this.opt(key); + if (object == null) { + this.put(key, new JSONArray().put(value)); + } else if (object instanceof JSONArray) { + this.put(key, ((JSONArray) object).put(value)); + } else { + throw new JSONException("JSONObject[" + key + + "] is not a JSONArray."); + } + return this; + } + + /** + * Produce a string from a double. The string "null" will be returned if the + * number is not finite. + * + * @param d + * A double. + * @return A String. + */ + public static String doubleToString(double d) { + if (Double.isInfinite(d) || Double.isNaN(d)) { + return "null"; + } + +// Shave off trailing zeros and decimal point, if possible. + + String string = Double.toString(d); + if (string.indexOf('.') > 0 && string.indexOf('e') < 0 + && string.indexOf('E') < 0) { + while (string.endsWith("0")) { + string = string.substring(0, string.length() - 1); + } + if (string.endsWith(".")) { + string = string.substring(0, string.length() - 1); + } + } + return string; + } + + /** + * Get the value object associated with a key. + * + * @param key + * A key string. + * @return The object associated with the key. + * @throws JSONException + * if the key is not found. + */ + public Object get(String key) throws JSONException { + if (key == null) { + throw new JSONException("Null key."); + } + Object object = this.opt(key); + if (object == null) { + throw new JSONException("JSONObject[" + quote(key) + "] not found."); + } + return object; + } + + /** + * Get the enum value associated with a key. + * + * @param clazz + * The type of enum to retrieve. + * @param key + * A key string. + * @return The enum value associated with the key + * @throws JSONException + * if the key is not found or if the value cannot be converted + * to an enum. + */ + public > E getEnum(Class clazz, String key) throws JSONException { + E val = optEnum(clazz, key); + if(val==null) { + // JSONException should really take a throwable argument. + // If it did, I would re-implement this with the Enum.valueOf + // method and place any thrown exception in the JSONException + throw new JSONException("JSONObject[" + quote(key) + + "] is not an enum of type " + quote(clazz.getSimpleName()) + + "."); + } + return val; + } + + /** + * Get the boolean value associated with a key. + * + * @param key + * A key string. + * @return The truth. + * @throws JSONException + * if the value is not a Boolean or the String "true" or + * "false". + */ + public boolean getBoolean(String key) throws JSONException { + Object object = this.get(key); + if (object.equals(Boolean.FALSE) + || (object instanceof String && ((String) object) + .equalsIgnoreCase("false"))) { + return false; + } else if (object.equals(Boolean.TRUE) + || (object instanceof String && ((String) object) + .equalsIgnoreCase("true"))) { + return true; + } + throw new JSONException("JSONObject[" + quote(key) + + "] is not a Boolean."); + } + + /** + * Get the BigInteger value associated with a key. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value cannot + * be converted to BigInteger. + */ + public BigInteger getBigInteger(String key) throws JSONException { + Object object = this.get(key); + try { + return new BigInteger(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] could not be converted to BigInteger."); + } + } + + /** + * Get the BigDecimal value associated with a key. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value + * cannot be converted to BigDecimal. + */ + public BigDecimal getBigDecimal(String key) throws JSONException { + Object object = this.get(key); + try { + return new BigDecimal(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] could not be converted to BigDecimal."); + } + } + + /** + * Get the double value associated with a key. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value is not a Number + * object and cannot be converted to a number. + */ + public double getDouble(String key) throws JSONException { + Object object = this.get(key); + try { + return object instanceof Number ? ((Number) object).doubleValue() + : Double.parseDouble((String) object); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] is not a number."); + } + } + + /** + * Get the int value associated with a key. + * + * @param key + * A key string. + * @return The integer value. + * @throws JSONException + * if the key is not found or if the value cannot be converted + * to an integer. + */ + public int getInt(String key) throws JSONException { + Object object = this.get(key); + try { + return object instanceof Number ? ((Number) object).intValue() + : Integer.parseInt((String) object); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] is not an int."); + } + } + + /** + * Get the JSONArray value associated with a key. + * + * @param key + * A key string. + * @return A JSONArray which is the value. + * @throws JSONException + * if the key is not found or if the value is not a JSONArray. + */ + public JSONArray getJSONArray(String key) throws JSONException { + Object object = this.get(key); + if (object instanceof JSONArray) { + return (JSONArray) object; + } + throw new JSONException("JSONObject[" + quote(key) + + "] is not a JSONArray."); + } + + /** + * Get the JSONObject value associated with a key. + * + * @param key + * A key string. + * @return A JSONObject which is the value. + * @throws JSONException + * if the key is not found or if the value is not a JSONObject. + */ + public JSONObject getJSONObject(String key) throws JSONException { + Object object = this.get(key); + if (object instanceof JSONObject) { + return (JSONObject) object; + } + throw new JSONException("JSONObject[" + quote(key) + + "] is not a JSONObject."); + } + + /** + * Get the long value associated with a key. + * + * @param key + * A key string. + * @return The long value. + * @throws JSONException + * if the key is not found or if the value cannot be converted + * to a long. + */ + public long getLong(String key) throws JSONException { + Object object = this.get(key); + try { + return object instanceof Number ? ((Number) object).longValue() + : Long.parseLong((String) object); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] is not a long."); + } + } + + /** + * Get an array of field names from a JSONObject. + * + * @return An array of field names, or null if there are no names. + */ + public static String[] getNames(JSONObject jo) { + int length = jo.length(); + if (length == 0) { + return null; + } + Iterator iterator = jo.keys(); + String[] names = new String[length]; + int i = 0; + while (iterator.hasNext()) { + names[i] = iterator.next(); + i += 1; + } + return names; + } + + /** + * Get an array of field names from an Object. + * + * @return An array of field names, or null if there are no names. + */ + public static String[] getNames(Object object) { + if (object == null) { + return null; + } + Class klass = object.getClass(); + Field[] fields = klass.getFields(); + int length = fields.length; + if (length == 0) { + return null; + } + String[] names = new String[length]; + for (int i = 0; i < length; i += 1) { + names[i] = fields[i].getName(); + } + return names; + } + + /** + * Get the string associated with a key. + * + * @param key + * A key string. + * @return A string which is the value. + * @throws JSONException + * if there is no string value for the key. + */ + public String getString(String key) throws JSONException { + Object object = this.get(key); + if (object instanceof String) { + return (String) object; + } + throw new JSONException("JSONObject[" + quote(key) + "] not a string."); + } + + /** + * Determine if the JSONObject contains a specific key. + * + * @param key + * A key string. + * @return true if the key exists in the JSONObject. + */ + public boolean has(String key) { + return this.map.containsKey(key); + } + + /** + * Increment a property of a JSONObject. If there is no such property, + * create one with a value of 1. If there is such a property, and if it is + * an Integer, Long, Double, or Float, then add one to it. + * + * @param key + * A key string. + * @return this. + * @throws JSONException + * If there is already a property with this name that is not an + * Integer, Long, Double, or Float. + */ + public JSONObject increment(String key) throws JSONException { + Object value = this.opt(key); + if (value == null) { + this.put(key, 1); + } else if (value instanceof BigInteger) { + this.put(key, ((BigInteger)value).add(BigInteger.ONE)); + } else if (value instanceof BigDecimal) { + this.put(key, ((BigDecimal)value).add(BigDecimal.ONE)); + } else if (value instanceof Integer) { + this.put(key, (Integer) value + 1); + } else if (value instanceof Long) { + this.put(key, (Long) value + 1); + } else if (value instanceof Double) { + this.put(key, (Double) value + 1); + } else if (value instanceof Float) { + this.put(key, (Float) value + 1); + } else { + throw new JSONException("Unable to increment [" + quote(key) + "]."); + } + return this; + } + + /** + * Determine if the value associated with the key is null or if there is no + * value. + * + * @param key + * A key string. + * @return true if there is no value associated with the key or if the value + * is the JSONObject.NULL object. + */ + public boolean isNull(String key) { + return JSONObject.NULL.equals(this.opt(key)); + } + + /** + * Get an enumeration of the keys of the JSONObject. + * + * @return An iterator of the keys. + */ + public Iterator keys() { + return this.keySet().iterator(); + } + + /** + * Get a set of keys of the JSONObject. + * + * @return A keySet. + */ + public Set keySet() { + return this.map.keySet(); + } + + /** + * Get the number of keys stored in the JSONObject. + * + * @return The number of keys in the JSONObject. + */ + public int length() { + return this.map.size(); + } + + /** + * Produce a JSONArray containing the names of the elements of this + * JSONObject. + * + * @return A JSONArray containing the key strings, or null if the JSONObject + * is empty. + */ + public JSONArray names() { + JSONArray ja = new JSONArray(); + Iterator keys = this.keys(); + while (keys.hasNext()) { + ja.put(keys.next()); + } + return ja.length() == 0 ? null : ja; + } + + /** + * Produce a string from a Number. + * + * @param number + * A Number + * @return A String. + * @throws JSONException + * If n is a non-finite number. + */ + public static String numberToString(Number number) throws JSONException { + if (number == null) { + throw new JSONException("Null pointer"); + } + testValidity(number); + + // Shave off trailing zeros and decimal point, if possible. + + String string = number.toString(); + if (string.indexOf('.') > 0 && string.indexOf('e') < 0 + && string.indexOf('E') < 0) { + while (string.endsWith("0")) { + string = string.substring(0, string.length() - 1); + } + if (string.endsWith(".")) { + string = string.substring(0, string.length() - 1); + } + } + return string; + } + + /** + * Get an optional value associated with a key. + * + * @param key + * A key string. + * @return An object which is the value, or null if there is no value. + */ + public Object opt(String key) { + return key == null ? null : this.map.get(key); + } + + /** + * Get the enum value associated with a key. + * + * @param clazz + * The type of enum to retrieve. + * @param key + * A key string. + * @return The enum value associated with the key or null if not found + */ + public > E optEnum(Class clazz, String key) { + return this.optEnum(clazz, key, null); + } + + /** + * Get the enum value associated with a key. + * + * @param clazz + * The type of enum to retrieve. + * @param key + * A key string. + * @param defaultValue + * The default in case the value is not found + * @return The enum value associated with the key or defaultValue + * if the value is not found or cannot be assigned to clazz + */ + public > E optEnum(Class clazz, String key, E defaultValue) { + try { + Object val = this.opt(key); + if (NULL.equals(val)) { + return defaultValue; + } + if (clazz.isAssignableFrom(val.getClass())) { + // we just checked it! + @SuppressWarnings("unchecked") + E myE = (E) val; + return myE; + } + return Enum.valueOf(clazz, val.toString()); + } catch (IllegalArgumentException e) { + return defaultValue; + } catch (NullPointerException e) { + return defaultValue; + } + } + + /** + * Get an optional boolean associated with a key. It returns false if there + * is no such key, or if the value is not Boolean.TRUE or the String "true". + * + * @param key + * A key string. + * @return The truth. + */ + public boolean optBoolean(String key) { + return this.optBoolean(key, false); + } + + /** + * Get an optional boolean associated with a key. It returns the + * defaultValue if there is no such key, or if it is not a Boolean or the + * String "true" or "false" (case insensitive). + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return The truth. + */ + public boolean optBoolean(String key, boolean defaultValue) { + try { + return this.getBoolean(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional double associated with a key, or NaN if there is no such + * key or if its value is not a number. If the value is a string, an attempt + * will be made to evaluate it as a number. + * + * @param key + * A string which is the key. + * @return An object which is the value. + */ + public double optDouble(String key) { + return this.optDouble(key, Double.NaN); + } + + /** + * Get an optional BigInteger associated with a key, or the defaultValue if + * there is no such key or if its value is not a number. If the value is a + * string, an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public BigInteger optBigInteger(String key, BigInteger defaultValue) { + try { + return this.getBigInteger(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional BigDecimal associated with a key, or the defaultValue if + * there is no such key or if its value is not a number. If the value is a + * string, an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) { + try { + return this.getBigDecimal(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional double associated with a key, or the defaultValue if + * there is no such key or if its value is not a number. If the value is a + * string, an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public double optDouble(String key, double defaultValue) { + try { + return this.getDouble(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional int value associated with a key, or zero if there is no + * such key or if the value is not a number. If the value is a string, an + * attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @return An object which is the value. + */ + public int optInt(String key) { + return this.optInt(key, 0); + } + + /** + * Get an optional int value associated with a key, or the default if there + * is no such key or if the value is not a number. If the value is a string, + * an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public int optInt(String key, int defaultValue) { + try { + return this.getInt(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional JSONArray associated with a key. It returns null if there + * is no such key, or if its value is not a JSONArray. + * + * @param key + * A key string. + * @return A JSONArray which is the value. + */ + public JSONArray optJSONArray(String key) { + Object o = this.opt(key); + return o instanceof JSONArray ? (JSONArray) o : null; + } + + /** + * Get an optional JSONObject associated with a key. It returns null if + * there is no such key, or if its value is not a JSONObject. + * + * @param key + * A key string. + * @return A JSONObject which is the value. + */ + public JSONObject optJSONObject(String key) { + Object object = this.opt(key); + return object instanceof JSONObject ? (JSONObject) object : null; + } + + /** + * Get an optional long value associated with a key, or zero if there is no + * such key or if the value is not a number. If the value is a string, an + * attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @return An object which is the value. + */ + public long optLong(String key) { + return this.optLong(key, 0); + } + + /** + * Get an optional long value associated with a key, or the default if there + * is no such key or if the value is not a number. If the value is a string, + * an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public long optLong(String key, long defaultValue) { + try { + return this.getLong(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional string associated with a key. It returns an empty string + * if there is no such key. If the value is not a string and is not null, + * then it is converted to a string. + * + * @param key + * A key string. + * @return A string which is the value. + */ + public String optString(String key) { + return this.optString(key, ""); + } + + /** + * Get an optional string associated with a key. It returns the defaultValue + * if there is no such key. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return A string which is the value. + */ + public String optString(String key, String defaultValue) { + Object object = this.opt(key); + return NULL.equals(object) ? defaultValue : object.toString(); + } + + private void populateMap(Object bean) { + Class klass = bean.getClass(); + +// If klass is a System class then set includeSuperClass to false. + + boolean includeSuperClass = klass.getClassLoader() != null; + + Method[] methods = includeSuperClass ? klass.getMethods() : klass + .getDeclaredMethods(); + for (int i = 0; i < methods.length; i += 1) { + try { + Method method = methods[i]; + if (Modifier.isPublic(method.getModifiers())) { + String name = method.getName(); + String key = ""; + if (name.startsWith("get")) { + if ("getClass".equals(name) + || "getDeclaringClass".equals(name)) { + key = ""; + } else { + key = name.substring(3); + } + } else if (name.startsWith("is")) { + key = name.substring(2); + } + if (key.length() > 0 + && Character.isUpperCase(key.charAt(0)) + && method.getParameterTypes().length == 0) { + if (key.length() == 1) { + key = key.toLowerCase(Locale.ROOT); + } else if (!Character.isUpperCase(key.charAt(1))) { + key = key.substring(0, 1).toLowerCase(Locale.ROOT) + + key.substring(1); + } + + Object result = method.invoke(bean, (Object[]) null); + if (result != null) { + this.map.put(key, wrap(result)); + } + } + } + } catch (Exception ignore) { + } + } + } + + /** + * Put a key/boolean pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * A boolean which is the value. + * @return this. + * @throws JSONException + * If the key is null. + */ + public JSONObject put(String key, boolean value) throws JSONException { + this.put(key, value ? Boolean.TRUE : Boolean.FALSE); + return this; + } + + /** + * Put a key/value pair in the JSONObject, where the value will be a + * JSONArray which is produced from a Collection. + * + * @param key + * A key string. + * @param value + * A Collection value. + * @return this. + * @throws JSONException + */ + public JSONObject put(String key, Collection value) throws JSONException { + this.put(key, new JSONArray(value)); + return this; + } + + /** + * Put a key/double pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * A double which is the value. + * @return this. + * @throws JSONException + * If the key is null or if the number is invalid. + */ + public JSONObject put(String key, double value) throws JSONException { + this.put(key, new Double(value)); + return this; + } + + /** + * Put a key/int pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * An int which is the value. + * @return this. + * @throws JSONException + * If the key is null. + */ + public JSONObject put(String key, int value) throws JSONException { + this.put(key, new Integer(value)); + return this; + } + + /** + * Put a key/long pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * A long which is the value. + * @return this. + * @throws JSONException + * If the key is null. + */ + public JSONObject put(String key, long value) throws JSONException { + this.put(key, new Long(value)); + return this; + } + + /** + * Put a key/value pair in the JSONObject, where the value will be a + * JSONObject which is produced from a Map. + * + * @param key + * A key string. + * @param value + * A Map value. + * @return this. + * @throws JSONException + */ + public JSONObject put(String key, Map value) throws JSONException { + this.put(key, new JSONObject(value)); + return this; + } + + /** + * Put a key/value pair in the JSONObject. If the value is null, then the + * key will be removed from the JSONObject if it is present. + * + * @param key + * A key string. + * @param value + * An object which is the value. It should be of one of these + * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, + * String, or the JSONObject.NULL object. + * @return this. + * @throws JSONException + * If the value is non-finite number or if the key is null. + */ + public JSONObject put(String key, Object value) throws JSONException { + if (key == null) { + throw new NullPointerException("Null key."); + } + if (value != null) { + testValidity(value); + this.map.put(key, value); + } else { + this.remove(key); + } + return this; + } + + /** + * Put a key/value pair in the JSONObject, but only if the key and the value + * are both non-null, and only if there is not already a member with that + * name. + * + * @param key string + * @param value object + * @return this. + * @throws JSONException + * if the key is a duplicate + */ + public JSONObject putOnce(String key, Object value) throws JSONException { + if (key != null && value != null) { + if (this.opt(key) != null) { + throw new JSONException("Duplicate key \"" + key + "\""); + } + this.put(key, value); + } + return this; + } + + /** + * Put a key/value pair in the JSONObject, but only if the key and the value + * are both non-null. + * + * @param key + * A key string. + * @param value + * An object which is the value. It should be of one of these + * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, + * String, or the JSONObject.NULL object. + * @return this. + * @throws JSONException + * If the value is a non-finite number. + */ + public JSONObject putOpt(String key, Object value) throws JSONException { + if (key != null && value != null) { + this.put(key, value); + } + return this; + } + + /** + * Creates a JSONPointer using an intialization string and tries to + * match it to an item within this JSONObject. For example, given a + * JSONObject initialized with this document: + *
+     * {
+     *     "a":{"b":"c"}
+     * }
+     * 
+ * and this JSONPointer string: + *
+     * "/a/b"
+     * 
+ * Then this method will return the String "c". + * A JSONPointerException may be thrown from code called by this method. + * + * @param jsonPointer string that can be used to create a JSONPointer + * @return the item matched by the JSONPointer, otherwise null + */ + public Object query(String jsonPointer) { + return new JSONPointer(jsonPointer).queryFrom(this); + } + + /** + * Queries and returns a value from this object using {@code jsonPointer}, or + * returns null if the query fails due to a missing key. + * + * @param jsonPointer the string representation of the JSON pointer + * @return the queried value or {@code null} + * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax + */ + public Object optQuery(String jsonPointer) { + JSONPointer pointer = new JSONPointer(jsonPointer); + try { + return pointer.queryFrom(this); + } catch (JSONPointerException e) { + return null; + } + } + + /** + * Produce a string in double quotes with backslash sequences in all the + * right places. A backslash will be inserted within = '\u0080' && c < '\u00a0') + || (c >= '\u2000' && c < '\u2100')) { + w.write("\\u"); + hhhh = Integer.toHexString(c); + w.write("0000", 0, 4 - hhhh.length()); + w.write(hhhh); + } else { + w.write(c); + } + } + } + w.write('"'); + return w; + } + + /** + * Remove a name and its value, if present. + * + * @param key + * The name to be removed. + * @return The value that was associated with the name, or null if there was + * no value. + */ + public Object remove(String key) { + return this.map.remove(key); + } + + /** + * Determine if two JSONObjects are similar. + * They must contain the same set of names which must be associated with + * similar values. + * + * @param other The other JSONObject + * @return true if they are equal + */ + public boolean similar(Object other) { + try { + if (!(other instanceof JSONObject)) { + return false; + } + Set set = this.keySet(); + if (!set.equals(((JSONObject)other).keySet())) { + return false; + } + Iterator iterator = set.iterator(); + while (iterator.hasNext()) { + String name = iterator.next(); + Object valueThis = this.get(name); + Object valueOther = ((JSONObject)other).get(name); + if (valueThis instanceof JSONObject) { + if (!((JSONObject)valueThis).similar(valueOther)) { + return false; + } + } else if (valueThis instanceof JSONArray) { + if (!((JSONArray)valueThis).similar(valueOther)) { + return false; + } + } else if (!valueThis.equals(valueOther)) { + return false; + } + } + return true; + } catch (Throwable exception) { + return false; + } + } + + /** + * Try to convert a string into a number, boolean, or null. If the string + * can't be converted, return the string. + * + * @param string + * A String. + * @return A simple JSON value. + */ + public static Object stringToValue(String string) { + if (string.equals("")) { + return string; + } + if (string.equalsIgnoreCase("true")) { + return Boolean.TRUE; + } + if (string.equalsIgnoreCase("false")) { + return Boolean.FALSE; + } + if (string.equalsIgnoreCase("null")) { + return JSONObject.NULL; + } + + /* + * If it might be a number, try converting it. If a number cannot be + * produced, then the value will just be a string. + */ + + char initial = string.charAt(0); + if ((initial >= '0' && initial <= '9') || initial == '-') { + try { + if (string.indexOf('.') > -1 || string.indexOf('e') > -1 + || string.indexOf('E') > -1 + || "-0".equals(string)) { + Double d = Double.valueOf(string); + if (!d.isInfinite() && !d.isNaN()) { + return d; + } + } else { + Long myLong = new Long(string); + if (string.equals(myLong.toString())) { + if (myLong.longValue() == myLong.intValue()) { + return Integer.valueOf(myLong.intValue()); + } + return myLong; + } + } + } catch (Exception ignore) { + } + } + return string; + } + + /** + * Throw an exception if the object is a NaN or infinite number. + * + * @param o + * The object to test. + * @throws JSONException + * If o is a non-finite number. + */ + public static void testValidity(Object o) throws JSONException { + if (o != null) { + if (o instanceof Double) { + if (((Double) o).isInfinite() || ((Double) o).isNaN()) { + throw new JSONException( + "JSON does not allow non-finite numbers."); + } + } else if (o instanceof Float) { + if (((Float) o).isInfinite() || ((Float) o).isNaN()) { + throw new JSONException( + "JSON does not allow non-finite numbers."); + } + } + } + } + + /** + * Produce a JSONArray containing the values of the members of this + * JSONObject. + * + * @param names + * A JSONArray containing a list of key strings. This determines + * the sequence of the values in the result. + * @return A JSONArray of values. + * @throws JSONException + * If any of the values are non-finite numbers. + */ + public JSONArray toJSONArray(JSONArray names) throws JSONException { + if (names == null || names.length() == 0) { + return null; + } + JSONArray ja = new JSONArray(); + for (int i = 0; i < names.length(); i += 1) { + ja.put(this.opt(names.getString(i))); + } + return ja; + } + + /** + * Make a JSON text of this JSONObject. For compactness, no whitespace is + * added. If this would not result in a syntactically correct JSON text, + * then null will be returned instead. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return a printable, displayable, portable, transmittable representation + * of the object, beginning with { (left + * brace) and ending with } (right + * brace). + */ + @Override + public String toString() { + try { + return this.toString(0); + } catch (Exception e) { + return null; + } + } + + /** + * Make a prettyprinted JSON text of this JSONObject. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @return a printable, displayable, portable, transmittable representation + * of the object, beginning with { (left + * brace) and ending with } (right + * brace). + * @throws JSONException + * If the object contains an invalid number. + */ + public String toString(int indentFactor) throws JSONException { + StringWriter w = new StringWriter(); + synchronized (w.getBuffer()) { + return this.write(w, indentFactor, 0).toString(); + } + } + + /** + * Make a JSON text of an Object value. If the object has an + * value.toJSONString() method, then that method will be used to produce the + * JSON text. The method is required to produce a strictly conforming text. + * If the object does not contain a toJSONString method (which is the most + * common case), then a text will be produced by other means. If the value + * is an array or Collection, then a JSONArray will be made from it and its + * toJSONString method will be called. If the value is a MAP, then a + * JSONObject will be made from it and its toJSONString method will be + * called. Otherwise, the value's toString method will be called, and the + * result will be quoted. + * + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @param value + * The value to be serialized. + * @return a printable, displayable, transmittable representation of the + * object, beginning with { (left + * brace) and ending with } (right + * brace). + * @throws JSONException + * If the value is or contains an invalid number. + */ + public static String valueToString(Object value) throws JSONException { + if (value == null || value.equals(null)) { + return "null"; + } + if (value instanceof JSONString) { + Object object; + try { + object = ((JSONString) value).toJSONString(); + } catch (Exception e) { + throw new JSONException(e); + } + if (object instanceof String) { + return (String) object; + } + throw new JSONException("Bad value from toJSONString: " + object); + } + if (value instanceof Number) { + // not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex + final String numberAsString = numberToString((Number) value); + try { + // Use the BigDecimal constructor for it's parser to validate the format. + new BigDecimal(numberAsString); + // Close enough to a JSON number that we will return it unquoted + return numberAsString; + } catch (NumberFormatException ex){ + // The Number value is not a valid JSON number. + // Instead we will quote it as a string + return quote(numberAsString); + } + } + if (value instanceof Boolean || value instanceof JSONObject + || value instanceof JSONArray) { + return value.toString(); + } + if (value instanceof Map) { + Map map = (Map) value; + return new JSONObject(map).toString(); + } + if (value instanceof Collection) { + Collection coll = (Collection) value; + return new JSONArray(coll).toString(); + } + if (value.getClass().isArray()) { + return new JSONArray(value).toString(); + } + if(value instanceof Enum){ + return quote(((Enum)value).name()); + } + return quote(value.toString()); + } + + /** + * Wrap an object, if necessary. If the object is null, return the NULL + * object. If it is an array or collection, wrap it in a JSONArray. If it is + * a map, wrap it in a JSONObject. If it is a standard property (Double, + * String, et al) then it is already wrapped. Otherwise, if it comes from + * one of the java packages, turn it into a string. And if it doesn't, try + * to wrap it in a JSONObject. If the wrapping fails, then null is returned. + * + * @param object + * The object to wrap + * @return The wrapped value + */ + public static Object wrap(Object object) { + try { + if (object == null) { + return NULL; + } + if (object instanceof JSONObject || object instanceof JSONArray + || NULL.equals(object) || object instanceof JSONString + || object instanceof Byte || object instanceof Character + || object instanceof Short || object instanceof Integer + || object instanceof Long || object instanceof Boolean + || object instanceof Float || object instanceof Double + || object instanceof String || object instanceof BigInteger + || object instanceof BigDecimal || object instanceof Enum) { + return object; + } + + if (object instanceof Collection) { + Collection coll = (Collection) object; + return new JSONArray(coll); + } + if (object.getClass().isArray()) { + return new JSONArray(object); + } + if (object instanceof Map) { + Map map = (Map) object; + return new JSONObject(map); + } + Package objectPackage = object.getClass().getPackage(); + String objectPackageName = objectPackage != null ? objectPackage + .getName() : ""; + if (objectPackageName.startsWith("java.") + || objectPackageName.startsWith("javax.") + || object.getClass().getClassLoader() == null) { + return object.toString(); + } + return new JSONObject(object); + } catch (Exception exception) { + return null; + } + } + + /** + * Write the contents of the JSONObject as JSON text to a writer. For + * compactness, no whitespace is added. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return The writer. + * @throws JSONException + */ + public Writer write(Writer writer) throws JSONException { + return this.write(writer, 0, 0); + } + + static final Writer writeValue(Writer writer, Object value, + int indentFactor, int indent) throws JSONException, IOException { + if (value == null || value.equals(null)) { + writer.write("null"); + } else if (value instanceof JSONString) { + Object o; + try { + o = ((JSONString) value).toJSONString(); + } catch (Exception e) { + throw new JSONException(e); + } + writer.write(o != null ? o.toString() : quote(value.toString())); + } else if (value instanceof Number) { + // not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary + final String numberAsString = numberToString((Number) value); + try { + // Use the BigDecimal constructor for it's parser to validate the format. + @SuppressWarnings("unused") + BigDecimal testNum = new BigDecimal(numberAsString); + // Close enough to a JSON number that we will use it unquoted + writer.write(numberAsString); + } catch (NumberFormatException ex){ + // The Number value is not a valid JSON number. + // Instead we will quote it as a string + quote(numberAsString, writer); + } + } else if (value instanceof Boolean) { + writer.write(value.toString()); + } else if (value instanceof Enum) { + writer.write(quote(((Enum)value).name())); + } else if (value instanceof JSONObject) { + ((JSONObject) value).write(writer, indentFactor, indent); + } else if (value instanceof JSONArray) { + ((JSONArray) value).write(writer, indentFactor, indent); + } else if (value instanceof Map) { + Map map = (Map) value; + new JSONObject(map).write(writer, indentFactor, indent); + } else if (value instanceof Collection) { + Collection coll = (Collection) value; + new JSONArray(coll).write(writer, indentFactor, indent); + } else if (value.getClass().isArray()) { + new JSONArray(value).write(writer, indentFactor, indent); + } else { + quote(value.toString(), writer); + } + return writer; + } + + static final void indent(Writer writer, int indent) throws IOException { + for (int i = 0; i < indent; i += 1) { + writer.write(' '); + } + } + + /** + * Write the contents of the JSONObject as JSON text to a writer. For + * compactness, no whitespace is added. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @param writer + * Writes the serialized JSON + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @param indent + * The indention of the top level. + * @return The writer. + * @throws JSONException + */ + public Writer write(Writer writer, int indentFactor, int indent) + throws JSONException { + try { + boolean commanate = false; + final int length = this.length(); + Iterator keys = this.keys(); + writer.write('{'); + + if (length == 1) { + Object key = keys.next(); + writer.write(quote(key.toString())); + writer.write(':'); + if (indentFactor > 0) { + writer.write(' '); + } + writeValue(writer, this.map.get(key), indentFactor, indent); + } else if (length != 0) { + final int newindent = indent + indentFactor; + while (keys.hasNext()) { + Object key = keys.next(); + if (commanate) { + writer.write(','); + } + if (indentFactor > 0) { + writer.write('\n'); + } + indent(writer, newindent); + writer.write(quote(key.toString())); + writer.write(':'); + if (indentFactor > 0) { + writer.write(' '); + } + writeValue(writer, this.map.get(key), indentFactor, newindent); + commanate = true; + } + if (indentFactor > 0) { + writer.write('\n'); + } + indent(writer, indent); + } + writer.write('}'); + return writer; + } catch (IOException exception) { + throw new JSONException(exception); + } + } + + /** + * Returns a java.util.Map containing all of the entries in this object. + * If an entry in the object is a JSONArray or JSONObject it will also + * be converted. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return a java.util.Map containing the entries of this object + */ + public Map toMap() { + Map results = new HashMap(); + for (Entry entry : this.map.entrySet()) { + Object value; + if (entry.getValue() == null || NULL.equals(entry.getValue())) { + value = null; + } else if (entry.getValue() instanceof JSONObject) { + value = ((JSONObject) entry.getValue()).toMap(); + } else if (entry.getValue() instanceof JSONArray) { + value = ((JSONArray) entry.getValue()).toList(); + } else { + value = entry.getValue(); + } + results.put(entry.getKey(), value); + } + return results; + } +} diff --git a/src/org/json/JSONPointer.java b/src/org/json/JSONPointer.java new file mode 100644 index 0000000..82de7f9 --- /dev/null +++ b/src/org/json/JSONPointer.java @@ -0,0 +1,267 @@ +package org.json; + +import static java.lang.String.format; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.*; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * A JSON Pointer is a simple query language defined for JSON documents by + * RFC 6901. + * + * In a nutshell, JSONPointer allows the user to navigate into a JSON document + * using strings, and retrieve targeted objects, like a simple form of XPATH. + * Path segments are separated by the '/' char, which signifies the root of + * the document when it appears as the first char of the string. Array + * elements are navigated using ordinals, counting from 0. JSONPointer strings + * may be extended to any arbitrary number of segments. If the navigation + * is successful, the matched item is returned. A matched item may be a + * JSONObject, a JSONArray, or a JSON value. If the JSONPointer string building + * fails, an appropriate exception is thrown. If the navigation fails to find + * a match, a JSONPointerException is thrown. + * + * @author JSON.org + * @version 2016-05-14 + */ +public class JSONPointer { + + // used for URL encoding and decoding + private static final String ENCODING = "utf-8"; + + /** + * This class allows the user to build a JSONPointer in steps, using + * exactly one segment in each step. + */ + public static class Builder { + + // Segments for the eventual JSONPointer string + private final List refTokens = new ArrayList(); + + /** + * Creates a {@code JSONPointer} instance using the tokens previously set using the + * {@link #append(String)} method calls. + */ + public JSONPointer build() { + return new JSONPointer(refTokens); + } + + /** + * Adds an arbitary token to the list of reference tokens. It can be any non-null value. + * + * Unlike in the case of JSON string or URI fragment representation of JSON pointers, the + * argument of this method MUST NOT be escaped. If you want to query the property called + * {@code "a~b"} then you should simply pass the {@code "a~b"} string as-is, there is no + * need to escape it as {@code "a~0b"}. + * + * @param token the new token to be appended to the list + * @return {@code this} + * @throws NullPointerException if {@code token} is null + */ + public Builder append(String token) { + if (token == null) { + throw new NullPointerException("token cannot be null"); + } + refTokens.add(token); + return this; + } + + /** + * Adds an integer to the reference token list. Although not necessarily, mostly this token will + * denote an array index. + * + * @param arrayIndex the array index to be added to the token list + * @return {@code this} + */ + public Builder append(int arrayIndex) { + refTokens.add(String.valueOf(arrayIndex)); + return this; + } + } + + /** + * Static factory method for {@link Builder}. Example usage: + * + *


+     * JSONPointer pointer = JSONPointer.builder()
+     *       .append("obj")
+     *       .append("other~key").append("another/key")
+     *       .append("\"")
+     *       .append(0)
+     *       .build();
+     * 
+ * + * @return a builder instance which can be used to construct a {@code JSONPointer} instance by chained + * {@link Builder#append(String)} calls. + */ + public static Builder builder() { + return new Builder(); + } + + // Segments for the JSONPointer string + private final List refTokens; + + /** + * Pre-parses and initializes a new {@code JSONPointer} instance. If you want to + * evaluate the same JSON Pointer on different JSON documents then it is recommended + * to keep the {@code JSONPointer} instances due to performance considerations. + * + * @param pointer the JSON String or URI Fragment representation of the JSON pointer. + * @throws IllegalArgumentException if {@code pointer} is not a valid JSON pointer + */ + public JSONPointer(String pointer) { + if (pointer == null) { + throw new NullPointerException("pointer cannot be null"); + } + if (pointer.isEmpty() || pointer.equals("#")) { + refTokens = Collections.emptyList(); + return; + } + if (pointer.startsWith("#/")) { + pointer = pointer.substring(2); + try { + pointer = URLDecoder.decode(pointer, ENCODING); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } else if (pointer.startsWith("/")) { + pointer = pointer.substring(1); + } else { + throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'"); + } + refTokens = new ArrayList(); + for (String token : pointer.split("/")) { + refTokens.add(unescape(token)); + } + } + + public JSONPointer(List refTokens) { + this.refTokens = new ArrayList(refTokens); + } + + private String unescape(String token) { + return token.replace("~1", "/").replace("~0", "~") + .replace("\\\"", "\"") + .replace("\\\\", "\\"); + } + + /** + * Evaluates this JSON Pointer on the given {@code document}. The {@code document} + * is usually a {@link JSONObject} or a {@link JSONArray} instance, but the empty + * JSON Pointer ({@code ""}) can be evaluated on any JSON values and in such case the + * returned value will be {@code document} itself. + * + * @param document the JSON document which should be the subject of querying. + * @return the result of the evaluation + * @throws JSONPointerException if an error occurs during evaluation + */ + public Object queryFrom(Object document) { + if (refTokens.isEmpty()) { + return document; + } + Object current = document; + for (String token : refTokens) { + if (current instanceof JSONObject) { + current = ((JSONObject) current).opt(unescape(token)); + } else if (current instanceof JSONArray) { + current = readByIndexToken(current, token); + } else { + throw new JSONPointerException(format( + "value [%s] is not an array or object therefore its key %s cannot be resolved", current, + token)); + } + } + return current; + } + + /** + * Matches a JSONArray element by ordinal position + * @param current the JSONArray to be evaluated + * @param indexToken the array index in string form + * @return the matched object. If no matching item is found a + * JSONPointerException is thrown + */ + private Object readByIndexToken(Object current, String indexToken) { + try { + int index = Integer.parseInt(indexToken); + JSONArray currentArr = (JSONArray) current; + if (index >= currentArr.length()) { + throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index, + currentArr.length())); + } + return currentArr.get(index); + } catch (NumberFormatException e) { + throw new JSONPointerException(format("%s is not an array index", indexToken), e); + } + } + + /** + * Returns a string representing the JSONPointer path value using string + * representation + */ + @Override + public String toString() { + StringBuilder rval = new StringBuilder(""); + for (String token: refTokens) { + rval.append('/').append(escape(token)); + } + return rval.toString(); + } + + /** + * Escapes path segment values to an unambiguous form. + * The escape char to be inserted is '~'. The chars to be escaped + * are ~, which maps to ~0, and /, which maps to ~1. Backslashes + * and double quote chars are also escaped. + * @param token the JSONPointer segment value to be escaped + * @return the escaped value for the token + */ + private String escape(String token) { + return token.replace("~", "~0") + .replace("/", "~1") + .replace("\\", "\\\\") + .replace("\"", "\\\""); + } + + /** + * Returns a string representing the JSONPointer path value using URI + * fragment identifier representation + */ + public String toURIFragment() { + try { + StringBuilder rval = new StringBuilder("#"); + for (String token : refTokens) { + rval.append('/').append(URLEncoder.encode(token, ENCODING)); + } + return rval.toString(); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/org/json/JSONPointerException.java b/src/org/json/JSONPointerException.java new file mode 100644 index 0000000..0ce1aeb --- /dev/null +++ b/src/org/json/JSONPointerException.java @@ -0,0 +1,45 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * The JSONPointerException is thrown by {@link JSONPointer} if an error occurs + * during evaluating a pointer. + * + * @author JSON.org + * @version 2016-05-13 + */ +public class JSONPointerException extends JSONException { + private static final long serialVersionUID = 8872944667561856751L; + + public JSONPointerException(String message) { + super(message); + } + + public JSONPointerException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/org/json/JSONString.java b/src/org/json/JSONString.java new file mode 100644 index 0000000..1f2d77d --- /dev/null +++ b/src/org/json/JSONString.java @@ -0,0 +1,18 @@ +package org.json; +/** + * The JSONString interface allows a toJSONString() + * method so that a class can change the behavior of + * JSONObject.toString(), JSONArray.toString(), + * and JSONWriter.value(Object). The + * toJSONString method will be used instead of the default behavior + * of using the Object's toString() method and quoting the result. + */ +public interface JSONString { + /** + * The toJSONString method allows a class to produce its own JSON + * serialization. + * + * @return A strictly syntactically correct JSON text. + */ + public String toJSONString(); +} diff --git a/src/org/json/JSONStringer.java b/src/org/json/JSONStringer.java new file mode 100644 index 0000000..3ce1d55 --- /dev/null +++ b/src/org/json/JSONStringer.java @@ -0,0 +1,78 @@ +package org.json; + +/* +Copyright (c) 2006 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import java.io.StringWriter; + +/** + * JSONStringer provides a quick and convenient way of producing JSON text. + * The texts produced strictly conform to JSON syntax rules. No whitespace is + * added, so the results are ready for transmission or storage. Each instance of + * JSONStringer can produce one JSON text. + *

+ * A JSONStringer instance provides a value method for appending + * values to the + * text, and a key + * method for adding keys before values in objects. There are array + * and endArray methods that make and bound array values, and + * object and endObject methods which make and bound + * object values. All of these methods return the JSONWriter instance, + * permitting cascade style. For example,

+ * myString = new JSONStringer()
+ *     .object()
+ *         .key("JSON")
+ *         .value("Hello, World!")
+ *     .endObject()
+ *     .toString();
which produces the string
+ * {"JSON":"Hello, World!"}
+ *

+ * The first method called must be array or object. + * There are no methods for adding commas or colons. JSONStringer adds them for + * you. Objects and arrays can be nested up to 20 levels deep. + *

+ * This can sometimes be easier than using a JSONObject to build a string. + * @author JSON.org + * @version 2015-12-09 + */ +public class JSONStringer extends JSONWriter { + /** + * Make a fresh JSONStringer. It can be used to build one JSON text. + */ + public JSONStringer() { + super(new StringWriter()); + } + + /** + * Return the JSON text. This method is used to obtain the product of the + * JSONStringer instance. It will return null if there was a + * problem in the construction of the JSON text (such as the calls to + * array were not properly balanced with calls to + * endArray). + * @return The JSON text. + */ + public String toString() { + return this.mode == 'd' ? this.writer.toString() : null; + } +} diff --git a/src/org/json/JSONTokener.java b/src/org/json/JSONTokener.java new file mode 100644 index 0000000..d0b197d --- /dev/null +++ b/src/org/json/JSONTokener.java @@ -0,0 +1,475 @@ +package org.json; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * A JSONTokener takes a source string and extracts characters and tokens from + * it. It is used by the JSONObject and JSONArray constructors to parse + * JSON source strings. + * @author JSON.org + * @version 2014-05-03 + */ +public class JSONTokener { + + private long character; + private boolean eof; + private long index; + private long line; + private char previous; + private Reader reader; + private boolean usePrevious; + + + /** + * Construct a JSONTokener from a Reader. + * + * @param reader A reader. + */ + public JSONTokener(Reader reader) { + this.reader = reader.markSupported() + ? reader + : new BufferedReader(reader); + this.eof = false; + this.usePrevious = false; + this.previous = 0; + this.index = 0; + this.character = 1; + this.line = 1; + } + + + /** + * Construct a JSONTokener from an InputStream. + * @param inputStream The source. + */ + public JSONTokener(InputStream inputStream) { + this(new InputStreamReader(inputStream)); + } + + + /** + * Construct a JSONTokener from a string. + * + * @param s A source string. + */ + public JSONTokener(String s) { + this(new StringReader(s)); + } + + + /** + * Back up one character. This provides a sort of lookahead capability, + * so that you can test for a digit or letter before attempting to parse + * the next number or identifier. + * @throws JSONException Thrown if trying to step back more than 1 step + * or if already at the start of the string + */ + public void back() throws JSONException { + if (this.usePrevious || this.index <= 0) { + throw new JSONException("Stepping back two steps is not supported"); + } + this.index -= 1; + this.character -= 1; + this.usePrevious = true; + this.eof = false; + } + + + /** + * Get the hex value of a character (base16). + * @param c A character between '0' and '9' or between 'A' and 'F' or + * between 'a' and 'f'. + * @return An int between 0 and 15, or -1 if c was not a hex digit. + */ + public static int dehexchar(char c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } + if (c >= 'A' && c <= 'F') { + return c - ('A' - 10); + } + if (c >= 'a' && c <= 'f') { + return c - ('a' - 10); + } + return -1; + } + + /** + * @return true if at the end of the file and we didn't step back + */ + public boolean end() { + return this.eof && !this.usePrevious; + } + + + /** + * Determine if the source string still contains characters that next() + * can consume. + * @return true if not yet at the end of the source. + * @throws JSONException thrown if there is an error stepping forward + * or backward while checking for more data. + */ + public boolean more() throws JSONException { + this.next(); + if (this.end()) { + return false; + } + this.back(); + return true; + } + + + /** + * Get the next character in the source string. + * + * @return The next character, or 0 if past the end of the source string. + * @throws JSONException Thrown if there is an error reading the source string. + */ + public char next() throws JSONException { + int c; + if (this.usePrevious) { + this.usePrevious = false; + c = this.previous; + } else { + try { + c = this.reader.read(); + } catch (IOException exception) { + throw new JSONException(exception); + } + + if (c <= 0) { // End of stream + this.eof = true; + c = 0; + } + } + this.index += 1; + if (this.previous == '\r') { + this.line += 1; + this.character = c == '\n' ? 0 : 1; + } else if (c == '\n') { + this.line += 1; + this.character = 0; + } else { + this.character += 1; + } + this.previous = (char) c; + return this.previous; + } + + + /** + * Consume the next character, and check that it matches a specified + * character. + * @param c The character to match. + * @return The character. + * @throws JSONException if the character does not match. + */ + public char next(char c) throws JSONException { + char n = this.next(); + if (n != c) { + throw this.syntaxError("Expected '" + c + "' and instead saw '" + + n + "'"); + } + return n; + } + + + /** + * Get the next n characters. + * + * @param n The number of characters to take. + * @return A string of n characters. + * @throws JSONException + * Substring bounds error if there are not + * n characters remaining in the source string. + */ + public String next(int n) throws JSONException { + if (n == 0) { + return ""; + } + + char[] chars = new char[n]; + int pos = 0; + + while (pos < n) { + chars[pos] = this.next(); + if (this.end()) { + throw this.syntaxError("Substring bounds error"); + } + pos += 1; + } + return new String(chars); + } + + + /** + * Get the next char in the string, skipping whitespace. + * @throws JSONException Thrown if there is an error reading the source string. + * @return A character, or 0 if there are no more characters. + */ + public char nextClean() throws JSONException { + for (;;) { + char c = this.next(); + if (c == 0 || c > ' ') { + return c; + } + } + } + + + /** + * Return the characters up to the next close quote character. + * Backslash processing is done. The formal JSON format does not + * allow strings in single quotes, but an implementation is allowed to + * accept them. + * @param quote The quoting character, either + * " (double quote) or + * ' (single quote). + * @return A String. + * @throws JSONException Unterminated string. + */ + public String nextString(char quote) throws JSONException { + char c; + StringBuilder sb = new StringBuilder(); + for (;;) { + c = this.next(); + switch (c) { + case 0: + case '\n': + case '\r': + throw this.syntaxError("Unterminated string"); + case '\\': + c = this.next(); + switch (c) { + case 'b': + sb.append('\b'); + break; + case 't': + sb.append('\t'); + break; + case 'n': + sb.append('\n'); + break; + case 'f': + sb.append('\f'); + break; + case 'r': + sb.append('\r'); + break; + case 'u': + try { + sb.append((char)Integer.parseInt(this.next(4), 16)); + } catch (NumberFormatException e) { + throw this.syntaxError("Illegal escape.", e); + } + break; + case '"': + case '\'': + case '\\': + case '/': + sb.append(c); + break; + default: + throw this.syntaxError("Illegal escape."); + } + break; + default: + if (c == quote) { + return sb.toString(); + } + sb.append(c); + } + } + } + + + /** + * Get the text up but not including the specified character or the + * end of line, whichever comes first. + * @param delimiter A delimiter character. + * @return A string. + * @throws JSONException Thrown if there is an error while searching + * for the delimiter + */ + public String nextTo(char delimiter) throws JSONException { + StringBuilder sb = new StringBuilder(); + for (;;) { + char c = this.next(); + if (c == delimiter || c == 0 || c == '\n' || c == '\r') { + if (c != 0) { + this.back(); + } + return sb.toString().trim(); + } + sb.append(c); + } + } + + + /** + * Get the text up but not including one of the specified delimiter + * characters or the end of line, whichever comes first. + * @param delimiters A set of delimiter characters. + * @return A string, trimmed. + * @throws JSONException Thrown if there is an error while searching + * for the delimiter + */ + public String nextTo(String delimiters) throws JSONException { + char c; + StringBuilder sb = new StringBuilder(); + for (;;) { + c = this.next(); + if (delimiters.indexOf(c) >= 0 || c == 0 || + c == '\n' || c == '\r') { + if (c != 0) { + this.back(); + } + return sb.toString().trim(); + } + sb.append(c); + } + } + + + /** + * Get the next value. The value can be a Boolean, Double, Integer, + * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. + * @throws JSONException If syntax error. + * + * @return An object. + */ + public Object nextValue() throws JSONException { + char c = this.nextClean(); + String string; + + switch (c) { + case '"': + case '\'': + return this.nextString(c); + case '{': + this.back(); + return new JSONObject(this); + case '[': + this.back(); + return new JSONArray(this); + } + + /* + * Handle unquoted text. This could be the values true, false, or + * null, or it can be a number. An implementation (such as this one) + * is allowed to also accept non-standard forms. + * + * Accumulate characters until we reach the end of the text or a + * formatting character. + */ + + StringBuilder sb = new StringBuilder(); + while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { + sb.append(c); + c = this.next(); + } + this.back(); + + string = sb.toString().trim(); + if ("".equals(string)) { + throw this.syntaxError("Missing value"); + } + return JSONObject.stringToValue(string); + } + + + /** + * Skip characters until the next character is the requested character. + * If the requested character is not found, no characters are skipped. + * @param to A character to skip to. + * @return The requested character, or zero if the requested character + * is not found. + * @throws JSONException Thrown if there is an error while searching + * for the to character + */ + public char skipTo(char to) throws JSONException { + char c; + try { + long startIndex = this.index; + long startCharacter = this.character; + long startLine = this.line; + this.reader.mark(1000000); + do { + c = this.next(); + if (c == 0) { + this.reader.reset(); + this.index = startIndex; + this.character = startCharacter; + this.line = startLine; + return c; + } + } while (c != to); + } catch (IOException exception) { + throw new JSONException(exception); + } + this.back(); + return c; + } + + + /** + * Make a JSONException to signal a syntax error. + * + * @param message The error message. + * @return A JSONException object, suitable for throwing + */ + public JSONException syntaxError(String message) { + return new JSONException(message + this.toString()); + } + + /** + * Make a JSONException to signal a syntax error. + * + * @param message The error message. + * @param causedBy The throwable that caused the error. + * @return A JSONException object, suitable for throwing + */ + public JSONException syntaxError(String message, Throwable causedBy) { + return new JSONException(message + this.toString(), causedBy); + } + + /** + * Make a printable string of this JSONTokener. + * + * @return " at {index} [character {character} line {line}]" + */ + @Override + public String toString() { + return " at " + this.index + " [character " + this.character + " line " + + this.line + "]"; + } +} diff --git a/src/org/json/JSONWriter.java b/src/org/json/JSONWriter.java new file mode 100644 index 0000000..b7c8ea8 --- /dev/null +++ b/src/org/json/JSONWriter.java @@ -0,0 +1,326 @@ +package org.json; + +import java.io.IOException; + +/* +Copyright (c) 2006 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * JSONWriter provides a quick and convenient way of producing JSON text. + * The texts produced strictly conform to JSON syntax rules. No whitespace is + * added, so the results are ready for transmission or storage. Each instance of + * JSONWriter can produce one JSON text. + *

+ * A JSONWriter instance provides a value method for appending + * values to the + * text, and a key + * method for adding keys before values in objects. There are array + * and endArray methods that make and bound array values, and + * object and endObject methods which make and bound + * object values. All of these methods return the JSONWriter instance, + * permitting a cascade style. For example,

+ * new JSONWriter(myWriter)
+ *     .object()
+ *         .key("JSON")
+ *         .value("Hello, World!")
+ *     .endObject();
which writes
+ * {"JSON":"Hello, World!"}
+ *

+ * The first method called must be array or object. + * There are no methods for adding commas or colons. JSONWriter adds them for + * you. Objects and arrays can be nested up to 200 levels deep. + *

+ * This can sometimes be easier than using a JSONObject to build a string. + * @author JSON.org + * @version 2016-08-08 + */ +public class JSONWriter { + private static final int maxdepth = 200; + + /** + * The comma flag determines if a comma should be output before the next + * value. + */ + private boolean comma; + + /** + * The current mode. Values: + * 'a' (array), + * 'd' (done), + * 'i' (initial), + * 'k' (key), + * 'o' (object). + */ + protected char mode; + + /** + * The object/array stack. + */ + private final JSONObject stack[]; + + /** + * The stack top index. A value of 0 indicates that the stack is empty. + */ + private int top; + + /** + * The writer that will receive the output. + */ + protected Appendable writer; + + /** + * Make a fresh JSONWriter. It can be used to build one JSON text. + */ + public JSONWriter(Appendable w) { + this.comma = false; + this.mode = 'i'; + this.stack = new JSONObject[maxdepth]; + this.top = 0; + this.writer = w; + } + + /** + * Append a value. + * @param string A string value. + * @return this + * @throws JSONException If the value is out of sequence. + */ + private JSONWriter append(String string) throws JSONException { + if (string == null) { + throw new JSONException("Null pointer"); + } + if (this.mode == 'o' || this.mode == 'a') { + try { + if (this.comma && this.mode == 'a') { + this.writer.append(','); + } + this.writer.append(string); + } catch (IOException e) { + throw new JSONException(e); + } + if (this.mode == 'o') { + this.mode = 'k'; + } + this.comma = true; + return this; + } + throw new JSONException("Value out of sequence."); + } + + /** + * Begin appending a new array. All values until the balancing + * endArray will be appended to this array. The + * endArray method must be called to mark the array's end. + * @return this + * @throws JSONException If the nesting is too deep, or if the object is + * started in the wrong place (for example as a key or after the end of the + * outermost array or object). + */ + public JSONWriter array() throws JSONException { + if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') { + this.push(null); + this.append("["); + this.comma = false; + return this; + } + throw new JSONException("Misplaced array."); + } + + /** + * End something. + * @param mode Mode + * @param c Closing character + * @return this + * @throws JSONException If unbalanced. + */ + private JSONWriter end(char mode, char c) throws JSONException { + if (this.mode != mode) { + throw new JSONException(mode == 'a' + ? "Misplaced endArray." + : "Misplaced endObject."); + } + this.pop(mode); + try { + this.writer.append(c); + } catch (IOException e) { + throw new JSONException(e); + } + this.comma = true; + return this; + } + + /** + * End an array. This method most be called to balance calls to + * array. + * @return this + * @throws JSONException If incorrectly nested. + */ + public JSONWriter endArray() throws JSONException { + return this.end('a', ']'); + } + + /** + * End an object. This method most be called to balance calls to + * object. + * @return this + * @throws JSONException If incorrectly nested. + */ + public JSONWriter endObject() throws JSONException { + return this.end('k', '}'); + } + + /** + * Append a key. The key will be associated with the next value. In an + * object, every value must be preceded by a key. + * @param string A key string. + * @return this + * @throws JSONException If the key is out of place. For example, keys + * do not belong in arrays or if the key is null. + */ + public JSONWriter key(String string) throws JSONException { + if (string == null) { + throw new JSONException("Null key."); + } + if (this.mode == 'k') { + try { + this.stack[this.top - 1].putOnce(string, Boolean.TRUE); + if (this.comma) { + this.writer.append(','); + } + this.writer.append(JSONObject.quote(string)); + this.writer.append(':'); + this.comma = false; + this.mode = 'o'; + return this; + } catch (IOException e) { + throw new JSONException(e); + } + } + throw new JSONException("Misplaced key."); + } + + + /** + * Begin appending a new object. All keys and values until the balancing + * endObject will be appended to this object. The + * endObject method must be called to mark the object's end. + * @return this + * @throws JSONException If the nesting is too deep, or if the object is + * started in the wrong place (for example as a key or after the end of the + * outermost array or object). + */ + public JSONWriter object() throws JSONException { + if (this.mode == 'i') { + this.mode = 'o'; + } + if (this.mode == 'o' || this.mode == 'a') { + this.append("{"); + this.push(new JSONObject()); + this.comma = false; + return this; + } + throw new JSONException("Misplaced object."); + + } + + + /** + * Pop an array or object scope. + * @param c The scope to close. + * @throws JSONException If nesting is wrong. + */ + private void pop(char c) throws JSONException { + if (this.top <= 0) { + throw new JSONException("Nesting error."); + } + char m = this.stack[this.top - 1] == null ? 'a' : 'k'; + if (m != c) { + throw new JSONException("Nesting error."); + } + this.top -= 1; + this.mode = this.top == 0 + ? 'd' + : this.stack[this.top - 1] == null + ? 'a' + : 'k'; + } + + /** + * Push an array or object scope. + * @param jo The scope to open. + * @throws JSONException If nesting is too deep. + */ + private void push(JSONObject jo) throws JSONException { + if (this.top >= maxdepth) { + throw new JSONException("Nesting too deep."); + } + this.stack[this.top] = jo; + this.mode = jo == null ? 'a' : 'k'; + this.top += 1; + } + + + /** + * Append either the value true or the value + * false. + * @param b A boolean. + * @return this + * @throws JSONException + */ + public JSONWriter value(boolean b) throws JSONException { + return this.append(b ? "true" : "false"); + } + + /** + * Append a double value. + * @param d A double. + * @return this + * @throws JSONException If the number is not finite. + */ + public JSONWriter value(double d) throws JSONException { + return this.value(new Double(d)); + } + + /** + * Append a long value. + * @param l A long. + * @return this + * @throws JSONException + */ + public JSONWriter value(long l) throws JSONException { + return this.append(Long.toString(l)); + } + + + /** + * Append an object value. + * @param object The object to append. It can be null, or a Boolean, Number, + * String, JSONObject, or JSONArray, or an object that implements JSONString. + * @return this + * @throws JSONException If the value is out of sequence. + */ + public JSONWriter value(Object object) throws JSONException { + return this.append(JSONObject.valueToString(object)); + } +} diff --git a/src/org/json/Property.java b/src/org/json/Property.java new file mode 100644 index 0000000..73ddb12 --- /dev/null +++ b/src/org/json/Property.java @@ -0,0 +1,72 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Properties; + +/** + * Converts a Property file data into JSONObject and back. + * @author JSON.org + * @version 2015-05-05 + */ +public class Property { + /** + * Converts a property file object into a JSONObject. The property file object is a table of name value pairs. + * @param properties java.util.Properties + * @return JSONObject + * @throws JSONException + */ + public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException { + JSONObject jo = new JSONObject(); + if (properties != null && !properties.isEmpty()) { + Enumeration enumProperties = properties.propertyNames(); + while(enumProperties.hasMoreElements()) { + String name = (String)enumProperties.nextElement(); + jo.put(name, properties.getProperty(name)); + } + } + return jo; + } + + /** + * Converts the JSONObject into a property file object. + * @param jo JSONObject + * @return java.util.Properties + * @throws JSONException + */ + public static Properties toProperties(JSONObject jo) throws JSONException { + Properties properties = new Properties(); + if (jo != null) { + Iterator keys = jo.keys(); + while (keys.hasNext()) { + String name = keys.next(); + properties.put(name, jo.getString(name)); + } + } + return properties; + } +} diff --git a/src/org/json/XML.java b/src/org/json/XML.java new file mode 100644 index 0000000..78dd6a0 --- /dev/null +++ b/src/org/json/XML.java @@ -0,0 +1,621 @@ +package org.json; + +/* +Copyright (c) 2015 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import java.util.Iterator; + +/** + * This provides static methods to convert an XML text into a JSONObject, and to + * covert a JSONObject into an XML text. + * + * @author JSON.org + * @version 2016-08-10 + */ +@SuppressWarnings("boxing") +public class XML { + /** The Character '&'. */ + public static final Character AMP = '&'; + + /** The Character '''. */ + public static final Character APOS = '\''; + + /** The Character '!'. */ + public static final Character BANG = '!'; + + /** The Character '='. */ + public static final Character EQ = '='; + + /** The Character '>'. */ + public static final Character GT = '>'; + + /** The Character '<'. */ + public static final Character LT = '<'; + + /** The Character '?'. */ + public static final Character QUEST = '?'; + + /** The Character '"'. */ + public static final Character QUOT = '"'; + + /** The Character '/'. */ + public static final Character SLASH = '/'; + + /** + * Creates an iterator for navigating Code Points in a string instead of + * characters. Once Java7 support is dropped, this can be replaced with + * + * string.codePoints() + * + * which is available in Java8 and above. + * + * @see http://stackoverflow.com/a/21791059/6030888 + */ + private static Iterable codePointIterator(final String string) { + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + private int nextIndex = 0; + private int length = string.length(); + + @Override + public boolean hasNext() { + return this.nextIndex < this.length; + } + + @Override + public Integer next() { + int result = string.codePointAt(this.nextIndex); + this.nextIndex += Character.charCount(result); + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + + /** + * Replace special characters with XML escapes: + * + *

+     * & (ampersand) is replaced by &amp;
+     * < (less than) is replaced by &lt;
+     * > (greater than) is replaced by &gt;
+     * " (double quote) is replaced by &quot;
+     * ' (single quote / apostrophe) is replaced by &apos;
+     * 
+ * + * @param string + * The string to be escaped. + * @return The escaped string. + */ + public static String escape(String string) { + StringBuilder sb = new StringBuilder(string.length()); + for (final int cp : codePointIterator(string)) { + switch (cp) { + case '&': + sb.append("&"); + break; + case '<': + sb.append("<"); + break; + case '>': + sb.append(">"); + break; + case '"': + sb.append("""); + break; + case '\'': + sb.append("'"); + break; + default: + if (mustEscape(cp)) { + sb.append("&#x"); + sb.append(Integer.toHexString(cp)); + sb.append(";"); + } else { + sb.appendCodePoint(cp); + } + } + } + return sb.toString(); + } + + /** + * @param cp code point to test + * @return true if the code point is not valid for an XML + */ + private static boolean mustEscape(int cp) { + /* Valid range from https://www.w3.org/TR/REC-xml/#charsets + * + * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + * + * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. + */ + // isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F) + // all ISO control characters are out of range except tabs and new lines + return (Character.isISOControl(cp) + && cp != 0x9 + && cp != 0xA + && cp != 0xD + ) || !( + // valid the range of acceptable characters that aren't control + (cp >= 0x20 && cp <= 0xD7FF) + || (cp >= 0xE000 && cp <= 0xFFFD) + || (cp >= 0x10000 && cp <= 0x10FFFF) + ) + ; + } + + /** + * Removes XML escapes from the string. + * + * @param string + * string to remove escapes from + * @return string with converted entities + */ + public static String unescape(String string) { + StringBuilder sb = new StringBuilder(string.length()); + for (int i = 0, length = string.length(); i < length; i++) { + char c = string.charAt(i); + if (c == '&') { + final int semic = string.indexOf(';', i); + if (semic > i) { + final String entity = string.substring(i + 1, semic); + if (entity.charAt(0) == '#') { + int cp; + if (entity.charAt(1) == 'x') { + // hex encoded unicode + cp = Integer.parseInt(entity.substring(2), 16); + } else { + // decimal encoded unicode + cp = Integer.parseInt(entity.substring(1)); + } + sb.appendCodePoint(cp); + } else { + if ("quot".equalsIgnoreCase(entity)) { + sb.append('"'); + } else if ("amp".equalsIgnoreCase(entity)) { + sb.append('&'); + } else if ("apos".equalsIgnoreCase(entity)) { + sb.append('\''); + } else if ("lt".equalsIgnoreCase(entity)) { + sb.append('<'); + } else if ("gt".equalsIgnoreCase(entity)) { + sb.append('>'); + } else { + sb.append('&').append(entity).append(';'); + } + } + // skip past the entity we just parsed. + i += entity.length() + 1; + } else { + // this shouldn't happen in most cases since the parser + // errors on unclosed enties. + sb.append(c); + } + } else { + // not part of an entity + sb.append(c); + } + } + return sb.toString(); + } + + /** + * Throw an exception if the string contains whitespace. Whitespace is not + * allowed in tagNames and attributes. + * + * @param string + * A string. + * @throws JSONException Thrown if the string contains whitespace or is empty. + */ + public static void noSpace(String string) throws JSONException { + int i, length = string.length(); + if (length == 0) { + throw new JSONException("Empty string."); + } + for (i = 0; i < length; i += 1) { + if (Character.isWhitespace(string.charAt(i))) { + throw new JSONException("'" + string + + "' contains a space character."); + } + } + } + + /** + * Scan the content following the named tag, attaching it to the context. + * + * @param x + * The XMLTokener containing the source string. + * @param context + * The JSONObject that will include the new material. + * @param name + * The tag name. + * @return true if the close tag is processed. + * @throws JSONException + */ + private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings) + throws JSONException { + char c; + int i; + JSONObject jsonobject = null; + String string; + String tagName; + Object token; + + // Test for and skip past these forms: + // + // + // + // + // Report errors for these forms: + // <> + // <= + // << + + token = x.nextToken(); + + // "); + return false; + } + x.back(); + } else if (c == '[') { + token = x.nextToken(); + if ("CDATA".equals(token)) { + if (x.next() == '[') { + string = x.nextCDATA(); + if (string.length() > 0) { + context.accumulate("content", string); + } + return false; + } + } + throw x.syntaxError("Expected 'CDATA['"); + } + i = 1; + do { + token = x.nextMeta(); + if (token == null) { + throw x.syntaxError("Missing '>' after ' 0); + return false; + } else if (token == QUEST) { + + // "); + return false; + } else if (token == SLASH) { + + // Close tag + if (x.nextToken() != GT) { + throw x.syntaxError("Misshaped tag"); + } + if (jsonobject.length() > 0) { + context.accumulate(tagName, jsonobject); + } else { + context.accumulate(tagName, ""); + } + return false; + + } else if (token == GT) { + // Content, between <...> and + for (;;) { + token = x.nextContent(); + if (token == null) { + if (tagName != null) { + throw x.syntaxError("Unclosed tag " + tagName); + } + return false; + } else if (token instanceof String) { + string = (String) token; + if (string.length() > 0) { + jsonobject.accumulate("content", + keepStrings ? unescape(string) : stringToValue(string)); + } + + } else if (token == LT) { + // Nested element + if (parse(x, jsonobject, tagName,keepStrings)) { + if (jsonobject.length() == 0) { + context.accumulate(tagName, ""); + } else if (jsonobject.length() == 1 + && jsonobject.opt("content") != null) { + context.accumulate(tagName, + jsonobject.opt("content")); + } else { + context.accumulate(tagName, jsonobject); + } + return false; + } + } + } + } else { + throw x.syntaxError("Misshaped tag"); + } + } + } + } + + /** + * This method is the same as {@link JSONObject.stringToValue(String)} + * except that this also tries to unescape String values. + * + * @param string String to convert + * @return JSON value of this string or the string + */ + public static Object stringToValue(String string) { + Object ret = JSONObject.stringToValue(string); + if(ret instanceof String){ + return unescape((String)ret); + } + return ret; + } + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject. Some information may be lost in this transformation because + * JSON is a data format and XML is a document format. XML uses elements, + * attributes, and content text, while JSON uses unordered collections of + * name/value pairs and arrays of values. JSON does not does not like to + * distinguish between elements and attributes. Sequences of similar + * elements are represented as JSONArrays. Content text may be placed in a + * "content" member. Comments, prologs, DTDs, and <[ [ ]]> + * are ignored. + * + * @param string + * The source string. + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown if there is an errors while parsing the string + */ + public static JSONObject toJSONObject(String string) throws JSONException { + return toJSONObject(string, false); + } + + + /** + * Convert a well-formed (but not necessarily valid) XML string into a + * JSONObject. Some information may be lost in this transformation because + * JSON is a data format and XML is a document format. XML uses elements, + * attributes, and content text, while JSON uses unordered collections of + * name/value pairs and arrays of values. JSON does not does not like to + * distinguish between elements and attributes. Sequences of similar + * elements are represented as JSONArrays. Content text may be placed in a + * "content" member. Comments, prologs, DTDs, and <[ [ ]]> + * are ignored. + * + * All values are converted as strings, for 1, 01, 29.0 will not be coerced to + * numbers but will instead be the exact value as seen in the XML document. + * + * @param string + * The source string. + * @param keepStrings If true, then values will not be coerced into boolean + * or numeric values and will instead be left as strings + * @return A JSONObject containing the structured data from the XML string. + * @throws JSONException Thrown if there is an errors while parsing the string + */ + public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { + JSONObject jo = new JSONObject(); + XMLTokener x = new XMLTokener(string); + while (x.more() && x.skipPast("<")) { + parse(x, jo, null, keepStrings); + } + return jo; + } + /** + * Convert a JSONObject into a well-formed, element-normal XML string. + * + * @param object + * A JSONObject. + * @return A string. + * @throws JSONException Thrown if there is an error parsing the string + */ + public static String toString(Object object) throws JSONException { + return toString(object, null); + } + + /** + * Convert a JSONObject into a well-formed, element-normal XML string. + * + * @param object + * A JSONObject. + * @param tagName + * The optional name of the enclosing tag. + * @return A string. + * @throws JSONException Thrown if there is an error parsing the string + */ + public static String toString(Object object, String tagName) + throws JSONException { + StringBuilder sb = new StringBuilder(); + JSONArray ja; + JSONObject jo; + String key; + Iterator keys; + String string; + Object value; + + if (object instanceof JSONObject) { + + // Emit + if (tagName != null) { + sb.append('<'); + sb.append(tagName); + sb.append('>'); + } + + // Loop thru the keys. + jo = (JSONObject) object; + keys = jo.keys(); + while (keys.hasNext()) { + key = keys.next(); + value = jo.opt(key); + if (value == null) { + value = ""; + } else if (value.getClass().isArray()) { + value = new JSONArray(value); + } + string = value instanceof String ? (String) value : null; + + // Emit content in body + if ("content".equals(key)) { + if (value instanceof JSONArray) { + ja = (JSONArray) value; + int i = 0; + for (Object val : ja) { + if (i > 0) { + sb.append('\n'); + } + sb.append(escape(val.toString())); + i++; + } + } else { + sb.append(escape(value.toString())); + } + + // Emit an array of similar keys + + } else if (value instanceof JSONArray) { + ja = (JSONArray) value; + for (Object val : ja) { + if (val instanceof JSONArray) { + sb.append('<'); + sb.append(key); + sb.append('>'); + sb.append(toString(val)); + sb.append("'); + } else { + sb.append(toString(val, key)); + } + } + } else if ("".equals(value)) { + sb.append('<'); + sb.append(key); + sb.append("/>"); + + // Emit a new tag + + } else { + sb.append(toString(value, key)); + } + } + if (tagName != null) { + + // Emit the close tag + sb.append("'); + } + return sb.toString(); + + } + + if (object != null) { + if (object.getClass().isArray()) { + object = new JSONArray(object); + } + + if (object instanceof JSONArray) { + ja = (JSONArray) object; + for (Object val : ja) { + // XML does not have good support for arrays. If an array + // appears in a place where XML is lacking, synthesize an + // element. + sb.append(toString(val, tagName == null ? "array" : tagName)); + } + return sb.toString(); + } + } + + string = (object == null) ? "null" : escape(object.toString()); + return (tagName == null) ? "\"" + string + "\"" + : (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName + + ">" + string + ""; + + } +} diff --git a/src/org/json/XMLTokener.java b/src/org/json/XMLTokener.java new file mode 100644 index 0000000..e45e747 --- /dev/null +++ b/src/org/json/XMLTokener.java @@ -0,0 +1,365 @@ +package org.json; + +/* +Copyright (c) 2002 JSON.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/** + * The XMLTokener extends the JSONTokener to provide additional methods + * for the parsing of XML texts. + * @author JSON.org + * @version 2015-12-09 + */ +public class XMLTokener extends JSONTokener { + + + /** The table of entity values. It initially contains Character values for + * amp, apos, gt, lt, quot. + */ + public static final java.util.HashMap entity; + + static { + entity = new java.util.HashMap(8); + entity.put("amp", XML.AMP); + entity.put("apos", XML.APOS); + entity.put("gt", XML.GT); + entity.put("lt", XML.LT); + entity.put("quot", XML.QUOT); + } + + /** + * Construct an XMLTokener from a string. + * @param s A source string. + */ + public XMLTokener(String s) { + super(s); + } + + /** + * Get the text in the CDATA block. + * @return The string up to the ]]>. + * @throws JSONException If the ]]> is not found. + */ + public String nextCDATA() throws JSONException { + char c; + int i; + StringBuilder sb = new StringBuilder(); + for (;;) { + c = next(); + if (end()) { + throw syntaxError("Unclosed CDATA"); + } + sb.append(c); + i = sb.length() - 3; + if (i >= 0 && sb.charAt(i) == ']' && + sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') { + sb.setLength(i); + return sb.toString(); + } + } + } + + + /** + * Get the next XML outer token, trimming whitespace. There are two kinds + * of tokens: the '<' character which begins a markup tag, and the content + * text between markup tags. + * + * @return A string, or a '<' Character, or null if there is no more + * source text. + * @throws JSONException + */ + public Object nextContent() throws JSONException { + char c; + StringBuilder sb; + do { + c = next(); + } while (Character.isWhitespace(c)); + if (c == 0) { + return null; + } + if (c == '<') { + return XML.LT; + } + sb = new StringBuilder(); + for (;;) { + if (c == '<' || c == 0) { + back(); + return sb.toString().trim(); + } + if (c == '&') { + sb.append(nextEntity(c)); + } else { + sb.append(c); + } + c = next(); + } + } + + + /** + * Return the next entity. These entities are translated to Characters: + * & ' > < ". + * @param ampersand An ampersand character. + * @return A Character or an entity String if the entity is not recognized. + * @throws JSONException If missing ';' in XML entity. + */ + public Object nextEntity(char ampersand) throws JSONException { + StringBuilder sb = new StringBuilder(); + for (;;) { + char c = next(); + if (Character.isLetterOrDigit(c) || c == '#') { + sb.append(Character.toLowerCase(c)); + } else if (c == ';') { + break; + } else { + throw syntaxError("Missing ';' in XML entity: &" + sb); + } + } + String string = sb.toString(); + Object object = entity.get(string); + return object != null ? object : ampersand + string + ";"; + } + + + /** + * Returns the next XML meta token. This is used for skipping over + * and structures. + * @return Syntax characters (< > / = ! ?) are returned as + * Character, and strings and names are returned as Boolean. We don't care + * what the values actually are. + * @throws JSONException If a string is not properly closed or if the XML + * is badly structured. + */ + public Object nextMeta() throws JSONException { + char c; + char q; + do { + c = next(); + } while (Character.isWhitespace(c)); + switch (c) { + case 0: + throw syntaxError("Misshaped meta tag"); + case '<': + return XML.LT; + case '>': + return XML.GT; + case '/': + return XML.SLASH; + case '=': + return XML.EQ; + case '!': + return XML.BANG; + case '?': + return XML.QUEST; + case '"': + case '\'': + q = c; + for (;;) { + c = next(); + if (c == 0) { + throw syntaxError("Unterminated string"); + } + if (c == q) { + return Boolean.TRUE; + } + } + default: + for (;;) { + c = next(); + if (Character.isWhitespace(c)) { + return Boolean.TRUE; + } + switch (c) { + case 0: + case '<': + case '>': + case '/': + case '=': + case '!': + case '?': + case '"': + case '\'': + back(); + return Boolean.TRUE; + } + } + } + } + + + /** + * Get the next XML Token. These tokens are found inside of angle + * brackets. It may be one of these characters: / > = ! ? or it + * may be a string wrapped in single quotes or double quotes, or it may be a + * name. + * @return a String or a Character. + * @throws JSONException If the XML is not well formed. + */ + public Object nextToken() throws JSONException { + char c; + char q; + StringBuilder sb; + do { + c = next(); + } while (Character.isWhitespace(c)); + switch (c) { + case 0: + throw syntaxError("Misshaped element"); + case '<': + throw syntaxError("Misplaced '<'"); + case '>': + return XML.GT; + case '/': + return XML.SLASH; + case '=': + return XML.EQ; + case '!': + return XML.BANG; + case '?': + return XML.QUEST; + +// Quoted string + + case '"': + case '\'': + q = c; + sb = new StringBuilder(); + for (;;) { + c = next(); + if (c == 0) { + throw syntaxError("Unterminated string"); + } + if (c == q) { + return sb.toString(); + } + if (c == '&') { + sb.append(nextEntity(c)); + } else { + sb.append(c); + } + } + default: + +// Name + + sb = new StringBuilder(); + for (;;) { + sb.append(c); + c = next(); + if (Character.isWhitespace(c)) { + return sb.toString(); + } + switch (c) { + case 0: + return sb.toString(); + case '>': + case '/': + case '=': + case '!': + case '?': + case '[': + case ']': + back(); + return sb.toString(); + case '<': + case '"': + case '\'': + throw syntaxError("Bad character in a name"); + } + } + } + } + + + /** + * Skip characters until past the requested string. + * If it is not found, we are left at the end of the source with a result of false. + * @param to A string to skip past. + * @throws JSONException + */ + public boolean skipPast(String to) throws JSONException { + boolean b; + char c; + int i; + int j; + int offset = 0; + int length = to.length(); + char[] circle = new char[length]; + + /* + * First fill the circle buffer with as many characters as are in the + * to string. If we reach an early end, bail. + */ + + for (i = 0; i < length; i += 1) { + c = next(); + if (c == 0) { + return false; + } + circle[i] = c; + } + + /* We will loop, possibly for all of the remaining characters. */ + + for (;;) { + j = offset; + b = true; + + /* Compare the circle buffer with the to string. */ + + for (i = 0; i < length; i += 1) { + if (circle[j] != to.charAt(i)) { + b = false; + break; + } + j += 1; + if (j >= length) { + j -= length; + } + } + + /* If we exit the loop with b intact, then victory is ours. */ + + if (b) { + return true; + } + + /* Get the next character. If there isn't one, then defeat is ours. */ + + c = next(); + if (c == 0) { + return false; + } + /* + * Shove the character in the circle buffer and advance the + * circle offset. The offset is mod n. + */ + circle[offset] = c; + offset += 1; + if (offset >= length) { + offset -= length; + } + } + } +} diff --git a/src/sig/ReadFile.java b/src/sig/ReadFile.java new file mode 100644 index 0000000..b27a12a --- /dev/null +++ b/src/sig/ReadFile.java @@ -0,0 +1,378 @@ +package sig; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import sig.utils.FileUtils; + +public class ReadFile { + + final static int HPMOD = 15; //15% normal HP. + final static int DMGMOD = 35; //35% normal damage. + static HashMap> VALID_EVENTS = new HashMap>(); + final static Integer RIGHT = 195; + final static Integer LEFT = 196; + final static Integer UP = 198; + final static Integer DOWN = 199; + final static Integer DIRECTION_MODIFIERS = -9999; + final static Integer DIRECTION_HORZ_MODIFIERS = -9998; + + public static void main(String[] args) { + + + VALID_EVENTS.put(1003,null); + VALID_EVENTS.put(1004,null); + VALID_EVENTS.put(1005,Arrays.asList(UP,DOWN)); + VALID_EVENTS.put(1006,Arrays.asList(UP,DOWN)); + VALID_EVENTS.put(1007,Arrays.asList(UP,DOWN,LEFT,RIGHT)); + VALID_EVENTS.put(1008,Arrays.asList(RIGHT)); + VALID_EVENTS.put(1009,null); + VALID_EVENTS.put(1010,null); + VALID_EVENTS.put(1011,null); + VALID_EVENTS.put(1012,null); + VALID_EVENTS.put(1013,null); + VALID_EVENTS.put(1014,null); + VALID_EVENTS.put(1015,null); + VALID_EVENTS.put(1016,null); + VALID_EVENTS.put(1017,Arrays.asList(0,1,2,3,4,5,6,7,8,9,10,11,12)); + VALID_EVENTS.put(1018,null); + VALID_EVENTS.put(1019,Arrays.asList(UP,DOWN,LEFT,RIGHT)); + VALID_EVENTS.put(1020,null); + VALID_EVENTS.put(1021,null); + VALID_EVENTS.put(1022,Arrays.asList(0,5)); + VALID_EVENTS.put(1023,null); + VALID_EVENTS.put(1024,null); + VALID_EVENTS.put(1025,null); + VALID_EVENTS.put(1027,null); + VALID_EVENTS.put(1028,null); + VALID_EVENTS.put(1030,null); + VALID_EVENTS.put(1031,null); + VALID_EVENTS.put(1032,Arrays.asList(0,1)); + VALID_EVENTS.put(1033,Arrays.asList(0,1)); + VALID_EVENTS.put(1035,Arrays.asList(0,1,2,3)); + VALID_EVENTS.put(1036,Arrays.asList(1,2,3)); + VALID_EVENTS.put(1037,null); + VALID_EVENTS.put(1038,null); + VALID_EVENTS.put(1039,null); + VALID_EVENTS.put(1043,null); + VALID_EVENTS.put(1045,Arrays.asList(0,5)); + VALID_EVENTS.put(1046,Arrays.asList(0,1,2,3,4,5)); + VALID_EVENTS.put(1053,null); + VALID_EVENTS.put(1054,null); + VALID_EVENTS.put(1055,Arrays.asList(0,3)); + VALID_EVENTS.put(1056,Arrays.asList(1,0)); + VALID_EVENTS.put(1096,Arrays.asList(0,2,5,6,7)); + VALID_EVENTS.put(1097,Arrays.asList(0,1,2,5,6,7)); + VALID_EVENTS.put(1098,null); + VALID_EVENTS.put(1099,null); + VALID_EVENTS.put(1102,null); + VALID_EVENTS.put(1100,Arrays.asList(0,1)); + VALID_EVENTS.put(1101,Arrays.asList(0,1,2,3,4,5)); + VALID_EVENTS.put(1103,null); + VALID_EVENTS.put(1105,Arrays.asList(0,2,5,6,7)); + VALID_EVENTS.put(1104,null); + VALID_EVENTS.put(1106,Arrays.asList(0,1)); + VALID_EVENTS.put(1107,null); + VALID_EVENTS.put(1108,Arrays.asList(0,1)); + VALID_EVENTS.put(1109,Arrays.asList(0,1)); + VALID_EVENTS.put(1110,null); + VALID_EVENTS.put(1111,Arrays.asList(0,1,2,3,4,5)); + VALID_EVENTS.put(1112,Arrays.asList(0,1,2,3,4)); + VALID_EVENTS.put(1113,Arrays.asList(0,1,2,3,4,5)); + VALID_EVENTS.put(1114,Arrays.asList(0,1,2,3,4,5)); + VALID_EVENTS.put(1115,null); + VALID_EVENTS.put(1116,Arrays.asList(0,1,2,3,4)); + VALID_EVENTS.put(1117,Arrays.asList(0,1,2,3)); + VALID_EVENTS.put(1118,Arrays.asList(0,1,2,3)); + VALID_EVENTS.put(1119,Arrays.asList(0,1,2,3)); + VALID_EVENTS.put(1120,Arrays.asList(0,1,2,3)); + VALID_EVENTS.put(1124,null); + VALID_EVENTS.put(1125,Arrays.asList(0,1,2,3,4,5,DIRECTION_MODIFIERS)); + VALID_EVENTS.put(1126,Arrays.asList(0,1,2,3,4,5,6,7,8,9,10)); + VALID_EVENTS.put(1127,Arrays.asList(0,1)); //Arrays.asList(0,1) + VALID_EVENTS.put(1128,null); + VALID_EVENTS.put(1129,Arrays.asList(0,1,2)); + VALID_EVENTS.put(1130,Arrays.asList(0,1,2,3,4,5,6)); + VALID_EVENTS.put(1131,null); + VALID_EVENTS.put(1132,Arrays.asList(0,1,2,3)); + VALID_EVENTS.put(1133,Arrays.asList(0,1,5)); + VALID_EVENTS.put(1134,null); + VALID_EVENTS.put(1135,Arrays.asList(0,1)); + VALID_EVENTS.put(1136,Arrays.asList(0,1,2,3,4)); + VALID_EVENTS.put(1137,Arrays.asList(0,1,DIRECTION_HORZ_MODIFIERS)); + VALID_EVENTS.put(1138,Arrays.asList(0,2)); + VALID_EVENTS.put(1139,Arrays.asList(0,1,2,3)); + VALID_EVENTS.put(1140,Arrays.asList(0,1,2,3,4)); + VALID_EVENTS.put(1141,null); + VALID_EVENTS.put(1142,null); + VALID_EVENTS.put(1143,null); + VALID_EVENTS.put(1144,Arrays.asList(0,1,2)); + VALID_EVENTS.put(1145,Arrays.asList(0,1,2)); + VALID_EVENTS.put(1146,Arrays.asList(0,1,2,3,4)); + VALID_EVENTS.put(1147,Arrays.asList(0,1)); + VALID_EVENTS.put(1148,Arrays.asList(0,1)); + VALID_EVENTS.put(1149,Arrays.asList(0,1,2)); + VALID_EVENTS.put(1150,Arrays.asList(0,1,2,3,4,5)); + VALID_EVENTS.put(1151,null); + VALID_EVENTS.put(1152,Arrays.asList(0,1)); + VALID_EVENTS.put(1153,null); + VALID_EVENTS.put(1154,Arrays.asList(0,1,2,3,4,5)); + VALID_EVENTS.put(1155,null); + VALID_EVENTS.put(1156,Arrays.asList(0,1,5,6)); + VALID_EVENTS.put(1157,null); + VALID_EVENTS.put(1158,Arrays.asList(0,5,6)); + VALID_EVENTS.put(1159,Arrays.asList(0,1,2,3,4)); + VALID_EVENTS.put(1160,Arrays.asList(0,1,2,3,4)); + VALID_EVENTS.put(1161,null); + VALID_EVENTS.put(1162,null); + VALID_EVENTS.put(1163,Arrays.asList(0,1,3,4,5,6,7)); + VALID_EVENTS.put(1164,Arrays.asList(0,1,2,3,4,5)); + VALID_EVENTS.put(1174,Arrays.asList(UP,DOWN,LEFT,RIGHT)); + VALID_EVENTS.put(1001,null); + VALID_EVENTS.put(1002,null); + VALID_EVENTS.put(1047,null); + VALID_EVENTS.put(1048,null); + VALID_EVENTS.put(1165,null); + VALID_EVENTS.put(1166,null); + + try { + for (int l=0;l=5000) { + //Found a valid adjacent tile. Track it. + stopAdjacentTileSearch = true; + } + } + if (adjtilex-tilex==32) { + rightIsFree=false; + } + if (tiley-adjtiley==32) { + topIsFree=false; + } + if (!rightIsFree && !topIsFree && stopAdjacentTileSearch) { + break; + } + } else { + System.out.println(adjtile); + } + } + Integer[] values = new Integer[VALID_EVENTS.keySet().size()]; + values = VALID_EVENTS.keySet().toArray(values); + //Pick a random value. + int slot = (int)(Math.random()*values.length); + tile.put("name", values[slot]); + if (VALID_EVENTS.get(values[slot])!=null) { + //see if there's an adjacent tile already and change that one to a random value. Otherwise make a new one. + if (adjtile==null) { + JSONObject obj = new JSONObject(); + if (topIsFree) { + obj.put("y", tiley-32); + obj.put("x", tilex); + topIsFree=false; + } else + if (rightIsFree){ + obj.put("y", tiley); + obj.put("x", tilex+32); + rightIsFree=false; + } + obj.put("width", 32); + obj.put("height", 32); + int tileID = SelectRandomModifier(VALID_EVENTS.get(values[slot]),objects,tilex,tiley,topIsFree,rightIsFree); + obj.put("name",Integer.toString(tileID)); + if (tileID!=-1) { + objects.put(obj); + } + } else { + int tileID = SelectRandomModifier(VALID_EVENTS.get(values[slot]),objects,tilex,tiley,topIsFree,rightIsFree); + if (tileID!=-1) { + adjtile.put("name", Integer.toString(tileID)); + } + } + } + } + } + AddRandomBossTile(objects,13088,4480,1,args[l]); //Pandora + AddRandomBossTile(objects,7520,3776,3,args[l]); //Rita + AddRandomBossTile(objects,6560,2784,4,args[l]); //Ashuri 2 + AddRandomBossTile(objects,14912,1248,4,args[l]); //Saya + AddRandomBossTile(objects,3200,6016,2,args[l]); //Kotri 1 + AddRandomBossTile(objects,9472,2432,1,args[l]); //Kotri 2 + AddRandomBossTile(objects,14400,5312,0,args[l]); //Cicini + AddRandomBossTile(objects,9888,2432,9,args[l]); //Syaro + AddRandomBossTile(objects,10496,5312,2,args[l]); //Chocolate + AddRandomBossTile(objects,9216,1696,2,args[l]); //Vanilla + AddRandomBossTile(objects,7712,2432,3,args[l]); //Nixie + AddRandomBossTile(objects,1632,1344,3,args[l]); //Nieve + AddRandomBossTile(objects,3520,1696,0,args[l]); //Aruraune + AddRandomBossTile(objects,14944,992,0,args[l]); //Lilith + AddRandomBossTile(objects,7296,5824,3,args[l]); //Seana + AddRandomBossTile(objects,8608,1664,6,args[l]); //Keke Bunny + AddRandomBossTile(objects,5152,2784,8,args[l]); //Illusion Alius I + AddRandomBossTile(objects,6144,2784,8,args[l]); //Illusion Alius II + AddRandomBossTile(objects,8800,2784,8,args[l]); //Illusion Alius III + AddRandomBossTile(objects,10560,6016,1,args[l]); //Shadow Pandora + AddRandomBossTile(objects,9408,1696,3,args[l]); //Shadow Rita + } + } + String[] json = new String[] {data.toString()}; + FileUtils.writetoFile(json, args[l]); + } + } catch (JSONException | IOException e) { + e.printStackTrace(); + } + } + + private static void AddTile(JSONArray objects,int x,int y,int event,int area,String currentArea) { + if (currentArea.contains("area"+area+".json")) { + JSONObject obj = new JSONObject(); + obj.put("x", x); + obj.put("y", y); + obj.put("name", Integer.toString(event)); //ENEMY HP MOD + obj.put("width", 32); + obj.put("height", 32); + objects.put(obj); + } + } + private static void AddRandomBossTile(JSONArray objects,int x,int y,int area,String currentArea) { + if (currentArea.contains("area"+area+".json")) { + int[] events = {1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1020,1021,1022,1023,1024,1025,1030,1031,1032,1033,1035,1036,1037,1038,1039,1043,1045,1046,1053,1054,1056}; + + + int chance=1; + int count=0; + while (true) { + if (Math.random()*chance<=1) { + JSONObject obj = new JSONObject(); + obj.put("x", x); + obj.put("y", y-count*32); + obj.put("name", Integer.toString(events[(int)(Math.random()*events.length)])); //ENEMY HP MOD + obj.put("width", 32); + obj.put("height", 32); + objects.put(obj); + } else { + break; + } + chance*=5; + count++; + } + } + } + + private static void AddHelperTiles(JSONArray objects) { + //Trust me, you want these... + for (int i=0;i<12;i++) { + JSONObject obj = new JSONObject(); + obj.put("x", 4064); + obj.put("y", 3168-i*32); + obj.put("name", "571"); //ENEMY HP MOD + obj.put("width", 32); + obj.put("height", 32); + objects.put(obj); + obj = new JSONObject(); + obj.put("x", 4096); + obj.put("y", 3168-i*32); + obj.put("name", Integer.toString(HPMOD)); + obj.put("width", 32); + obj.put("height", 32); + objects.put(obj); + obj = new JSONObject(); + obj.put("x", 4160); + obj.put("y", 3168-i*32); + obj.put("name", "572"); //ENEMY DMG MOD + obj.put("width", 32); + obj.put("height", 32); + objects.put(obj); + obj = new JSONObject(); + obj.put("x", 4192); + obj.put("y", 3168-i*32); + obj.put("name", Integer.toString(DMGMOD)); + obj.put("width", 32); + obj.put("height", 32); + objects.put(obj); + } + } + + private static int SelectRandomModifier(List list,JSONArray objects,int tilex,int tiley,boolean top, boolean right) { + List finalList = new ArrayList(); + if (list!=null) { + if (list.contains(DIRECTION_MODIFIERS) || list.contains(DIRECTION_HORZ_MODIFIERS)) { + Integer[] randDir = null; + if (list.contains(DIRECTION_MODIFIERS)) { + randDir = new Integer[] {RIGHT,LEFT,UP,DOWN}; + } else { + randDir = new Integer[] {RIGHT,LEFT}; + } + for (int i=0;i0) { + AttributedString as = new AttributedString(message); + as.addAttribute(TextAttribute.FONT, font); + as.addAttribute(TextAttribute.KERNING,TextAttribute.KERNING_ON); + as.addAttribute(TextAttribute.WIDTH,TextAttribute.WIDTH_EXTENDED); + as.addAttribute(TextAttribute.TRACKING,0.5); + g.setColor(shadow_color); + Graphics2D g2 = (Graphics2D) g; + FontRenderContext frc = g2.getFontMetrics(font).getFontRenderContext(); + GlyphVector gv = font.createGlyphVector(frc, message); + Shape shape = gv.getOutline((int)(x+xoffset),(int)(y+yoffset)); + g2.setClip(null); + g2.setStroke(new BasicStroke(font_thickness + outline_thickness*2)); + g2.setColor(shadow_color); + g2.setRenderingHint( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2.draw(shape); + GlyphVector gv2 = font.createGlyphVector(frc, message); + Shape shape2 = gv2.getOutline((int)(x+xoffset),(int)(y+yoffset)); + g2.setClip(null); + g2.setStroke(new BasicStroke(font_thickness)); + g2.setColor(text_color); + g2.setRenderingHint( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2.draw(shape2); + g2.setColor(text_color); + g2.drawString(as.getIterator(),(int)(x+xoffset),(int)(y+yoffset)); + } + } + public static void drawCenteredOutlineText(Graphics g, Font font, double x, double y, int font_size, int outline_size, Color text_color, Color shadow_color, String message) { + Rectangle2D textBounds = TextUtils.calculateStringBoundsFont(message, font); + drawOutlineText(g,font,x,y,-textBounds.getWidth()/2,-textBounds.getHeight()/2,font_size,outline_size,text_color,shadow_color,message); + } + public static void drawCenteredOutlineText(Graphics g, Font font, double x, double y, int outline_size, Color text_color, Color shadow_color, String message) { + drawCenteredOutlineText(g,font,x,y,1,outline_size,text_color,shadow_color,message); + } + public static void drawText(Graphics g, double x, double y, Color color, String message) { + if (message.length()>0) { + AttributedString as = new AttributedString(message); + as.addAttribute(TextAttribute.FONT, MyPanel.programFont); + g.setColor(color); + g.drawString(as.getIterator(),(int)x,(int)y); + } + } + public static void drawTextFont(Graphics g, Font font, double x, double y, Color color, String message) { + if (message.length()>0) { + AttributedString as = new AttributedString(message); + as.addAttribute(TextAttribute.FONT, font); + g.setColor(color); + g.drawString(as.getIterator(),(int)x,(int)y); + } + } + public static void drawHealthbar(Graphics g, Rectangle bounds, double pct, Color healthbarcol) { + g.setColor(Color.BLACK); + g.draw3DRect((int)bounds.getX(), (int)bounds.getY(), (int)bounds.getWidth(), (int)bounds.getHeight(), true); + g.setColor(healthbarcol); + g.fill3DRect((int)bounds.getX()+1, (int)bounds.getY()+1, (int)(bounds.getWidth()*pct)-1, (int)bounds.getHeight()-1, true); + } + /** + * Centers the text along the X Axis. + */ + public static void drawCenteredText(Graphics g, Font font, int x, int y, Color color, String text) { + AttributedString as = new AttributedString(text); + as.addAttribute(TextAttribute.FONT, font); + g.setColor(color); + Rectangle2D textBounds = TextUtils.calculateStringBoundsFont(text, font); + g.drawString(as.getIterator(),(int)(x-textBounds.getWidth()/2),(int)(y+textBounds.getHeight())); + } + + public static Color convertStringToColor(String s) { + String[] split = s.split(","); + if (split.length==3) { + return new Color( + Math.min(Math.abs(Integer.parseInt(split[0])),255), + Math.min(Math.abs(Integer.parseInt(split[1])),255), + Math.min(Math.abs(Integer.parseInt(split[2])),255)); + } else + if (split.length==4) { + return new Color( + Math.min(Math.abs(Integer.parseInt(split[0])),255), + Math.min(Math.abs(Integer.parseInt(split[1])),255), + Math.min(Math.abs(Integer.parseInt(split[2])),255), + Math.min(Math.abs(Integer.parseInt(split[3])),255)); + } else { + System.out.println("WARNING! Invalid Color string specified ("+s+")."); + return null; + } + } + + public static void drawImage(Graphics g, Image img, double x, double y, Color blend_col, ImageObserver source) { + BufferedImage tmp = new BufferedImage(img.getWidth(source),img.getHeight(source),BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = tmp.createGraphics(); + g2.drawImage(img, 0, 0, null); + g2.setComposite(AlphaComposite.SrcAtop); + g2.setColor(blend_col); + g2.fillRect(0, 0, img.getWidth(source), img.getHeight(source)); + g2.dispose(); + g.drawImage(tmp,(int)x,(int)y,source); + } + + public static void drawImageScaled(Graphics g, Image img, double x, double y, double xsize, double ysize, Color blend_col, ImageObserver source) { + BufferedImage tmp = new BufferedImage(img.getWidth(source),img.getHeight(source),BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = tmp.createGraphics(); + g2.drawImage(img, 0, 0, null); + g2.setComposite(AlphaComposite.SrcAtop); + g2.setColor(blend_col); + g2.fillRect(0, 0, img.getWidth(source), img.getHeight(source)); + g2.dispose(); + g.drawImage(tmp,(int)x,(int)y,(int)xsize,(int)ysize,source); + } + + public static Color invertColor(Color c) { + return new Color(255-c.getRed(),255-c.getGreen(),255-c.getBlue(),255); + } +} diff --git a/src/sig/utils/FileUtils.java b/src/sig/utils/FileUtils.java new file mode 100644 index 0000000..7a47a55 --- /dev/null +++ b/src/sig/utils/FileUtils.java @@ -0,0 +1,348 @@ +package sig.utils; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.Reader; +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import sig.sigIRC; +import sig.modules.RabiRaceModule; +import sig.modules.ChatLog.ChatLogMessage; + +public class FileUtils { + public static String[] readFromFile(String filename) { + File file = new File(filename); + //System.out.println(file.getAbsolutePath()); + List contents= new ArrayList(); + if (file.exists()) { + try( + FileReader fw = new FileReader(filename); + BufferedReader bw = new BufferedReader(fw);) + { + String readline = bw.readLine(); + do { + if (readline!=null) { + //System.out.println(readline); + contents.add(readline); + readline = bw.readLine(); + }} while (readline!=null); + fw.close(); + bw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return contents.toArray(new String[contents.size()]); + } + + private static String readAll(Reader rd) throws IOException { + StringBuilder sb = new StringBuilder(); + int cp; + while ((cp = rd.read()) != -1) { + sb.append((char) cp); + } + return sb.toString(); + } + + private static String readFilter(Reader rd, HashMap channel_ids) throws IOException { + StringBuilder sb = new StringBuilder(); + boolean allowed=false; + boolean quotation_mark=false; + boolean endquotation_mark=false; + boolean foundChannel=false; + boolean nextBrace=false; + boolean outputStuff=false; + String numb = ""; + int braceCount=0; + int channelCount=0; + int vals=0; + int cp; + while ((cp = rd.read()) != -1) { + if (braceCount==0) { + allowed=true; + } else + if (braceCount==1 && !quotation_mark){ + quotation_mark=true; + numb=""; + allowed=false; + } else + if (!endquotation_mark) { + if ((char)cp >= '0' && + (char)cp <= '9') { + allowed=false; + numb+=(char)cp; + } else { + allowed=false; + endquotation_mark=true; + try { + if (channel_ids.containsKey(Long.parseLong(numb))) { + if (channelCount>=1) { + sb.append(","); + } + sb.append("\""+numb+"\""); + foundChannel=true; + System.out.println("Found channel "+numb); + outputStuff=true; + } + } catch (NumberFormatException e) { + + } + } + } else + if (!nextBrace && foundChannel) { + allowed=true; + if ((char)cp == '{') { + nextBrace=true; + } + } else + if (foundChannel) { + allowed=true; + if (braceCount==1) { + allowed=false; + channelCount++; + quotation_mark=false; + endquotation_mark=false; + foundChannel=false; + nextBrace=false; + } + } else { + allowed=false; + if (braceCount==1) { + allowed=false; + quotation_mark=false; + endquotation_mark=false; + foundChannel=false; + nextBrace=false; + } + } + + /*if (outputStuff && vals++<1000) { + System.out.print((char)cp); + }*/ + if ((char)cp == '{') { + braceCount++; + //System.out.println("Brace count is "+braceCount+"."); + } else + if ((char)cp == '}') { + braceCount--; + //System.out.println("Brace count is "+braceCount+"."); + } + + if (allowed) { + sb.append((char) cp); + } + } + sb.append("}"); + //System.out.println("============="); + //System.out.println(sb.toString()); + return sb.toString(); + } + + public static JSONObject readJsonFromUrlWithFilter(String url, HashMap filter) throws IOException, JSONException { + return readJsonFromUrlWithFilter(url,filter,null,false); + } + + public static JSONObject readJsonFromFileWithFilter(String file, HashMap filter) throws IOException, JSONException { + InputStream is = new FileInputStream(new File(file)); + try { + BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); + String jsonText = readFilter(rd,filter); + JSONObject json = new JSONObject(jsonText); + jsonText=null; + return json; + } finally { + is.close(); + } + } + + public static JSONObject readJsonFromUrlWithFilter(String url, HashMap filter, String file, boolean writeToFile) throws IOException, JSONException { + InputStream is = new URL(url).openStream(); + try { + BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); + String jsonText = readFilter(rd,filter); + if (writeToFile) { + writetoFile(new String[]{jsonText},file); + } + JSONObject json = new JSONObject(jsonText); + return json; + } finally { + is.close(); + } + } + + public static JSONObject readJsonFromUrl(String url) throws IOException, JSONException { + return readJsonFromUrl(url,null,false); + } + + public static JSONArray readJsonArrayFromUrl(String url) throws IOException, JSONException { + return readJsonArrayFromUrl(url,null,false); + } + + public static JSONObject readJsonFromFile(String file) throws IOException, JSONException { + InputStream is = new FileInputStream(new File(file)); + try { + BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); + String jsonText = readAll(rd); + JSONObject json = new JSONObject(jsonText); + jsonText=null; + return json; + } finally { + is.close(); + } + } + + public static JSONObject readJsonFromUrl(String url, String file, boolean writeToFile) throws IOException, JSONException { + InputStream is = new URL(url).openStream(); + try { + BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); + String jsonText = readAll(rd); + if (writeToFile) { + writetoFile(new String[]{jsonText},file); + } + JSONObject json = new JSONObject(jsonText); + return json; + } finally { + is.close(); + } + } + + public static JSONArray readJsonArrayFromUrl(String url, String file, boolean writeToFile) throws IOException, JSONException { + InputStream is = new URL(url).openStream(); + try { + BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); + String jsonText = readAll(rd); + if (writeToFile) { + writetoFile(new String[]{jsonText},file); + } + JSONArray json = new JSONArray(jsonText); + return json; + } finally { + is.close(); + } + } + + public static void logToFile(String message, String filename) { + if ((!filename.equalsIgnoreCase("debug.log") && + !filename.equalsIgnoreCase("debug2.log")) || (filename.equalsIgnoreCase("debug.log") && RabiRaceModule.DEBUGMODE==1) + || + (filename.equalsIgnoreCase("debug2.log") && RabiRaceModule.DEBUGMODE==2) + ) { + logToFile(message,filename,false); + } + } + + public static void logToFile(String message, String filename, boolean outputToChatLog) { + File file = new File(filename); + try { + + if (!file.exists()) { + file.createNewFile(); + } + + FileWriter fw = new FileWriter(file, true); + PrintWriter pw = new PrintWriter(fw); + + pw.println(message); + pw.flush(); + pw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + if (outputToChatLog && sigIRC.chatlogmodule_enabled) { + ChatLogMessage.importMessages(message); + } + } + + public static void writetoFile(String[] data, String filename) { + File file = new File(filename); + try { + + if (!file.exists()) { + file.createNewFile(); + } + + FileWriter fw = new FileWriter(file,false); + PrintWriter pw = new PrintWriter(fw); + + for (String s : data) { + pw.println(s); + } + pw.flush(); + pw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void copyFile(File source, File dest) throws IOException { + FileChannel sourceChannel = null; + FileChannel destChannel = null; + try { + sourceChannel = new FileInputStream(source).getChannel(); + destChannel = new FileOutputStream(dest).getChannel(); + destChannel.transferFrom(sourceChannel, 0, sourceChannel.size()); + }finally{ + sourceChannel.close(); + destChannel.close(); + } + } + + public static void deleteFile(String filename) { + File file = new File(filename); + if (file.exists()) { + file.delete(); + } + } + + + public static void downloadFileFromUrl(String url, String file,boolean bearer) throws IOException, JSONException { + File filer = new File(file); + filer.createNewFile(); + + URL website = new URL(url); + HttpURLConnection connection = (HttpURLConnection) website.openConnection(); + /*for (String s : connection.getHeaderFields().keySet()) { + System.out.println(s+": "+connection.getHeaderFields().get(s)); + }*/ + connection.setRequestMethod("GET"); + //connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("Accept", "application/vnd.twitchtv.v5+json"); + connection.setRequestProperty("Authorization", ((bearer)?"Bearer":"OAuth") + " "+sigIRC.oauth.replace("oauth:", "")); + if (sigIRC.CLIENTID.length()!=0) { + connection.setRequestProperty("Client-ID", sigIRC.CLIENTID); + //System.out.println("Using "+ sigIRC.oauth+"/"+sigIRC.CLIENTID); + } + try { + ReadableByteChannel rbc = Channels.newChannel(connection.getInputStream()); + FileOutputStream fos = new FileOutputStream(file); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + } catch (ConnectException e) { + System.out.println("Failed to connect, moving on..."); + } + } + + public static void downloadFileFromUrl(String url, String file) throws IOException, JSONException { + downloadFileFromUrl(url,file,false); //Uses OAUTH instead of Bearer + } +} diff --git a/src/sig/utils/GithubUtils.java b/src/sig/utils/GithubUtils.java new file mode 100644 index 0000000..7cd1579 --- /dev/null +++ b/src/sig/utils/GithubUtils.java @@ -0,0 +1,35 @@ +package sig.utils; + +import java.io.IOException; +import java.util.Arrays; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public class GithubUtils { + public static int getSizeOfFileFromLatestGithubCommit(String filename) { + try { + JSONObject data = FileUtils.readJsonFromUrl("https://api.github.com/repos/sigonasr2/sigIRCv2"); + String url = data.getString("commits_url").replace("{/sha}", ""); + JSONArray data_array = FileUtils.readJsonArrayFromUrl(url); + JSONObject dat = data_array.getJSONObject(0); + JSONObject datapoint1 = dat.getJSONObject("commit"); + datapoint1 = datapoint1.getJSONObject("tree"); + url = datapoint1.getString("url"); + data = FileUtils.readJsonFromUrl(url); + data_array = data.getJSONArray("tree"); + for (int i=0;i=0) { + String piece1 = sourcestring.substring(0,pos); + String piece2 = sourcestring.substring(pos+findstring.length(),sourcestring.length()); + //basemsg = basemsg.replaceFirst(e.getEmoteName(),e.getSpaceFiller()); + sourcestring = piece1+replacestring+piece2; + } + return sourcestring; + } + + public static boolean isAlphanumeric(String str) { + return str.matches("^[a-zA-Z0-9!\\-.?'\":,\\+ ]+$"); + } + + public static boolean isNumeric(String str) + { + if (str.length()>0) { + return str.matches("-?\\d+(\\.\\d+)?"); //match a number with optional '-' and decimal. + } else { + return false; + } + } + + public static boolean isInteger(String s, int radix) { + if(s.isEmpty()) return false; + for(int i = 0; i < s.length(); i++) { + if(i == 0 && s.charAt(i) == '-') { + if(s.length() == 1) return false; + else continue; + } + if(Character.digit(s.charAt(i),radix) < 0) return false; + } + return true; + } + + public static String convertSecondsToTimeFormat(int seconds) { + StringBuilder sb = new StringBuilder(); + int sec = seconds%60; + int min = (seconds/60)%60; + int hrs = (seconds/3600)%24; + if (hrs>0) { + if (hrs>=10) { + sb.append(hrs); + } else { + sb.append(0); + sb.append(hrs); + } + sb.append(":"); + } + if (min>=10) { + sb.append(min); + } else { + sb.append(0); + sb.append(min); + } + sb.append(":"); + if (sec>=10) { + sb.append(sec); + } else { + sb.append(0); + sb.append(sec); + } + return sb.toString(); + } + + public static String getActualChannelName() { + return sigIRC.channel.replaceFirst("#", ""); + } + + /** + * Converts a three CSV value to RGB value. + */ + public static Color convertStringToColor(String col) { + String[] split = col.split(","); + return new Color(Integer.parseInt(split[0]),Integer.parseInt(split[1]),Integer.parseInt(split[2])); + } + + public static List WrapText(String msg, Font font, double width) { + List displayMessage = new ArrayList(); + String rawmessage = msg; + int textWidth = (int)TextUtils.calculateStringBoundsFont(rawmessage, font).getWidth(); + int maxWidth = (int)width; + do { + rawmessage = BreakTextAtNextSection(rawmessage+" ",font,displayMessage,maxWidth); + textWidth = (int)TextUtils.calculateStringBoundsFont(rawmessage, font).getWidth(); + } while (textWidth>maxWidth); + if (rawmessage.length()>0) { + displayMessage.add(rawmessage); + } + return displayMessage; + //System.out.println(displayMessage+": "+messageDisplaySize); + } + + private static String BreakTextAtNextSection(String msg, Font font, List list, int maxWidth) { + int marker = 1; + int textWidth = (int)TextUtils.calculateStringBoundsFont(msg.substring(0, marker), font).getWidth(); + while (textWidth0) { + string.append(days); + } + if (hours>0) { + string.append(((string.length()>0)?":":"")+(hours%24)); + } + if (minutes>0) { + string.append(((string.length()>0)?":":"")+df.format((minutes%60))); + } + if (seconds>0) { + string.append(((string.length()>0)?":":"")+df.format((seconds%60))); + } + return string.toString(); + } +}