1 // Copyright 2014 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // Library for converting WOFF2 format font files to their TTF versions.
16
17 #include "./woff2_dec.h"
18
19 #include <stdlib.h>
20 #include <complex>
21 #include <cstring>
22 #include <limits>
23 #include <string>
24 #include <vector>
25
26 #include "./buffer.h"
27 #include "./decode.h"
28 #include "./round.h"
29 #include "./store_bytes.h"
30 #include "./table_tags.h"
31 #include "./woff2_common.h"
32
33 namespace woff2 {
34
35 namespace {
36
37 using std::string;
38 using std::vector;
39
40
41 // simple glyph flags
42 const int kGlyfOnCurve = 1 << 0;
43 const int kGlyfXShort = 1 << 1;
44 const int kGlyfYShort = 1 << 2;
45 const int kGlyfRepeat = 1 << 3;
46 const int kGlyfThisXIsSame = 1 << 4;
47 const int kGlyfThisYIsSame = 1 << 5;
48
49 // composite glyph flags
50 // See CompositeGlyph.java in sfntly for full definitions
51 const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
52 const int FLAG_WE_HAVE_A_SCALE = 1 << 3;
53 const int FLAG_MORE_COMPONENTS = 1 << 5;
54 const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
55 const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
56 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
57
58 const size_t kSfntHeaderSize = 12;
59 const size_t kSfntEntrySize = 16;
60 const size_t kCheckSumAdjustmentOffset = 8;
61
62 const size_t kEndPtsOfContoursOffset = 10;
63 const size_t kCompositeGlyphBegin = 10;
64
65 // Based on section 6.1.1 of MicroType Express draft spec
Read255UShort(Buffer * buf,unsigned int * value)66 bool Read255UShort(Buffer* buf, unsigned int* value) {
67 static const int kWordCode = 253;
68 static const int kOneMoreByteCode2 = 254;
69 static const int kOneMoreByteCode1 = 255;
70 static const int kLowestUCode = 253;
71 uint8_t code = 0;
72 if (!buf->ReadU8(&code)) {
73 return FONT_COMPRESSION_FAILURE();
74 }
75 if (code == kWordCode) {
76 uint16_t result = 0;
77 if (!buf->ReadU16(&result)) {
78 return FONT_COMPRESSION_FAILURE();
79 }
80 *value = result;
81 return true;
82 } else if (code == kOneMoreByteCode1) {
83 uint8_t result = 0;
84 if (!buf->ReadU8(&result)) {
85 return FONT_COMPRESSION_FAILURE();
86 }
87 *value = result + kLowestUCode;
88 return true;
89 } else if (code == kOneMoreByteCode2) {
90 uint8_t result = 0;
91 if (!buf->ReadU8(&result)) {
92 return FONT_COMPRESSION_FAILURE();
93 }
94 *value = result + kLowestUCode * 2;
95 return true;
96 } else {
97 *value = code;
98 return true;
99 }
100 }
101
ReadBase128(Buffer * buf,uint32_t * value)102 bool ReadBase128(Buffer* buf, uint32_t* value) {
103 uint32_t result = 0;
104 for (size_t i = 0; i < 5; ++i) {
105 uint8_t code = 0;
106 if (!buf->ReadU8(&code)) {
107 return FONT_COMPRESSION_FAILURE();
108 }
109 // If any of the top seven bits are set then we're about to overflow.
110 if (result & 0xe0000000) {
111 return FONT_COMPRESSION_FAILURE();
112 }
113 result = (result << 7) | (code & 0x7f);
114 if ((code & 0x80) == 0) {
115 *value = result;
116 return true;
117 }
118 }
119 // Make sure not to exceed the size bound
120 return FONT_COMPRESSION_FAILURE();
121 }
122
WithSign(int flag,int baseval)123 int WithSign(int flag, int baseval) {
124 // Precondition: 0 <= baseval < 65536 (to avoid integer overflow)
125 return (flag & 1) ? baseval : -baseval;
126 }
127
TripletDecode(const uint8_t * flags_in,const uint8_t * in,size_t in_size,unsigned int n_points,std::vector<Point> * result,size_t * in_bytes_consumed)128 bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
129 unsigned int n_points, std::vector<Point>* result,
130 size_t* in_bytes_consumed) {
131 int x = 0;
132 int y = 0;
133
134 if (n_points > in_size) {
135 return FONT_COMPRESSION_FAILURE();
136 }
137 unsigned int triplet_index = 0;
138
139 for (unsigned int i = 0; i < n_points; ++i) {
140 uint8_t flag = flags_in[i];
141 bool on_curve = !(flag >> 7);
142 flag &= 0x7f;
143 unsigned int n_data_bytes;
144 if (flag < 84) {
145 n_data_bytes = 1;
146 } else if (flag < 120) {
147 n_data_bytes = 2;
148 } else if (flag < 124) {
149 n_data_bytes = 3;
150 } else {
151 n_data_bytes = 4;
152 }
153 if (triplet_index + n_data_bytes > in_size ||
154 triplet_index + n_data_bytes < triplet_index) {
155 return FONT_COMPRESSION_FAILURE();
156 }
157 int dx, dy;
158 if (flag < 10) {
159 dx = 0;
160 dy = WithSign(flag, ((flag & 14) << 7) + in[triplet_index]);
161 } else if (flag < 20) {
162 dx = WithSign(flag, (((flag - 10) & 14) << 7) + in[triplet_index]);
163 dy = 0;
164 } else if (flag < 84) {
165 int b0 = flag - 20;
166 int b1 = in[triplet_index];
167 dx = WithSign(flag, 1 + (b0 & 0x30) + (b1 >> 4));
168 dy = WithSign(flag >> 1, 1 + ((b0 & 0x0c) << 2) + (b1 & 0x0f));
169 } else if (flag < 120) {
170 int b0 = flag - 84;
171 dx = WithSign(flag, 1 + ((b0 / 12) << 8) + in[triplet_index]);
172 dy = WithSign(flag >> 1,
173 1 + (((b0 % 12) >> 2) << 8) + in[triplet_index + 1]);
174 } else if (flag < 124) {
175 int b2 = in[triplet_index + 1];
176 dx = WithSign(flag, (in[triplet_index] << 4) + (b2 >> 4));
177 dy = WithSign(flag >> 1, ((b2 & 0x0f) << 8) + in[triplet_index + 2]);
178 } else {
179 dx = WithSign(flag, (in[triplet_index] << 8) + in[triplet_index + 1]);
180 dy = WithSign(flag >> 1,
181 (in[triplet_index + 2] << 8) + in[triplet_index + 3]);
182 }
183 triplet_index += n_data_bytes;
184 // Possible overflow but coordinate values are not security sensitive
185 x += dx;
186 y += dy;
187 result->push_back(Point());
188 Point& back = result->back();
189 back.x = x;
190 back.y = y;
191 back.on_curve = on_curve;
192 }
193 *in_bytes_consumed = triplet_index;
194 return true;
195 }
196
197 // This function stores just the point data. On entry, dst points to the
198 // beginning of a simple glyph. Returns true on success.
StorePoints(const std::vector<Point> & points,unsigned int n_contours,unsigned int instruction_length,uint8_t * dst,size_t dst_size,size_t * glyph_size)199 bool StorePoints(const std::vector<Point>& points,
200 unsigned int n_contours, unsigned int instruction_length,
201 uint8_t* dst, size_t dst_size, size_t* glyph_size) {
202 // I believe that n_contours < 65536, in which case this is safe. However, a
203 // comment and/or an assert would be good.
204 unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 +
205 instruction_length;
206 int last_flag = -1;
207 int repeat_count = 0;
208 int last_x = 0;
209 int last_y = 0;
210 unsigned int x_bytes = 0;
211 unsigned int y_bytes = 0;
212
213 for (unsigned int i = 0; i < points.size(); ++i) {
214 const Point& point = points[i];
215 int flag = point.on_curve ? kGlyfOnCurve : 0;
216 int dx = point.x - last_x;
217 int dy = point.y - last_y;
218 if (dx == 0) {
219 flag |= kGlyfThisXIsSame;
220 } else if (dx > -256 && dx < 256) {
221 flag |= kGlyfXShort | (dx > 0 ? kGlyfThisXIsSame : 0);
222 x_bytes += 1;
223 } else {
224 x_bytes += 2;
225 }
226 if (dy == 0) {
227 flag |= kGlyfThisYIsSame;
228 } else if (dy > -256 && dy < 256) {
229 flag |= kGlyfYShort | (dy > 0 ? kGlyfThisYIsSame : 0);
230 y_bytes += 1;
231 } else {
232 y_bytes += 2;
233 }
234
235 if (flag == last_flag && repeat_count != 255) {
236 dst[flag_offset - 1] |= kGlyfRepeat;
237 repeat_count++;
238 } else {
239 if (repeat_count != 0) {
240 if (flag_offset >= dst_size) {
241 return FONT_COMPRESSION_FAILURE();
242 }
243 dst[flag_offset++] = repeat_count;
244 }
245 if (flag_offset >= dst_size) {
246 return FONT_COMPRESSION_FAILURE();
247 }
248 dst[flag_offset++] = flag;
249 repeat_count = 0;
250 }
251 last_x = point.x;
252 last_y = point.y;
253 last_flag = flag;
254 }
255
256 if (repeat_count != 0) {
257 if (flag_offset >= dst_size) {
258 return FONT_COMPRESSION_FAILURE();
259 }
260 dst[flag_offset++] = repeat_count;
261 }
262 unsigned int xy_bytes = x_bytes + y_bytes;
263 if (xy_bytes < x_bytes ||
264 flag_offset + xy_bytes < flag_offset ||
265 flag_offset + xy_bytes > dst_size) {
266 return FONT_COMPRESSION_FAILURE();
267 }
268
269 int x_offset = flag_offset;
270 int y_offset = flag_offset + x_bytes;
271 last_x = 0;
272 last_y = 0;
273 for (unsigned int i = 0; i < points.size(); ++i) {
274 int dx = points[i].x - last_x;
275 if (dx == 0) {
276 // pass
277 } else if (dx > -256 && dx < 256) {
278 dst[x_offset++] = std::abs(dx);
279 } else {
280 // will always fit for valid input, but overflow is harmless
281 x_offset = Store16(dst, x_offset, dx);
282 }
283 last_x += dx;
284 int dy = points[i].y - last_y;
285 if (dy == 0) {
286 // pass
287 } else if (dy > -256 && dy < 256) {
288 dst[y_offset++] = std::abs(dy);
289 } else {
290 y_offset = Store16(dst, y_offset, dy);
291 }
292 last_y += dy;
293 }
294 *glyph_size = y_offset;
295 return true;
296 }
297
298 // Compute the bounding box of the coordinates, and store into a glyf buffer.
299 // A precondition is that there are at least 10 bytes available.
ComputeBbox(const std::vector<Point> & points,uint8_t * dst)300 void ComputeBbox(const std::vector<Point>& points, uint8_t* dst) {
301 int x_min = 0;
302 int y_min = 0;
303 int x_max = 0;
304 int y_max = 0;
305
306 for (unsigned int i = 0; i < points.size(); ++i) {
307 int x = points[i].x;
308 int y = points[i].y;
309 if (i == 0 || x < x_min) x_min = x;
310 if (i == 0 || x > x_max) x_max = x;
311 if (i == 0 || y < y_min) y_min = y;
312 if (i == 0 || y > y_max) y_max = y;
313 }
314 size_t offset = 2;
315 offset = Store16(dst, offset, x_min);
316 offset = Store16(dst, offset, y_min);
317 offset = Store16(dst, offset, x_max);
318 offset = Store16(dst, offset, y_max);
319 }
320
321 // Process entire bbox stream. This is done as a separate pass to allow for
322 // composite bbox computations (an optional more aggressive transform).
ProcessBboxStream(Buffer * bbox_stream,unsigned int n_glyphs,const std::vector<uint32_t> & loca_values,uint8_t * glyf_buf,size_t glyf_buf_length)323 bool ProcessBboxStream(Buffer* bbox_stream, unsigned int n_glyphs,
324 const std::vector<uint32_t>& loca_values, uint8_t* glyf_buf,
325 size_t glyf_buf_length) {
326 const uint8_t* buf = bbox_stream->buffer();
327 if (n_glyphs >= 65536 || loca_values.size() != n_glyphs + 1) {
328 return FONT_COMPRESSION_FAILURE();
329 }
330 // Safe because n_glyphs is bounded
331 unsigned int bitmap_length = ((n_glyphs + 31) >> 5) << 2;
332 if (!bbox_stream->Skip(bitmap_length)) {
333 return FONT_COMPRESSION_FAILURE();
334 }
335 for (unsigned int i = 0; i < n_glyphs; ++i) {
336 if (buf[i >> 3] & (0x80 >> (i & 7))) {
337 uint32_t loca_offset = loca_values[i];
338 if (loca_values[i + 1] - loca_offset < kEndPtsOfContoursOffset) {
339 return FONT_COMPRESSION_FAILURE();
340 }
341 if (glyf_buf_length < 2 + 10 ||
342 loca_offset > glyf_buf_length - 2 - 10) {
343 return FONT_COMPRESSION_FAILURE();
344 }
345 if (!bbox_stream->Read(glyf_buf + loca_offset + 2, 8)) {
346 return FONT_COMPRESSION_FAILURE();
347 }
348 }
349 }
350 return true;
351 }
352
ProcessComposite(Buffer * composite_stream,uint8_t * dst,size_t dst_size,size_t * glyph_size,bool * have_instructions)353 bool ProcessComposite(Buffer* composite_stream, uint8_t* dst,
354 size_t dst_size, size_t* glyph_size, bool* have_instructions) {
355 size_t start_offset = composite_stream->offset();
356 bool we_have_instructions = false;
357
358 uint16_t flags = FLAG_MORE_COMPONENTS;
359 while (flags & FLAG_MORE_COMPONENTS) {
360 if (!composite_stream->ReadU16(&flags)) {
361 return FONT_COMPRESSION_FAILURE();
362 }
363 we_have_instructions |= (flags & FLAG_WE_HAVE_INSTRUCTIONS) != 0;
364 size_t arg_size = 2; // glyph index
365 if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) {
366 arg_size += 4;
367 } else {
368 arg_size += 2;
369 }
370 if (flags & FLAG_WE_HAVE_A_SCALE) {
371 arg_size += 2;
372 } else if (flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
373 arg_size += 4;
374 } else if (flags & FLAG_WE_HAVE_A_TWO_BY_TWO) {
375 arg_size += 8;
376 }
377 if (!composite_stream->Skip(arg_size)) {
378 return FONT_COMPRESSION_FAILURE();
379 }
380 }
381 size_t composite_glyph_size = composite_stream->offset() - start_offset;
382 if (composite_glyph_size + kCompositeGlyphBegin > dst_size) {
383 return FONT_COMPRESSION_FAILURE();
384 }
385 Store16(dst, 0, 0xffff); // nContours = -1 for composite glyph
386 std::memcpy(dst + kCompositeGlyphBegin,
387 composite_stream->buffer() + start_offset,
388 composite_glyph_size);
389 *glyph_size = kCompositeGlyphBegin + composite_glyph_size;
390 *have_instructions = we_have_instructions;
391 return true;
392 }
393
394 // Build TrueType loca table
StoreLoca(const std::vector<uint32_t> & loca_values,int index_format,uint8_t * dst,size_t dst_size)395 bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format,
396 uint8_t* dst, size_t dst_size) {
397 const uint64_t loca_size = loca_values.size();
398 const uint64_t offset_size = index_format ? 4 : 2;
399 if ((loca_size << 2) >> 2 != loca_size) {
400 return FONT_COMPRESSION_FAILURE();
401 }
402 if (offset_size * loca_size > dst_size) {
403 return FONT_COMPRESSION_FAILURE();
404 }
405 size_t offset = 0;
406 for (size_t i = 0; i < loca_values.size(); ++i) {
407 uint32_t value = loca_values[i];
408 if (index_format) {
409 offset = StoreU32(dst, offset, value);
410 } else {
411 offset = Store16(dst, offset, value >> 1);
412 }
413 }
414 return true;
415 }
416
417 // Reconstruct entire glyf table based on transformed original
ReconstructGlyf(const uint8_t * data,size_t data_size,uint8_t * dst,size_t dst_size,uint8_t * loca_buf,size_t loca_size)418 bool ReconstructGlyf(const uint8_t* data, size_t data_size,
419 uint8_t* dst, size_t dst_size,
420 uint8_t* loca_buf, size_t loca_size) {
421 static const int kNumSubStreams = 7;
422 Buffer file(data, data_size);
423 uint32_t version;
424 std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
425
426 if (!file.ReadU32(&version)) {
427 return FONT_COMPRESSION_FAILURE();
428 }
429 uint16_t num_glyphs;
430 uint16_t index_format;
431 if (!file.ReadU16(&num_glyphs) ||
432 !file.ReadU16(&index_format)) {
433 return FONT_COMPRESSION_FAILURE();
434 }
435 unsigned int offset = (2 + kNumSubStreams) * 4;
436 if (offset > data_size) {
437 return FONT_COMPRESSION_FAILURE();
438 }
439 // Invariant from here on: data_size >= offset
440 for (int i = 0; i < kNumSubStreams; ++i) {
441 uint32_t substream_size;
442 if (!file.ReadU32(&substream_size)) {
443 return FONT_COMPRESSION_FAILURE();
444 }
445 if (substream_size > data_size - offset) {
446 return FONT_COMPRESSION_FAILURE();
447 }
448 substreams[i] = std::make_pair(data + offset, substream_size);
449 offset += substream_size;
450 }
451 Buffer n_contour_stream(substreams[0].first, substreams[0].second);
452 Buffer n_points_stream(substreams[1].first, substreams[1].second);
453 Buffer flag_stream(substreams[2].first, substreams[2].second);
454 Buffer glyph_stream(substreams[3].first, substreams[3].second);
455 Buffer composite_stream(substreams[4].first, substreams[4].second);
456 Buffer bbox_stream(substreams[5].first, substreams[5].second);
457 Buffer instruction_stream(substreams[6].first, substreams[6].second);
458
459 std::vector<uint32_t> loca_values(num_glyphs + 1);
460 std::vector<unsigned int> n_points_vec;
461 std::vector<Point> points;
462 uint32_t loca_offset = 0;
463 for (unsigned int i = 0; i < num_glyphs; ++i) {
464 size_t glyph_size = 0;
465 uint16_t n_contours = 0;
466 if (!n_contour_stream.ReadU16(&n_contours)) {
467 return FONT_COMPRESSION_FAILURE();
468 }
469 uint8_t* glyf_dst = dst + loca_offset;
470 size_t glyf_dst_size = dst_size - loca_offset;
471 if (n_contours == 0xffff) {
472 // composite glyph
473 bool have_instructions = false;
474 unsigned int instruction_size = 0;
475 if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size,
476 &glyph_size, &have_instructions)) {
477 return FONT_COMPRESSION_FAILURE();
478 }
479 if (have_instructions) {
480 if (!Read255UShort(&glyph_stream, &instruction_size)) {
481 return FONT_COMPRESSION_FAILURE();
482 }
483 if (instruction_size + 2 > glyf_dst_size - glyph_size) {
484 return FONT_COMPRESSION_FAILURE();
485 }
486 Store16(glyf_dst, glyph_size, instruction_size);
487 if (!instruction_stream.Read(glyf_dst + glyph_size + 2,
488 instruction_size)) {
489 return FONT_COMPRESSION_FAILURE();
490 }
491 glyph_size += instruction_size + 2;
492 }
493 } else if (n_contours > 0) {
494 // simple glyph
495 n_points_vec.clear();
496 points.clear();
497 unsigned int total_n_points = 0;
498 unsigned int n_points_contour;
499 for (unsigned int j = 0; j < n_contours; ++j) {
500 if (!Read255UShort(&n_points_stream, &n_points_contour)) {
501 return FONT_COMPRESSION_FAILURE();
502 }
503 n_points_vec.push_back(n_points_contour);
504 if (total_n_points + n_points_contour < total_n_points) {
505 return FONT_COMPRESSION_FAILURE();
506 }
507 total_n_points += n_points_contour;
508 }
509 unsigned int flag_size = total_n_points;
510 if (flag_size > flag_stream.length() - flag_stream.offset()) {
511 return FONT_COMPRESSION_FAILURE();
512 }
513 const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset();
514 const uint8_t* triplet_buf = glyph_stream.buffer() +
515 glyph_stream.offset();
516 size_t triplet_size = glyph_stream.length() - glyph_stream.offset();
517 size_t triplet_bytes_consumed = 0;
518 if (!TripletDecode(flags_buf, triplet_buf, triplet_size, total_n_points,
519 &points, &triplet_bytes_consumed)) {
520 return FONT_COMPRESSION_FAILURE();
521 }
522 const uint32_t header_and_endpts_contours_size =
523 kEndPtsOfContoursOffset + 2 * n_contours;
524 if (glyf_dst_size < header_and_endpts_contours_size) {
525 return FONT_COMPRESSION_FAILURE();
526 }
527 Store16(glyf_dst, 0, n_contours);
528 ComputeBbox(points, glyf_dst);
529 size_t offset = kEndPtsOfContoursOffset;
530 int end_point = -1;
531 for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) {
532 end_point += n_points_vec[contour_ix];
533 if (end_point >= 65536) {
534 return FONT_COMPRESSION_FAILURE();
535 }
536 offset = Store16(glyf_dst, offset, end_point);
537 }
538 if (!flag_stream.Skip(flag_size)) {
539 return FONT_COMPRESSION_FAILURE();
540 }
541 if (!glyph_stream.Skip(triplet_bytes_consumed)) {
542 return FONT_COMPRESSION_FAILURE();
543 }
544 unsigned int instruction_size;
545 if (!Read255UShort(&glyph_stream, &instruction_size)) {
546 return FONT_COMPRESSION_FAILURE();
547 }
548 if (glyf_dst_size - header_and_endpts_contours_size <
549 instruction_size + 2) {
550 return FONT_COMPRESSION_FAILURE();
551 }
552 uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size;
553 Store16(instruction_dst, 0, instruction_size);
554 if (!instruction_stream.Read(instruction_dst + 2, instruction_size)) {
555 return FONT_COMPRESSION_FAILURE();
556 }
557 if (!StorePoints(points, n_contours, instruction_size,
558 glyf_dst, glyf_dst_size, &glyph_size)) {
559 return FONT_COMPRESSION_FAILURE();
560 }
561 } else {
562 glyph_size = 0;
563 }
564 loca_values[i] = loca_offset;
565 if (glyph_size + 3 < glyph_size) {
566 return FONT_COMPRESSION_FAILURE();
567 }
568 glyph_size = Round4(glyph_size);
569 if (glyph_size > dst_size - loca_offset) {
570 // This shouldn't happen, but this test defensively maintains the
571 // invariant that loca_offset <= dst_size.
572 return FONT_COMPRESSION_FAILURE();
573 }
574 loca_offset += glyph_size;
575 }
576 loca_values[num_glyphs] = loca_offset;
577 if (!ProcessBboxStream(&bbox_stream, num_glyphs, loca_values,
578 dst, dst_size)) {
579 return FONT_COMPRESSION_FAILURE();
580 }
581 return StoreLoca(loca_values, index_format, loca_buf, loca_size);
582 }
583
584 // This is linear search, but could be changed to binary because we
585 // do have a guarantee that the tables are sorted by tag. But the total
586 // cpu time is expected to be very small in any case.
FindTable(const std::vector<Table> & tables,uint32_t tag)587 const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) {
588 size_t n_tables = tables.size();
589 for (size_t i = 0; i < n_tables; ++i) {
590 if (tables[i].tag == tag) {
591 return &tables[i];
592 }
593 }
594 return NULL;
595 }
596
ReconstructTransformed(const std::vector<Table> & tables,uint32_t tag,const uint8_t * transformed_buf,size_t transformed_size,uint8_t * dst,size_t dst_length)597 bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag,
598 const uint8_t* transformed_buf, size_t transformed_size,
599 uint8_t* dst, size_t dst_length) {
600 if (tag == kGlyfTableTag) {
601 const Table* glyf_table = FindTable(tables, tag);
602 const Table* loca_table = FindTable(tables, kLocaTableTag);
603 if (glyf_table == NULL || loca_table == NULL) {
604 return FONT_COMPRESSION_FAILURE();
605 }
606 if (static_cast<uint64_t>(glyf_table->dst_offset + glyf_table->dst_length) >
607 dst_length) {
608 return FONT_COMPRESSION_FAILURE();
609 }
610 if (static_cast<uint64_t>(loca_table->dst_offset + loca_table->dst_length) >
611 dst_length) {
612 return FONT_COMPRESSION_FAILURE();
613 }
614 return ReconstructGlyf(transformed_buf, transformed_size,
615 dst + glyf_table->dst_offset, glyf_table->dst_length,
616 dst + loca_table->dst_offset, loca_table->dst_length);
617 } else if (tag == kLocaTableTag) {
618 // processing was already done by glyf table, but validate
619 if (!FindTable(tables, kGlyfTableTag)) {
620 return FONT_COMPRESSION_FAILURE();
621 }
622 } else {
623 // transform for the tag is not known
624 return FONT_COMPRESSION_FAILURE();
625 }
626 return true;
627 }
628
ComputeChecksum(const uint8_t * buf,size_t size)629 uint32_t ComputeChecksum(const uint8_t* buf, size_t size) {
630 uint32_t checksum = 0;
631 for (size_t i = 0; i < size; i += 4) {
632 // We assume the addition is mod 2^32, which is valid because unsigned
633 checksum += (buf[i] << 24) | (buf[i + 1] << 16) |
634 (buf[i + 2] << 8) | buf[i + 3];
635 }
636 return checksum;
637 }
638
FixChecksums(const std::vector<Table> & tables,uint8_t * dst)639 bool FixChecksums(const std::vector<Table>& tables, uint8_t* dst) {
640 const Table* head_table = FindTable(tables, kHeadTableTag);
641 if (head_table == NULL ||
642 head_table->dst_length < kCheckSumAdjustmentOffset + 4) {
643 return FONT_COMPRESSION_FAILURE();
644 }
645 size_t adjustment_offset = head_table->dst_offset + kCheckSumAdjustmentOffset;
646 StoreU32(dst, adjustment_offset, 0);
647 size_t n_tables = tables.size();
648 uint32_t file_checksum = 0;
649 for (size_t i = 0; i < n_tables; ++i) {
650 const Table* table = &tables[i];
651 size_t table_length = table->dst_length;
652 uint8_t* table_data = dst + table->dst_offset;
653 uint32_t checksum = ComputeChecksum(table_data, table_length);
654 StoreU32(dst, kSfntHeaderSize + i * kSfntEntrySize + 4, checksum);
655 file_checksum += checksum;
656 }
657 file_checksum += ComputeChecksum(dst,
658 kSfntHeaderSize + kSfntEntrySize * n_tables);
659 uint32_t checksum_adjustment = 0xb1b0afba - file_checksum;
660 StoreU32(dst, adjustment_offset, checksum_adjustment);
661 return true;
662 }
663
Woff2Uncompress(uint8_t * dst_buf,size_t dst_size,const uint8_t * src_buf,size_t src_size)664 bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
665 const uint8_t* src_buf, size_t src_size) {
666 size_t uncompressed_size = dst_size;
667 int ok = BrotliDecompressBuffer(src_size, src_buf,
668 &uncompressed_size, dst_buf);
669 if (!ok || uncompressed_size != dst_size) {
670 return FONT_COMPRESSION_FAILURE();
671 }
672 return true;
673 }
674
ReadShortDirectory(Buffer * file,std::vector<Table> * tables,size_t num_tables)675 bool ReadShortDirectory(Buffer* file, std::vector<Table>* tables,
676 size_t num_tables) {
677 for (size_t i = 0; i < num_tables; ++i) {
678 Table* table = &(*tables)[i];
679 uint8_t flag_byte;
680 if (!file->ReadU8(&flag_byte)) {
681 return FONT_COMPRESSION_FAILURE();
682 }
683 uint32_t tag;
684 if ((flag_byte & 0x3f) == 0x3f) {
685 if (!file->ReadU32(&tag)) {
686 return FONT_COMPRESSION_FAILURE();
687 }
688 } else {
689 tag = kKnownTags[flag_byte & 0x3f];
690 }
691 // Bits 6 and 7 are reserved and must be 0.
692 if ((flag_byte & 0xC0) != 0) {
693 return FONT_COMPRESSION_FAILURE();
694 }
695 uint32_t flags = 0;
696 if (i > 0) {
697 flags |= kWoff2FlagsContinueStream;
698 }
699 // Always transform the glyf and loca tables
700 if (tag == kGlyfTableTag || tag == kLocaTableTag) {
701 flags |= kWoff2FlagsTransform;
702 }
703 uint32_t dst_length;
704 if (!ReadBase128(file, &dst_length)) {
705 return FONT_COMPRESSION_FAILURE();
706 }
707 uint32_t transform_length = dst_length;
708 if ((flags & kWoff2FlagsTransform) != 0) {
709 if (!ReadBase128(file, &transform_length)) {
710 return FONT_COMPRESSION_FAILURE();
711 }
712 }
713 table->tag = tag;
714 table->flags = flags;
715 table->transform_length = transform_length;
716 table->dst_length = dst_length;
717 }
718 return true;
719 }
720
721 } // namespace
722
ComputeWOFF2FinalSize(const uint8_t * data,size_t length)723 size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) {
724 Buffer file(data, length);
725 uint32_t total_length;
726
727 if (!file.Skip(16) ||
728 !file.ReadU32(&total_length)) {
729 return 0;
730 }
731 return total_length;
732 }
733
ConvertWOFF2ToTTF(uint8_t * result,size_t result_length,const uint8_t * data,size_t length)734 bool ConvertWOFF2ToTTF(uint8_t* result, size_t result_length,
735 const uint8_t* data, size_t length) {
736 Buffer file(data, length);
737
738 uint32_t signature;
739 uint32_t flavor;
740 if (!file.ReadU32(&signature) || signature != kWoff2Signature ||
741 !file.ReadU32(&flavor)) {
742 return FONT_COMPRESSION_FAILURE();
743 }
744
745 // TODO(user): Should call IsValidVersionTag() here.
746
747 uint32_t reported_length;
748 if (!file.ReadU32(&reported_length) || length != reported_length) {
749 return FONT_COMPRESSION_FAILURE();
750 }
751 uint16_t num_tables;
752 if (!file.ReadU16(&num_tables) || !num_tables) {
753 return FONT_COMPRESSION_FAILURE();
754 }
755 // We don't care about these fields of the header:
756 // uint16_t reserved
757 // uint32_t total_sfnt_size
758 if (!file.Skip(6)) {
759 return FONT_COMPRESSION_FAILURE();
760 }
761 uint32_t compressed_length;
762 if (!file.ReadU32(&compressed_length)) {
763 return FONT_COMPRESSION_FAILURE();
764 }
765 // We don't care about these fields of the header:
766 // uint16_t major_version, minor_version
767 // uint32_t meta_offset, meta_length, meta_orig_length
768 // uint32_t priv_offset, priv_length
769 if (!file.Skip(24)) {
770 return FONT_COMPRESSION_FAILURE();
771 }
772 std::vector<Table> tables(num_tables);
773 // Note: change below to ReadLongDirectory to enable long format.
774 if (!ReadShortDirectory(&file, &tables, num_tables)) {
775 return FONT_COMPRESSION_FAILURE();
776 }
777 uint64_t src_offset = file.offset();
778 uint64_t dst_offset = kSfntHeaderSize +
779 kSfntEntrySize * static_cast<uint64_t>(num_tables);
780 uint64_t uncompressed_sum = 0;
781 for (uint16_t i = 0; i < num_tables; ++i) {
782 Table* table = &tables[i];
783 table->src_offset = src_offset;
784 table->src_length = (i == 0 ? compressed_length : 0);
785 src_offset += table->src_length;
786 if (src_offset > std::numeric_limits<uint32_t>::max()) {
787 return FONT_COMPRESSION_FAILURE();
788 }
789 src_offset = Round4(src_offset); // TODO: reconsider
790 table->dst_offset = dst_offset;
791 dst_offset += table->dst_length;
792 if (dst_offset > std::numeric_limits<uint32_t>::max()) {
793 return FONT_COMPRESSION_FAILURE();
794 }
795 dst_offset = Round4(dst_offset);
796
797 uncompressed_sum += table->src_length;
798 if (uncompressed_sum > std::numeric_limits<uint32_t>::max()) {
799 return FONT_COMPRESSION_FAILURE();
800 }
801 }
802 // Enforce same 30M limit on uncompressed tables as OTS
803 if (uncompressed_sum > 30 * 1024 * 1024) {
804 return FONT_COMPRESSION_FAILURE();
805 }
806 if (src_offset > length || dst_offset > result_length) {
807 return FONT_COMPRESSION_FAILURE();
808 }
809
810 const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables;
811 if (sfnt_header_and_table_directory_size > result_length) {
812 return FONT_COMPRESSION_FAILURE();
813 }
814
815 // Start building the font
816 size_t offset = 0;
817 offset = StoreU32(result, offset, flavor);
818 offset = Store16(result, offset, num_tables);
819 unsigned max_pow2 = 0;
820 while (1u << (max_pow2 + 1) <= num_tables) {
821 max_pow2++;
822 }
823 const uint16_t output_search_range = (1u << max_pow2) << 4;
824 offset = Store16(result, offset, output_search_range);
825 offset = Store16(result, offset, max_pow2);
826 offset = Store16(result, offset, (num_tables << 4) - output_search_range);
827 for (uint16_t i = 0; i < num_tables; ++i) {
828 const Table* table = &tables[i];
829 offset = StoreU32(result, offset, table->tag);
830 offset = StoreU32(result, offset, 0); // checksum, to fill in later
831 offset = StoreU32(result, offset, table->dst_offset);
832 offset = StoreU32(result, offset, table->dst_length);
833 }
834 std::vector<uint8_t> uncompressed_buf;
835 bool continue_valid = false;
836 const uint8_t* transform_buf = NULL;
837 for (uint16_t i = 0; i < num_tables; ++i) {
838 const Table* table = &tables[i];
839 uint32_t flags = table->flags;
840 const uint8_t* src_buf = data + table->src_offset;
841 size_t transform_length = table->transform_length;
842 if ((flags & kWoff2FlagsContinueStream) != 0) {
843 if (!continue_valid) {
844 return FONT_COMPRESSION_FAILURE();
845 }
846 } else if ((flags & kWoff2FlagsContinueStream) == 0) {
847 uint64_t total_size = transform_length;
848 for (uint16_t j = i + 1; j < num_tables; ++j) {
849 if ((tables[j].flags & kWoff2FlagsContinueStream) == 0) {
850 break;
851 }
852 total_size += tables[j].transform_length;
853 if (total_size > std::numeric_limits<uint32_t>::max()) {
854 return FONT_COMPRESSION_FAILURE();
855 }
856 }
857 uncompressed_buf.resize(total_size);
858 if (!Woff2Uncompress(&uncompressed_buf[0], total_size,
859 src_buf, compressed_length)) {
860 return FONT_COMPRESSION_FAILURE();
861 }
862 transform_buf = &uncompressed_buf[0];
863 continue_valid = true;
864 } else {
865 return FONT_COMPRESSION_FAILURE();
866 }
867
868 if ((flags & kWoff2FlagsTransform) == 0) {
869 if (transform_length != table->dst_length) {
870 return FONT_COMPRESSION_FAILURE();
871 }
872 if (static_cast<uint64_t>(table->dst_offset + transform_length) >
873 result_length) {
874 return FONT_COMPRESSION_FAILURE();
875 }
876 std::memcpy(result + table->dst_offset, transform_buf,
877 transform_length);
878 } else {
879 if (!ReconstructTransformed(tables, table->tag,
880 transform_buf, transform_length, result, result_length)) {
881 return FONT_COMPRESSION_FAILURE();
882 }
883 }
884 if (continue_valid) {
885 transform_buf += transform_length;
886 if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) {
887 return FONT_COMPRESSION_FAILURE();
888 }
889 }
890 }
891
892 return FixChecksums(tables, result);
893 }
894
895 } // namespace woff2
896