Line data Source code
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 :
29 0 : ReadableFontData::ReadableFontData(ByteArray* array)
30 : : FontData(array),
31 : checksum_set_(false),
32 0 : checksum_(0) {
33 0 : }
34 :
35 0 : 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
41 0 : ReadableFontData* ReadableFontData::CreateReadableFontData(ByteVector* b) {
42 0 : assert(b);
43 0 : ByteArrayPtr ba = new MemoryByteArray(b->size());
44 0 : ba->Put(0, b);
45 0 : ReadableFontDataPtr wfd = new ReadableFontData(ba);
46 0 : return wfd.Detach();
47 : }
48 :
49 0 : int64_t ReadableFontData::Checksum() {
50 0 : AutoLock lock(checksum_lock_);
51 0 : if (!checksum_set_) {
52 0 : ComputeChecksum();
53 : }
54 0 : return checksum_;
55 : }
56 :
57 0 : void ReadableFontData::SetCheckSumRanges(const IntegerList& ranges) {
58 0 : checksum_range_ = ranges;
59 0 : checksum_set_ = false; // UNIMPLEMENTED: atomicity
60 0 : }
61 :
62 0 : int32_t ReadableFontData::ReadUByte(int32_t index) {
63 0 : int32_t b = array_->Get(BoundOffset(index));
64 0 : 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 0 : return kInvalidUnsigned;
70 : }
71 0 : return b;
72 : }
73 :
74 0 : int32_t ReadableFontData::ReadByte(int32_t index) {
75 0 : int32_t b = array_->Get(BoundOffset(index));
76 0 : 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 0 : return kInvalidByte;
82 : }
83 0 : return (b << 24) >> 24;
84 : }
85 :
86 0 : int32_t ReadableFontData::ReadBytes(int32_t index,
87 : byte_t* b,
88 : int32_t offset,
89 : int32_t length) {
90 0 : return array_->Get(BoundOffset(index), b, offset, BoundLength(index, length));
91 : }
92 :
93 0 : int32_t ReadableFontData::ReadChar(int32_t index) {
94 0 : return ReadUByte(index);
95 : }
96 :
97 0 : int32_t ReadableFontData::ReadUShort(int32_t index) {
98 0 : int32_t b1 = ReadUByte(index);
99 0 : if (b1 < 0)
100 0 : return kInvalidUnsigned;
101 0 : int32_t b2 = ReadUByte(index + 1);
102 0 : if (b2 < 0)
103 0 : return kInvalidUnsigned;
104 0 : return 0xffff & (b1 << 8 | b2);
105 : }
106 :
107 0 : int32_t ReadableFontData::ReadShort(int32_t index) {
108 0 : int32_t b1 = ReadByte(index);
109 0 : if (b1 == kInvalidByte)
110 0 : return kInvalidShort;
111 0 : int32_t b2 = ReadUByte(index + 1);
112 0 : if (b2 < 0)
113 0 : return kInvalidShort;
114 :
115 0 : uint32_t result = static_cast<uint32_t>(b1) << 8 | b2;
116 0 : return static_cast<int32_t>(result << 16) >> 16;
117 : }
118 :
119 0 : int32_t ReadableFontData::ReadUInt24(int32_t index) {
120 0 : int32_t b1 = ReadUByte(index);
121 0 : if (b1 < 0)
122 0 : return kInvalidUnsigned;
123 0 : int32_t b2 = ReadUByte(index + 1);
124 0 : if (b2 < 0)
125 0 : return kInvalidUnsigned;
126 0 : int32_t b3 = ReadUByte(index + 2);
127 0 : if (b3 < 0)
128 0 : return kInvalidUnsigned;
129 0 : return 0xffffff & (b1 << 16 | b2 << 8 | b3);
130 : }
131 :
132 0 : int64_t ReadableFontData::ReadULong(int32_t index) {
133 0 : int32_t b1 = ReadUByte(index);
134 0 : if (b1 < 0)
135 0 : return kInvalidUnsigned;
136 0 : int32_t b2 = ReadUByte(index + 1);
137 0 : if (b2 < 0)
138 0 : return kInvalidUnsigned;
139 0 : int32_t b3 = ReadUByte(index + 2);
140 0 : if (b3 < 0)
141 0 : return kInvalidUnsigned;
142 0 : int32_t b4 = ReadUByte(index + 3);
143 0 : if (b4 < 0)
144 0 : return kInvalidUnsigned;
145 0 : return 0xffffffffL & (b1 << 24 | b2 << 16 | b3 << 8 | b4);
146 : }
147 :
148 0 : int32_t ReadableFontData::ReadULongAsInt(int32_t index) {
149 0 : 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 0 : return static_cast<int32_t>(ulong);
156 : }
157 :
158 0 : int64_t ReadableFontData::ReadULongLE(int32_t index) {
159 0 : int32_t b1 = ReadUByte(index);
160 0 : if (b1 < 0)
161 0 : return kInvalidUnsigned;
162 0 : int32_t b2 = ReadUByte(index + 1);
163 0 : if (b2 < 0)
164 0 : return kInvalidUnsigned;
165 0 : int32_t b3 = ReadUByte(index + 2);
166 0 : if (b3 < 0)
167 0 : return kInvalidUnsigned;
168 0 : int32_t b4 = ReadUByte(index + 3);
169 0 : if (b4 < 0)
170 0 : return kInvalidUnsigned;
171 0 : return 0xffffffffL & (b1 | b2 << 8 | b3 << 16 | b4 << 24);
172 : }
173 :
174 0 : int32_t ReadableFontData::ReadLong(int32_t index) {
175 0 : int32_t b1 = ReadByte(index);
176 0 : if (b1 == kInvalidByte)
177 0 : return kInvalidLong;
178 0 : int32_t b2 = ReadUByte(index + 1);
179 0 : if (b2 < 0)
180 0 : return kInvalidLong;
181 0 : int32_t b3 = ReadUByte(index + 2);
182 0 : if (b3 < 0)
183 0 : return kInvalidLong;
184 0 : int32_t b4 = ReadUByte(index + 3);
185 0 : if (b4 < 0)
186 0 : return kInvalidLong;
187 0 : return static_cast<uint32_t>(b1) << 24 | b2 << 16 | b3 << 8 | b4;
188 : }
189 :
190 0 : int32_t ReadableFontData::ReadFixed(int32_t index) {
191 0 : return ReadLong(index);
192 : }
193 :
194 0 : int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) {
195 0 : int32_t high = ReadULong(index);
196 0 : if (high == kInvalidUnsigned)
197 0 : return kInvalidLongDateTime;
198 0 : int32_t low = ReadULong(index + 4);
199 0 : if (low == kInvalidUnsigned)
200 0 : return kInvalidLongDateTime;
201 0 : return (int64_t)high << 32 | low;
202 : }
203 :
204 0 : int32_t ReadableFontData::ReadFWord(int32_t index) {
205 0 : return ReadShort(index);
206 : }
207 :
208 0 : int32_t ReadableFontData::ReadFUFWord(int32_t index) {
209 0 : return ReadUShort(index);
210 : }
211 :
212 0 : int32_t ReadableFontData::CopyTo(OutputStream* os) {
213 0 : return array_->CopyTo(os, BoundOffset(0), Length());
214 : }
215 :
216 0 : int32_t ReadableFontData::CopyTo(WritableFontData* wfd) {
217 0 : return array_->CopyTo(wfd->BoundOffset(0),
218 : wfd->array_,
219 : BoundOffset(0),
220 0 : Length());
221 : }
222 :
223 0 : int32_t ReadableFontData::CopyTo(ByteArray* ba) {
224 0 : return array_->CopyTo(ba, BoundOffset(0), Length());
225 : }
226 :
227 0 : 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 0 : int32_t location = 0;
234 0 : int32_t bottom = 0;
235 0 : int32_t top = length;
236 0 : while (top != bottom) {
237 0 : location = (top + bottom) / 2;
238 0 : int32_t location_start = ReadUShort(start_index + location * start_offset);
239 0 : if (key < location_start) {
240 : // location is below current location
241 0 : top = location;
242 : } else {
243 : // is key below the upper bound?
244 0 : 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 0 : if (key <= location_end)
249 0 : return location;
250 :
251 : // location is above the current location
252 0 : bottom = location + 1;
253 : }
254 : }
255 0 : return -1;
256 : }
257 :
258 0 : int32_t ReadableFontData::SearchUShort(int32_t start_index,
259 : int32_t start_offset,
260 : int32_t length,
261 : int32_t key) {
262 0 : int32_t location = 0;
263 0 : int32_t bottom = 0;
264 0 : int32_t top = length;
265 0 : while (top != bottom) {
266 0 : location = (top + bottom) / 2;
267 0 : int32_t location_start = ReadUShort(start_index + location * start_offset);
268 0 : if (key == location_start)
269 0 : return location;
270 :
271 0 : if (key < location_start) {
272 : // location is below current location
273 0 : top = location;
274 : } else {
275 : // location is above current location
276 0 : bottom = location + 1;
277 : }
278 : }
279 0 : return -1;
280 : }
281 :
282 0 : 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 0 : int32_t location = 0;
289 0 : int32_t bottom = 0;
290 0 : int32_t top = length;
291 0 : while (top != bottom) {
292 0 : location = (top + bottom) / 2;
293 0 : int32_t location_start = ReadULongAsInt(start_index
294 0 : + location * start_offset);
295 0 : if (key < location_start) {
296 : // location is below current location
297 0 : top = location;
298 : } else {
299 : // is key below the upper bound?
300 0 : 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 0 : if (key <= location_end)
305 0 : return location;
306 :
307 : // location is above the current location
308 0 : bottom = location + 1;
309 : }
310 : }
311 0 : return -1;
312 : }
313 :
314 0 : CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset,
315 : int32_t length) {
316 0 : if (offset < 0 || length < 0 ||
317 0 : offset > std::numeric_limits<int32_t>::max() - length ||
318 0 : offset + length > Size()) {
319 : #if !defined (SFNTLY_NO_EXCEPTION)
320 : throw IndexOutOfBoundsException(
321 : "Attempt to bind data outside of its limits");
322 : #endif
323 0 : return NULL;
324 : }
325 0 : FontDataPtr slice = new ReadableFontData(this, offset, length);
326 0 : return slice.Detach();
327 : }
328 :
329 0 : CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) {
330 0 : 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 0 : return NULL;
336 : }
337 0 : FontDataPtr slice = new ReadableFontData(this, offset);
338 0 : return slice.Detach();
339 : }
340 :
341 0 : ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset)
342 : : FontData(data, offset),
343 : checksum_set_(false),
344 0 : checksum_(0) {
345 0 : }
346 :
347 0 : ReadableFontData::ReadableFontData(ReadableFontData* data,
348 : int32_t offset,
349 0 : int32_t length)
350 : : FontData(data, offset, length),
351 : checksum_set_(false),
352 0 : checksum_(0) {
353 0 : }
354 :
355 0 : void ReadableFontData::ComputeChecksum() {
356 : // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity
357 0 : int64_t sum = 0;
358 0 : if (checksum_range_.empty()) {
359 0 : sum = ComputeCheckSum(0, Length());
360 : } else {
361 0 : for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size();
362 0 : low_bound_index += 2) {
363 0 : int32_t low_bound = checksum_range_[low_bound_index];
364 0 : int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ?
365 0 : Length() :
366 0 : checksum_range_[low_bound_index + 1];
367 0 : sum += ComputeCheckSum(low_bound, high_bound);
368 : }
369 : }
370 :
371 0 : checksum_ = sum & 0xffffffffL;
372 0 : checksum_set_ = true;
373 0 : }
374 :
375 0 : int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound,
376 : int32_t high_bound) {
377 0 : int64_t sum = 0;
378 : // Checksum all whole 4-byte chunks.
379 0 : for (int32_t i = low_bound; i <= high_bound - 4; i += 4) {
380 0 : sum += ReadULong(i);
381 : }
382 :
383 : // Add last fragment if not 4-byte multiple
384 0 : int32_t off = high_bound & -4;
385 0 : if (off < high_bound) {
386 0 : int32_t b3 = ReadUByte(off);
387 0 : int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0;
388 0 : int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0;
389 0 : int32_t b0 = 0;
390 0 : sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
391 : }
392 0 : return sum;
393 : }
394 :
395 : } // namespace sfntly
|