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