1464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com/*
2464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com * Copyright 2011 Google Inc. All Rights Reserved.
3464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com *
4464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com * Licensed under the Apache License, Version 2.0 (the "License");
5464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com * you may not use this file except in compliance with the License.
6464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com * You may obtain a copy of the License at
7464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com *
8464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com *      http://www.apache.org/licenses/LICENSE-2.0
9464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com *
10464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com * Unless required by applicable law or agreed to in writing, software
11464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com * distributed under the License is distributed on an "AS IS" BASIS,
12464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com * See the License for the specific language governing permissions and
14464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com * limitations under the License.
15464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com */
16464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
17464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com#include "sfntly/data/readable_font_data.h"
18760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com
19760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com#include <stdio.h>
20760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com
2109f3dda615ba59d0b686e8c36f1e8426b9235746arthurhsu@google.com#include "sfntly/data/memory_byte_array.h"
22464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com#include "sfntly/data/writable_font_data.h"
23464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com#include "sfntly/port/exception_type.h"
24464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
25464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.comnamespace sfntly {
26464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
27464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.comReadableFontData::ReadableFontData(ByteArray* array)
28246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com    : FontData(array),
29246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com      checksum_set_(false),
30246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com      checksum_(0) {
31464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
32464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
33246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comReadableFontData::~ReadableFontData() {}
34464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
3532a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com// TODO(arthurhsu): re-investigate the memory model of this function.  It's
3632a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com//                  not too useful without copying, but it's not performance
3732a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com//                  savvy to do copying.
3832a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.comCALLER_ATTACH
3932a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.comReadableFontData* ReadableFontData::CreateReadableFontData(ByteVector* b) {
4032a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  assert(b);
4132a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  ByteArrayPtr ba = new MemoryByteArray(b->size());
4232a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  ba->Put(0, b);
4332a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  ReadableFontDataPtr wfd = new ReadableFontData(ba);
4432a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  return wfd.Detach();
4532a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com}
4632a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com
47246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint64_t ReadableFontData::Checksum() {
4809f3dda615ba59d0b686e8c36f1e8426b9235746arthurhsu@google.com  AutoLock lock(checksum_lock_);
49464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com  if (!checksum_set_) {
50246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com    ComputeChecksum();
51464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com  }
52464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com  return checksum_;
53464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
54464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
55246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comvoid ReadableFontData::SetCheckSumRanges(const IntegerList& ranges) {
56464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com  checksum_range_ = ranges;
57464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com  checksum_set_ = false;  // UNIMPLEMENTED: atomicity
58464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
59464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
60246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::ReadUByte(int32_t index) {
6132a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  int32_t b = array_->Get(BoundOffset(index));
6232a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com#if !defined (SFNTLY_NO_EXCEPTION)
6332a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  if (b < 0) {
6432a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com    throw IndexOutOfBoundException(
6532a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com        "Index attempted to be read from is out of bounds", index);
6632a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  }
6732a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com#endif
6832a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  return b;
69464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
70464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
71246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::ReadByte(int32_t index) {
7232a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  int32_t b = array_->Get(BoundOffset(index));
7332a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com#if !defined (SFNTLY_NO_EXCEPTION)
7432a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  if (b < 0) {
7532a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com    throw IndexOutOfBoundException(
7632a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com        "Index attempted to be read from is out of bounds", index);
7732a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  }
7832a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com#endif
7932a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  return (b << 24) >> 24;
80464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
81464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
82246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::ReadBytes(int32_t index,
8332a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com                                    byte_t* b,
84246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                                    int32_t offset,
85246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                                    int32_t length) {
86246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return array_->Get(BoundOffset(index), b, offset, BoundLength(index, length));
87464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
88464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
89246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::ReadChar(int32_t index) {
90246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return ReadUByte(index);
91464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
92464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
93246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::ReadUShort(int32_t index) {
94246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return 0xffff & (ReadUByte(index) << 8 | ReadUByte(index + 1));
95464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
96464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
97246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::ReadShort(int32_t index) {
98246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return ((ReadByte(index) << 8 | ReadUByte(index + 1)) << 16) >> 16;
99464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
100464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
101246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::ReadUInt24(int32_t index) {
102246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return 0xffffff & (ReadUByte(index) << 16 |
103246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                     ReadUByte(index + 1) << 8 |
104246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                     ReadUByte(index + 2));
105464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
106464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
107246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint64_t ReadableFontData::ReadULong(int32_t index) {
108246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return 0xffffffffL & (ReadUByte(index) << 24 |
109246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                        ReadUByte(index + 1) << 16 |
110246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                        ReadUByte(index + 2) << 8 |
111246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                        ReadUByte(index + 3));
112464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
113464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
114246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::ReadULongAsInt(int32_t index) {
115246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  int64_t ulong = ReadULong(index);
1160e411afcef9fc211b3f8f70d31bc1dfa4c0f85d3arthurhsu@google.com#if !defined (SFNTLY_NO_EXCEPTION)
117464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com  if ((ulong & 0x80000000) == 0x80000000) {
118464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com    throw ArithmeticException("Long value too large to fit into an integer.");
119464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com  }
1200e411afcef9fc211b3f8f70d31bc1dfa4c0f85d3arthurhsu@google.com#endif
12132a01c7c6e7be46dda9bfc78de9ce32d99e4c8b7arthurhsu@google.com  return static_cast<int32_t>(ulong);
122464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
123464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
124333edd91cb32d6acfd0307ba2ae8f60baed75ff4arthurhsu@google.comint64_t ReadableFontData::ReadULongLE(int32_t index) {
125333edd91cb32d6acfd0307ba2ae8f60baed75ff4arthurhsu@google.com  return 0xffffffffL & (ReadUByte(index) |
126333edd91cb32d6acfd0307ba2ae8f60baed75ff4arthurhsu@google.com                        ReadUByte(index + 1) << 8 |
127333edd91cb32d6acfd0307ba2ae8f60baed75ff4arthurhsu@google.com                        ReadUByte(index + 2) << 16 |
128333edd91cb32d6acfd0307ba2ae8f60baed75ff4arthurhsu@google.com                        ReadUByte(index + 3) << 24);
129333edd91cb32d6acfd0307ba2ae8f60baed75ff4arthurhsu@google.com}
130333edd91cb32d6acfd0307ba2ae8f60baed75ff4arthurhsu@google.com
131246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::ReadLong(int32_t index) {
132246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return ReadByte(index) << 24 |
133246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com         ReadUByte(index + 1) << 16 |
134246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com         ReadUByte(index + 2) << 8 |
135246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com         ReadUByte(index + 3);
136464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
137464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
138246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::ReadFixed(int32_t index) {
139246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return ReadLong(index);
140464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
141464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
142246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) {
143246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return (int64_t)ReadULong(index) << 32 | ReadULong(index + 4);
144464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
145464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
146246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::ReadFWord(int32_t index) {
147246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return ReadShort(index);
148464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
149464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
150246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::ReadFUFWord(int32_t index) {
151246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return ReadUShort(index);
152464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
153464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
154246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::CopyTo(OutputStream* os) {
155246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return array_->CopyTo(os, BoundOffset(0), Length());
156464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
157464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
158246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::CopyTo(WritableFontData* wfd) {
159246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return array_->CopyTo(wfd->BoundOffset(0),
160246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                        wfd->array_,
161246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                        BoundOffset(0),
162246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                        Length());
163464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
164464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
165246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint32_t ReadableFontData::CopyTo(ByteArray* ba) {
166246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return array_->CopyTo(ba, BoundOffset(0), Length());
167464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
168464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
169760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.comint32_t ReadableFontData::SearchUShort(int32_t start_index,
170760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com                                       int32_t start_offset,
171760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com                                       int32_t end_index,
172760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com                                       int32_t end_offset,
173760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com                                       int32_t length,
174760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com                                       int32_t key) {
175760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com  int32_t location = 0;
176760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com  int32_t bottom = 0;
177760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com  int32_t top = length;
178760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com  while (top != bottom) {
179760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com    location = (top + bottom) / 2;
180760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com    int32_t location_start = ReadUShort(start_index + location * start_offset);
181760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com    if (key < location_start) {
182760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      // location is below current location
183760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      top = location;
184760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com    } else {
185760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      // is key below the upper bound?
186760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      int32_t location_end = ReadUShort(end_index + location * end_offset);
187760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com#if defined (SFNTLY_DEBUG_FONTDATA)
188760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
189760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com#endif
190760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      if (key <= location_end) {
191760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com        return location;
192760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      } else {
193760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com        // location is above the current location
194760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com        bottom = location + 1;
195760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      }
196760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com    }
197760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com  }
198760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com  return -1;
199760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com}
200760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com
2016b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.comint32_t ReadableFontData::SearchUShort(int32_t start_index,
2026b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com                                       int32_t start_offset,
2036b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com                                       int32_t length,
2046b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com                                       int32_t key) {
2056b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com  int32_t location = 0;
2066b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com  int32_t bottom = 0;
2076b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com  int32_t top = length;
2086b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com  while (top != bottom) {
2096b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com    location = (top + bottom) / 2;
2106b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com    int32_t location_start = ReadUShort(start_index + location * start_offset);
2116b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com    if (key < location_start) {
2126b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com      // location is below current location
2136b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com      top = location;
2146b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com    } else if (key > location_start) {
2156b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com      // location is above current location
2166b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com      bottom = location + 1;
2176b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com    } else {
2186b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com      return location;
2196b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com    }
2206b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com  }
2216b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com  return -1;
2226b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com}
2236b8e073e978eed96605da6f92d6db740a39864baarthurhsu@google.com
224760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.comint32_t ReadableFontData::SearchULong(int32_t start_index,
225760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com                                      int32_t start_offset,
226760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com                                      int32_t end_index,
227760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com                                      int32_t end_offset,
228760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com                                      int32_t length,
229760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com                                      int32_t key) {
230760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com  int32_t location = 0;
231760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com  int32_t bottom = 0;
232760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com  int32_t top = length;
233760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com  while (top != bottom) {
234760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com    location = (top + bottom) / 2;
235760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com    int32_t location_start = ReadULongAsInt(start_index
236760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com                                            + location * start_offset);
237760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com    if (key < location_start) {
238760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      // location is below current location
239760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      top = location;
240760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com    } else {
241760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      // is key below the upper bound?
242760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      int32_t location_end = ReadULongAsInt(end_index + location * end_offset);
243760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com#if defined (SFNTLY_DEBUG_FONTDATA)
244760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
245760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com#endif
246760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      if (key <= location_end) {
247760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com        return location;
248760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      } else {
249760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com        // location is above the current location
250760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com        bottom = location + 1;
251760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com      }
252760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com    }
253760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com  }
254760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com  return -1;
255760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com}
256760e6005f25f8d45d413d286ab5a38263ece63addfilimon@google.com
257246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comCALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset,
258464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com                                                int32_t length) {
259246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  if (offset < 0 || offset + length > Size()) {
260144e5cb2b372c30d8a4b90267b52646368dd89fcarthurhsu@google.com#if !defined (SFNTLY_NO_EXCEPTION)
261144e5cb2b372c30d8a4b90267b52646368dd89fcarthurhsu@google.com    throw IndexOutOfBoundsException(
262144e5cb2b372c30d8a4b90267b52646368dd89fcarthurhsu@google.com        "Attempt to bind data outside of its limits");
263144e5cb2b372c30d8a4b90267b52646368dd89fcarthurhsu@google.com#endif
264464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com    return NULL;
265464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com  }
266464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com  FontDataPtr slice = new ReadableFontData(this, offset, length);
267246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return slice.Detach();
268464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
269464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
270246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comCALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) {
271246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  if (offset < 0 || offset > Size()) {
272144e5cb2b372c30d8a4b90267b52646368dd89fcarthurhsu@google.com#if !defined (SFNTLY_NO_EXCEPTION)
273144e5cb2b372c30d8a4b90267b52646368dd89fcarthurhsu@google.com    throw IndexOutOfBoundsException(
274144e5cb2b372c30d8a4b90267b52646368dd89fcarthurhsu@google.com        "Attempt to bind data outside of its limits");
275144e5cb2b372c30d8a4b90267b52646368dd89fcarthurhsu@google.com#endif
276464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com    return NULL;
277464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com  }
278464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com  FontDataPtr slice = new ReadableFontData(this, offset);
279246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return slice.Detach();
280246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com}
281246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com
282246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset)
283246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com    : FontData(data, offset),
284246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com      checksum_set_(false),
285246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com      checksum_(0) {
286246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com}
287246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com
288246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comReadableFontData::ReadableFontData(ReadableFontData* data,
289246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                                   int32_t offset,
290246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                                   int32_t length)
291246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com    : FontData(data, offset, length),
292246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com      checksum_set_(false),
293246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com      checksum_(0) {
294246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com}
295246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com
296246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comvoid ReadableFontData::ComputeChecksum() {
297246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity
298246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  int64_t sum = 0;
299246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  if (checksum_range_.empty()) {
300246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com    sum = ComputeCheckSum(0, Length());
301246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  } else {
302246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com    for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size();
303246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com         low_bound_index += 2) {
304246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com      int32_t low_bound = checksum_range_[low_bound_index];
305246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com      int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ?
306246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                                Length() :
307246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                                checksum_range_[low_bound_index + 1];
308246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com      sum += ComputeCheckSum(low_bound, high_bound);
309246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com    }
310246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  }
311246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com
312246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  checksum_ = sum & 0xffffffffL;
313246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  checksum_set_ = true;
314246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com}
315246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com
316246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.comint64_t ReadableFontData::ComputeCheckSum(int32_t low_bound,
317246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com                                          int32_t high_bound) {
318246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  int64_t sum = 0;
319c10c3d53cd1401f158e89697b7fe019b6828fa00arthurhsu@google.com  // Checksum all whole 4-byte chunks.
320c10c3d53cd1401f158e89697b7fe019b6828fa00arthurhsu@google.com  for (int32_t i = low_bound; i <= high_bound - 4; i += 4) {
321c10c3d53cd1401f158e89697b7fe019b6828fa00arthurhsu@google.com    sum += ReadULong(i);
322c10c3d53cd1401f158e89697b7fe019b6828fa00arthurhsu@google.com  }
323c10c3d53cd1401f158e89697b7fe019b6828fa00arthurhsu@google.com
324c10c3d53cd1401f158e89697b7fe019b6828fa00arthurhsu@google.com  // Add last fragment if not 4-byte multiple
325c10c3d53cd1401f158e89697b7fe019b6828fa00arthurhsu@google.com  int32_t off = high_bound & -4;
326c10c3d53cd1401f158e89697b7fe019b6828fa00arthurhsu@google.com  if (off < high_bound) {
327c10c3d53cd1401f158e89697b7fe019b6828fa00arthurhsu@google.com    int32_t b3 = ReadUByte(off);
328c10c3d53cd1401f158e89697b7fe019b6828fa00arthurhsu@google.com    int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0;
329c10c3d53cd1401f158e89697b7fe019b6828fa00arthurhsu@google.com    int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0;
330c10c3d53cd1401f158e89697b7fe019b6828fa00arthurhsu@google.com    int32_t b0 = 0;
331246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com    sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
332246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  }
333246300f7fab1f2539c3207ce5ec28cc355465be8arthurhsu@google.com  return sum;
334464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}
335464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com
336464987db923362e596195f9eebd34fc508c9a41arthurhsu@google.com}  // namespace sfntly
337