1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/system_wrappers/source/file_impl.h"
12
13#include <assert.h>
14
15#ifdef _WIN32
16#include <Windows.h>
17#else
18#include <stdarg.h>
19#include <string.h>
20#endif
21
22#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
23
24namespace webrtc {
25
26FileWrapper* FileWrapper::Create() {
27  return new FileWrapperImpl();
28}
29
30FileWrapperImpl::FileWrapperImpl()
31    : rw_lock_(RWLockWrapper::CreateRWLock()),
32      id_(NULL),
33      managed_file_handle_(true),
34      open_(false),
35      looping_(false),
36      read_only_(false),
37      max_size_in_bytes_(0),
38      size_in_bytes_(0) {
39  memset(file_name_utf8_, 0, kMaxFileNameSize);
40}
41
42FileWrapperImpl::~FileWrapperImpl() {
43  if (id_ != NULL && managed_file_handle_) {
44    fclose(id_);
45  }
46}
47
48int FileWrapperImpl::CloseFile() {
49  WriteLockScoped write(*rw_lock_);
50  return CloseFileImpl();
51}
52
53int FileWrapperImpl::Rewind() {
54  WriteLockScoped write(*rw_lock_);
55  if (looping_ || !read_only_) {
56    if (id_ != NULL) {
57      size_in_bytes_ = 0;
58      return fseek(id_, 0, SEEK_SET);
59    }
60  }
61  return -1;
62}
63
64int FileWrapperImpl::SetMaxFileSize(size_t bytes) {
65  WriteLockScoped write(*rw_lock_);
66  max_size_in_bytes_ = bytes;
67  return 0;
68}
69
70int FileWrapperImpl::Flush() {
71  WriteLockScoped write(*rw_lock_);
72  return FlushImpl();
73}
74
75int FileWrapperImpl::FileName(char* file_name_utf8, size_t size) const {
76  ReadLockScoped read(*rw_lock_);
77  size_t length = strlen(file_name_utf8_);
78  if (length > kMaxFileNameSize) {
79    assert(false);
80    return -1;
81  }
82  if (length < 1) {
83    return -1;
84  }
85
86  // Make sure to NULL terminate
87  if (size < length) {
88    length = size - 1;
89  }
90  memcpy(file_name_utf8, file_name_utf8_, length);
91  file_name_utf8[length] = 0;
92  return 0;
93}
94
95bool FileWrapperImpl::Open() const {
96  ReadLockScoped read(*rw_lock_);
97  return open_;
98}
99
100int FileWrapperImpl::OpenFile(const char* file_name_utf8, bool read_only,
101                              bool loop, bool text) {
102  WriteLockScoped write(*rw_lock_);
103  if (id_ != NULL && !managed_file_handle_)
104    return -1;
105  size_t length = strlen(file_name_utf8);
106  if (length > kMaxFileNameSize - 1) {
107    return -1;
108  }
109
110  read_only_ = read_only;
111
112  FILE* tmp_id = NULL;
113#if defined _WIN32
114  wchar_t wide_file_name[kMaxFileNameSize];
115  wide_file_name[0] = 0;
116
117  MultiByteToWideChar(CP_UTF8,
118                      0,  // UTF8 flag
119                      file_name_utf8,
120                      -1,  // Null terminated string
121                      wide_file_name,
122                      kMaxFileNameSize);
123  if (text) {
124    if (read_only) {
125      tmp_id = _wfopen(wide_file_name, L"rt");
126    } else {
127      tmp_id = _wfopen(wide_file_name, L"wt");
128    }
129  } else {
130    if (read_only) {
131      tmp_id = _wfopen(wide_file_name, L"rb");
132    } else {
133      tmp_id = _wfopen(wide_file_name, L"wb");
134    }
135  }
136#else
137  if (text) {
138    if (read_only) {
139      tmp_id = fopen(file_name_utf8, "rt");
140    } else {
141      tmp_id = fopen(file_name_utf8, "wt");
142    }
143  } else {
144    if (read_only) {
145      tmp_id = fopen(file_name_utf8, "rb");
146    } else {
147      tmp_id = fopen(file_name_utf8, "wb");
148    }
149  }
150#endif
151
152  if (tmp_id != NULL) {
153    // +1 comes from copying the NULL termination character.
154    memcpy(file_name_utf8_, file_name_utf8, length + 1);
155    if (id_ != NULL) {
156      fclose(id_);
157    }
158    id_ = tmp_id;
159    managed_file_handle_ = true;
160    looping_ = loop;
161    open_ = true;
162    return 0;
163  }
164  return -1;
165}
166
167int FileWrapperImpl::OpenFromFileHandle(FILE* handle,
168                                        bool manage_file,
169                                        bool read_only,
170                                        bool loop) {
171  WriteLockScoped write(*rw_lock_);
172  if (!handle)
173    return -1;
174
175  if (id_ != NULL) {
176    if (managed_file_handle_)
177      fclose(id_);
178    else
179      return -1;
180  }
181
182  id_ = handle;
183  managed_file_handle_ = manage_file;
184  read_only_ = read_only;
185  looping_ = loop;
186  open_ = true;
187  return 0;
188}
189
190int FileWrapperImpl::Read(void* buf, int length) {
191  WriteLockScoped write(*rw_lock_);
192  if (length < 0)
193    return -1;
194
195  if (id_ == NULL)
196    return -1;
197
198  int bytes_read = static_cast<int>(fread(buf, 1, length, id_));
199  if (bytes_read != length && !looping_) {
200    CloseFileImpl();
201  }
202  return bytes_read;
203}
204
205int FileWrapperImpl::WriteText(const char* format, ...) {
206  WriteLockScoped write(*rw_lock_);
207  if (format == NULL)
208    return -1;
209
210  if (read_only_)
211    return -1;
212
213  if (id_ == NULL)
214    return -1;
215
216  va_list args;
217  va_start(args, format);
218  int num_chars = vfprintf(id_, format, args);
219  va_end(args);
220
221  if (num_chars >= 0) {
222    return num_chars;
223  } else {
224    CloseFileImpl();
225    return -1;
226  }
227}
228
229bool FileWrapperImpl::Write(const void* buf, int length) {
230  WriteLockScoped write(*rw_lock_);
231  if (buf == NULL)
232    return false;
233
234  if (length < 0)
235    return false;
236
237  if (read_only_)
238    return false;
239
240  if (id_ == NULL)
241    return false;
242
243  // Check if it's time to stop writing.
244  if (max_size_in_bytes_ > 0 &&
245      (size_in_bytes_ + length) > max_size_in_bytes_) {
246    FlushImpl();
247    return false;
248  }
249
250  size_t num_bytes = fwrite(buf, 1, length, id_);
251  if (num_bytes > 0) {
252    size_in_bytes_ += num_bytes;
253    return true;
254  }
255
256  CloseFileImpl();
257  return false;
258}
259
260int FileWrapperImpl::CloseFileImpl() {
261  if (id_ != NULL) {
262    if (managed_file_handle_)
263      fclose(id_);
264    id_ = NULL;
265  }
266  memset(file_name_utf8_, 0, kMaxFileNameSize);
267  open_ = false;
268  return 0;
269}
270
271int FileWrapperImpl::FlushImpl() {
272  if (id_ != NULL) {
273    return fflush(id_);
274  }
275  return -1;
276}
277
278}  // namespace webrtc
279