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 "sfntly/data/memory_byte_array.h"
22 #include "sfntly/data/writable_font_data.h"
23 #include "sfntly/port/exception_type.h"
24
25 namespace sfntly {
26
ReadableFontData(ByteArray * array)27 ReadableFontData::ReadableFontData(ByteArray* array)
28 : FontData(array),
29 checksum_set_(false),
30 checksum_(0) {
31 }
32
~ReadableFontData()33 ReadableFontData::~ReadableFontData() {}
34
35 // TODO(arthurhsu): re-investigate the memory model of this function. It's
36 // not too useful without copying, but it's not performance
37 // savvy to do copying.
38 CALLER_ATTACH
CreateReadableFontData(ByteVector * b)39 ReadableFontData* ReadableFontData::CreateReadableFontData(ByteVector* b) {
40 assert(b);
41 ByteArrayPtr ba = new MemoryByteArray(b->size());
42 ba->Put(0, b);
43 ReadableFontDataPtr wfd = new ReadableFontData(ba);
44 return wfd.Detach();
45 }
46
Checksum()47 int64_t ReadableFontData::Checksum() {
48 AutoLock lock(checksum_lock_);
49 if (!checksum_set_) {
50 ComputeChecksum();
51 }
52 return checksum_;
53 }
54
SetCheckSumRanges(const IntegerList & ranges)55 void ReadableFontData::SetCheckSumRanges(const IntegerList& ranges) {
56 checksum_range_ = ranges;
57 checksum_set_ = false; // UNIMPLEMENTED: atomicity
58 }
59
ReadUByte(int32_t index)60 int32_t ReadableFontData::ReadUByte(int32_t index) {
61 int32_t b = array_->Get(BoundOffset(index));
62 #if !defined (SFNTLY_NO_EXCEPTION)
63 if (b < 0) {
64 throw IndexOutOfBoundException(
65 "Index attempted to be read from is out of bounds", index);
66 }
67 #endif
68 return b;
69 }
70
ReadByte(int32_t index)71 int32_t ReadableFontData::ReadByte(int32_t index) {
72 int32_t b = array_->Get(BoundOffset(index));
73 #if !defined (SFNTLY_NO_EXCEPTION)
74 if (b < 0) {
75 throw IndexOutOfBoundException(
76 "Index attempted to be read from is out of bounds", index);
77 }
78 #endif
79 return (b << 24) >> 24;
80 }
81
ReadBytes(int32_t index,byte_t * b,int32_t offset,int32_t length)82 int32_t ReadableFontData::ReadBytes(int32_t index,
83 byte_t* b,
84 int32_t offset,
85 int32_t length) {
86 return array_->Get(BoundOffset(index), b, offset, BoundLength(index, length));
87 }
88
ReadChar(int32_t index)89 int32_t ReadableFontData::ReadChar(int32_t index) {
90 return ReadUByte(index);
91 }
92
ReadUShort(int32_t index)93 int32_t ReadableFontData::ReadUShort(int32_t index) {
94 return 0xffff & (ReadUByte(index) << 8 | ReadUByte(index + 1));
95 }
96
ReadShort(int32_t index)97 int32_t ReadableFontData::ReadShort(int32_t index) {
98 return ((ReadByte(index) << 8 | ReadUByte(index + 1)) << 16) >> 16;
99 }
100
ReadUInt24(int32_t index)101 int32_t ReadableFontData::ReadUInt24(int32_t index) {
102 return 0xffffff & (ReadUByte(index) << 16 |
103 ReadUByte(index + 1) << 8 |
104 ReadUByte(index + 2));
105 }
106
ReadULong(int32_t index)107 int64_t ReadableFontData::ReadULong(int32_t index) {
108 return 0xffffffffL & (ReadUByte(index) << 24 |
109 ReadUByte(index + 1) << 16 |
110 ReadUByte(index + 2) << 8 |
111 ReadUByte(index + 3));
112 }
113
ReadULongAsInt(int32_t index)114 int32_t ReadableFontData::ReadULongAsInt(int32_t index) {
115 int64_t ulong = ReadULong(index);
116 #if !defined (SFNTLY_NO_EXCEPTION)
117 if ((ulong & 0x80000000) == 0x80000000) {
118 throw ArithmeticException("Long value too large to fit into an integer.");
119 }
120 #endif
121 return static_cast<int32_t>(ulong);
122 }
123
ReadULongLE(int32_t index)124 int64_t ReadableFontData::ReadULongLE(int32_t index) {
125 return 0xffffffffL & (ReadUByte(index) |
126 ReadUByte(index + 1) << 8 |
127 ReadUByte(index + 2) << 16 |
128 ReadUByte(index + 3) << 24);
129 }
130
ReadLong(int32_t index)131 int32_t ReadableFontData::ReadLong(int32_t index) {
132 return ReadByte(index) << 24 |
133 ReadUByte(index + 1) << 16 |
134 ReadUByte(index + 2) << 8 |
135 ReadUByte(index + 3);
136 }
137
ReadFixed(int32_t index)138 int32_t ReadableFontData::ReadFixed(int32_t index) {
139 return ReadLong(index);
140 }
141
ReadDateTimeAsLong(int32_t index)142 int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) {
143 return (int64_t)ReadULong(index) << 32 | ReadULong(index + 4);
144 }
145
ReadFWord(int32_t index)146 int32_t ReadableFontData::ReadFWord(int32_t index) {
147 return ReadShort(index);
148 }
149
ReadFUFWord(int32_t index)150 int32_t ReadableFontData::ReadFUFWord(int32_t index) {
151 return ReadUShort(index);
152 }
153
CopyTo(OutputStream * os)154 int32_t ReadableFontData::CopyTo(OutputStream* os) {
155 return array_->CopyTo(os, BoundOffset(0), Length());
156 }
157
CopyTo(WritableFontData * wfd)158 int32_t ReadableFontData::CopyTo(WritableFontData* wfd) {
159 return array_->CopyTo(wfd->BoundOffset(0),
160 wfd->array_,
161 BoundOffset(0),
162 Length());
163 }
164
CopyTo(ByteArray * ba)165 int32_t ReadableFontData::CopyTo(ByteArray* ba) {
166 return array_->CopyTo(ba, BoundOffset(0), Length());
167 }
168
SearchUShort(int32_t start_index,int32_t start_offset,int32_t end_index,int32_t end_offset,int32_t length,int32_t key)169 int32_t ReadableFontData::SearchUShort(int32_t start_index,
170 int32_t start_offset,
171 int32_t end_index,
172 int32_t end_offset,
173 int32_t length,
174 int32_t key) {
175 int32_t location = 0;
176 int32_t bottom = 0;
177 int32_t top = length;
178 while (top != bottom) {
179 location = (top + bottom) / 2;
180 int32_t location_start = ReadUShort(start_index + location * start_offset);
181 if (key < location_start) {
182 // location is below current location
183 top = location;
184 } else {
185 // is key below the upper bound?
186 int32_t location_end = ReadUShort(end_index + location * end_offset);
187 #if defined (SFNTLY_DEBUG_FONTDATA)
188 fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
189 #endif
190 if (key <= location_end) {
191 return location;
192 } else {
193 // location is above the current location
194 bottom = location + 1;
195 }
196 }
197 }
198 return -1;
199 }
200
SearchUShort(int32_t start_index,int32_t start_offset,int32_t length,int32_t key)201 int32_t ReadableFontData::SearchUShort(int32_t start_index,
202 int32_t start_offset,
203 int32_t length,
204 int32_t key) {
205 int32_t location = 0;
206 int32_t bottom = 0;
207 int32_t top = length;
208 while (top != bottom) {
209 location = (top + bottom) / 2;
210 int32_t location_start = ReadUShort(start_index + location * start_offset);
211 if (key < location_start) {
212 // location is below current location
213 top = location;
214 } else if (key > location_start) {
215 // location is above current location
216 bottom = location + 1;
217 } else {
218 return location;
219 }
220 }
221 return -1;
222 }
223
SearchULong(int32_t start_index,int32_t start_offset,int32_t end_index,int32_t end_offset,int32_t length,int32_t key)224 int32_t ReadableFontData::SearchULong(int32_t start_index,
225 int32_t start_offset,
226 int32_t end_index,
227 int32_t end_offset,
228 int32_t length,
229 int32_t key) {
230 int32_t location = 0;
231 int32_t bottom = 0;
232 int32_t top = length;
233 while (top != bottom) {
234 location = (top + bottom) / 2;
235 int32_t location_start = ReadULongAsInt(start_index
236 + location * start_offset);
237 if (key < location_start) {
238 // location is below current location
239 top = location;
240 } else {
241 // is key below the upper bound?
242 int32_t location_end = ReadULongAsInt(end_index + location * end_offset);
243 #if defined (SFNTLY_DEBUG_FONTDATA)
244 fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
245 #endif
246 if (key <= location_end) {
247 return location;
248 } else {
249 // location is above the current location
250 bottom = location + 1;
251 }
252 }
253 }
254 return -1;
255 }
256
Slice(int32_t offset,int32_t length)257 CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset,
258 int32_t length) {
259 if (offset < 0 || offset + length > Size()) {
260 #if !defined (SFNTLY_NO_EXCEPTION)
261 throw IndexOutOfBoundsException(
262 "Attempt to bind data outside of its limits");
263 #endif
264 return NULL;
265 }
266 FontDataPtr slice = new ReadableFontData(this, offset, length);
267 return slice.Detach();
268 }
269
Slice(int32_t offset)270 CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) {
271 if (offset < 0 || offset > Size()) {
272 #if !defined (SFNTLY_NO_EXCEPTION)
273 throw IndexOutOfBoundsException(
274 "Attempt to bind data outside of its limits");
275 #endif
276 return NULL;
277 }
278 FontDataPtr slice = new ReadableFontData(this, offset);
279 return slice.Detach();
280 }
281
ReadableFontData(ReadableFontData * data,int32_t offset)282 ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset)
283 : FontData(data, offset),
284 checksum_set_(false),
285 checksum_(0) {
286 }
287
ReadableFontData(ReadableFontData * data,int32_t offset,int32_t length)288 ReadableFontData::ReadableFontData(ReadableFontData* data,
289 int32_t offset,
290 int32_t length)
291 : FontData(data, offset, length),
292 checksum_set_(false),
293 checksum_(0) {
294 }
295
ComputeChecksum()296 void ReadableFontData::ComputeChecksum() {
297 // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity
298 int64_t sum = 0;
299 if (checksum_range_.empty()) {
300 sum = ComputeCheckSum(0, Length());
301 } else {
302 for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size();
303 low_bound_index += 2) {
304 int32_t low_bound = checksum_range_[low_bound_index];
305 int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ?
306 Length() :
307 checksum_range_[low_bound_index + 1];
308 sum += ComputeCheckSum(low_bound, high_bound);
309 }
310 }
311
312 checksum_ = sum & 0xffffffffL;
313 checksum_set_ = true;
314 }
315
ComputeCheckSum(int32_t low_bound,int32_t high_bound)316 int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound,
317 int32_t high_bound) {
318 int64_t sum = 0;
319 // Checksum all whole 4-byte chunks.
320 for (int32_t i = low_bound; i <= high_bound - 4; i += 4) {
321 sum += ReadULong(i);
322 }
323
324 // Add last fragment if not 4-byte multiple
325 int32_t off = high_bound & -4;
326 if (off < high_bound) {
327 int32_t b3 = ReadUByte(off);
328 int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0;
329 int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0;
330 int32_t b0 = 0;
331 sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
332 }
333 return sum;
334 }
335
336 } // namespace sfntly
337