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#if defined (WIN32)
18#include <windows.h>
19#endif
20
21#include <string.h>
22
23#include <algorithm>
24
25#include "sfntly/port/memory_input_stream.h"
26#include "sfntly/port/exception_type.h"
27
28namespace sfntly {
29
30MemoryInputStream::MemoryInputStream()
31    : buffer_(NULL),
32      position_(0),
33      length_(0) {
34}
35
36MemoryInputStream::~MemoryInputStream() {
37  Close();
38}
39
40int32_t MemoryInputStream::Available() {
41  return length_ - position_;
42}
43
44void MemoryInputStream::Close() {
45}
46
47void MemoryInputStream::Mark(int32_t readlimit) {
48  // NOP
49  UNREFERENCED_PARAMETER(readlimit);
50}
51
52bool MemoryInputStream::MarkSupported() {
53  return false;
54}
55
56int32_t MemoryInputStream::Read() {
57  if (!buffer_) {
58#if !defined (SFNTLY_NO_EXCEPTION)
59    throw IOException("no memory attached");
60#endif
61    return 0;
62  }
63  if (position_ >= length_) {
64#if !defined (SFNTLY_NO_EXCEPTION)
65    throw IOException("eof reached");
66#endif
67    return 0;
68  }
69  byte_t value = buffer_[position_++];
70  return value;
71}
72
73int32_t MemoryInputStream::Read(ByteVector* b) {
74  return Read(b, 0, b->size());
75}
76
77int32_t MemoryInputStream::Read(ByteVector* b, int32_t offset, int32_t length) {
78  assert(b);
79  if (!buffer_) {
80#if !defined (SFNTLY_NO_EXCEPTION)
81    throw IOException("no memory attached");
82#endif
83    return 0;
84  }
85  if (position_ >= length_) {
86#if !defined (SFNTLY_NO_EXCEPTION)
87    throw IOException("eof reached");
88#endif
89    return 0;
90  }
91  size_t read_count = std::min<size_t>(length_ - position_, length);
92  if (b->size() < (size_t)(offset + read_count)) {
93    b->resize((size_t)(offset + read_count));
94  }
95  memcpy(&((*b)[offset]), buffer_ + position_, read_count);
96  position_ += read_count;
97  return read_count;
98}
99
100void MemoryInputStream::Reset() {
101  // NOP
102}
103
104int64_t MemoryInputStream::Skip(int64_t n) {
105  if (!buffer_) {
106#if !defined (SFNTLY_NO_EXCEPTION)
107    throw IOException("no memory attached");
108#endif
109    return 0;
110  }
111  int64_t skip_count = 0;
112  if (n < 0) {  // move backwards
113    skip_count = std::max<int64_t>(0 - (int64_t)position_, n);
114    position_ -= (size_t)(0 - skip_count);
115  } else {
116    skip_count = std::min<size_t>(length_ - position_, (size_t)n);
117    position_ += (size_t)skip_count;
118  }
119  return skip_count;
120}
121
122void MemoryInputStream::Unread(ByteVector* b) {
123  Unread(b, 0, b->size());
124}
125
126void MemoryInputStream::Unread(ByteVector* b, int32_t offset, int32_t length) {
127  assert(b);
128  assert(b->size() >= size_t(offset + length));
129  if (!buffer_) {
130#if !defined (SFNTLY_NO_EXCEPTION)
131    throw IOException("no memory attached");
132#endif
133    return;
134  }
135  size_t unread_count = std::min<size_t>(position_, length);
136  position_ -= unread_count;
137  Read(b, offset, length);
138  position_ -= unread_count;
139}
140
141bool MemoryInputStream::Attach(const byte_t* buffer, size_t length) {
142  assert(buffer);
143  assert(length);
144  buffer_ = buffer;
145  length_ = length;
146  return true;
147}
148
149}  // namespace sfntly
150