• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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