Coverage Report

Created: 2024-08-27 12:17

/src/harfbuzz/src/hb-buffer-serialize.cc
Line
Count
Source (jump to first uncovered line)
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.hh"
28
29
#ifndef HB_NO_BUFFER_SERIALIZE
30
31
#include "hb-buffer.hh"
32
33
34
static const char *_hb_buffer_serialize_formats[] = {
35
  "text",
36
  "json",
37
  nullptr
38
};
39
40
/**
41
 * hb_buffer_serialize_list_formats:
42
 *
43
 * Returns a list of supported buffer serialization formats.
44
 *
45
 * Return value: (transfer none):
46
 * A string array of buffer serialization formats. Should not be freed.
47
 *
48
 * Since: 0.9.7
49
 **/
50
const char **
51
hb_buffer_serialize_list_formats ()
52
0
{
53
0
  return _hb_buffer_serialize_formats;
54
0
}
55
56
/**
57
 * hb_buffer_serialize_format_from_string:
58
 * @str: (array length=len) (element-type uint8_t): a string to parse
59
 * @len: length of @str, or -1 if string is `NULL` terminated
60
 *
61
 * Parses a string into an #hb_buffer_serialize_format_t. Does not check if
62
 * @str is a valid buffer serialization format, use
63
 * hb_buffer_serialize_list_formats() to get the list of supported formats.
64
 *
65
 * Return value:
66
 * The parsed #hb_buffer_serialize_format_t.
67
 *
68
 * Since: 0.9.7
69
 **/
70
hb_buffer_serialize_format_t
71
hb_buffer_serialize_format_from_string (const char *str, int len)
72
0
{
73
  /* Upper-case it. */
74
0
  return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u);
75
0
}
76
77
/**
78
 * hb_buffer_serialize_format_to_string:
79
 * @format: an #hb_buffer_serialize_format_t to convert.
80
 *
81
 * Converts @format to the string corresponding it, or `NULL` if it is not a valid
82
 * #hb_buffer_serialize_format_t.
83
 *
84
 * Return value: (transfer none):
85
 * A `NULL` terminated string corresponding to @format. Should not be freed.
86
 *
87
 * Since: 0.9.7
88
 **/
89
const char *
90
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
91
0
{
92
0
  switch ((unsigned) format)
93
0
  {
94
0
    case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return _hb_buffer_serialize_formats[0];
95
0
    case HB_BUFFER_SERIALIZE_FORMAT_JSON: return _hb_buffer_serialize_formats[1];
96
0
    default:
97
0
    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:  return nullptr;
98
0
  }
99
0
}
100
101
static unsigned int
102
_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
103
                                  unsigned int start,
104
                                  unsigned int end,
105
                                  char *buf,
106
                                  unsigned int buf_size,
107
                                  unsigned int *buf_consumed,
108
                                  hb_font_t *font,
109
                                  hb_buffer_serialize_flags_t flags)
110
0
{
111
0
  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
112
0
  hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
113
0
                             nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
114
115
0
  *buf_consumed = 0;
116
0
  hb_position_t x = 0, y = 0;
117
0
  for (unsigned int i = start; i < end; i++)
118
0
  {
119
0
    char b[1024];
120
0
    char *p = b;
121
122
    /* In the following code, we know b is large enough that no overflow can happen. */
123
124
0
#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END
125
126
0
    if (i)
127
0
      *p++ = ',';
128
0
    else
129
0
      *p++ = '[';
130
131
0
    *p++ = '{';
132
133
0
    APPEND ("\"g\":");
134
0
    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
135
0
    {
136
0
      char g[128];
137
0
      hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
138
0
      *p++ = '"';
139
0
      for (char *q = g; *q; q++)
140
0
      {
141
0
  if (unlikely (*q == '"' || *q == '\\'))
142
0
    *p++ = '\\';
143
0
  *p++ = *q;
144
0
      }
145
0
      *p++ = '"';
146
0
    }
147
0
    else
148
0
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
149
150
0
    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
151
0
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
152
0
    }
153
154
0
    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
155
0
    {
156
0
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
157
0
       x+pos[i].x_offset, y+pos[i].y_offset));
158
0
      if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
159
0
        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
160
0
         pos[i].x_advance, pos[i].y_advance));
161
0
    }
162
163
0
    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
164
0
    {
165
0
      if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
166
0
        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
167
0
    }
168
169
0
    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
170
0
    {
171
0
      hb_glyph_extents_t extents;
172
0
      hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
173
0
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
174
0
                                extents.x_bearing, extents.y_bearing));
