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/byte_array.h"
18
19#include <algorithm>
20
21#include "sfntly/port/exception_type.h"
22
23namespace sfntly {
24
25const int32_t ByteArray::COPY_BUFFER_SIZE = 8192;
26
27ByteArray::~ByteArray() {}
28
29int32_t ByteArray::Length() { return filled_length_; }
30int32_t ByteArray::Size() { return storage_length_; }
31
32int32_t ByteArray::SetFilledLength(int32_t filled_length) {
33  filled_length_ = std::min<int32_t>(filled_length, storage_length_);
34  return filled_length_;
35}
36
37int32_t ByteArray::Get(int32_t index) {
38  if (index < 0 || index >= Length())
39    return -1;
40  return InternalGet(index) & 0xff;
41}
42
43int32_t ByteArray::Get(int32_t index, ByteVector* b) {
44  assert(b);
45  return Get(index, &((*b)[0]), 0, b->size());
46}
47
48int32_t ByteArray::Get(int32_t index,
49                       byte_t* b,
50                       int32_t offset,
51                       int32_t length) {
52  assert(b);
53  if (index < 0 || index >= filled_length_) {
54    return 0;
55  }
56  int32_t actual_length = std::min<int32_t>(length, filled_length_ - index);
57  return InternalGet(index, b, offset, actual_length);
58}
59
60void ByteArray::Put(int32_t index, byte_t b) {
61  if (index < 0 || index >= Size()) {
62#if defined (SFNTLY_NO_EXCEPTION)
63    return;
64#else
65    throw IndexOutOfBoundException(
66        "Attempt to write outside the bounds of the data");
67#endif
68  }
69  InternalPut(index, b);
70  filled_length_ = std::max<int32_t>(filled_length_, index + 1);
71}
72
73int32_t ByteArray::Put(int index, ByteVector* b) {
74  assert(b);
75  return Put(index, &((*b)[0]), 0, b->size());
76}
77
78int32_t ByteArray::Put(int32_t index,
79                       byte_t* b,
80                       int32_t offset,
81                       int32_t length) {
82  assert(b);
83  if (index < 0 || index >= Size()) {
84#if defined (SFNTLY_NO_EXCEPTION)
85    return 0;
86#else
87    throw IndexOutOfBoundException(
88        "Attempt to write outside the bounds of the data");
89#endif
90  }
91  int32_t actual_length = std::min<int32_t>(length, Size() - index);
92  int32_t bytes_written = InternalPut(index, b, offset, actual_length);
93  filled_length_ = std::max<int32_t>(filled_length_, index + bytes_written);
94  return bytes_written;
95}
96
97int32_t ByteArray::CopyTo(ByteArray* array) {
98  return CopyTo(array, 0, Length());
99}
100
101int32_t ByteArray::CopyTo(ByteArray* array, int32_t offset, int32_t length) {
102  return CopyTo(0, array, offset, length);
103}
104
105int32_t ByteArray::CopyTo(int32_t dst_offset, ByteArray* array,
106                          int32_t src_offset, int32_t length) {
107  assert(array);
108  if (array->Size() < dst_offset + length) {  // insufficient space
109    return -1;
110  }
111
112  ByteVector b(COPY_BUFFER_SIZE);
113  int32_t bytes_read = 0;
114  int32_t index = 0;
115  int32_t remaining_length = length;
116  int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length);
117  while ((bytes_read =
118              Get(index + src_offset, &(b[0]), 0, buffer_length)) > 0) {
119    int bytes_written = array->Put(index + dst_offset, &(b[0]), 0, bytes_read);
120    UNREFERENCED_PARAMETER(bytes_written);
121    index += bytes_read;
122    remaining_length -= bytes_read;
123    buffer_length = std::min<int32_t>(b.size(), remaining_length);
124  }
125  return index;
126}
127
128int32_t ByteArray::CopyTo(OutputStream* os) {
129    return CopyTo(os, 0, Length());
130}
131
132int32_t ByteArray::CopyTo(OutputStream* os, int32_t offset, int32_t length) {
133  ByteVector b(COPY_BUFFER_SIZE);
134  int32_t bytes_read = 0;
135  int32_t index = 0;
136  int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length);
137  while ((bytes_read = Get(index + offset, &(b[0]), 0, buffer_length)) > 0) {
138    os->Write(&b, 0, bytes_read);
139    index += bytes_read;
140    buffer_length = std::min<int32_t>(b.size(), length - index);
141  }
142  return index;
143}
144
145bool ByteArray::CopyFrom(InputStream* is, int32_t length) {
146  ByteVector b(COPY_BUFFER_SIZE);
147  int32_t bytes_read = 0;
148  int32_t index = 0;
149  int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length);
150  while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) {
151    if (Put(index, &(b[0]), 0, bytes_read) != bytes_read) {
152#if defined (SFNTLY_NO_EXCEPTION)
153      return 0;
154#else
155      throw IOException("Error writing bytes.");
156#endif
157    }
158    index += bytes_read;
159    length -= bytes_read;
160    buffer_length = std::min<int32_t>(b.size(), length);
161  }
162  return true;
163}
164
165bool ByteArray::CopyFrom(InputStream* is) {
166  ByteVector b(COPY_BUFFER_SIZE);
167  int32_t bytes_read = 0;
168  int32_t index = 0;
169  int32_t buffer_length = COPY_BUFFER_SIZE;
170  while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) {
171    if (Put(index, &b[0], 0, bytes_read) != bytes_read) {
172#if defined (SFNTLY_NO_EXCEPTION)
173      return 0;
174#else
175      throw IOException("Error writing bytes.");
176#endif
177    }
178    index += bytes_read;
179  }
180  return true;
181}
182
183ByteArray::ByteArray(int32_t filled_length,
184                     int32_t storage_length,
185                     bool growable) {
186  Init(filled_length, storage_length, growable);
187}
188
189ByteArray::ByteArray(int32_t filled_length, int32_t storage_length) {
190  Init(filled_length, storage_length, false);
191}
192
193void ByteArray::Init(int32_t filled_length,
194                     int32_t storage_length,
195                     bool growable) {
196  storage_length_ = storage_length;
197  growable_ = growable;
198  SetFilledLength(filled_length);
199}
200
201}  // namespace sfntly
202