1 /*
2  * Copyright 2011 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "sfntly/data/readable_font_data.h"
18 
19 #include <stdio.h>
20 
21 #include <limits>
22 
23 #include "sfntly/data/memory_byte_array.h"
24 #include "sfntly/data/writable_font_data.h"
25 #include "sfntly/port/exception_type.h"
26 
27 namespace sfntly {
28 
ReadableFontData(ByteArray * array)29 ReadableFontData::ReadableFontData(ByteArray* array)
30     : FontData(array),
31       checksum_set_(false),
32       checksum_(0) {
33 }
34 
~ReadableFontData()35 ReadableFontData::~ReadableFontData() {}
36 
37 // TODO(arthurhsu): re-investigate the memory model of this function.  It's
38 //                  not too useful without copying, but it's not performance
39 //                  savvy to do copying.
40 CALLER_ATTACH
CreateReadableFontData(ByteVector * b)41 ReadableFontData* ReadableFontData::CreateReadableFontData(ByteVector* b) {
42   assert(b);
43   ByteArrayPtr ba = new MemoryByteArray(b->size());
44   ba->Put(0, b);
45   ReadableFontDataPtr wfd = new ReadableFontData(ba);
46   return wfd.Detach();
47 }
48 
Checksum()49 int64_t ReadableFontData::Checksum() {
50   AutoLock lock(checksum_lock_);
51   if (!checksum_set_) {
52     ComputeChecksum();
53   }
54   return checksum_;
55 }
56 
SetCheckSumRanges(const IntegerList & ranges)57 void ReadableFontData::SetCheckSumRanges(const IntegerList& ranges) {
58   checksum_range_ = ranges;
59   checksum_set_ = false;  // UNIMPLEMENTED: atomicity
60 }
61 
ReadUByte(int32_t index)62 int32_t ReadableFontData::ReadUByte(int32_t index) {
63   int32_t b = array_->Get(BoundOffset(index));
64   if (b < 0) {
65 #if !defined (SFNTLY_NO_EXCEPTION)
66     throw IndexOutOfBoundException(
67         "Index attempted to be read from is out of bounds", index);
68 #endif
69     return kInvalidUnsigned;
70   }
71   return b;
72 }
73 
ReadByte(int32_t index)74 int32_t ReadableFontData::ReadByte(int32_t index) {
75   int32_t b = array_->Get(BoundOffset(index));
76   if (b < 0) {
77 #if !defined (SFNTLY_NO_EXCEPTION)
78     throw IndexOutOfBoundException(
79         "Index attempted to be read from is out of bounds", index);
80 #endif
81     return kInvalidByte;
82   }
83   return (b << 24) >> 24;
84 }
85 
ReadBytes(int32_t index,byte_t * b,int32_t offset,int32_t length)86 int32_t ReadableFontData::ReadBytes(int32_t index,
87                                     byte_t* b,
88                                     int32_t offset,
89                                     int32_t length) {
90   return array_->Get(BoundOffset(index), b, offset, BoundLength(index, length));
91 }
92 
ReadChar(int32_t index)93 int32_t ReadableFontData::ReadChar(int32_t index) {
94   return ReadUByte(index);
95 }
96 
ReadUShort(int32_t index)97 int32_t ReadableFontData::ReadUShort(int32_t index) {
98   int32_t b1 = ReadUByte(index);
99   if (b1 < 0)
100     return kInvalidUnsigned;
101   int32_t b2 = ReadUByte(index + 1);
102   if (b2 < 0)
103     return kInvalidUnsigned;
104   return 0xffff & (b1 << 8 | b2);
105 }
106 
ReadShort(int32_t index)107 int32_t ReadableFontData::ReadShort(int32_t index) {
108   int32_t b1 = ReadByte(index);
109   if (b1 == kInvalidByte)
110     return kInvalidShort;
111   int32_t b2 = ReadUByte(index + 1);
112   if (b2 < 0)
113     return kInvalidShort;
114 
115   uint32_t result = static_cast<uint32_t>(b1) << 8 | b2;
116   return static_cast<int32_t>(result << 16) >> 16;
117 }
118 
ReadUInt24(int32_t index)119 int32_t ReadableFontData::ReadUInt24(int32_t index) {
120   int32_t b1 = ReadUByte(index);
121   if (b1 < 0)
122     return kInvalidUnsigned;
123   int32_t b2 = ReadUByte(index + 1);
124   if (b2 < 0)
125     return kInvalidUnsigned;
126   int32_t b3 = ReadUByte(index + 2);
127   if (b3 < 0)
128     return kInvalidUnsigned;
129   return 0xffffff & (b1 << 16 | b2 << 8 | b3);
130 }
131 
ReadULong(int32_t index)132 int64_t ReadableFontData::ReadULong(int32_t index) {
133   int32_t b1 = ReadUByte(index);
134   if (b1 < 0)
135     return kInvalidUnsigned;
136   int32_t b2 = ReadUByte(index + 1);
137   if (b2 < 0)
138     return kInvalidUnsigned;
139   int32_t b3 = ReadUByte(index + 2);
140   if (b3 < 0)
141     return kInvalidUnsigned;
142   int32_t b4 = ReadUByte(index + 3);
143   if (b4 < 0)
144     return kInvalidUnsigned;
145   return 0xffffffffL & (b1 << 24 | b2 << 16 | b3 << 8 | b4);
146 }
147 
ReadULongAsInt(int32_t index)148 int32_t ReadableFontData::ReadULongAsInt(int32_t index) {
149   int64_t ulong = ReadULong(index);
150 #if !defined (SFNTLY_NO_EXCEPTION)
151   if ((ulong & 0x80000000) == 0x80000000) {
152     throw ArithmeticException("Long value too large to fit into an integer.");
153   }
154 #endif
155   return static_cast<int32_t>(ulong);
156 }
157 
ReadULongLE(int32_t index)158 int64_t ReadableFontData::ReadULongLE(int32_t index) {
159   int32_t b1 = ReadUByte(index);
160   if (b1 < 0)
161     return kInvalidUnsigned;
162   int32_t b2 = ReadUByte(index + 1);
163   if (b2 < 0)
164     return kInvalidUnsigned;
165   int32_t b3 = ReadUByte(index + 2);
166   if (b3 < 0)
167     return kInvalidUnsigned;
168   int32_t b4 = ReadUByte(index + 3);
169   if (b4 < 0)
170     return kInvalidUnsigned;
171   return 0xffffffffL & (b1 | b2 << 8 | b3 << 16 | b4 << 24);
172 }
173 
ReadLong(int32_t index)174 int32_t ReadableFontData::ReadLong(int32_t index) {
175   int32_t b1 = ReadByte(index);
176   if (b1 == kInvalidByte)
177     return kInvalidLong;
178   int32_t b2 = ReadUByte(index + 1);
179   if (b2 < 0)
180     return kInvalidLong;
181   int32_t b3 = ReadUByte(index + 2);
182   if (b3 < 0)
183     return kInvalidLong;
184   int32_t b4 = ReadUByte(index + 3);
185   if (b4 < 0)
186     return kInvalidLong;
187   return static_cast<uint32_t>(b1) << 24 | b2 << 16 | b3 << 8 | b4;
188 }
189 
ReadFixed(int32_t index)190 int32_t ReadableFontData::ReadFixed(int32_t index) {
191   return ReadLong(index);
192 }
193 
ReadDateTimeAsLong(int32_t index)194 int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) {
195   int32_t high = ReadULong(index);
196   if (high == kInvalidUnsigned)
197     return kInvalidLongDateTime;
198   int32_t low = ReadULong(index + 4);
199   if (low == kInvalidUnsigned)
200     return kInvalidLongDateTime;
201   return (int64_t)high << 32 | low;
202 }
203 
ReadFWord(int32_t index)204 int32_t ReadableFontData::ReadFWord(int32_t index) {
205   return ReadShort(index);
206 }
207 
ReadFUFWord(int32_t index)208 int32_t ReadableFontData::ReadFUFWord(int32_t index) {
209   return ReadUShort(index);
210 }
211 
CopyTo(OutputStream * os)212 int32_t ReadableFontData::CopyTo(OutputStream* os) {
213   return array_->CopyTo(os, BoundOffset(0), Length());
214 }
215 
CopyTo(WritableFontData * wfd)216 int32_t ReadableFontData::CopyTo(WritableFontData* wfd) {
217   return array_->CopyTo(wfd->BoundOffset(0),
218                         wfd->array_,
219                         BoundOffset(0),
220                         Length());
221 }
222 
CopyTo(ByteArray * ba)223 int32_t ReadableFontData::CopyTo(ByteArray* ba) {
224   return array_->CopyTo(ba, BoundOffset(0), Length());
225 }
226 
SearchUShort(int32_t start_index,int32_t start_offset,int32_t end_index,int32_t end_offset,int32_t length,int32_t key)227 int32_t ReadableFontData::SearchUShort(int32_t start_index,
228                                        int32_t start_offset,
229                                        int32_t end_index,
230                                        int32_t end_offset,
231                                        int32_t length,
232                                        int32_t key) {
233   int32_t location = 0;
234   int32_t bottom = 0;
235   int32_t top = length;
236   while (top != bottom) {
237     location = (top + bottom) / 2;
238     int32_t location_start = ReadUShort(start_index + location * start_offset);
239     if (key < location_start) {
240       // location is below current location
241       top = location;
242     } else {
243       // is key below the upper bound?
244       int32_t location_end = ReadUShort(end_index + location * end_offset);
245 #if defined (SFNTLY_DEBUG_FONTDATA)
246       fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
247 #endif
248       if (key <= location_end)
249         return location;
250 
251       // location is above the current location
252       bottom = location + 1;
253     }
254   }
255   return -1;
256 }
257 
SearchUShort(int32_t start_index,int32_t start_offset,int32_t length,int32_t key)258 int32_t ReadableFontData::SearchUShort(int32_t start_index,
259                                        int32_t start_offset,
260                                        int32_t length,
261                                        int32_t key) {
262   int32_t location = 0;
263   int32_t bottom = 0;
264   int32_t top = length;
265   while (top != bottom) {
266     location = (top + bottom) / 2;
267     int32_t location_start = ReadUShort(start_index + location * start_offset);
268     if (key == location_start)
269       return location;
270 
271     if (key < location_start) {
272       // location is below current location
273       top = location;
274     } else {
275       // location is above current location
276       bottom = location + 1;
277     }
278   }
279   return -1;
280 }
281 
SearchULong(int32_t start_index,int32_t start_offset,int32_t end_index,int32_t end_offset,int32_t length,int32_t key)282 int32_t ReadableFontData::SearchULong(int32_t start_index,
283                                       int32_t start_offset,
284                                       int32_t end_index,
285                                       int32_t end_offset,
286                                       int32_t length,
287                                       int32_t key) {
288   int32_t location = 0;
289   int32_t bottom = 0;
290   int32_t top = length;
291   while (top != bottom) {
292     location = (top + bottom) / 2;
293     int32_t location_start = ReadULongAsInt(start_index
294                                             + location * start_offset);
295     if (key < location_start) {
296       // location is below current location
297       top = location;
298     } else {
299       // is key below the upper bound?
300       int32_t location_end = ReadULongAsInt(end_index + location * end_offset);
301 #if defined (SFNTLY_DEBUG_FONTDATA)
302       fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
303 #endif
304       if (key <= location_end)
305         return location;
306 
307       // location is above the current location
308       bottom = location + 1;
309     }
310   }
311   return -1;
312 }
313 
Slice(int32_t offset,int32_t length)314 CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset,
315                                                 int32_t length) {
316   if (offset < 0 || length < 0 ||
317       offset > std::numeric_limits<int32_t>::max() - length ||
318       offset + length > Size()) {
319 #if !defined (SFNTLY_NO_EXCEPTION)
320     throw IndexOutOfBoundsException(
321         "Attempt to bind data outside of its limits");
322 #endif
323     return NULL;
324   }
325   FontDataPtr slice = new ReadableFontData(this, offset, length);
326   return slice.Detach();
327 }
328 
Slice(int32_t offset)329 CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) {
330   if (offset < 0 || offset > Size()) {
331 #if !defined (SFNTLY_NO_EXCEPTION)
332     throw IndexOutOfBoundsException(
333         "Attempt to bind data outside of its limits");
334 #endif
335     return NULL;
336   }
337   FontDataPtr slice = new ReadableFontData(this, offset);
338   return slice.Detach();
339 }
340 
ReadableFontData(ReadableFontData * data,int32_t offset)341 ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset)
342     : FontData(data, offset),
343       checksum_set_(false),
344       checksum_(0) {
345 }
346 
ReadableFontData(ReadableFontData * data,int32_t offset,int32_t length)347 ReadableFontData::ReadableFontData(ReadableFontData* data,
348                                    int32_t offset,
349                                    int32_t length)
350     : FontData(data, offset, length),
351       checksum_set_(false),
352       checksum_(0) {
353 }
354 
ComputeChecksum()355 void ReadableFontData::ComputeChecksum() {
356   // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity
357   int64_t sum = 0;
358   if (checksum_range_.empty()) {
359     sum = ComputeCheckSum(0, Length());
360   } else {
361     for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size();
362          low_bound_index += 2) {
363       int32_t low_bound = checksum_range_[low_bound_index];
364       int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ?
365                                 Length() :
366                                 checksum_range_[low_bound_index + 1];
367       sum += ComputeCheckSum(low_bound, high_bound);
368     }
369   }
370 
371   checksum_ = sum & 0xffffffffL;
372   checksum_set_ = true;
373 }
374 
ComputeCheckSum(int32_t low_bound,int32_t high_bound)375 int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound,
376                                           int32_t high_bound) {
377   int64_t sum = 0;
378   // Checksum all whole 4-byte chunks.
379   for (int32_t i = low_bound; i <= high_bound - 4; i += 4) {
380     sum += ReadULong(i);
381   }
382 
383   // Add last fragment if not 4-byte multiple
384   int32_t off = high_bound & -4;
385   if (off < high_bound) {
386     int32_t b3 = ReadUByte(off);
387     int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0;
388     int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0;
389     int32_t b0 = 0;
390     sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
391   }
392   return sum;
393 }
394 
395 }  // namespace sfntly
396