Coverage Report

Created: 2026-03-31 11:00

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