Return-Path: Delivered-To: apmail-couchdb-dev-archive@www.apache.org Received: (qmail 13757 invoked from network); 5 Apr 2011 10:01:12 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 5 Apr 2011 10:01:12 -0000 Received: (qmail 16937 invoked by uid 500); 5 Apr 2011 10:01:11 -0000 Delivered-To: apmail-couchdb-dev-archive@couchdb.apache.org Received: (qmail 16901 invoked by uid 500); 5 Apr 2011 10:01:11 -0000 Mailing-List: contact dev-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list dev@couchdb.apache.org Received: (qmail 16893 invoked by uid 99); 5 Apr 2011 10:01:11 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 05 Apr 2011 10:01:11 +0000 X-ASF-Spam-Status: No, hits=-0.7 required=5.0 tests=FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS,T_TO_NO_BRKTS_FREEMAIL X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of bchesneau@gmail.com designates 209.85.210.180 as permitted sender) Received: from [209.85.210.180] (HELO mail-iy0-f180.google.com) (209.85.210.180) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 05 Apr 2011 10:01:05 +0000 Received: by mail-iy0-f180.google.com with SMTP id 40so320552iyf.11 for ; Tue, 05 Apr 2011 03:00:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:in-reply-to:references:date :message-id:subject:from:to:content-type:content-transfer-encoding; bh=NrlGpaWuaUy6CEavzsMpBqu6i88+iFp3bCm7n7dzXuU=; b=mPZIZjK7HPs3InJRsljtyvNgfIJTZYWJIZydf91dGWvaLdQmb0tS4efBYTDbX2zcyy uX2yC4FqIpuuaY7CU9tDcGoYm9PM533jP9CRaqt1MN8RKb9RPrfBYWqtI3QH+Y9R3U9Y UpP6mGP9vE8tqE50bbdkBUHr3wmEF1FOu0+aE= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type:content-transfer-encoding; b=W6A59FX3ewqW+oUrvgWycle0dBVzEcRwnDyuqDS1Oc+rhux3t1L1BKUaYHxeWWtb3Q w8uBFFymhR/0GJdBFSqkmxJwWB8a4bpIeI69J0IBicW4+K0/BxTjhtd6air81ljhjE19 e9Y2YFTsKtJeTJRT5uIm0+uUIiR9XaMBqQO4Q= MIME-Version: 1.0 Received: by 10.43.70.137 with SMTP id yg9mr1266926icb.218.1301997644377; Tue, 05 Apr 2011 03:00:44 -0700 (PDT) Received: by 10.231.34.200 with HTTP; Tue, 5 Apr 2011 03:00:44 -0700 (PDT) In-Reply-To: References: <20110405094243.410D92388A1C@eris.apache.org> Date: Tue, 5 Apr 2011 12:00:44 +0200 Message-ID: Subject: Re: svn commit: r1088941 [1/3] - in /couchdb/trunk: ./ src/ src/couchdb/ src/ejson/ src/ejson/yajl/ test/etap/ utils/ From: Benoit Chesneau To: dev@couchdb.apache.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable forgot to say thanks for the work done on eep0018 btw :) - benoit On Tue, Apr 5, 2011 at 11:59 AM, Benoit Chesneau wrot= e: > mmm why mochijson is in ejson folder ? Why don't we do the abstraction > at couchdb level ? More than a cosmectic reason, I think It would be > better to have a clean separation between codes. > > In this case to let couchdb do the abstraction (and reuse the > couch_util functions we had) then we don't have to duplicate code and > eventually we could replace ejson by what we want in the future. Also > it make it easy to use ejson as an external module in apps like > bigcouch or rcouch or whatever based on CouchDB core. > > - beno=EEt > > On Tue, Apr 5, 2011 at 11:42 AM, =A0 wrote: >> Author: fdmanana >> Date: Tue Apr =A05 09:42:41 2011 >> New Revision: 1088941 >> >> URL: http://svn.apache.org/viewvc?rev=3D1088941&view=3Drev >> Log: >> Added ejson application >> >> This is a NIF based JSON decoder/encoder based on Paul Davis' eep0018 >> implementation (https://github.com/davisp/eep0018/), with some modificat= ions >> from Damien (big number support and optimizations) on top, plus a few fi= xes >> from my side and Beno=EEt on top of Damien's fork. >> This module fallbacks to mochijson2 when the NIF is not loaded or compil= ed. >> The NIF is only compiled and used if we're using an OTP release >=3D R13= B04. >> >> Thanks everyone. Closes COUCHDB-1118. >> >> >> Added: >> =A0 =A0couchdb/trunk/src/ejson/ >> =A0 =A0couchdb/trunk/src/ejson/Makefile.am >> =A0 =A0couchdb/trunk/src/ejson/decode.c >> =A0 =A0couchdb/trunk/src/ejson/ejson.app.in >> =A0 =A0couchdb/trunk/src/ejson/ejson.c >> =A0 =A0couchdb/trunk/src/ejson/ejson.erl >> =A0 =A0couchdb/trunk/src/ejson/encode.c >> =A0 =A0couchdb/trunk/src/ejson/erl_nif_compat.h >> =A0 =A0couchdb/trunk/src/ejson/mochijson2.erl >> =A0 =A0couchdb/trunk/src/ejson/mochinum.erl >> =A0 =A0couchdb/trunk/src/ejson/yajl/ >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl.c >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_alloc.c >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_alloc.h >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_buf.c >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_buf.h >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_bytestack.h >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_common.h >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_encode.c >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_encode.h >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_gen.c >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_gen.h >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_lex.c >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_lex.h >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_parse.h >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_parser.c >> =A0 =A0couchdb/trunk/src/ejson/yajl/yajl_parser.h >> Modified: >> =A0 =A0couchdb/trunk/.gitignore >> =A0 =A0couchdb/trunk/NOTICE >> =A0 =A0couchdb/trunk/configure.ac >> =A0 =A0couchdb/trunk/src/Makefile.am >> =A0 =A0couchdb/trunk/src/couchdb/couch_api_wrap.erl >> =A0 =A0couchdb/trunk/src/couchdb/couch_db.hrl >> =A0 =A0couchdb/trunk/src/couchdb/couch_httpd_external.erl >> =A0 =A0couchdb/trunk/src/couchdb/couch_os_process.erl >> =A0 =A0couchdb/trunk/src/couchdb/couch_util.erl >> =A0 =A0couchdb/trunk/test/etap/130-attachments-md5.t >> =A0 =A0couchdb/trunk/test/etap/140-attachment-comp.t >> =A0 =A0couchdb/trunk/test/etap/150-invalid-view-seq.t >> =A0 =A0couchdb/trunk/test/etap/160-vhosts.t >> =A0 =A0couchdb/trunk/test/etap/171-os-daemons-config.es >> =A0 =A0couchdb/trunk/test/etap/173-os-daemon-cfg-register.es >> =A0 =A0couchdb/trunk/test/etap/test_util.erl.in >> =A0 =A0couchdb/trunk/utils/Makefile.am >> >> Modified: couchdb/trunk/.gitignore >> URL: http://svn.apache.org/viewvc/couchdb/trunk/.gitignore?rev=3D1088941= &r1=3D1088940&r2=3D1088941&view=3Ddiff >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/.gitignore (original) >> +++ couchdb/trunk/.gitignore Tue Apr =A05 09:42:41 2011 >> @@ -64,6 +64,10 @@ src/couchdb/priv/couchspawnkillable >> =A0src/couchdb/priv/stat_descriptions.cfg >> =A0src/erlang-oauth/oauth.app >> =A0src/ibrowse/ibrowse.app >> +src/ejson/ejson.app >> +src/ejson/.deps/ >> +src/ejson/.libs/ >> +src/ejson/priv >> =A0src/mochiweb/mochiweb.app >> =A0test/local.ini >> =A0test/etap/run >> >> Modified: couchdb/trunk/NOTICE >> URL: http://svn.apache.org/viewvc/couchdb/trunk/NOTICE?rev=3D1088941&r1= =3D1088940&r2=3D1088941&view=3Ddiff >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/NOTICE (original) >> +++ couchdb/trunk/NOTICE Tue Apr =A05 09:42:41 2011 >> @@ -49,3 +49,13 @@ This product also includes the following >> =A0* jspec.js (http://visionmedia.github.com/jspec/) >> >> =A0 Copyright 2010 TJ Holowaychuk >> + >> + * yajl (http://lloyd.github.com/yajl/) >> + >> + =A0Copyright 2010, Lloyd Hilaiel >> + >> + * ejson >> + >> + =A0Based on Paul Davis' eep0018 implementation (https://github.com/dav= isp/eep0018/), >> + =A0with some modifications from Damien Katz, Filipe Manana and Beno=C3= =AEt Chesneau. >> + =A0This application uses yajl. >> \ No newline at end of file >> >> Modified: couchdb/trunk/configure.ac >> URL: http://svn.apache.org/viewvc/couchdb/trunk/configure.ac?rev=3D10889= 41&r1=3D1088940&r2=3D1088941&view=3Ddiff >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/configure.ac (original) >> +++ couchdb/trunk/configure.ac Tue Apr =A05 09:42:41 2011 >> @@ -262,6 +262,10 @@ if test `echo $version | ${AWK} "{print >> =A0 =A0 fi >> =A0fi >> >> +otp_release=3D"`${ERL} -noshell -eval 'io:put_chars(erlang:system_info(= otp_release)).' -s erlang halt`" >> +AC_SUBST(otp_release) >> +AM_CONDITIONAL([USE_OTP_NIFS], [test x$otp_release \> xR13B03]) >> + >> =A0has_crypto=3D`${ERL} -eval "case application:load(crypto) of ok -> ok= ; _ -> exit(no_crypto) end." -noshell -s init stop` >> >> =A0if test -n "$has_crypto"; then >> @@ -419,6 +423,7 @@ AC_CONFIG_FILES([src/erlang-oauth/Makefi >> =A0AC_CONFIG_FILES([src/etap/Makefile]) >> =A0AC_CONFIG_FILES([src/ibrowse/Makefile]) >> =A0AC_CONFIG_FILES([src/mochiweb/Makefile]) >> +AC_CONFIG_FILES([src/ejson/Makefile]) >> =A0AC_CONFIG_FILES([test/Makefile]) >> =A0AC_CONFIG_FILES([test/bench/Makefile]) >> =A0AC_CONFIG_FILES([test/etap/Makefile]) >> >> Modified: couchdb/trunk/src/Makefile.am >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/Makefile.am?rev=3D10= 88941&r1=3D1088940&r2=3D1088941&view=3Ddiff >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/Makefile.am (original) >> +++ couchdb/trunk/src/Makefile.am Tue Apr =A05 09:42:41 2011 >> @@ -10,4 +10,4 @@ >> =A0## License for the specific language governing permissions and limita= tions under >> =A0## the License. >> >> -SUBDIRS =3D couchdb erlang-oauth etap ibrowse mochiweb >> +SUBDIRS =3D couchdb erlang-oauth etap ibrowse mochiweb ejson >> >> Modified: couchdb/trunk/src/couchdb/couch_api_wrap.erl >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_api_wr= ap.erl?rev=3D1088941&r1=3D1088940&r2=3D1088941&view=3Ddiff >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/couchdb/couch_api_wrap.erl (original) >> +++ couchdb/trunk/src/couchdb/couch_api_wrap.erl Tue Apr =A05 09:42:41 2= 011 >> @@ -427,7 +427,7 @@ options_to_query_args([revs | Rest], Acc >> =A0options_to_query_args([{open_revs, all} | Rest], Acc) -> >> =A0 =A0 options_to_query_args(Rest, [{"open_revs", "all"} | Acc]); >> =A0options_to_query_args([{open_revs, Revs} | Rest], Acc) -> >> - =A0 =A0JsonRevs =3D ?JSON_ENCODE(couch_doc:revs_to_strs(Revs)), >> + =A0 =A0JsonRevs =3D ?b2l(?JSON_ENCODE(couch_doc:revs_to_strs(Revs))), >> =A0 =A0 options_to_query_args(Rest, [{"open_revs", JsonRevs} | Acc]). >> >> >> >> Modified: couchdb/trunk/src/couchdb/couch_db.hrl >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_db.hrl= ?rev=3D1088941&r1=3D1088940&r2=3D1088941&view=3Ddiff >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/couchdb/couch_db.hrl (original) >> +++ couchdb/trunk/src/couchdb/couch_db.hrl Tue Apr =A05 09:42:41 2011 >> @@ -20,8 +20,8 @@ >> =A0% the lowest possible database sequence number >> =A0-define(LOWEST_SEQ, 0). >> >> --define(JSON_ENCODE(V), couch_util:json_encode(V)). >> --define(JSON_DECODE(V), couch_util:json_decode(V)). >> +-define(JSON_ENCODE(V), ejson:encode(V)). >> +-define(JSON_DECODE(V), ejson:decode(V)). >> >> =A0-define(b2l(V), binary_to_list(V)). >> =A0-define(l2b(V), list_to_binary(V)). >> >> Modified: couchdb/trunk/src/couchdb/couch_httpd_external.erl >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_= external.erl?rev=3D1088941&r1=3D1088940&r2=3D1088941&view=3Ddiff >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/couchdb/couch_httpd_external.erl (original) >> +++ couchdb/trunk/src/couchdb/couch_httpd_external.erl Tue Apr =A05 09:4= 2:41 2011 >> @@ -105,11 +105,11 @@ json_query_keys({Json}) -> >> =A0json_query_keys([], Acc) -> >> =A0 =A0 {lists:reverse(Acc)}; >> =A0json_query_keys([{<<"startkey">>, Value} | Rest], Acc) -> >> - =A0 =A0json_query_keys(Rest, [{<<"startkey">>, couch_util:json_decode(= Value)}|Acc]); >> + =A0 =A0json_query_keys(Rest, [{<<"startkey">>, ?JSON_DECODE(Value)}|Ac= c]); >> =A0json_query_keys([{<<"endkey">>, Value} | Rest], Acc) -> >> - =A0 =A0json_query_keys(Rest, [{<<"endkey">>, couch_util:json_decode(Va= lue)}|Acc]); >> + =A0 =A0json_query_keys(Rest, [{<<"endkey">>, ?JSON_DECODE(Value)}|Acc]= ); >> =A0json_query_keys([{<<"key">>, Value} | Rest], Acc) -> >> - =A0 =A0json_query_keys(Rest, [{<<"key">>, couch_util:json_decode(Value= )}|Acc]); >> + =A0 =A0json_query_keys(Rest, [{<<"key">>, ?JSON_DECODE(Value)}|Acc]); >> =A0json_query_keys([Term | Rest], Acc) -> >> =A0 =A0 json_query_keys(Rest, [Term|Acc]). >> >> >> Modified: couchdb/trunk/src/couchdb/couch_os_process.erl >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_os_pro= cess.erl?rev=3D1088941&r1=3D1088940&r2=3D1088941&view=3Ddiff >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/couchdb/couch_os_process.erl (original) >> +++ couchdb/trunk/src/couchdb/couch_os_process.erl Tue Apr =A05 09:42:41= 2011 >> @@ -60,7 +60,7 @@ prompt(Pid, Data) -> >> =A0% Utility functions for reading and writing >> =A0% in custom functions >> =A0writeline(OsProc, Data) when is_record(OsProc, os_proc) -> >> - =A0 =A0port_command(OsProc#os_proc.port, Data ++ "\n"). >> + =A0 =A0port_command(OsProc#os_proc.port, [Data, $\n]). >> >> =A0readline(#os_proc{} =3D OsProc) -> >> =A0 =A0 readline(OsProc, []). >> >> Modified: couchdb/trunk/src/couchdb/couch_util.erl >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_util.e= rl?rev=3D1088941&r1=3D1088940&r2=3D1088941&view=3Ddiff >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/couchdb/couch_util.erl (original) >> +++ couchdb/trunk/src/couchdb/couch_util.erl Tue Apr =A05 09:42:41 2011 >> @@ -21,7 +21,6 @@ >> =A0-export([get_nested_json_value/2, json_user_ctx/1]). >> =A0-export([proplist_apply_field/2, json_apply_field/2]). >> =A0-export([to_binary/1, to_integer/1, to_list/1, url_encode/1]). >> --export([json_encode/1, json_decode/1]). >> =A0-export([verify/2,simple_call/2,shutdown_sync/1]). >> =A0-export([get_value/2, get_value/3]). >> =A0-export([md5/1, md5_init/0, md5_update/2, md5_final/1]). >> @@ -374,22 +373,6 @@ url_encode([H|T]) -> >> =A0url_encode([]) -> >> =A0 =A0 []. >> >> -json_encode(V) -> >> - =A0 =A0Handler =3D >> - =A0 =A0fun({L}) when is_list(L) -> >> - =A0 =A0 =A0 =A0{struct,L}; >> - =A0 =A0(Bad) -> >> - =A0 =A0 =A0 =A0exit({json_encode, {bad_term, Bad}}) >> - =A0 =A0end, >> - =A0 =A0(mochijson2:encoder([{handler, Handler}]))(V). >> - >> -json_decode(V) -> >> - =A0 =A0try (mochijson2:decoder([{object_hook, fun({struct,L}) -> {L} e= nd}]))(V) >> - =A0 =A0catch >> - =A0 =A0 =A0 =A0_Type:_Error -> >> - =A0 =A0 =A0 =A0 =A0 =A0throw({invalid_json,V}) >> - =A0 =A0end. >> - >> =A0verify([X|RestX], [Y|RestY], Result) -> >> =A0 =A0 verify(RestX, RestY, (X bxor Y) bor Result); >> =A0verify([], [], Result) -> >> >> Added: couchdb/trunk/src/ejson/Makefile.am >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/Makefile.am?re= v=3D1088941&view=3Dauto >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/ejson/Makefile.am (added) >> +++ couchdb/trunk/src/ejson/Makefile.am Tue Apr =A05 09:42:41 2011 >> @@ -0,0 +1,86 @@ >> +## Licensed under the Apache License, Version 2.0 (the "License"); you = may not >> +## use this file except in compliance with the License. You may obtain = a copy of >> +## the License at >> +## >> +## =A0 http://www.apache.org/licenses/LICENSE-2.0 >> +## >> +## Unless required by applicable law or agreed to in writing, software >> +## distributed under the License is distributed on an "AS IS" BASIS, WI= THOUT >> +## WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See= the >> +## License for the specific language governing permissions and limitati= ons under >> +## the License. >> + >> +ejsonebindir =3D $(localerlanglibdir)/ejson-0.1.0/ebin >> +ejsonprivdir =3D $(localerlanglibdir)/ejson-0.1.0/priv >> + >> +CLEANFILES =3D \ >> + =A0 =A0$(ejsonebin_make_generated_file_list) \ >> + =A0 =A0$(ejsonpriv_make_generated_file_list) >> + >> +if USE_OTP_NIFS >> +ejsonpriv_LTLIBRARIES =3D ejson.la >> +endif >> + >> +EJSON_C_SRCS =3D \ >> + =A0 =A0 =A0 ejson.c \ >> + =A0 =A0 =A0 decode.c \ >> + =A0 =A0 =A0 encode.c \ >> + =A0 =A0 =A0 yajl/yajl_alloc.c \ >> + =A0 =A0 =A0 yajl/yajl_buf.c \ >> + =A0 =A0 =A0 yajl/yajl.c \ >> + =A0 =A0 =A0 yajl/yajl_encode.c \ >> + =A0 =A0 =A0 yajl/yajl_gen.c \ >> + =A0 =A0 =A0 yajl/yajl_lex.c \ >> + =A0 =A0 =A0 yajl/yajl_parser.c >> + >> +if USE_OTP_NIFS >> +ejson_la_SOURCES =3D $(EJSON_C_SRCS) >> +ejson_la_LDFLAGS =3D -module -avoid-version >> + >> +if WINDOWS >> +ejson_la_LDFLAGS +=3D -no-undefined >> +endif >> +endif >> + >> +ejson_file_collection =3D \ >> + =A0 =A0ejson.app.in \ >> + =A0 =A0ejson.erl \ >> + =A0 =A0mochijson2.erl \ >> + =A0 =A0mochinum.erl \ >> + =A0 =A0$(JSON_C_SRCS) >> + >> +ejsonebin_make_generated_file_list =3D \ >> + =A0 =A0ejson.app \ >> + =A0 =A0ejson.beam \ >> + =A0 =A0mochijson2.beam \ >> + =A0 =A0mochinum.beam >> + >> +ejsonebin_DATA =3D \ >> + =A0 =A0$(ejsonebin_make_generated_file_list) >> + >> +EXTRA_DIST =3D =A0\ >> + =A0 =A0$(ejson_file_collection) \ >> + =A0 =A0erl_nif_compat.h \ >> + =A0 =A0yajl/yajl_alloc.h \ >> + =A0 =A0yajl/yajl_buf.h \ >> + =A0 =A0yajl/yajl_bytestack.h \ >> + =A0 =A0yajl/yajl_common.h \ >> + =A0 =A0yajl/yajl_encode.h \ >> + =A0 =A0yajl/yajl_gen.h \ >> + =A0 =A0yajl/yajl_lex.h \ >> + =A0 =A0yajl/yajl_parse.h \ >> + =A0 =A0yajl/yajl_parser.h \ >> + =A0 =A0priv >> + >> +if USE_OTP_NIFS >> +priv/ejson.so: .libs/ejson.so >> + =A0 =A0 =A0 $(LN_S) .libs priv >> + >> +all: priv/ejson.so >> +endif >> + >> +%.app: %.app.in >> + =A0 =A0 =A0 cp $< $@ >> + >> +%.beam: %.erl >> + =A0 =A0 =A0 $(ERLC) $(ERLC_FLAGS) $< >> >> Added: couchdb/trunk/src/ejson/decode.c >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/decode.c?rev= =3D1088941&view=3Dauto >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/ejson/decode.c (added) >> +++ couchdb/trunk/src/ejson/decode.c Tue Apr =A05 09:42:41 2011 >> @@ -0,0 +1,296 @@ >> +#include >> +#include >> +#include >> + >> +#include "erl_nif.h" >> +#include "erl_nif_compat.h" >> +#include "yajl/yajl_parse.h" >> +#include "yajl/yajl_parser.h" >> +#include "yajl/yajl_lex.h" >> + >> +typedef struct { >> + =A0 =A0ERL_NIF_TERM head; >> + =A0 =A0ErlNifEnv* env; >> +} decode_ctx; >> + >> +#define ENV(ctxarg) (((decode_ctx*)ctxarg)->env) >> + >> +#define CONTINUE 1 >> +#define CANCEL 0 >> + >> + >> +static ERL_NIF_TERM >> +make_error(yajl_handle handle, ErlNifEnv* env) >> +{ >> + =A0 =A0char* yajlError =3D (char*) yajl_get_error(handle, 0, NULL, 0); >> + =A0 =A0ERL_NIF_TERM errMsg; >> + >> + =A0 =A0if(yajlError !=3D NULL) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0errMsg =3D enif_make_string(env, yajlError, ERL_NIF_LAT= IN1); >> + =A0 =A0 =A0 =A0yajl_free_error(handle, (unsigned char*) yajlError); >> + =A0 =A0} >> + =A0 =A0else >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0errMsg =3D enif_make_string(env, "unknown parse error",= ERL_NIF_LATIN1); >> + =A0 =A0} >> + >> + =A0 =A0return enif_make_tuple(env, 2, >> + =A0 =A0 =A0 =A0enif_make_atom(env, "error"), >> + =A0 =A0 =A0 =A0enif_make_tuple(env, 2, >> + =A0 =A0 =A0 =A0 =A0 =A0enif_make_uint(env, handle->bytesConsumed), >> + =A0 =A0 =A0 =A0 =A0 =A0errMsg >> + =A0 =A0 =A0 =A0) >> + =A0 =A0); >> +} >> + >> + >> +static void >> +add_to_head(void* vctx, ERL_NIF_TERM newhead) >> +{ >> + =A0 =A0decode_ctx* ctx =3D (decode_ctx*)vctx; >> + =A0 =A0ctx->head =3D enif_make_list_cell(ctx->env, newhead, ctx->head)= ; >> +} >> + >> +static int >> +decode_null(void* ctx) >> +{ >> + =A0 =A0add_to_head(ctx, enif_make_atom(ENV(ctx), "null")); >> + =A0 =A0return CONTINUE; >> +} >> + >> +static int >> +decode_boolean(void* ctx, int val) >> +{ >> + =A0 =A0add_to_head(ctx, enif_make_atom(ENV(ctx), val ? "true" : "false= ")); >> + =A0 =A0return CONTINUE; >> +} >> + >> +static int >> +decode_number(void * ctx, const char * numberVal, unsigned int numberLe= n) >> +{ >> + =A0 =A0// scan in the input to see if it's a float or int >> + >> + =A0 =A0int numberType =3D 0; // 0 means integer, 1 means float >> + =A0 =A0unsigned int i; >> + =A0 =A0ErlNifBinary bin; >> + =A0 =A0int missingDot =3D 1; >> + =A0 =A0unsigned int expPos; >> + >> + =A0 =A0for(i=3D0; i> + =A0 =A0 =A0 =A0switch (numberVal[i]) { >> + =A0 =A0 =A0 =A0case '.': >> + =A0 =A0 =A0 =A0 =A0 =A0missingDot =3D 0; >> + =A0 =A0 =A0 =A0 =A0 =A0numberType =3D 1; // it's =A0a float >> + =A0 =A0 =A0 =A0 =A0 =A0goto loopend; >> + =A0 =A0 =A0 =A0case 'E': >> + =A0 =A0 =A0 =A0case 'e': >> + =A0 =A0 =A0 =A0 =A0 =A0expPos =3D i; >> + =A0 =A0 =A0 =A0 =A0 =A0numberType =3D 1; // it's =A0a float >> + =A0 =A0 =A0 =A0 =A0 =A0goto loopend; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> +loopend: >> + =A0 =A0if ((numberType =3D=3D 1) && missingDot) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0if(!enif_alloc_binary_compat(ENV(ctx), numberLen + 2, &= bin)) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0return CANCEL; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0memcpy(bin.data, numberVal, expPos); >> + =A0 =A0 =A0 =A0bin.data[expPos] =3D '.'; >> + =A0 =A0 =A0 =A0bin.data[expPos + 1] =3D '0'; >> + =A0 =A0 =A0 =A0memcpy(bin.data + expPos + 2, numberVal + expPos, numbe= rLen - expPos); >> + =A0 =A0} >> + =A0 =A0else >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0if(!enif_alloc_binary_compat(ENV(ctx), numberLen, &bin)= ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0return CANCEL; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0memcpy(bin.data, numberVal, numberLen); >> + =A0 =A0} >> + =A0 =A0add_to_head(ctx, enif_make_tuple(ENV(ctx), 2, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enif_make_int(ENV(ctx),= numberType), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enif_make_binary(ENV(ct= x), &bin))); >> + =A0 =A0return CONTINUE; >> +} >> + >> + >> + >> +static int >> +decode_string(void* ctx, const unsigned char* data, unsigned int size) >> +{ >> + =A0 =A0ErlNifBinary bin; >> + =A0 =A0if(!enif_alloc_binary_compat(ENV(ctx), size, &bin)) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0return CANCEL; >> + =A0 =A0} >> + =A0 =A0memcpy(bin.data, data, size); >> + =A0 =A0add_to_head(ctx, enif_make_binary(ENV(ctx), &bin)); >> + =A0 =A0return CONTINUE; >> +} >> + >> +static int >> +decode_start_array(void* ctx) >> +{ >> + =A0 =A0add_to_head(ctx, enif_make_int(ENV(ctx), 0)); >> + =A0 =A0return CONTINUE; >> +} >> + >> + >> +static int >> +decode_end_array(void* ctx) >> +{ >> + =A0 =A0add_to_head(ctx, enif_make_int(ENV(ctx), 1)); >> + =A0 =A0return CONTINUE; >> +} >> + >> + >> +static int >> +decode_start_map(void* ctx) >> +{ >> + =A0 =A0add_to_head(ctx, enif_make_int(ENV(ctx), 2)); >> + =A0 =A0return CONTINUE; >> +} >> + >> + >> +static int >> +decode_end_map(void* ctx) >> +{ >> + =A0 =A0add_to_head(ctx, enif_make_int(ENV(ctx), 3)); >> + =A0 =A0return CONTINUE; >> +} >> + >> + >> +static int >> +decode_map_key(void* ctx, const unsigned char* data, unsigned int size) >> +{ >> + =A0 =A0ErlNifBinary bin; >> + =A0 =A0if(!enif_alloc_binary_compat(ENV(ctx), size, &bin)) >> + =A0 =A0{ >> + =A0 =A0 =A0 return CANCEL; >> + =A0 =A0} >> + =A0 =A0memcpy(bin.data, data, size); >> + =A0 =A0add_to_head(ctx, enif_make_tuple(ENV(ctx), 2, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enif_make_int(ENV(ctx),= 3), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enif_make_binary(ENV(ct= x), &bin))); >> + =A0 =A0return CONTINUE; >> +} >> + >> +static yajl_callbacks >> +decoder_callbacks =3D { >> + =A0 =A0decode_null, >> + =A0 =A0decode_boolean, >> + =A0 =A0NULL, >> + =A0 =A0NULL, >> + =A0 =A0decode_number, >> + =A0 =A0decode_string, >> + =A0 =A0decode_start_map, >> + =A0 =A0decode_map_key, >> + =A0 =A0decode_end_map, >> + =A0 =A0decode_start_array, >> + =A0 =A0decode_end_array >> +}; >> + >> +static int >> +check_rest(unsigned char* data, unsigned int size, unsigned int used) >> +{ >> + =A0 =A0unsigned int i =3D 0; >> + =A0 =A0for(i =3D used; i < size; i++) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0switch(data[i]) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0case ' ': >> + =A0 =A0 =A0 =A0 =A0 =A0case '\t': >> + =A0 =A0 =A0 =A0 =A0 =A0case '\r': >> + =A0 =A0 =A0 =A0 =A0 =A0case '\n': >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0continue; >> + =A0 =A0 =A0 =A0 =A0 =A0default: >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return CANCEL; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + >> + =A0 =A0return CONTINUE; >> +} >> + >> +ERL_NIF_TERM >> +reverse_tokens(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) >> +{ >> + =A0 =A0decode_ctx ctx; >> + =A0 =A0yajl_parser_config conf =3D {0, 1}; // No comments, check utf8 >> + =A0 =A0yajl_handle handle =3D yajl_alloc(&decoder_callbacks, &conf, NU= LL, &ctx); >> + =A0 =A0yajl_status status; >> + =A0 =A0unsigned int used; >> + =A0 =A0ErlNifBinary bin; >> + =A0 =A0ERL_NIF_TERM ret; >> + >> + =A0 =A0ctx.env =3D env; >> + =A0 =A0ctx.head =3D enif_make_list_from_array(env, NULL, 0); >> + >> + =A0 =A0if(!enif_inspect_iolist_as_binary(env, argv[0], &bin)) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0ret =3D enif_make_badarg(env); >> + =A0 =A0 =A0 =A0goto done; >> + =A0 =A0} >> + >> + =A0 =A0status =3D yajl_parse(handle, bin.data, bin.size); >> + =A0 =A0used =3D handle->bytesConsumed; >> + >> + =A0 =A0// Parsing something like "2.0" (without quotes) will >> + =A0 =A0// cause a spurious semi-error. We add the extra size >> + =A0 =A0// check so that "2008-20-10" doesn't pass. >> + =A0 =A0if(status =3D=3D yajl_status_insufficient_data && used =3D=3D b= in.size) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0status =3D yajl_parse_complete(handle); >> + =A0 =A0} >> + >> + =A0 =A0if(status =3D=3D yajl_status_ok && used !=3D bin.size) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0if(check_rest(bin.data, bin.size, used) =3D=3D CANCEL) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0ret =3D enif_make_tuple(env, 2, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enif_make_atom(env, "error"), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enif_make_atom(env, "garbage_after_valu= e") >> + =A0 =A0 =A0 =A0 =A0 =A0); >> + =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + >> + =A0 =A0switch(status) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0case yajl_status_ok: >> + =A0 =A0 =A0 =A0 =A0 =A0ret =3D enif_make_tuple(env, 2, enif_make_atom(= env, "ok"), ctx.head); >> + =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + >> + =A0 =A0 =A0 =A0case yajl_status_error: >> + =A0 =A0 =A0 =A0 =A0 =A0ret =3D make_error(handle, env); >> + =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + >> + =A0 =A0 =A0 =A0case yajl_status_insufficient_data: >> + =A0 =A0 =A0 =A0 =A0 =A0ret =3D enif_make_tuple(env, 2, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enif_make_atom(env, "error"), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enif_make_atom(env, "insufficient_data"= ) >> + =A0 =A0 =A0 =A0 =A0 =A0); >> + =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + >> + =A0 =A0 =A0 =A0case yajl_status_client_canceled: >> + =A0 =A0 =A0 =A0/* the only time we do this is when we can't allocate a= binary. */ >> + =A0 =A0 =A0 =A0 =A0 =A0ret =3D enif_make_tuple(env, 2, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enif_make_atom(env, "error"), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enif_make_atom(env, "insufficient_memor= y") >> + =A0 =A0 =A0 =A0 =A0 =A0); >> + =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + >> + =A0 =A0 =A0 =A0default: >> + =A0 =A0 =A0 =A0 =A0 =A0ret =3D enif_make_tuple(env, 2, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enif_make_atom(env, "error"), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enif_make_atom(env, "unknown") >> + =A0 =A0 =A0 =A0 =A0 =A0); >> + =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + =A0 =A0} >> + >> +done: >> + =A0 =A0if(handle !=3D NULL) yajl_free(handle); >> + =A0 =A0return ret; >> +} >> >> Added: couchdb/trunk/src/ejson/ejson.app.in >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/ejson.app.in?r= ev=3D1088941&view=3Dauto >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/ejson/ejson.app.in (added) >> +++ couchdb/trunk/src/ejson/ejson.app.in Tue Apr =A05 09:42:41 2011 >> @@ -0,0 +1,9 @@ >> +{application, ejson, [ >> + =A0 =A0{description, "EJSON - decode and encode JSON into/from Erlang = terms"}, >> + =A0 =A0{vsn, "0.1.0"}, >> + =A0 =A0{modules, [ejson]}, >> + =A0 =A0{registered, []}, >> + =A0 =A0{applications, [kernel, stdlib]}, >> + =A0 =A0{env, []} >> +]}. >> + >> >> Added: couchdb/trunk/src/ejson/ejson.c >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/ejson.c?rev=3D= 1088941&view=3Dauto >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/ejson/ejson.c (added) >> +++ couchdb/trunk/src/ejson/ejson.c Tue Apr =A05 09:42:41 2011 >> @@ -0,0 +1,30 @@ >> +#include "erl_nif.h" >> + >> +ERL_NIF_TERM final_encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM = argv[]); >> +ERL_NIF_TERM reverse_tokens(ErlNifEnv* env, int argc, const ERL_NIF_TER= M argv[]); >> + >> +int >> +on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM info) >> +{ >> + =A0 =A0return 0; >> +} >> + >> +int >> +on_reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM info) >> +{ >> + =A0 =A0return 0; >> +} >> + >> +int >> +on_upgrade(ErlNifEnv* env, void** priv_data, void** old_data, ERL_NIF_T= ERM info) >> +{ >> + =A0 =A0return 0; >> +} >> + >> +static ErlNifFunc nif_funcs[] =3D >> +{ >> + =A0 =A0{"final_encode", 1, final_encode}, >> + =A0 =A0{"reverse_tokens", 1, reverse_tokens} >> +}; >> + >> +ERL_NIF_INIT(ejson, nif_funcs, &on_load, &on_reload, &on_upgrade, NULL)= ; >> >> Added: couchdb/trunk/src/ejson/ejson.erl >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/ejson.erl?rev= =3D1088941&view=3Dauto >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/ejson/ejson.erl (added) >> +++ couchdb/trunk/src/ejson/ejson.erl Tue Apr =A05 09:42:41 2011 >> @@ -0,0 +1,151 @@ >> +-module(ejson). >> +-export([encode/1, decode/1]). >> +-on_load(init/0). >> + >> +init() -> >> + =A0 =A0SoName =3D case code:priv_dir(ejson) of >> + =A0 =A0{error, bad_name} -> >> + =A0 =A0 =A0 =A0case filelib:is_dir(filename:join(["..", priv])) of >> + =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0filename:join(["..", priv, ejson]); >> + =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0filename:join([priv, ejson]) >> + =A0 =A0 =A0 =A0end; >> + =A0 =A0Dir -> >> + =A0 =A0 =A0 =A0filename:join(Dir, ejson) >> + =A0 =A0end, >> + =A0 =A0(catch erlang:load_nif(SoName, 0)), >> + =A0 =A0ok. >> + >> + >> +decode(IoList) -> >> + =A0 =A0try >> + =A0 =A0 =A0 =A0nif_decode(IoList) >> + =A0 =A0catch exit:ejson_nif_not_loaded -> >> + =A0 =A0 =A0 =A0erl_decode(IoList) >> + =A0 =A0end. >> + >> +encode(EJson) -> >> + =A0 =A0try >> + =A0 =A0 =A0 =A0nif_encode(EJson) >> + =A0 =A0catch exit:ejson_nif_not_loaded -> >> + =A0 =A0 =A0 =A0erl_encode(EJson) >> + =A0 =A0end. >> + >> + >> +nif_decode(IoList) -> >> + =A0 =A0case reverse_tokens(IoList) of >> + =A0 =A0{ok, ReverseTokens} -> >> + =A0 =A0 =A0 =A0[[EJson]] =3D make_ejson(ReverseTokens, [[]]), >> + =A0 =A0 =A0 =A0EJson; >> + =A0 =A0Error -> >> + =A0 =A0 =A0 =A0throw({invalid_json, {Error, IoList}}) >> + =A0 =A0end. >> + >> + >> +erl_decode(IoList) -> >> + =A0 =A0try >> + =A0 =A0 =A0 =A0(mochijson2:decoder([{object_hook, fun({struct, L}) -> = {L} end}]))(IoList) >> + =A0 =A0catch _Type:Error -> >> + =A0 =A0 =A0 =A0throw({invalid_json, {Error, IoList}}) >> + =A0 =A0end. >> + >> + >> +nif_encode(EJson) -> >> + =A0 =A0RevList =3D encode_rev(EJson), >> + =A0 =A0final_encode(lists:reverse(lists:flatten([RevList]))). >> + >> + >> +erl_encode(EJson) -> >> + =A0 =A0Opts =3D [{handler, fun mochi_encode_handler/1}], >> + =A0 =A0iolist_to_binary((mochijson2:encoder(Opts))(EJson)). >> + >> +mochi_encode_handler({L}) when is_list(L) -> >> + =A0 =A0{struct, L}; >> +mochi_encode_handler(Bad) -> >> + =A0 =A0exit({json_encode, {bad_term, Bad}}). >> + >> + >> +% Encode the json into a reverse list that's almost an iolist >> +% everything in the list is the final output except for tuples with >> +% {0, Strings} and {1, Floats}, which are to be converted to strings >> +% inside the NIF. >> +encode_rev(true) -> >> + =A0 =A0<<"true">>; >> +encode_rev(false) -> >> + =A0 =A0<<"false">>; >> +encode_rev(null) -> >> + =A0 =A0<<"null">>; >> +encode_rev(I) when is_integer(I) -> >> + =A0 =A0list_to_binary(integer_to_list(I)); >> +encode_rev(S) when is_binary(S) -> >> + =A0 =A0{0, S}; >> +encode_rev(S) when is_atom(S) -> >> + =A0 =A0{0, list_to_binary(atom_to_list(S))}; >> +encode_rev(F) when is_float(F) -> >> + =A0 =A0{1, F}; >> +encode_rev({Props}) when is_list(Props) -> >> + =A0 =A0encode_proplist_rev(Props, [<<"{">>]); >> +encode_rev(Array) when is_list(Array) -> >> + =A0 =A0encode_array_rev(Array, [<<"[">>]); >> +encode_rev(Bad) -> >> + =A0 =A0throw({json_encode, {bad_term, Bad}}). >> + >> + >> +encode_array_rev([], Acc) -> >> + =A0 =A0[<<"]">> | Acc]; >> +encode_array_rev([Val | Rest], [<<"[">>]) -> >> + =A0 =A0encode_array_rev(Rest, [encode_rev(Val), <<"[">>]); >> +encode_array_rev([Val | Rest], Acc) -> >> + =A0 =A0encode_array_rev(Rest, [encode_rev(Val), <<",">> | Acc]). >> + >> + >> +encode_proplist_rev([], Acc) -> >> + =A0 =A0[<<"}">> | Acc]; >> +encode_proplist_rev([{Key,Val} | Rest], [<<"{">>]) -> >> + =A0 =A0encode_proplist_rev( >> + =A0 =A0 =A0 =A0Rest, [encode_rev(Val), <<":">>, {0, as_binary(Key)}, <= <"{">>]); >> +encode_proplist_rev([{Key,Val} | Rest], Acc) -> >> + =A0 =A0encode_proplist_rev( >> + =A0 =A0 =A0 =A0Rest, [encode_rev(Val), <<":">>, {0, as_binary(Key)}, <= <",">> | Acc]). >> + >> +as_binary(B) when is_binary(B) -> >> + =A0 =A0B; >> +as_binary(A) when is_atom(A) -> >> + =A0 =A0list_to_binary(atom_to_list(A)); >> +as_binary(L) when is_list(L) -> >> + =A0 =A0list_to_binary(L). >> + >> + >> +make_ejson([], Stack) -> >> + =A0 =A0Stack; >> +make_ejson([0 | RevEvs], [ArrayValues, PrevValues | RestStack]) -> >> + =A0 =A0% 0 ArrayStart >> + =A0 =A0make_ejson(RevEvs, [[ArrayValues | PrevValues] | RestStack]); >> +make_ejson([1 | RevEvs], Stack) -> >> + =A0 =A0% 1 ArrayEnd >> + =A0 =A0make_ejson(RevEvs, [[] | Stack]); >> +make_ejson([2 | RevEvs], [ObjValues, PrevValues | RestStack]) -> >> + =A0 =A0% 2 ObjectStart >> + =A0 =A0make_ejson(RevEvs, [[{ObjValues} | PrevValues] | RestStack]); >> +make_ejson([3 | RevEvs], Stack) -> >> + =A0 =A0% 3 ObjectEnd >> + =A0 =A0make_ejson(RevEvs, [[] | Stack]); >> +make_ejson([{0, Value} | RevEvs], [Vals | RestStack] =3D _Stack) -> >> + =A0 =A0% {0, IntegerString} >> + =A0 =A0make_ejson(RevEvs, [[list_to_integer(binary_to_list(Value)) | V= als] | RestStack]); >> +make_ejson([{1, Value} | RevEvs], [Vals | RestStack] =3D _Stack) -> >> + =A0 =A0% {1, FloatString} >> + =A0 =A0make_ejson(RevEvs, [[list_to_float(binary_to_list(Value)) | Val= s] | RestStack]); >> +make_ejson([{3, String} | RevEvs], [[PrevValue|RestObject] | RestStack]= =3D _Stack) -> >> + =A0 =A0% {3 , ObjectKey} >> + =A0 =A0make_ejson(RevEvs, [[{String, PrevValue}|RestObject] | RestStac= k]); >> +make_ejson([Value | RevEvs], [Vals | RestStack] =3D _Stack) -> >> + =A0 =A0make_ejson(RevEvs, [[Value | Vals] | RestStack]). >> + >> + >> +reverse_tokens(_) -> >> + =A0 =A0exit(ejson_nif_not_loaded). >> + >> +final_encode(_) -> >> + =A0 =A0exit(ejson_nif_not_loaded). >> >> Added: couchdb/trunk/src/ejson/encode.c >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/encode.c?rev= =3D1088941&view=3Dauto >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/ejson/encode.c (added) >> +++ couchdb/trunk/src/ejson/encode.c Tue Apr =A05 09:42:41 2011 >> @@ -0,0 +1,164 @@ >> +#include >> +#include >> +#include >> + >> +#include "erl_nif.h" >> +#include "erl_nif_compat.h" >> +#include "yajl/yajl_encode.h" >> + >> +#define SUCCESS 0 >> +#define NOMEM 1 >> +#define BADARG 2 >> + >> + >> +typedef struct { >> + =A0 =A0ErlNifEnv* env; >> + =A0 =A0ErlNifBinary bin; >> + =A0 =A0size_t fill_offset; >> + =A0 =A0int error; >> +} encode_ctx; >> + >> + >> +static int >> +ensure_buffer(void* vctx, unsigned int len) { >> + =A0 =A0encode_ctx* ctx =3D (encode_ctx*)vctx; >> + =A0 =A0if ((ctx->bin.size - ctx->fill_offset) < len) { >> + =A0 =A0 =A0 =A0if(!enif_realloc_binary_compat(ctx->env, &(ctx->bin), (= ctx->bin.size * 2) + len)) { >> + =A0 =A0 =A0 =A0 =A0 =A0return NOMEM; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + =A0 =A0return SUCCESS; >> +} >> + >> +static void >> +fill_buffer(void* vctx, const char* str, unsigned int len) >> +{ >> + =A0 =A0encode_ctx* ctx =3D (encode_ctx*)vctx; >> + >> + =A0 =A0if (ctx->error || (ctx->error =3D ensure_buffer(vctx, len))) { >> + =A0 =A0 =A0 =A0return; >> + =A0 =A0} >> + =A0 =A0memcpy(ctx->bin.data + ctx->fill_offset, str, len); >> + =A0 =A0ctx->fill_offset +=3D len; >> +} >> + >> +/* Json encode the string binary into the ctx.bin, >> + =A0with surrounding quotes and all */ >> +static int >> +encode_string(void* vctx, ERL_NIF_TERM binary) >> +{ >> + =A0 =A0encode_ctx* ctx =3D (encode_ctx*)vctx; >> + =A0 =A0ErlNifBinary bin; >> + >> + =A0 =A0if(!enif_inspect_binary(ctx->env, binary, &bin)) { >> + =A0 =A0 =A0 =A0return NOMEM; >> + =A0 =A0} >> + =A0 =A0fill_buffer(ctx, "\"", 1); >> + =A0 =A0if (ctx->error) { >> + =A0 =A0 =A0 =A0return ctx->error; >> + =A0 =A0} >> + =A0 =A0yajl_string_encode2(fill_buffer, ctx, bin.data, bin.size); >> + =A0 =A0fill_buffer(ctx, "\"", 1); >> + >> + =A0 =A0return ctx->error; >> +} >> + >> +static ERL_NIF_TERM >> +no_mem_error(ErlNifEnv* env) >> +{ >> + =A0 =A0return enif_make_tuple(env, 2, >> + =A0 =A0 =A0 =A0 =A0 =A0enif_make_atom(env, "error"), >> + =A0 =A0 =A0 =A0 =A0 =A0enif_make_atom(env, "insufficient_memory")); >> +} >> + >> +ERL_NIF_TERM >> +final_encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) >> +{ >> + =A0 =A0ERL_NIF_TERM head =3D argv[0]; >> + =A0 =A0ERL_NIF_TERM term; >> + =A0 =A0double number; >> + =A0 =A0encode_ctx ctx; >> + >> + =A0 =A0ctx.env =3D env; >> + =A0 =A0ctx.fill_offset =3D 0; >> + =A0 =A0ctx.error =3D 0; >> + >> + =A0 =A0if (!enif_alloc_binary_compat(env, 100, &ctx.bin)) { >> + =A0 =A0 =A0 =A0 =A0 =A0return no_mem_error(env); >> + =A0 =A0} >> + >> + =A0 =A0while(enif_get_list_cell(env, head, &term, &head)) { >> + =A0 =A0 =A0 =A0ErlNifBinary termbin; >> + =A0 =A0 =A0 =A0const ERL_NIF_TERM* array; >> + =A0 =A0 =A0 =A0int arity; >> + =A0 =A0 =A0 =A0int code; >> + >> + =A0 =A0 =A0 =A0// We scan the list, looking for things to write into t= he binary, or >> + =A0 =A0 =A0 =A0// encode and then write into the binary. We encode val= ues that are >> + =A0 =A0 =A0 =A0// tuples tagged with a type and a value: {Type, Value}= where Type >> + =A0 =A0 =A0 =A0// is a an Integer and Value is what is to be encoded >> + >> + =A0 =A0 =A0 =A0if (enif_get_tuple(env, term, &arity, &array)) { >> + =A0 =A0 =A0 =A0 =A0 =A0// It's a tuple to encode and copy >> + =A0 =A0 =A0 =A0 =A0 =A0if (arity !=3D 2 || !enif_get_int(env, array[0]= , &code)) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// not arity 2 or the first element isn= 't an int >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ctx.error =3D BADARG; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0if (code =3D=3D 0) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// {0, String} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (encode_string(&ctx, array[1]) !=3D = SUCCESS) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0else { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// {1, Double} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if(!enif_get_double(env, array[1], &num= ber)) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ctx.error =3D BADARG; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// We can't encode these. >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (isnan(number) || isinf(number)) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ctx.error =3D BADARG; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ((ctx.error =3D ensure_buffer(&ctx, = 32)) !=3D SUCCESS) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// write the string into the buffer >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0snprintf((char*)ctx.bin.data+ctx.fill_o= ffset, 32, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"%.16g", number); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// increment the length >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ctx.fill_offset +=3D strlen((char*)ctx.= bin.data+ctx.fill_offset); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0} else if (enif_inspect_binary(env, term, &termbin)) { >> + =A0 =A0 =A0 =A0 =A0 =A0// this is a regular binary, copy the contents = into the buffer >> + =A0 =A0 =A0 =A0 =A0 =A0fill_buffer(&ctx, (char*)termbin.data, termbin.= size); >> + =A0 =A0 =A0 =A0 =A0 =A0if (ctx.error) { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0else { >> + =A0 =A0 =A0 =A0 =A0 =A0//not a binary, not a tuple, wtf! >> + =A0 =A0 =A0 =A0 =A0 =A0ctx.error =3D BADARG; >> + =A0 =A0 =A0 =A0 =A0 =A0goto done; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> +done: >> + =A0 =A0if (ctx.error =3D=3D NOMEM) { >> + =A0 =A0 =A0 =A0enif_release_binary_compat(env, &ctx.bin); >> + =A0 =A0 =A0 =A0return no_mem_error(env); >> + =A0 =A0} else if (ctx.error =3D=3D BADARG) { >> + =A0 =A0 =A0 =A0enif_release_binary_compat(env, &ctx.bin); >> + =A0 =A0 =A0 =A0return enif_make_badarg(env); >> + =A0 =A0} >> + >> + =A0 =A0// Resize the binary to our exact final size >> + =A0 =A0if(!enif_realloc_binary_compat(env, &(ctx.bin), ctx.fill_offset= )) { >> + =A0 =A0 =A0 =A0enif_release_binary_compat(env, &ctx.bin); >> + =A0 =A0 =A0 =A0return no_mem_error(env); >> + =A0 =A0} >> + =A0 =A0// make the binary term which transfers ownership >> + =A0 =A0return enif_make_binary(env, &ctx.bin); >> +} >> + >> >> Added: couchdb/trunk/src/ejson/erl_nif_compat.h >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/erl_nif_compat= .h?rev=3D1088941&view=3Dauto >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/ejson/erl_nif_compat.h (added) >> +++ couchdb/trunk/src/ejson/erl_nif_compat.h Tue Apr =A05 09:42:41 2011 >> @@ -0,0 +1,102 @@ >> +#ifndef ERL_NIF_COMPAT_H_ >> +#define ERL_NIF_COMPAT_H_ >> + >> +#ifdef __cplusplus >> +extern "C" { >> +#endif /* __cplusplus */ >> + >> +#include "erl_nif.h" >> + >> + >> +#if ERL_NIF_MAJOR_VERSION =3D=3D 0 && ERL_NIF_MINOR_VERSION =3D=3D 1 >> +#define OTP_R13B03 >> +#elif ERL_NIF_MAJOR_VERSION =3D=3D 1 && ERL_NIF_MINOR_VERSION =3D=3D 0 >> +#define OTP_R13B04 >> +#elif ERL_NIF_MAJOR_VERSION =3D=3D 2 && ERL_NIF_MINOR_VERSION =3D=3D 0 >> +#define OTP_R14A >> +#define OTP_R14B >> +#define OTP_R14B01 >> +#elif ERL_NIF_MAJOR_VERSION =3D=3D 2 && ERL_NIF_MINOR_VERSION =3D=3D 1 >> +#define OTP_R14B02 >> +#endif >> + >> + >> +#ifdef OTP_R13B03 >> + >> +#define enif_open_resource_type_compat enif_open_resource_type >> +#define enif_alloc_resource_compat enif_alloc_resource >> +#define enif_release_resource_compat enif_release_resource >> +#define enif_alloc_binary_compat enif_alloc_binary >> +#define enif_alloc_compat enif_alloc >> +#define enif_release_binary_compat enif_release_binary >> +#define enif_free_compat enif_free >> +#define enif_get_atom_compat enif_get_atom >> +#define enif_priv_data_compat enif_get_data >> +#define enif_make_uint_compat enif_make_ulong >> + >> +#define enif_make_string_compat(E, B, Enc) \ >> + =A0 =A0enif_make_string(E, B) >> + >> +#endif /* R13B03 */ >> + >> + >> +#ifdef OTP_R13B04 >> + >> +#define enif_open_resource_type_compat enif_open_resource_type >> +#define enif_alloc_resource_compat enif_alloc_resource >> +#define enif_release_resource_compat enif_release_resource >> +#define enif_alloc_binary_compat enif_alloc_binary >> +#define enif_realloc_binary_compat enif_realloc_binary >> +#define enif_release_binary_compat enif_release_binary >> +#define enif_alloc_compat enif_alloc >> +#define enif_free_compat enif_free >> +#define enif_get_atom_compat enif_get_atom >> +#define enif_priv_data_compat enif_priv_data >> +#define enif_make_string_compat enif_make_string >> +#define enif_make_uint_compat enif_make_uint >> + >> +#endif /* R13B04 */ >> + >> + >> +/* OTP R14 and future releases */ >> +#if !defined(OTP_R13B03) && !defined(OTP_R13B04) >> + >> +#define enif_open_resource_type_compat(E, N, D, F, T) \ >> + =A0 =A0enif_open_resource_type(E, NULL, N, D, F, T) >> + >> +#define enif_alloc_resource_compat(E, T, S) \ >> + =A0 =A0enif_alloc_resource(T, S) >> + >> +#define enif_release_resource_compat(E, H) \ >> + =A0 =A0enif_release_resource(H) >> + >> +#define enif_alloc_binary_compat(E, S, B) \ >> + =A0 =A0enif_alloc_binary(S, B) >> + >> +#define enif_realloc_binary_compat(E, S, B) \ >> + =A0 =A0enif_realloc_binary(S, B) >> + >> +#define enif_release_binary_compat(E, B) \ >> + =A0 =A0enif_release_binary(B) >> + >> +#define enif_alloc_compat(E, S) \ >> + =A0 =A0enif_alloc(S) >> + >> +#define enif_free_compat(E, P) \ >> + =A0 =A0enif_free(P) >> + >> +#define enif_get_atom_compat(E, T, B, S) \ >> + =A0 =A0enif_get_atom(E, T, B, S, ERL_NIF_LATIN1) >> + >> +#define enif_priv_data_compat enif_priv_data >> +#define enif_make_string_compat enif_make_string >> +#define enif_make_uint_compat enif_make_uint >> + >> +#endif =A0/* R14 and future releases */ >> + >> + >> +#ifdef __cplusplus >> +} >> +#endif /* __cplusplus */ >> + >> +#endif /* ERL_NIF_COMPAT_H_ */ >> >> Added: couchdb/trunk/src/ejson/mochijson2.erl >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/mochijson2.erl= ?rev=3D1088941&view=3Dauto >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/ejson/mochijson2.erl (added) >> +++ couchdb/trunk/src/ejson/mochijson2.erl Tue Apr =A05 09:42:41 2011 >> @@ -0,0 +1,849 @@ >> +%% @author Bob Ippolito >> +%% @copyright 2007 Mochi Media, Inc. >> + >> +%% @doc Yet another JSON (RFC 4627) library for Erlang. mochijson2 work= s >> +%% =A0 =A0 =A0with binaries as strings, arrays as lists (without an {ar= ray, _}) >> +%% =A0 =A0 =A0wrapper and it only knows how to decode UTF-8 (and ASCII)= . >> +%% >> +%% =A0 =A0 =A0JSON terms are decoded as follows (javascript -> erlang): >> +%% =A0 =A0 =A0
    >> +%% =A0 =A0 =A0 =A0 =A0
  • {"key": "value"} -> >> +%% =A0 =A0 =A0 =A0 =A0 =A0 =A0{struct, [{<<"key">>, <<"valu= e">>}]}
  • >> +%% =A0 =A0 =A0 =A0 =A0
  • ["array", 123, 12.34, true, false, null] -> >> +%% =A0 =A0 =A0 =A0 =A0 =A0 =A0[<<"array">>, 123, 12.34, true, fal= se, null] >> +%% =A0 =A0 =A0 =A0 =A0
  • >> +%% =A0 =A0 =A0
