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-buffer.hh"
  28 
  29 
  30 static const char *serialize_formats[] = {
  31   "text",
  32   "json",
  33   nullptr
  34 };
  35 
  36 /**
  37  * hb_buffer_serialize_list_formats:
  38  *
  39  * Returns a list of supported buffer serialization formats.
  40  *
  41  * Return value: (transfer none):
  42  * A string array of buffer serialization formats. Should not be freed.
  43  *
  44  * Since: 0.9.7
  45  **/
  46 const char **
  47 hb_buffer_serialize_list_formats ()
  48 {
  49   return serialize_formats;
  50 }
  51 
  52 /**
  53  * hb_buffer_serialize_format_from_string:
  54  * @str: (array length=len) (element-type uint8_t): a string to parse
  55  * @len: length of @str, or -1 if string is %NULL terminated
  56  *
  57  * Parses a string into an #hb_buffer_serialize_format_t. Does not check if
  58  * @str is a valid buffer serialization format, use
  59  * hb_buffer_serialize_list_formats() to get the list of supported formats.
  60  *
  61  * Return value:
  62  * The parsed #hb_buffer_serialize_format_t.
  63  *
  64  * Since: 0.9.7
  65  **/
  66 hb_buffer_serialize_format_t
  67 hb_buffer_serialize_format_from_string (const char *str, int len)
  68 {
  69   /* Upper-case it. */
  70   return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u);
  71 }
  72 
  73 /**
  74  * hb_buffer_serialize_format_to_string:
  75  * @format: an #hb_buffer_serialize_format_t to convert.
  76  *
  77  * Converts @format to the string corresponding it, or %NULL if it is not a valid
  78  * #hb_buffer_serialize_format_t.
  79  *
  80  * Return value: (transfer none):
  81  * A %NULL terminated string corresponding to @format. Should not be freed.
  82  *
  83  * Since: 0.9.7
  84  **/
  85 const char *
  86 hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
  87 {
  88   switch (format)
  89   {
  90     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:       return serialize_formats[0];
  91     case HB_BUFFER_SERIALIZE_FORMAT_JSON:       return serialize_formats[1];
  92     default:
  93     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:    return nullptr;
  94   }
  95 }
  96 
  97 static unsigned int
  98 _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
  99                                   unsigned int start,
 100                                   unsigned int end,
 101                                   char *buf,
 102                                   unsigned int buf_size,
 103                                   unsigned int *buf_consumed,
 104                                   hb_font_t *font,
 105                                   hb_buffer_serialize_flags_t flags)
 106 {
 107   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
 108   hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
 109                              nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
 110 
 111   *buf_consumed = 0;
 112   hb_position_t x = 0, y = 0;
 113   for (unsigned int i = start; i < end; i++)
 114   {
 115     char b[1024];
 116     char *p = b;
 117 
 118     /* In the following code, we know b is large enough that no overflow can happen. */
 119 
 120 #define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END
 121 
 122     if (i)
 123       *p++ = ',';
 124 
 125     *p++ = '{';
 126 
 127     APPEND ("\"g\":");
 128     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
 129     {
 130       char g[128];
 131       hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
 132       *p++ = '"';
 133       for (char *q = g; *q; q++) {
 134         if (*q == '"')
 135           *p++ = '\\';
 136         *p++ = *q;
 137       }
 138       *p++ = '"';
 139     }
 140     else
 141       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
 142 
 143     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
 144       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
 145     }
 146 
 147     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
 148     {
 149       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
 150                              x+pos[i].x_offset, y+pos[i].y_offset));
 151       if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
 152         p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
 153                                pos[i].x_advance, pos[i].y_advance));
 154     }
 155 
 156     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
 157     {
 158       if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
 159         p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
 160     }
 161 
 162     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
 163     {
 164       hb_glyph_extents_t extents;
 165       hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
 166       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
 167                 extents.x_bearing, extents.y_bearing));
 168       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
 169                 extents.width, extents.height));
 170     }
 171 
 172     *p++ = '}';
 173 
 174     unsigned int l = p - b;
 175     if (buf_size > l)
 176     {
 177       memcpy (buf, b, l);
 178       buf += l;
 179       buf_size -= l;
 180       *buf_consumed += l;
 181       *buf = '\0';
 182     } else
 183       return i - start;
 184 
 185     if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
 186     {
 187       x += pos[i].x_advance;
 188       y += pos[i].y_advance;
 189     }
 190   }
 191 
 192   return end - start;
 193 }
 194 
 195 static unsigned int
 196 _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
 197                                   unsigned int start,
 198                                   unsigned int end,
 199                                   char *buf,
 200                                   unsigned int buf_size,
 201                                   unsigned int *buf_consumed,
 202                                   hb_font_t *font,
 203                                   hb_buffer_serialize_flags_t flags)
 204 {
 205   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
 206   hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
 207                              nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
 208 
 209   *buf_consumed = 0;
 210   hb_position_t x = 0, y = 0;
 211   for (unsigned int i = start; i < end; i++)
 212   {
 213     char b[1024];
 214     char *p = b;
 215 
 216     /* In the following code, we know b is large enough that no overflow can happen. */
 217 
 218     if (i)
 219       *p++ = '|';
 220 
 221     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
 222     {
 223       hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
 224       p += strlen (p);
 225     }
 226     else
 227       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
 228 
 229     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
 230       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
 231     }
 232 
 233     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
 234     {
 235       if (x+pos[i].x_offset || y+pos[i].y_offset)
 236         p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
 237 
 238       if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
 239       {
 240         *p++ = '+';
 241         p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
 242         if (pos[i].y_advance)
 243           p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
 244       }
 245     }
 246 
 247     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
 248     {
 249       if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
 250         p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
 251     }
 252 
 253     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
 254     {
 255       hb_glyph_extents_t extents;
 256       hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
 257       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
 258     }
 259 
 260     unsigned int l = p - b;
 261     if (buf_size > l)
 262     {
 263       memcpy (buf, b, l);
 264       buf += l;
 265       buf_size -= l;
 266       *buf_consumed += l;
 267       *buf = '\0';
 268     } else
 269       return i - start;
 270 
 271     if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
 272     {
 273       x += pos[i].x_advance;
 274       y += pos[i].y_advance;
 275     }
 276   }
 277 
 278   return end - start;
 279 }
 280 
 281 /**
 282  * hb_buffer_serialize_glyphs:
 283  * @buffer: an #hb_buffer_t buffer.
 284  * @start: the first item in @buffer to serialize.
 285  * @end: the last item in @buffer to serialize.
 286  * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
 287  *       write serialized buffer into.
 288  * @buf_size: the size of @buf.
 289  * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
 290  * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
 291  *        read glyph names and extents. If %NULL, and empty font will be used.
 292  * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
 293  * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
 294  *         to serialize.
 295  *
 296  * Serializes @buffer into a textual representation of its glyph content,
 297  * useful for showing the contents of the buffer, for example during debugging.
 298  * There are currently two supported serialization formats:
 299  *
 300  * ## text
 301  * A human-readable, plain text format.
 302  * The serialized glyphs will look something like:
 303  *
 304  * ```
 305  * [uni0651=0@518,0+0|uni0628=0+1897]
 306  * ```
 307  * - The serialized glyphs are delimited with `[` and `]`.
 308  * - Glyphs are separated with `|`
 309  * - Each glyph starts with glyph name, or glyph index if
 310  *   #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then,
 311  *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster.
 312  *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
 313  *     - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then,
 314  *     - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
 315  *   - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the
 316  *     #hb_glyph_extents_t in the format
 317  *     `&lt;x_bearing,y_bearing,width,height&gt;`
 318  *
 319  * ## json
 320  * TODO.
 321  *
 322  * Return value:
 323  * The number of serialized items.
 324  *
 325  * Since: 0.9.7
 326  **/
 327 unsigned int
 328 hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
 329                             unsigned int start,
 330                             unsigned int end,
 331                             char *buf,
 332                             unsigned int buf_size,
 333                             unsigned int *buf_consumed,
 334                             hb_font_t *font,
 335                             hb_buffer_serialize_format_t format,
 336                             hb_buffer_serialize_flags_t flags)
 337 {
 338   assert (start <= end && end <= buffer->len);
 339 
 340   unsigned int sconsumed;
 341   if (!buf_consumed)
 342     buf_consumed = &sconsumed;
 343   *buf_consumed = 0;
 344   if (buf_size)
 345     *buf = '\0';
 346 
 347   assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
 348           buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
 349 
 350   if (!buffer->have_positions)
 351     flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
 352 
 353   if (unlikely (start == end))
 354     return 0;
 355 
 356   if (!font)
 357     font = hb_font_get_empty ();
 358 
 359   switch (format)
 360   {
 361     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
 362       return _hb_buffer_serialize_glyphs_text (buffer, start, end,
 363                                                buf, buf_size, buf_consumed,
 364                                                font, flags);
 365 
 366     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
 367       return _hb_buffer_serialize_glyphs_json (buffer, start, end,
 368                                                buf, buf_size, buf_consumed,
 369                                                font, flags);
 370 
 371     default:
 372     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
 373       return 0;
 374 
 375   }
 376 }
 377 
 378 
 379 static hb_bool_t
 380 parse_uint (const char *pp, const char *end, uint32_t *pv)
 381 {
 382   char buf[32];
 383   unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
 384   strncpy (buf, pp, len);
 385   buf[len] = '\0';
 386 
 387   char *p = buf;
 388   char *pend = p;
 389   uint32_t v;
 390 
 391   errno = 0;
 392   v = strtol (p, &pend, 10);
 393   if (errno || p == pend || pend - p != end - pp)
 394     return false;
 395 
 396   *pv = v;
 397   return true;
 398 }
 399 
 400 static hb_bool_t
 401 parse_int (const char *pp, const char *end, int32_t *pv)
 402 {
 403   char buf[32];
 404   unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
 405   strncpy (buf, pp, len);
 406   buf[len] = '\0';
 407 
 408   char *p = buf;
 409   char *pend = p;
 410   int32_t v;
 411 
 412   errno = 0;
 413   v = strtol (p, &pend, 10);
 414   if (errno || p == pend || pend - p != end - pp)
 415     return false;
 416 
 417   *pv = v;
 418   return true;
 419 }
 420 
 421 #include "hb-buffer-deserialize-json.hh"
 422 #include "hb-buffer-deserialize-text.hh"
 423 
 424 /**
 425  * hb_buffer_deserialize_glyphs:
 426  * @buffer: an #hb_buffer_t buffer.
 427  * @buf: (array length=buf_len):
 428  * @buf_len:
 429  * @end_ptr: (out):
 430  * @font:
 431  * @format:
 432  *
 433  *
 434  *
 435  * Return value:
 436  *
 437  * Since: 0.9.7
 438  **/
 439 hb_bool_t
 440 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
 441                               const char *buf,
 442                               int buf_len, /* -1 means nul-terminated */
 443                               const char **end_ptr, /* May be NULL */
 444                               hb_font_t *font, /* May be NULL */
 445                               hb_buffer_serialize_format_t format)
 446 {
 447   const char *end;
 448   if (!end_ptr)
 449     end_ptr = &end;
 450   *end_ptr = buf;
 451 
 452   assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
 453           buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
 454 
 455   if (buf_len == -1)
 456     buf_len = strlen (buf);
 457 
 458   if (!buf_len)
 459   {
 460     *end_ptr = buf;
 461     return false;
 462   }
 463 
 464   hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
 465 
 466   if (!font)
 467     font = hb_font_get_empty ();
 468 
 469   switch (format)
 470   {
 471     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
 472       return _hb_buffer_deserialize_glyphs_text (buffer,
 473                                                  buf, buf_len, end_ptr,
 474                                                  font);
 475 
 476     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
 477       return _hb_buffer_deserialize_glyphs_json (buffer,
 478                                                  buf, buf_len, end_ptr,
 479                                                  font);
 480 
 481     default:
 482     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
 483       return false;
 484 
 485   }
 486 }