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