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