175
0
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
176
0
                                extents.width, extents.height));
177
0
    }
178
179
0
    *p++ = '}';
180
0
    if (i == end-1)
181
0
      *p++ = ']';
182
183
0
    unsigned int l = p - b;
184
0
    if (buf_size > l)
185
0
    {
186
0
      hb_memcpy (buf, b, l);
187
0
      buf += l;
188
0
      buf_size -= l;
189
0
      *buf_consumed += l;
190
0
      *buf = '\0';
191
0
    } else
192
0
      return i - start;
193
194
0
    if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
195
0
    {
196
0
      x += pos[i].x_advance;
197
0
      y += pos[i].y_advance;
198
0
    }
199
0
  }
200
201
0
  return end - start;
202
0
}
203
204
static unsigned int
205
_hb_buffer_serialize_unicode_json (hb_buffer_t *buffer,
206
          unsigned int start,
207
          unsigned int end,
208
          char *buf,
209
          unsigned int buf_size,
210
          unsigned int *buf_consumed,
211
          hb_buffer_serialize_flags_t flags)
212
0
{
213
0
  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
214
215
0
  *buf_consumed = 0;
216
0
  for (unsigned int i = start; i < end; i++)
217
0
  {
218
0
    char b[1024];
219
0
    char *p = b;
220
221
0
    if (i)
222
0
      *p++ = ',';
223
0
    else
224
0
      *p++ = '[';
225
226
0
    *p++ = '{';
227
228
0
    APPEND ("\"u\":");
229
230
0
    p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
231
232
0
    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
233
0
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
234
0
    }
235
236
0
    *p++ = '}';
237
238
0
    if (i == end-1)
239
0
      *p++ = ']';
240
241
0
    unsigned int l = p - b;
242
0
    if (buf_size > l)
243
0
    {
244
0
      hb_memcpy (buf, b, l);
245
0
      buf += l;
246
0
      buf_size -= l;
247
0
      *buf_consumed += l;
248
0
      *buf = '\0';
249
0
    } else
250
0
      return i - start;
251
252
0
  }
253
254
0
  return end - start;
255
0
}
256
257
static unsigned int
258
_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
259
                                  unsigned int start,
260
                                  unsigned int end,
261
                                  char *buf,
262
                                  unsigned int buf_size,
263
                                  unsigned int *buf_consumed,
264
                                  hb_font_t *font,
265
                                  hb_buffer_serialize_flags_t flags)
266
0
{
267
0
  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
268
0
  hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
269
0
           nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
270
271
0
  *buf_consumed = 0;
272
0
  hb_position_t x = 0, y = 0;
273
0
  for (unsigned int i = start; i < end; i++)
274
0
  {
275
0
    char b[1024];
276
0
    char *p = b;
277
278
    /* In the following code, we know b is large enough that no overflow can happen. */
279
280
0
    if (i)
281
0
      *p++ = '|';
282
0
    else
283
0
      *p++ = '[';
284
285
0
    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
286
0
    {
287
      /* TODO Escape delimiters we use. */
288
0
      hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
289
0
      p += strlen (p);
290
0
    }
291
0
    else
292
0
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
293
294
0
    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
295
0
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
296
0
    }
297
298
0
    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
299
0
    {
300
0
      if (x+pos[i].x_offset || y+pos[i].y_offset)
301
0
        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
302
303
0
      if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
304
0
      {
305
0
        *p++ = '+';
306
0
        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
307
0
        if (pos[i].y_advance)
308
0
          p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
309
0
      }
310
0
    }
311
312
0
    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
313
0
    {
314
0
      if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
315
0
        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
316
0
    }
317
318
0
    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
319
0
    {
320
0
      hb_glyph_extents_t extents;
321
0
      hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
322
0
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
323
0
    }
324
325
0
    if (i == end-1) {
326
0
      *p++ = ']';
327
0
    }
328
329
0
    unsigned int l = p - b;
330
0
    if (buf_size > l)
331
0
    {
332
0
      hb_memcpy (buf, b, l);
333
0
      buf += l;
334
0
      buf_size -= l;
335
0
      *buf_consumed += l;
336
0
      *buf = '\0';
337
0
    } else
338
0
      return i - start;
339
340
0
    if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
341
0
    {
342
0
      x += pos[i].x_advance;
343
0
      y += pos[i].y_advance;
344
0
    }
345
0
  }
346
347
0
  return end - start;
