… | |
… | |
60 | #define expect_false(expr) expect ((expr) != 0, 0) |
60 | #define expect_false(expr) expect ((expr) != 0, 0) |
61 | #define expect_true(expr) expect ((expr) != 0, 1) |
61 | #define expect_true(expr) expect ((expr) != 0, 1) |
62 | |
62 | |
63 | #ifdef USE_ITHREADS |
63 | #ifdef USE_ITHREADS |
64 | # define JSON_SLOW 1 |
64 | # define JSON_SLOW 1 |
|
|
65 | # define JSON_STASH (json_stash ? json_stash : gv_stashpv ("JSON::XS", 1)) |
65 | #else |
66 | #else |
66 | # define JSON_SLOW 0 |
67 | # define JSON_SLOW 0 |
|
|
68 | # define JSON_STASH json_stash |
67 | #endif |
69 | #endif |
68 | |
70 | |
69 | static HV *json_stash, *json_boolean_stash; // JSON::XS:: |
71 | static HV *json_stash, *json_boolean_stash; // JSON::XS:: |
70 | static SV *json_true, *json_false; |
72 | static SV *json_true, *json_false; |
71 | |
73 | |
… | |
… | |
333 | --enc->indent; |
335 | --enc->indent; |
334 | encode_indent (enc); encode_ch (enc, ']'); |
336 | encode_indent (enc); encode_ch (enc, ']'); |
335 | } |
337 | } |
336 | |
338 | |
337 | static void |
339 | static void |
338 | encode_he (enc_t *enc, HE *he) |
340 | encode_hk (enc_t *enc, HE *he) |
339 | { |
341 | { |
340 | encode_ch (enc, '"'); |
342 | encode_ch (enc, '"'); |
341 | |
343 | |
342 | if (HeKLEN (he) == HEf_SVKEY) |
344 | if (HeKLEN (he) == HEf_SVKEY) |
343 | { |
345 | { |
… | |
… | |
356 | encode_ch (enc, '"'); |
358 | encode_ch (enc, '"'); |
357 | |
359 | |
358 | if (enc->json.flags & F_SPACE_BEFORE) encode_space (enc); |
360 | if (enc->json.flags & F_SPACE_BEFORE) encode_space (enc); |
359 | encode_ch (enc, ':'); |
361 | encode_ch (enc, ':'); |
360 | if (enc->json.flags & F_SPACE_AFTER ) encode_space (enc); |
362 | if (enc->json.flags & F_SPACE_AFTER ) encode_space (enc); |
361 | encode_sv (enc, HeVAL (he)); |
|
|
362 | } |
363 | } |
363 | |
364 | |
364 | // compare hash entries, used when all keys are bytestrings |
365 | // compare hash entries, used when all keys are bytestrings |
365 | static int |
366 | static int |
366 | he_cmp_fast (const void *a_, const void *b_) |
367 | he_cmp_fast (const void *a_, const void *b_) |
… | |
… | |
371 | HE *b = *(HE **)b_; |
372 | HE *b = *(HE **)b_; |
372 | |
373 | |
373 | STRLEN la = HeKLEN (a); |
374 | STRLEN la = HeKLEN (a); |
374 | STRLEN lb = HeKLEN (b); |
375 | STRLEN lb = HeKLEN (b); |
375 | |
376 | |
376 | if (!(cmp = memcmp (HeKEY (a), HeKEY (b), la < lb ? la : lb))) |
377 | if (!(cmp = memcmp (HeKEY (b), HeKEY (a), lb < la ? lb : la))) |
377 | cmp = la - lb; |
378 | cmp = lb - la; |
378 | |
379 | |
379 | return cmp; |
380 | return cmp; |
380 | } |
381 | } |
381 | |
382 | |
382 | // compare hash entries, used when some keys are sv's or utf-x |
383 | // compare hash entries, used when some keys are sv's or utf-x |
383 | static int |
384 | static int |
384 | he_cmp_slow (const void *a, const void *b) |
385 | he_cmp_slow (const void *a, const void *b) |
385 | { |
386 | { |
386 | return sv_cmp (HeSVKEY_force (*(HE **)a), HeSVKEY_force (*(HE **)b)); |
387 | return sv_cmp (HeSVKEY_force (*(HE **)b), HeSVKEY_force (*(HE **)a)); |
387 | } |
388 | } |
388 | |
389 | |
389 | static void |
390 | static void |
390 | encode_hv (enc_t *enc, HV *hv) |
391 | encode_hv (enc_t *enc, HV *hv) |
391 | { |
392 | { |
|
|
393 | HE *he; |
392 | int count, i; |
394 | int count; |
393 | |
395 | |
394 | if (enc->indent >= enc->maxdepth) |
396 | if (enc->indent >= enc->maxdepth) |
395 | croak ("data structure too deep (hit recursion limit)"); |
397 | croak ("data structure too deep (hit recursion limit)"); |
396 | |
398 | |
397 | encode_ch (enc, '{'); encode_nl (enc); ++enc->indent; |
399 | encode_ch (enc, '{'); encode_nl (enc); ++enc->indent; |
398 | |
400 | |
399 | if ((count = hv_iterinit (hv))) |
|
|
400 | { |
|
|
401 | // for canonical output we have to sort by keys first |
401 | // for canonical output we have to sort by keys first |
402 | // actually, this is mostly due to the stupid so-called |
402 | // actually, this is mostly due to the stupid so-called |
403 | // security workaround added somewhere in 5.8.x. |
403 | // security workaround added somewhere in 5.8.x. |
404 | // that randomises hash orderings |
404 | // that randomises hash orderings |
405 | if (enc->json.flags & F_CANONICAL) |
405 | if (enc->json.flags & F_CANONICAL) |
|
|
406 | { |
|
|
407 | int count = hv_iterinit (hv); |
|
|
408 | |
|
|
409 | if (SvMAGICAL (hv)) |
406 | { |
410 | { |
|
|
411 | // need to count by iterating. could improve by dynamically building the vector below |
|
|
412 | // but I don't care for the speed of this special case. |
|
|
413 | // note also that we will run into undefined behaviour when the two iterations |
|
|
414 | // do not result in the same count, something I might care for in some later release. |
|
|
415 | |
|
|
416 | count = 0; |
|
|
417 | while (hv_iternext (hv)) |
|
|
418 | ++count; |
|
|
419 | |
|
|
420 | hv_iterinit (hv); |
|
|
421 | } |
|
|
422 | |
|
|
423 | if (count) |
|
|
424 | { |
407 | int fast = 1; |
425 | int i, fast = 1; |
408 | HE *he; |
|
|
409 | #if defined(__BORLANDC__) || defined(_MSC_VER) |
426 | #if defined(__BORLANDC__) || defined(_MSC_VER) |
410 | HE **hes = _alloca (count * sizeof (HE)); |
427 | HE **hes = _alloca (count * sizeof (HE)); |
411 | #else |
428 | #else |
412 | HE *hes [count]; // if your compiler dies here, you need to enable C99 mode |
429 | HE *hes [count]; // if your compiler dies here, you need to enable C99 mode |
413 | #endif |
430 | #endif |
… | |
… | |
440 | |
457 | |
441 | FREETMPS; |
458 | FREETMPS; |
442 | LEAVE; |
459 | LEAVE; |
443 | } |
460 | } |
444 | |
461 | |
445 | for (i = 0; i < count; ++i) |
462 | while (count--) |
446 | { |
463 | { |
447 | encode_indent (enc); |
464 | encode_indent (enc); |
|
|
465 | he = hes [count]; |
448 | encode_he (enc, hes [i]); |
466 | encode_hk (enc, he); |
|
|
467 | encode_sv (enc, expect_false (SvMAGICAL (hv)) ? hv_iterval (hv, he) : HeVAL (he)); |
449 | |
468 | |
450 | if (i < count - 1) |
469 | if (count) |
451 | encode_comma (enc); |
470 | encode_comma (enc); |
452 | } |
471 | } |
453 | |
|
|
454 | encode_nl (enc); |
|
|
455 | } |
472 | } |
|
|
473 | } |
456 | else |
474 | else |
457 | { |
475 | { |
|
|
476 | if (hv_iterinit (hv) || SvMAGICAL (hv)) |
458 | HE *he = hv_iternext (hv); |
477 | if ((he = hv_iternext (hv))) |
459 | |
|
|
460 | for (;;) |
478 | for (;;) |
461 | { |
479 | { |
462 | encode_indent (enc); |
480 | encode_indent (enc); |
463 | encode_he (enc, he); |
481 | encode_hk (enc, he); |
|
|
482 | encode_sv (enc, expect_false (SvMAGICAL (hv)) ? hv_iterval (hv, he) : HeVAL (he)); |
464 | |
483 | |
465 | if (!(he = hv_iternext (hv))) |
484 | if (!(he = hv_iternext (hv))) |
466 | break; |
485 | break; |
467 | |
486 | |
468 | encode_comma (enc); |
487 | encode_comma (enc); |
469 | } |
488 | } |
|
|
489 | } |
470 | |
490 | |
471 | encode_nl (enc); |
491 | encode_nl (enc); |
472 | } |
|
|
473 | } |
|
|
474 | |
492 | |
475 | --enc->indent; encode_indent (enc); encode_ch (enc, '}'); |
493 | --enc->indent; encode_indent (enc); encode_ch (enc, '}'); |
476 | } |
494 | } |
477 | |
495 | |
478 | // encode objects, arrays and special \0=false and \1=true values. |
496 | // encode objects, arrays and special \0=false and \1=true values. |
… | |
… | |
1223 | |
1241 | |
1224 | case 't': |
1242 | case 't': |
1225 | if (dec->end - dec->cur >= 4 && !memcmp (dec->cur, "true", 4)) |
1243 | if (dec->end - dec->cur >= 4 && !memcmp (dec->cur, "true", 4)) |
1226 | { |
1244 | { |
1227 | dec->cur += 4; |
1245 | dec->cur += 4; |
|
|
1246 | #if JSON_SLOW |
|
|
1247 | json_true = get_sv ("JSON::XS::true", 1); SvREADONLY_on (json_true); |
|
|
1248 | #endif |
1228 | return SvREFCNT_inc (json_true); |
1249 | return SvREFCNT_inc (json_true); |
1229 | } |
1250 | } |
1230 | else |
1251 | else |
1231 | ERR ("'true' expected"); |
1252 | ERR ("'true' expected"); |
1232 | |
1253 | |
… | |
… | |
1234 | |
1255 | |
1235 | case 'f': |
1256 | case 'f': |
1236 | if (dec->end - dec->cur >= 5 && !memcmp (dec->cur, "false", 5)) |
1257 | if (dec->end - dec->cur >= 5 && !memcmp (dec->cur, "false", 5)) |
1237 | { |
1258 | { |
1238 | dec->cur += 5; |
1259 | dec->cur += 5; |
|
|
1260 | #if JSON_SLOW |
|
|
1261 | json_false = get_sv ("JSON::XS::false", 1); SvREADONLY_on (json_false); |
|
|
1262 | #endif |
1239 | return SvREFCNT_inc (json_false); |
1263 | return SvREFCNT_inc (json_false); |
1240 | } |
1264 | } |
1241 | else |
1265 | else |
1242 | ERR ("'false' expected"); |
1266 | ERR ("'false' expected"); |
1243 | |
1267 | |
… | |
… | |
1378 | json_boolean_stash = 0; |
1402 | json_boolean_stash = 0; |
1379 | |
1403 | |
1380 | void new (char *klass) |
1404 | void new (char *klass) |
1381 | PPCODE: |
1405 | PPCODE: |
1382 | { |
1406 | { |
1383 | HV *stash = !JSON_SLOW || json_stash |
|
|
1384 | ? json_stash |
|
|
1385 | : gv_stashpv ("JSON::XS", 1); |
|
|
1386 | SV *pv = NEWSV (0, sizeof (JSON)); |
1407 | SV *pv = NEWSV (0, sizeof (JSON)); |
1387 | SvPOK_only (pv); |
1408 | SvPOK_only (pv); |
1388 | Zero (SvPVX (pv), 1, JSON); |
1409 | Zero (SvPVX (pv), 1, JSON); |
1389 | ((JSON *)SvPVX (pv))->flags = F_DEFAULT; |
1410 | ((JSON *)SvPVX (pv))->flags = F_DEFAULT; |
1390 | XPUSHs (sv_2mortal (sv_bless (newRV_noinc (pv), stash))); |
1411 | XPUSHs (sv_2mortal (sv_bless (newRV_noinc (pv), JSON_STASH))); |
1391 | } |
1412 | } |
1392 | |
1413 | |
1393 | void ascii (JSON *self, int enable = 1) |
1414 | void ascii (JSON *self, int enable = 1) |
1394 | ALIAS: |
1415 | ALIAS: |
1395 | ascii = F_ASCII |
1416 | ascii = F_ASCII |