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