pdf-lex.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. // Copyright (C) 2004-2024 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #include "mupdf/fitz.h"
  23. #include "mupdf/pdf.h"
  24. #include <string.h>
  25. #define IS_NUMBER \
  26. '+':case'-':case'.':case'0':case'1':case'2':case'3':\
  27. case'4':case'5':case'6':case'7':case'8':case'9'
  28. #define IS_WHITE \
  29. '\x00':case'\x09':case'\x0a':case'\x0c':case'\x0d':case'\x20'
  30. #define IS_HEX \
  31. '0':case'1':case'2':case'3':case'4':case'5':case'6':\
  32. case'7':case'8':case'9':case'A':case'B':case'C':\
  33. case'D':case'E':case'F':case'a':case'b':case'c':\
  34. case'd':case'e':case'f'
  35. #define IS_DELIM \
  36. '(':case')':case'<':case'>':case'[':case']':case'{':\
  37. case'}':case'/':case'%'
  38. #define RANGE_0_9 \
  39. '0':case'1':case'2':case'3':case'4':case'5':\
  40. case'6':case'7':case'8':case'9'
  41. #define RANGE_a_f \
  42. 'a':case'b':case'c':case'd':case'e':case'f'
  43. #define RANGE_A_F \
  44. 'A':case'B':case'C':case'D':case'E':case'F'
  45. #define RANGE_0_7 \
  46. '0':case'1':case'2':case'3':case'4':case'5':case'6':case'7'
  47. /* #define DUMP_LEXER_STREAM */
  48. #ifdef DUMP_LEXER_STREAM
  49. static inline int lex_byte(fz_context *ctx, fz_stream *stm)
  50. {
  51. int c = fz_read_byte(ctx, stm);
  52. if (c == EOF)
  53. fz_write_printf(ctx, fz_stdout(ctx), "<EOF>");
  54. else if (c >= 32 && c < 128)
  55. fz_write_printf(ctx, fz_stdout(ctx), "%c", c);
  56. else
  57. fz_write_printf(ctx, fz_stdout(ctx), "<%02x>", c);
  58. return c;
  59. }
  60. #else
  61. #define lex_byte(C,S) fz_read_byte(C,S)
  62. #endif
  63. static inline int iswhite(int ch)
  64. {
  65. return
  66. ch == '\000' ||
  67. ch == '\011' ||
  68. ch == '\012' ||
  69. ch == '\014' ||
  70. ch == '\015' ||
  71. ch == '\040';
  72. }
  73. static inline int fz_isprint(int ch)
  74. {
  75. return ch >= ' ' && ch <= '~';
  76. }
  77. static inline int unhex(int ch)
  78. {
  79. if (ch >= '0' && ch <= '9') return ch - '0';
  80. if (ch >= 'A' && ch <= 'F') return ch - 'A' + 0xA;
  81. if (ch >= 'a' && ch <= 'f') return ch - 'a' + 0xA;
  82. return 0;
  83. }
  84. static void
  85. lex_white(fz_context *ctx, fz_stream *f)
  86. {
  87. int c;
  88. do {
  89. c = lex_byte(ctx, f);
  90. } while ((c <= 32) && (iswhite(c)));
  91. if (c != EOF)
  92. fz_unread_byte(ctx, f);
  93. }
  94. static void
  95. lex_comment(fz_context *ctx, fz_stream *f)
  96. {
  97. int c;
  98. do {
  99. c = lex_byte(ctx, f);
  100. } while ((c != '\012') && (c != '\015') && (c != EOF));
  101. }
  102. /* Fast(ish) but inaccurate strtof, with Adobe overflow handling. */
  103. static float acrobat_compatible_atof(char *s)
  104. {
  105. int neg = 0;
  106. int i = 0;
  107. while (*s == '-')
  108. {
  109. neg = 1;
  110. ++s;
  111. }
  112. while (*s == '+')
  113. {
  114. ++s;
  115. }
  116. while (*s >= '0' && *s <= '9')
  117. {
  118. /* We deliberately ignore overflow here.
  119. * Tests show that Acrobat handles * overflows in exactly the same way we do:
  120. * 123450000000000000000678 is read as 678.
  121. */
  122. i = i * 10 + (*s - '0');
  123. ++s;
  124. }
  125. if (*s == '.')
  126. {
  127. float v = i;
  128. float n = 0;
  129. float d = 1;
  130. ++s;
  131. while (*s >= '0' && *s <= '9')
  132. {
  133. n = 10 * n + (*s - '0');
  134. d = 10 * d;
  135. ++s;
  136. }
  137. v += n / d;
  138. return neg ? -v : v;
  139. }
  140. else
  141. {
  142. return neg ? -i : i;
  143. }
  144. }
  145. /* Fast but inaccurate atoi. */
  146. static int64_t fast_atoi(char *s)
  147. {
  148. int neg = 0;
  149. int64_t i = 0;
  150. while (*s == '-')
  151. {
  152. neg = 1;
  153. ++s;
  154. }
  155. while (*s == '+')
  156. {
  157. ++s;
  158. }
  159. while (*s >= '0' && *s <= '9')
  160. {
  161. /* We deliberately ignore overflow here. */
  162. i = i * 10 + (*s - '0');
  163. ++s;
  164. }
  165. return neg ? -i : i;
  166. }
  167. static int
  168. lex_number(fz_context *ctx, fz_stream *f, pdf_lexbuf *buf, int c)
  169. {
  170. char *s = buf->scratch;
  171. char *e = buf->scratch + buf->size - 1; /* leave space for zero terminator */
  172. char *isreal = (c == '.' ? s : NULL);
  173. int neg = (c == '-');
  174. int isbad = 0;
  175. *s++ = c;
  176. c = lex_byte(ctx, f);
  177. /* skip extra '-' signs at start of number */
  178. if (neg)
  179. {
  180. while (c == '-')
  181. c = lex_byte(ctx, f);
  182. }
  183. while (s < e)
  184. {
  185. switch (c)
  186. {
  187. case IS_WHITE:
  188. case IS_DELIM:
  189. fz_unread_byte(ctx, f);
  190. goto end;
  191. case EOF:
  192. goto end;
  193. case '.':
  194. if (isreal)
  195. isbad = 1;
  196. isreal = s;
  197. *s++ = c;
  198. break;
  199. case '-':
  200. /* Bug 703248: Some PDFs (particularly those
  201. * generated by google docs) apparently have
  202. * numbers like 0.000000000000-5684342 in them.
  203. * We'll stop our interpretation at the -, but
  204. * keep reading to skip over the trailing
  205. * digits so they aren't parsed later. */
  206. *s++ = '\0';
  207. break;
  208. case RANGE_0_9:
  209. *s++ = c;
  210. break;
  211. default:
  212. isbad = 1;
  213. *s++ = c;
  214. break;
  215. }
  216. c = lex_byte(ctx, f);
  217. }
  218. end:
  219. *s = '\0';
  220. if (isbad)
  221. return PDF_TOK_KEYWORD;
  222. if (isreal)
  223. {
  224. /* We'd like to use the fastest possible atof
  225. * routine, but we'd rather match acrobats
  226. * handling of broken numbers. As such, we
  227. * spot common broken cases and call an
  228. * acrobat compatible routine where required. */
  229. if (neg > 1 || isreal - buf->scratch >= 10)
  230. buf->f = acrobat_compatible_atof(buf->scratch);
  231. else
  232. buf->f = fz_atof(buf->scratch);
  233. return PDF_TOK_REAL;
  234. }
  235. else
  236. {
  237. buf->i = fast_atoi(buf->scratch);
  238. return PDF_TOK_INT;
  239. }
  240. }
  241. static void
  242. lex_name(fz_context *ctx, fz_stream *f, pdf_lexbuf *lb)
  243. {
  244. char *s = lb->scratch;
  245. char *e = s + fz_minz(127, lb->size);
  246. int c;
  247. while (1)
  248. {
  249. if (s == e)
  250. {
  251. if (e - lb->scratch < 127)
  252. {
  253. s += pdf_lexbuf_grow(ctx, lb);
  254. e = lb->scratch + fz_minz(127, lb->size);
  255. }
  256. else
  257. {
  258. /* truncate names that are too long */
  259. fz_warn(ctx, "name is too long");
  260. *s = 0;
  261. lb->len = s - lb->scratch;
  262. s = NULL;
  263. }
  264. }
  265. c = lex_byte(ctx, f);
  266. switch (c)
  267. {
  268. case IS_WHITE:
  269. case IS_DELIM:
  270. fz_unread_byte(ctx, f);
  271. goto end;
  272. case EOF:
  273. goto end;
  274. case '#':
  275. {
  276. int hex[2];
  277. int i;
  278. for (i = 0; i < 2; i++)
  279. {
  280. c = fz_peek_byte(ctx, f);
  281. switch (c)
  282. {
  283. case RANGE_0_9:
  284. if (i == 1 && c == '0' && hex[0] == 0)
  285. goto illegal;
  286. hex[i] = lex_byte(ctx, f) - '0';
  287. break;
  288. case RANGE_a_f:
  289. hex[i] = lex_byte(ctx, f) - 'a' + 10;
  290. break;
  291. case RANGE_A_F:
  292. hex[i] = lex_byte(ctx, f) - 'A' + 10;
  293. break;
  294. default:
  295. goto illegal;
  296. case EOF:
  297. goto illegal_eof;
  298. }
  299. }
  300. if (s) *s++ = (hex[0] << 4) + hex[1];
  301. break;
  302. illegal:
  303. if (i == 1)
  304. fz_unread_byte(ctx, f);
  305. illegal_eof:
  306. if (s) *s++ = '#';
  307. continue;
  308. }
  309. default:
  310. if (s) *s++ = c;
  311. break;
  312. }
  313. }
  314. end:
  315. if (s)
  316. {
  317. *s = '\0';
  318. lb->len = s - lb->scratch;
  319. }
  320. }
  321. static int
  322. lex_string(fz_context *ctx, fz_stream *f, pdf_lexbuf *lb)
  323. {
  324. char *s = lb->scratch;
  325. char *e = s + lb->size;
  326. int bal = 1;
  327. int oct;
  328. int c;
  329. while (1)
  330. {
  331. if (s == e)
  332. {
  333. s += pdf_lexbuf_grow(ctx, lb);
  334. e = lb->scratch + lb->size;
  335. }
  336. c = lex_byte(ctx, f);
  337. switch (c)
  338. {
  339. case EOF:
  340. return PDF_TOK_ERROR;
  341. case '(':
  342. bal++;
  343. *s++ = c;
  344. break;
  345. case ')':
  346. bal --;
  347. if (bal == 0)
  348. goto end;
  349. *s++ = c;
  350. break;
  351. case '\\':
  352. c = lex_byte(ctx, f);
  353. switch (c)
  354. {
  355. case EOF:
  356. return PDF_TOK_ERROR;
  357. case 'n':
  358. *s++ = '\n';
  359. break;
  360. case 'r':
  361. *s++ = '\r';
  362. break;
  363. case 't':
  364. *s++ = '\t';
  365. break;
  366. case 'b':
  367. *s++ = '\b';
  368. break;
  369. case 'f':
  370. *s++ = '\f';
  371. break;
  372. case '(':
  373. *s++ = '(';
  374. break;
  375. case ')':
  376. *s++ = ')';
  377. break;
  378. case '\\':
  379. *s++ = '\\';
  380. break;
  381. case RANGE_0_7:
  382. oct = c - '0';
  383. c = lex_byte(ctx, f);
  384. if (c >= '0' && c <= '7')
  385. {
  386. oct = oct * 8 + (c - '0');
  387. c = lex_byte(ctx, f);
  388. if (c >= '0' && c <= '7')
  389. oct = oct * 8 + (c - '0');
  390. else if (c != EOF)
  391. fz_unread_byte(ctx, f);
  392. }
  393. else if (c != EOF)
  394. fz_unread_byte(ctx, f);
  395. *s++ = oct;
  396. break;
  397. case '\n':
  398. break;
  399. case '\r':
  400. c = lex_byte(ctx, f);
  401. if ((c != '\n') && (c != EOF))
  402. fz_unread_byte(ctx, f);
  403. break;
  404. default:
  405. *s++ = c;
  406. }
  407. break;
  408. /* Bug 708256: PDF 32000-1 says that any occurence of \n, \r, or \r\n in a
  409. * (unless escaped with a '\') should be interpreted as a single 0x0a byte. */
  410. case '\n':
  411. *s++ = 0x0a;
  412. break;
  413. case '\r':
  414. *s++ = 0x0a;
  415. c = lex_byte(ctx, f);
  416. if ((c != '\n') && (c != EOF))
  417. fz_unread_byte(ctx, f);
  418. break;
  419. default:
  420. *s++ = c;
  421. break;
  422. }
  423. }
  424. end:
  425. lb->len = s - lb->scratch;
  426. return PDF_TOK_STRING;
  427. }
  428. static int
  429. lex_hex_string(fz_context *ctx, fz_stream *f, pdf_lexbuf *lb)
  430. {
  431. char *s = lb->scratch;
  432. char *e = s + lb->size;
  433. int a = 0, x = 0;
  434. int c;
  435. while (1)
  436. {
  437. if (s == e)
  438. {
  439. s += pdf_lexbuf_grow(ctx, lb);
  440. e = lb->scratch + lb->size;
  441. }
  442. c = lex_byte(ctx, f);
  443. switch (c)
  444. {
  445. case IS_WHITE:
  446. break;
  447. default:
  448. fz_warn(ctx, "invalid character in hex string");
  449. /* fall through */
  450. case IS_HEX:
  451. if (x)
  452. {
  453. *s++ = a * 16 + unhex(c);
  454. x = !x;
  455. }
  456. else
  457. {
  458. a = unhex(c);
  459. x = !x;
  460. }
  461. break;
  462. case '>':
  463. if (x)
  464. {
  465. *s++ = a * 16; /* pad truncated string with '0' */
  466. }
  467. goto end;
  468. case EOF:
  469. return PDF_TOK_ERROR;
  470. }
  471. }
  472. end:
  473. lb->len = s - lb->scratch;
  474. return PDF_TOK_STRING;
  475. }
  476. static pdf_token
  477. pdf_token_from_keyword(char *key)
  478. {
  479. switch (*key)
  480. {
  481. case 'R':
  482. if (!strcmp(key, "R")) return PDF_TOK_R;
  483. break;
  484. case 't':
  485. if (!strcmp(key, "true")) return PDF_TOK_TRUE;
  486. if (!strcmp(key, "trailer")) return PDF_TOK_TRAILER;
  487. break;
  488. case 'f':
  489. if (!strcmp(key, "false")) return PDF_TOK_FALSE;
  490. break;
  491. case 'n':
  492. if (!strcmp(key, "null")) return PDF_TOK_NULL;
  493. if (!strcmp(key, "newobj")) return PDF_TOK_NEWOBJ;
  494. break;
  495. case 'o':
  496. if (!strcmp(key, "obj")) return PDF_TOK_OBJ;
  497. break;
  498. case 'e':
  499. if (!strcmp(key, "endobj")) return PDF_TOK_ENDOBJ;
  500. if (!strcmp(key, "endstream")) return PDF_TOK_ENDSTREAM;
  501. break;
  502. case 's':
  503. if (!strcmp(key, "stream")) return PDF_TOK_STREAM;
  504. if (!strcmp(key, "startxref")) return PDF_TOK_STARTXREF;
  505. break;
  506. case 'x':
  507. if (!strcmp(key, "xref")) return PDF_TOK_XREF;
  508. break;
  509. }
  510. while (*key)
  511. {
  512. if (!fz_isprint(*key))
  513. return PDF_TOK_ERROR;
  514. ++key;
  515. }
  516. return PDF_TOK_KEYWORD;
  517. }
  518. void pdf_lexbuf_init(fz_context *ctx, pdf_lexbuf *lb, int size)
  519. {
  520. lb->size = lb->base_size = size;
  521. lb->len = 0;
  522. lb->scratch = &lb->buffer[0];
  523. }
  524. void pdf_lexbuf_fin(fz_context *ctx, pdf_lexbuf *lb)
  525. {
  526. if (lb && lb->size != lb->base_size)
  527. fz_free(ctx, lb->scratch);
  528. }
  529. ptrdiff_t pdf_lexbuf_grow(fz_context *ctx, pdf_lexbuf *lb)
  530. {
  531. char *old = lb->scratch;
  532. size_t newsize = lb->size * 2;
  533. if (lb->size == lb->base_size)
  534. {
  535. lb->scratch = Memento_label(fz_malloc(ctx, newsize), "pdf_lexbuf");
  536. memcpy(lb->scratch, lb->buffer, lb->size);
  537. }
  538. else
  539. {
  540. lb->scratch = fz_realloc(ctx, lb->scratch, newsize);
  541. }
  542. lb->size = newsize;
  543. return lb->scratch - old;
  544. }
  545. pdf_token
  546. pdf_lex(fz_context *ctx, fz_stream *f, pdf_lexbuf *buf)
  547. {
  548. while (1)
  549. {
  550. int c = lex_byte(ctx, f);
  551. switch (c)
  552. {
  553. case EOF:
  554. return PDF_TOK_EOF;
  555. case IS_WHITE:
  556. lex_white(ctx, f);
  557. break;
  558. case '%':
  559. lex_comment(ctx, f);
  560. break;
  561. case '/':
  562. lex_name(ctx, f, buf);
  563. return PDF_TOK_NAME;
  564. case '(':
  565. return lex_string(ctx, f, buf);
  566. case ')':
  567. return PDF_TOK_ERROR;
  568. case '<':
  569. c = lex_byte(ctx, f);
  570. if (c == '<')
  571. return PDF_TOK_OPEN_DICT;
  572. if (c != EOF)
  573. fz_unread_byte(ctx, f);
  574. return lex_hex_string(ctx, f, buf);
  575. case '>':
  576. c = lex_byte(ctx, f);
  577. if (c == '>')
  578. return PDF_TOK_CLOSE_DICT;
  579. if (c != EOF)
  580. fz_unread_byte(ctx, f);
  581. return PDF_TOK_ERROR;
  582. case '[':
  583. return PDF_TOK_OPEN_ARRAY;
  584. case ']':
  585. return PDF_TOK_CLOSE_ARRAY;
  586. case '{':
  587. return PDF_TOK_OPEN_BRACE;
  588. case '}':
  589. return PDF_TOK_CLOSE_BRACE;
  590. case IS_NUMBER:
  591. return lex_number(ctx, f, buf, c);
  592. default: /* isregular: !isdelim && !iswhite && c != EOF */
  593. fz_unread_byte(ctx, f);
  594. lex_name(ctx, f, buf);
  595. return pdf_token_from_keyword(buf->scratch);
  596. }
  597. }
  598. }
  599. pdf_token
  600. pdf_lex_no_string(fz_context *ctx, fz_stream *f, pdf_lexbuf *buf)
  601. {
  602. while (1)
  603. {
  604. int c = lex_byte(ctx, f);
  605. switch (c)
  606. {
  607. case EOF:
  608. return PDF_TOK_EOF;
  609. case IS_WHITE:
  610. lex_white(ctx, f);
  611. break;
  612. case '%':
  613. lex_comment(ctx, f);
  614. break;
  615. case '/':
  616. lex_name(ctx, f, buf);
  617. return PDF_TOK_NAME;
  618. case '(':
  619. return PDF_TOK_ERROR; /* no strings allowed */
  620. case ')':
  621. return PDF_TOK_ERROR; /* no strings allowed */
  622. case '<':
  623. c = lex_byte(ctx, f);
  624. if (c == '<')
  625. return PDF_TOK_OPEN_DICT;
  626. if (c != EOF)
  627. fz_unread_byte(ctx, f);
  628. return PDF_TOK_ERROR; /* no strings allowed */
  629. case '>':
  630. c = lex_byte(ctx, f);
  631. if (c == '>')
  632. return PDF_TOK_CLOSE_DICT;
  633. if (c != EOF)
  634. fz_unread_byte(ctx, f);
  635. return PDF_TOK_ERROR;
  636. case '[':
  637. return PDF_TOK_OPEN_ARRAY;
  638. case ']':
  639. return PDF_TOK_CLOSE_ARRAY;
  640. case '{':
  641. return PDF_TOK_OPEN_BRACE;
  642. case '}':
  643. return PDF_TOK_CLOSE_BRACE;
  644. case IS_NUMBER:
  645. return lex_number(ctx, f, buf, c);
  646. default: /* isregular: !isdelim && !iswhite && c != EOF */
  647. fz_unread_byte(ctx, f);
  648. lex_name(ctx, f, buf);
  649. return pdf_token_from_keyword(buf->scratch);
  650. }
  651. }
  652. }
  653. void pdf_append_token(fz_context *ctx, fz_buffer *fzbuf, int tok, pdf_lexbuf *buf)
  654. {
  655. switch (tok)
  656. {
  657. case PDF_TOK_NAME:
  658. fz_append_printf(ctx, fzbuf, "/%s", buf->scratch);
  659. break;
  660. case PDF_TOK_STRING:
  661. if (buf->len >= buf->size)
  662. pdf_lexbuf_grow(ctx, buf);
  663. buf->scratch[buf->len] = 0;
  664. fz_append_pdf_string(ctx, fzbuf, buf->scratch);
  665. break;
  666. case PDF_TOK_OPEN_DICT:
  667. fz_append_string(ctx, fzbuf, "<<");
  668. break;
  669. case PDF_TOK_CLOSE_DICT:
  670. fz_append_string(ctx, fzbuf, ">>");
  671. break;
  672. case PDF_TOK_OPEN_ARRAY:
  673. fz_append_byte(ctx, fzbuf, '[');
  674. break;
  675. case PDF_TOK_CLOSE_ARRAY:
  676. fz_append_byte(ctx, fzbuf, ']');
  677. break;
  678. case PDF_TOK_OPEN_BRACE:
  679. fz_append_byte(ctx, fzbuf, '{');
  680. break;
  681. case PDF_TOK_CLOSE_BRACE:
  682. fz_append_byte(ctx, fzbuf, '}');
  683. break;
  684. case PDF_TOK_INT:
  685. fz_append_printf(ctx, fzbuf, "%ld", buf->i);
  686. break;
  687. case PDF_TOK_REAL:
  688. fz_append_printf(ctx, fzbuf, "%g", buf->f);
  689. break;
  690. default:
  691. fz_append_data(ctx, fzbuf, buf->scratch, buf->len);
  692. break;
  693. }
  694. }