>> +%% =A0 =A0 =A0
    >> +%% =A0 =A0 =A0 =A0 =A0
  • Strings in JSON decode to UTF-8 binaries in E= rlang
  • >> +%% =A0 =A0 =A0 =A0 =A0
  • Objects decode to {struct, PropList}
  • >> +%% =A0 =A0 =A0 =A0 =A0
  • Numbers decode to integer or float
  • >> +%% =A0 =A0 =A0 =A0 =A0
  • true, false, null decode to their respective = terms.
  • >> +%% =A0 =A0 =A0
>> +%% =A0 =A0 =A0The encoder will accept the same format that the decoder = will produce, >> +%% =A0 =A0 =A0but will also allow additional cases for leniency: >> +%% =A0 =A0 =A0
    >> +%% =A0 =A0 =A0 =A0 =A0
  • atoms other than true, false, null will be co= nsidered UTF-8 >> +%% =A0 =A0 =A0 =A0 =A0 =A0 =A0strings (even as a proplist key) >> +%% =A0 =A0 =A0 =A0 =A0
  • >> +%% =A0 =A0 =A0 =A0 =A0
  • {json, IoList} will insert IoList directly in= to the output >> +%% =A0 =A0 =A0 =A0 =A0 =A0 =A0with no validation >> +%% =A0 =A0 =A0 =A0 =A0
  • >> +%% =A0 =A0 =A0 =A0 =A0
  • {array, Array} will be encoded as Array >> +%% =A0 =A0 =A0 =A0 =A0 =A0 =A0(legacy mochijson style) >> +%% =A0 =A0 =A0 =A0 =A0
  • >> +%% =A0 =A0 =A0 =A0 =A0
  • A non-empty raw proplist will be encoded as a= n object as long >> +%% =A0 =A0 =A0 =A0 =A0 =A0 =A0as the first pair does not have an atom k= ey of json, struct, >> +%% =A0 =A0 =A0 =A0 =A0 =A0 =A0or array >> +%% =A0 =A0 =A0 =A0 =A0
  • >> +%% =A0 =A0 =A0
