1 : /******************************************************************************
2 : * $Id: cpl_vsil_buffered_reader.cpp 19683 2010-05-13 11:54:59Z rouault $
3 : *
4 : * Project: VSI Virtual File System
5 : * Purpose: Implementation of buffered reader IO functions.
6 : * Author: Even Rouault, even.rouault at mines-paris.org
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Even Rouault
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : /* The intent of this class is to be a wrapper around an underlying virtual */
31 : /* handle and add very basic caching of last read bytes, so that a backward */
32 : /* seek of a few bytes doesn't require a seek on the underlying virtual handle. */
33 : /* This enable us to improve dramatically the performance of CPLReadLine2L() on */
34 : /* a gzip file */
35 :
36 : #include "cpl_vsi_virtual.h"
37 :
38 : #define MAX_BUFFER_SIZE 65536
39 :
40 : CPL_CVSID("$Id: cpl_vsil_buffered_reader.cpp 19683 2010-05-13 11:54:59Z rouault $");
41 :
42 : class VSIBufferedReaderHandle : public VSIVirtualHandle
43 : {
44 : VSIVirtualHandle* poBaseHandle;
45 : char pabyBuffer[MAX_BUFFER_SIZE];
46 : GUIntBig nBufferOffset;
47 : int nBufferSize;
48 : GUIntBig nCurOffset;
49 :
50 : public:
51 :
52 : VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle);
53 : ~VSIBufferedReaderHandle();
54 :
55 : virtual int Seek( vsi_l_offset nOffset, int nWhence );
56 : virtual vsi_l_offset Tell();
57 : virtual size_t Read( void *pBuffer, size_t nSize, size_t nMemb );
58 : virtual size_t Write( const void *pBuffer, size_t nSize, size_t nMemb );
59 : virtual int Eof();
60 : virtual int Flush();
61 : virtual int Close();
62 : };
63 :
64 : /************************************************************************/
65 : /* VSICreateBufferedReaderHandle() */
66 : /************************************************************************/
67 :
68 66 : VSIVirtualHandle* VSICreateBufferedReaderHandle(VSIVirtualHandle* poBaseHandle)
69 : {
70 66 : return new VSIBufferedReaderHandle(poBaseHandle);
71 : }
72 :
73 : /************************************************************************/
74 : /* VSIBufferedReaderHandle() */
75 : /************************************************************************/
76 :
77 66 : VSIBufferedReaderHandle::VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle)
78 : {
79 66 : this->poBaseHandle = poBaseHandle;
80 66 : nBufferOffset = 0;
81 66 : nBufferSize = 0;
82 66 : nCurOffset = 0;
83 66 : }
84 :
85 : /************************************************************************/
86 : /* ~VSIBufferedReaderHandle() */
87 : /************************************************************************/
88 :
89 66 : VSIBufferedReaderHandle::~VSIBufferedReaderHandle()
90 : {
91 66 : delete poBaseHandle;
92 66 : }
93 :
94 : /************************************************************************/
95 : /* Seek() */
96 : /************************************************************************/
97 :
98 205405 : int VSIBufferedReaderHandle::Seek( vsi_l_offset nOffset, int nWhence )
99 : {
100 205405 : if (nWhence == SEEK_CUR)
101 120 : nCurOffset += nOffset;
102 205285 : else if (nWhence == SEEK_END)
103 : {
104 5 : poBaseHandle->Seek(nOffset, nWhence);
105 5 : nCurOffset = poBaseHandle->Tell();
106 : }
107 : else
108 205280 : nCurOffset = nOffset;
109 :
110 205405 : return 0;
111 : }
112 :
113 : /************************************************************************/
114 : /* Tell() */
115 : /************************************************************************/
116 :
117 205266 : vsi_l_offset VSIBufferedReaderHandle::Tell()
118 : {
119 205266 : return nCurOffset;
120 : }
121 : /************************************************************************/
122 : /* Read() */
123 : /************************************************************************/
124 :
125 206485 : size_t VSIBufferedReaderHandle::Read( void *pBuffer, size_t nSize, size_t nMemb )
126 : {
127 206485 : const size_t nTotalToRead = nSize * nMemb;
128 :
129 206485 : if (nSize == 0)
130 0 : return 0;
131 :
132 206485 : if (nBufferSize != 0 &&
133 : nCurOffset >= nBufferOffset && nCurOffset <= nBufferOffset + nBufferSize)
134 : {
135 : /* We try to read from an offset located within the buffer */
136 206294 : const int nReadInBuffer = MIN(nTotalToRead, nBufferOffset + nBufferSize - nCurOffset);
137 206294 : memcpy(pBuffer, pabyBuffer + nCurOffset - nBufferOffset, nReadInBuffer);
138 206294 : const int nToReadInFile = nTotalToRead - nReadInBuffer;
139 206294 : if (nToReadInFile > 0)
140 : {
141 : /* The beginning of the the data to read is located in the buffer */
142 : /* but the end must be read from the file */
143 : //CPLAssert(poBaseHandle->Tell() == nBufferOffset + nBufferSize);
144 :
145 206285 : const int nReadInFile = poBaseHandle->Read((GByte*)pBuffer + nReadInBuffer, 1, nToReadInFile);
146 206285 : const int nRead = nReadInBuffer + nReadInFile;
147 :
148 206285 : nBufferSize = MIN(nRead, MAX_BUFFER_SIZE);
149 206285 : nBufferOffset = nCurOffset + nRead - nBufferSize;
150 206285 : memcpy(pabyBuffer, (GByte*)pBuffer + nRead - nBufferSize, nBufferSize);
151 :
152 206285 : nCurOffset += nRead;
153 : //CPLAssert(poBaseHandle->Tell() == nBufferOffset + nBufferSize);
154 : //CPLAssert(poBaseHandle->Tell() == nCurOffset);
155 :
156 206285 : return nRead / nSize;
157 : }
158 : else
159 : {
160 : /* The data to read is completely located within the buffer */
161 9 : nCurOffset += nTotalToRead;
162 9 : return nTotalToRead / nSize;
163 : }
164 : }
165 : else
166 : {
167 : /* We try either to read before or after the buffer, so a seek is necessary */
168 191 : poBaseHandle->Seek(nCurOffset, SEEK_SET);
169 191 : const int nReadInFile = poBaseHandle->Read(pBuffer, 1, nTotalToRead);
170 191 : nBufferSize = MIN(nReadInFile, MAX_BUFFER_SIZE);
171 191 : nBufferOffset = nCurOffset + nReadInFile - nBufferSize;
172 191 : memcpy(pabyBuffer, (GByte*)pBuffer + nReadInFile - nBufferSize, nBufferSize);
173 :
174 191 : nCurOffset += nReadInFile;
175 : //CPLAssert(poBaseHandle->Tell() == nBufferOffset + nBufferSize);
176 : //CPLAssert(poBaseHandle->Tell() == nCurOffset);
177 :
178 191 : return nReadInFile / nSize;
179 : }
180 :
181 : }
182 :
183 : /************************************************************************/
184 : /* Write() */
185 : /************************************************************************/
186 :
187 0 : size_t VSIBufferedReaderHandle::Write( const void *pBuffer, size_t nSize, size_t nMemb )
188 : {
189 : CPLError(CE_Failure, CPLE_NotSupported,
190 0 : "VSIFWriteL is not supported on buffer reader streams\n");
191 0 : return 0;
192 : }
193 :
194 :
195 : /************************************************************************/
196 : /* Eof() */
197 : /************************************************************************/
198 :
199 0 : int VSIBufferedReaderHandle::Eof()
200 : {
201 0 : return poBaseHandle->Eof();
202 : }
203 :
204 : /************************************************************************/
205 : /* Flush() */
206 : /************************************************************************/
207 :
208 0 : int VSIBufferedReaderHandle::Flush()
209 : {
210 0 : return 0;
211 : }
212 :
213 : /************************************************************************/
214 : /* Close() */
215 : /************************************************************************/
216 :
217 66 : int VSIBufferedReaderHandle::Close()
218 : {
219 66 : if (poBaseHandle)
220 : {
221 66 : poBaseHandle->Close();
222 66 : delete poBaseHandle;
223 66 : poBaseHandle = NULL;
224 : }
225 66 : return 0;
226 : }
|