Line data Source code
1 : /**********************************************************************
2 : *
3 : * Project: CPL - Common Portability Library
4 : * Purpose: Implement VSI large file api for stdout
5 : * Author: Even Rouault, <even dot rouault at spatialys.com>
6 : *
7 : **********************************************************************
8 : * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "cpl_port.h"
30 : #include "cpl_vsi.h"
31 :
32 : #include <cstddef>
33 : #include <cstdio>
34 : #include <cstring>
35 : #if HAVE_FCNTL_H
36 : #include <fcntl.h>
37 : #endif
38 :
39 : #include "cpl_error.h"
40 : #include "cpl_vsi_virtual.h"
41 :
42 : #ifdef _WIN32
43 : #include <io.h>
44 : #include <fcntl.h>
45 : #endif
46 :
47 : static VSIWriteFunction pWriteFunction = fwrite;
48 : static FILE *pWriteStream = stdout;
49 :
50 : /************************************************************************/
51 : /* VSIStdoutSetRedirection() */
52 : /************************************************************************/
53 :
54 : /** Set an alternative write function and output file handle instead of
55 : * fwrite() / stdout.
56 : *
57 : * @param pFct Function with same signature as fwrite()
58 : * @param stream File handle on which to output. Passed to pFct.
59 : *
60 : * @since GDAL 2.0
61 : */
62 0 : void VSIStdoutSetRedirection(VSIWriteFunction pFct, FILE *stream)
63 : {
64 0 : pWriteFunction = pFct;
65 0 : pWriteStream = stream;
66 0 : }
67 :
68 : //! @cond Doxygen_Suppress
69 :
70 : /************************************************************************/
71 : /* ==================================================================== */
72 : /* VSIStdoutFilesystemHandler */
73 : /* ==================================================================== */
74 : /************************************************************************/
75 :
76 : class VSIStdoutFilesystemHandler final : public VSIFilesystemHandler
77 : {
78 : CPL_DISALLOW_COPY_ASSIGN(VSIStdoutFilesystemHandler)
79 :
80 : public:
81 1225 : VSIStdoutFilesystemHandler() = default;
82 :
83 : VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
84 : bool bSetError,
85 : CSLConstList /* papszOptions */) override;
86 : int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
87 : int nFlags) override;
88 :
89 0 : bool SupportsRead(const char * /* pszPath */) override
90 : {
91 0 : return false;
92 : }
93 : };
94 :
95 : /************************************************************************/
96 : /* ==================================================================== */
97 : /* VSIStdoutHandle */
98 : /* ==================================================================== */
99 : /************************************************************************/
100 :
101 : class VSIStdoutHandle final : public VSIVirtualHandle
102 : {
103 : CPL_DISALLOW_COPY_ASSIGN(VSIStdoutHandle)
104 :
105 : vsi_l_offset m_nOffset = 0;
106 :
107 : public:
108 3 : VSIStdoutHandle() = default;
109 6 : ~VSIStdoutHandle() override = default;
110 :
111 : int Seek(vsi_l_offset nOffset, int nWhence) override;
112 : vsi_l_offset Tell() override;
113 : size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
114 : size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
115 : int Eof() override;
116 : int Flush() override;
117 : int Close() override;
118 : };
119 :
120 : /************************************************************************/
121 : /* Seek() */
122 : /************************************************************************/
123 :
124 0 : int VSIStdoutHandle::Seek(vsi_l_offset nOffset, int nWhence)
125 :
126 : {
127 0 : if (nOffset == 0 && (nWhence == SEEK_END || nWhence == SEEK_CUR))
128 0 : return 0;
129 0 : if (nWhence == SEEK_SET && nOffset == Tell())
130 0 : return 0;
131 0 : CPLError(CE_Failure, CPLE_NotSupported, "Seek() unsupported on /vsistdout");
132 0 : return -1;
133 : }
134 :
135 : /************************************************************************/
136 : /* Tell() */
137 : /************************************************************************/
138 :
139 1 : vsi_l_offset VSIStdoutHandle::Tell()
140 : {
141 1 : return m_nOffset;
142 : }
143 :
144 : /************************************************************************/
145 : /* Flush() */
146 : /************************************************************************/
147 :
148 4 : int VSIStdoutHandle::Flush()
149 :
150 : {
151 4 : if (pWriteStream == stdout)
152 4 : return fflush(stdout);
153 : else
154 0 : return 0;
155 : }
156 :
157 : /************************************************************************/
158 : /* Read() */
159 : /************************************************************************/
160 :
161 0 : size_t VSIStdoutHandle::Read(void * /* pBuffer */, size_t /* nSize */,
162 : size_t /* nCount */)
163 : {
164 0 : CPLError(CE_Failure, CPLE_NotSupported, "Read() unsupported on /vsistdout");
165 0 : return 0;
166 : }
167 :
168 : /************************************************************************/
169 : /* Write() */
170 : /************************************************************************/
171 :
172 20 : size_t VSIStdoutHandle::Write(const void *pBuffer, size_t nSize, size_t nCount)
173 :
174 : {
175 20 : size_t nRet = pWriteFunction(pBuffer, nSize, nCount, pWriteStream);
176 20 : m_nOffset += nSize * nRet;
177 20 : return nRet;
178 : }
179 :
180 : /************************************************************************/
181 : /* Eof() */
182 : /************************************************************************/
183 :
184 0 : int VSIStdoutHandle::Eof()
185 :
186 : {
187 0 : return 0;
188 : }
189 :
190 : /************************************************************************/
191 : /* Close() */
192 : /************************************************************************/
193 :
194 3 : int VSIStdoutHandle::Close()
195 :
196 : {
197 3 : return Flush();
198 : }
199 :
200 : /************************************************************************/
201 : /* ==================================================================== */
202 : /* VSIStdoutFilesystemHandler */
203 : /* ==================================================================== */
204 : /************************************************************************/
205 :
206 : /************************************************************************/
207 : /* Open() */
208 : /************************************************************************/
209 :
210 : VSIVirtualHandle *
211 5 : VSIStdoutFilesystemHandler::Open(const char * /* pszFilename */,
212 : const char *pszAccess, bool /* bSetError */,
213 : CSLConstList /* papszOptions */)
214 : {
215 5 : if (strchr(pszAccess, 'r') != nullptr || strchr(pszAccess, '+') != nullptr)
216 : {
217 2 : CPLError(CE_Failure, CPLE_NotSupported,
218 : "Read or update mode not supported on /vsistdout");
219 2 : return nullptr;
220 : }
221 :
222 : #ifdef _WIN32
223 : if (strchr(pszAccess, 'b') != nullptr)
224 : setmode(fileno(stdout), O_BINARY);
225 : #endif
226 :
227 3 : return new VSIStdoutHandle;
228 : }
229 :
230 : /************************************************************************/
231 : /* Stat() */
232 : /************************************************************************/
233 :
234 10 : int VSIStdoutFilesystemHandler::Stat(const char * /* pszFilename */,
235 : VSIStatBufL *pStatBuf, int /* nFlags */)
236 :
237 : {
238 10 : memset(pStatBuf, 0, sizeof(VSIStatBufL));
239 :
240 10 : return -1;
241 : }
242 :
243 : /************************************************************************/
244 : /* ==================================================================== */
245 : /* VSIStdoutRedirectFilesystemHandler */
246 : /* ==================================================================== */
247 : /************************************************************************/
248 :
249 : class VSIStdoutRedirectFilesystemHandler final : public VSIFilesystemHandler
250 : {
251 : public:
252 : VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
253 : bool bSetError,
254 : CSLConstList /* papszOptions */) override;
255 : int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
256 : int nFlags) override;
257 :
258 1 : bool SupportsRead(const char * /* pszPath */) override
259 : {
260 1 : return false;
261 : }
262 : };
263 :
264 : /************************************************************************/
265 : /* ==================================================================== */
266 : /* VSIStdoutRedirectHandle */
267 : /* ==================================================================== */
268 : /************************************************************************/
269 :
270 : class VSIStdoutRedirectHandle final : public VSIVirtualHandle
271 : {
272 : VSIVirtualHandle *m_poHandle = nullptr;
273 :
274 : CPL_DISALLOW_COPY_ASSIGN(VSIStdoutRedirectHandle)
275 :
276 : public:
277 : explicit VSIStdoutRedirectHandle(VSIVirtualHandle *poHandle);
278 : ~VSIStdoutRedirectHandle() override;
279 :
280 : int Seek(vsi_l_offset nOffset, int nWhence) override;
281 : vsi_l_offset Tell() override;
282 : size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
283 : size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
284 : int Eof() override;
285 : int Flush() override;
286 : int Close() override;
287 : };
288 :
289 : /************************************************************************/
290 : /* VSIStdoutRedirectHandle() */
291 : /************************************************************************/
292 :
293 6 : VSIStdoutRedirectHandle::VSIStdoutRedirectHandle(VSIVirtualHandle *poHandle)
294 6 : : m_poHandle(poHandle)
295 : {
296 6 : }
297 :
298 : /************************************************************************/
299 : /* ~VSIStdoutRedirectHandle() */
300 : /************************************************************************/
301 :
302 12 : VSIStdoutRedirectHandle::~VSIStdoutRedirectHandle()
303 : {
304 6 : delete m_poHandle;
305 12 : }
306 :
307 : /************************************************************************/
308 : /* Seek() */
309 : /************************************************************************/
310 :
311 0 : int VSIStdoutRedirectHandle::Seek(vsi_l_offset /* nOffset */, int /* nWhence */)
312 : {
313 0 : CPLError(CE_Failure, CPLE_NotSupported,
314 : "Seek() unsupported on /vsistdout_redirect");
315 0 : return -1;
316 : }
317 :
318 : /************************************************************************/
319 : /* Tell() */
320 : /************************************************************************/
321 :
322 271 : vsi_l_offset VSIStdoutRedirectHandle::Tell()
323 : {
324 271 : return m_poHandle->Tell();
325 : }
326 :
327 : /************************************************************************/
328 : /* Flush() */
329 : /************************************************************************/
330 :
331 1 : int VSIStdoutRedirectHandle::Flush()
332 :
333 : {
334 1 : return m_poHandle->Flush();
335 : }
336 :
337 : /************************************************************************/
338 : /* Read() */
339 : /************************************************************************/
340 :
341 0 : size_t VSIStdoutRedirectHandle::Read(void * /* pBuffer */, size_t /* nSize */,
342 : size_t /* nCount */)
343 : {
344 0 : CPLError(CE_Failure, CPLE_NotSupported,
345 : "Read() unsupported on /vsistdout_redirect");
346 0 : return 0;
347 : }
348 :
349 : /************************************************************************/
350 : /* Write() */
351 : /************************************************************************/
352 :
353 567 : size_t VSIStdoutRedirectHandle::Write(const void *pBuffer, size_t nSize,
354 : size_t nCount)
355 :
356 : {
357 567 : return m_poHandle->Write(pBuffer, nSize, nCount);
358 : }
359 :
360 : /************************************************************************/
361 : /* Eof() */
362 : /************************************************************************/
363 :
364 0 : int VSIStdoutRedirectHandle::Eof()
365 :
366 : {
367 0 : return m_poHandle->Eof();
368 : }
369 :
370 : /************************************************************************/
371 : /* Close() */
372 : /************************************************************************/
373 :
374 6 : int VSIStdoutRedirectHandle::Close()
375 :
376 : {
377 6 : return m_poHandle->Close();
378 : }
379 :
380 : /************************************************************************/
381 : /* ==================================================================== */
382 : /* VSIStdoutRedirectFilesystemHandler */
383 : /* ==================================================================== */
384 : /************************************************************************/
385 :
386 : /************************************************************************/
387 : /* Open() */
388 : /************************************************************************/
389 :
390 21 : VSIVirtualHandle *VSIStdoutRedirectFilesystemHandler::Open(
391 : const char *pszFilename, const char *pszAccess, bool /* bSetError */,
392 : CSLConstList /* papszOptions */)
393 :
394 : {
395 21 : if (strchr(pszAccess, 'r') != nullptr || strchr(pszAccess, '+') != nullptr)
396 : {
397 15 : CPLError(CE_Failure, CPLE_NotSupported,
398 : "Read or update mode not supported on /vsistdout_redirect");
399 15 : return nullptr;
400 : }
401 :
402 6 : VSIVirtualHandle *poHandle = reinterpret_cast<VSIVirtualHandle *>(
403 : VSIFOpenL(pszFilename + strlen("/vsistdout_redirect/"), pszAccess));
404 6 : if (poHandle == nullptr)
405 0 : return nullptr;
406 :
407 6 : return new VSIStdoutRedirectHandle(poHandle);
408 : }
409 :
410 : /************************************************************************/
411 : /* Stat() */
412 : /************************************************************************/
413 :
414 24 : int VSIStdoutRedirectFilesystemHandler::Stat(const char * /* pszFilename */,
415 : VSIStatBufL *pStatBuf,
416 : int /* nFlags */)
417 : {
418 24 : memset(pStatBuf, 0, sizeof(VSIStatBufL));
419 :
420 24 : return -1;
421 : }
422 :
423 : //! @endcond
424 :
425 : /************************************************************************/
426 : /* VSIInstallStdoutHandler() */
427 : /************************************************************************/
428 :
429 : /*!
430 : \brief Install /vsistdout/ file system handler
431 :
432 : A special file handler is installed that allows writing to the standard
433 : output stream.
434 :
435 : The file operations available are of course limited to Write().
436 :
437 : A variation of this file system exists as the /vsistdout_redirect/ file
438 : system handler, where the output function can be defined with
439 : VSIStdoutSetRedirection().
440 :
441 : \verbatim embed:rst
442 : See :ref:`/vsistdout/ documentation <vsistdout>`
443 : \endverbatim
444 :
445 : @since GDAL 1.8.0
446 : */
447 :
448 1225 : void VSIInstallStdoutHandler()
449 :
450 : {
451 1225 : VSIFileManager::InstallHandler("/vsistdout/",
452 1225 : new VSIStdoutFilesystemHandler);
453 1225 : VSIFileManager::InstallHandler("/vsistdout_redirect/",
454 1225 : new VSIStdoutRedirectFilesystemHandler);
455 1225 : }
|