ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/JSON-XS/XS.xs
Revision: 1.2
Committed: Thu Mar 22 17:28:50 2007 UTC (17 years, 2 months ago) by root
Branch: MAIN
Changes since 1.1: +13 -3 lines
Log Message:
added preliminary documentation

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5     #include "assert.h"
6     #include "string.h"
7     #include "stdlib.h"
8    
9     #define F_ASCII 0x00000001
10     #define F_UTF8 0x00000002
11     #define F_INDENT 0x00000004
12     #define F_CANONICAL 0x00000008
13     #define F_SPACE_BEFORE 0x00000010
14     #define F_SPACE_AFTER 0x00000020
15     #define F_JSON_RPC 0x00000040
16    
17 root 1.2 #define F_PRETTY F_INDENT | F_SPACE_BEFORE | F_SPACE_AFTER
18 root 1.1 #define F_DEFAULT 0
19    
20     #define INIT_SIZE 32 // initial scalar size to be allocated
21    
22     #define SB do {
23     #define SE } while (0)
24    
25     static HV *json_stash;
26    
27     // structure used for encoding JSON
28     typedef struct
29     {
30     char *cur;
31     STRLEN len; // SvLEN (sv)
32     char *end; // SvEND (sv)
33     SV *sv;
34     UV flags;
35     int max_recurse;
36     int indent;
37     } enc_t;
38    
39     // structure used for decoding JSON
40     typedef struct
41     {
42     char *cur;
43     char *end;
44     char *err;
45     UV flags;
46     } dec_t;
47    
48     static UV *
49     SvJSON (SV *sv)
50     {
51     if (!(SvROK (sv) && SvOBJECT (SvRV (sv)) && SvSTASH (SvRV (sv)) == json_stash))
52     croak ("object is not of type JSON::XS");
53    
54     return &SvUVX (SvRV (sv));
55     }
56    
57     /////////////////////////////////////////////////////////////////////////////
58    
59     static void
60     need (enc_t *enc, STRLEN len)
61     {
62     if (enc->cur + len >= enc->end)
63     {
64     STRLEN cur = enc->cur - SvPVX (enc->sv);
65     SvGROW (enc->sv, cur + len + 1);
66     enc->cur = SvPVX (enc->sv) + cur;
67     enc->end = SvEND (enc->sv);
68     }
69     }
70    
71     static void
72     encode_ch (enc_t *enc, char ch)
73     {
74     need (enc, 1);
75     *enc->cur++ = ch;
76     }
77    
78     static void
79     encode_str (enc_t *enc, char *str, STRLEN len, int is_utf8)
80     {
81     char *end = str + len;
82    
83     while (str < end)
84     {
85     unsigned char ch = *(unsigned char *)str;
86     if (ch >= 0x20 && ch < 0x80) // most common case
87     {
88     *enc->cur++ = ch;
89     str++;
90     }
91     else
92     {
93     STRLEN clen;
94     UV uch;
95    
96     if (is_utf8)
97     {
98     uch = utf8n_to_uvuni (str, end - str, &clen, UTF8_CHECK_ONLY);
99     if (clen < 0)
100     croak ("malformed UTF-8 character in string, cannot convert to JSON");
101     }
102     else
103     {
104     uch = ch;
105     clen = 1;
106     }
107    
108     need (enc, len += 6);
109    
110     if (uch < 0xa0 || enc->flags & F_ASCII)
111     {
112     if (uch > 0xFFFFUL)
113     {
114     len += 6;
115     need (enc, len += 6);
116     sprintf (enc->cur, "\\u%04x\\u%04x",
117     (uch - 0x10000) / 0x400 + 0xD800,
118     (uch - 0x10000) % 0x400 + 0xDC00);
119     enc->cur += 12;
120     }
121     else
122     {
123     sprintf (enc->cur, "\\u%04x", uch);
124     enc->cur += 6;
125     }
126     }
127     else if (is_utf8)
128     {
129     memcpy (enc->cur, str, clen);
130     enc->cur += clen;
131     }
132     else
133     enc->cur = uvuni_to_utf8_flags (enc->cur, uch, 0);
134    
135     str += clen;
136     }
137    
138     --len;
139     }
140     }
141    
142     #define INDENT SB \
143     if (enc->flags & F_INDENT) \
144     { \
145     int i_; \
146     need (enc, enc->indent); \
147     for (i_ = enc->indent * 3; i_--; )\
148     encode_ch (enc, ' '); \
149     } \
150     SE
151    
152 root 1.2 #define SPACE SB need (enc, 1); encode_ch (enc, ' '); SE
153 root 1.1 #define NL SB if (enc->flags & F_INDENT) { need (enc, 1); encode_ch (enc, '\n'); } SE
154     #define COMMA SB \
155     encode_ch (enc, ','); \
156     if (enc->flags & F_INDENT) \
157     NL; \
158     else if (enc->flags & F_SPACE_AFTER) \
159     SPACE; \
160     SE
161    
162     static void encode_sv (enc_t *enc, SV *sv);
163    
164     static void
165     encode_av (enc_t *enc, AV *av)
166     {
167     int i, len = av_len (av);
168    
169     encode_ch (enc, '['); NL;
170     ++enc->indent;
171    
172     for (i = 0; i <= len; ++i)
173     {
174     INDENT;
175     encode_sv (enc, *av_fetch (av, i, 0));
176    
177     if (i < len)
178     COMMA;
179     }
180    
181     NL;
182    
183     --enc->indent;
184     INDENT; encode_ch (enc, ']');
185     }
186    
187     static void
188     encode_he (enc_t *enc, HE *he)
189     {
190     encode_ch (enc, '"');
191    
192     if (HeKLEN (he) == HEf_SVKEY)
193     {
194     SV *sv = HeSVKEY (he);
195     STRLEN len;
196     char *str = SvPV (sv, len);
197    
198     encode_str (enc, str, len, SvUTF8 (sv));
199     }
200     else
201     encode_str (enc, HeKEY (he), HeKLEN (he), HeKUTF8 (he));
202    
203     encode_ch (enc, '"');
204    
205     if (enc->flags & F_SPACE_BEFORE) SPACE;
206     encode_ch (enc, ':');
207     if (enc->flags & F_SPACE_AFTER ) SPACE;
208     encode_sv (enc, HeVAL (he));
209     }
210    
211     // compare hash entries, used when all keys are bytestrings
212     static int
213     he_cmp_fast (const void *a_, const void *b_)
214     {
215     int cmp;
216    
217     HE *a = *(HE **)a_;
218     HE *b = *(HE **)b_;
219    
220     STRLEN la = HeKLEN (a);
221     STRLEN lb = HeKLEN (b);
222    
223     if (!(cmp == memcmp (HeKEY (a), HeKEY (b), la < lb ? la : lb)))
224     cmp = la < lb ? -1 : la == lb ? 0 : 1;
225    
226     return cmp;
227     }
228    
229     // compare hash entries, used when some keys are sv's or utf-x
230     static int
231     he_cmp_slow (const void *a, const void *b)
232     {
233     return sv_cmp (HeSVKEY_force (*(HE **)a), HeSVKEY_force (*(HE **)b));
234     }
235    
236     static void
237     encode_hv (enc_t *enc, HV *hv)
238     {
239     int count, i;
240    
241     encode_ch (enc, '{'); NL; ++enc->indent;
242    
243     if ((count = hv_iterinit (hv)))
244     {
245     // for canonical output we have to sort by keys first
246     // actually, this is mostly due to the stupid so-called
247     // security workaround added somewhere in 5.8.x.
248     // that randomises hash orderings
249     if (enc->flags & F_CANONICAL)
250     {
251     HE *he, *hes [count];
252     int fast = 1;
253    
254     i = 0;
255     while ((he = hv_iternext (hv)))
256     {
257     hes [i++] = he;
258     if (HeKLEN (he) < 0 || HeKUTF8 (he))
259     fast = 0;
260     }
261    
262     assert (i == count);
263    
264     if (fast)
265     qsort (hes, count, sizeof (HE *), he_cmp_fast);
266     else
267     {
268     // hack to disable "use bytes"
269     COP *oldcop = PL_curcop, cop;
270     cop.op_private = 0;
271     PL_curcop = &cop;
272    
273     SAVETMPS;
274     qsort (hes, count, sizeof (HE *), he_cmp_slow);
275     FREETMPS;
276    
277     PL_curcop = oldcop;
278     }
279    
280     for (i = 0; i < count; ++i)
281     {
282     INDENT;
283     encode_he (enc, hes [i]);
284    
285     if (i < count - 1)
286     COMMA;
287     }
288    
289     NL;
290     }
291     else
292     {
293     SV *sv;
294     HE *he = hv_iternext (hv);
295    
296     for (;;)
297     {
298     INDENT;
299     encode_he (enc, he);
300    
301     if (!(he = hv_iternext (hv)))
302     break;
303    
304     COMMA;
305     }
306    
307     NL;
308     }
309     }
310    
311     --enc->indent; INDENT; encode_ch (enc, '}');
312     }
313    
314     static void
315     encode_sv (enc_t *enc, SV *sv)
316     {
317     if (SvPOKp (sv))
318     {
319     STRLEN len;
320     char *str = SvPV (sv, len);
321     encode_ch (enc, '"');
322     encode_str (enc, str, len, SvUTF8 (sv));
323     encode_ch (enc, '"');
324     }
325     else if (SvNOKp (sv))
326     {
327     need (enc, NV_DIG + 32);
328     Gconvert (SvNVX (sv), NV_DIG, 0, enc->cur);
329     enc->cur += strlen (enc->cur);
330     }
331     else if (SvIOKp (sv))
332     {
333     need (enc, 64);
334     enc->cur +=
335     SvIsUV(sv)
336     ? snprintf (enc->cur, 64, "%"UVuf, (UV)SvUVX (sv))
337     : snprintf (enc->cur, 64, "%"IVdf, (IV)SvIVX (sv));
338     }
339     else if (SvROK (sv))
340     {
341     if (!--enc->max_recurse)
342     croak ("data structure too deep (hit recursion limit)");
343    
344     sv = SvRV (sv);
345    
346     switch (SvTYPE (sv))
347     {
348     case SVt_PVAV: encode_av (enc, (AV *)sv); break;
349     case SVt_PVHV: encode_hv (enc, (HV *)sv); break;
350    
351     default:
352     croak ("JSON can only represent references to arrays or hashes");
353     }
354     }
355     else if (!SvOK (sv))
356     encode_str (enc, "null", 4, 0);
357     else
358     croak ("encountered perl type that JSON cannot handle");
359     }
360    
361     static SV *
362     encode_json (SV *scalar, UV flags)
363     {
364     enc_t enc;
365     enc.flags = flags;
366     enc.sv = sv_2mortal (NEWSV (0, INIT_SIZE));
367     enc.cur = SvPVX (enc.sv);
368     enc.end = SvEND (enc.sv);
369     enc.max_recurse = 0;
370     enc.indent = 0;
371    
372     SvPOK_only (enc.sv);
373     encode_sv (&enc, scalar);
374    
375     if (!(flags & (F_ASCII | F_UTF8)))
376     SvUTF8_on (enc.sv);
377    
378     SvCUR_set (enc.sv, enc.cur - SvPVX (enc.sv));
379     return enc.sv;
380     }
381    
382     /////////////////////////////////////////////////////////////////////////////
383    
384     #define WS \
385     for (;;) \
386     { \
387     char ch = *dec->cur; \
388     if (ch > 0x20 \
389     || (ch != 0x20 && ch != 0x0a && ch != 0x0d && ch != 0x09)) \
390     break; \
391     ++dec->cur; \
392     }
393    
394     #define ERR(reason) SB dec->err = reason; goto fail; SE
395     #define EXPECT_CH(ch) SB \
396     if (*dec->cur != ch) \
397     ERR (# ch " expected"); \
398     ++dec->cur; \
399     SE
400    
401     static SV *decode_sv (dec_t *dec);
402    
403     #define APPEND_CH(ch) SB \
404     SvGROW (sv, cur + 1 + 1); \
405     SvPVX (sv)[cur++] = (ch); \
406     SE
407    
408     static signed char decode_hexdigit[256];
409    
410     static UV
411     decode_4hex (dec_t *dec)
412     {
413     signed char d1, d2, d3, d4;
414    
415     d1 = decode_hexdigit [((unsigned char *)dec->cur) [0]];
416     if (d1 < 0) ERR ("four hexadecimal digits expected");
417     d2 = decode_hexdigit [((unsigned char *)dec->cur) [1]];
418     if (d2 < 0) ERR ("four hexadecimal digits expected");
419     d3 = decode_hexdigit [((unsigned char *)dec->cur) [2]];
420     if (d3 < 0) ERR ("four hexadecimal digits expected");
421     d4 = decode_hexdigit [((unsigned char *)dec->cur) [3]];
422     if (d4 < 0) ERR ("four hexadecimal digits expected");
423    
424     dec->cur += 4;
425    
426     return ((UV)d1) << 12
427     | ((UV)d2) << 8
428     | ((UV)d3) << 4
429     | ((UV)d4);
430    
431     fail:
432     return (UV)-1;
433     }
434    
435     static SV *
436     decode_str (dec_t *dec)
437     {
438     SV *sv = NEWSV (0,2);
439     STRLEN cur = 0;
440     int utf8 = 0;
441    
442     for (;;)
443     {
444     unsigned char ch = *(unsigned char *)dec->cur;
445    
446     if (ch == '"')
447     break;
448     else if (ch == '\\')
449     {
450     switch (*++dec->cur)
451     {
452     case '\\':
453     case '/':
454     case '"': APPEND_CH (*dec->cur++); break;
455    
456     case 'b': APPEND_CH ('\010'); ++dec->cur; break;
457     case 't': APPEND_CH ('\011'); ++dec->cur; break;
458     case 'n': APPEND_CH ('\012'); ++dec->cur; break;
459     case 'f': APPEND_CH ('\014'); ++dec->cur; break;
460     case 'r': APPEND_CH ('\015'); ++dec->cur; break;
461    
462     case 'u':
463     {
464     UV lo, hi;
465     ++dec->cur;
466    
467     hi = decode_4hex (dec);
468     if (hi == (UV)-1)
469     goto fail;
470    
471     // possibly a surrogate pair
472     if (hi >= 0xd800 && hi < 0xdc00)
473     {
474     if (dec->cur [0] != '\\' || dec->cur [1] != 'u')
475     ERR ("illegal surrogate character");
476    
477     dec->cur += 2;
478    
479     lo = decode_4hex (dec);
480     if (lo == (UV)-1)
481     goto fail;
482    
483     if (lo < 0xdc00 || lo >= 0xe000)
484     ERR ("surrogate pair expected");
485    
486     hi = (hi - 0xD800) * 0x400 + (lo - 0xDC00) + 0x10000;
487     }
488     else if (lo >= 0xdc00 && lo < 0xe000)
489     ERR ("illegal surrogate character");
490    
491     if (hi >= 0x80)
492     {
493     utf8 = 1;
494    
495     SvGROW (sv, cur + 4 + 1); // at most 4 bytes for 21 bits
496     cur = (char *)uvuni_to_utf8_flags (SvPVX (sv) + cur, hi, 0) - SvPVX (sv);
497     }
498     else
499     APPEND_CH (hi);
500     }
501     break;
502     }
503     }
504     else if (ch >= 0x20 && ch <= 0x7f)
505     APPEND_CH (*dec->cur++);
506     else if (ch >= 0x80)
507     {
508     STRLEN clen;
509     UV uch = utf8n_to_uvuni (dec->cur, dec->end - dec->cur, &clen, UTF8_CHECK_ONLY);
510     if (clen < 0)
511     ERR ("malformed UTF-8 character in string, cannot convert to JSON");
512    
513     SvGROW (sv, cur + clen + 1); // at most 4 bytes for 21 bits
514     memcpy (SvPVX (sv) + cur, dec->cur, clen);
515     dec->cur += clen;
516     }
517     else
518     ERR ("invalid character encountered");
519     }
520    
521     ++dec->cur;
522    
523     SvPOK_only (sv);
524    
525     SvCUR_set (sv, cur);
526     *SvEND (sv) = 0;
527    
528     if (utf8)
529     SvUTF8_on (sv);
530    
531     return sv;
532    
533     fail:
534     SvREFCNT_dec (sv);
535     return 0;
536     }
537    
538     static SV *
539     decode_num (dec_t *dec)
540     {
541     int is_nv = 0;
542     char *start = dec->cur;
543    
544     // [minus]
545     if (*dec->cur == '-')
546     ++dec->cur;
547    
548     if (*dec->cur == '0')
549     {
550     ++dec->cur;
551     if (*dec->cur >= '0' && *dec->cur <= '9')
552     ERR ("malformed number (leading zero must not be followed by another digit)");
553     }
554    
555     // int
556     while (*dec->cur >= '0' && *dec->cur <= '9')
557     ++dec->cur;
558    
559     // [frac]
560     if (*dec->cur == '.')
561     {
562     is_nv = 1;
563    
564     do
565     {
566     ++dec->cur;
567     }
568     while (*dec->cur >= '0' && *dec->cur <= '9');
569     }
570    
571     // [exp]
572     if (*dec->cur == 'e' || *dec->cur == 'E')
573     {
574     is_nv = 1;
575    
576     ++dec->cur;
577     if (*dec->cur == '-' || *dec->cur == '+')
578     ++dec->cur;
579    
580     while (*dec->cur >= '0' && *dec->cur <= '9')
581     ++dec->cur;
582     }
583    
584     if (!is_nv)
585     {
586     UV uv;
587     int numtype = grok_number (start, dec->cur - start, &uv);
588     if (numtype & IS_NUMBER_IN_UV)
589     if (numtype & IS_NUMBER_NEG)
590     {
591     if (uv < (UV)IV_MIN)
592     return newSViv (-(IV)uv);
593     }
594     else
595     return newSVuv (uv);
596     }
597    
598     return newSVnv (Atof (start));
599    
600     fail:
601     return 0;
602     }
603    
604     static SV *
605     decode_av (dec_t *dec)
606     {
607     AV *av = newAV ();
608    
609     for (;;)
610     {
611     SV *value;
612    
613     value = decode_sv (dec);
614     if (!value)
615     goto fail;
616    
617     av_push (av, value);
618    
619     WS;
620    
621     if (*dec->cur == ']')
622     {
623     ++dec->cur;
624     break;
625     }
626    
627     if (*dec->cur != ',')
628     ERR (", or ] expected while parsing array");
629    
630     ++dec->cur;
631     }
632    
633     return newRV_noinc ((SV *)av);
634    
635     fail:
636     SvREFCNT_dec (av);
637     return 0;
638     }
639    
640     static SV *
641     decode_hv (dec_t *dec)
642     {
643     HV *hv = newHV ();
644    
645     for (;;)
646     {
647     SV *key, *value;
648    
649     WS; EXPECT_CH ('"');
650    
651     key = decode_str (dec);
652     if (!key)
653     goto fail;
654    
655     WS; EXPECT_CH (':');
656    
657     value = decode_sv (dec);
658     if (!value)
659     {
660     SvREFCNT_dec (key);
661     goto fail;
662     }
663    
664     //TODO: optimise
665     hv_store_ent (hv, key, value, 0);
666    
667     WS;
668    
669     if (*dec->cur == '}')
670     {
671     ++dec->cur;
672     break;
673     }
674    
675     if (*dec->cur != ',')
676     ERR (", or } expected while parsing object/hash");
677    
678     ++dec->cur;
679     }
680    
681     return newRV_noinc ((SV *)hv);
682    
683     fail:
684     SvREFCNT_dec (hv);
685     return 0;
686     }
687    
688     static SV *
689     decode_sv (dec_t *dec)
690     {
691     WS;
692     switch (*dec->cur)
693     {
694     case '"': ++dec->cur; return decode_str (dec);
695     case '[': ++dec->cur; return decode_av (dec);
696     case '{': ++dec->cur; return decode_hv (dec);
697    
698     case '-':
699     case '0': case '1': case '2': case '3': case '4':
700     case '5': case '6': case '7': case '8': case '9':
701     return decode_num (dec);
702    
703     case 't':
704     if (dec->end - dec->cur >= 4 && !memcmp (dec->cur, "true", 4))
705     {
706     dec->cur += 4;
707     return newSViv (1);
708     }
709     else
710     ERR ("'true' expected");
711    
712     break;
713    
714     case 'f':
715     if (dec->end - dec->cur >= 5 && !memcmp (dec->cur, "false", 5))
716     {
717     dec->cur += 5;
718     return newSViv (0);
719     }
720     else
721     ERR ("'false' expected");
722    
723     break;
724    
725     case 'n':
726     if (dec->end - dec->cur >= 4 && !memcmp (dec->cur, "null", 4))
727     {
728     dec->cur += 4;
729     return newSViv (1);
730     }
731     else
732     ERR ("'null' expected");
733    
734     break;
735    
736     default:
737     ERR ("malformed json string");
738     break;
739     }
740    
741     fail:
742     return 0;
743     }
744    
745     static SV *
746     decode_json (SV *string, UV flags)
747     {
748     SV *sv;
749    
750     if (!(flags & F_UTF8))
751     sv_utf8_upgrade (string);
752    
753     SvGROW (string, SvCUR (string) + 1); // should basically be a NOP
754    
755     dec_t dec;
756     dec.flags = flags;
757     dec.cur = SvPVX (string);
758     dec.end = SvEND (string);
759     dec.err = 0;
760    
761     *dec.end = 1; // invalid anywhere
762     sv = decode_sv (&dec);
763     *dec.end = 0;
764    
765     if (!sv)
766     {
767     IV offset = utf8_distance (dec.cur, SvPVX (string));
768     SV *uni = sv_newmortal ();
769    
770     pv_uni_display (uni, dec.cur, dec.end - dec.cur, 20, UNI_DISPLAY_QQ);
771     croak ("%s, at character %d (%s)",
772     dec.err,
773     (int)offset,
774     dec.cur != dec.end ? SvPV_nolen (uni) : "(end of string)");
775     }
776    
777     sv_dump (sv);//D
778     return sv_2mortal (sv);
779     }
780    
781     MODULE = JSON::XS PACKAGE = JSON::XS
782    
783     BOOT:
784     {
785     int i;
786    
787     memset (decode_hexdigit, 0xff, 256);
788     for (i = 10; i--; )
789     decode_hexdigit ['0' + i] = i;
790    
791     for (i = 6; --i; )
792     {
793     decode_hexdigit ['a' + i] = 10 + i;
794     decode_hexdigit ['A' + i] = 10 + i;
795     }
796    
797     json_stash = gv_stashpv ("JSON::XS", 1);
798     }
799    
800     SV *new (char *dummy)
801     CODE:
802     RETVAL = sv_bless (newRV_noinc (newSVuv (F_DEFAULT)), json_stash);
803     OUTPUT:
804     RETVAL
805    
806     SV *ascii (SV *self, int enable)
807     ALIAS:
808     ascii = F_ASCII
809     utf8 = F_UTF8
810     indent = F_INDENT
811     canonical = F_CANONICAL
812     space_before = F_SPACE_BEFORE
813     space_after = F_SPACE_AFTER
814     json_rpc = F_JSON_RPC
815 root 1.2 pretty = F_PRETTY
816 root 1.1 CODE:
817     {
818     UV *uv = SvJSON (self);
819     if (enable)
820     *uv |= ix;
821     else
822     *uv &= ~ix;
823    
824     RETVAL = newSVsv (self);
825     }
826     OUTPUT:
827     RETVAL
828    
829     void encode (SV *self, SV *scalar)
830     PPCODE:
831     XPUSHs (encode_json (scalar, *SvJSON (self)));
832    
833 root 1.2 void decode (SV *self, SV *jsonstr)
834 root 1.1 PPCODE:
835 root 1.2 XPUSHs (decode_json (jsonstr, *SvJSON (self)));
836    
837     void to_json (SV *scalar)
838     PPCODE:
839     XPUSHs (encode_json (scalar, F_UTF8));
840    
841     void from_json (SV *jsonstr)
842     PPCODE:
843     XPUSHs (decode_json (jsonstr, F_UTF8));
844 root 1.1