1/* 2 * Copyright © 2012,2013 Google, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Google Author(s): Behdad Esfahbod 25 */ 26 27#include "hb-buffer-private.hh" 28 29 30static const char *serialize_formats[] = { 31 "text", 32 "json", 33 NULL 34}; 35 36/** 37 * hb_buffer_serialize_list_formats: 38 * 39 * 40 * 41 * Return value: (transfer none): 42 * 43 * Since: 1.0 44 **/ 45const char ** 46hb_buffer_serialize_list_formats (void) 47{ 48 return serialize_formats; 49} 50 51/** 52 * hb_buffer_serialize_format_from_string: 53 * @str: 54 * @len: 55 * 56 * 57 * 58 * Return value: 59 * 60 * Since: 1.0 61 **/ 62hb_buffer_serialize_format_t 63hb_buffer_serialize_format_from_string (const char *str, int len) 64{ 65 /* Upper-case it. */ 66 return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u); 67} 68 69/** 70 * hb_buffer_serialize_format_to_string: 71 * @format: 72 * 73 * 74 * 75 * Return value: 76 * 77 * Since: 1.0 78 **/ 79const char * 80hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) 81{ 82 switch (format) 83 { 84 case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0]; 85 case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1]; 86 default: 87 case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return NULL; 88 } 89} 90 91static unsigned int 92_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, 93 unsigned int start, 94 unsigned int end, 95 char *buf, 96 unsigned int buf_size, 97 unsigned int *buf_consumed, 98 hb_font_t *font, 99 hb_buffer_serialize_flags_t flags) 100{ 101 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); 102 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); 103 104 *buf_consumed = 0; 105 for (unsigned int i = start; i < end; i++) 106 { 107 char b[1024]; 108 char *p = b; 109 110 /* In the following code, we know b is large enough that no overflow can happen. */ 111 112#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END 113 114 if (i) 115 *p++ = ','; 116 117 *p++ = '{'; 118 119 APPEND ("\"g\":"); 120 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) 121 { 122 char g[128]; 123 hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g)); 124 *p++ = '"'; 125 for (char *q = g; *q; q++) { 126 if (*q == '"') 127 *p++ = '\\'; 128 *p++ = *q; 129 } 130 *p++ = '"'; 131 } 132 else 133 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint)); 134 135 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { 136 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster)); 137 } 138 139 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) 140 { 141 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d", 142 pos[i].x_offset, pos[i].y_offset); 143 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", 144 pos[i].x_advance, pos[i].y_advance); 145 } 146 147 *p++ = '}'; 148 149 unsigned int l = p - b; 150 if (buf_size > l) 151 { 152 memcpy (buf, b, l); 153 buf += l; 154 buf_size -= l; 155 *buf_consumed += l; 156 *buf = '\0'; 157 } else 158 return i - start; 159 } 160 161 return end - start; 162} 163 164static unsigned int 165_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, 166 unsigned int start, 167 unsigned int end, 168 char *buf, 169 unsigned int buf_size, 170 unsigned int *buf_consumed, 171 hb_font_t *font, 172 hb_buffer_serialize_flags_t flags) 173{ 174 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); 175 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); 176 177 *buf_consumed = 0; 178 for (unsigned int i = start; i < end; i++) 179 { 180 char b[1024]; 181 char *p = b; 182 183 /* In the following code, we know b is large enough that no overflow can happen. */ 184 185 if (i) 186 *p++ = '|'; 187 188 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) 189 { 190 hb_font_glyph_to_string (font, info[i].codepoint, p, 128); 191 p += strlen (p); 192 } 193 else 194 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint)); 195 196 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { 197 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster)); 198 } 199 200 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) 201 { 202 if (pos[i].x_offset || pos[i].y_offset) 203 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset)); 204 205 *p++ = '+'; 206 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance)); 207 if (pos[i].y_advance) 208 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance)); 209 } 210 211 unsigned int l = p - b; 212 if (buf_size > l) 213 { 214 memcpy (buf, b, l); 215 buf += l; 216 buf_size -= l; 217 *buf_consumed += l; 218 *buf = '\0'; 219 } else 220 return i - start; 221 } 222 223 return end - start; 224} 225 226/* Returns number of items, starting at start, that were serialized. */ 227/** 228 * hb_buffer_serialize_glyphs: 229 * @buffer: a buffer. 230 * @start: 231 * @end: 232 * @buf: (array length=buf_size): 233 * @buf_size: 234 * @buf_consumed: (out): 235 * @font: 236 * @format: 237 * @flags: 238 * 239 * 240 * 241 * Return value: 242 * 243 * Since: 1.0 244 **/ 245unsigned int 246hb_buffer_serialize_glyphs (hb_buffer_t *buffer, 247 unsigned int start, 248 unsigned int end, 249 char *buf, 250 unsigned int buf_size, 251 unsigned int *buf_consumed, /* May be NULL */ 252 hb_font_t *font, /* May be NULL */ 253 hb_buffer_serialize_format_t format, 254 hb_buffer_serialize_flags_t flags) 255{ 256 assert (start <= end && end <= buffer->len); 257 258 unsigned int sconsumed; 259 if (!buf_consumed) 260 buf_consumed = &sconsumed; 261 *buf_consumed = 0; 262 263 assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || 264 buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); 265 266 if (unlikely (start == end)) 267 return 0; 268 269 if (!font) 270 font = hb_font_get_empty (); 271 272 switch (format) 273 { 274 case HB_BUFFER_SERIALIZE_FORMAT_TEXT: 275 return _hb_buffer_serialize_glyphs_text (buffer, start, end, 276 buf, buf_size, buf_consumed, 277 font, flags); 278 279 case HB_BUFFER_SERIALIZE_FORMAT_JSON: 280 return _hb_buffer_serialize_glyphs_json (buffer, start, end, 281 buf, buf_size, buf_consumed, 282 font, flags); 283 284 default: 285 case HB_BUFFER_SERIALIZE_FORMAT_INVALID: 286 return 0; 287 288 } 289} 290 291 292static hb_bool_t 293parse_uint (const char *pp, const char *end, uint32_t *pv) 294{ 295 char buf[32]; 296 unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); 297 strncpy (buf, pp, len); 298 buf[len] = '\0'; 299 300 char *p = buf; 301 char *pend = p; 302 uint32_t v; 303 304 errno = 0; 305 v = strtol (p, &pend, 10); 306 if (errno || p == pend || pend - p != end - pp) 307 return false; 308 309 *pv = v; 310 return true; 311} 312 313static hb_bool_t 314parse_int (const char *pp, const char *end, int32_t *pv) 315{ 316 char buf[32]; 317 unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); 318 strncpy (buf, pp, len); 319 buf[len] = '\0'; 320 321 char *p = buf; 322 char *pend = p; 323 int32_t v; 324 325 errno = 0; 326 v = strtol (p, &pend, 10); 327 if (errno || p == pend || pend - p != end - pp) 328 return false; 329 330 *pv = v; 331 return true; 332} 333 334#include "hb-buffer-deserialize-json.hh" 335#include "hb-buffer-deserialize-text.hh" 336 337/** 338 * hb_buffer_deserialize_glyphs: 339 * @buffer: a buffer. 340 * @buf: (array length=buf_len): 341 * @buf_len: 342 * @end_ptr: (out): 343 * @font: 344 * @format: 345 * 346 * 347 * 348 * Return value: 349 * 350 * Since: 1.0 351 **/ 352hb_bool_t 353hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, 354 const char *buf, 355 int buf_len, /* -1 means nul-terminated */ 356 const char **end_ptr, /* May be NULL */ 357 hb_font_t *font, /* May be NULL */ 358 hb_buffer_serialize_format_t format) 359{ 360 const char *end; 361 if (!end_ptr) 362 end_ptr = &end; 363 *end_ptr = buf; 364 365 assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || 366 buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); 367 368 if (buf_len == -1) 369 buf_len = strlen (buf); 370 371 if (!buf_len) 372 { 373 *end_ptr = buf; 374 return false; 375 } 376 377 hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); 378 379 if (!font) 380 font = hb_font_get_empty (); 381 382 switch (format) 383 { 384 case HB_BUFFER_SERIALIZE_FORMAT_TEXT: 385 return _hb_buffer_deserialize_glyphs_text (buffer, 386 buf, buf_len, end_ptr, 387 font); 388 389 case HB_BUFFER_SERIALIZE_FORMAT_JSON: 390 return _hb_buffer_deserialize_glyphs_json (buffer, 391 buf, buf_len, end_ptr, 392 font); 393 394 default: 395 case HB_BUFFER_SERIALIZE_FORMAT_INVALID: 396 return false; 397 398 } 399} 400