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