Home | History | Annotate | Download | only in src
      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-private.hh"
     28 
     29 
     30 static const char *serialize_formats[] = {
     31   "text",
     32   "json",
     33   NULL
     34 };
     35 
     36 const char **
     37 hb_buffer_serialize_list_formats (void)
     38 {
     39   return serialize_formats;
     40 }
     41 
     42 hb_buffer_serialize_format_t
     43 hb_buffer_serialize_format_from_string (const char *str, int len)
     44 {
     45   /* Upper-case it. */
     46   return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020);
     47 }
     48 
     49 const char *
     50 hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
     51 {
     52   switch (format)
     53   {
     54     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:	return serialize_formats[0];
     55     case HB_BUFFER_SERIALIZE_FORMAT_JSON:	return serialize_formats[1];
     56     default:
     57     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:	return NULL;
     58   }
     59 }
     60 
     61 static unsigned int
     62 _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
     63 				  unsigned int start,
     64 				  unsigned int end,
     65 				  char *buf,
     66 				  unsigned int buf_size,
     67 				  unsigned int *buf_consumed,
     68 				  hb_font_t *font,
     69 				  hb_buffer_serialize_flags_t flags)
     70 {
     71   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
     72   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
     73 
     74   *buf_consumed = 0;
     75   for (unsigned int i = start; i < end; i++)
     76   {
     77     char b[1024];
     78     char *p = b;
     79 
     80     /* In the following code, we know b is large enough that no overflow can happen. */
     81 
     82 #define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END
     83 
     84     if (i)
     85       *p++ = ',';
     86 
     87     *p++ = '{';
     88 
     89     APPEND ("\"g\":");
     90     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
     91     {
     92       char g[128];
     93       hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
     94       *p++ = '"';
     95       for (char *q = g; *q; q++) {
     96         if (*q == '"')
     97 	  *p++ = '\\';
     98 	*p++ = *q;
     99       }
    100       *p++ = '"';
    101     }
    102     else
    103       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint);
    104 
    105     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
    106       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster);
    107     }
    108 
    109     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
    110     {
    111       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
    112 		     pos[i].x_offset, pos[i].y_offset);
    113       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
    114 		     pos[i].x_advance, pos[i].y_advance);
    115     }
    116 
    117     *p++ = '}';
    118 
    119     if (buf_size > (p - b))
    120     {
    121       unsigned int l = p - b;
    122       memcpy (buf, b, l);
    123       buf += l;
    124       buf_size -= l;
    125       *buf_consumed += l;
    126       *buf = '\0';
    127     } else
    128       return i - start;
    129   }
    130 
    131   return end - start;
    132 }
    133 
    134 static unsigned int
    135 _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
    136 				  unsigned int start,
    137 				  unsigned int end,
    138 				  char *buf,
    139 				  unsigned int buf_size,
    140 				  unsigned int *buf_consumed,
    141 				  hb_font_t *font,
    142 				  hb_buffer_serialize_flags_t flags)
    143 {
    144   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
    145   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
    146 
    147   *buf_consumed = 0;
    148   for (unsigned int i = start; i < end; i++)
    149   {
    150     char b[1024];
    151     char *p = b;
    152 
    153     /* In the following code, we know b is large enough that no overflow can happen. */
    154 
    155     if (i)
    156       *p++ = '|';
    157 
    158     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
    159     {
    160       hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
    161       p += strlen (p);
    162     }
    163     else
    164       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint);
    165 
    166     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
    167       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster);
    168     }
    169 
    170     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
    171     {
    172       if (pos[i].x_offset || pos[i].y_offset)
    173 	p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset);
    174 
    175       *p++ = '+';
    176       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance);
    177       if (pos->y_advance)
    178 	p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance);
    179     }
    180 
    181     if (buf_size > (p - b))
    182     {
    183       unsigned int l = p - b;
    184       memcpy (buf, b, l);
    185       buf += l;
    186       buf_size -= l;
    187       *buf_consumed += l;
    188       *buf = '\0';
    189     } else
    190       return i - start;
    191   }
    192 
    193   return end - start;
    194 }
    195 
    196 /* Returns number of items, starting at start, that were serialized. */
    197 unsigned int
    198 hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
    199 			    unsigned int start,
    200 			    unsigned int end,
    201 			    char *buf,
    202 			    unsigned int buf_size,
    203 			    unsigned int *buf_consumed, /* May be NULL */
    204 			    hb_font_t *font, /* May be NULL */
    205 			    hb_buffer_serialize_format_t format,
    206 			    hb_buffer_serialize_flags_t flags)
    207 {
    208   assert (start <= end && end <= buffer->len);
    209 
    210   unsigned int sconsumed;
    211   if (!buf_consumed)
    212     buf_consumed = &sconsumed;
    213   *buf_consumed = 0;
    214 
    215   assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
    216 	  buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
    217 
    218   if (unlikely (start == end))
    219     return 0;
    220 
    221   if (!font)
    222     font = hb_font_get_empty ();
    223 
    224   switch (format)
    225   {
    226     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
    227       return _hb_buffer_serialize_glyphs_text (buffer, start, end,
    228 					       buf, buf_size, buf_consumed,
    229 					       font, flags);
    230 
    231     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
    232       return _hb_buffer_serialize_glyphs_json (buffer, start, end,
    233 					       buf, buf_size, buf_consumed,
    234 					       font, flags);
    235 
    236     default:
    237     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
    238       return 0;
    239 
    240   }
    241 }
    242 
    243 
    244 static hb_bool_t
    245 parse_uint (const char *pp, const char *end, uint32_t *pv)
    246 {
    247   char buf[32];
    248   unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
    249   strncpy (buf, pp, len);
    250   buf[len] = '\0';
    251 
    252   char *p = buf;
    253   char *pend = p;
    254   uint32_t v;
    255 
    256   errno = 0;
    257   v = strtol (p, &pend, 10);
    258   if (errno || p == pend || pend - p != end - pp)
    259     return false;
    260 
    261   *pv = v;
    262   return true;
    263 }
    264 
    265 static hb_bool_t
    266 parse_int (const char *pp, const char *end, int32_t *pv)
    267 {
    268   char buf[32];
    269   unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
    270   strncpy (buf, pp, len);
    271   buf[len] = '\0';
    272 
    273   char *p = buf;
    274   char *pend = p;
    275   int32_t v;
    276 
    277   errno = 0;
    278   v = strtol (p, &pend, 10);
    279   if (errno || p == pend || pend - p != end - pp)
    280     return false;
    281 
    282   *pv = v;
    283   return true;
    284 }
    285 
    286 #include "hb-buffer-deserialize-json.hh"
    287 #include "hb-buffer-deserialize-text.hh"
    288 
    289 hb_bool_t
    290 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
    291 			      const char *buf,
    292 			      int buf_len, /* -1 means nul-terminated */
    293 			      const char **end_ptr, /* May be NULL */
    294 			      hb_font_t *font, /* May be NULL */
    295 			      hb_buffer_serialize_format_t format)
    296 {
    297   const char *end;
    298   if (!end_ptr)
    299     end_ptr = &end;
    300   *end_ptr = buf;
    301 
    302   assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
    303 	  buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
    304 
    305   if (buf_len == -1)
    306     buf_len = strlen (buf);
    307 
    308   if (!buf_len)
    309   {
    310     *end_ptr = buf;
    311     return false;
    312   }
    313 
    314   hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
    315 
    316   if (!font)
    317     font = hb_font_get_empty ();
    318 
    319   switch (format)
    320   {
    321     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
    322       return _hb_buffer_deserialize_glyphs_text (buffer,
    323 						 buf, buf_len, end_ptr,
    324 						 font);
    325 
    326     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
    327       return _hb_buffer_deserialize_glyphs_json (buffer,
    328 						 buf, buf_len, end_ptr,
    329 						 font);
    330 
    331     default:
    332     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
    333       return false;
    334 
    335   }
    336 }
    337