ultrajsonenc.c
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2011-2012, ESN Social Software AB and Jonas Tarnstrom
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are met:
00007     * Redistributions of source code must retain the above copyright
00008       notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright
00010       notice, this list of conditions and the following disclaimer in the
00011       documentation and/or other materials provided with the distribution.
00012     * Neither the name of the ESN Social Software AB nor the
00013       names of its contributors may be used to endorse or promote products
00014       derived from this software without specific prior written permission.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 DISCLAIMED. IN NO EVENT SHALL ESN SOCIAL SOFTWARE AB OR JONAS TARNSTROM BE LIABLE 
00020 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 
00027 Portions of code from:
00028 MODP_ASCII - Ascii transformations (upper/lower, etc)
00029 http://code.google.com/p/stringencoders/
00030 Copyright (c) 2007  Nick Galbreath -- nickg [at] modp [dot] com. All rights reserved.
00031 
00032 */
00033 
00034 #include "ultrajson.h"
00035 #include <stdio.h>
00036 #include <assert.h>
00037 #include <string.h>
00038 #include <stdlib.h>
00039 #include <math.h>
00040 
00041 #include <float.h>
00042 
00043 #ifndef TRUE
00044 #define TRUE 1
00045 #endif
00046 #ifndef FALSE
00047 #define FALSE 0
00048 #endif
00049 
00050 static const double g_pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000};
00051 static const char g_hexChars[] = "0123456789abcdef";
00052 static const char g_escapeChars[] = "0123456789\\b\\t\\n\\f\\r\\\"\\\\\\/";
00053 
00054 
00055 /*
00056 FIXME: While this is fine dandy and working it's a magic value mess which probably only the author understands.
00057 Needs a cleanup and more documentation */
00058 
00059 /*
00060 Table for pure ascii output escaping all characters above 127 to \uXXXX */
00061 static const JSUINT8 g_asciiOutputTable[256] = 
00062 {
00063 /* 0x00 */ 0, 30, 30, 30, 30, 30, 30, 30, 10, 12, 14, 30, 16, 18, 30, 30, 
00064 /* 0x10 */ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
00065 /* 0x20 */ 1, 1, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 24, 
00066 /* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00067 /* 0x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
00068 /* 0x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 1, 1, 1,
00069 /* 0x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
00070 /* 0x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00071 /* 0x80 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
00072 /* 0x90 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00073 /* 0xa0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
00074 /* 0xb0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00075 /* 0xc0 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
00076 /* 0xd0 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
00077 /* 0xe0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
00078 /* 0xf0 */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
00079 };
00080 
00081 
00082 static void SetError (JSOBJ obj, JSONObjectEncoder *enc, const char *message)
00083 {
00084     enc->errorMsg = message;
00085     enc->errorObj = obj;
00086 }
00087 
00088 /*
00089 FIXME: Keep track of how big these get across several encoder calls and try to make an estimate
00090 That way we won't run our head into the wall each call */
00091 void Buffer_Realloc (JSONObjectEncoder *enc, size_t cbNeeded)
00092 {
00093     size_t curSize = enc->end - enc->start;
00094     size_t newSize = curSize * 2;
00095     size_t offset = enc->offset - enc->start;
00096 
00097     while (newSize < curSize + cbNeeded)
00098     {
00099         newSize *= 2;
00100     }
00101 
00102     if (enc->heap)
00103     {
00104         enc->start = (char *) enc->realloc (enc->start, newSize);
00105         if (!enc->start)
00106         {
00107             SetError (NULL, enc, "Could not reserve memory block");
00108             return;
00109         }
00110     }
00111     else
00112     {
00113         char *oldStart = enc->start;
00114         enc->heap = 1;
00115         enc->start = (char *) enc->malloc (newSize);
00116         if (!enc->start)
00117         {
00118             SetError (NULL, enc, "Could not reserve memory block");
00119             return;
00120         }
00121         memcpy (enc->start, oldStart, offset);
00122     }
00123     enc->offset = enc->start + offset;
00124     enc->end = enc->start + newSize;
00125 }
00126 
00127 FASTCALL_ATTR INLINE_PREFIX void FASTCALL_MSVC Buffer_AppendShortHexUnchecked (char *outputOffset, unsigned short value)
00128 {
00129     *(outputOffset++) = g_hexChars[(value & 0xf000) >> 12];
00130     *(outputOffset++) = g_hexChars[(value & 0x0f00) >> 8];
00131     *(outputOffset++) = g_hexChars[(value & 0x00f0) >> 4];
00132     *(outputOffset++) = g_hexChars[(value & 0x000f) >> 0];
00133 }
00134 
00135 int Buffer_EscapeStringUnvalidated (JSOBJ obj, JSONObjectEncoder *enc, const char *io, const char *end)
00136 {
00137     char *of = (char *) enc->offset;
00138 
00139     while (1)
00140     {
00141         switch (*io)
00142         {
00143         case 0x00:
00144             if (io < end)
00145             {
00146                 *(of++) = '\\';
00147                 *(of++) = 'u';
00148                 *(of++) = '0';
00149                 *(of++) = '0';
00150                 *(of++) = '0';
00151                 *(of++) = '0';
00152                 break;
00153             }
00154             else
00155             {
00156                 enc->offset += (of - enc->offset); 
00157                 return TRUE;
00158             }
00159 
00160         case '\"': (*of++) = '\\'; (*of++) = '\"'; break;
00161         case '\\': (*of++) = '\\'; (*of++) = '\\'; break;
00162         case '/':  (*of++) = '\\'; (*of++) = '/'; break;
00163         case '\b': (*of++) = '\\'; (*of++) = 'b'; break;
00164         case '\f': (*of++) = '\\'; (*of++) = 'f'; break;
00165         case '\n': (*of++) = '\\'; (*of++) = 'n'; break;
00166         case '\r': (*of++) = '\\'; (*of++) = 'r'; break;
00167         case '\t': (*of++) = '\\'; (*of++) = 't'; break;
00168 
00169         case 0x01:
00170         case 0x02:
00171         case 0x03:
00172         case 0x04:
00173         case 0x05:
00174         case 0x06:
00175         case 0x07:
00176         case 0x0b:
00177         case 0x0e:
00178         case 0x0f:
00179         case 0x10:
00180         case 0x11:
00181         case 0x12:
00182         case 0x13:
00183         case 0x14:
00184         case 0x15:
00185         case 0x16:
00186         case 0x17:
00187         case 0x18:
00188         case 0x19:
00189         case 0x1a:
00190         case 0x1b:
00191         case 0x1c:
00192         case 0x1d:
00193         case 0x1e:
00194         case 0x1f:
00195             *(of++) = '\\';
00196             *(of++) = 'u';
00197             *(of++) = '0';
00198             *(of++) = '0';
00199             *(of++) = g_hexChars[ (unsigned char) (((*io) & 0xf0) >> 4)];
00200             *(of++) = g_hexChars[ (unsigned char) ((*io) & 0x0f)];
00201             break;
00202 
00203         default: (*of++) = (*io); break;
00204         }
00205 
00206         io++;
00207     }
00208 
00209     return FALSE;
00210 }
00211 
00212 
00213 /*
00214 FIXME:
00215 This code only works with Little and Big Endian
00216 
00217 FIXME: The JSON spec says escape "/" but non of the others do and we don't 
00218 want to be left alone doing it so we don't :)
00219 
00220 */
00221 int Buffer_EscapeStringValidated (JSOBJ obj, JSONObjectEncoder *enc, const char *io, const char *end)
00222 {
00223     JSUTF32 ucs;
00224     char *of = (char *) enc->offset;
00225 
00226     while (1)
00227     {
00228 
00229         //JSUINT8 chr = (unsigned char) *io;
00230         JSUINT8 utflen = g_asciiOutputTable[(unsigned char) *io];
00231 
00232         switch (utflen)
00233         {
00234             case 0: 
00235             {
00236                 if (io < end)
00237                 {
00238                     *(of++) = '\\';
00239                     *(of++) = 'u';
00240                     *(of++) = '0';
00241                     *(of++) = '0';
00242                     *(of++) = '0';
00243                     *(of++) = '0';
00244                     io ++;
00245                     continue;
00246                 }
00247                 else
00248                 {
00249                     enc->offset += (of - enc->offset); 
00250                     return TRUE;
00251                 }
00252             }
00253 
00254             case 1:
00255             {
00256                 *(of++)= (*io++); 
00257                 continue;
00258             }
00259 
00260             case 2:
00261             {
00262                 JSUTF32 in;
00263                 JSUTF16 in16;
00264 
00265                 if (end - io < 1)
00266                 {
00267                     enc->offset += (of - enc->offset);
00268                     SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string");
00269                     return FALSE;
00270                 }
00271 
00272                 memcpy(&in16, io, sizeof(JSUTF16));
00273                 in = (JSUTF32) in16;
00274 
00275 #ifdef __LITTLE_ENDIAN__
00276                 ucs = ((in & 0x1f) << 6) | ((in >> 8) & 0x3f);
00277 #else
00278                 ucs = ((in & 0x1f00) >> 2) | (in & 0x3f);
00279 #endif
00280 
00281                 if (ucs < 0x80)
00282                 {
00283                     enc->offset += (of - enc->offset);
00284                     SetError (obj, enc, "Overlong 2 byte UTF-8 sequence detected when encoding string");
00285                     return FALSE;
00286                 }
00287 
00288                 io += 2;
00289                 break;
00290             }
00291 
00292             case 3:
00293             {
00294                 JSUTF32 in;
00295                 JSUTF16 in16;
00296                 JSUINT8 in8;
00297 
00298                 if (end - io < 2)
00299                 {
00300                     enc->offset += (of - enc->offset);
00301                     SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string");
00302                     return FALSE;
00303                 }
00304 
00305                 memcpy(&in16, io, sizeof(JSUTF16));
00306                 memcpy(&in8, io + 2, sizeof(JSUINT8));
00307 #ifdef __LITTLE_ENDIAN__
00308                 in = (JSUTF32) in16;
00309                 in |= in8 << 16;
00310                 ucs = ((in & 0x0f) << 12) | ((in & 0x3f00) >> 2) | ((in & 0x3f0000) >> 16);
00311 #else
00312                 in = in16 << 8;
00313                 in |= in8;
00314                 ucs = ((in & 0x0f0000) >> 4) | ((in & 0x3f00) >> 2) | (in & 0x3f);
00315 #endif
00316 
00317 
00318                 if (ucs < 0x800)
00319                 {
00320                     enc->offset += (of - enc->offset);
00321                     SetError (obj, enc, "Overlong 3 byte UTF-8 sequence detected when encoding string");
00322                     return FALSE;
00323                 }
00324 
00325                 io += 3;
00326                 break;
00327             }
00328             case 4:
00329             {
00330                 JSUTF32 in;
00331                 
00332                 if (end - io < 3)
00333                 {
00334                     enc->offset += (of - enc->offset);
00335                     SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string");
00336                     return FALSE;
00337                 }
00338 
00339                 memcpy(&in, io, sizeof(JSUTF32));
00340 #ifdef __LITTLE_ENDIAN__
00341                 ucs = ((in & 0x07) << 18) | ((in & 0x3f00) << 4) | ((in & 0x3f0000) >> 10) | ((in & 0x3f000000) >> 24);
00342 #else
00343                 ucs = ((in & 0x07000000) >> 6) | ((in & 0x3f0000) >> 4) | ((in & 0x3f00) >> 2) | (in & 0x3f);
00344 #endif
00345                 if (ucs < 0x10000)
00346                 {
00347                     enc->offset += (of - enc->offset);
00348                     SetError (obj, enc, "Overlong 4 byte UTF-8 sequence detected when encoding string");
00349                     return FALSE;
00350                 }
00351 
00352                 io += 4;
00353                 break;
00354             }
00355 
00356 
00357             case 5:
00358             case 6:
00359                 enc->offset += (of - enc->offset);
00360                 SetError (obj, enc, "Unsupported UTF-8 sequence length when encoding string");
00361                 return FALSE;
00362 
00363             case 30:
00364                 // \uXXXX encode
00365                 *(of++) = '\\';
00366                 *(of++) = 'u';
00367                 *(of++) = '0';
00368                 *(of++) = '0';
00369                 *(of++) = g_hexChars[ (unsigned char) (((*io) & 0xf0) >> 4)];
00370                 *(of++) = g_hexChars[ (unsigned char) ((*io) & 0x0f)];
00371                 io ++;
00372                 continue;
00373 
00374             case 10:
00375             case 12:
00376             case 14:
00377             case 16:
00378             case 18:
00379             case 20:
00380             case 22:
00381             case 24:
00382                 *(of++) = *( (char *) (g_escapeChars + utflen + 0));
00383                 *(of++) = *( (char *) (g_escapeChars + utflen + 1));
00384                 io ++;
00385                 continue;
00386         }
00387 
00388         /*
00389         If the character is a UTF8 sequence of length > 1 we end up here */
00390         if (ucs >= 0x10000)
00391         {
00392             ucs -= 0x10000;
00393             *(of++) = '\\';
00394             *(of++) = 'u';
00395             Buffer_AppendShortHexUnchecked(of, (ucs >> 10) + 0xd800);
00396             of += 4;
00397 
00398             *(of++) = '\\';
00399             *(of++) = 'u';
00400             Buffer_AppendShortHexUnchecked(of, (ucs & 0x3ff) + 0xdc00);
00401             of += 4;
00402         }
00403         else
00404         {
00405             *(of++) = '\\';
00406             *(of++) = 'u';
00407             Buffer_AppendShortHexUnchecked(of, ucs);
00408             of += 4;
00409         }
00410     }
00411 
00412     return FALSE;
00413 }
00414 
00415 #define Buffer_Reserve(__enc, __len) \
00416     if ((__enc)->end - (__enc)->offset < (__len))  \
00417     {   \
00418         Buffer_Realloc((__enc), (__len));\
00419     }   \
00420 
00421 
00422 #define Buffer_AppendCharUnchecked(__enc, __chr) \
00423                 *((__enc)->offset++) = __chr; \
00424 
00425 FASTCALL_ATTR INLINE_PREFIX void FASTCALL_MSVC strreverse(char* begin, char* end)
00426 {
00427     char aux;
00428     while (end > begin)
00429     aux = *end, *end-- = *begin, *begin++ = aux;
00430 }
00431 
00432 void Buffer_AppendIntUnchecked(JSONObjectEncoder *enc, JSINT32 value)
00433 {
00434     char* wstr;
00435     JSUINT32 uvalue = (value < 0) ? -value : value;
00436 
00437     wstr = enc->offset;
00438     // Conversion. Number is reversed.
00439     
00440     do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10);
00441     if (value < 0) *wstr++ = '-';
00442 
00443     // Reverse string
00444     strreverse(enc->offset,wstr - 1);
00445     enc->offset += (wstr - (enc->offset));
00446 }
00447 
00448 void Buffer_AppendLongUnchecked(JSONObjectEncoder *enc, JSINT64 value)
00449 {
00450     char* wstr;
00451     JSUINT64 uvalue = (value < 0) ? -value : value;
00452 
00453     wstr = enc->offset;
00454     // Conversion. Number is reversed.
00455     
00456     do *wstr++ = (char)(48 + (uvalue % 10ULL)); while(uvalue /= 10ULL);
00457     if (value < 0) *wstr++ = '-';
00458 
00459     // Reverse string
00460     strreverse(enc->offset,wstr - 1);
00461     enc->offset += (wstr - (enc->offset));
00462 }
00463 
00464 int Buffer_AppendDoubleUnchecked(JSOBJ obj, JSONObjectEncoder *enc, double value)
00465 {
00466     /* if input is larger than thres_max, revert to exponential */
00467     const double thres_max = (double) 1e16 - 1;
00468     int count;
00469     double diff = 0.0;
00470     char* str = enc->offset;
00471     char* wstr = str;
00472     unsigned long long whole;
00473     double tmp;
00474     unsigned long long frac;
00475     int neg;
00476     double pow10;
00477 
00478     if (value == HUGE_VAL || value == -HUGE_VAL)
00479     {
00480         SetError (obj, enc, "Invalid Inf value when encoding double");
00481         return FALSE;
00482     }
00483     if (! (value == value)) 
00484     {
00485         SetError (obj, enc, "Invalid Nan value when encoding double");
00486         return FALSE;
00487     }
00488 
00489 
00490     /* we'll work in positive values and deal with the
00491     negative sign issue later */
00492     neg = 0;
00493     if (value < 0) 
00494     {
00495         neg = 1;
00496         value = -value;
00497     }
00498 
00499     pow10 = g_pow10[enc->doublePrecision];
00500 
00501     whole = (unsigned long long) value;
00502     tmp = (value - whole) * pow10;
00503     frac = (unsigned long long)(tmp);
00504     diff = tmp - frac;
00505 
00506     if (diff > 0.5) 
00507     {
00508         ++frac;
00509         /* handle rollover, e.g.  case 0.99 with prec 1 is 1.0  */
00510         if (frac >= pow10) 
00511         {
00512             frac = 0;
00513             ++whole;
00514         }
00515     } 
00516     else 
00517     if (diff == 0.5 && ((frac == 0) || (frac & 1))) 
00518     {
00519         /* if halfway, round up if odd, OR
00520         if last digit is 0.  That last part is strange */
00521         ++frac;
00522     }
00523 
00524     /* for very large numbers switch back to native sprintf for exponentials.
00525     anyone want to write code to replace this? */
00526     /*
00527     normal printf behavior is to print EVERY whole number digit
00528     which can be 100s of characters overflowing your buffers == bad
00529     */
00530     if (value > thres_max) 
00531     {
00532         enc->offset += sprintf(str, "%.15e", neg ? -value : value);
00533         return TRUE;
00534     }
00535 
00536     if (enc->doublePrecision == 0) 
00537     {
00538         diff = value - whole;
00539 
00540         if (diff > 0.5) 
00541         {
00542         /* greater than 0.5, round up, e.g. 1.6 -> 2 */
00543         ++whole;
00544         }
00545         else 
00546         if (diff == 0.5 && (whole & 1)) 
00547         {
00548             /* exactly 0.5 and ODD, then round up */
00549             /* 1.5 -> 2, but 2.5 -> 2 */
00550             ++whole;
00551         }
00552 
00553             //vvvvvvvvvvvvvvvvvvv  Diff from modp_dto2
00554     } 
00555     else 
00556     if (frac) 
00557     { 
00558         count = enc->doublePrecision;
00559         // now do fractional part, as an unsigned number
00560         // we know it is not 0 but we can have leading zeros, these
00561         // should be removed
00562         while (!(frac % 10))
00563         {
00564         --count;
00565         frac /= 10;
00566         }
00567         //^^^^^^^^^^^^^^^^^^^  Diff from modp_dto2
00568 
00569         // now do fractional part, as an unsigned number
00570         do 
00571         {
00572             --count;
00573             *wstr++ = (char)(48 + (frac % 10));
00574         } while (frac /= 10);
00575         // add extra 0s
00576         while (count-- > 0)
00577         {
00578             *wstr++ = '0';
00579         }
00580         // add decimal
00581         *wstr++ = '.';
00582     }
00583     else
00584     {
00585         *wstr++ = '0';
00586         *wstr++ = '.';
00587     }
00588 
00589     // do whole part
00590     // Take care of sign
00591     // Conversion. Number is reversed.
00592     do *wstr++ = (char)(48 + (whole % 10)); while (whole /= 10);
00593     
00594     if (neg) 
00595     {
00596         *wstr++ = '-';
00597     }
00598     strreverse(str, wstr-1);
00599     enc->offset += (wstr - (enc->offset));
00600 
00601     return TRUE;
00602 }
00603 
00604 
00605 
00606 
00607 
00608 
00609 /*
00610 FIXME:
00611 Handle integration functions returning NULL here */
00612 
00613 /*
00614 FIXME:
00615 Perhaps implement recursion detection */
00616 
00617 void encode(JSOBJ obj, JSONObjectEncoder *enc, const char *name, size_t cbName)
00618 {
00619     const char *value;
00620     char *objName;
00621     int count;
00622     JSOBJ iterObj;
00623     size_t szlen;
00624     JSONTypeContext tc;
00625 
00626     if (enc->level > enc->recursionMax)
00627     {
00628         SetError (obj, enc, "Maximum recursion level reached");
00629         return;
00630     }
00631 
00632     /*
00633     This reservation must hold 
00634 
00635     length of _name as encoded worst case +
00636     maxLength of double to string OR maxLength of JSLONG to string
00637 
00638     Since input is assumed to be UTF-8 the worst character length is:
00639 
00640     4 bytes (of UTF-8) => "\uXXXX\uXXXX" (12 bytes)
00641     */
00642 
00643     Buffer_Reserve(enc, 256 + (((cbName / 4) + 1) * 12));
00644     if (enc->errorMsg)
00645     {
00646         return;
00647     }
00648 
00649     if (name)
00650     {
00651         Buffer_AppendCharUnchecked(enc, '\"');
00652 
00653         if (enc->forceASCII)
00654         {
00655             if (!Buffer_EscapeStringValidated(obj, enc, name, name + cbName))
00656             {
00657                 return;
00658             }
00659         }
00660         else
00661         {
00662             if (!Buffer_EscapeStringUnvalidated(obj, enc, name, name + cbName))
00663             {
00664                 return;
00665             }
00666         }
00667 
00668 
00669         Buffer_AppendCharUnchecked(enc, '\"');
00670 
00671         Buffer_AppendCharUnchecked (enc, ':');
00672 #ifndef JSON_NO_EXTRA_WHITESPACE
00673         Buffer_AppendCharUnchecked (enc, ' ');
00674 #endif
00675     }
00676 
00677     enc->beginTypeContext(obj, &tc);
00678 
00679     switch (tc.type)
00680     {
00681         case JT_INVALID:
00682             return;
00683 
00684         case JT_ARRAY:
00685         {
00686             count = 0;
00687             enc->iterBegin(obj, &tc);
00688 
00689             Buffer_AppendCharUnchecked (enc, '[');
00690 
00691             while (enc->iterNext(obj, &tc))
00692             {
00693                 if (count > 0)
00694                 {
00695                     Buffer_AppendCharUnchecked (enc, ',');
00696 #ifndef JSON_NO_EXTRA_WHITESPACE
00697                     Buffer_AppendCharUnchecked (buffer, ' ');
00698 #endif
00699                 }
00700 
00701                 iterObj = enc->iterGetValue(obj, &tc);
00702 
00703                 enc->level ++;
00704                 encode (iterObj, enc, NULL, 0);         
00705                 count ++;
00706             }
00707 
00708             enc->iterEnd(obj, &tc);
00709             Buffer_AppendCharUnchecked (enc, ']');
00710             break;
00711         }
00712 
00713         case JT_OBJECT:
00714         {
00715             count = 0;
00716             enc->iterBegin(obj, &tc);
00717 
00718             Buffer_AppendCharUnchecked (enc, '{');
00719 
00720             while (enc->iterNext(obj, &tc))
00721             {
00722                 if (count > 0)
00723                 {
00724                     Buffer_AppendCharUnchecked (enc, ',');
00725 #ifndef JSON_NO_EXTRA_WHITESPACE
00726                     Buffer_AppendCharUnchecked (enc, ' ');
00727 #endif
00728                 }
00729 
00730                 iterObj = enc->iterGetValue(obj, &tc);
00731                 objName = enc->iterGetName(obj, &tc, &szlen);
00732 
00733                 enc->level ++;
00734                 encode (iterObj, enc, objName, szlen);          
00735                 count ++;
00736             }
00737 
00738             enc->iterEnd(obj, &tc);
00739             Buffer_AppendCharUnchecked (enc, '}');
00740             break;
00741         }
00742 
00743         case JT_LONG:
00744         {
00745             Buffer_AppendLongUnchecked (enc, enc->getLongValue(obj, &tc));
00746             break;
00747         }
00748 
00749         case JT_INT:
00750         {
00751             Buffer_AppendIntUnchecked (enc, enc->getIntValue(obj, &tc));
00752             break;
00753         }
00754 
00755         case JT_TRUE:
00756         {
00757             Buffer_AppendCharUnchecked (enc, 't');
00758             Buffer_AppendCharUnchecked (enc, 'r');
00759             Buffer_AppendCharUnchecked (enc, 'u');
00760             Buffer_AppendCharUnchecked (enc, 'e');
00761             break;
00762         }
00763 
00764         case JT_FALSE:
00765         {
00766             Buffer_AppendCharUnchecked (enc, 'f');
00767             Buffer_AppendCharUnchecked (enc, 'a');
00768             Buffer_AppendCharUnchecked (enc, 'l');
00769             Buffer_AppendCharUnchecked (enc, 's');
00770             Buffer_AppendCharUnchecked (enc, 'e');
00771             break;
00772         }
00773 
00774 
00775         case JT_NULL: 
00776         {
00777             Buffer_AppendCharUnchecked (enc, 'n');
00778             Buffer_AppendCharUnchecked (enc, 'u');
00779             Buffer_AppendCharUnchecked (enc, 'l');
00780             Buffer_AppendCharUnchecked (enc, 'l');
00781             break;
00782         }
00783 
00784         case JT_DOUBLE:
00785         {
00786             if (!Buffer_AppendDoubleUnchecked (obj, enc, enc->getDoubleValue(obj, &tc)))
00787             {
00788                 enc->endTypeContext(obj, &tc);
00789                 enc->level --;
00790                 return;
00791             }
00792             break;
00793         }
00794 
00795         case JT_UTF8:
00796         {
00797             value = enc->getStringValue(obj, &tc, &szlen);
00798             Buffer_Reserve(enc, ((szlen / 4) + 1) * 12);
00799             if (enc->errorMsg)
00800             {
00801                 enc->endTypeContext(obj, &tc);
00802                 return;
00803             }
00804             Buffer_AppendCharUnchecked (enc, '\"');
00805 
00806 
00807             if (enc->forceASCII)
00808             {
00809                 if (!Buffer_EscapeStringValidated(obj, enc, value, value + szlen))
00810                 {
00811                     enc->endTypeContext(obj, &tc);
00812                     enc->level --;
00813                     return;
00814                 }
00815             }
00816             else
00817             {
00818                 if (!Buffer_EscapeStringUnvalidated(obj, enc, value, value + szlen))
00819                 {
00820                     enc->endTypeContext(obj, &tc);
00821                     enc->level --;
00822                     return;
00823                 }
00824             }
00825 
00826             Buffer_AppendCharUnchecked (enc, '\"');
00827             break;
00828         }
00829     }
00830 
00831     enc->endTypeContext(obj, &tc);
00832     enc->level --;
00833 
00834 }
00835 
00836 char *JSON_EncodeObject(JSOBJ obj, JSONObjectEncoder *enc, char *_buffer, size_t _cbBuffer)
00837 {
00838     enc->malloc = enc->malloc ? enc->malloc : malloc;
00839     enc->free =  enc->free ? enc->free : free;
00840     enc->realloc = enc->realloc ? enc->realloc : realloc;
00841     enc->errorMsg = NULL;
00842     enc->errorObj = NULL;
00843     enc->level = 0;
00844 
00845     if (enc->recursionMax < 1)
00846     {
00847         enc->recursionMax = JSON_MAX_RECURSION_DEPTH;
00848     }
00849 
00850     if (enc->doublePrecision < 0 ||
00851             enc->doublePrecision > JSON_DOUBLE_MAX_DECIMALS)
00852     {
00853         enc->doublePrecision = JSON_DOUBLE_MAX_DECIMALS;
00854     }
00855 
00856     if (_buffer == NULL)
00857     {
00858         _cbBuffer = 32768;
00859         enc->start = (char *) enc->malloc (_cbBuffer);
00860         if (!enc->start)
00861         {
00862             SetError(obj, enc, "Could not reserve memory block");
00863             return NULL;
00864         }
00865         enc->heap = 1;
00866     }
00867     else
00868     {
00869         enc->start = _buffer;
00870         enc->heap = 0;
00871     }
00872 
00873     enc->end = enc->start + _cbBuffer;
00874     enc->offset = enc->start;
00875 
00876 
00877     encode (obj, enc, NULL, 0);
00878     
00879     Buffer_Reserve(enc, 1);
00880     if (enc->errorMsg)
00881     {
00882         return NULL;
00883     }
00884     Buffer_AppendCharUnchecked(enc, '\0');
00885 
00886     return enc->start;
00887 }


rosbridge_library
Author(s): Jonathan Mace
autogenerated on Thu Jan 2 2014 11:53:35