Fix build error
[platform/upstream/harfbuzz.git] / src / hb-buffer-serialize.cc
1 /*
2  * Copyright © 2012,2013  Google, Inc.
3  *
4  *  This is part of HarfBuzz, a text shaping library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Google Author(s): Behdad Esfahbod
25  */
26
27 #include "hb.hh"
28
29 #ifndef HB_NO_BUFFER_SERIALIZE
30
31 #include "hb-buffer.hh"
32
33
34 static const char *_hb_buffer_serialize_formats[] = {
35   "text",
36   "json",
37   nullptr
38 };
39
40 /**
41  * hb_buffer_serialize_list_formats:
42  *
43  * Returns a list of supported buffer serialization formats.
44  *
45  * Return value: (transfer none):
46  * A string array of buffer serialization formats. Should not be freed.
47  *
48  * Since: 0.9.7
49  **/
50 const char **
51 hb_buffer_serialize_list_formats ()
52 {
53   return _hb_buffer_serialize_formats;
54 }
55
56 /**
57  * hb_buffer_serialize_format_from_string:
58  * @str: (array length=len) (element-type uint8_t): a string to parse
59  * @len: length of @str, or -1 if string is `NULL` terminated
60  *
61  * Parses a string into an #hb_buffer_serialize_format_t. Does not check if
62  * @str is a valid buffer serialization format, use
63  * hb_buffer_serialize_list_formats() to get the list of supported formats.
64  *
65  * Return value:
66  * The parsed #hb_buffer_serialize_format_t.
67  *
68  * Since: 0.9.7
69  **/
70 hb_buffer_serialize_format_t
71 hb_buffer_serialize_format_from_string (const char *str, int len)
72 {
73   /* Upper-case it. */
74   return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u);
75 }
76
77 /**
78  * hb_buffer_serialize_format_to_string:
79  * @format: an #hb_buffer_serialize_format_t to convert.
80  *
81  * Converts @format to the string corresponding it, or `NULL` if it is not a valid
82  * #hb_buffer_serialize_format_t.
83  *
84  * Return value: (transfer none):
85  * A `NULL` terminated string corresponding to @format. Should not be freed.
86  *
87  * Since: 0.9.7
88  **/
89 const char *
90 hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
91 {
92   switch ((unsigned) format)
93   {
94     case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return _hb_buffer_serialize_formats[0];
95     case HB_BUFFER_SERIALIZE_FORMAT_JSON: return _hb_buffer_serialize_formats[1];
96     default:
97     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:  return nullptr;
98   }
99 }
100
101 static unsigned int
102 _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
103                                   unsigned int start,
104                                   unsigned int end,
105                                   char *buf,
106                                   unsigned int buf_size,
107                                   unsigned int *buf_consumed,
108                                   hb_font_t *font,
109                                   hb_buffer_serialize_flags_t flags)
110 {
111   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
112   hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
113                              nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
114
115   *buf_consumed = 0;
116   hb_position_t x = 0, y = 0;
117   for (unsigned int i = start; i < end; i++)
118   {
119     char b[1024];
120     char *p = b;
121
122     /* In the following code, we know b is large enough that no overflow can happen. */
123
124 #define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END
125
126     if (i)
127       *p++ = ',';
128     else
129       *p++ = '[';
130
131     *p++ = '{';
132
133     APPEND ("\"g\":");
134     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
135     {
136       char g[128];
137       hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
138       *p++ = '"';
139       for (char *q = g; *q; q++)
140       {
141         if (unlikely (*q == '"' || *q == '\\'))
142           *p++ = '\\';
143         *p++ = *q;
144       }
145       *p++ = '"';
146     }
147     else
148       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
149
150     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
151       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
152     }
153
154     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
155     {
156       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
157                    x+pos[i].x_offset, y+pos[i].y_offset));
158       if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
159         p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
160                      pos[i].x_advance, pos[i].y_advance));
161     }
162
163     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
164     {
165       if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
166         p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
167     }
168
169     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
170     {
171       hb_glyph_extents_t extents;
172       hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
173       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
174                                 extents.x_bearing, extents.y_bearing));
175       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
176                                 extents.width, extents.height));
177     }
178
179     *p++ = '}';
180     if (i == end-1)
181       *p++ = ']';
182
183     unsigned int l = p - b;
184     if (buf_size > l)
185     {
186       hb_memcpy (buf, b, l);
187       buf += l;
188       buf_size -= l;
189       *buf_consumed += l;
190       *buf = '\0';
191     } else
192       return i - start;
193
194     if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
195     {
196       x += pos[i].x_advance;
197       y += pos[i].y_advance;
198     }
199   }
200
201   return end - start;
202 }
203
204 static unsigned int
205 _hb_buffer_serialize_unicode_json (hb_buffer_t *buffer,
206           unsigned int start,
207           unsigned int end,
208           char *buf,
209           unsigned int buf_size,
210           unsigned int *buf_consumed,
211           hb_buffer_serialize_flags_t flags)
212 {
213   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
214
215   *buf_consumed = 0;
216   for (unsigned int i = start; i < end; i++)
217   {
218     char b[1024];
219     char *p = b;
220
221     if (i)
222       *p++ = ',';
223     else
224       *p++ = '[';
225
226     *p++ = '{';
227
228     APPEND ("\"u\":");
229
230     p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
231
232     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
233       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
234     }
235
236     *p++ = '}';
237
238     if (i == end-1)
239       *p++ = ']';
240
241     unsigned int l = p - b;
242     if (buf_size > l)
243     {
244       hb_memcpy (buf, b, l);
245       buf += l;
246       buf_size -= l;
247       *buf_consumed += l;
248       *buf = '\0';
249     } else
250       return i - start;
251
252   }
253
254   return end - start;
255 }
256
257 static unsigned int
258 _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
259                                   unsigned int start,
260                                   unsigned int end,
261                                   char *buf,
262                                   unsigned int buf_size,
263                                   unsigned int *buf_consumed,
264                                   hb_font_t *font,
265                                   hb_buffer_serialize_flags_t flags)
266 {
267   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
268   hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
269            nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
270
271   *buf_consumed = 0;
272   hb_position_t x = 0, y = 0;
273   for (unsigned int i = start; i < end; i++)
274   {
275     char b[1024];
276     char *p = b;
277
278     /* In the following code, we know b is large enough that no overflow can happen. */
279
280     if (i)
281       *p++ = '|';
282     else
283       *p++ = '[';
284
285     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
286     {
287       /* TODO Escape delimiters we use. */
288       hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
289       p += strlen (p);
290     }
291     else
292       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
293
294     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
295       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
296     }
297
298     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
299     {
300       if (x+pos[i].x_offset || y+pos[i].y_offset)
301         p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
302
303       if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
304       {
305         *p++ = '+';
306         p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
307         if (pos[i].y_advance)
308           p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
309       }
310     }
311
312     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
313     {
314       if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
315         p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
316     }
317
318     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
319     {
320       hb_glyph_extents_t extents;
321       hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
322       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
323     }
324
325     if (i == end-1) {
326       *p++ = ']';
327     }
328
329     unsigned int l = p - b;
330     if (buf_size > l)
331     {
332       hb_memcpy (buf, b, l);
333       buf += l;
334       buf_size -= l;
335       *buf_consumed += l;
336       *buf = '\0';
337     } else
338       return i - start;
339
340     if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
341     {
342       x += pos[i].x_advance;
343       y += pos[i].y_advance;
344     }
345   }
346
347   return end - start;
348 }
349
350
351 static unsigned int
352 _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
353                                    unsigned int start,
354                                    unsigned int end,
355                                    char *buf,
356                                    unsigned int buf_size,
357                                    unsigned int *buf_consumed,
358                                    hb_buffer_serialize_flags_t flags)
359 {
360   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
361   *buf_consumed = 0;
362   for (unsigned int i = start; i < end; i++)
363   {
364     char b[1024];
365     char *p = b;
366
367     if (i)
368       *p++ = '|';
369     else
370       *p++ = '<';
371
372     p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "U+%04X", info[i].codepoint));
373
374     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
375       p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
376     }
377
378     if (i == end-1)
379       *p++ = '>';
380
381     unsigned int l = p - b;
382     if (buf_size > l)
383     {
384       hb_memcpy (buf, b, l);
385       buf += l;
386       buf_size -= l;
387       *buf_consumed += l;
388       *buf = '\0';
389     } else
390       return i - start;
391   }
392   return end - start;
393 }
394
395 /**
396  * hb_buffer_serialize_glyphs:
397  * @buffer: an #hb_buffer_t buffer.
398  * @start: the first item in @buffer to serialize.
399  * @end: the last item in @buffer to serialize.
400  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
401  *       write serialized buffer into.
402  * @buf_size: the size of @buf.
403  * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
404  * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
405  *        read glyph names and extents. If `NULL`, an empty font will be used.
406  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
407  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
408  *         to serialize.
409  *
410  * Serializes @buffer into a textual representation of its glyph content,
411  * useful for showing the contents of the buffer, for example during debugging.
412  * There are currently two supported serialization formats:
413  *
414  * ## text
415  * A human-readable, plain text format.
416  * The serialized glyphs will look something like:
417  *
418  * ```
419  * [uni0651=0@518,0+0|uni0628=0+1897]
420  * ```
421  *
422  * - The serialized glyphs are delimited with `[` and `]`.
423  * - Glyphs are separated with `|`
424  * - Each glyph starts with glyph name, or glyph index if
425  *   #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then,
426  *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster.
427  *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
428  *     - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then,
429  *     - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
430  *   - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the #hb_glyph_extents_t in the format `<x_bearing,y_bearing,width,height>`
431  *
432  * ## json
433  * A machine-readable, structured format.
434  * The serialized glyphs will look something like:
435  *
436  * ```
437  * [{"g":"uni0651","cl":0,"dx":518,"dy":0,"ax":0,"ay":0},
438  * {"g":"uni0628","cl":0,"dx":0,"dy":0,"ax":1897,"ay":0}]
439  * ```
440  *
441  * Each glyph is a JSON object, with the following properties:
442  * - `g`: the glyph name or glyph index if
443  *   #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set.
444  * - `cl`: #hb_glyph_info_t.cluster if
445  *   #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set.
446  * - `dx`,`dy`,`ax`,`ay`: #hb_glyph_position_t.x_offset, #hb_glyph_position_t.y_offset,
447  *    #hb_glyph_position_t.x_advance and #hb_glyph_position_t.y_advance
448  *    respectively, if #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set.
449  * - `xb`,`yb`,`w`,`h`: #hb_glyph_extents_t.x_bearing, #hb_glyph_extents_t.y_bearing,
450  *    #hb_glyph_extents_t.width and #hb_glyph_extents_t.height respectively if
451  *    #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set.
452  *
453  * Return value:
454  * The number of serialized items.
455  *
456  * Since: 0.9.7
457  **/
458 unsigned int
459 hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
460                             unsigned int start,
461                             unsigned int end,
462                             char *buf,
463                             unsigned int buf_size,
464                             unsigned int *buf_consumed,
465                             hb_font_t *font,
466                             hb_buffer_serialize_format_t format,
467                             hb_buffer_serialize_flags_t flags)
468 {
469   end = hb_clamp (end, start, buffer->len);
470   start = hb_min (start, end);
471
472   unsigned int sconsumed;
473   if (!buf_consumed)
474     buf_consumed = &sconsumed;
475   *buf_consumed = 0;
476   if (buf_size)
477     *buf = '\0';
478
479   buffer->assert_glyphs ();
480
481   if (!buffer->have_positions)
482     flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
483
484   if (unlikely (start == end))
485     return 0;
486
487   if (!font)
488     font = hb_font_get_empty ();
489
490   switch (format)
491   {
492     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
493       return _hb_buffer_serialize_glyphs_text (buffer, start, end,
494                  buf, buf_size, buf_consumed,
495                  font, flags);
496
497     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
498       return _hb_buffer_serialize_glyphs_json (buffer, start, end,
499                  buf, buf_size, buf_consumed,
500                  font, flags);
501
502     default:
503     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
504       return 0;
505
506   }
507 }
508
509 /**
510  * hb_buffer_serialize_unicode:
511  * @buffer: an #hb_buffer_t buffer.
512  * @start: the first item in @buffer to serialize.
513  * @end: the last item in @buffer to serialize.
514  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
515  *       write serialized buffer into.
516  * @buf_size: the size of @buf.
517  * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
518  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
519  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
520  *         to serialize.
521  *
522  * Serializes @buffer into a textual representation of its content,
523  * when the buffer contains Unicode codepoints (i.e., before shaping). This is
524  * useful for showing the contents of the buffer, for example during debugging.
525  * There are currently two supported serialization formats:
526  *
527  * ## text
528  * A human-readable, plain text format.
529  * The serialized codepoints will look something like:
530  *
531  * ```
532  *  <U+0651=0|U+0628=1>
533  * ```
534  *
535  * - Glyphs are separated with `|`
536  * - Unicode codepoints are expressed as zero-padded four (or more)
537  *   digit hexadecimal numbers preceded by `U+`
538  * - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, the cluster
539  *   will be indicated with a `=` then #hb_glyph_info_t.cluster.
540  *
541  * ## json
542  * A machine-readable, structured format.
543  * The serialized codepoints will be a list of objects with the following
544  * properties:
545  * - `u`: the Unicode codepoint as a decimal integer
546  * - `cl`: #hb_glyph_info_t.cluster if
547  *   #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set.
548  *
549  * For example:
550  *
551  * ```
552  * [{u:1617,cl:0},{u:1576,cl:1}]
553  * ```
554  *
555  * Return value:
556  * The number of serialized items.
557  *
558  * Since: 2.7.3
559  **/
560 unsigned int
561 hb_buffer_serialize_unicode (hb_buffer_t *buffer,
562                              unsigned int start,
563                              unsigned int end,
564                              char *buf,
565                              unsigned int buf_size,
566                              unsigned int *buf_consumed,
567                              hb_buffer_serialize_format_t format,
568                              hb_buffer_serialize_flags_t flags)
569 {
570   end = hb_clamp (end, start, buffer->len);
571   start = hb_min (start, end);
572
573   unsigned int sconsumed;
574   if (!buf_consumed)
575     buf_consumed = &sconsumed;
576   *buf_consumed = 0;
577   if (buf_size)
578     *buf = '\0';
579
580   buffer->assert_unicode ();
581
582   if (unlikely (start == end))
583     return 0;
584
585   switch (format)
586   {
587     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
588       return _hb_buffer_serialize_unicode_text (buffer, start, end,
589                                                 buf, buf_size, buf_consumed, flags);
590
591     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
592       return _hb_buffer_serialize_unicode_json (buffer, start, end,
593                                                 buf, buf_size, buf_consumed, flags);
594
595     default:
596     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
597       return 0;
598
599   }
600 }
601
602 static unsigned int
603 _hb_buffer_serialize_invalid (hb_buffer_t *buffer,
604                               unsigned int start,
605                               unsigned int end,
606                               char *buf,
607                               unsigned int buf_size,
608                               unsigned int *buf_consumed,
609                               hb_buffer_serialize_format_t format,
610                               hb_buffer_serialize_flags_t flags)
611 {
612   assert (!buffer->len);
613
614   unsigned int sconsumed;
615   if (!buf_consumed)
616     buf_consumed = &sconsumed;
617   if (buf_size < 3)
618     return 0;
619   if (format == HB_BUFFER_SERIALIZE_FORMAT_JSON) {
620     *buf++ = '[';
621     *buf++ = ']';
622     *buf = '\0';
623   } else if (format == HB_BUFFER_SERIALIZE_FORMAT_TEXT) {
624     *buf++ = '!';
625     *buf++ = '!';
626     *buf = '\0';
627   }
628   *buf_consumed = 2;
629   return 0;
630 }
631
632 /**
633  * hb_buffer_serialize:
634  * @buffer: an #hb_buffer_t buffer.
635  * @start: the first item in @buffer to serialize.
636  * @end: the last item in @buffer to serialize.
637  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
638  *       write serialized buffer into.
639  * @buf_size: the size of @buf.
640  * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
641  * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
642  *        read glyph names and extents. If `NULL`, an empty font will be used.
643  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
644  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
645  *         to serialize.
646  *
647  * Serializes @buffer into a textual representation of its content, whether
648  * Unicode codepoints or glyph identifiers and positioning information. This is
649  * useful for showing the contents of the buffer, for example during debugging.
650  * See the documentation of hb_buffer_serialize_unicode() and
651  * hb_buffer_serialize_glyphs() for a description of the output format.
652  *
653  * Return value:
654  * The number of serialized items.
655  *
656  * Since: 2.7.3
657  **/
658 unsigned int
659 hb_buffer_serialize (hb_buffer_t *buffer,
660                      unsigned int start,
661                      unsigned int end,
662                      char *buf,
663                      unsigned int buf_size,
664                      unsigned int *buf_consumed,
665                      hb_font_t *font,
666                      hb_buffer_serialize_format_t format,
667                      hb_buffer_serialize_flags_t flags)
668 {
669   switch (buffer->content_type)
670   {
671
672     case HB_BUFFER_CONTENT_TYPE_GLYPHS:
673       return hb_buffer_serialize_glyphs (buffer, start, end, buf, buf_size,
674                                          buf_consumed, font, format, flags);
675
676     case HB_BUFFER_CONTENT_TYPE_UNICODE:
677       return hb_buffer_serialize_unicode (buffer, start, end, buf, buf_size,
678                                           buf_consumed, format, flags);
679
680     case HB_BUFFER_CONTENT_TYPE_INVALID:
681     default:
682       return _hb_buffer_serialize_invalid (buffer, start, end, buf, buf_size,
683                                            buf_consumed, format, flags);
684   }
685 }
686
687 static bool
688 parse_int (const char *pp, const char *end, int32_t *pv)
689 {
690   int v;
691   const char *p = pp;
692   if (unlikely (!hb_parse_int (&p, end, &v, true/* whole buffer */)))
693     return false;
694
695   *pv = v;
696   return true;
697 }
698
699 static bool
700 parse_uint (const char *pp, const char *end, uint32_t *pv)
701 {
702   unsigned int v;
703   const char *p = pp;
704   if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */)))
705     return false;
706
707   *pv = v;
708   return true;
709 }
710
711 static bool
712 parse_hex (const char *pp, const char *end, uint32_t *pv)
713 {
714   unsigned int v;
715   const char *p = pp;
716   if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */, 16)))
717     return false;
718
719   *pv = v;
720   return true;
721 }
722
723 #include "hb-buffer-deserialize-json.hh"
724 #include "hb-buffer-deserialize-text-glyphs.hh"
725 #include "hb-buffer-deserialize-text-unicode.hh"
726
727 /**
728  * hb_buffer_deserialize_glyphs:
729  * @buffer: an #hb_buffer_t buffer.
730  * @buf: (array length=buf_len): string to deserialize
731  * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
732  * @end_ptr: (out) (optional): output pointer to the character after last
733  *                               consumed one.
734  * @font: (nullable): font for getting glyph IDs
735  * @format: the #hb_buffer_serialize_format_t of the input @buf
736  *
737  * Deserializes glyphs @buffer from textual representation in the format
738  * produced by hb_buffer_serialize_glyphs().
739  *
740  * Return value: `true` if parse was successful, `false` if an error
741  * occurred.
742  *
743  * Since: 0.9.7
744  **/
745 hb_bool_t
746 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
747                               const char *buf,
748                               int buf_len, /* -1 means nul-terminated */
749                               const char **end_ptr, /* May be NULL */
750                               hb_font_t *font, /* May be NULL */
751                               hb_buffer_serialize_format_t format)
752 {
753   const char *end;
754   if (!end_ptr)
755     end_ptr = &end;
756   *end_ptr = buf;
757
758   buffer->assert_glyphs ();
759
760   if (unlikely (hb_object_is_immutable (buffer)))
761   {
762     if (end_ptr)
763       *end_ptr = buf;
764     return false;
765   }
766
767   if (buf_len == -1)
768     buf_len = strlen (buf);
769
770   if (!buf_len)
771   {
772     *end_ptr = buf;
773     return false;
774   }
775
776   hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
777
778   if (!font)
779     font = hb_font_get_empty ();
780
781   switch (format)
782   {
783     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
784       return _hb_buffer_deserialize_text_glyphs (buffer,
785                                                  buf, buf_len, end_ptr,
786                                                  font);
787
788     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
789       return _hb_buffer_deserialize_json (buffer,
790                                           buf, buf_len, end_ptr,
791                                           font);
792
793     default:
794     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
795       return false;
796
797   }
798 }
799
800
801 /**
802  * hb_buffer_deserialize_unicode:
803  * @buffer: an #hb_buffer_t buffer.
804  * @buf: (array length=buf_len): string to deserialize
805  * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
806  * @end_ptr: (out) (optional): output pointer to the character after last
807  *                               consumed one.
808  * @format: the #hb_buffer_serialize_format_t of the input @buf
809  *
810  * Deserializes Unicode @buffer from textual representation in the format
811  * produced by hb_buffer_serialize_unicode().
812  *
813  * Return value: `true` if parse was successful, `false` if an error
814  * occurred.
815  *
816  * Since: 2.7.3
817  **/
818 hb_bool_t
819 hb_buffer_deserialize_unicode (hb_buffer_t *buffer,
820                                const char *buf,
821                                int buf_len, /* -1 means nul-terminated */
822                                const char **end_ptr, /* May be NULL */
823                                hb_buffer_serialize_format_t format)
824 {
825   const char *end;
826   if (!end_ptr)
827     end_ptr = &end;
828   *end_ptr = buf;
829
830   buffer->assert_unicode ();
831
832   if (unlikely (hb_object_is_immutable (buffer)))
833   {
834     if (end_ptr)
835       *end_ptr = buf;
836     return false;
837   }
838
839   if (buf_len == -1)
840     buf_len = strlen (buf);
841
842   if (!buf_len)
843   {
844     *end_ptr = buf;
845     return false;
846   }
847
848   hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
849
850   hb_font_t* font = hb_font_get_empty ();
851
852   switch (format)
853   {
854     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
855       return _hb_buffer_deserialize_text_unicode (buffer,
856                                                   buf, buf_len, end_ptr,
857                                                   font);
858
859     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
860       return _hb_buffer_deserialize_json (buffer,
861                                           buf, buf_len, end_ptr,
862                                           font);
863
864     default:
865     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
866       return false;
867
868   }
869 }
870
871
872 #endif