348
0
}
349
350
351
static unsigned int
352
_hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
353
                                   unsigned int start,
354
                                   unsigned int end,
355
                                   char *buf,
356
                                   unsigned int buf_size,
357
                                   unsigned int *buf_consumed,
358
                                   hb_buffer_serialize_flags_t flags)
359
6.26k
{
360
6.26k
  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
361
6.26k
  *buf_consumed = 0;
362
125k
  for (unsigned int i = start; i < end; i++)
363
119k
  {
364
119k
    char b[1024];
365
119k
    char *p = b;
366
367
119k
    if (i)
368
112k
      *p++ = '|';
369
6.26k
    else
370
6.26k
      *p++ = '<';
371
372
119k
    p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "U+%04X", info[i].codepoint));
373
374
119k
    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
375
0
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
376
0
    }
377
378
119k
    if (i == end-1)
379
6.26k
      *p++ = '>';
380
381
119k
    unsigned int l = p - b;
382
119k
    if (buf_size > l)
383
119k
    {
384
119k
      hb_memcpy (buf, b, l);
385
119k
      buf += l;
386
119k
      buf_size -= l;
387
119k
      *buf_consumed += l;
388
119k
      *buf = '\0';
389
119k
    } else
390
0
      return i - start;
391
119k
  }
392
6.26k
  return end - start;
393
6.26k
}
394
395
/**
396
 * hb_buffer_serialize_glyphs:
397
 * @buffer: an #hb_buffer_t buffer.
398
 * @start: the first item in @buffer to serialize.
399
 * @end: the last item in @buffer to serialize.
400
 * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
401
 *       write serialized buffer into.
402
 * @buf_size: the size of @buf.
403
 * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
404
 * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
405
 *        read glyph names and extents. If `NULL`, an empty font will be used.
406
 * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
407
 * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
408
 *         to serialize.
409
 *
410
 * Serializes @buffer into a textual representation of its glyph content,
411
 * useful for showing the contents of the buffer, for example during debugging.
412
 * There are currently two supported serialization formats:
413
 *
414
 * ## text
415
 * A human-readable, plain text format.
416
 * The serialized glyphs will look something like:
417
 *
418
 * ```
419
 * [uni0651=0@518,0+0|uni0628=0+1897]
420
 * ```
421
 *
422
 * - The serialized glyphs are delimited with `[` and `]`.
423
 * - Glyphs are separated with `|`
424
 * - Each glyph starts with glyph name, or glyph index if
425
 *   #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then,
426
 *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster.
427
 *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
428
 *     - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then,
429
 *     - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
430
 *   - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the #hb_glyph_extents_t in the format `<x_bearing,y_bearing,width,height>`
431
 *
432
 * ## json
433
 * A machine-readable, structured format.
434
 * The serialized glyphs will look something like:
435
 *
436
 * ```
437
 * [{"g":"uni0651","cl":0,"dx":518,"dy":0,"ax":0,"ay":0},
438
 * {"g":"uni0628","cl":0,"dx":0,"dy":0,"ax":1897,"ay":0}]
439
 * ```
440
 *
441
 * Each glyph is a JSON object, with the following properties:
442
 * - `g`: the glyph name or glyph index if
443
 *   #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set.
444
 * - `cl`: #hb_glyph_info_t.cluster if
445
 *   #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set.
446
 * - `dx`,`dy`,`ax`,`ay`: #hb_glyph_position_t.x_offset, #hb_glyph_position_t.y_offset,
447
 *    #hb_glyph_position_t.x_advance and #hb_glyph_position_t.y_advance
448
 *    respectively, if #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set.
449
 * - `xb`,`yb`,`w`,`h`: #hb_glyph_extents_t.x_bearing, #hb_glyph_extents_t.y_bearing,
450
 *    #hb_glyph_extents_t.width and #hb_glyph_extents_t.height respectively if
451
 *    #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set.
452
 *
453
 * Return value:
454
 * The number of serialized items.
455
 *
456
 * Since: 0.9.7
457
 **/
458
unsigned int
459
hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
460
                            unsigned int start,
461
                            unsigned int end,
462
                            char *buf,
463
                            unsigned int buf_size,
464
                            unsigned int *buf_consumed,
465
                            hb_font_t *font,
466
                            hb_buffer_serialize_format_t format,
467
                            hb_buffer_serialize_flags_t flags)
