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 30 static 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: 0.9.2 44 **/ 45 const char ** 46 hb_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: 0.9.2 61 **/ 62 hb_buffer_serialize_format_t 63 hb_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: 0.9.2 78 **/ 79 const char * 80 hb_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 91 static 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 = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ? 103 NULL : hb_buffer_get_glyph_positions (buffer, NULL); 104 105 *buf_consumed = 0; 106 for (unsigned int i = start; i < end; i++) 107 { 108 char b[1024]; 109 char *p = b; 110 111 /* In the following code, we know b is large enough that no overflow can happen. */ 112 113 #define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END 114 115 if (i) 116 *p++ = ','; 117 118 *p++ = '{'; 119 120 APPEND ("\"g\":"); 121 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) 122 { 123 char g[128]; 124 hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g)); 125 *p++ = '"'; 126 for (char *q = g; *q; q++) { 127 if (*q == '"') 128 *p++ = '\\'; 129 *p++ = *q; 130 } 131 *p++ = '"'; 132 } 133 else 134 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint)); 135 136 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { 137 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster)); 138 } 139 140 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) 141 { 142 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d", 143 pos[i].x_offset, pos[i].y_offset); 144 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", 145 pos[i].x_advance, pos[i].y_advance); 146 } 147 148 if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) 149 { 150 hb_glyph_extents_t extents; 151 hb_font_get_glyph_extents(font, info[i].codepoint, &extents); 152 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d", 153 extents.x_bearing, extents.y_bearing)); 154 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d", 155 extents.width, extents.height)); 156 } 157 158 *p++ = '}'; 159 160 unsigned int l = p - b; 161 if (buf_size > l) 162 { 163 memcpy (buf, b, l); 164 buf += l; 165 buf_size -= l; 166 *buf_consumed += l; 167 *buf = '\0'; 168 } else 169 return i - start; 170 } 171 172 return end - start; 173 } 174 175 static unsigned int 176 _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, 177 unsigned int start, 178 unsigned int end, 179 char *buf, 180 unsigned int buf_size, 181 unsigned int *buf_consumed, 182 hb_font_t *font, 183 hb_buffer_serialize_flags_t flags) 184 { 185 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); 186 hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ? 187 NULL : hb_buffer_get_glyph_positions (buffer, NULL); 188 189 *buf_consumed = 0; 190 for (unsigned int i = start; i < end; i++) 191 { 192 char b[1024]; 193 char *p = b; 194 195 /* In the following code, we know b is large enough that no overflow can happen. */ 196 197 if (i) 198 *p++ = '|'; 199 200 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) 201 { 202 hb_font_glyph_to_string (font, info[i].codepoint, p, 128); 203 p += strlen (p); 204 } 205 else 206 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint)); 207 208 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { 209 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster)); 210 } 211 212 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) 213 { 214 if (pos[i].x_offset || pos[i].y_offset) 215 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset)); 216 217 *p++ = '+'; 218 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance)); 219 if (pos[i].y_advance) 220 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance)); 221 } 222 223 if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) 224 { 225 hb_glyph_extents_t extents; 226 hb_font_get_glyph_extents(font, info[i].codepoint, &extents); 227 p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height)); 228 } 229 230 unsigned int l = p - b; 231 if (buf_size > l) 232 { 233 memcpy (buf, b, l); 234 buf += l; 235 buf_size -= l; 236 *buf_consumed += l; 237 *buf = '\0'; 238 } else 239 return i - start; 240 } 241 242 return end - start; 243 } 244 245 /* Returns number of items, starting at start, that were serialized. */ 246 /** 247 * hb_buffer_serialize_glyphs: 248 * @buffer: a buffer. 249 * @start: 250 * @end: 251 * @buf: (array length=buf_size): 252 * @buf_size: 253 * @buf_consumed: (out): 254 * @font: 255 * @format: 256 * @flags: 257 * 258 * 259 * 260 * Return value: 261 * 262 * Since: 0.9.2 263 **/ 264 unsigned int 265 hb_buffer_serialize_glyphs (hb_buffer_t *buffer, 266 unsigned int start, 267 unsigned int end, 268 char *buf, 269 unsigned int buf_size, 270 unsigned int *buf_consumed, /* May be NULL */ 271 hb_font_t *font, /* May be NULL */ 272 hb_buffer_serialize_format_t format, 273 hb_buffer_serialize_flags_t flags) 274 { 275 assert (start <= end && end <= buffer->len); 276 277 unsigned int sconsumed; 278 if (!buf_consumed) 279 buf_consumed = &sconsumed; 280 *buf_consumed = 0; 281 282 assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || 283 buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); 284 285 if (unlikely (start == end)) 286 return 0; 287 288 if (!font) 289 font = hb_font_get_empty (); 290 291 switch (format) 292 { 293 case HB_BUFFER_SERIALIZE_FORMAT_TEXT: 294 return _hb_buffer_serialize_glyphs_text (buffer, start, end, 295 buf, buf_size, buf_consumed, 296 font, flags); 297 298 case HB_BUFFER_SERIALIZE_FORMAT_JSON: 299 return _hb_buffer_serialize_glyphs_json (buffer, start, end, 300 buf, buf_size, buf_consumed, 301 font, flags); 302 303 default: 304 case HB_BUFFER_SERIALIZE_FORMAT_INVALID: 305 return 0; 306 307 } 308 } 309 310 311 static hb_bool_t 312 parse_uint (const char *pp, const char *end, uint32_t *pv) 313 { 314 char buf[32]; 315 unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); 316 strncpy (buf, pp, len); 317 buf[len] = '\0'; 318 319 char *p = buf; 320 char *pend = p; 321 uint32_t v; 322 323 errno = 0; 324 v = strtol (p, &pend, 10); 325 if (errno || p == pend || pend - p != end - pp) 326 return false; 327 328 *pv = v; 329 return true; 330 } 331 332 static hb_bool_t 333 parse_int (const char *pp, const char *end, int32_t *pv) 334 { 335 char buf[32]; 336 unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); 337 strncpy (buf, pp, len); 338 buf[len] = '\0'; 339 340 char *p = buf; 341 char *pend = p; 342 int32_t v; 343 344 errno = 0; 345 v = strtol (p, &pend, 10); 346 if (errno || p == pend || pend - p != end - pp) 347 return false; 348 349 *pv = v; 350 return true; 351 } 352 353 #include "hb-buffer-deserialize-json.hh" 354 #include "hb-buffer-deserialize-text.hh" 355 356 /** 357 * hb_buffer_deserialize_glyphs: 358 * @buffer: a buffer. 359 * @buf: (array length=buf_len): 360 * @buf_len: 361 * @end_ptr: (out): 362 * @font: 363 * @format: 364 * 365 * 366 * 367 * Return value: 368 * 369 * Since: 0.9.2 370 **/ 371 hb_bool_t 372 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, 373 const char *buf, 374 int buf_len, /* -1 means nul-terminated */ 375 const char **end_ptr, /* May be NULL */ 376 hb_font_t *font, /* May be NULL */ 377 hb_buffer_serialize_format_t format) 378 { 379 const char *end; 380 if (!end_ptr) 381 end_ptr = &end; 382 *end_ptr = buf; 383 384 assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || 385 buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); 386 387 if (buf_len == -1) 388 buf_len = strlen (buf); 389 390 if (!buf_len) 391 { 392 *end_ptr = buf; 393 return false; 394 } 395 396 hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); 397 398 if (!font) 399 font = hb_font_get_empty (); 400 401 switch (format) 402 { 403 case HB_BUFFER_SERIALIZE_FORMAT_TEXT: 404 return _hb_buffer_deserialize_glyphs_text (buffer, 405 buf, buf_len, end_ptr, 406 font); 407 408 case HB_BUFFER_SERIALIZE_FORMAT_JSON: 409 return _hb_buffer_deserialize_glyphs_json (buffer, 410 buf, buf_len, end_ptr, 411 font); 412 413 default: 414 case HB_BUFFER_SERIALIZE_FORMAT_INVALID: 415 return false; 416 417 } 418 }