You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

950 lines
22 KiB

пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
  1. // This file is part of Jiffy released under the MIT license.
  2. // See the LICENSE file for more information.
  3. #include <assert.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include "jiffy.h"
  7. #include "termstack.h"
  8. #define BIN_INC_SIZE 2048
  9. #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
  10. #define MAYBE_PRETTY(e) \
  11. do { \
  12. if(e->pretty) { \
  13. if(!enc_shift(e)) \
  14. return 0; \
  15. } \
  16. } while(0)
  17. #if WINDOWS || WIN32
  18. #define inline __inline
  19. #define snprintf _snprintf
  20. #endif
  21. typedef struct {
  22. ErlNifEnv* env;
  23. jiffy_st* atoms;
  24. size_t bytes_per_red;
  25. int uescape;
  26. int pretty;
  27. int use_nil;
  28. int escape_forward_slashes;
  29. int shiftcnt;
  30. int count;
  31. size_t iosize;
  32. ERL_NIF_TERM iolist;
  33. int partial_output;
  34. ErlNifBinary buffer;
  35. int have_buffer;
  36. unsigned char* p;
  37. size_t i;
  38. } Encoder;
  39. // String constants for pretty printing.
  40. // Every string starts with its length.
  41. #define NUM_SHIFTS 8
  42. static char* shifts[NUM_SHIFTS] = {
  43. "\x01\n",
  44. "\x03\n ",
  45. "\x05\n ",
  46. "\x07\n ",
  47. "\x09\n ",
  48. "\x0b\n ",
  49. "\x0d\n ",
  50. "\x0f\n "
  51. };
  52. Encoder*
  53. enc_new(ErlNifEnv* env)
  54. {
  55. jiffy_st* st = (jiffy_st*) enif_priv_data(env);
  56. Encoder* e = enif_alloc_resource(st->res_enc, sizeof(Encoder));
  57. e->atoms = st;
  58. e->bytes_per_red = DEFAULT_BYTES_PER_REDUCTION;
  59. e->uescape = 0;
  60. e->pretty = 0;
  61. e->use_nil = 0;
  62. e->escape_forward_slashes = 0;
  63. e->shiftcnt = 0;
  64. e->count = 0;
  65. e->iosize = 0;
  66. e->iolist = enif_make_list(env, 0);
  67. e->partial_output = 0;
  68. if(!enif_alloc_binary(BIN_INC_SIZE, &e->buffer)) {
  69. enif_release_resource(e);
  70. return NULL;
  71. }
  72. e->have_buffer = 1;
  73. e->p = e->buffer.data;
  74. e->i = 0;
  75. return e;
  76. }
  77. int
  78. enc_init(Encoder* e, ErlNifEnv* env)
  79. {
  80. e->env = env;
  81. return 1;
  82. }
  83. void
  84. enc_destroy(ErlNifEnv* env, void* obj)
  85. {
  86. Encoder* e = (Encoder*) obj;
  87. if(e->have_buffer) {
  88. enif_release_binary(&e->buffer);
  89. }
  90. }
  91. ERL_NIF_TERM
  92. enc_error(Encoder* e, const char* msg)
  93. {
  94. //assert(0 && msg);
  95. return make_error(e->atoms, e->env, msg);
  96. }
  97. ERL_NIF_TERM
  98. enc_obj_error(Encoder* e, const char* msg, ERL_NIF_TERM obj)
  99. {
  100. return make_obj_error(e->atoms, e->env, msg, obj);
  101. }
  102. int
  103. enc_flush(Encoder* e)
  104. {
  105. ERL_NIF_TERM bin;
  106. if(e->i == 0) {
  107. return 1;
  108. }
  109. if(e->i < e->buffer.size) {
  110. if(!enif_realloc_binary(&e->buffer, e->i)) {
  111. return 0;
  112. }
  113. }
  114. bin = enif_make_binary(e->env, &e->buffer);
  115. e->have_buffer = 0;
  116. e->iolist = enif_make_list_cell(e->env, bin, e->iolist);
  117. e->iosize += e->i;
  118. return 1;
  119. }
  120. static inline int
  121. enc_ensure(Encoder* e, size_t req)
  122. {
  123. size_t new_size = BIN_INC_SIZE;
  124. if(e->have_buffer) {
  125. if(req < (e->buffer.size - e->i)) {
  126. return 1;
  127. }
  128. if(!enc_flush(e)) {
  129. return 0;
  130. }
  131. }
  132. for(new_size = BIN_INC_SIZE; new_size < req; new_size <<= 1);
  133. if(!enif_alloc_binary(new_size, &e->buffer)) {
  134. return 0;
  135. }
  136. e->have_buffer = 1;
  137. e->p = e->buffer.data;
  138. e->i = 0;
  139. return 1;
  140. }
  141. static inline int
  142. enc_literal(Encoder* e, const char* literal, size_t len)
  143. {
  144. if(!enc_ensure(e, len)) {
  145. return 0;
  146. }
  147. memcpy(&(e->p[e->i]), literal, len);
  148. e->i += len;
  149. e->count++;
  150. return 1;
  151. }
  152. static inline int
  153. enc_bignum(Encoder* e, ERL_NIF_TERM value) {
  154. /* This is a bignum and we need to handle it up in Erlang code as
  155. * the NIF API doesn't support them yet.
  156. *
  157. * Flush our current output and mark ourselves as needing a fixup
  158. * after we return. */
  159. if(!enc_flush(e)) {
  160. return 0;
  161. }
  162. e->iolist = enif_make_list_cell(e->env, value, e->iolist);
  163. e->partial_output = 1;
  164. return 1;
  165. }
  166. static inline int
  167. enc_special_character(Encoder* e, int val) {
  168. switch(val) {
  169. case '\"':
  170. case '\\':
  171. e->p[e->i++] = '\\';
  172. e->p[e->i++] = val;
  173. return 1;
  174. case '\b':
  175. e->p[e->i++] = '\\';
  176. e->p[e->i++] = 'b';
  177. return 1;
  178. case '\f':
  179. e->p[e->i++] = '\\';
  180. e->p[e->i++] = 'f';
  181. return 1;
  182. case '\n':
  183. e->p[e->i++] = '\\';
  184. e->p[e->i++] = 'n';
  185. return 1;
  186. case '\r':
  187. e->p[e->i++] = '\\';
  188. e->p[e->i++] = 'r';
  189. return 1;
  190. case '\t':
  191. e->p[e->i++] = '\\';
  192. e->p[e->i++] = 't';
  193. return 1;
  194. case '/':
  195. if(e->escape_forward_slashes) {
  196. e->p[e->i++] = '\\';
  197. }
  198. e->p[e->i++] = '/';
  199. return 1;
  200. default:
  201. if(val < 0x20) {
  202. e->i += unicode_uescape(val, &(e->p[e->i]));
  203. return 1;
  204. }
  205. return 0;
  206. }
  207. }
  208. static int
  209. enc_atom(Encoder* e, ERL_NIF_TERM val)
  210. {
  211. static const int MAX_ESCAPE_LEN = 12;
  212. unsigned char data[512];
  213. size_t size;
  214. int i;
  215. if(!enif_get_atom(e->env, val, (char*)data, 512, ERL_NIF_LATIN1)) {
  216. return 0;
  217. }
  218. size = strlen((const char*)data);
  219. /* Reserve space for the first quotation mark and most of the output. */
  220. if(!enc_ensure(e, size + MAX_ESCAPE_LEN + 1)) {
  221. return 0;
  222. }
  223. e->p[e->i++] = '\"';
  224. i = 0;
  225. while(i < size) {
  226. if(!enc_ensure(e, MAX_ESCAPE_LEN)) {
  227. return 0;
  228. }
  229. if(enc_special_character(e, data[i])) {
  230. i++;
  231. } else if(data[i] < 0x80) {
  232. e->p[e->i++] = data[i];
  233. i++;
  234. } else if(data[i] >= 0x80) {
  235. /* The atom encoding is latin1, so we don't need validation
  236. * as all latin1 characters are valid Unicode codepoints. */
  237. if (!e->uescape) {
  238. e->i += unicode_to_utf8(data[i], &e->p[e->i]);
  239. } else {
  240. e->i += unicode_uescape(data[i], &e->p[e->i]);
  241. }
  242. i++;
  243. }
  244. }
  245. if(!enc_ensure(e, 1)) {
  246. return 0;
  247. }
  248. e->p[e->i++] = '\"';
  249. e->count++;
  250. return 1;
  251. }
  252. static int
  253. enc_string(Encoder* e, ERL_NIF_TERM val)
  254. {
  255. static const int MAX_ESCAPE_LEN = 12;
  256. ErlNifBinary bin;
  257. unsigned char* data;
  258. size_t size;
  259. int esc_len;
  260. int ulen;
  261. int uval;
  262. int i;
  263. if(!enif_inspect_binary(e->env, val, &bin)) {
  264. return 0;
  265. }
  266. data = bin.data;
  267. size = bin.size;
  268. /* Reserve space for the first quotation mark and most of the output. */
  269. if(!enc_ensure(e, size + MAX_ESCAPE_LEN + 1)) {
  270. return 0;
  271. }
  272. e->p[e->i++] = '\"';
  273. i = 0;
  274. while(i < size) {
  275. if(!enc_ensure(e, MAX_ESCAPE_LEN)) {
  276. return 0;
  277. }
  278. if(enc_special_character(e, data[i])) {
  279. i++;
  280. } else if(data[i] < 0x80) {
  281. e->p[e->i++] = data[i++];
  282. } else if(data[i] >= 0x80) {
  283. ulen = utf8_validate(&(data[i]), size - i);
  284. if (ulen < 0) {
  285. return 0;
  286. } else if (e->uescape) {
  287. uval = utf8_to_unicode(&(data[i]), size-i);
  288. if(uval < 0) {
  289. return 0;
  290. }
  291. esc_len = unicode_uescape(uval, &(e->p[e->i]));
  292. if(esc_len < 0) {
  293. return 0;
  294. }
  295. e->i += esc_len;
  296. } else {
  297. memcpy(&e->p[e->i], &data[i], ulen);
  298. e->i += ulen;
  299. }
  300. i += ulen;
  301. }
  302. }
  303. if(!enc_ensure(e, 1)) {
  304. return 0;
  305. }
  306. e->p[e->i++] = '\"';
  307. e->count++;
  308. return 1;
  309. }
  310. static inline int
  311. enc_object_key(ErlNifEnv *env, Encoder* e, ERL_NIF_TERM val)
  312. {
  313. if(enif_is_atom(env, val)) {
  314. return enc_atom(e, val);
  315. }
  316. return enc_string(e, val);
  317. }
  318. // From https://www.slideshare.net/andreialexandrescu1/three-optimization-tips-for-c-15708507
  319. #define P01 10
  320. #define P02 100
  321. #define P03 1000
  322. #define P04 10000
  323. #define P05 100000
  324. #define P06 1000000
  325. #define P07 10000000
  326. #define P08 100000000
  327. #define P09 1000000000
  328. #define P10 10000000000
  329. #define P11 100000000000L
  330. #define P12 1000000000000L
  331. int
  332. digits10(ErlNifUInt64 v)
  333. {
  334. if (v < P01) return 1;
  335. if (v < P02) return 2;
  336. if (v < P03) return 3;
  337. if (v < P12) {
  338. if (v < P08) {
  339. if (v < P06) {
  340. if (v < P04) {
  341. return 4;
  342. }
  343. return 5 + (v >= P05);
  344. }
  345. return 7 + (v >= P07);
  346. }
  347. if (v < P10) {
  348. return 9 + (v >= P09);
  349. }
  350. return 11 + (v >= P11);
  351. }
  352. return 12 + digits10(v / P12);
  353. }
  354. unsigned int
  355. u64ToAsciiTable(unsigned char *dst, ErlNifUInt64 value)
  356. {
  357. static const char digits[201] =
  358. "0001020304050607080910111213141516171819"
  359. "2021222324252627282930313233343536373839"
  360. "4041424344454647484950515253545556575859"
  361. "6061626364656667686970717273747576777879"
  362. "8081828384858687888990919293949596979899";
  363. const int length = digits10(value);
  364. int next = length - 1;
  365. while (value >= 100) {
  366. const int i = (value % 100) * 2;
  367. value /= 100;
  368. dst[next] = digits[i + 1];
  369. dst[next - 1] = digits[i];
  370. next -= 2;
  371. }
  372. // Handle last 1-2 digits.
  373. if (value < 10) {
  374. dst[next] = '0' + (unsigned int) value;
  375. } else {
  376. const int i = (unsigned int) value * 2;
  377. dst[next] = digits[i + 1];
  378. dst[next - 1] = digits[i];
  379. }
  380. return length;
  381. }
  382. unsigned
  383. i64ToAsciiTable(unsigned char *dst, ErlNifSInt64 value)
  384. {
  385. if (value < 0) {
  386. *dst++ = '-';
  387. return 1 + u64ToAsciiTable(dst, -value);
  388. } else {
  389. return u64ToAsciiTable(dst, value);
  390. }
  391. }
  392. static inline int
  393. enc_long(Encoder* e, ErlNifSInt64 val)
  394. {
  395. if(!enc_ensure(e, 32)) {
  396. return 0;
  397. }
  398. e->i += i64ToAsciiTable(&(e->p[e->i]), val);
  399. e->count++;
  400. return 1;
  401. }
  402. static inline int
  403. enc_double(Encoder* e, double val)
  404. {
  405. unsigned char* start;
  406. size_t len;
  407. if(!enc_ensure(e, 32)) {
  408. return 0;
  409. }
  410. start = &(e->p[e->i]);
  411. if(!double_to_shortest(start, e->buffer.size, &len, val)) {
  412. return 0;
  413. }
  414. e->i += len;
  415. e->count++;
  416. return 1;
  417. }
  418. static inline int
  419. enc_char(Encoder* e, char c)
  420. {
  421. if(!enc_ensure(e, 1)) {
  422. return 0;
  423. }
  424. e->p[e->i++] = c;
  425. return 1;
  426. }
  427. static int
  428. enc_shift(Encoder* e) {
  429. int i;
  430. char* shift;
  431. assert(e->shiftcnt >= 0 && "Invalid shift count.");
  432. shift = shifts[MIN(e->shiftcnt, NUM_SHIFTS-1)];
  433. if(!enc_literal(e, shift + 1, *shift))
  434. return 0;
  435. // Finish the rest of this shift it's it bigger than
  436. // our largest predefined constant.
  437. for(i = NUM_SHIFTS - 1; i < e->shiftcnt; i++) {
  438. if(!enc_literal(e, " ", 2))
  439. return 0;
  440. }
  441. return 1;
  442. }
  443. static inline int
  444. enc_start_object(Encoder* e)
  445. {
  446. e->count++;
  447. e->shiftcnt++;
  448. if(!enc_char(e, '{'))
  449. return 0;
  450. MAYBE_PRETTY(e);
  451. return 1;
  452. }
  453. static inline int
  454. enc_end_object(Encoder* e)
  455. {
  456. e->shiftcnt--;
  457. MAYBE_PRETTY(e);
  458. return enc_char(e, '}');
  459. }
  460. static inline int
  461. enc_start_array(Encoder* e)
  462. {
  463. e->count++;
  464. e->shiftcnt++;
  465. if(!enc_char(e, '['))
  466. return 0;
  467. MAYBE_PRETTY(e);
  468. return 1;
  469. }
  470. static inline int
  471. enc_end_array(Encoder* e)
  472. {
  473. e->shiftcnt--;
  474. MAYBE_PRETTY(e);
  475. return enc_char(e, ']');
  476. }
  477. static inline int
  478. enc_colon(Encoder* e)
  479. {
  480. if(e->pretty)
  481. return enc_literal(e, " : ", 3);
  482. return enc_char(e, ':');
  483. }
  484. static inline int
  485. enc_comma(Encoder* e)
  486. {
  487. if(!enc_char(e, ','))
  488. return 0;
  489. MAYBE_PRETTY(e);
  490. return 1;
  491. }
  492. #if MAP_TYPE_PRESENT
  493. int
  494. enc_map_to_ejson(ErlNifEnv* env, ERL_NIF_TERM map, ERL_NIF_TERM* out)
  495. {
  496. ErlNifMapIterator iter;
  497. size_t size;
  498. ERL_NIF_TERM list;
  499. ERL_NIF_TERM tuple;
  500. ERL_NIF_TERM key;
  501. ERL_NIF_TERM val;
  502. if(!enif_get_map_size(env, map, &size)) {
  503. return 0;
  504. }
  505. list = enif_make_list(env, 0);
  506. if(size == 0) {
  507. *out = enif_make_tuple1(env, list);
  508. return 1;
  509. }
  510. if(!enif_map_iterator_create(env, map, &iter, ERL_NIF_MAP_ITERATOR_HEAD)) {
  511. return 0;
  512. }
  513. do {
  514. if(!enif_map_iterator_get_pair(env, &iter, &key, &val)) {
  515. enif_map_iterator_destroy(env, &iter);
  516. return 0;
  517. }
  518. tuple = enif_make_tuple2(env, key, val);
  519. list = enif_make_list_cell(env, tuple, list);
  520. } while(enif_map_iterator_next(env, &iter));
  521. enif_map_iterator_destroy(env, &iter);
  522. *out = enif_make_tuple1(env, list);
  523. return 1;
  524. }
  525. #endif
  526. ERL_NIF_TERM
  527. encode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  528. {
  529. jiffy_st* st = (jiffy_st*) enif_priv_data(env);
  530. Encoder* e;
  531. ERL_NIF_TERM opts;
  532. ERL_NIF_TERM val;
  533. ERL_NIF_TERM tmp_argv[3];
  534. if(argc != 2) {
  535. return enif_make_badarg(env);
  536. }
  537. e = enc_new(env);
  538. if(e == NULL) {
  539. return make_error(st, env, "internal_error");
  540. }
  541. tmp_argv[0] = enif_make_resource(env, e);
  542. tmp_argv[1] = enif_make_tuple1(env, argv[0]);
  543. tmp_argv[2] = enif_make_list(env, 0);
  544. enif_release_resource(e);
  545. opts = argv[1];
  546. if(!enif_is_list(env, opts)) {
  547. return enif_make_badarg(env);
  548. }
  549. while(enif_get_list_cell(env, opts, &val, &opts)) {
  550. if(enif_is_identical(val, e->atoms->atom_uescape)) {
  551. e->uescape = 1;
  552. } else if(enif_is_identical(val, e->atoms->atom_pretty)) {
  553. e->pretty = 1;
  554. } else if(enif_is_identical(val, e->atoms->atom_escape_forward_slashes)) {
  555. e->escape_forward_slashes = 1;
  556. } else if(enif_is_identical(val, e->atoms->atom_use_nil)) {
  557. e->use_nil = 1;
  558. } else if(enif_is_identical(val, e->atoms->atom_force_utf8)) {
  559. // Ignore, handled in Erlang
  560. } else if(get_bytes_per_iter(env, val, &(e->bytes_per_red))) {
  561. continue;
  562. } else if(get_bytes_per_red(env, val, &(e->bytes_per_red))) {
  563. continue;
  564. } else {
  565. return enif_make_badarg(env);
  566. }
  567. }
  568. return encode_iter(env, 3, tmp_argv);
  569. }
  570. ERL_NIF_TERM
  571. encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  572. {
  573. jiffy_st* st = (jiffy_st*) enif_priv_data(env);
  574. Encoder* e;
  575. TermStack stack;
  576. ERL_NIF_TERM ret = 0;
  577. ERL_NIF_TERM curr;
  578. ERL_NIF_TERM item;
  579. const ERL_NIF_TERM* tuple;
  580. int arity;
  581. ErlNifSInt64 lval;
  582. double dval;
  583. size_t start;
  584. size_t bytes_processed = 0;
  585. if(!enif_get_resource(env, argv[0], st->res_enc, (void**) &e)) {
  586. return enif_make_badarg(env);
  587. }
  588. if(!enc_init(e, env)) {
  589. return enif_make_badarg(env);
  590. }
  591. if(!termstack_restore(env, argv[1], &stack)) {
  592. return enif_make_badarg(env);
  593. }
  594. e->iolist = argv[2];
  595. start = e->iosize + e->i;
  596. while(!termstack_is_empty(&stack)) {
  597. bytes_processed = (e->iosize + e->i) - start;
  598. if(should_yield(bytes_processed, e->bytes_per_red)) {
  599. ERL_NIF_TERM tmp_argv[3];
  600. assert(enif_is_list(env, e->iolist));
  601. tmp_argv[0] = argv[0];
  602. tmp_argv[1] = termstack_save(env, &stack);
  603. tmp_argv[2] = e->iolist;
  604. termstack_destroy(&stack);
  605. bump_used_reds(env, bytes_processed, e->bytes_per_red);
  606. #if SCHEDULE_NIF_PRESENT
  607. return enif_schedule_nif(
  608. env,
  609. "nif_encode_iter",
  610. 0,
  611. encode_iter,
  612. 3,
  613. tmp_argv
  614. );
  615. #else
  616. return enif_make_tuple2(
  617. env,
  618. st->atom_iter,
  619. enif_make_tuple(env, 3, tmp_argv)
  620. );
  621. #endif
  622. }
  623. curr = termstack_pop(&stack);
  624. if(enif_is_atom(env, curr)) {
  625. if(enif_is_identical(curr, e->atoms->ref_object)) {
  626. curr = termstack_pop(&stack);
  627. if(!enif_get_list_cell(env, curr, &item, &curr)) {
  628. if(!enc_end_object(e)) {
  629. ret = enc_error(e, "internal_error");
  630. goto done;
  631. }
  632. continue;
  633. }
  634. if(!enif_get_tuple(env, item, &arity, &tuple)) {
  635. ret = enc_obj_error(e, "invalid_object_member", item);
  636. goto done;
  637. }
  638. if(arity != 2) {
  639. ret = enc_obj_error(e, "invalid_object_member_arity", item);
  640. goto done;
  641. }
  642. if(!enc_comma(e)) {
  643. ret = enc_error(e, "internal_error");
  644. goto done;
  645. }
  646. if(!enc_object_key(env, e, tuple[0])) {
  647. ret = enc_obj_error(e, "invalid_object_member_key", tuple[0]);
  648. goto done;
  649. }
  650. if(!enc_colon(e)) {
  651. ret = enc_error(e, "internal_error");
  652. goto done;
  653. }
  654. termstack_push(&stack, curr);
  655. termstack_push(&stack, e->atoms->ref_object);
  656. termstack_push(&stack, tuple[1]);
  657. } else if(enif_is_identical(curr, e->atoms->ref_array)) {
  658. curr = termstack_pop(&stack);
  659. if(!enif_get_list_cell(env, curr, &item, &curr)) {
  660. if(!enc_end_array(e)) {
  661. ret = enc_error(e, "internal_error");
  662. goto done;
  663. }
  664. continue;
  665. }
  666. if(!enc_comma(e)) {
  667. ret = enc_error(e, "internal_error");
  668. goto done;
  669. }
  670. termstack_push(&stack, curr);
  671. termstack_push(&stack, e->atoms->ref_array);
  672. termstack_push(&stack, item);
  673. } else if(enif_is_identical(curr, e->atoms->atom_null)) {
  674. if(!enc_literal(e, "null", 4)) {
  675. ret = enc_error(e, "null");
  676. goto done;
  677. }
  678. } else if(e->use_nil && enif_is_identical(curr, e->atoms->atom_nil)) {
  679. if(!enc_literal(e, "null", 4)) {
  680. ret = enc_error(e, "null");
  681. goto done;
  682. }
  683. } else if(enif_is_identical(curr, e->atoms->atom_true)) {
  684. if(!enc_literal(e, "true", 4)) {
  685. ret = enc_error(e, "true");
  686. goto done;
  687. }
  688. } else if(enif_is_identical(curr, e->atoms->atom_false)) {
  689. if(!enc_literal(e, "false", 5)) {
  690. ret = enc_error(e, "false");
  691. goto done;
  692. }
  693. } else if(!enc_atom(e, curr)) {
  694. ret = enc_obj_error(e, "invalid_string", curr);
  695. goto done;
  696. }
  697. } else if(enif_is_binary(env, curr)) {
  698. if(!enc_string(e, curr)) {
  699. ret = enc_obj_error(e, "invalid_string", curr);
  700. goto done;
  701. }
  702. } else if(enif_get_int64(env, curr, &lval)) {
  703. if(!enc_long(e, lval)) {
  704. ret = enc_error(e, "internal_error");
  705. goto done;
  706. }
  707. } else if(enif_get_double(env, curr, &dval)) {
  708. if(!enc_double(e, dval)) {
  709. ret = enc_error(e, "internal_error");
  710. goto done;
  711. }
  712. } else if(enif_get_tuple(env, curr, &arity, &tuple)) {
  713. if(arity != 1) {
  714. ret = enc_obj_error(e, "invalid_ejson", curr);
  715. goto done;
  716. }
  717. if(!enif_is_list(env, tuple[0])) {
  718. ret = enc_obj_error(e, "invalid_object", curr);
  719. goto done;
  720. }
  721. if(!enc_start_object(e)) {
  722. ret = enc_error(e, "internal_error");
  723. goto done;
  724. }
  725. if(!enif_get_list_cell(env, tuple[0], &item, &curr)) {
  726. if(!enc_end_object(e)) {
  727. ret = enc_error(e, "internal_error");
  728. goto done;
  729. }
  730. continue;
  731. }
  732. if(!enif_get_tuple(env, item, &arity, &tuple)) {
  733. ret = enc_obj_error(e, "invalid_object_member", item);
  734. goto done;
  735. }
  736. if(arity != 2) {
  737. ret = enc_obj_error(e, "invalid_object_member_arity", item);
  738. goto done;
  739. }
  740. if(!enc_object_key(env, e, tuple[0])) {
  741. ret = enc_obj_error(e, "invalid_object_member_key", tuple[0]);
  742. goto done;
  743. }
  744. if(!enc_colon(e)) {
  745. ret = enc_error(e, "internal_error");
  746. goto done;
  747. }
  748. termstack_push(&stack, curr);
  749. termstack_push(&stack, e->atoms->ref_object);
  750. termstack_push(&stack, tuple[1]);
  751. #if MAP_TYPE_PRESENT
  752. } else if(enif_is_map(env, curr)) {
  753. if(!enc_map_to_ejson(env, curr, &curr)) {
  754. ret = enc_error(e, "internal_error");
  755. goto done;
  756. }
  757. termstack_push(&stack, curr);
  758. #endif
  759. } else if(enif_is_list(env, curr)) {
  760. if(!enc_start_array(e)) {
  761. ret = enc_error(e, "internal_error");
  762. goto done;
  763. }
  764. if(!enif_get_list_cell(env, curr, &item, &curr)) {
  765. if(!enc_end_array(e)) {
  766. ret = enc_error(e, "internal_error");
  767. goto done;
  768. }
  769. continue;
  770. }
  771. termstack_push(&stack, curr);
  772. termstack_push(&stack, e->atoms->ref_array);
  773. termstack_push(&stack, item);
  774. } else if(enif_is_number(env, curr)) {
  775. if(!enc_bignum(e, curr)) {
  776. ret = enc_error(e, "internal_error");
  777. goto done;
  778. }
  779. } else {
  780. ret = enc_obj_error(e, "invalid_ejson", curr);
  781. goto done;
  782. }
  783. }
  784. if(!enc_flush(e)) {
  785. ret = enc_error(e, "internal_error");
  786. goto done;
  787. }
  788. assert(enif_is_list(env, e->iolist));
  789. if(e->partial_output) {
  790. ret = enif_make_tuple2(env, e->atoms->atom_partial, e->iolist);
  791. } else {
  792. ret = e->iolist;
  793. }
  794. done:
  795. bump_used_reds(env, bytes_processed, e->bytes_per_red);
  796. termstack_destroy(&stack);
  797. return ret;
  798. }