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