>> + >> +-module(mochijson2). >> +-author('bob@mochimedia.com'). >> +-export([encoder/1, encode/1]). >> +-export([decoder/1, decode/1]). >> + >> +% This is a macro to placate syntax highlighters.. >> +-define(Q, $\"). >> +-define(ADV_COL(S, N), S#decoder{offset=3DN+S#decoder.offset, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 column= =3DN+S#decoder.column}). >> +-define(INC_COL(S), S#decoder{offset=3D1+S#decoder.offset, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0column=3D1+= S#decoder.column}). >> +-define(INC_LINE(S), S#decoder{offset=3D1+S#decoder.offset, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 column=3D1= , >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 line=3D1+S= #decoder.line}). >> +-define(INC_CHAR(S, C), >> + =A0 =A0 =A0 =A0case C of >> + =A0 =A0 =A0 =A0 =A0 =A0$\n -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0S#decoder{column=3D1, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0line=3D1+S#decoder.= line, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0offset=3D1+S#decode= r.offset}; >> + =A0 =A0 =A0 =A0 =A0 =A0_ -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0S#decoder{column=3D1+S#decoder.column, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0offset=3D1+S#decode= r.offset} >> + =A0 =A0 =A0 =A0end). >> +-define(IS_WHITESPACE(C), >> + =A0 =A0 =A0 =A0(C =3D:=3D $\s orelse C =3D:=3D $\t orelse C =3D:=3D $\= r orelse C =3D:=3D $\n)). >> + >> +%% @type iolist() =3D [char() | binary() | iolist()] >> +%% @type iodata() =3D iolist() | binary() >> +%% @type json_string() =3D atom | binary() >> +%% @type json_number() =3D integer() | float() >> +%% @type json_array() =3D [json_term()] >> +%% @type json_object() =3D {struct, [{json_string(), json_term()}]} >> +%% @type json_iolist() =3D {json, iolist()} >> +%% @type json_term() =3D json_string() | json_number() | json_array() | >> +%% =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 json_object() | json_iolist(= ) >> + >> +-record(encoder, {handler=3Dnull, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0utf8=3Dfalse}). >> + >> +-record(decoder, {object_hook=3Dnull, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0offset=3D0, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0line=3D1, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0column=3D1, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0state=3Dnull}). >> + >> +%% @spec encoder([encoder_option()]) -> function() >> +%% @doc Create an encoder/1 with the given options. >> +%% @type encoder_option() =3D handler_option() | utf8_option() >> +%% @type utf8_option() =3D boolean(). Emit unicode as utf8 (default - f= alse) >> +encoder(Options) -> >> + =A0 =A0State =3D parse_encoder_options(Options, #encoder{}), >> + =A0 =A0fun (O) -> json_encode(O, State) end. >> + >> +%% @spec encode(json_term()) -> iolist() >> +%% @doc Encode the given as JSON to an iolist. >> +encode(Any) -> >> + =A0 =A0json_encode(Any, #encoder{}). >> + >> +%% @spec decoder([decoder_option()]) -> function() >> +%% @doc Create a decoder/1 with the given options. >> +decoder(Options) -> >> + =A0 =A0State =3D parse_decoder_options(Options, #decoder{}), >> + =A0 =A0fun (O) -> json_decode(O, State) end. >> + >> +%% @spec decode(iolist()) -> json_term() >> +%% @doc Decode the given iolist to Erlang terms. >> +decode(S) -> >> + =A0 =A0json_decode(S, #decoder{}). >> + >> +%% Internal API >> + >> +parse_encoder_options([], State) -> >> + =A0 =A0State; >> +parse_encoder_options([{handler, Handler} | Rest], State) -> >> + =A0 =A0parse_encoder_options(Rest, State#encoder{handler=3DHandler}); >> +parse_encoder_options([{utf8, Switch} | Rest], State) -> >> + =A0 =A0parse_encoder_options(Rest, State#encoder{utf8=3DSwitch}). >> + >> +parse_decoder_options([], State) -> >> + =A0 =A0State; >> +parse_decoder_options([{object_hook, Hook} | Rest], State) -> >> + =A0 =A0parse_decoder_options(Rest, State#decoder{object_hook=3DHook}). >> + >> +json_encode(true, _State) -> >> + =A0 =A0<<"true">>; >> +json_encode(false, _State) -> >> + =A0 =A0<<"false">>; >> +json_encode(null, _State) -> >> + =A0 =A0<<"null">>; >> +json_encode(I, _State) when is_integer(I) -> >> + =A0 =A0integer_to_list(I); >> +json_encode(F, _State) when is_float(F) -> >> + =A0 =A0mochinum:digits(F); >> +json_encode(S, State) when is_binary(S); is_atom(S) -> >> + =A0 =A0json_encode_string(S, State); >> +json_encode([{K, _}|_] =3D Props, State) when (K =3D/=3D struct andalso >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 K =3D/=3D array andalso >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 K =3D/=3D json) -> >> + =A0 =A0json_encode_proplist(Props, State); >> +json_encode({struct, Props}, State) when is_list(Props) -> >> + =A0 =A0json_encode_proplist(Props, State); >> +json_encode(Array, State) when is_list(Array) -> >> + =A0 =A0json_encode_array(Array, State); >> +json_encode({array, Array}, State) when is_list(Array) -> >> + =A0 =A0json_encode_array(Array, State); >> +json_encode({json, IoList}, _State) -> >> + =A0 =A0IoList; >> +json_encode(Bad, #encoder{handler=3Dnull}) -> >> + =A0 =A0exit({json_encode, {bad_term, Bad}}); >> +json_encode(Bad, State=3D#encoder{handler=3DHandler}) -> >> + =A0 =A0json_encode(Handler(Bad), State). >> + >> +json_encode_array([], _State) -> >> + =A0 =A0<<"[]">>; >> +json_encode_array(L, State) -> >> + =A0 =A0F =3D fun (O, Acc) -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0[$,, json_encode(O, State) | Acc] >> + =A0 =A0 =A0 =A0end, >> + =A0 =A0[$, | Acc1] =3D lists:foldl(F, "[", L), >> + =A0 =A0lists:reverse([$\] | Acc1]). >> + >> +json_encode_proplist([], _State) -> >> + =A0 =A0<<"{}">>; >> +json_encode_proplist(Props, State) -> >> + =A0 =A0F =3D fun ({K, V}, Acc) -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0KS =3D json_encode_string(K, State), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0VS =3D json_encode(V, State), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0[$,, VS, $:, KS | Acc] >> + =A0 =A0 =A0 =A0end, >> + =A0 =A0[$, | Acc1] =3D lists:foldl(F, "{", Props), >> + =A0 =A0lists:reverse([$\} | Acc1]). >> + >> +json_encode_string(A, State) when is_atom(A) -> >> + =A0 =A0L =3D atom_to_list(A), >> + =A0 =A0case json_string_is_safe(L) of >> + =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0[?Q, L, ?Q]; >> + =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0json_encode_string_unicode(xmerl_ucs:from_utf8(= L), State, [?Q]) >> + =A0 =A0end; >> +json_encode_string(B, State) when is_binary(B) -> >> + =A0 =A0case json_bin_is_safe(B) of >> + =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0[?Q, B, ?Q]; >> + =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0json_encode_string_unicode(xmerl_ucs:from_utf8(= B), State, [?Q]) >> + =A0 =A0end; >> +json_encode_string(I, _State) when is_integer(I) -> >> + =A0 =A0[?Q, integer_to_list(I), ?Q]; >> +json_encode_string(L, State) when is_list(L) -> >> + =A0 =A0case json_string_is_safe(L) of >> + =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0[?Q, L, ?Q]; >> + =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0json_encode_string_unicode(L, State, [?Q]) >> + =A0 =A0end. >> + >> +json_string_is_safe([]) -> >> + =A0 =A0true; >> +json_string_is_safe([C | Rest]) -> >> + =A0 =A0case C of >> + =A0 =A0 =A0 =A0?Q -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0$\\ -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0$\b -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0$\f -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0$\n -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0$\r -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0$\t -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0C when C >=3D 0, C < $\s; C >=3D 16#7f, C =3D< 16#10FFF= F -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0C when C < 16#7f -> >> + =A0 =A0 =A0 =A0 =A0 =A0json_string_is_safe(Rest); >> + =A0 =A0 =A0 =A0_ -> >> + =A0 =A0 =A0 =A0 =A0 =A0false >> + =A0 =A0end. >> + >> +json_bin_is_safe(<<>>) -> >> + =A0 =A0true; >> +json_bin_is_safe(<>) -> >> + =A0 =A0case C of >> + =A0 =A0 =A0 =A0?Q -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0$\\ -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0$\b -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0$\f -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0$\n -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0$\r -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0$\t -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0C when C >=3D 0, C < $\s; C >=3D 16#7f -> >> + =A0 =A0 =A0 =A0 =A0 =A0false; >> + =A0 =A0 =A0 =A0C when C < 16#7f -> >> + =A0 =A0 =A0 =A0 =A0 =A0json_bin_is_safe(Rest) >> + =A0 =A0end. >> + >> +json_encode_string_unicode([], _State, Acc) -> >> + =A0 =A0lists:reverse([$\" | Acc]); >> +json_encode_string_unicode([C | Cs], State, Acc) -> >> + =A0 =A0Acc1 =3D case C of >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ?Q -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 [?Q, $\\ | Acc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 %% Escaping solidus is only useful when tr= ying to protect >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 %% against "" injection attacks w= hich are only >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 %% possible when JSON is inserted into a H= TML document >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 %% in-line. mochijson2 does not protect yo= u from this, so >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 %% if you do insert directly into HTML the= n you need to >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 %% uncomment the following case or escape = the output of encode. >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 %% >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 %% $/ -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 %% =A0 =A0[$/, $\\ | Acc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 %% >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 $\\ -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 [$\\, $\\ | Acc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 $\b -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 [$b, $\\ | Acc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 $\f -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 [$f, $\\ | Acc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 $\n -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 [$n, $\\ | Acc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 $\r -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 [$r, $\\ | Acc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 $\t -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 [$t, $\\ | Acc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 C when C >=3D 0, C < $\s -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 [unihex(C) | Acc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 C when C >=3D 16#7f, C =3D< 16#10FFFF, Sta= te#encoder.utf8 -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 [xmerl_ucs:to_utf8(C) | Acc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 C when =A0C >=3D 16#7f, C =3D< 16#10FFFF, = not State#encoder.utf8 -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 [unihex(C) | Acc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 C when C < 16#7f -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 [C | Acc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 _ -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 exit({json_encode, {bad_char, C}}) >> + =A0 =A0 =A0 =A0 =A0 end, >> + =A0 =A0json_encode_string_unicode(Cs, State, Acc1). >> + >> +hexdigit(C) when C >=3D 0, C =3D< 9 -> >> + =A0 =A0C + $0; >> +hexdigit(C) when C =3D< 15 -> >> + =A0 =A0C + $a - 10. >> + >> +unihex(C) when C < 16#10000 -> >> + =A0 =A0<> =3D <>, >> + =A0 =A0Digits =3D [hexdigit(D) || D <- [D3, D2, D1, D0]], >> + =A0 =A0[$\\, $u | Digits]; >> +unihex(C) when C =3D< 16#10FFFF -> >> + =A0 =A0N =3D C - 16#10000, >> + =A0 =A0S1 =3D 16#d800 bor ((N bsr 10) band 16#3ff), >> + =A0 =A0S2 =3D 16#dc00 bor (N band 16#3ff), >> + =A0 =A0[unihex(S1), unihex(S2)]. >> + >> +json_decode(L, S) when is_list(L) -> >> + =A0 =A0json_decode(iolist_to_binary(L), S); >> +json_decode(B, S) -> >> + =A0 =A0{Res, S1} =3D decode1(B, S), >> + =A0 =A0{eof, _} =3D tokenize(B, S1#decoder{state=3Dtrim}), >> + =A0 =A0Res. >> + >> +decode1(B, S=3D#decoder{state=3Dnull}) -> >> + =A0 =A0case tokenize(B, S#decoder{state=3Dany}) of >> + =A0 =A0 =A0 =A0{{const, C}, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0{C, S1}; >> + =A0 =A0 =A0 =A0{start_array, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0decode_array(B, S1); >> + =A0 =A0 =A0 =A0{start_object, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0decode_object(B, S1) >> + =A0 =A0end. >> + >> +make_object(V, #decoder{object_hook=3Dnull}) -> >> + =A0 =A0V; >> +make_object(V, #decoder{object_hook=3DHook}) -> >> + =A0 =A0Hook(V). >> + >> +decode_object(B, S) -> >> + =A0 =A0decode_object(B, S#decoder{state=3Dkey}, []). >> + >> +decode_object(B, S=3D#decoder{state=3Dkey}, Acc) -> >> + =A0 =A0case tokenize(B, S) of >> + =A0 =A0 =A0 =A0{end_object, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0V =3D make_object({struct, lists:reverse(Acc)},= S1), >> + =A0 =A0 =A0 =A0 =A0 =A0{V, S1#decoder{state=3Dnull}}; >> + =A0 =A0 =A0 =A0{{const, K}, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0{colon, S2} =3D tokenize(B, S1), >> + =A0 =A0 =A0 =A0 =A0 =A0{V, S3} =3D decode1(B, S2#decoder{state=3Dnull}= ), >> + =A0 =A0 =A0 =A0 =A0 =A0decode_object(B, S3#decoder{state=3Dcomma}, [{K= , V} | Acc]) >> + =A0 =A0end; >> +decode_object(B, S=3D#decoder{state=3Dcomma}, Acc) -> >> + =A0 =A0case tokenize(B, S) of >> + =A0 =A0 =A0 =A0{end_object, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0V =3D make_object({struct, lists:reverse(Acc)},= S1), >> + =A0 =A0 =A0 =A0 =A0 =A0{V, S1#decoder{state=3Dnull}}; >> + =A0 =A0 =A0 =A0{comma, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0decode_object(B, S1#decoder{state=3Dkey}, Acc) >> + =A0 =A0end. >> + >> +decode_array(B, S) -> >> + =A0 =A0decode_array(B, S#decoder{state=3Dany}, []). >> + >> +decode_array(B, S=3D#decoder{state=3Dany}, Acc) -> >> + =A0 =A0case tokenize(B, S) of >> + =A0 =A0 =A0 =A0{end_array, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0{lists:reverse(Acc), S1#decoder{state=3Dnull}}; >> + =A0 =A0 =A0 =A0{start_array, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0{Array, S2} =3D decode_array(B, S1), >> + =A0 =A0 =A0 =A0 =A0 =A0decode_array(B, S2#decoder{state=3Dcomma}, [Arr= ay | Acc]); >> + =A0 =A0 =A0 =A0{start_object, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0{Array, S2} =3D decode_object(B, S1), >> + =A0 =A0 =A0 =A0 =A0 =A0decode_array(B, S2#decoder{state=3Dcomma}, [Arr= ay | Acc]); >> + =A0 =A0 =A0 =A0{{const, Const}, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0decode_array(B, S1#decoder{state=3Dcomma}, [Con= st | Acc]) >> + =A0 =A0end; >> +decode_array(B, S=3D#decoder{state=3Dcomma}, Acc) -> >> + =A0 =A0case tokenize(B, S) of >> + =A0 =A0 =A0 =A0{end_array, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0{lists:reverse(Acc), S1#decoder{state=3Dnull}}; >> + =A0 =A0 =A0 =A0{comma, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0decode_array(B, S1#decoder{state=3Dany}, Acc) >> + =A0 =A0end. >> + >> +tokenize_string(B, S=3D#decoder{offset=3DO}) -> >> + =A0 =A0case tokenize_string_fast(B, O) of >> + =A0 =A0 =A0 =A0{escape, O1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0Length =3D O1 - O, >> + =A0 =A0 =A0 =A0 =A0 =A0S1 =3D ?ADV_COL(S, Length), >> + =A0 =A0 =A0 =A0 =A0 =A0<<_:O/binary, Head:Length/binary, _/binary>> = =3D B, >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, S1, lists:reverse(binary_to_= list(Head))); >> + =A0 =A0 =A0 =A0O1 -> >> + =A0 =A0 =A0 =A0 =A0 =A0Length =3D O1 - O, >> + =A0 =A0 =A0 =A0 =A0 =A0<<_:O/binary, String:Length/binary, ?Q, _/binar= y>> =3D B, >> + =A0 =A0 =A0 =A0 =A0 =A0{{const, String}, ?ADV_COL(S, Length + 1)} >> + =A0 =A0end. >> + >> +tokenize_string_fast(B, O) -> >> + =A0 =A0case B of >> + =A0 =A0 =A0 =A0<<_:O/binary, ?Q, _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0O; >> + =A0 =A0 =A0 =A0<<_:O/binary, $\\, _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0{escape, O}; >> + =A0 =A0 =A0 =A0<<_:O/binary, C1, _/binary>> when C1 < 128 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string_fast(B, 1 + O); >> + =A0 =A0 =A0 =A0<<_:O/binary, C1, C2, _/binary>> when C1 >=3D 194, C1 = =3D< 223, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0C2 >=3D 128, C2 =3D< 191 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string_fast(B, 2 + O); >> + =A0 =A0 =A0 =A0<<_:O/binary, C1, C2, C3, _/binary>> when C1 >=3D 224, = C1 =3D< 239, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0C2 >=3D 128, C2 =3D< 191, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0C3 >=3D 128, C3 =3D< 191 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string_fast(B, 3 + O); >> + =A0 =A0 =A0 =A0<<_:O/binary, C1, C2, C3, C4, _/binary>> when C1 >=3D 2= 40, C1 =3D< 244, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0C2 >=3D 128, C2 =3D< 191, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0C3 >=3D 128, C3 =3D< 191, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0C4 >=3D 128, C4 =3D< 191 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string_fast(B, 4 + O); >> + =A0 =A0 =A0 =A0_ -> >> + =A0 =A0 =A0 =A0 =A0 =A0throw(invalid_utf8) >> + =A0 =A0end. >> + >> +tokenize_string(B, S=3D#decoder{offset=3DO}, Acc) -> >> + =A0 =A0case B of >> + =A0 =A0 =A0 =A0<<_:O/binary, ?Q, _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0{{const, iolist_to_binary(lists:reverse(Acc))},= ?INC_COL(S)}; >> + =A0 =A0 =A0 =A0<<_:O/binary, "\\\"", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 2), [$\" | Acc])= ; >> + =A0 =A0 =A0 =A0<<_:O/binary, "\\\\", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 2), [$\\ | Acc])= ; >> + =A0 =A0 =A0 =A0<<_:O/binary, "\\/", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 2), [$/ | Acc]); >> + =A0 =A0 =A0 =A0<<_:O/binary, "\\b", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 2), [$\b | Acc])= ; >> + =A0 =A0 =A0 =A0<<_:O/binary, "\\f", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 2), [$\f | Acc])= ; >> + =A0 =A0 =A0 =A0<<_:O/binary, "\\n", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 2), [$\n | Acc])= ; >> + =A0 =A0 =A0 =A0<<_:O/binary, "\\r", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 2), [$\r | Acc])= ; >> + =A0 =A0 =A0 =A0<<_:O/binary, "\\t", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 2), [$\t | Acc])= ; >> + =A0 =A0 =A0 =A0<<_:O/binary, "\\u", C3, C2, C1, C0, Rest/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0C =3D erlang:list_to_integer([C3, C2, C1, C0], = 16), >> + =A0 =A0 =A0 =A0 =A0 =A0if C > 16#D7FF, C < 16#DC00 -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0%% coalesce UTF-16 surrogate pair >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0<<"\\u", D3, D2, D1, D0, _/binary>> =3D= Rest, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0D =3D erlang:list_to_integer([D3,D2,D1,= D0], 16), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0[CodePoint] =3D xmerl_ucs:from_utf16be(= <> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0D:16/big-unsigned-integer>>), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Acc1 =3D lists:reverse(xmerl_ucs:to_utf= 8(CodePoint), Acc), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 12), Acc= 1); >> + =A0 =A0 =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Acc1 =3D lists:reverse(xmerl_ucs:to_utf= 8(C), Acc), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 6), Acc1= ) >> + =A0 =A0 =A0 =A0 =A0 =A0end; >> + =A0 =A0 =A0 =A0<<_:O/binary, C1, _/binary>> when C1 < 128 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?INC_CHAR(S, C1), [C1 | Acc]= ); >> + =A0 =A0 =A0 =A0<<_:O/binary, C1, C2, _/binary>> when C1 >=3D 194, C1 = =3D< 223, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0C2 >=3D 128, C2 =3D< 191 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 2), [C2, C1 | Ac= c]); >> + =A0 =A0 =A0 =A0<<_:O/binary, C1, C2, C3, _/binary>> when C1 >=3D 224, = C1 =3D< 239, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0C2 >=3D 128, C2 =3D< 191, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0C3 >=3D 128, C3 =3D< 191 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 3), [C3, C2, C1 = | Acc]); >> + =A0 =A0 =A0 =A0<<_:O/binary, C1, C2, C3, C4, _/binary>> when C1 >=3D 2= 40, C1 =3D< 244, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0C2 >=3D 128, C2 =3D< 191, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0C3 >=3D 128, C3 =3D< 191, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0C4 >=3D 128, C4 =3D< 191 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?ADV_COL(S, 4), [C4, C3, C2,= C1 | Acc]); >> + =A0 =A0 =A0 =A0_ -> >> + =A0 =A0 =A0 =A0 =A0 =A0throw(invalid_utf8) >> + =A0 =A0end. >> + >> +tokenize_number(B, S) -> >> + =A0 =A0case tokenize_number(B, sign, S, []) of >> + =A0 =A0 =A0 =A0{{int, Int}, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0{{const, list_to_integer(Int)}, S1}; >> + =A0 =A0 =A0 =A0{{float, Float}, S1} -> >> + =A0 =A0 =A0 =A0 =A0 =A0{{const, list_to_float(Float)}, S1} >> + =A0 =A0end. >> + >> +tokenize_number(B, sign, S=3D#decoder{offset=3DO}, []) -> >> + =A0 =A0case B of >> + =A0 =A0 =A0 =A0<<_:O/binary, $-, _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, int, ?INC_COL(S), [$-]); >> + =A0 =A0 =A0 =A0_ -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, int, S, []) >> + =A0 =A0end; >> +tokenize_number(B, int, S=3D#decoder{offset=3DO}, Acc) -> >> + =A0 =A0case B of >> + =A0 =A0 =A0 =A0<<_:O/binary, $0, _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, frac, ?INC_COL(S), [$0 | Acc= ]); >> + =A0 =A0 =A0 =A0<<_:O/binary, C, _/binary>> when C >=3D $1 andalso C = =3D< $9 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, int1, ?INC_COL(S), [C | Acc]= ) >> + =A0 =A0end; >> +tokenize_number(B, int1, S=3D#decoder{offset=3DO}, Acc) -> >> + =A0 =A0case B of >> + =A0 =A0 =A0 =A0<<_:O/binary, C, _/binary>> when C >=3D $0 andalso C = =3D< $9 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, int1, ?INC_COL(S), [C | Acc]= ); >> + =A0 =A0 =A0 =A0_ -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, frac, S, Acc) >> + =A0 =A0end; >> +tokenize_number(B, frac, S=3D#decoder{offset=3DO}, Acc) -> >> + =A0 =A0case B of >> + =A0 =A0 =A0 =A0<<_:O/binary, $., C, _/binary>> when C >=3D $0, C =3D< = $9 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, frac1, ?ADV_COL(S, 2), [C, $= . | Acc]); >> + =A0 =A0 =A0 =A0<<_:O/binary, E, _/binary>> when E =3D:=3D $e orelse E = =3D:=3D $E -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, esign, ?INC_COL(S), [$e, $0,= $. | Acc]); >> + =A0 =A0 =A0 =A0_ -> >> + =A0 =A0 =A0 =A0 =A0 =A0{{int, lists:reverse(Acc)}, S} >> + =A0 =A0end; >> +tokenize_number(B, frac1, S=3D#decoder{offset=3DO}, Acc) -> >> + =A0 =A0case B of >> + =A0 =A0 =A0 =A0<<_:O/binary, C, _/binary>> when C >=3D $0 andalso C = =3D< $9 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, frac1, ?INC_COL(S), [C | Acc= ]); >> + =A0 =A0 =A0 =A0<<_:O/binary, E, _/binary>> when E =3D:=3D $e orelse E = =3D:=3D $E -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, esign, ?INC_COL(S), [$e | Ac= c]); >> + =A0 =A0 =A0 =A0_ -> >> + =A0 =A0 =A0 =A0 =A0 =A0{{float, lists:reverse(Acc)}, S} >> + =A0 =A0end; >> +tokenize_number(B, esign, S=3D#decoder{offset=3DO}, Acc) -> >> + =A0 =A0case B of >> + =A0 =A0 =A0 =A0<<_:O/binary, C, _/binary>> when C =3D:=3D $- orelse C= =3D:=3D $+ -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, eint, ?INC_COL(S), [C | Acc]= ); >> + =A0 =A0 =A0 =A0_ -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, eint, S, Acc) >> + =A0 =A0end; >> +tokenize_number(B, eint, S=3D#decoder{offset=3DO}, Acc) -> >> + =A0 =A0case B of >> + =A0 =A0 =A0 =A0<<_:O/binary, C, _/binary>> when C >=3D $0 andalso C = =3D< $9 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, eint1, ?INC_COL(S), [C | Acc= ]) >> + =A0 =A0end; >> +tokenize_number(B, eint1, S=3D#decoder{offset=3DO}, Acc) -> >> + =A0 =A0case B of >> + =A0 =A0 =A0 =A0<<_:O/binary, C, _/binary>> when C >=3D $0 andalso C = =3D< $9 -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, eint1, ?INC_COL(S), [C | Acc= ]); >> + =A0 =A0 =A0 =A0_ -> >> + =A0 =A0 =A0 =A0 =A0 =A0{{float, lists:reverse(Acc)}, S} >> + =A0 =A0end. >> + >> +tokenize(B, S=3D#decoder{offset=3DO}) -> >> + =A0 =A0case B of >> + =A0 =A0 =A0 =A0<<_:O/binary, C, _/binary>> when ?IS_WHITESPACE(C) -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize(B, ?INC_CHAR(S, C)); >> + =A0 =A0 =A0 =A0<<_:O/binary, "{", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0{start_object, ?INC_COL(S)}; >> + =A0 =A0 =A0 =A0<<_:O/binary, "}", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0{end_object, ?INC_COL(S)}; >> + =A0 =A0 =A0 =A0<<_:O/binary, "[", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0{start_array, ?INC_COL(S)}; >> + =A0 =A0 =A0 =A0<<_:O/binary, "]", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0{end_array, ?INC_COL(S)}; >> + =A0 =A0 =A0 =A0<<_:O/binary, ",", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0{comma, ?INC_COL(S)}; >> + =A0 =A0 =A0 =A0<<_:O/binary, ":", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0{colon, ?INC_COL(S)}; >> + =A0 =A0 =A0 =A0<<_:O/binary, "null", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0{{const, null}, ?ADV_COL(S, 4)}; >> + =A0 =A0 =A0 =A0<<_:O/binary, "true", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0{{const, true}, ?ADV_COL(S, 4)}; >> + =A0 =A0 =A0 =A0<<_:O/binary, "false", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0{{const, false}, ?ADV_COL(S, 5)}; >> + =A0 =A0 =A0 =A0<<_:O/binary, "\"", _/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_string(B, ?INC_COL(S)); >> + =A0 =A0 =A0 =A0<<_:O/binary, C, _/binary>> when (C >=3D $0 andalso C = =3D< $9) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 orelse C =3D:=3D $- -> >> + =A0 =A0 =A0 =A0 =A0 =A0tokenize_number(B, S); >> + =A0 =A0 =A0 =A0<<_:O/binary>> -> >> + =A0 =A0 =A0 =A0 =A0 =A0trim =3D S#decoder.state, >> + =A0 =A0 =A0 =A0 =A0 =A0{eof, S} >> + =A0 =A0end. >> +%% >> +%% Tests >> +%% >> +-ifdef(TEST). >> +-include_lib("eunit/include/eunit.hrl"). >> + >> + >> +%% testing constructs borrowed from the Yaws JSON implementation. >> + >> +%% Create an object from a list of Key/Value pairs. >> + >> +obj_new() -> >> + =A0 =A0{struct, []}. >> + >> +is_obj({struct, Props}) -> >> + =A0 =A0F =3D fun ({K, _}) when is_binary(K) -> true end, >> + =A0 =A0lists:all(F, Props). >> + >> +obj_from_list(Props) -> >> + =A0 =A0Obj =3D {struct, Props}, >> + =A0 =A0?assert(is_obj(Obj)), >> + =A0 =A0Obj. >> + >> +%% Test for equivalence of Erlang terms. >> +%% Due to arbitrary order of construction, equivalent objects might >> +%% compare unequal as erlang terms, so we need to carefully recurse >> +%% through aggregates (tuples and objects). >> + >> +equiv({struct, Props1}, {struct, Props2}) -> >> + =A0 =A0equiv_object(Props1, Props2); >> +equiv(L1, L2) when is_list(L1), is_list(L2) -> >> + =A0 =A0equiv_list(L1, L2); >> +equiv(N1, N2) when is_number(N1), is_number(N2) -> N1 =3D=3D N2; >> +equiv(B1, B2) when is_binary(B1), is_binary(B2) -> B1 =3D=3D B2; >> +equiv(A, A) when A =3D:=3D true orelse A =3D:=3D false orelse A =3D:=3D= null -> true. >> + >> +%% Object representation and traversal order is unknown. >> +%% Use the sledgehammer and sort property lists. >> + >> +equiv_object(Props1, Props2) -> >> + =A0 =A0L1 =3D lists:keysort(1, Props1), >> + =A0 =A0L2 =3D lists:keysort(1, Props2), >> + =A0 =A0Pairs =3D lists:zip(L1, L2), >> + =A0 =A0true =3D lists:all(fun({{K1, V1}, {K2, V2}}) -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 equiv(K1, K2) = and equiv(V1, V2) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 end, Pairs). >> + >> +%% Recursively compare tuple elements for equivalence. >> + >> +equiv_list([], []) -> >> + =A0 =A0true; >> +equiv_list([V1 | L1], [V2 | L2]) -> >> + =A0 =A0equiv(V1, V2) andalso equiv_list(L1, L2). >> + >> +decode_test() -> >> + =A0 =A0[1199344435545.0, 1] =3D decode(<<"[1199344435545.0,1]">>), >> + =A0 =A0<<16#F0,16#9D,16#9C,16#95>> =3D decode([34,"\\ud835","\\udf15",= 34]). >> + >> +e2j_vec_test() -> >> + =A0 =A0test_one(e2j_test_vec(utf8), 1). >> + >> +test_one([], _N) -> >> + =A0 =A0%% io:format("~p tests passed~n", [N-1]), >> + =A0 =A0ok; >> +test_one([{E, J} | Rest], N) -> >> + =A0 =A0%% io:format("[~p] ~p ~p~n", [N, E, J]), >> + =A0 =A0true =3D equiv(E, decode(J)), >> + =A0 =A0true =3D equiv(E, decode(encode(E))), >> + =A0 =A0test_one(Rest, 1+N). >> + >> +e2j_test_vec(utf8) -> >> + =A0 =A0[ >> + =A0 =A0 {1, "1"}, >> + =A0 =A0 {3.1416, "3.14160"}, %% text representation may truncate, trai= l zeroes >> + =A0 =A0 {-1, "-1"}, >> + =A0 =A0 {-3.1416, "-3.14160"}, >> + =A0 =A0 {12.0e10, "1.20000e+11"}, >> + =A0 =A0 {1.234E+10, "1.23400e+10"}, >> + =A0 =A0 {-1.234E-10, "-1.23400e-10"}, >> + =A0 =A0 {10.0, "1.0e+01"}, >> + =A0 =A0 {123.456, "1.23456E+2"}, >> + =A0 =A0 {10.0, "1e1"}, >> + =A0 =A0 {<<"foo">>, "\"foo\""}, >> + =A0 =A0 {<<"foo", 5, "bar">>, "\"foo\\u0005bar\""}, >> + =A0 =A0 {<<"">>, "\"\""}, >> + =A0 =A0 {<<"\n\n\n">>, "\"\\n\\n\\n\""}, >> + =A0 =A0 {<<"\" \b\f\r\n\t\"">>, "\"\\\" \\b\\f\\r\\n\\t\\\"\""}, >> + =A0 =A0 {obj_new(), "{}"}, >> + =A0 =A0 {obj_from_list([{<<"foo">>, <<"bar">>}]), "{\"foo\":\"bar\"}"}= , >> + =A0 =A0 {obj_from_list([{<<"foo">>, <<"bar">>}, {<<"baz">>, 123}]), >> + =A0 =A0 =A0"{\"foo\":\"bar\",\"baz\":123}"}, >> + =A0 =A0 {[], "[]"}, >> + =A0 =A0 {[[]], "[[]]"}, >> + =A0 =A0 {[1, <<"foo">>], "[1,\"foo\"]"}, >> + >> + =A0 =A0 %% json array in a json object >> + =A0 =A0 {obj_from_list([{<<"foo">>, [123]}]), >> + =A0 =A0 =A0"{\"foo\":[123]}"}, >> + >> + =A0 =A0 %% json object in a json object >> + =A0 =A0 {obj_from_list([{<<"foo">>, obj_from_list([{<<"bar">>, true}])= }]), >> + =A0 =A0 =A0"{\"foo\":{\"bar\":true}}"}, >> + >> + =A0 =A0 %% fold evaluation order >> + =A0 =A0 {obj_from_list([{<<"foo">>, []}, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 {<<"bar">>, obj_from_list([{<<= "baz">>, true}])}, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 {<<"alice">>, <<"bob">>}]), >> + =A0 =A0 =A0"{\"foo\":[],\"bar\":{\"baz\":true},\"alice\":\"bob\"}"}, >> + >> + =A0 =A0 %% json object in a json array >> + =A0 =A0 {[-123, <<"foo">>, obj_from_list([{<<"bar">>, []}]), null], >> + =A0 =A0 =A0"[-123,\"foo\",{\"bar\":[]},null]"} >> + =A0 =A0]. >> + >> +%% test utf8 encoding >> +encoder_utf8_test() -> >> + =A0 =A0%% safe conversion case (default) >> + =A0 =A0[34,"\\u0001","\\u0442","\\u0435","\\u0441","\\u0442",34] =3D >> + =A0 =A0 =A0 =A0encode(<<1,"\321\202\320\265\321\201\321\202">>), >> + >> + =A0 =A0%% raw utf8 output (optional) >> + =A0 =A0Enc =3D mochijson2:encoder([{utf8, true}]), >> + =A0 =A0[34,"\\u0001",[209,130],[208,181],[209,129],[209,130],34] =3D >> + =A0 =A0 =A0 =A0Enc(<<1,"\321\202\320\265\321\201\321\202">>). >> + >> +input_validation_test() -> >> + =A0 =A0Good =3D [ >> + =A0 =A0 =A0 =A0{16#00A3, <>}, %% pound >> + =A0 =A0 =A0 =A0{16#20AC, <>}, %% euro >> + =A0 =A0 =A0 =A0{16#10196, <>} %% d= enarius >> + =A0 =A0], >> + =A0 =A0lists:foreach(fun({CodePoint, UTF8}) -> >> + =A0 =A0 =A0 =A0Expect =3D list_to_binary(xmerl_ucs:to_utf8(CodePoint))= , >> + =A0 =A0 =A0 =A0Expect =3D decode(UTF8) >> + =A0 =A0end, Good), >> + >> + =A0 =A0Bad =3D [ >> + =A0 =A0 =A0 =A0%% 2nd, 3rd, or 4th byte of a multi-byte sequence w/o l= eading byte >> + =A0 =A0 =A0 =A0<>, >> + =A0 =A0 =A0 =A0%% missing continuations, last byte in each should be 8= 0-BF >> + =A0 =A0 =A0 =A0<>, >> + =A0 =A0 =A0 =A0<>, >> + =A0 =A0 =A0 =A0<>, >> + =A0 =A0 =A0 =A0%% we don't support code points > 10FFFF per RFC 3629 >> + =A0 =A0 =A0 =A0<>, >> + =A0 =A0 =A0 =A0%% escape characters trigger a different code path >> + =A0 =A0 =A0 =A0<> >> + =A0 =A0], >> + =A0 =A0lists:foreach( >> + =A0 =A0 =A0fun(X) -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0ok =3D try decode(X) catch invalid_utf8 -> = ok end, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0%% could be {ucs,{bad_utf8_character_code}}= or >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0%% =A0 =A0 =A0 =A0 =A0{json_encode,{bad_cha= r,_}} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0{'EXIT', _} =3D (catch encode(X)) >> + =A0 =A0 =A0end, Bad). >> + >> +inline_json_test() -> >> + =A0 =A0?assertEqual(<<"\"iodata iodata\"">>, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 iolist_to_binary( >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 encode({json, [<<"\"iodata">>, " i= odata\""]}))), >> + =A0 =A0?assertEqual({struct, [{<<"key">>, <<"iodata iodata">>}]}, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 decode( >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 encode({struct, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 [{key, {json, [<<"= \"iodata">>, " iodata\""]}}]}))), >> + =A0 =A0ok. >> + >> +big_unicode_test() -> >> + =A0 =A0UTF8Seq =3D list_to_binary(xmerl_ucs:to_utf8(16#0001d120)), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 <<"\"\\ud834\\udd20\"">>, >> + =A0 =A0 =A0 iolist_to_binary(encode(UTF8Seq))), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 UTF8Seq, >> + =A0 =A0 =A0 decode(iolist_to_binary(encode(UTF8Seq)))), >> + =A0 =A0ok. >> + >> +custom_decoder_test() -> >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 {struct, [{<<"key">>, <<"value">>}]}, >> + =A0 =A0 =A0 (decoder([]))("{\"key\": \"value\"}")), >> + =A0 =A0F =3D fun ({struct, [{<<"key">>, <<"value">>}]}) -> win end, >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 win, >> + =A0 =A0 =A0 (decoder([{object_hook, F}]))("{\"key\": \"value\"}")), >> + =A0 =A0ok. >> + >> +atom_test() -> >> + =A0 =A0%% JSON native atoms >> + =A0 =A0[begin >> + =A0 =A0 =A0 =A0 ?assertEqual(A, decode(atom_to_list(A))), >> + =A0 =A0 =A0 =A0 ?assertEqual(iolist_to_binary(atom_to_list(A)), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0iolist_to_binary(encode(A))= ) >> + =A0 =A0 end || A <- [true, false, null]], >> + =A0 =A0%% Atom to string >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 <<"\"foo\"">>, >> + =A0 =A0 =A0 iolist_to_binary(encode(foo))), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 <<"\"\\ud834\\udd20\"">>, >> + =A0 =A0 =A0 iolist_to_binary(encode(list_to_atom(xmerl_ucs:to_utf8(16#= 0001d120))))), >> + =A0 =A0ok. >> + >> +key_encode_test() -> >> + =A0 =A0%% Some forms are accepted as keys that would not be strings in= other >> + =A0 =A0%% cases >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 <<"{\"foo\":1}">>, >> + =A0 =A0 =A0 iolist_to_binary(encode({struct, [{foo, 1}]}))), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 <<"{\"foo\":1}">>, >> + =A0 =A0 =A0 iolist_to_binary(encode({struct, [{<<"foo">>, 1}]}))), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 <<"{\"foo\":1}">>, >> + =A0 =A0 =A0 iolist_to_binary(encode({struct, [{"foo", 1}]}))), >> + =A0 =A0 =A0 ?assertEqual( >> + =A0 =A0 =A0 <<"{\"foo\":1}">>, >> + =A0 =A0 =A0 iolist_to_binary(encode([{foo, 1}]))), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 <<"{\"foo\":1}">>, >> + =A0 =A0 =A0 iolist_to_binary(encode([{<<"foo">>, 1}]))), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 <<"{\"foo\":1}">>, >> + =A0 =A0 =A0 iolist_to_binary(encode([{"foo", 1}]))), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 <<"{\"\\ud834\\udd20\":1}">>, >> + =A0 =A0 =A0 iolist_to_binary( >> + =A0 =A0 =A0 =A0 encode({struct, [{[16#0001d120], 1}]}))), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 <<"{\"1\":1}">>, >> + =A0 =A0 =A0 iolist_to_binary(encode({struct, [{1, 1}]}))), >> + =A0 =A0ok. >> + >> +unsafe_chars_test() -> >> + =A0 =A0Chars =3D "\"\\\b\f\n\r\t", >> + =A0 =A0[begin >> + =A0 =A0 =A0 =A0 ?assertEqual(false, json_string_is_safe([C])), >> + =A0 =A0 =A0 =A0 ?assertEqual(false, json_bin_is_safe(<>)), >> + =A0 =A0 =A0 =A0 ?assertEqual(<>, decode(encode(<>))) >> + =A0 =A0 end || C <- Chars], >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 false, >> + =A0 =A0 =A0 json_string_is_safe([16#0001d120])), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 false, >> + =A0 =A0 =A0 json_bin_is_safe(list_to_binary(xmerl_ucs:to_utf8(16#0001d= 120)))), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 [16#0001d120], >> + =A0 =A0 =A0 xmerl_ucs:from_utf8( >> + =A0 =A0 =A0 =A0 binary_to_list( >> + =A0 =A0 =A0 =A0 =A0 decode(encode(list_to_atom(xmerl_ucs:to_utf8(16#00= 01d120))))))), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 false, >> + =A0 =A0 =A0 json_string_is_safe([16#110000])), >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 false, >> + =A0 =A0 =A0 json_bin_is_safe(list_to_binary(xmerl_ucs:to_utf8([16#1100= 00])))), >> + =A0 =A0%% solidus can be escaped but isn't unsafe by default >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 <<"/">>, >> + =A0 =A0 =A0 decode(<<"\"\\/\"">>)), >> + =A0 =A0ok. >> + >> +int_test() -> >> + =A0 =A0?assertEqual(0, decode("0")), >> + =A0 =A0?assertEqual(1, decode("1")), >> + =A0 =A0?assertEqual(11, decode("11")), >> + =A0 =A0ok. >> + >> +large_int_test() -> >> + =A0 =A0?assertEqual(<<"-2147483649214748364921474836492147483649">>, >> + =A0 =A0 =A0 =A0iolist_to_binary(encode(-214748364921474836492147483649= 2147483649))), >> + =A0 =A0?assertEqual(<<"2147483649214748364921474836492147483649">>, >> + =A0 =A0 =A0 =A0iolist_to_binary(encode(2147483649214748364921474836492= 147483649))), >> + =A0 =A0ok. >> + >> +float_test() -> >> + =A0 =A0?assertEqual(<<"-2147483649.0">>, iolist_to_binary(encode(-2147= 483649.0))), >> + =A0 =A0?assertEqual(<<"2147483648.0">>, iolist_to_binary(encode(214748= 3648.0))), >> + =A0 =A0ok. >> + >> +handler_test() -> >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 {'EXIT',{json_encode,{bad_term,{}}}}, >> + =A0 =A0 =A0 catch encode({})), >> + =A0 =A0F =3D fun ({}) -> [] end, >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 <<"[]">>, >> + =A0 =A0 =A0 iolist_to_binary((encoder([{handler, F}]))({}))), >> + =A0 =A0ok. >> + >> +-endif. >> >> Added: couchdb/trunk/src/ejson/mochinum.erl >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/mochinum.erl?r= ev=3D1088941&view=3Dauto >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/ejson/mochinum.erl (added) >> +++ couchdb/trunk/src/ejson/mochinum.erl Tue Apr =A05 09:42:41 2011 >> @@ -0,0 +1,354 @@ >> +%% @copyright 2007 Mochi Media, Inc. >> +%% @author Bob Ippolito >> + >> +%% @doc Useful numeric algorithms for floats that cover some deficienci= es >> +%% in the math module. More interesting is digits/1, which implements >> +%% the algorithm from: >> +%% http://www.cs.indiana.edu/~burger/fp/index.html >> +%% See also "Printing Floating-Point Numbers Quickly and Accurately" >> +%% in Proceedings of the SIGPLAN '96 Conference on Programming Language >> +%% Design and Implementation. >> + >> +-module(mochinum). >> +-author("Bob Ippolito "). >> +-export([digits/1, frexp/1, int_pow/2, int_ceil/1]). >> + >> +%% IEEE 754 Float exponent bias >> +-define(FLOAT_BIAS, 1022). >> +-define(MIN_EXP, -1074). >> +-define(BIG_POW, 4503599627370496). >> + >> +%% External API >> + >> +%% @spec digits(number()) -> string() >> +%% @doc =A0Returns a string that accurately represents the given intege= r or float >> +%% =A0 =A0 =A0 using a conservative amount of digits. Great for generat= ing >> +%% =A0 =A0 =A0 human-readable output, or compact ASCII serializations f= or floats. >> +digits(N) when is_integer(N) -> >> + =A0 =A0integer_to_list(N); >> +digits(0.0) -> >> + =A0 =A0"0.0"; >> +digits(Float) -> >> + =A0 =A0{Frac1, Exp1} =3D frexp_int(Float), >> + =A0 =A0[Place0 | Digits0] =3D digits1(Float, Exp1, Frac1), >> + =A0 =A0{Place, Digits} =3D transform_digits(Place0, Digits0), >> + =A0 =A0R =3D insert_decimal(Place, Digits), >> + =A0 =A0case Float < 0 of >> + =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0[$- | R]; >> + =A0 =A0 =A0 =A0_ -> >> + =A0 =A0 =A0 =A0 =A0 =A0R >> + =A0 =A0end. >> + >> +%% @spec frexp(F::float()) -> {Frac::float(), Exp::float()} >> +%% @doc =A0Return the fractional and exponent part of an IEEE 754 doubl= e, >> +%% =A0 =A0 =A0 equivalent to the libc function of the same name. >> +%% =A0 =A0 =A0 F =3D Frac * pow(2, Exp). >> +frexp(F) -> >> + =A0 =A0frexp1(unpack(F)). >> + >> +%% @spec int_pow(X::integer(), N::integer()) -> Y::integer() >> +%% @doc =A0Moderately efficient way to exponentiate integers. >> +%% =A0 =A0 =A0 int_pow(10, 2) =3D 100. >> +int_pow(_X, 0) -> >> + =A0 =A01; >> +int_pow(X, N) when N > 0 -> >> + =A0 =A0int_pow(X, N, 1). >> + >> +%% @spec int_ceil(F::float()) -> integer() >> +%% @doc =A0Return the ceiling of F as an integer. The ceiling is define= d as >> +%% =A0 =A0 =A0 F when F =3D=3D trunc(F); >> +%% =A0 =A0 =A0 trunc(F) when F < 0; >> +%% =A0 =A0 =A0 trunc(F) + 1 when F > 0. >> +int_ceil(X) -> >> + =A0 =A0T =3D trunc(X), >> + =A0 =A0case (X - T) of >> + =A0 =A0 =A0 =A0Pos when Pos > 0 -> T + 1; >> + =A0 =A0 =A0 =A0_ -> T >> + =A0 =A0end. >> + >> + >> +%% Internal API >> + >> +int_pow(X, N, R) when N < 2 -> >> + =A0 =A0R * X; >> +int_pow(X, N, R) -> >> + =A0 =A0int_pow(X * X, N bsr 1, case N band 1 of 1 -> R * X; 0 -> R end= ). >> + >> +insert_decimal(0, S) -> >> + =A0 =A0"0." ++ S; >> +insert_decimal(Place, S) when Place > 0 -> >> + =A0 =A0L =3D length(S), >> + =A0 =A0case Place - L of >> + =A0 =A0 =A0 =A0 0 -> >> + =A0 =A0 =A0 =A0 =A0 =A0S ++ ".0"; >> + =A0 =A0 =A0 =A0N when N < 0 -> >> + =A0 =A0 =A0 =A0 =A0 =A0{S0, S1} =3D lists:split(L + N, S), >> + =A0 =A0 =A0 =A0 =A0 =A0S0 ++ "." ++ S1; >> + =A0 =A0 =A0 =A0N when N < 6 -> >> + =A0 =A0 =A0 =A0 =A0 =A0%% More places than digits >> + =A0 =A0 =A0 =A0 =A0 =A0S ++ lists:duplicate(N, $0) ++ ".0"; >> + =A0 =A0 =A0 =A0_ -> >> + =A0 =A0 =A0 =A0 =A0 =A0insert_decimal_exp(Place, S) >> + =A0 =A0end; >> +insert_decimal(Place, S) when Place > -6 -> >> + =A0 =A0"0." ++ lists:duplicate(abs(Place), $0) ++ S; >> +insert_decimal(Place, S) -> >> + =A0 =A0insert_decimal_exp(Place, S). >> + >> +insert_decimal_exp(Place, S) -> >> + =A0 =A0[C | S0] =3D S, >> + =A0 =A0S1 =3D case S0 of >> + =A0 =A0 =A0 =A0 =A0 =A0 [] -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "0"; >> + =A0 =A0 =A0 =A0 =A0 =A0 _ -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 S0 >> + =A0 =A0 =A0 =A0 end, >> + =A0 =A0Exp =3D case Place < 0 of >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"e-"; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"e+" >> + =A0 =A0 =A0 =A0 =A0end, >> + =A0 =A0[C] ++ "." ++ S1 ++ Exp ++ integer_to_list(abs(Place - 1)). >> + >> + >> +digits1(Float, Exp, Frac) -> >> + =A0 =A0Round =3D ((Frac band 1) =3D:=3D 0), >> + =A0 =A0case Exp >=3D 0 of >> + =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0BExp =3D 1 bsl Exp, >> + =A0 =A0 =A0 =A0 =A0 =A0case (Frac =3D/=3D ?BIG_POW) of >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0scale((Frac * BExp * 2), 2, BEx= p, BExp, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Round, Round, Float= ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0scale((Frac * BExp * 4), 4, (BE= xp * 2), BExp, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Round, Round, Float= ) >> + =A0 =A0 =A0 =A0 =A0 =A0end; >> + =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0case (Exp =3D:=3D ?MIN_EXP) orelse (Frac =3D/= =3D ?BIG_POW) of >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0scale((Frac * 2), 1 bsl (1 - Ex= p), 1, 1, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Round, Round, Float= ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0scale((Frac * 4), 1 bsl (2 - Ex= p), 2, 1, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Round, Round, Float= ) >> + =A0 =A0 =A0 =A0 =A0 =A0end >> + =A0 =A0end. >> + >> +scale(R, S, MPlus, MMinus, LowOk, HighOk, Float) -> >> + =A0 =A0Est =3D int_ceil(math:log10(abs(Float)) - 1.0e-10), >> + =A0 =A0%% Note that the scheme implementation uses a 326 element look-= up table >> + =A0 =A0%% for int_pow(10, N) where we do not. >> + =A0 =A0case Est >=3D 0 of >> + =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0fixup(R, S * int_pow(10, Est), MPlus, MMinus, E= st, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0LowOk, HighOk); >> + =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0Scale =3D int_pow(10, -Est), >> + =A0 =A0 =A0 =A0 =A0 =A0fixup(R * Scale, S, MPlus * Scale, MMinus * Sca= le, Est, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0LowOk, HighOk) >> + =A0 =A0end. >> + >> +fixup(R, S, MPlus, MMinus, K, LowOk, HighOk) -> >> + =A0 =A0TooLow =3D case HighOk of >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 true -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (R + MPlus) >=3D S; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 false -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (R + MPlus) > S >> + =A0 =A0 =A0 =A0 =A0 =A0 end, >> + =A0 =A0case TooLow of >> + =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0[(K + 1) | generate(R, S, MPlus, MMinus, LowOk,= HighOk)]; >> + =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0[K | generate(R * 10, S, MPlus * 10, MMinus * 1= 0, LowOk, HighOk)] >> + =A0 =A0end. >> + >> +generate(R0, S, MPlus, MMinus, LowOk, HighOk) -> >> + =A0 =A0D =3D R0 div S, >> + =A0 =A0R =3D R0 rem S, >> + =A0 =A0TC1 =3D case LowOk of >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0R =3D< MMinus; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0R < MMinus >> + =A0 =A0 =A0 =A0 =A0end, >> + =A0 =A0TC2 =3D case HighOk of >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(R + MPlus) >=3D S; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(R + MPlus) > S >> + =A0 =A0 =A0 =A0 =A0end, >> + =A0 =A0case TC1 of >> + =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0case TC2 of >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0[D | generate(R * 10, S, MPlus = * 10, MMinus * 10, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Low= Ok, HighOk)]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0[D + 1] >> + =A0 =A0 =A0 =A0 =A0 =A0end; >> + =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0case TC2 of >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0[D]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0case R * 2 < S of >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0true -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0[D]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0false -> >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0[D + 1] >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0end >> + =A0 =A0 =A0 =A0 =A0 =A0end >> + =A0 =A0end. >> + >> +unpack(Float) -> >> + =A0 =A0<> =3D <>, >> + =A0 =A0{Sign, Exp, Frac}. >> + >> +frexp1({_Sign, 0, 0}) -> >> + =A0 =A0{0.0, 0}; >> +frexp1({Sign, 0, Frac}) -> >> + =A0 =A0Exp =3D log2floor(Frac), >> + =A0 =A0<> =3D <>, >> + =A0 =A0{Frac1, -(?FLOAT_BIAS) - 52 + Exp}; >> +frexp1({Sign, Exp, Frac}) -> >> + =A0 =A0<> =3D <>, >> + =A0 =A0{Frac1, Exp - ?FLOAT_BIAS}. >> + >> +log2floor(Int) -> >> + =A0 =A0log2floor(Int, 0). >> + >> +log2floor(0, N) -> >> + =A0 =A0N; >> +log2floor(Int, N) -> >> + =A0 =A0log2floor(Int bsr 1, 1 + N). >> + >> + >> +transform_digits(Place, [0 | Rest]) -> >> + =A0 =A0transform_digits(Place, Rest); >> +transform_digits(Place, Digits) -> >> + =A0 =A0{Place, [$0 + D || D <- Digits]}. >> + >> + >> +frexp_int(F) -> >> + =A0 =A0case unpack(F) of >> + =A0 =A0 =A0 =A0{_Sign, 0, Frac} -> >> + =A0 =A0 =A0 =A0 =A0 =A0{Frac, ?MIN_EXP}; >> + =A0 =A0 =A0 =A0{_Sign, Exp, Frac} -> >> + =A0 =A0 =A0 =A0 =A0 =A0{Frac + (1 bsl 52), Exp - 53 - ?FLOAT_BIAS} >> + =A0 =A0end. >> + >> +%% >> +%% Tests >> +%% >> +-ifdef(TEST). >> +-include_lib("eunit/include/eunit.hrl"). >> + >> +int_ceil_test() -> >> + =A0 =A0?assertEqual(1, int_ceil(0.0001)), >> + =A0 =A0?assertEqual(0, int_ceil(0.0)), >> + =A0 =A0?assertEqual(1, int_ceil(0.99)), >> + =A0 =A0?assertEqual(1, int_ceil(1.0)), >> + =A0 =A0?assertEqual(-1, int_ceil(-1.5)), >> + =A0 =A0?assertEqual(-2, int_ceil(-2.0)), >> + =A0 =A0ok. >> + >> +int_pow_test() -> >> + =A0 =A0?assertEqual(1, int_pow(1, 1)), >> + =A0 =A0?assertEqual(1, int_pow(1, 0)), >> + =A0 =A0?assertEqual(1, int_pow(10, 0)), >> + =A0 =A0?assertEqual(10, int_pow(10, 1)), >> + =A0 =A0?assertEqual(100, int_pow(10, 2)), >> + =A0 =A0?assertEqual(1000, int_pow(10, 3)), >> + =A0 =A0ok. >> + >> +digits_test() -> >> + =A0 =A0?assertEqual("0", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(0)), >> + =A0 =A0?assertEqual("0.0", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(0.0)), >> + =A0 =A0?assertEqual("1.0", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(1.0)), >> + =A0 =A0?assertEqual("-1.0", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(-1.0)), >> + =A0 =A0?assertEqual("0.1", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(0.1)), >> + =A0 =A0?assertEqual("0.01", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(0.01)), >> + =A0 =A0?assertEqual("0.001", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(0.001)), >> + =A0 =A0?assertEqual("1.0e+6", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(1000000.0)), >> + =A0 =A0?assertEqual("0.5", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(0.5)), >> + =A0 =A0?assertEqual("4503599627370496.0", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(4503599627370496.0)), >> + =A0 =A0%% small denormalized number >> + =A0 =A0%% 4.94065645841246544177e-324 =3D:=3D 5.0e-324 >> + =A0 =A0<> =3D <<0,0,0,0,0,0,0,1>>, >> + =A0 =A0?assertEqual("5.0e-324", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(SmallDenorm)), >> + =A0 =A0?assertEqual(SmallDenorm, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_to_float(digits(SmallDenorm))), >> + =A0 =A0%% large denormalized number >> + =A0 =A0%% 2.22507385850720088902e-308 >> + =A0 =A0<> =3D <<0,15,255,255,255,255,255,255>>, >> + =A0 =A0?assertEqual("2.225073858507201e-308", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(BigDenorm)), >> + =A0 =A0?assertEqual(BigDenorm, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_to_float(digits(BigDenorm))), >> + =A0 =A0%% small normalized number >> + =A0 =A0%% 2.22507385850720138309e-308 >> + =A0 =A0<> =3D <<0,16,0,0,0,0,0,0>>, >> + =A0 =A0?assertEqual("2.2250738585072014e-308", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(SmallNorm)), >> + =A0 =A0?assertEqual(SmallNorm, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_to_float(digits(SmallNorm))), >> + =A0 =A0%% large normalized number >> + =A0 =A0%% 1.79769313486231570815e+308 >> + =A0 =A0<> =3D <<127,239,255,255,255,255,255,255>>, >> + =A0 =A0?assertEqual("1.7976931348623157e+308", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(LargeNorm)), >> + =A0 =A0?assertEqual(LargeNorm, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_to_float(digits(LargeNorm))), >> + =A0 =A0%% issue #10 - mochinum:frexp(math:pow(2, -1074)). >> + =A0 =A0?assertEqual("5.0e-324", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 digits(math:pow(2, -1074))), >> + =A0 =A0ok. >> + >> +frexp_test() -> >> + =A0 =A0%% zero >> + =A0 =A0?assertEqual({0.0, 0}, frexp(0.0)), >> + =A0 =A0%% one >> + =A0 =A0?assertEqual({0.5, 1}, frexp(1.0)), >> + =A0 =A0%% negative one >> + =A0 =A0?assertEqual({-0.5, 1}, frexp(-1.0)), >> + =A0 =A0%% small denormalized number >> + =A0 =A0%% 4.94065645841246544177e-324 >> + =A0 =A0<> =3D <<0,0,0,0,0,0,0,1>>, >> + =A0 =A0?assertEqual({0.5, -1073}, frexp(SmallDenorm)), >> + =A0 =A0%% large denormalized number >> + =A0 =A0%% 2.22507385850720088902e-308 >> + =A0 =A0<> =3D <<0,15,255,255,255,255,255,255>>, >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 {0.99999999999999978, -1022}, >> + =A0 =A0 =A0 frexp(BigDenorm)), >> + =A0 =A0%% small normalized number >> + =A0 =A0%% 2.22507385850720138309e-308 >> + =A0 =A0<> =3D <<0,16,0,0,0,0,0,0>>, >> + =A0 =A0?assertEqual({0.5, -1021}, frexp(SmallNorm)), >> + =A0 =A0%% large normalized number >> + =A0 =A0%% 1.79769313486231570815e+308 >> + =A0 =A0<> =3D <<127,239,255,255,255,255,255,255>>, >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 =A0{0.99999999999999989, 1024}, >> + =A0 =A0 =A0 =A0frexp(LargeNorm)), >> + =A0 =A0%% issue #10 - mochinum:frexp(math:pow(2, -1074)). >> + =A0 =A0?assertEqual( >> + =A0 =A0 =A0 {0.5, -1073}, >> + =A0 =A0 =A0 frexp(math:pow(2, -1074))), >> + =A0 =A0ok. >> + >> +-endif. >> >> Added: couchdb/trunk/src/ejson/yajl/yajl.c >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/yajl/yajl.c?re= v=3D1088941&view=3Dauto >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/ejson/yajl/yajl.c (added) >> +++ couchdb/trunk/src/ejson/yajl/yajl.c Tue Apr =A05 09:42:41 2011 >> @@ -0,0 +1,159 @@ >> +/* >> + * Copyright 2010, Lloyd Hilaiel. >> + * >> + * Redistribution and use in source and binary forms, with or without >> + * modification, are permitted provided that the following conditions a= re >> + * met: >> + * >> + * =A01. Redistributions of source code must retain the above copyright >> + * =A0 =A0 notice, this list of conditions and the following disclaimer= . >> + * >> + * =A02. Redistributions in binary form must reproduce the above copyri= ght >> + * =A0 =A0 notice, this list of conditions and the following disclaimer= in >> + * =A0 =A0 the documentation and/or other materials provided with the >> + * =A0 =A0 distribution. >> + * >> + * =A03. Neither the name of Lloyd Hilaiel nor the names of its >> + * =A0 =A0 contributors may be used to endorse or promote products deri= ved >> + * =A0 =A0 from this software without specific prior written permission= . >> + * >> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR >> + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED >> + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE A= RE >> + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, >> + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >> + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR >> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, >> + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISIN= G >> + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE >> + * POSSIBILITY OF SUCH DAMAGE. >> + */ >> + >> +#include "yajl_parse.h" >> +#include "yajl_lex.h" >> +#include "yajl_parser.h" >> +#include "yajl_alloc.h" >> + >> +#include >> +#include >> +#include >> + >> +const char * >> +yajl_status_to_string(yajl_status stat) >> +{ >> + =A0 =A0const char * statStr =3D "unknown"; >> + =A0 =A0switch (stat) { >> + =A0 =A0 =A0 =A0case yajl_status_ok: >> + =A0 =A0 =A0 =A0 =A0 =A0statStr =3D "ok, no error"; >> + =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0case yajl_status_client_canceled: >> + =A0 =A0 =A0 =A0 =A0 =A0statStr =3D "client canceled parse"; >> + =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0case yajl_status_insufficient_data: >> + =A0 =A0 =A0 =A0 =A0 =A0statStr =3D "eof was met before the parse could= complete"; >> + =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0case yajl_status_error: >> + =A0 =A0 =A0 =A0 =A0 =A0statStr =3D "parse error"; >> + =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0} >> + =A0 =A0return statStr; >> +} >> + >> +yajl_handle >> +yajl_alloc(const yajl_callbacks * callbacks, >> + =A0 =A0 =A0 =A0 =A0 const yajl_parser_config * config, >> + =A0 =A0 =A0 =A0 =A0 const yajl_alloc_funcs * afs, >> + =A0 =A0 =A0 =A0 =A0 void * ctx) >> +{ >> + =A0 =A0unsigned int allowComments =3D 0; >> + =A0 =A0unsigned int validateUTF8 =3D 0; >> + =A0 =A0yajl_handle hand =3D NULL; >> + =A0 =A0yajl_alloc_funcs afsBuffer; >> + >> + =A0 =A0/* first order of business is to set up memory allocation routi= nes */ >> + =A0 =A0if (afs !=3D NULL) { >> + =A0 =A0 =A0 =A0if (afs->malloc =3D=3D NULL || afs->realloc =3D=3D NULL= || afs->free =3D=3D NULL) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0return NULL; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} else { >> + =A0 =A0 =A0 =A0yajl_set_default_alloc_funcs(&afsBuffer); >> + =A0 =A0 =A0 =A0afs =3D &afsBuffer; >> + =A0 =A0} >> + >> + =A0 =A0hand =3D (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle= _t)); >> + >> + =A0 =A0/* copy in pointers to allocation routines */ >> + =A0 =A0memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc= _funcs)); >> + >> + =A0 =A0if (config !=3D NULL) { >> + =A0 =A0 =A0 =A0allowComments =3D config->allowComments; >> + =A0 =A0 =A0 =A0validateUTF8 =3D config->checkUTF8; >> + =A0 =A0} >> + >> + =A0 =A0hand->callbacks =3D callbacks; >> + =A0 =A0hand->ctx =3D ctx; >> + =A0 =A0hand->lexer =3D yajl_lex_alloc(&(hand->alloc), allowComments, v= alidateUTF8); >> + =A0 =A0hand->bytesConsumed =3D 0; >> + =A0 =A0hand->decodeBuf =3D yajl_buf_alloc(&(hand->alloc)); >> + =A0 =A0yajl_bs_init(hand->stateStack, &(hand->alloc)); >> + >> + =A0 =A0yajl_bs_push(hand->stateStack, yajl_state_start); >> + >> + =A0 =A0return hand; >> +} >> + >> +void >> +yajl_free(yajl_handle handle) >> +{ >> + =A0 =A0yajl_bs_free(handle->stateStack); >> + =A0 =A0yajl_buf_free(handle->decodeBuf); >> + =A0 =A0yajl_lex_free(handle->lexer); >> + =A0 =A0YA_FREE(&(handle->alloc), handle); >> +} >> + >> +yajl_status >> +yajl_parse(yajl_handle hand, const unsigned char * jsonText, >> + =A0 =A0 =A0 =A0 =A0 unsigned int jsonTextLen) >> +{ >> + =A0 =A0yajl_status status; >> + =A0 =A0status =3D yajl_do_parse(hand, jsonText, jsonTextLen); >> + =A0 =A0return status; >> +} >> + >> +yajl_status >> +yajl_parse_complete(yajl_handle hand) >> +{ >> + =A0 =A0/* The particular case we want to handle is a trailing number. >> + =A0 =A0 * Further input consisting of digits could cause our interpret= ation >> + =A0 =A0 * of the number to change (buffered "1" but "2" comes in). >> + =A0 =A0 * A very simple approach to this is to inject whitespace to te= rminate >> + =A0 =A0 * any number in the lex buffer. >> + =A0 =A0 */ >> + =A0 =A0return yajl_parse(hand, (const unsigned char *)" ", 1); >> +} >> + >> +unsigned char * >> +yajl_get_error(yajl_handle hand, int verbose, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 const unsigned char * jsonText, unsigned i= nt jsonTextLen) >> +{ >> + =A0 =A0return yajl_render_error_string(hand, jsonText, jsonTextLen, ve= rbose); >> +} >> + >> +unsigned int >> +yajl_get_bytes_consumed(yajl_handle hand) >> +{ >> + =A0 =A0if (!hand) return 0; >> + =A0 =A0else return hand->bytesConsumed; >> +} >> + >> + >> +void >> +yajl_free_error(yajl_handle hand, unsigned char * str) >> +{ >> + =A0 =A0/* use memory allocation functions if set */ >> + =A0 =A0YA_FREE(&(hand->alloc), str); >> +} >> + >> +/* XXX: add utility routines to parse from file */ >> >> Added: couchdb/trunk/src/ejson/yajl/yajl_alloc.c >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/yajl/yajl_allo= c.c?rev=3D1088941&view=3Dauto >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/ejson/yajl/yajl_alloc.c (added) >> +++ couchdb/trunk/src/ejson/yajl/yajl_alloc.c Tue Apr =A05 09:42:41 2011 >> @@ -0,0 +1,65 @@ >> +/* >> + * Copyright 2010, Lloyd Hilaiel. >> + * >> + * Redistribution and use in source and binary forms, with or without >> + * modification, are permitted provided that the following conditions a= re >> + * met: >> + * >> + * =A01. Redistributions of source code must retain the above copyright >> + * =A0 =A0 notice, this list of conditions and the following disclaimer= . >> + * >> + * =A02. Redistributions in binary form must reproduce the above copyri= ght >> + * =A0 =A0 notice, this list of conditions and the following disclaimer= in >> + * =A0 =A0 the documentation and/or other materials provided with the >> + * =A0 =A0 distribution. >> + * >> + * =A03. Neither the name of Lloyd Hilaiel nor the names of its >> + * =A0 =A0 contributors may be used to endorse or promote products deri= ved >> + * =A0 =A0 from this software without specific prior written permission= . >> + * >> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR >> + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED >> + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE A= RE >> + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, >> + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >> + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR >> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, >> + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISIN= G >> + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE >> + * POSSIBILITY OF SUCH DAMAGE. >> + */ >> + >> +/** >> + * \file yajl_alloc.h >> + * default memory allocation routines for yajl which use malloc/realloc= and >> + * free >> + */ >> + >> +#include "yajl_alloc.h" >> +#include >> + >> +static void * yajl_internal_malloc(void *ctx, unsigned int sz) >> +{ >> + =A0 =A0return malloc(sz); >> +} >> + >> +static void * yajl_internal_realloc(void *ctx, void * previous, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0unsigned int sz) >> +{ >> + =A0 =A0return realloc(previous, sz); >> +} >> + >> +static void yajl_internal_free(void *ctx, void * ptr) >> +{ >> + =A0 =A0free(ptr); >> +} >> + >> +void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf) >> +{ >> + =A0 =A0yaf->malloc =3D yajl_internal_malloc; >> + =A0 =A0yaf->free =3D yajl_internal_free; >> + =A0 =A0yaf->realloc =3D yajl_internal_realloc; >> + =A0 =A0yaf->ctx =3D NULL; >> +} >> + >> >> Added: couchdb/trunk/src/ejson/yajl/yajl_alloc.h >> URL: http://svn.apache.org/viewvc/couchdb/trunk/src/ejson/yajl/yajl_allo= c.h?rev=3D1088941&view=3Dauto >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- couchdb/trunk/src/ejson/yajl/yajl_alloc.h (added) >> +++ couchdb/trunk/src/ejson/yajl/yajl_alloc.h Tue Apr =A05 09:42:41 2011 >> @@ -0,0 +1,50 @@ >> +/* >> + * Copyright 2010, Lloyd Hilaiel. >> + * >> + * Redistribution and use in source and binary forms, with or without >> + * modification, are permitted provided that the following conditions a= re >> + * met: >> + * >> + * =A01. Redistributions of source code must retain the above copyright >> + * =A0 =A0 notice, this list of conditions and the following disclaimer= . >> + * >> + * =A02. Redistributions in binary form must reproduce the above copyri= ght >> + * =A0 =A0 notice, this list of conditions and the following disclaimer= in >> + * =A0 =A0 the documentation and/or other materials provided with the >> + * =A0 =A0 distribution. >> + * >> + * =A03. Neither the name of Lloyd Hilaiel nor the names of its >> + * =A0 =A0 contributors may be used to endorse or promote products deri= ved >> + * =A0 =A0 from this software without specific prior written permission= . >> + * >> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR >> + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED >> + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE A= RE >> + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, >> + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >> + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR >> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, >> + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISIN= G >> + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE >> + * POSSIBILITY OF SUCH DAMAGE. >> + */ >> + >> +/** >> + * \file yajl_alloc.h >> + * default memory allocation routines for yajl which use malloc/realloc= and >> + * free >> + */ >> + >> +#ifndef __YAJL_ALLOC_H__ >> +#define __YAJL_ALLOC_H__ >> + >> +#include "yajl_common.h" >> + >> +#define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz)) >> +#define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr)) >> +#define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz)= ) >> + >> +void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf); >> + >> +#endif >> >> >> >