Coverage Report

Created: 2026-09-28 10:59

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