1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/fileback.cpp
3 // Purpose: Back an input stream with memory or a file
4 // Author: Mike Wetherell
6 // Copyright: (c) 2006 Mike Wetherell
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
19 #include "wx/fileback.h"
26 #include "wx/private/filename.h"
28 // Prefer wxFFile unless wxFile has large file support but wxFFile does not.
30 #if wxUSE_FFILE && (defined wxHAS_LARGE_FFILES || !defined wxHAS_LARGE_FILES)
31 typedef wxFFile wxBFFile
;
32 static const bool wxBadSeek
= false;
34 typedef wxFile wxBFFile
;
35 static const wxFileOffset wxBadSeek
= wxInvalidOffset
;
38 /////////////////////////////////////////////////////////////////////////////
39 // Backing file implementation
41 class wxBackingFileImpl
44 wxBackingFileImpl(wxInputStream
*stream
,
46 const wxString
& prefix
);
49 void Release() { if (--m_refcount
== 0) delete this; }
50 wxBackingFileImpl
*AddRef() { m_refcount
++; return this; }
52 wxStreamError
ReadAt(wxFileOffset pos
, void *buffer
, size_t *size
);
53 wxFileOffset
GetLength() const;
58 wxInputStream
*m_stream
;
59 wxStreamError m_parenterror
;
68 wxFileOffset m_filelen
;
71 wxBackingFileImpl::wxBackingFileImpl(wxInputStream
*stream
,
73 const wxString
& prefix
)
76 m_parenterror(wxSTREAM_NO_ERROR
),
83 wxFileOffset len
= m_stream
->GetLength();
85 if (len
>= 0 && len
+ size_t(1) < m_bufsize
)
86 m_bufsize
= size_t(len
+ 1);
89 m_buf
= new char[m_bufsize
];
92 wxBackingFileImpl::~wxBackingFileImpl()
97 if (!m_filename
.empty())
98 wxRemoveFile(m_filename
);
101 wxStreamError
wxBackingFileImpl::ReadAt(wxFileOffset pos
,
105 size_t reqestedSize
= *size
;
108 // size1 is the number of bytes it will read directly from the backing
109 // file. size2 is any remaining bytes not yet backed, these are returned
110 // from the buffer or read from the parent stream.
113 if (pos
+ reqestedSize
<= m_filelen
+ size_t(0)) {
114 size1
= reqestedSize
;
116 } else if (pos
< m_filelen
) {
117 size1
= size_t(m_filelen
- pos
);
118 size2
= reqestedSize
- size1
;
121 size2
= reqestedSize
;
125 return wxSTREAM_READ_ERROR
;
127 // read the backing file
129 if (m_file
.Seek(pos
) == wxBadSeek
)
130 return wxSTREAM_READ_ERROR
;
132 ssize_t n
= m_file
.Read(buffer
, size1
);
139 return wxSTREAM_READ_ERROR
;
142 // read from the buffer or parent stream
145 while (*size
< reqestedSize
)
147 // if pos is further ahead than the parent has been read so far,
148 // then read forward in the parent stream
149 while (pos
- m_filelen
+ size_t(0) >= m_buflen
)
151 // if the parent is small enough, don't use a backing file
152 // just the buffer memory
153 if (!m_stream
&& m_filelen
== 0)
154 return m_parenterror
;
156 // before refilling the buffer write out the current buffer
157 // to the backing file if there is anything in it
160 if (!m_file
.IsOpened())
161 if (!wxCreateTempFile(m_prefix
, &m_file
, &m_filename
))
162 return wxSTREAM_READ_ERROR
;
164 if (m_file
.Seek(m_filelen
) == wxBadSeek
)
165 return wxSTREAM_READ_ERROR
;
167 size_t count
= m_file
.Write(m_buf
, m_buflen
);
170 if (count
< m_buflen
) {
178 m_parenterror
= wxSTREAM_READ_ERROR
;
179 return m_parenterror
;
191 return m_parenterror
;
194 m_buflen
= m_stream
->Read(m_buf
, m_bufsize
).LastRead();
196 if (m_buflen
< m_bufsize
) {
197 m_parenterror
= m_stream
->GetLastError();
198 if (m_parenterror
== wxSTREAM_NO_ERROR
)
199 m_parenterror
= wxSTREAM_EOF
;
205 // copy to the user's buffer
206 size_t start
= size_t(pos
- m_filelen
);
207 size_t len
= wxMin(m_buflen
- start
, reqestedSize
- *size
);
209 memcpy((char*)buffer
+ *size
, m_buf
+ start
, len
);
215 return wxSTREAM_NO_ERROR
;
218 wxFileOffset
wxBackingFileImpl::GetLength() const
220 if (m_parenterror
!= wxSTREAM_EOF
) {
222 return m_stream
->GetLength();
224 return m_filelen
+ m_buflen
;
228 /////////////////////////////////////////////////////////////////////////////
229 // Backing File, the handle part
231 wxBackingFile::wxBackingFile(wxInputStream
*stream
,
233 const wxString
& prefix
)
234 : m_impl(new wxBackingFileImpl(stream
, bufsize
, prefix
))
238 wxBackingFile::wxBackingFile(const wxBackingFile
& backer
)
239 : m_impl(backer
.m_impl
? backer
.m_impl
->AddRef() : NULL
)
243 wxBackingFile
& wxBackingFile::operator=(const wxBackingFile
& backer
)
245 if (backer
.m_impl
!= m_impl
) {
249 m_impl
= backer
.m_impl
;
258 wxBackingFile::~wxBackingFile()
265 /////////////////////////////////////////////////////////////////////////////
268 wxBackedInputStream::wxBackedInputStream(const wxBackingFile
& backer
)
274 wxFileOffset
wxBackedInputStream::GetLength() const
276 return m_backer
.m_impl
->GetLength();
279 wxFileOffset
wxBackedInputStream::FindLength() const
281 wxFileOffset len
= GetLength();
283 if (len
== wxInvalidOffset
&& IsOk()) {
284 // read a byte at 7ff...ffe
285 wxFileOffset pos
= 1;
286 pos
<<= sizeof(pos
) * 8 - 1;
290 m_backer
.m_impl
->ReadAt(pos
, &ch
, &size
);
297 size_t wxBackedInputStream::OnSysRead(void *buffer
, size_t size
)
302 m_lasterror
= m_backer
.m_impl
->ReadAt(m_pos
, buffer
, &size
);
307 wxFileOffset
wxBackedInputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
317 wxFileOffset len
= GetLength();
318 if (len
== wxInvalidOffset
)
319 return wxInvalidOffset
;
333 wxFileOffset
wxBackedInputStream::OnSysTell() const
338 #endif // wxUSE_BACKINGFILE