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 const char ** 37 hb_buffer_serialize_list_formats (void) 38 { 39 return serialize_formats; 40 } 41 42 hb_buffer_serialize_format_t 43 hb_buffer_serialize_format_from_string (const char *str, int len) 44 { 45 /* Upper-case it. */ 46 return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020); 47 } 48 49 const char * 50 hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) 51 { 52 switch (format) 53 { 54 case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0]; 55 case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1]; 56 default: 57 case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return NULL; 58 } 59 } 60 61 static unsigned int 62 _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, 63 unsigned int start, 64 unsigned int end, 65 char *buf, 66 unsigned int buf_size, 67 unsigned int *buf_consumed, 68 hb_font_t *font, 69 hb_buffer_serialize_flags_t flags) 70 { 71 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); 72 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); 73 74 *buf_consumed = 0; 75 for (unsigned int i = start; i < end; i++) 76 { 77 char b[1024]; 78 char *p = b; 79 80 /* In the following code, we know b is large enough that no overflow can happen. */ 81 82 #define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END 83 84 if (i) 85 *p++ = ','; 86 87 *p++ = '{'; 88 89 APPEND ("\"g\":"); 90 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) 91 { 92 char g[128]; 93 hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g)); 94 *p++ = '"'; 95 for (char *q = g; *q; q++) { 96 if (*q == '"') 97 *p++ = '\\'; 98 *p++ = *q; 99 } 100 *p++ = '"'; 101 } 102 else 103 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint); 104 105 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { 106 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster); 107 } 108 109 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) 110 { 111 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d", 112 pos[i].x_offset, pos[i].y_offset); 113 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", 114 pos[i].x_advance, pos[i].y_advance); 115 } 116 117 *p++ = '}'; 118 119 if (buf_size > (p - b)) 120 { 121 unsigned int l = p - b; 122 memcpy (buf, b, l); 123 buf += l; 124 buf_size -= l; 125 *buf_consumed += l; 126 *buf = '\0'; 127 } else 128 return i - start; 129 } 130 131 return end - start; 132 } 133 134 static unsigned int 135 _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, 136 unsigned int start, 137 unsigned int end, 138 char *buf, 139 unsigned int buf_size, 140 unsigned int *buf_consumed, 141 hb_font_t *font, 142 hb_buffer_serialize_flags_t flags) 143 { 144 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); 145 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); 146 147 *buf_consumed = 0; 148 for (unsigned int i = start; i < end; i++) 149 { 150 char b[1024]; 151 char *p = b; 152 153 /* In the following code, we know b is large enough that no overflow can happen. */ 154 155 if (i) 156 *p++ = '|'; 157 158 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) 159 { 160 hb_font_glyph_to_string (font, info[i].codepoint, p, 128); 161 p += strlen (p); 162 } 163 else 164 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint); 165 166 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { 167 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster); 168 } 169 170 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) 171 { 172 if (pos[i].x_offset || pos[i].y_offset) 173 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset); 174 175 *p++ = '+'; 176 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance); 177 if (pos->y_advance) 178 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance); 179 } 180 181 if (buf_size > (p - b)) 182 { 183 unsigned int l = p - b; 184 memcpy (buf, b, l); 185 buf += l; 186 buf_size -= l; 187 *buf_consumed += l; 188 *buf = '\0'; 189 } else 190 return i - start; 191 } 192 193 return end - start; 194 } 195 196 /* Returns number of items, starting at start, that were serialized. */ 197 unsigned int 198 hb_buffer_serialize_glyphs (hb_buffer_t *buffer, 199 unsigned int start, 200 unsigned int end, 201 char *buf, 202 unsigned int buf_size, 203 unsigned int *buf_consumed, /* May be NULL */ 204 hb_font_t *font, /* May be NULL */ 205 hb_buffer_serialize_format_t format, 206 hb_buffer_serialize_flags_t flags) 207 { 208 assert (start <= end && end <= buffer->len); 209 210 unsigned int sconsumed; 211 if (!buf_consumed) 212 buf_consumed = &sconsumed; 213 *buf_consumed = 0; 214 215 assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || 216 buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); 217 218 if (unlikely (start == end)) 219 return 0; 220 221 if (!font) 222 font = hb_font_get_empty (); 223 224 switch (format) 225 { 226 case HB_BUFFER_SERIALIZE_FORMAT_TEXT: 227 return _hb_buffer_serialize_glyphs_text (buffer, start, end, 228 buf, buf_size, buf_consumed, 229 font, flags); 230 231 case HB_BUFFER_SERIALIZE_FORMAT_JSON: 232 return _hb_buffer_serialize_glyphs_json (buffer, start, end, 233 buf, buf_size, buf_consumed, 234 font, flags); 235 236 default: 237 case HB_BUFFER_SERIALIZE_FORMAT_INVALID: 238 return 0; 239 240 } 241 } 242 243 244 static hb_bool_t 245 parse_uint (const char *pp, const char *end, uint32_t *pv) 246 { 247 char buf[32]; 248 unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); 249 strncpy (buf, pp, len); 250 buf[len] = '\0'; 251 252 char *p = buf; 253 char *pend = p; 254 uint32_t v; 255 256 errno = 0; 257 v = strtol (p, &pend, 10); 258 if (errno || p == pend || pend - p != end - pp) 259 return false; 260 261 *pv = v; 262 return true; 263 } 264 265 static hb_bool_t 266 parse_int (const char *pp, const char *end, int32_t *pv) 267 { 268 char buf[32]; 269 unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); 270 strncpy (buf, pp, len); 271 buf[len] = '\0'; 272 273 char *p = buf; 274 char *pend = p; 275 int32_t v; 276 277 errno = 0; 278 v = strtol (p, &pend, 10); 279 if (errno || p == pend || pend - p != end - pp) 280 return false; 281 282 *pv = v; 283 return true; 284 } 285 286 #include "hb-buffer-deserialize-json.hh" 287 #include "hb-buffer-deserialize-text.hh" 288 289 hb_bool_t 290 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, 291 const char *buf, 292 int buf_len, /* -1 means nul-terminated */ 293 const char **end_ptr, /* May be NULL */ 294 hb_font_t *font, /* May be NULL */ 295 hb_buffer_serialize_format_t format) 296 { 297 const char *end; 298 if (!end_ptr) 299 end_ptr = &end; 300 *end_ptr = buf; 301 302 assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || 303 buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); 304 305 if (buf_len == -1) 306 buf_len = strlen (buf); 307 308 if (!buf_len) 309 { 310 *end_ptr = buf; 311 return false; 312 } 313 314 hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); 315 316 if (!font) 317 font = hb_font_get_empty (); 318 319 switch (format) 320 { 321 case HB_BUFFER_SERIALIZE_FORMAT_TEXT: 322 return _hb_buffer_deserialize_glyphs_text (buffer, 323 buf, buf_len, end_ptr, 324 font); 325 326 case HB_BUFFER_SERIALIZE_FORMAT_JSON: 327 return _hb_buffer_deserialize_glyphs_json (buffer, 328 buf, buf_len, end_ptr, 329 font); 330 331 default: 332 case HB_BUFFER_SERIALIZE_FORMAT_INVALID: 333 return false; 334 335 } 336 } 337