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