468
0
{
469
0
  end = hb_clamp (end, start, buffer->len);
470
0
  start = hb_min (start, end);
471
472
0
  unsigned int sconsumed;
473
0
  if (!buf_consumed)
474
0
    buf_consumed = &sconsumed;
475
0
  *buf_consumed = 0;
476
0
  if (buf_size)
477
0
    *buf = '\0';
478
479
0
  buffer->assert_glyphs ();
480
481
0
  if (!buffer->have_positions)
482
0
    flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
483
484
0
  if (unlikely (start == end))
485
0
    return 0;
486
487
0
  if (!font)
488
0
    font = hb_font_get_empty ();
489
490
0
  switch (format)
491
0
  {
492
0
    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
493
0
      return _hb_buffer_serialize_glyphs_text (buffer, start, end,
494
0
                 buf, buf_size, buf_consumed,
495
0
                 font, flags);
496
497
0
    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
498
0
      return _hb_buffer_serialize_glyphs_json (buffer, start, end,
499
0
                 buf, buf_size, buf_consumed,
500
0
                 font, flags);
501
502
0
    default:
503
0
    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
504
0
      return 0;
505
506
0
  }
507
0
}
508
509
/**
510
 * hb_buffer_serialize_unicode:
511
 * @buffer: an #hb_buffer_t buffer.
512
 * @start: the first item in @buffer to serialize.
513
 * @end: the last item in @buffer to serialize.
514
 * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
515
 *       write serialized buffer into.
516
 * @buf_size: the size of @buf.
517
 * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
518
 * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
519
 * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
520
 *         to serialize.
521
 *
522
 * Serializes @buffer into a textual representation of its content,
523
 * when the buffer contains Unicode codepoints (i.e., before shaping). This is
524
 * useful for showing the contents of the buffer, for example during debugging.
525
 * There are currently two supported serialization formats:
526
 *
527
 * ## text
528
 * A human-readable, plain text format.
529
 * The serialized codepoints will look something like:
530
 *
531
 * ```
532
 *  <U+0651=0|U+0628=1>
533
 * ```
534
 *
535
 * - Glyphs are separated with `|`
536
 * - Unicode codepoints are expressed as zero-padded four (or more)
537
 *   digit hexadecimal numbers preceded by `U+`
538
 * - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, the cluster
539
 *   will be indicated with a `=` then #hb_glyph_info_t.cluster.
540
 *
541
 * ## json
542
 * A machine-readable, structured format.
543
 * The serialized codepoints will be a list of objects with the following
544
 * properties:
545
 * - `u`: the Unicode codepoint as a decimal integer
546
 * - `cl`: #hb_glyph_info_t.cluster if
547
 *   #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set.
548
 *
549
 * For example:
550
 *
551
 * ```
552
 * [{u:1617,cl:0},{u:1576,cl:1}]
553
 * ```
554
 *
555
 * Return value:
556
 * The number of serialized items.
557
 *
558
 * Since: 2.7.3
559
 **/
560
unsigned int
561
hb_buffer_serialize_unicode (hb_buffer_t *buffer,
562
                             unsigned int start,
563
                             unsigned int end,
564
                             char *buf,
565
                             unsigned int buf_size,
566
                             unsigned int *buf_consumed,
567
                             hb_buffer_serialize_format_t format,
568
                             hb_buffer_serialize_flags_t flags)
569
6.26k
{
570
6.26k
  end = hb_clamp (end, start, buffer->len);
571
6.26k
  start = hb_min (start, end);
572
573
6.26k
  unsigned int sconsumed;
574
6.26k
  if (!buf_consumed)
575
0
    buf_consumed = &sconsumed;
576
6.26k
  *buf_consumed = 0;
577
6.26k
  if (buf_size)
578
6.26k
    *buf = '\0';
579
580
6.26k
  buffer->assert_unicode ();
581
582
6.26k
  if (unlikely (start == end))
583
0
    return 0;
584
585
6.26k
  switch (format)
586
6.26k
  {
587
6.26k
    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
588
6.26k
      return _hb_buffer_serialize_unicode_text (buffer, start, end,
589
6.26k
                                                buf, buf_size, buf_consumed, flags);
590
591
0
    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
592
0
      return _hb_buffer_serialize_unicode_json (buffer, start, end,
593
0
                                                buf, buf_size, buf_consumed, flags);
594
595
0
    default:
596
0
    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
597
0
      return 0;
598
599
6.26k
  }
600
6.26k
}
601
602
static unsigned int
603
_hb_buffer_serialize_invalid (hb_buffer_t *buffer,
604
                              unsigned int start,
605
                              unsigned int end,
606
                              char *buf,
607
                              unsigned int buf_size,
608
                              unsigned int *buf_consumed,
609
                              hb_buffer_serialize_format_t format,
610
                              hb_buffer_serialize_flags_t flags)
