Coverage Report

Created: 2025-07-07 10:01

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