1/*
2 *  Copyright (c) 2011 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 <cassert>
14
15#ifdef _WIN32
16    #include <Windows.h>
17#else
18    #include <stdarg.h>
19    #include <string.h>
20#endif
21
22namespace webrtc {
23FileWrapper* FileWrapper::Create()
24{
25    return new FileWrapperImpl();
26}
27
28FileWrapperImpl::FileWrapperImpl()
29    : _id(NULL),
30      _open(false),
31      _looping(false),
32      _readOnly(false),
33      _text(false),
34      _maxSizeInBytes(-1),
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
48WebRtc_Word32 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
73WebRtc_Word32 FileWrapperImpl::SetMaxFileSize(WebRtc_Word32 bytes)
74{
75    _maxSizeInBytes = bytes;
76    return 0;
77}
78
79WebRtc_Word32 FileWrapperImpl::Flush()
80{
81    if (_id != NULL)
82    {
83        return fflush(_id);
84    }
85    return -1;
86}
87
88WebRtc_Word32 FileWrapperImpl::FileName(WebRtc_Word8* fileNameUTF8,
89                                        WebRtc_UWord32 size) const
90{
91    WebRtc_Word32 len = static_cast<WebRtc_Word32>(strlen(_fileNameUTF8));
92    if(len > kMaxFileNameSize)
93    {
94        assert(false);
95        return -1;
96    }
97    if(len < 1)
98    {
99        return -1;
100    }
101    // Make sure to NULL terminate
102    if(size < (WebRtc_UWord32)len)
103    {
104        len = size - 1;
105    }
106    memcpy(fileNameUTF8, _fileNameUTF8, len);
107    fileNameUTF8[len] = 0;
108    return 0;
109}
110
111bool
112FileWrapperImpl::Open() const
113{
114    return _open;
115}
116
117WebRtc_Word32 FileWrapperImpl::OpenFile(const WebRtc_Word8 *fileNameUTF8,
118                                        const bool readOnly, const bool loop,
119                                        const bool text)
120{
121    WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8);
122    if (length > kMaxFileNameSize)
123    {
124        return -1;
125    }
126
127    _readOnly = readOnly;
128
129    FILE *tmpId = NULL;
130#if defined _WIN32
131    wchar_t wideFileName[kMaxFileNameSize];
132    wideFileName[0] = 0;
133
134    MultiByteToWideChar(CP_UTF8,
135                        0 /*UTF8 flag*/,
136                        fileNameUTF8,
137                        -1 /*Null terminated string*/,
138                        wideFileName,
139                        kMaxFileNameSize);
140    if(text)
141    {
142        if(readOnly)
143        {
144            tmpId = _wfopen(wideFileName, L"rt");
145        } else {
146            tmpId = _wfopen(wideFileName, L"wt");
147        }
148    } else {
149        if(readOnly)
150        {
151            tmpId = _wfopen(wideFileName, L"rb");
152        } else {
153            tmpId = _wfopen(wideFileName, L"wb");
154        }
155    }
156#else
157    if(text)
158    {
159        if(readOnly)
160        {
161            tmpId = fopen(fileNameUTF8, "rt");
162        } else {
163            tmpId = fopen(fileNameUTF8, "wt");
164        }
165    } else {
166        if(readOnly)
167        {
168            tmpId = fopen(fileNameUTF8, "rb");
169        } else {
170            tmpId = fopen(fileNameUTF8, "wb");
171        }
172    }
173#endif
174
175    if (tmpId != NULL)
176    {
177        // + 1 comes fro copying the NULL termination charachter too
178        memcpy(_fileNameUTF8, fileNameUTF8, length + 1);
179        if (_id != NULL)
180        {
181            fclose(_id);
182        }
183        _id = tmpId;
184        _looping = loop;
185        _open = true;
186        return 0;
187    }
188    return -1;
189}
190
191int FileWrapperImpl::Read(void *buf, int len)
192{
193    if(len < 0)
194    {
195        return 0;
196    }
197    if (_id != NULL)
198    {
199        WebRtc_Word32 res = static_cast<WebRtc_Word32>(fread(buf, 1, len, _id));
200        if (res != len)
201        {
202            if(!_looping)
203            {
204                CloseFile();
205            }
206        }
207        return res;
208    }
209    return -1;
210}
211
212WebRtc_Word32 FileWrapperImpl::WriteText(const WebRtc_Word8* text, ...)
213{
214    assert(!_readOnly);
215    assert(!_text);
216
217    if (_id == NULL)
218    {
219        return -1;
220    }
221
222    char tempBuff[kFileMaxTextMessageSize];
223    if (text)
224    {
225        va_list args;
226        va_start(args, text);
227#ifdef _WIN32
228        _vsnprintf(tempBuff, kFileMaxTextMessageSize-1, text, args);
229#else
230        vsnprintf(tempBuff, kFileMaxTextMessageSize-1, text, args);
231#endif
232        va_end(args);
233        WebRtc_Word32 nBytes;
234        nBytes = fprintf(_id, "%s", tempBuff);
235        if (nBytes > 0)
236        {
237            return 0;
238        }
239        CloseFile();
240    }
241    return -1;
242}
243
244bool FileWrapperImpl::Write(const void* buf, int len)
245{
246    assert(!_readOnly);
247    if (_id != NULL)
248    {
249        // Check if it's time to stop writing.
250        if ((_maxSizeInBytes != -1) &&
251             _sizeInBytes + len > (WebRtc_UWord32)_maxSizeInBytes)
252        {
253            Flush();
254            return false;
255        }
256
257        size_t nBytes = fwrite((WebRtc_UWord8*)buf, 1, len, _id);
258        if (nBytes > 0)
259        {
260            _sizeInBytes += static_cast<WebRtc_Word32>(nBytes);
261            return true;
262        }
263        CloseFile();
264    }
265    return false;
266}
267} // namespace webrtc
268