611
0
{
612
0
  assert (!buffer->len);
613
614
0
  unsigned int sconsumed;
615
0
  if (!buf_consumed)
616
0
    buf_consumed = &sconsumed;
617
0
  if (buf_size < 3)
618
0
    return 0;
619
0
  if (format == HB_BUFFER_SERIALIZE_FORMAT_JSON) {
620
0
    *buf++ = '[';
621
0
    *buf++ = ']';
622
0
    *buf = '\0';
623
0
  } else if (format == HB_BUFFER_SERIALIZE_FORMAT_TEXT) {
624
0
    *buf++ = '!';
625
0
    *buf++ = '!';
626
0
    *buf = '\0';
627
0
  }
628
0
  *buf_consumed = 2;
629
0
  return 0;
630
0
}
631
632
/**
633
 * hb_buffer_serialize:
634
 * @buffer: an #hb_buffer_t buffer.
635
 * @start: the first item in @buffer to serialize.
636
 * @end: the last item in @buffer to serialize.
637
 * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
638
 *       write serialized buffer into.
639
 * @buf_size: the size of @buf.
640
 * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf.
641
 * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
642
 *        read glyph names and extents. If `NULL`, an empty font will be used.
643
 * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
644
 * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
645
 *         to serialize.
646
 *
647
 * Serializes @buffer into a textual representation of its content, whether
648
 * Unicode codepoints or glyph identifiers and positioning information. This is
649
 * useful for showing the contents of the buffer, for example during debugging.
650
 * See the documentation of hb_buffer_serialize_unicode() and
651
 * hb_buffer_serialize_glyphs() for a description of the output format.
652
 *
653
 * Return value:
654
 * The number of serialized items.
655
 *
656
 * Since: 2.7.3
657
 **/
658
unsigned int
659
hb_buffer_serialize (hb_buffer_t *buffer,
660
                     unsigned int start,
661
                     unsigned int end,
662
                     char *buf,
663
                     unsigned int buf_size,
664
                     unsigned int *buf_consumed,
665
                     hb_font_t *font,
666
                     hb_buffer_serialize_format_t format,
667
                     hb_buffer_serialize_flags_t flags)
668
0
{
669
0
  switch (buffer->content_type)
670
0
  {
671
672
0
    case HB_BUFFER_CONTENT_TYPE_GLYPHS:
673
0
      return hb_buffer_serialize_glyphs (buffer, start, end, buf, buf_size,
674
0
           buf_consumed, font, format, flags);
675
676
0
    case HB_BUFFER_CONTENT_TYPE_UNICODE:
677
0
      return hb_buffer_serialize_unicode (buffer, start, end, buf, buf_size,
678
0
            buf_consumed, format, flags);
679
680
0
    case HB_BUFFER_CONTENT_TYPE_INVALID:
681
0
    default:
682
0
      return _hb_buffer_serialize_invalid (buffer, start, end, buf, buf_size,
683
0
             buf_consumed, format, flags);
684
0
  }
685
0
}
686
687
static bool
688
parse_int (const char *pp, const char *end, int32_t *pv)
689
0
{
690
0
  int v;
691
0
  const char *p = pp;
692
0
  if (unlikely (!hb_parse_int (&p, end, &v, true/* whole buffer */)))
693
0
    return false;
694
695
0
  *pv = v;
696
0
  return true;
697
0
}
698
699
static bool
700
parse_uint (const char *pp, const char *end, uint32_t *pv)
701
0
{
702
0
  unsigned int v;
703
0
  const char *p = pp;
704
0
  if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */)))
705
0
    return false;
706
707
0
  *pv = v;
708
0
  return true;
709
0
}
710
711
static bool
712
parse_hex (const char *pp, const char *end, uint32_t *pv)
713
0
{
714
0
  unsigned int v;
715
0
  const char *p = pp;
716
0
  if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */, 16)))
717
0
    return false;
718
719
0
  *pv = v;
720
0
  return true;
