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
30static 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 **/
46const char **
47hb_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 **/
66hb_buffer_serialize_format_t
67hb_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 **/
85const char *
86hb_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
97static 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
195static 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 **/
327unsigned int
328hb_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
379static hb_bool_t
380parse_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
400static hb_bool_t
401parse_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 **/
439hb_bool_t
440hb_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 nullptr */
444 hb_font_t *font, /* May be nullptr */
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}
487