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#include "FileStreams.h"
12
13static inline HRESULT ConvertBoolToHRESULT(bool result)
14{
15  #ifdef _WIN32
16  if (result)
17    return S_OK;
18  DWORD lastError = ::GetLastError();
19  if (lastError == 0)
20    return E_FAIL;
21  return lastError;
22  #else
23  return result ? S_OK: E_FAIL;
24  #endif
25}
26
27bool CInFileStream::Open(LPCTSTR fileName)
28{
29  return File.Open(fileName);
30}
31
32#ifdef USE_WIN_FILE
33#ifndef _UNICODE
34bool CInFileStream::Open(LPCWSTR fileName)
35{
36  return File.Open(fileName);
37}
38#endif
39#endif
40
41bool CInFileStream::OpenShared(LPCTSTR fileName, bool shareForWrite)
42{
43  return File.OpenShared(fileName, shareForWrite);
44}
45
46#ifdef USE_WIN_FILE
47#ifndef _UNICODE
48bool CInFileStream::OpenShared(LPCWSTR fileName, bool shareForWrite)
49{
50  return File.OpenShared(fileName, shareForWrite);
51}
52#endif
53#endif
54
55STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
56{
57  #ifdef USE_WIN_FILE
58
59  UInt32 realProcessedSize;
60  bool result = File.ReadPart(data, size, realProcessedSize);
61  if(processedSize != NULL)
62    *processedSize = realProcessedSize;
63  return ConvertBoolToHRESULT(result);
64
65  #else
66
67  if(processedSize != NULL)
68    *processedSize = 0;
69  ssize_t res = File.Read(data, (size_t)size);
70  if (res == -1)
71    return E_FAIL;
72  if(processedSize != NULL)
73    *processedSize = (UInt32)res;
74  return S_OK;
75
76  #endif
77}
78
79#ifndef _WIN32_WCE
80STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
81{
82  #ifdef _WIN32
83  UInt32 realProcessedSize;
84  BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE),
85      data, size, (DWORD *)&realProcessedSize, NULL);
86  if(processedSize != NULL)
87    *processedSize = realProcessedSize;
88  if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE)
89    return S_OK;
90  return ConvertBoolToHRESULT(res != FALSE);
91
92  #else
93
94  if(processedSize != NULL)
95    *processedSize = 0;
96  ssize_t res;
97  do
98  {
99    res = read(0, data, (size_t)size);
100  }
101  while (res < 0 && (errno == EINTR));
102  if (res == -1)
103    return E_FAIL;
104  if(processedSize != NULL)
105    *processedSize = (UInt32)res;
106  return S_OK;
107
108  #endif
109}
110
111#endif
112
113STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin,
114    UInt64 *newPosition)
115{
116  if(seekOrigin >= 3)
117    return STG_E_INVALIDFUNCTION;
118
119  #ifdef USE_WIN_FILE
120
121  UInt64 realNewPosition;
122  bool result = File.Seek(offset, seekOrigin, realNewPosition);
123  if(newPosition != NULL)
124    *newPosition = realNewPosition;
125  return ConvertBoolToHRESULT(result);
126
127  #else
128
129  off_t res = File.Seek(offset, seekOrigin);
130  if (res == -1)
131    return E_FAIL;
132  if(newPosition != NULL)
133    *newPosition = (UInt64)res;
134  return S_OK;
135
136  #endif
137}
138
139STDMETHODIMP CInFileStream::GetSize(UInt64 *size)
140{
141  return ConvertBoolToHRESULT(File.GetLength(*size));
142}
143
144
145//////////////////////////
146// COutFileStream
147
148HRESULT COutFileStream::Close()
149{
150  return ConvertBoolToHRESULT(File.Close());
151}
152
153STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
154{
155  #ifdef USE_WIN_FILE
156
157  UInt32 realProcessedSize;
158  bool result = File.WritePart(data, size, realProcessedSize);
159  ProcessedSize += realProcessedSize;
160  if(processedSize != NULL)
161    *processedSize = realProcessedSize;
162  return ConvertBoolToHRESULT(result);
163
164  #else
165
166  if(processedSize != NULL)
167    *processedSize = 0;
168  ssize_t res = File.Write(data, (size_t)size);
169  if (res == -1)
170    return E_FAIL;
171  if(processedSize != NULL)
172    *processedSize = (UInt32)res;
173  ProcessedSize += res;
174  return S_OK;
175
176  #endif
177}
178
179STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
180{
181  if(seekOrigin >= 3)
182    return STG_E_INVALIDFUNCTION;
183  #ifdef USE_WIN_FILE
184
185  UInt64 realNewPosition;
186  bool result = File.Seek(offset, seekOrigin, realNewPosition);
187  if(newPosition != NULL)
188    *newPosition = realNewPosition;
189  return ConvertBoolToHRESULT(result);
190
191  #else
192
193  off_t res = File.Seek(offset, seekOrigin);
194  if (res == -1)
195    return E_FAIL;
196  if(newPosition != NULL)
197    *newPosition = (UInt64)res;
198  return S_OK;
199
200  #endif
201}
202
203STDMETHODIMP COutFileStream::SetSize(Int64 newSize)
204{
205  #ifdef USE_WIN_FILE
206  UInt64 currentPos;
207  if(!File.Seek(0, FILE_CURRENT, currentPos))
208    return E_FAIL;
209  bool result = File.SetLength(newSize);
210  UInt64 currentPos2;
211  result = result && File.Seek(currentPos, currentPos2);
212  return result ? S_OK : E_FAIL;
213  #else
214  return E_FAIL;
215  #endif
216}
217
218#ifndef _WIN32_WCE
219STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
220{
221  if(processedSize != NULL)
222    *processedSize = 0;
223
224  #ifdef _WIN32
225  UInt32 realProcessedSize;
226  BOOL res = TRUE;
227  if (size > 0)
228  {
229    // Seems that Windows doesn't like big amounts writing to stdout.
230    // So we limit portions by 32KB.
231    UInt32 sizeTemp = (1 << 15);
232    if (sizeTemp > size)
233      sizeTemp = size;
234    res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
235        data, sizeTemp, (DWORD *)&realProcessedSize, NULL);
236    size -= realProcessedSize;
237    data = (const void *)((const Byte *)data + realProcessedSize);
238    if(processedSize != NULL)
239      *processedSize += realProcessedSize;
240  }
241  return ConvertBoolToHRESULT(res != FALSE);
242
243  #else
244
245  ssize_t res;
246  do
247  {
248    res = write(1, data, (size_t)size);
249  }
250  while (res < 0 && (errno == EINTR));
251  if (res == -1)
252    return E_FAIL;
253  if(processedSize != NULL)
254    *processedSize = (UInt32)res;
255  return S_OK;
256
257  return S_OK;
258  #endif
259}
260
261#endif
262