721
0
}
722
723
#include "hb-buffer-deserialize-json.hh"
724
#include "hb-buffer-deserialize-text-glyphs.hh"
725
#include "hb-buffer-deserialize-text-unicode.hh"
726
727
/**
728
 * hb_buffer_deserialize_glyphs:
729
 * @buffer: an #hb_buffer_t buffer.
730
 * @buf: (array length=buf_len): string to deserialize
731
 * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
732
 * @end_ptr: (out) (optional): output pointer to the character after last
733
 *                               consumed one.
734
 * @font: (nullable): font for getting glyph IDs
735
 * @format: the #hb_buffer_serialize_format_t of the input @buf
736
 *
737
 * Deserializes glyphs @buffer from textual representation in the format
738
 * produced by hb_buffer_serialize_glyphs().
739
 *
740
 * Return value: `true` if parse was successful, `false` if an error
741
 * occurred.
742
 *
743
 * Since: 0.9.7
744
 **/
745
hb_bool_t
746
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
747
                              const char *buf,
748
                              int buf_len, /* -1 means nul-terminated */
749
                              const char **end_ptr, /* May be NULL */
750
                              hb_font_t *font, /* May be NULL */
751
                              hb_buffer_serialize_format_t format)
752
0
{
753
0
  const char *end;
754
0
  if (!end_ptr)
755
0
    end_ptr = &end;
756
0
  *end_ptr = buf;
757
758
0
  buffer->assert_glyphs ();
759
760
0
  if (unlikely (hb_object_is_immutable (buffer)))
761
0
  {
762
0
    if (end_ptr)
763
0
      *end_ptr = buf;
764
0
    return false;
765
0
  }
766
767
0
  if (buf_len == -1)
768
0
    buf_len = strlen (buf);
769
770
0
  if (!buf_len)
771
0
  {
772
0
    *end_ptr = buf;
773
0
    return false;
774
0
  }
775
776
0
  hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
777
778
0
  if (!font)
779
0
    font = hb_font_get_empty ();
780
781
0
  switch (format)
782
0
  {
783
0
    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
784
0
      return _hb_buffer_deserialize_text_glyphs (buffer,
785
0
             buf, buf_len, end_ptr,
786
0
             font);
787
788
0
    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
789
0
      return _hb_buffer_deserialize_json (buffer,
790
0
                                          buf, buf_len, end_ptr,
791
0
                                          font);
792
793
0
    default:
794
0
    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
795
0
      return false;
796
797
0
  }
798
0
}
799
800
801
/**
802
 * hb_buffer_deserialize_unicode:
803
 * @buffer: an #hb_buffer_t buffer.
804
 * @buf: (array length=buf_len): string to deserialize
805
 * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated
806
 * @end_ptr: (out) (optional): output pointer to the character after last
807
 *                               consumed one.
808
 * @format: the #hb_buffer_serialize_format_t of the input @buf
809
 *
810
 * Deserializes Unicode @buffer from textual representation in the format
811
 * produced by hb_buffer_serialize_unicode().
812
 *
813
 * Return value: `true` if parse was successful, `false` if an error
814
 * occurred.
815
 *
816
 * Since: 2.7.3
817
 **/
818
hb_bool_t
819
hb_buffer_deserialize_unicode (hb_buffer_t *buffer,
820
                               const char *buf,
821
                               int buf_len, /* -1 means nul-terminated */
822
                               const char **end_ptr, /* May be NULL */
823
                               hb_buffer_serialize_format_t format)
824
0
{
825
0
  const char *end;
826
0
  if (!end_ptr)
827
0
    end_ptr = &end;
828
0
  *end_ptr = buf;
829
830
0
  buffer->assert_unicode ();
831
832
0
  if (unlikely (hb_object_is_immutable (buffer)))
833
0
  {
834
0
    if (end_ptr)
835
0
      *end_ptr = buf;
836
0
    return false;
837
0
  }
838
839
0
  if (buf_len == -1)
840
0
    buf_len = strlen (buf);
841
842
0
  if (!buf_len)
843
0
  {
844
0
    *end_ptr = buf;
845
0
    return false;
846
0
  }
847
848
0
  hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
849
850
0
  hb_font_t* font = hb_font_get_empty ();
851
852
0
  switch (format)
853
0
  {
854
0
    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
855
0
      return _hb_buffer_deserialize_text_unicode (buffer,
856
0
              buf, buf_len, end_ptr,
857
0
              font);
858
859
0
    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
860
0
      return _hb_buffer_deserialize_json (buffer,
861
0
                                          buf, buf_len, end_ptr,
862
0
                                          font);
863
864
0
    default:
865
0
    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
866
0
      return false;
867
868
0
  }
869
0
}
870
871
872
#endif