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