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 <algorithm>
22
23#include "sfntly/port/file_input_stream.h"
24#include "sfntly/port/exception_type.h"
25
26namespace sfntly {
27
28FileInputStream::FileInputStream()
29    : file_(NULL),
30      position_(0),
31      length_(0) {
32}
33
34FileInputStream::~FileInputStream() {
35  Close();
36}
37
38int32_t FileInputStream::Available() {
39  return length_ - position_;
40}
41
42void FileInputStream::Close() {
43  if (file_) {
44    fclose(file_);
45    length_ = 0;
46    position_ = 0;
47    file_ = NULL;
48  }
49}
50
51void FileInputStream::Mark(int32_t readlimit) {
52  // NOP
53  UNREFERENCED_PARAMETER(readlimit);
54}
55
56bool FileInputStream::MarkSupported() {
57  return false;
58}
59
60int32_t FileInputStream::Read() {
61  if (!file_) {
62#if !defined (SFNTLY_NO_EXCEPTION)
63    throw IOException("no opened file");
64#endif
65    return 0;
66  }
67  if (feof(file_)) {
68#if !defined (SFNTLY_NO_EXCEPTION)
69    throw IOException("eof reached");
70#endif
71    return 0;
72  }
73  byte_t value;
74  size_t length = fread(&value, 1, 1, file_);
75  position_ += length;
76  return value;
77}
78
79int32_t FileInputStream::Read(ByteVector* b) {
80  return Read(b, 0, b->size());
81}
82
83int32_t FileInputStream::Read(ByteVector* b, int32_t offset, int32_t length) {
84  assert(b);
85  if (!file_) {
86#if !defined (SFNTLY_NO_EXCEPTION)
87    throw IOException("no opened file");
88#endif
89    return 0;
90  }
91  if (feof(file_)) {
92#if !defined (SFNTLY_NO_EXCEPTION)
93    throw IOException("eof reached");
94#endif
95    return 0;
96  }
97  size_t read_count = std::min<size_t>(length_ - position_, length);
98  if (b->size() < (size_t)(offset + read_count)) {
99    b->resize((size_t)(offset + read_count));
100  }
101  int32_t actual_read = fread(&((*b)[offset]), 1, read_count, file_);
102  position_ += actual_read;
103  return actual_read;
104}
105
106void FileInputStream::Reset() {
107  // NOP
108}
109
110int64_t FileInputStream::Skip(int64_t n) {
111  if (!file_) {
112#if !defined (SFNTLY_NO_EXCEPTION)
113    throw IOException("no opened file");
114#endif
115    return 0;
116  }
117  int64_t skip_count = 0;
118  if (n < 0) {  // move backwards
119    skip_count = std::max<int64_t>(0 - (int64_t)position_, n);
120    position_ -= (size_t)(0 - skip_count);
121    fseek(file_, position_, SEEK_SET);
122  } else {
123    skip_count = std::min<size_t>(length_ - position_, (size_t)n);
124    position_ += (size_t)skip_count;
125    fseek(file_, (size_t)skip_count, SEEK_CUR);
126  }
127  return skip_count;
128}
129
130void FileInputStream::Unread(ByteVector* b) {
131  Unread(b, 0, b->size());
132}
133
134void FileInputStream::Unread(ByteVector* b, int32_t offset, int32_t length) {
135  assert(b);
136  assert(b->size() >= size_t(offset + length));
137  if (!file_) {
138#if !defined (SFNTLY_NO_EXCEPTION)
139    throw IOException("no opened file");
140#endif
141    return;
142  }
143  size_t unread_count = std::min<size_t>(position_, length);
144  fseek(file_, position_ - unread_count, SEEK_SET);
145  position_ -= unread_count;
146  Read(b, offset, length);
147  fseek(file_, position_ - unread_count, SEEK_SET);
148  position_ -= unread_count;
149}
150
151bool FileInputStream::Open(const char* file_path) {
152  assert(file_path);
153  if (file_) {
154    Close();
155  }
156#if defined (WIN32)
157  fopen_s(&file_, file_path, "rb");
158#else
159  file_ = fopen(file_path, "rb");
160#endif
161  if (file_ == NULL) {
162    return false;
163  }
164
165  fseek(file_, 0, SEEK_END);
166  length_ = ftell(file_);
167  fseek(file_, 0, SEEK_SET);
168  return true;
169}
170
171}  // namespace sfntly
172