tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hb-buffer-serialize.cc (26321B)


      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      if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents))
    173      {
    174 p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
    175 			  extents.x_bearing, extents.y_bearing));
    176 p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
    177 			  extents.width, extents.height));
    178      }
    179    }
    180 
    181    *p++ = '}';
    182    if (i == end-1)
    183      *p++ = ']';
    184 
    185    unsigned int l = p - b;
    186    if (buf_size > l)
    187    {
    188      hb_memcpy (buf, b, l);
    189      buf += l;
    190      buf_size -= l;
    191      *buf_consumed += l;
    192      *buf = '\0';
    193    } else
    194      return i - start;
    195 
    196    if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
    197    {
    198      x += pos[i].x_advance;
    199      y += pos[i].y_advance;
    200    }
    201  }
    202 
    203  return end - start;
    204 }
    205 
    206 static unsigned int
    207 _hb_buffer_serialize_unicode_json (hb_buffer_t *buffer,
    208          unsigned int start,
    209          unsigned int end,
    210          char *buf,
    211          unsigned int buf_size,
    212          unsigned int *buf_consumed,
    213          hb_buffer_serialize_flags_t flags)
    214 {
    215  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
    216 
    217  *buf_consumed = 0;
    218  for (unsigned int i = start; i < end; i++)
    219  {
    220    char b[1024];
    221    char *p = b;
    222 
    223    if (i)
    224      *p++ = ',';
    225    else
    226      *p++ = '[';
    227 
    228    *p++ = '{';
    229 
    230    APPEND ("\"u\":");
    231 
    232    p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
    233 
    234    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
    235      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
    236    }
    237 
    238    *p++ = '}';
    239 
    240    if (i == end-1)
    241      *p++ = ']';
    242 
    243    unsigned int l = p - b;
    244    if (buf_size > l)
    245    {
    246      hb_memcpy (buf, b, l);
    247      buf += l;
    248      buf_size -= l;
    249      *buf_consumed += l;
    250      *buf = '\0';
    251    } else
    252      return i - start;
    253 
    254  }
    255 
    256  return end - start;
    257 }
    258 
    259 static unsigned int
    260 _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
    261                                  unsigned int start,
    262                                  unsigned int end,
    263                                  char *buf,
    264                                  unsigned int buf_size,
    265                                  unsigned int *buf_consumed,
    266                                  hb_font_t *font,
    267                                  hb_buffer_serialize_flags_t flags)
    268 {
    269  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
    270  hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
    271           nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
    272 
    273  *buf_consumed = 0;
    274  hb_position_t x = 0, y = 0;
    275  for (unsigned int i = start; i < end; i++)
    276  {
    277    char b[1024];
    278    char *p = b;
    279 
    280    /* In the following code, we know b is large enough that no overflow can happen. */
    281 
    282    if (i)
    283      *p++ = '|';
    284    else
    285      *p++ = '[';
    286 
    287    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
    288    {
    289      /* TODO Escape delimiters we use. */
    290      hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
    291      p += strlen (p);
    292    }
    293    else
    294      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
    295 
    296    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
    297      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
    298    }
    299 
    300    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
    301    {
    302      if (x+pos[i].x_offset || y+pos[i].y_offset)
    303        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
    304 
    305      if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
    306      {
    307        *p++ = '+';
    308        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
    309        if (pos[i].y_advance)
    310          p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
    311      }
    312    }
    313 
    314    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
    315    {
    316      if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
    317        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
    318    }
    319 
    320    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
    321    {
    322      hb_glyph_extents_t extents;
    323      if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents))
    324 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));
    325    }
    326 
    327    if (i == end-1) {
    328      *p++ = ']';
    329    }
    330 
    331    unsigned int l = p - b;
    332    if (buf_size > l)
    333    {
    334      hb_memcpy (buf, b, l);
    335      buf += l;
    336      buf_size -= l;
    337      *buf_consumed += l;
    338      *buf = '\0';
    339    } else
    340      return i - start;
    341 
    342    if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
    343    {
    344      x += pos[i].x_advance;
    345      y += pos[i].y_advance;
    346    }
    347  }
    348 
    349  return end - start;
    350 }
    351 
    352 
    353 static unsigned int
    354 _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
    355                                   unsigned int start,
    356                                   unsigned int end,
    357                                   char *buf,
    358                                   unsigned int buf_size,
    359                                   unsigned int *buf_consumed,
    360                                   hb_buffer_serialize_flags_t flags)
    361 {
    362  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
    363  *buf_consumed = 0;
    364  for (unsigned int i = start; i < end; i++)
    365  {
    366    char b[1024];
    367    char *p = b;
    368 
    369    if (i)
    370      *p++ = '|';
    371    else
    372      *p++ = '<';
    373 
    374    p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "U+%04X", info[i].codepoint));
    375 
    376    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
    377      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
    378    }
    379 
    380    if (i == end-1)
    381      *p++ = '>';
    382 
    383    unsigned int l = p - b;
    384    if (buf_size > l)
    385    {
    386      hb_memcpy (buf, b, l);
    387      buf += l;
    388      buf_size -= l;
    389      *buf_consumed += l;
    390      *buf = '\0';
    391    } else
    392      return i - start;
    393  }
    394  return end - start;
    395 }
    396 
    397 /**
    398 * hb_buffer_serialize_glyphs:
    399 * @buffer: an #hb_buffer_t buffer.
    400 * @start: the first item in @buffer to serialize.
    401 * @end: the last item in @buffer to serialize.
    402 * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
    403 *       write serialized buffer into.
    404 * @buf_size: the size of @buf.
    405 * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
    406 * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
    407 *        read glyph names and extents. If `NULL`, an empty font will be used.
    408 * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
    409 * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
    410 *         to serialize.
    411 *
    412 * Serializes @buffer into a textual representation of its glyph content,
    413 * useful for showing the contents of the buffer, for example during debugging.
    414 * There are currently two supported serialization formats:
    415 *
    416 * ## text
    417 * A human-readable, plain text format.
    418 * The serialized glyphs will look something like:
    419 *
    420 * ```
    421 * [uni0651=0@518,0+0|uni0628=0+1897]
    422 * ```
    423 *
    424 * - The serialized glyphs are delimited with `[` and `]`.
    425 * - Glyphs are separated with `|`
    426 * - Each glyph starts with glyph name, or glyph index if
    427 *   #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then,
    428 *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster.
    429 *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
    430 *     - If #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not both 0, `@x_offset,y_offset`. Then,
    431 *     - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
    432 *   - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the #hb_glyph_extents_t in the format `<x_bearing,y_bearing,width,height>`
    433 *
    434 * ## json
    435 * A machine-readable, structured format.
    436 * The serialized glyphs will look something like:
    437 *
    438 * ```
    439 * [{"g":"uni0651","cl":0,"dx":518,"dy":0,"ax":0,"ay":0},
    440 * {"g":"uni0628","cl":0,"dx":0,"dy":0,"ax":1897,"ay":0}]
    441 * ```
    442 *
    443 * Each glyph is a JSON object, with the following properties:
    444 * - `g`: the glyph name or glyph index if
    445 *   #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set.
    446 * - `cl`: #hb_glyph_info_t.cluster if
    447 *   #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set.
    448 * - `dx`,`dy`,`ax`,`ay`: #hb_glyph_position_t.x_offset, #hb_glyph_position_t.y_offset,
    449 *    #hb_glyph_position_t.x_advance and #hb_glyph_position_t.y_advance
    450 *    respectively, if #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set.
    451 * - `xb`,`yb`,`w`,`h`: #hb_glyph_extents_t.x_bearing, #hb_glyph_extents_t.y_bearing,
    452 *    #hb_glyph_extents_t.width and #hb_glyph_extents_t.height respectively if
    453 *    #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set.
    454 *
    455 * Return value:
    456 * The number of serialized items.
    457 *
    458 * Since: 0.9.7
    459 **/
    460 unsigned int
    461 hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
    462                            unsigned int start,
    463                            unsigned int end,
    464                            char *buf,
    465                            unsigned int buf_size,
    466                            unsigned int *buf_consumed,
    467                            hb_font_t *font,
    468                            hb_buffer_serialize_format_t format,
    469                            hb_buffer_serialize_flags_t flags)
    470 {
    471  end = hb_clamp (end, start, buffer->len);
    472  start = hb_min (start, end);
    473 
    474  unsigned int sconsumed;
    475  if (!buf_consumed)
    476    buf_consumed = &sconsumed;
    477  *buf_consumed = 0;
    478  if (buf_size)
    479    *buf = '\0';
    480 
    481  buffer->assert_glyphs ();
    482 
    483  if (!buffer->have_positions)
    484    flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
    485 
    486  if (unlikely (start == end))
    487    return 0;
    488 
    489  if (!font)
    490    font = hb_font_get_empty ();
    491 
    492  switch (format)
    493  {
    494    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
    495      return _hb_buffer_serialize_glyphs_text (buffer, start, end,
    496                 buf, buf_size, buf_consumed,
    497                 font, flags);
    498 
    499    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
    500      return _hb_buffer_serialize_glyphs_json (buffer, start, end,
    501                 buf, buf_size, buf_consumed,
    502                 font, flags);
    503 
    504    default:
    505    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
    506      return 0;
    507 
    508  }
    509 }
    510 
    511 /**
    512 * hb_buffer_serialize_unicode:
    513 * @buffer: an #hb_buffer_t buffer.
    514 * @start: the first item in @buffer to serialize.
    515 * @end: the last item in @buffer to serialize.
    516 * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
    517 *       write serialized buffer into.
    518 * @buf_size: the size of @buf.
    519 * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
    520 * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
    521 * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
    522 *         to serialize.
    523 *
    524 * Serializes @buffer into a textual representation of its content,
    525 * when the buffer contains Unicode codepoints (i.e., before shaping). This is
    526 * useful for showing the contents of the buffer, for example during debugging.
    527 * There are currently two supported serialization formats:
    528 *
    529 * ## text
    530 * A human-readable, plain text format.
    531 * The serialized codepoints will look something like:
    532 *
    533 * ```
    534 *  <U+0651=0|U+0628=1>
    535 * ```
    536 *
    537 * - Glyphs are separated with `|`
    538 * - Unicode codepoints are expressed as zero-padded four (or more)
    539 *   digit hexadecimal numbers preceded by `U+`
    540 * - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, the cluster
    541 *   will be indicated with a `=` then #hb_glyph_info_t.cluster.
    542 *
    543 * ## json
    544 * A machine-readable, structured format.
    545 * The serialized codepoints will be a list of objects with the following
    546 * properties:
    547 * - `u`: the Unicode codepoint as a decimal integer
    548 * - `cl`: #hb_glyph_info_t.cluster if
    549 *   #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set.
    550 *
    551 * For example:
    552 *
    553 * ```
    554 * [{u:1617,cl:0},{u:1576,cl:1}]
    555 * ```
    556 *
    557 * Return value:
    558 * The number of serialized items.
    559 *
    560 * Since: 2.7.3
    561 **/
    562 unsigned int
    563 hb_buffer_serialize_unicode (hb_buffer_t *buffer,
    564                             unsigned int start,
    565                             unsigned int end,
    566                             char *buf,
    567                             unsigned int buf_size,
    568                             unsigned int *buf_consumed,
    569                             hb_buffer_serialize_format_t format,
    570                             hb_buffer_serialize_flags_t flags)
    571 {
    572  end = hb_clamp (end, start, buffer->len);
    573  start = hb_min (start, end);
    574 
    575  unsigned int sconsumed;
    576  if (!buf_consumed)
    577    buf_consumed = &sconsumed;
    578  *buf_consumed = 0;
    579  if (buf_size)
    580    *buf = '\0';
    581 
    582  buffer->assert_unicode ();
    583 
    584  if (unlikely (start == end))
    585    return 0;
    586 
    587  switch (format)
    588  {
    589    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
    590      return _hb_buffer_serialize_unicode_text (buffer, start, end,
    591                                                buf, buf_size, buf_consumed, flags);
    592 
    593    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
    594      return _hb_buffer_serialize_unicode_json (buffer, start, end,
    595                                                buf, buf_size, buf_consumed, flags);
    596 
    597    default:
    598    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
    599      return 0;
    600 
    601  }
    602 }
    603 
    604 static unsigned int
    605 _hb_buffer_serialize_invalid (hb_buffer_t *buffer,
    606                              unsigned int start,
    607                              unsigned int end,
    608                              char *buf,
    609                              unsigned int buf_size,
    610                              unsigned int *buf_consumed,
    611                              hb_buffer_serialize_format_t format,
    612                              hb_buffer_serialize_flags_t flags)
    613 {
    614  assert (!buffer->len);
    615 
    616  unsigned int sconsumed;
    617  if (!buf_consumed)
    618    buf_consumed = &sconsumed;
    619  if (buf_size < 3)
    620    return 0;
    621  if (format == HB_BUFFER_SERIALIZE_FORMAT_JSON) {
    622    *buf++ = '[';
    623    *buf++ = ']';
    624    *buf = '\0';
    625  } else if (format == HB_BUFFER_SERIALIZE_FORMAT_TEXT) {
    626    *buf++ = '!';
    627    *buf++ = '!';
    628    *buf = '\0';
    629  }
    630  *buf_consumed = 2;
    631  return 0;
    632 }
    633 
    634 /**
    635 * hb_buffer_serialize:
    636 * @buffer: an #hb_buffer_t buffer.
    637 * @start: the first item in @buffer to serialize.
    638 * @end: the last item in @buffer to serialize.
    639 * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
    640 *       write serialized buffer into.
    641 * @buf_size: the size of @buf.
    642 * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
    643 * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
    644 *        read glyph names and extents. If `NULL`, an empty font will be used.
    645 * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
    646 * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
    647 *         to serialize.
    648 *
    649 * Serializes @buffer into a textual representation of its content, whether
    650 * Unicode codepoints or glyph identifiers and positioning information. This is
    651 * useful for showing the contents of the buffer, for example during debugging.
    652 * See the documentation of hb_buffer_serialize_unicode() and
    653 * hb_buffer_serialize_glyphs() for a description of the output format.
    654 *
    655 * Return value:
    656 * The number of serialized items.
    657 *
    658 * Since: 2.7.3
    659 **/
    660 unsigned int
    661 hb_buffer_serialize (hb_buffer_t *buffer,
    662                     unsigned int start,
    663                     unsigned int end,
    664                     char *buf,
    665                     unsigned int buf_size,
    666                     unsigned int *buf_consumed,
    667                     hb_font_t *font,
    668                     hb_buffer_serialize_format_t format,
    669                     hb_buffer_serialize_flags_t flags)
    670 {
    671  switch (buffer->content_type)
    672  {
    673 
    674    case HB_BUFFER_CONTENT_TYPE_GLYPHS:
    675      return hb_buffer_serialize_glyphs (buffer, start, end, buf, buf_size,
    676 				 buf_consumed, font, format, flags);
    677 
    678    case HB_BUFFER_CONTENT_TYPE_UNICODE:
    679      return hb_buffer_serialize_unicode (buffer, start, end, buf, buf_size,
    680 				  buf_consumed, format, flags);
    681 
    682    case HB_BUFFER_CONTENT_TYPE_INVALID:
    683    default:
    684      return _hb_buffer_serialize_invalid (buffer, start, end, buf, buf_size,
    685 				   buf_consumed, format, flags);
    686  }
    687 }
    688 
    689 static bool
    690 parse_int (const char *pp, const char *end, int32_t *pv)
    691 {
    692  int v;
    693  const char *p = pp;
    694  if (unlikely (!hb_parse_int (&p, end, &v, true/* whole buffer */)))
    695    return false;
    696 
    697  *pv = v;
    698  return true;
    699 }
    700 
    701 static bool
    702 parse_uint (const char *pp, const char *end, uint32_t *pv)
    703 {
    704  unsigned int v;
    705  const char *p = pp;
    706  if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */)))
    707    return false;
    708 
    709  *pv = v;
    710  return true;
    711 }
    712 
    713 static bool
    714 parse_hex (const char *pp, const char *end, uint32_t *pv)
    715 {
    716  unsigned int v;
    717  const char *p = pp;
    718  if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */, 16)))
    719    return false;
    720 
    721  *pv = v;
    722  return true;
    723 }
    724 
    725 #include "hb-buffer-deserialize-json.hh"
    726 #include "hb-buffer-deserialize-text-glyphs.hh"
    727 #include "hb-buffer-deserialize-text-unicode.hh"
    728 
    729 /**
    730 * hb_buffer_deserialize_glyphs:
    731 * @buffer: an #hb_buffer_t buffer.
    732 * @buf: (array length=buf_len): string to deserialize
    733 * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
    734 * @end_ptr: (out) (optional): output pointer to the character after last
    735 *                               consumed one.
    736 * @font: (nullable): font for getting glyph IDs
    737 * @format: the #hb_buffer_serialize_format_t of the input @buf
    738 *
    739 * Deserializes glyphs @buffer from textual representation in the format
    740 * produced by hb_buffer_serialize_glyphs().
    741 *
    742 * Return value: `true` if the full string was parsed, `false` otherwise.
    743 *
    744 * Since: 0.9.7
    745 **/
    746 hb_bool_t
    747 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
    748                              const char *buf,
    749                              int buf_len, /* -1 means nul-terminated */
    750                              const char **end_ptr, /* May be NULL */
    751                              hb_font_t *font, /* May be NULL */
    752                              hb_buffer_serialize_format_t format)
    753 {
    754  const char *end;
    755  if (!end_ptr)
    756    end_ptr = &end;
    757  *end_ptr = buf;
    758 
    759  buffer->assert_glyphs ();
    760 
    761  if (unlikely (hb_object_is_immutable (buffer)))
    762  {
    763    if (end_ptr)
    764      *end_ptr = buf;
    765    return false;
    766  }
    767 
    768  if (buf_len == -1)
    769    buf_len = strlen (buf);
    770 
    771  if (!buf_len)
    772  {
    773    *end_ptr = buf;
    774    return false;
    775  }
    776 
    777  hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
    778 
    779  if (!font)
    780    font = hb_font_get_empty ();
    781 
    782  switch (format)
    783  {
    784    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
    785      return _hb_buffer_deserialize_text_glyphs (buffer,
    786 					 buf, buf_len, end_ptr,
    787 					 font);
    788 
    789    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
    790      return _hb_buffer_deserialize_json (buffer,
    791                                          buf, buf_len, end_ptr,
    792                                          font);
    793 
    794    default:
    795    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
    796      return false;
    797 
    798  }
    799 }
    800 
    801 
    802 /**
    803 * hb_buffer_deserialize_unicode:
    804 * @buffer: an #hb_buffer_t buffer.
    805 * @buf: (array length=buf_len): string to deserialize
    806 * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
    807 * @end_ptr: (out) (optional): output pointer to the character after last
    808 *                               consumed one.
    809 * @format: the #hb_buffer_serialize_format_t of the input @buf
    810 *
    811 * Deserializes Unicode @buffer from textual representation in the format
    812 * produced by hb_buffer_serialize_unicode().
    813 *
    814 * Return value: `true` if the full string was parsed, `false` otherwise.
    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