]> git.saurik.com Git - wxWidgets.git/blame - src/common/fileback.cpp
leave i386 compiler to default
[wxWidgets.git] / src / common / fileback.cpp
CommitLineData
f8f6c91a
MW
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/fileback.cpp
3// Purpose: Back an input stream with memory or a file
4// Author: Mike Wetherell
f8f6c91a
MW
5// Copyright: (c) 2006 Mike Wetherell
6// Licence: wxWindows licence
7/////////////////////////////////////////////////////////////////////////////
8
9// For compilers that support precompilation, includes "wx.h".
10#include "wx/wxprec.h"
11
12#ifdef __BORLANDC__
13 #pragma hdrstop
14#endif
15
916af76f 16#if wxUSE_FILESYSTEM
f8f6c91a 17
916af76f 18#include "wx/private/fileback.h"
360c6a85 19
f8f6c91a 20#ifndef WX_PRECOMP
f8f6c91a
MW
21 #include "wx/utils.h"
22 #include "wx/log.h"
23#endif
24
f8f6c91a
MW
25#include "wx/private/filename.h"
26
27// Prefer wxFFile unless wxFile has large file support but wxFFile does not.
28//
82b99cf9 29#if wxUSE_FFILE && (defined wxHAS_LARGE_FFILES || !defined wxHAS_LARGE_FILES)
f8f6c91a
MW
30typedef wxFFile wxBFFile;
31static const bool wxBadSeek = false;
32#else
33typedef wxFile wxBFFile;
34static const wxFileOffset wxBadSeek = wxInvalidOffset;
35#endif
36
37/////////////////////////////////////////////////////////////////////////////
38// Backing file implementation
39
40class wxBackingFileImpl
41{
42public:
43 wxBackingFileImpl(wxInputStream *stream,
44 size_t bufsize,
45 const wxString& prefix);
46 ~wxBackingFileImpl();
47
48 void Release() { if (--m_refcount == 0) delete this; }
49 wxBackingFileImpl *AddRef() { m_refcount++; return this; }
50
51 wxStreamError ReadAt(wxFileOffset pos, void *buffer, size_t *size);
52 wxFileOffset GetLength() const;
53
54private:
55 int m_refcount;
56
57 wxInputStream *m_stream;
58 wxStreamError m_parenterror;
59
60 char *m_buf;
61 size_t m_bufsize;
62 size_t m_buflen;
63
64 wxString m_prefix;
65 wxString m_filename;
66 wxBFFile m_file;
67 wxFileOffset m_filelen;
68};
69
70wxBackingFileImpl::wxBackingFileImpl(wxInputStream *stream,
71 size_t bufsize,
72 const wxString& prefix)
73 : m_refcount(1),
74 m_stream(stream),
75 m_parenterror(wxSTREAM_NO_ERROR),
76 m_buf(NULL),
77 m_bufsize(bufsize),
78 m_buflen(0),
79 m_prefix(prefix),
80 m_filelen(0)
81{
82 wxFileOffset len = m_stream->GetLength();
83
12811c1c 84 if (len >= 0 && len + size_t(1) < m_bufsize)
8aa3cd14 85 m_bufsize = size_t(len + 1);
f8f6c91a
MW
86
87 if (m_bufsize)
88 m_buf = new char[m_bufsize];
89}
90
91wxBackingFileImpl::~wxBackingFileImpl()
92{
93 delete m_stream;
94 delete [] m_buf;
95
96 if (!m_filename.empty())
97 wxRemoveFile(m_filename);
98}
99
100wxStreamError wxBackingFileImpl::ReadAt(wxFileOffset pos,
101 void *buffer,
102 size_t *size)
103{
104 size_t reqestedSize = *size;
105 *size = 0;
106
107 // size1 is the number of bytes it will read directly from the backing
108 // file. size2 is any remaining bytes not yet backed, these are returned
109 // from the buffer or read from the parent stream.
110 size_t size1, size2;
111
112 if (pos + reqestedSize <= m_filelen + size_t(0)) {
113 size1 = reqestedSize;
114 size2 = 0;
115 } else if (pos < m_filelen) {
4ee9daf4 116 size1 = size_t(m_filelen - pos);
f8f6c91a
MW
117 size2 = reqestedSize - size1;
118 } else {
119 size1 = 0;
120 size2 = reqestedSize;
121 }
122
123 if (pos < 0)
124 return wxSTREAM_READ_ERROR;
125
126 // read the backing file
127 if (size1) {
128 if (m_file.Seek(pos) == wxBadSeek)
129 return wxSTREAM_READ_ERROR;
130
131 ssize_t n = m_file.Read(buffer, size1);
132 if (n > 0) {
133 *size = n;
134 pos += n;
135 }
136
137 if (*size < size1)
138 return wxSTREAM_READ_ERROR;
139 }
140
141 // read from the buffer or parent stream
142 if (size2)
143 {
144 while (*size < reqestedSize)
145 {
146 // if pos is further ahead than the parent has been read so far,
147 // then read forward in the parent stream
148 while (pos - m_filelen + size_t(0) >= m_buflen)
149 {
150 // if the parent is small enough, don't use a backing file
151 // just the buffer memory
152 if (!m_stream && m_filelen == 0)
153 return m_parenterror;
154
155 // before refilling the buffer write out the current buffer
156 // to the backing file if there is anything in it
157 if (m_buflen)
158 {
159 if (!m_file.IsOpened())
160 if (!wxCreateTempFile(m_prefix, &m_file, &m_filename))
161 return wxSTREAM_READ_ERROR;
162
163 if (m_file.Seek(m_filelen) == wxBadSeek)
164 return wxSTREAM_READ_ERROR;
165
166 size_t count = m_file.Write(m_buf, m_buflen);
167 m_filelen += count;
168
169 if (count < m_buflen) {
5276b0a5 170 wxDELETE(m_stream);
f8f6c91a 171 if (count > 0) {
5276b0a5 172 wxDELETEA(m_buf);
f8f6c91a
MW
173 m_buflen = 0;
174 }
175 m_parenterror = wxSTREAM_READ_ERROR;
176 return m_parenterror;
177 }
178
179 m_buflen = 0;
180
181 if (!m_stream) {
5276b0a5 182 wxDELETEA(m_buf);
f8f6c91a
MW
183 }
184 }
185
186 if (!m_stream)
187 return m_parenterror;
188
189 // refill buffer
190 m_buflen = m_stream->Read(m_buf, m_bufsize).LastRead();
191
192 if (m_buflen < m_bufsize) {
193 m_parenterror = m_stream->GetLastError();
194 if (m_parenterror == wxSTREAM_NO_ERROR)
195 m_parenterror = wxSTREAM_EOF;
5276b0a5 196 wxDELETE(m_stream);
f8f6c91a
MW
197 }
198 }
199
200 // copy to the user's buffer
4ee9daf4 201 size_t start = size_t(pos - m_filelen);
f8f6c91a
MW
202 size_t len = wxMin(m_buflen - start, reqestedSize - *size);
203
204 memcpy((char*)buffer + *size, m_buf + start, len);
205 *size += len;
206 pos += len;
207 }
208 }
209
210 return wxSTREAM_NO_ERROR;
211}
212
213wxFileOffset wxBackingFileImpl::GetLength() const
214{
215 if (m_parenterror != wxSTREAM_EOF) {
216 wxLogNull nolog;
217 return m_stream->GetLength();
218 }
219 return m_filelen + m_buflen;
220}
221
222
223/////////////////////////////////////////////////////////////////////////////
224// Backing File, the handle part
225
226wxBackingFile::wxBackingFile(wxInputStream *stream,
227 size_t bufsize,
228 const wxString& prefix)
229 : m_impl(new wxBackingFileImpl(stream, bufsize, prefix))
230{
231}
232
233wxBackingFile::wxBackingFile(const wxBackingFile& backer)
234 : m_impl(backer.m_impl ? backer.m_impl->AddRef() : NULL)
235{
236}
237
238wxBackingFile& wxBackingFile::operator=(const wxBackingFile& backer)
239{
240 if (backer.m_impl != m_impl) {
241 if (m_impl)
242 m_impl->Release();
243
244 m_impl = backer.m_impl;
245
246 if (m_impl)
247 m_impl->AddRef();
248 }
249
250 return *this;
251}
252
253wxBackingFile::~wxBackingFile()
254{
255 if (m_impl)
256 m_impl->Release();
257}
258
259
260/////////////////////////////////////////////////////////////////////////////
261// Input stream
262
263wxBackedInputStream::wxBackedInputStream(const wxBackingFile& backer)
264 : m_backer(backer),
265 m_pos(0)
266{
267}
268
1ab48408
MW
269wxFileOffset wxBackedInputStream::GetLength() const
270{
271 return m_backer.m_impl->GetLength();
272}
273
274wxFileOffset wxBackedInputStream::FindLength() const
275{
276 wxFileOffset len = GetLength();
277
278 if (len == wxInvalidOffset && IsOk()) {
279 // read a byte at 7ff...ffe
280 wxFileOffset pos = 1;
281 pos <<= sizeof(pos) * 8 - 1;
282 pos = ~pos - 1;
283 char ch;
284 size_t size = 1;
285 m_backer.m_impl->ReadAt(pos, &ch, &size);
286 len = GetLength();
287 }
288
289 return len;
290}
03647350 291
f8f6c91a
MW
292size_t wxBackedInputStream::OnSysRead(void *buffer, size_t size)
293{
294 if (!IsOk())
295 return 0;
296
297 m_lasterror = m_backer.m_impl->ReadAt(m_pos, buffer, &size);
298 m_pos += size;
299 return size;
300}
301
f8f6c91a
MW
302wxFileOffset wxBackedInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
303{
304 switch (mode) {
305 case wxFromCurrent:
306 {
307 m_pos += pos;
308 break;
309 }
310 case wxFromEnd:
311 {
312 wxFileOffset len = GetLength();
313 if (len == wxInvalidOffset)
314 return wxInvalidOffset;
315 m_pos = len + pos;
316 break;
317 }
318 default:
319 {
320 m_pos = pos;
321 break;
322 }
323 }
324
325 return m_pos;
326}
327
328wxFileOffset wxBackedInputStream::OnSysTell() const
329{
330 return m_pos;
331}
332
916af76f 333#endif // wxUSE_FILESYSTEM