readable_font_data.cc revision 1bc53e167ca0bee0c89a938fe69e5bdb86b28d6b
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
27namespace sfntly {
28
29ReadableFontData::ReadableFontData(ByteArray* array)
30    : FontData(array),
31      checksum_set_(false),
32      checksum_(0) {
33}
34
35ReadableFontData::~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.
40CALLER_ATTACH
41ReadableFontData* 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
49int64_t ReadableFontData::Checksum() {
50  AutoLock lock(checksum_lock_);
51  if (!checksum_set_) {
52    ComputeChecksum();
53  }
54  return checksum_;
55}
56
57void ReadableFontData::SetCheckSumRanges(const IntegerList& ranges) {
58  checksum_range_ = ranges;
59  checksum_set_ = false;  // UNIMPLEMENTED: atomicity
60}
61
62int32_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
74int32_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
86int32_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
93int32_t ReadableFontData::ReadChar(int32_t index) {
94  return ReadUByte(index);
95}
96
97int32_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
107int32_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
119int32_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
132int64_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
148int32_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
158int64_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
174int32_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
190int32_t ReadableFontData::ReadFixed(int32_t index) {
191  return ReadLong(index);
192}
193
194int64_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
204int32_t ReadableFontData::ReadFWord(int32_t index) {
205  return ReadShort(index);
206}
207
208int32_t ReadableFontData::ReadFUFWord(int32_t index) {
209  return ReadUShort(index);
210}
211
212int32_t ReadableFontData::CopyTo(OutputStream* os) {
213  return array_->CopyTo(os, BoundOffset(0), Length());
214}
215
216int32_t ReadableFontData::CopyTo(WritableFontData* wfd) {
217  return array_->CopyTo(wfd->BoundOffset(0),
218                        wfd->array_,
219                        BoundOffset(0),
220                        Length());
221}
222
223int32_t ReadableFontData::CopyTo(ByteArray* ba) {
224  return array_->CopyTo(ba, BoundOffset(0), Length());
225}
226
227int32_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
258int32_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
282int32_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
314CALLER_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
329CALLER_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
341ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset)
342    : FontData(data, offset),
343      checksum_set_(false),
344      checksum_(0) {
345}
346
347ReadableFontData::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
355void 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
375int64_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