1// FileStreams.cpp 2 3#include "StdAfx.h" 4 5#ifndef _WIN32 6#include <fcntl.h> 7#include <unistd.h> 8#include <errno.h> 9#endif 10 11#ifdef SUPPORT_DEVICE_FILE 12#include "../../../C/Alloc.h" 13#include "../../Common/Defs.h" 14#endif 15 16#include "FileStreams.h" 17 18static inline HRESULT ConvertBoolToHRESULT(bool result) 19{ 20 #ifdef _WIN32 21 if (result) 22 return S_OK; 23 DWORD lastError = ::GetLastError(); 24 if (lastError == 0) 25 return E_FAIL; 26 return HRESULT_FROM_WIN32(lastError); 27 #else 28 return result ? S_OK: E_FAIL; 29 #endif 30} 31 32bool CInFileStream::Open(LPCTSTR fileName) 33{ 34 return File.Open(fileName); 35} 36 37#ifdef USE_WIN_FILE 38#ifndef _UNICODE 39bool CInFileStream::Open(LPCWSTR fileName) 40{ 41 return File.Open(fileName); 42} 43#endif 44#endif 45 46bool CInFileStream::OpenShared(LPCTSTR fileName, bool shareForWrite) 47{ 48 return File.OpenShared(fileName, shareForWrite); 49} 50 51#ifdef USE_WIN_FILE 52#ifndef _UNICODE 53bool CInFileStream::OpenShared(LPCWSTR fileName, bool shareForWrite) 54{ 55 return File.OpenShared(fileName, shareForWrite); 56} 57#endif 58#endif 59 60#ifdef SUPPORT_DEVICE_FILE 61 62static const UInt32 kClusterSize = 1 << 18; 63CInFileStream::CInFileStream(): 64 VirtPos(0), 65 PhyPos(0), 66 Buffer(0), 67 BufferSize(0) 68{ 69} 70 71#endif 72 73CInFileStream::~CInFileStream() 74{ 75 #ifdef SUPPORT_DEVICE_FILE 76 MidFree(Buffer); 77 #endif 78} 79 80STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) 81{ 82 #ifdef USE_WIN_FILE 83 84 #ifdef SUPPORT_DEVICE_FILE 85 if (processedSize != NULL) 86 *processedSize = 0; 87 if (size == 0) 88 return S_OK; 89 if (File.IsDeviceFile) 90 { 91 if (File.LengthDefined) 92 { 93 if (VirtPos >= File.Length) 94 return VirtPos == File.Length ? S_OK : E_FAIL; 95 UInt64 rem = File.Length - VirtPos; 96 if (size > rem) 97 size = (UInt32)rem; 98 } 99 for (;;) 100 { 101 const UInt32 mask = kClusterSize - 1; 102 UInt64 mask2 = ~(UInt64)mask; 103 UInt64 alignedPos = VirtPos & mask2; 104 if (BufferSize > 0 && BufferStartPos == alignedPos) 105 { 106 UInt32 pos = (UInt32)VirtPos & mask; 107 if (pos >= BufferSize) 108 return S_OK; 109 UInt32 rem = MyMin(BufferSize - pos, size); 110 memcpy(data, Buffer + pos, rem); 111 VirtPos += rem; 112 if (processedSize != NULL) 113 *processedSize += rem; 114 return S_OK; 115 } 116 117 bool useBuffer = false; 118 if ((VirtPos & mask) != 0 || ((ptrdiff_t)data & mask) != 0 ) 119 useBuffer = true; 120 else 121 { 122 UInt64 end = VirtPos + size; 123 if ((end & mask) != 0) 124 { 125 end &= mask2; 126 if (end <= VirtPos) 127 useBuffer = true; 128 else 129 size = (UInt32)(end - VirtPos); 130 } 131 } 132 if (!useBuffer) 133 break; 134 if (alignedPos != PhyPos) 135 { 136 UInt64 realNewPosition; 137 bool result = File.Seek(alignedPos, FILE_BEGIN, realNewPosition); 138 if (!result) 139 return ConvertBoolToHRESULT(result); 140 PhyPos = realNewPosition; 141 } 142 143 BufferStartPos = alignedPos; 144 UInt32 readSize = kClusterSize; 145 if (File.LengthDefined) 146 readSize = (UInt32)MyMin(File.Length - PhyPos, (UInt64)kClusterSize); 147 148 if (Buffer == 0) 149 { 150 Buffer = (Byte *)MidAlloc(kClusterSize); 151 if (Buffer == 0) 152 return E_OUTOFMEMORY; 153 } 154 bool result = File.Read1(Buffer, readSize, BufferSize); 155 if (!result) 156 return ConvertBoolToHRESULT(result); 157 158 if (BufferSize == 0) 159 return S_OK; 160 PhyPos += BufferSize; 161 } 162 163 if (VirtPos != PhyPos) 164 { 165 UInt64 realNewPosition; 166 bool result = File.Seek(VirtPos, FILE_BEGIN, realNewPosition); 167 if (!result) 168 return ConvertBoolToHRESULT(result); 169 PhyPos = VirtPos = realNewPosition; 170 } 171 } 172 #endif 173 174 UInt32 realProcessedSize; 175 bool result = File.ReadPart(data, size, realProcessedSize); 176 if (processedSize != NULL) 177 *processedSize = realProcessedSize; 178 #ifdef SUPPORT_DEVICE_FILE 179 VirtPos += realProcessedSize; 180 PhyPos += realProcessedSize; 181 #endif 182 return ConvertBoolToHRESULT(result); 183 184 #else 185 186 if (processedSize != NULL) 187 *processedSize = 0; 188 ssize_t res = File.Read(data, (size_t)size); 189 if (res == -1) 190 return E_FAIL; 191 if (processedSize != NULL) 192 *processedSize = (UInt32)res; 193 return S_OK; 194 195 #endif 196} 197 198#ifdef UNDER_CE 199STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) 200{ 201 size_t s2 = fread(data, 1, size, stdout); 202 if (processedSize != 0) 203 *processedSize = s2; 204 return (s2 = size) ? S_OK : E_FAIL; 205} 206#else 207STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) 208{ 209 #ifdef _WIN32 210 211 DWORD realProcessedSize; 212 UInt32 sizeTemp = (1 << 20); 213 if (sizeTemp > size) 214 sizeTemp = size; 215 BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL); 216 if (processedSize != NULL) 217 *processedSize = realProcessedSize; 218 if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE) 219 return S_OK; 220 return ConvertBoolToHRESULT(res != FALSE); 221 222 #else 223 224 if (processedSize != NULL) 225 *processedSize = 0; 226 ssize_t res; 227 do 228 { 229 res = read(0, data, (size_t)size); 230 } 231 while (res < 0 && (errno == EINTR)); 232 if (res == -1) 233 return E_FAIL; 234 if (processedSize != NULL) 235 *processedSize = (UInt32)res; 236 return S_OK; 237 238 #endif 239} 240 241#endif 242 243STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, 244 UInt64 *newPosition) 245{ 246 if (seekOrigin >= 3) 247 return STG_E_INVALIDFUNCTION; 248 249 #ifdef USE_WIN_FILE 250 251 #ifdef SUPPORT_DEVICE_FILE 252 if (File.IsDeviceFile) 253 { 254 UInt64 newVirtPos = offset; 255 switch(seekOrigin) 256 { 257 case STREAM_SEEK_SET: break; 258 case STREAM_SEEK_CUR: newVirtPos += VirtPos; break; 259 case STREAM_SEEK_END: newVirtPos += File.Length; break; 260 default: return STG_E_INVALIDFUNCTION; 261 } 262 VirtPos = newVirtPos; 263 if (newPosition) 264 *newPosition = newVirtPos; 265 return S_OK; 266 } 267 #endif 268 269 UInt64 realNewPosition; 270 bool result = File.Seek(offset, seekOrigin, realNewPosition); 271 272 #ifdef SUPPORT_DEVICE_FILE 273 PhyPos = VirtPos = realNewPosition; 274 #endif 275 276 if (newPosition != NULL) 277 *newPosition = realNewPosition; 278 return ConvertBoolToHRESULT(result); 279 280 #else 281 282 off_t res = File.Seek(offset, seekOrigin); 283 if (res == -1) 284 return E_FAIL; 285 if (newPosition != NULL) 286 *newPosition = (UInt64)res; 287 return S_OK; 288 289 #endif 290} 291 292STDMETHODIMP CInFileStream::GetSize(UInt64 *size) 293{ 294 return ConvertBoolToHRESULT(File.GetLength(*size)); 295} 296 297 298////////////////////////// 299// COutFileStream 300 301HRESULT COutFileStream::Close() 302{ 303 return ConvertBoolToHRESULT(File.Close()); 304} 305 306STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize) 307{ 308 #ifdef USE_WIN_FILE 309 310 UInt32 realProcessedSize; 311 bool result = File.WritePart(data, size, realProcessedSize); 312 ProcessedSize += realProcessedSize; 313 if (processedSize != NULL) 314 *processedSize = realProcessedSize; 315 return ConvertBoolToHRESULT(result); 316 317 #else 318 319 if (processedSize != NULL) 320 *processedSize = 0; 321 ssize_t res = File.Write(data, (size_t)size); 322 if (res == -1) 323 return E_FAIL; 324 if (processedSize != NULL) 325 *processedSize = (UInt32)res; 326 ProcessedSize += res; 327 return S_OK; 328 329 #endif 330} 331 332STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 333{ 334 if (seekOrigin >= 3) 335 return STG_E_INVALIDFUNCTION; 336 #ifdef USE_WIN_FILE 337 338 UInt64 realNewPosition; 339 bool result = File.Seek(offset, seekOrigin, realNewPosition); 340 if (newPosition != NULL) 341 *newPosition = realNewPosition; 342 return ConvertBoolToHRESULT(result); 343 344 #else 345 346 off_t res = File.Seek(offset, seekOrigin); 347 if (res == -1) 348 return E_FAIL; 349 if (newPosition != NULL) 350 *newPosition = (UInt64)res; 351 return S_OK; 352 353 #endif 354} 355 356STDMETHODIMP COutFileStream::SetSize(UInt64 newSize) 357{ 358 #ifdef USE_WIN_FILE 359 UInt64 currentPos; 360 if (!File.Seek(0, FILE_CURRENT, currentPos)) 361 return E_FAIL; 362 bool result = File.SetLength(newSize); 363 UInt64 currentPos2; 364 result = result && File.Seek(currentPos, currentPos2); 365 return result ? S_OK : E_FAIL; 366 #else 367 return E_FAIL; 368 #endif 369} 370 371#ifdef UNDER_CE 372STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize) 373{ 374 size_t s2 = fwrite(data, 1, size, stdout); 375 if (processedSize != 0) 376 *processedSize = s2; 377 return (s2 = size) ? S_OK : E_FAIL; 378} 379#else 380STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize) 381{ 382 if (processedSize != NULL) 383 *processedSize = 0; 384 385 #ifdef _WIN32 386 UInt32 realProcessedSize; 387 BOOL res = TRUE; 388 if (size > 0) 389 { 390 // Seems that Windows doesn't like big amounts writing to stdout. 391 // So we limit portions by 32KB. 392 UInt32 sizeTemp = (1 << 15); 393 if (sizeTemp > size) 394 sizeTemp = size; 395 res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), 396 data, sizeTemp, (DWORD *)&realProcessedSize, NULL); 397 size -= realProcessedSize; 398 data = (const void *)((const Byte *)data + realProcessedSize); 399 if (processedSize != NULL) 400 *processedSize += realProcessedSize; 401 } 402 return ConvertBoolToHRESULT(res != FALSE); 403 404 #else 405 406 ssize_t res; 407 do 408 { 409 res = write(1, data, (size_t)size); 410 } 411 while (res < 0 && (errno == EINTR)); 412 if (res == -1) 413 return E_FAIL; 414 if (processedSize != NULL) 415 *processedSize = (UInt32)res; 416 return S_OK; 417 418 return S_OK; 419 #endif 420} 421 422#endif 423