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 : #include <fcntl.h>
20 :
21 : #include "cpl_error.h"
22 : #include "cpl_vsi_virtual.h"
23 :
24 : #ifdef _WIN32
25 : #include <io.h>
26 : #endif
27 :
28 : static VSIWriteFunction pWriteFunction = fwrite;
29 : static FILE *pWriteStream = stdout;
30 :
31 : /************************************************************************/
32 : /* VSIStdoutSetRedirection() */
33 : /************************************************************************/
34 :
35 : /** Set an alternative write function and output file handle instead of
36 : * fwrite() / stdout.
37 : *
38 : * @param pFct Function with same signature as fwrite()
39 : * @param stream File handle on which to output. Passed to pFct.
40 : *
41 : * @since GDAL 2.0
42 : */
43 0 : void VSIStdoutSetRedirection(VSIWriteFunction pFct, FILE *stream)
44 : {
45 0 : pWriteFunction = pFct;
46 0 : pWriteStream = stream;
47 0 : }
48 :
49 : //! @cond Doxygen_Suppress
50 :
51 : /************************************************************************/
52 : /* ==================================================================== */
53 : /* VSIStdoutFilesystemHandler */
54 : /* ==================================================================== */
55 : /************************************************************************/
56 :
57 : class VSIStdoutFilesystemHandler final : public VSIFilesystemHandler
58 : {
59 : CPL_DISALLOW_COPY_ASSIGN(VSIStdoutFilesystemHandler)
60 :
61 : public:
62 1754 : VSIStdoutFilesystemHandler() = default;
63 :
64 : VSIVirtualHandleUniquePtr Open(const char *pszFilename,
65 : const char *pszAccess, bool bSetError,
66 : CSLConstList /* papszOptions */) override;
67 : int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
68 : int nFlags) override;
69 :
70 0 : bool SupportsRead(const char * /* pszPath */) override
71 : {
72 0 : return false;
73 : }
74 : };
75 :
76 : /************************************************************************/
77 : /* ==================================================================== */
78 : /* VSIStdoutHandle */
79 : /* ==================================================================== */
80 : /************************************************************************/
81 :
82 : class VSIStdoutHandle final : public VSIVirtualHandle
83 : {
84 : CPL_DISALLOW_COPY_ASSIGN(VSIStdoutHandle)
85 :
86 : vsi_l_offset m_nOffset = 0;
87 : bool m_bError = false;
88 :
89 : public:
90 5 : VSIStdoutHandle() = default;
91 10 : ~VSIStdoutHandle() override = default;
92 :
93 : int Seek(vsi_l_offset nOffset, int nWhence) override;
94 : vsi_l_offset Tell() override;
95 : size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
96 : size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
97 :
98 0 : void ClearErr() override
99 : {
100 0 : m_bError = false;
101 0 : }
102 :
103 0 : int Error() override
104 : {
105 0 : return m_bError;
106 : }
107 :
108 0 : int Eof() override
109 : {
110 0 : return FALSE;
111 : }
112 :
113 : int Flush() override;
114 : int Close() override;
115 : };
116 :
117 : /************************************************************************/
118 : /* Seek() */
119 : /************************************************************************/
120 :
121 0 : int VSIStdoutHandle::Seek(vsi_l_offset nOffset, int nWhence)
122 :
123 : {
124 0 : if (nOffset == 0 && (nWhence == SEEK_END || nWhence == SEEK_CUR))
125 0 : return 0;
126 0 : if (nWhence == SEEK_SET && nOffset == Tell())
127 0 : return 0;
128 0 : CPLError(CE_Failure, CPLE_NotSupported, "Seek() unsupported on /vsistdout");
129 0 : return -1;
130 : }
131 :
132 : /************************************************************************/
133 : /* Tell() */
134 : /************************************************************************/
135 :
136 2 : vsi_l_offset VSIStdoutHandle::Tell()
137 : {
138 2 : return m_nOffset;
139 : }
140 :
141 : /************************************************************************/
142 : /* Flush() */
143 : /************************************************************************/
144 :
145 7 : int VSIStdoutHandle::Flush()
146 :
147 : {
148 7 : if (pWriteStream == stdout)
149 7 : return fflush(stdout);
150 : else
151 0 : return 0;
152 : }
153 :
154 : /************************************************************************/
155 : /* Read() */
156 : /************************************************************************/
157 :
158 0 : size_t VSIStdoutHandle::Read(void * /* pBuffer */, size_t nSize, size_t nCount)
159 : {
160 0 : if (nSize > 0 && nCount > 0)
161 : {
162 0 : CPLError(CE_Failure, CPLE_NotSupported,
163 : "Read() unsupported on /vsistdout");
164 0 : m_bError = true;
165 : }
166 0 : return 0;
167 : }
168 :
169 : /************************************************************************/
170 : /* Write() */
171 : /************************************************************************/
172 :
173 427 : size_t VSIStdoutHandle::Write(const void *pBuffer, size_t nSize, size_t nCount)
174 :
175 : {
176 427 : size_t nRet = pWriteFunction(pBuffer, nSize, nCount, pWriteStream);
177 427 : m_nOffset += nSize * nRet;
178 427 : return nRet;
179 : }
180 :
181 : /************************************************************************/
182 : /* Close() */
183 : /************************************************************************/
184 :
185 5 : int VSIStdoutHandle::Close()
186 :
187 : {
188 5 : return Flush();
189 : }
190 :
191 : /************************************************************************/
192 : /* ==================================================================== */
193 : /* VSIStdoutFilesystemHandler */
194 : /* ==================================================================== */
195 : /************************************************************************/
196 :
197 : /************************************************************************/
198 : /* Open() */
199 : /************************************************************************/
200 :
201 : VSIVirtualHandleUniquePtr
202 12 : VSIStdoutFilesystemHandler::Open(const char * /* pszFilename */,
203 : const char *pszAccess, bool /* bSetError */,
204 : CSLConstList /* papszOptions */)
205 : {
206 12 : if (strchr(pszAccess, 'r') != nullptr || strchr(pszAccess, '+') != nullptr)
207 : {
208 7 : CPLError(CE_Failure, CPLE_NotSupported,
209 : "Read or update mode not supported on /vsistdout");
210 7 : return nullptr;
211 : }
212 :
213 : #ifdef _WIN32
214 : if (strchr(pszAccess, 'b') != nullptr)
215 : setmode(fileno(stdout), O_BINARY);
216 : #endif
217 :
218 : return VSIVirtualHandleUniquePtr(
219 5 : std::make_unique<VSIStdoutHandle>().release());
220 : }
221 :
222 : /************************************************************************/
223 : /* Stat() */
224 : /************************************************************************/
225 :
226 26 : int VSIStdoutFilesystemHandler::Stat(const char * /* pszFilename */,
227 : VSIStatBufL *pStatBuf, int /* nFlags */)
228 :
229 : {
230 26 : memset(pStatBuf, 0, sizeof(VSIStatBufL));
231 :
232 26 : return -1;
233 : }
234 :
235 : /************************************************************************/
236 : /* ==================================================================== */
237 : /* VSIStdoutRedirectFilesystemHandler */
238 : /* ==================================================================== */
239 : /************************************************************************/
240 :
241 : class VSIStdoutRedirectFilesystemHandler final : public VSIFilesystemHandler
242 : {
243 : public:
244 : VSIVirtualHandleUniquePtr Open(const char *pszFilename,
245 : const char *pszAccess, bool bSetError,
246 : CSLConstList /* papszOptions */) override;
247 : int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
248 : int nFlags) override;
249 :
250 1 : bool SupportsRead(const char * /* pszPath */) override
251 : {
252 1 : return false;
253 : }
254 : };
255 :
256 : /************************************************************************/
257 : /* ==================================================================== */
258 : /* VSIStdoutRedirectHandle */
259 : /* ==================================================================== */
260 : /************************************************************************/
261 :
262 : class VSIStdoutRedirectHandle final : public VSIVirtualHandle
263 : {
264 : VSIVirtualHandle *m_poHandle = nullptr;
265 : bool m_bError = false;
266 :
267 : CPL_DISALLOW_COPY_ASSIGN(VSIStdoutRedirectHandle)
268 :
269 : public:
270 : explicit VSIStdoutRedirectHandle(VSIVirtualHandle *poHandle);
271 : ~VSIStdoutRedirectHandle() override;
272 :
273 : int Seek(vsi_l_offset nOffset, int nWhence) override;
274 : vsi_l_offset Tell() override;
275 : size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
276 : size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
277 :
278 0 : void ClearErr() override
279 : {
280 0 : m_bError = false;
281 0 : }
282 :
283 0 : int Error() override
284 : {
285 0 : return m_bError;
286 : }
287 :
288 0 : int Eof() override
289 : {
290 0 : return FALSE;
291 : }
292 :
293 : int Flush() override;
294 : int Close() override;
295 : };
296 :
297 : /************************************************************************/
298 : /* VSIStdoutRedirectHandle() */
299 : /************************************************************************/
300 :
301 7 : VSIStdoutRedirectHandle::VSIStdoutRedirectHandle(VSIVirtualHandle *poHandle)
302 7 : : m_poHandle(poHandle)
303 : {
304 7 : }
305 :
306 : /************************************************************************/
307 : /* ~VSIStdoutRedirectHandle() */
308 : /************************************************************************/
309 :
310 14 : VSIStdoutRedirectHandle::~VSIStdoutRedirectHandle()
311 : {
312 7 : delete m_poHandle;
313 14 : }
314 :
315 : /************************************************************************/
316 : /* Seek() */
317 : /************************************************************************/
318 :
319 0 : int VSIStdoutRedirectHandle::Seek(vsi_l_offset /* nOffset */, int /* nWhence */)
320 : {
321 0 : CPLError(CE_Failure, CPLE_NotSupported,
322 : "Seek() unsupported on /vsistdout_redirect");
323 0 : return -1;
324 : }
325 :
326 : /************************************************************************/
327 : /* Tell() */
328 : /************************************************************************/
329 :
330 272 : vsi_l_offset VSIStdoutRedirectHandle::Tell()
331 : {
332 272 : return m_poHandle->Tell();
333 : }
334 :
335 : /************************************************************************/
336 : /* Flush() */
337 : /************************************************************************/
338 :
339 2 : int VSIStdoutRedirectHandle::Flush()
340 :
341 : {
342 2 : return m_poHandle->Flush();
343 : }
344 :
345 : /************************************************************************/
346 : /* Read() */
347 : /************************************************************************/
348 :
349 0 : size_t VSIStdoutRedirectHandle::Read(void * /* pBuffer */, size_t nSize,
350 : size_t nCount)
351 : {
352 0 : if (nSize > 0 && nCount > 0)
353 : {
354 0 : CPLError(CE_Failure, CPLE_NotSupported,
355 : "Read() unsupported on /vsistdout");
356 0 : m_bError = true;
357 : }
358 0 : return 0;
359 : }
360 :
361 : /************************************************************************/
362 : /* Write() */
363 : /************************************************************************/
364 :
365 592 : size_t VSIStdoutRedirectHandle::Write(const void *pBuffer, size_t nSize,
366 : size_t nCount)
367 :
368 : {
369 592 : return m_poHandle->Write(pBuffer, nSize, nCount);
370 : }
371 :
372 : /************************************************************************/
373 : /* Close() */
374 : /************************************************************************/
375 :
376 10 : int VSIStdoutRedirectHandle::Close()
377 :
378 : {
379 10 : return m_poHandle->Close();
380 : }
381 :
382 : /************************************************************************/
383 : /* ==================================================================== */
384 : /* VSIStdoutRedirectFilesystemHandler */
385 : /* ==================================================================== */
386 : /************************************************************************/
387 :
388 : /************************************************************************/
389 : /* Open() */
390 : /************************************************************************/
391 :
392 26 : VSIVirtualHandleUniquePtr VSIStdoutRedirectFilesystemHandler::Open(
393 : const char *pszFilename, const char *pszAccess, bool /* bSetError */,
394 : CSLConstList /* papszOptions */)
395 :
396 : {
397 26 : if (strchr(pszAccess, 'r') != nullptr || strchr(pszAccess, '+') != nullptr)
398 : {
399 19 : CPLError(CE_Failure, CPLE_NotSupported,
400 : "Read or update mode not supported on /vsistdout_redirect");
401 19 : return nullptr;
402 : }
403 :
404 : auto poHandle = VSIFilesystemHandler::OpenStatic(
405 14 : pszFilename + strlen("/vsistdout_redirect/"), pszAccess);
406 7 : if (poHandle == nullptr)
407 0 : return nullptr;
408 :
409 : return VSIVirtualHandleUniquePtr(
410 14 : std::make_unique<VSIStdoutRedirectHandle>(poHandle.release())
411 7 : .release());
412 : }
413 :
414 : /************************************************************************/
415 : /* Stat() */
416 : /************************************************************************/
417 :
418 37 : int VSIStdoutRedirectFilesystemHandler::Stat(const char * /* pszFilename */,
419 : VSIStatBufL *pStatBuf,
420 : int /* nFlags */)
421 : {
422 37 : memset(pStatBuf, 0, sizeof(VSIStatBufL));
423 :
424 37 : 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 1754 : void VSIInstallStdoutHandler()
453 :
454 : {
455 1754 : VSIFileManager::InstallHandler("/vsistdout/",
456 1754 : new VSIStdoutFilesystemHandler);
457 1754 : VSIFileManager::InstallHandler("/vsistdout_redirect/",
458 1754 : new VSIStdoutRedirectFilesystemHandler);
459 1754 : }
|