Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

975 рядки
23 KiB

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