readable_font_data.cc revision 529b91d37af56176354f05229a86bfa87ff1fb00
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 !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
71int32_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
82int32_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
89int32_t ReadableFontData::ReadChar(int32_t index) {
90  return ReadUByte(index);
91}
92
93int32_t ReadableFontData::ReadUShort(int32_t index) {
94  return 0xffff & (ReadUByte(index) << 8 | ReadUByte(index + 1));
95}
96
97int32_t ReadableFontData::ReadShort(int32_t index) {
98  return ((ReadByte(index) << 8 | ReadUByte(index + 1)) << 16) >> 16;
99}
100
101int32_t ReadableFontData::ReadUInt24(int32_t index) {
102  return 0xffffff & (ReadUByte(index) << 16 |
103                     ReadUByte(index + 1) << 8 |
104                     ReadUByte(index + 2));
105}
106
107int64_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
114int32_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
124int32_t ReadableFontData::ReadLong(int32_t index) {
125  return ReadByte(index) << 24 |
126         ReadUByte(index + 1) << 16 |
127         ReadUByte(index + 2) << 8 |
128         ReadUByte(index + 3);
129}
130
131int32_t ReadableFontData::ReadFixed(int32_t index) {
132  return ReadLong(index);
133}
134
135int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) {
136  return (int64_t)ReadULong(index) << 32 | ReadULong(index + 4);
137}
138
139int32_t ReadableFontData::ReadFWord(int32_t index) {
140  return ReadShort(index);
141}
142
143int32_t ReadableFontData::ReadFUFWord(int32_t index) {
144  return ReadUShort(index);
145}
146
147int32_t ReadableFontData::CopyTo(OutputStream* os) {
148  return array_->CopyTo(os, BoundOffset(0), Length());
149}
150
151int32_t ReadableFontData::CopyTo(WritableFontData* wfd) {
152  return array_->CopyTo(wfd->BoundOffset(0),
153                        wfd->array_,
154                        BoundOffset(0),
155                        Length());
156}
157
158int32_t ReadableFontData::CopyTo(ByteArray* ba) {
159  return array_->CopyTo(ba, BoundOffset(0), Length());
160}
161
162int32_t ReadableFontData::SearchUShort(int32_t start_index,
163                                       int32_t start_offset,
164                                       int32_t end_index,
165                                       int32_t end_offset,
166                                       int32_t length,
167                                       int32_t key) {
168  int32_t location = 0;
169  int32_t bottom = 0;
170  int32_t top = length;
171  while (top != bottom) {
172    location = (top + bottom) / 2;
173    int32_t location_start = ReadUShort(start_index + location * start_offset);
174    if (key < location_start) {
175      // location is below current location
176      top = location;
177    } else {
178      // is key below the upper bound?
179      int32_t location_end = ReadUShort(end_index + location * end_offset);
180#if defined (SFNTLY_DEBUG_FONTDATA)
181      fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
182#endif
183      if (key <= location_end) {
184        return location;
185      } else {
186        // location is above the current location
187        bottom = location + 1;
188      }
189    }
190  }
191  return -1;
192}
193
194int32_t ReadableFontData::SearchUShort(int32_t start_index,
195                                       int32_t start_offset,
196                                       int32_t length,
197                                       int32_t key) {
198  int32_t location = 0;
199  int32_t bottom = 0;
200  int32_t top = length;
201  while (top != bottom) {
202    location = (top + bottom) / 2;
203    int32_t location_start = ReadUShort(start_index + location * start_offset);
204    if (key < location_start) {
205      // location is below current location
206      top = location;
207    } else if (key > location_start) {
208      // location is above current location
209      bottom = location + 1;
210    } else {
211      return location;
212    }
213  }
214  return -1;
215}
216
217int32_t ReadableFontData::SearchULong(int32_t start_index,
218                                      int32_t start_offset,
219                                      int32_t end_index,
220                                      int32_t end_offset,
221                                      int32_t length,
222                                      int32_t key) {
223  int32_t location = 0;
224  int32_t bottom = 0;
225  int32_t top = length;
226  while (top != bottom) {
227    location = (top + bottom) / 2;
228    int32_t location_start = ReadULongAsInt(start_index
229                                            + location * start_offset);
230    if (key < location_start) {
231      // location is below current location
232      top = location;
233    } else {
234      // is key below the upper bound?
235      int32_t location_end = ReadULongAsInt(end_index + location * end_offset);
236#if defined (SFNTLY_DEBUG_FONTDATA)
237      fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
238#endif
239      if (key <= location_end) {
240        return location;
241      } else {
242        // location is above the current location
243        bottom = location + 1;
244      }
245    }
246  }
247  return -1;
248}
249
250CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset,
251                                                int32_t length) {
252  if (offset < 0 || offset + length > Size()) {
253    return NULL;
254  }
255  FontDataPtr slice = new ReadableFontData(this, offset, length);
256  // Note: exception not ported because the condition is always false in C++.
257  // if (slice == null) { throw new IndexOutOfBoundsException( ...
258  return slice.Detach();
259}
260
261CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) {
262  if (offset < 0 || offset > Size()) {
263    return NULL;
264  }
265  FontDataPtr slice = new ReadableFontData(this, offset);
266  // Note: exception not ported because the condition is always false in C++.
267  // if (slice == null) { throw new IndexOutOfBoundsException( ...
268  return slice.Detach();
269}
270
271ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset)
272    : FontData(data, offset),
273      checksum_set_(false),
274      checksum_(0) {
275}
276
277ReadableFontData::ReadableFontData(ReadableFontData* data,
278                                   int32_t offset,
279                                   int32_t length)
280    : FontData(data, offset, length),
281      checksum_set_(false),
282      checksum_(0) {
283}
284
285void ReadableFontData::ComputeChecksum() {
286  // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity
287  int64_t sum = 0;
288  if (checksum_range_.empty()) {
289    sum = ComputeCheckSum(0, Length());
290  } else {
291    for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size();
292         low_bound_index += 2) {
293      int32_t low_bound = checksum_range_[low_bound_index];
294      int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ?
295                                Length() :
296                                checksum_range_[low_bound_index + 1];
297      sum += ComputeCheckSum(low_bound, high_bound);
298    }
299  }
300
301  checksum_ = sum & 0xffffffffL;
302  checksum_set_ = true;
303}
304
305int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound,
306                                          int32_t high_bound) {
307  int64_t sum = 0;
308  // Checksum all whole 4-byte chunks.
309  for (int32_t i = low_bound; i <= high_bound - 4; i += 4) {
310    sum += ReadULong(i);
311  }
312
313  // Add last fragment if not 4-byte multiple
314  int32_t off = high_bound & -4;
315  if (off < high_bound) {
316    int32_t b3 = ReadUByte(off);
317    int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0;
318    int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0;
319    int32_t b0 = 0;
320    sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
321  }
322  return sum;
323}
324
325}  // namespace sfntly
326