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 "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
22namespace webrtc {
23
24FileWrapper* FileWrapper::Create()
25{
26    return new FileWrapperImpl();
27}
28
29FileWrapperImpl::FileWrapperImpl()
30    : _id(NULL),
31      _open(false),
32      _looping(false),
33      _readOnly(false),
34      _maxSizeInBytes(0),
35      _sizeInBytes(0)
36{
37    memset(_fileNameUTF8, 0, kMaxFileNameSize);
38}
39
40FileWrapperImpl::~FileWrapperImpl()
41{
42    if (_id != NULL)
43    {
44        fclose(_id);
45    }
46}
47
48int FileWrapperImpl::CloseFile()
49{
50    if (_id != NULL)
51    {
52        fclose(_id);
53        _id = NULL;
54    }
55    memset(_fileNameUTF8, 0, kMaxFileNameSize);
56    _open = false;
57    return 0;
58}
59
60int FileWrapperImpl::Rewind()
61{
62    if(_looping || !_readOnly)
63    {
64        if (_id != NULL)
65        {
66            _sizeInBytes = 0;
67            return fseek(_id, 0, SEEK_SET);
68        }
69    }
70    return -1;
71}
72
73int FileWrapperImpl::SetMaxFileSize(size_t bytes)
74{
75    _maxSizeInBytes = bytes;
76    return 0;
77}
78
79int FileWrapperImpl::Flush()
80{
81    if (_id != NULL)
82    {
83        return fflush(_id);
84    }
85    return -1;
86}
87
88int FileWrapperImpl::FileName(char* fileNameUTF8,
89                              size_t size) const
90{
91    size_t length = strlen(_fileNameUTF8);
92    if(length > kMaxFileNameSize)
93    {
94        assert(false);
95        return -1;
96    }
97    if(length < 1)
98    {
99        return -1;
100    }
101
102    // Make sure to NULL terminate
103    if(size < length)
104    {
105        length = size - 1;
106    }
107    memcpy(fileNameUTF8, _fileNameUTF8, length);
108    fileNameUTF8[length] = 0;
109    return 0;
110}
111
112bool FileWrapperImpl::Open() const
113{
114    return _open;
115}
116
117int FileWrapperImpl::OpenFile(const char *fileNameUTF8, bool readOnly,
118                              bool loop, bool text)
119{
120    size_t length = strlen(fileNameUTF8);
121    if (length > kMaxFileNameSize - 1)
122    {
123        return -1;
124    }
125
126    _readOnly = readOnly;
127
128    FILE *tmpId = NULL;
129#if defined _WIN32
130    wchar_t wideFileName[kMaxFileNameSize];
131    wideFileName[0] = 0;
132
133    MultiByteToWideChar(CP_UTF8,
134                        0 /*UTF8 flag*/,
135                        fileNameUTF8,
136                        -1 /*Null terminated string*/,
137                        wideFileName,
138                        kMaxFileNameSize);
139    if(text)
140    {
141        if(readOnly)
142        {
143            tmpId = _wfopen(wideFileName, L"rt");
144        } else {
145            tmpId = _wfopen(wideFileName, L"wt");
146        }
147    } else {
148        if(readOnly)
149        {
150            tmpId = _wfopen(wideFileName, L"rb");
151        } else {
152            tmpId = _wfopen(wideFileName, L"wb");
153        }
154    }
155#else
156    if(text)
157    {
158        if(readOnly)
159        {
160            tmpId = fopen(fileNameUTF8, "rt");
161        } else {
162            tmpId = fopen(fileNameUTF8, "wt");
163        }
164    } else {
165        if(readOnly)
166        {
167            tmpId = fopen(fileNameUTF8, "rb");
168        } else {
169            tmpId = fopen(fileNameUTF8, "wb");
170        }
171    }
172#endif
173
174    if (tmpId != NULL)
175    {
176        // +1 comes from copying the NULL termination character.
177        memcpy(_fileNameUTF8, fileNameUTF8, length + 1);
178        if (_id != NULL)
179        {
180            fclose(_id);
181        }
182        _id = tmpId;
183        _looping = loop;
184        _open = true;
185        return 0;
186    }
187    return -1;
188}
189
190int FileWrapperImpl::Read(void* buf, int length)
191{
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    {
201        CloseFile();
202    }
203    return bytes_read;
204}
205
206int FileWrapperImpl::WriteText(const char* format, ...)
207{
208    if (format == NULL)
209        return -1;
210
211    if (_readOnly)
212        return -1;
213
214    if (_id == NULL)
215        return -1;
216
217    va_list args;
218    va_start(args, format);
219    int num_chars = vfprintf(_id, format, args);
220    va_end(args);
221
222    if (num_chars >= 0)
223    {
224        return num_chars;
225    }
226    else
227    {
228        CloseFile();
229        return -1;
230    }
231}
232
233bool FileWrapperImpl::Write(const void* buf, int length)
234{
235    if (buf == NULL)
236        return false;
237
238    if (length < 0)
239        return false;
240
241    if (_readOnly)
242        return false;
243
244    if (_id == NULL)
245        return false;
246
247    // Check if it's time to stop writing.
248    if (_maxSizeInBytes > 0 && (_sizeInBytes + length) > _maxSizeInBytes)
249    {
250        Flush();
251        return false;
252    }
253
254    size_t num_bytes = fwrite(buf, 1, length, _id);
255    if (num_bytes > 0)
256    {
257        _sizeInBytes += num_bytes;
258        return true;
259    }
260
261    CloseFile();
262    return false;
263}
264
265} // namespace webrtc
266