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 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_port.h"
14 : #include "cpl_vsi.h"
15 :
16 : #include <cstddef>
17 : #include <cstdio>
18 : #include <cstring>
19 : #if HAVE_FCNTL_H
20 : #include <fcntl.h>
21 : #endif
22 :
23 : #include "cpl_error.h"
24 : #include "cpl_vsi_virtual.h"
25 :
26 : #ifdef _WIN32
27 : #include <io.h>
28 : #include <fcntl.h>
29 : #endif
30 :
31 : static VSIWriteFunction pWriteFunction = fwrite;
32 : static FILE *pWriteStream = stdout;
33 :
34 : /************************************************************************/
35 : /* VSIStdoutSetRedirection() */
36 : /************************************************************************/
37 :
38 : /** Set an alternative write function and output file handle instead of
39 : * fwrite() / stdout.
40 : *
41 : * @param pFct Function with same signature as fwrite()
42 : * @param stream File handle on which to output. Passed to pFct.
43 : *
44 : * @since GDAL 2.0
45 : */
46 0 : void VSIStdoutSetRedirection(VSIWriteFunction pFct, FILE *stream)
47 : {
48 0 : pWriteFunction = pFct;
49 0 : pWriteStream = stream;
50 0 : }
51 :
52 : //! @cond Doxygen_Suppress
53 :
54 : /************************************************************************/
55 : /* ==================================================================== */
56 : /* VSIStdoutFilesystemHandler */
57 : /* ==================================================================== */
58 : /************************************************************************/
59 :
60 : class VSIStdoutFilesystemHandler final : public VSIFilesystemHandler
61 : {
62 : CPL_DISALLOW_COPY_ASSIGN(VSIStdoutFilesystemHandler)
63 :
64 : public:
65 1304 : VSIStdoutFilesystemHandler() = default;
66 :
67 : VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
68 : bool bSetError,
69 : CSLConstList /* papszOptions */) override;
70 : int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
71 : int nFlags) override;
72 :
73 0 : bool SupportsRead(const char * /* pszPath */) override
74 : {
75 0 : return false;
76 : }
77 : };
78 :
79 : /************************************************************************/
80 : /* ==================================================================== */
81 : /* VSIStdoutHandle */
82 : /* ==================================================================== */
83 : /************************************************************************/
84 :
85 : class VSIStdoutHandle final : public VSIVirtualHandle
86 : {
87 : CPL_DISALLOW_COPY_ASSIGN(VSIStdoutHandle)
88 :
89 : vsi_l_offset m_nOffset = 0;
90 : bool m_bError = false;
91 :
92 : public:
93 3 : VSIStdoutHandle() = default;
94 6 : ~VSIStdoutHandle() override = default;
95 :
96 : int Seek(vsi_l_offset nOffset, int nWhence) override;
97 : vsi_l_offset Tell() override;
98 : size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
99 : size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
100 :
101 0 : void ClearErr() override
102 : {
103 0 : m_bError = false;
104 0 : }
105 :
106 0 : int Error() override
107 : {
108 0 : return m_bError;
109 : }
110 :
111 0 : int Eof() override
112 : {
113 0 : return FALSE;
114 : }
115 :
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, size_t nCount)
162 : {
163 0 : if (nSize > 0 && nCount > 0)
164 : {
165 0 : CPLError(CE_Failure, CPLE_NotSupported,
166 : "Read() unsupported on /vsistdout");
167 0 : m_bError = true;
168 : }
169 0 : return 0;
170 : }
171 :
172 : /************************************************************************/
173 : /* Write() */
174 : /************************************************************************/
175 :
176 20 : size_t VSIStdoutHandle::Write(const void *pBuffer, size_t nSize, size_t nCount)
177 :
178 : {
179 20 : size_t nRet = pWriteFunction(pBuffer, nSize, nCount, pWriteStream);
180 20 : m_nOffset += nSize * nRet;
181 20 : return nRet;
182 : }
183 :
184 : /************************************************************************/
185 : /* Close() */
186 : /************************************************************************/
187 :
188 3 : int VSIStdoutHandle::Close()
189 :
190 : {
191 3 : return Flush();
192 : }
193 :
194 : /************************************************************************/
195 : /* ==================================================================== */
196 : /* VSIStdoutFilesystemHandler */
197 : /* ==================================================================== */
198 : /************************************************************************/
199 :
200 : /************************************************************************/
201 : /* Open() */
202 : /************************************************************************/
203 :
204 : VSIVirtualHandle *
205 5 : VSIStdoutFilesystemHandler::Open(const char * /* pszFilename */,
206 : const char *pszAccess, bool /* bSetError */,
207 : CSLConstList /* papszOptions */)
208 : {
209 5 : if (strchr(pszAccess, 'r') != nullptr || strchr(pszAccess, '+') != nullptr)
210 : {
211 2 : CPLError(CE_Failure, CPLE_NotSupported,
212 : "Read or update mode not supported on /vsistdout");
213 2 : return nullptr;
214 : }
215 :
216 : #ifdef _WIN32
217 : if (strchr(pszAccess, 'b') != nullptr)
218 : setmode(fileno(stdout), O_BINARY);
219 : #endif
220 :
221 3 : return new VSIStdoutHandle;
222 : }
223 :
224 : /************************************************************************/
225 : /* Stat() */
226 : /************************************************************************/
227 :
228 10 : int VSIStdoutFilesystemHandler::Stat(const char * /* pszFilename */,
229 : VSIStatBufL *pStatBuf, int /* nFlags */)
230 :
231 : {
232 10 : memset(pStatBuf, 0, sizeof(VSIStatBufL));
233 :
234 10 : return -1;
235 : }
236 :
237 : /************************************************************************/
238 : /* ==================================================================== */
239 : /* VSIStdoutRedirectFilesystemHandler */
240 : /* ==================================================================== */
241 : /************************************************************************/
242 :
243 : class VSIStdoutRedirectFilesystemHandler final : public VSIFilesystemHandler
244 : {
245 : public:
246 : VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
247 : bool bSetError,
248 : CSLConstList /* papszOptions */) override;
249 : int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
250 : int nFlags) override;
251 :
252 1 : bool SupportsRead(const char * /* pszPath */) override
253 : {
254 1 : return false;
255 : }
256 : };
257 :
258 : /************************************************************************/
259 : /* ==================================================================== */
260 : /* VSIStdoutRedirectHandle */
261 : /* ==================================================================== */
262 : /************************************************************************/
263 :
264 : class VSIStdoutRedirectHandle final : public VSIVirtualHandle
265 : {
266 : VSIVirtualHandle *m_poHandle = nullptr;
267 : bool m_bError = false;
268 :
269 : CPL_DISALLOW_COPY_ASSIGN(VSIStdoutRedirectHandle)
270 :
271 : public:
272 : explicit VSIStdoutRedirectHandle(VSIVirtualHandle *poHandle);
273 : ~VSIStdoutRedirectHandle() override;
274 :
275 : int Seek(vsi_l_offset nOffset, int nWhence) override;
276 : vsi_l_offset Tell() override;
277 : size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
278 : size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
279 :
280 0 : void ClearErr() override
281 : {
282 0 : m_bError = false;
283 0 : }
284 :
285 0 : int Error() override
286 : {
287 0 : return m_bError;
288 : }
289 :
290 0 : int Eof() override
291 : {
292 0 : return FALSE;
293 : }
294 :
295 : int Flush() override;
296 : int Close() override;
297 : };
298 :
299 : /************************************************************************/
300 : /* VSIStdoutRedirectHandle() */
301 : /************************************************************************/
302 :
303 6 : VSIStdoutRedirectHandle::VSIStdoutRedirectHandle(VSIVirtualHandle *poHandle)
304 6 : : m_poHandle(poHandle)
305 : {
306 6 : }
307 :
308 : /************************************************************************/
309 : /* ~VSIStdoutRedirectHandle() */
310 : /************************************************************************/
311 :
312 12 : VSIStdoutRedirectHandle::~VSIStdoutRedirectHandle()
313 : {
314 6 : delete m_poHandle;
315 12 : }
316 :
317 : /************************************************************************/
318 : /* Seek() */
319 : /************************************************************************/
320 :
321 0 : int VSIStdoutRedirectHandle::Seek(vsi_l_offset /* nOffset */, int /* nWhence */)
322 : {
323 0 : CPLError(CE_Failure, CPLE_NotSupported,
324 : "Seek() unsupported on /vsistdout_redirect");
325 0 : return -1;
326 : }
327 :
328 : /************************************************************************/
329 : /* Tell() */
330 : /************************************************************************/
331 :
332 271 : vsi_l_offset VSIStdoutRedirectHandle::Tell()
333 : {
334 271 : return m_poHandle->Tell();
335 : }
336 :
337 : /************************************************************************/
338 : /* Flush() */
339 : /************************************************************************/
340 :
341 1 : int VSIStdoutRedirectHandle::Flush()
342 :
343 : {
344 1 : return m_poHandle->Flush();
345 : }
346 :
347 : /************************************************************************/
348 : /* Read() */
349 : /************************************************************************/
350 :
351 0 : size_t VSIStdoutRedirectHandle::Read(void * /* pBuffer */, size_t nSize,
352 : size_t nCount)
353 : {
354 0 : if (nSize > 0 && nCount > 0)
355 : {
356 0 : CPLError(CE_Failure, CPLE_NotSupported,
357 : "Read() unsupported on /vsistdout");
358 0 : m_bError = true;
359 : }
360 0 : return 0;
361 : }
362 :
363 : /************************************************************************/
364 : /* Write() */
365 : /************************************************************************/
366 :
367 567 : size_t VSIStdoutRedirectHandle::Write(const void *pBuffer, size_t nSize,
368 : size_t nCount)
369 :
370 : {
371 567 : return m_poHandle->Write(pBuffer, nSize, nCount);
372 : }
373 :
374 : /************************************************************************/
375 : /* Close() */
376 : /************************************************************************/
377 :
378 6 : int VSIStdoutRedirectHandle::Close()
379 :
380 : {
381 6 : return m_poHandle->Close();
382 : }
383 :
384 : /************************************************************************/
385 : /* ==================================================================== */
386 : /* VSIStdoutRedirectFilesystemHandler */
387 : /* ==================================================================== */
388 : /************************************************************************/
389 :
390 : /************************************************************************/
391 : /* Open() */
392 : /************************************************************************/
393 :
394 21 : VSIVirtualHandle *VSIStdoutRedirectFilesystemHandler::Open(
395 : const char *pszFilename, const char *pszAccess, bool /* bSetError */,
396 : CSLConstList /* papszOptions */)
397 :
398 : {
399 21 : if (strchr(pszAccess, 'r') != nullptr || strchr(pszAccess, '+') != nullptr)
400 : {
401 15 : CPLError(CE_Failure, CPLE_NotSupported,
402 : "Read or update mode not supported on /vsistdout_redirect");
403 15 : return nullptr;
404 : }
405 :
406 6 : VSIVirtualHandle *poHandle = reinterpret_cast<VSIVirtualHandle *>(
407 : VSIFOpenL(pszFilename + strlen("/vsistdout_redirect/"), pszAccess));
408 6 : if (poHandle == nullptr)
409 0 : return nullptr;
410 :
411 6 : return new VSIStdoutRedirectHandle(poHandle);
412 : }
413 :
414 : /************************************************************************/
415 : /* Stat() */
416 : /************************************************************************/
417 :
418 24 : int VSIStdoutRedirectFilesystemHandler::Stat(const char * /* pszFilename */,
419 : VSIStatBufL *pStatBuf,
420 : int /* nFlags */)
421 : {
422 24 : memset(pStatBuf, 0, sizeof(VSIStatBufL));
423 :
424 24 : return -1;
425 : }
426 :
427 : //! @endcond
428 :
429 : /************************************************************************/
430 : /* VSIInstallStdoutHandler() */
431 : /************************************************************************/
432 :
433 : /*!
434 : \brief Install /vsistdout/ file system handler
435 :
436 : A special file handler is installed that allows writing to the standard
437 : output stream.
438 :
439 : The file operations available are of course limited to Write().
440 :
441 : A variation of this file system exists as the /vsistdout_redirect/ file
442 : system handler, where the output function can be defined with
443 : VSIStdoutSetRedirection().
444 :
445 : \verbatim embed:rst
446 : See :ref:`/vsistdout/ documentation <vsistdout>`
447 : \endverbatim
448 :
449 : @since GDAL 1.8.0
450 : */
451 :
452 1304 : void VSIInstallStdoutHandler()
453 :
454 : {
455 1304 : VSIFileManager::InstallHandler("/vsistdout/",
456 1304 : new VSIStdoutFilesystemHandler);
457 1304 : VSIFileManager::InstallHandler("/vsistdout_redirect/",
458 1304 : new VSIStdoutRedirectFilesystemHandler);
459 1304 : }
|