Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: CPL - Common Portability Library
4 : * Purpose: Convenience functions.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1998, Frank Warmerdam
9 : * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_config.h"
15 :
16 : #ifdef HAVE_USELOCALE
17 : // For uselocale, define _XOPEN_SOURCE = 700
18 : // but on Solaris, we don't have uselocale and we cannot have
19 : // std=c++11 with _XOPEN_SOURCE != 600
20 : #if defined(__sun__) && __cplusplus >= 201103L
21 : #if _XOPEN_SOURCE != 600
22 : #ifdef _XOPEN_SOURCE
23 : #undef _XOPEN_SOURCE
24 : #endif
25 : #define _XOPEN_SOURCE 600
26 : #endif
27 : #else
28 : #ifdef _XOPEN_SOURCE
29 : #undef _XOPEN_SOURCE
30 : #endif
31 : #define _XOPEN_SOURCE 700
32 : #endif
33 : #endif
34 :
35 : // For atoll (at least for NetBSD)
36 : #ifndef _ISOC99_SOURCE
37 : #define _ISOC99_SOURCE
38 : #endif
39 :
40 : #ifdef MSVC_USE_VLD
41 : #include <vld.h>
42 : #endif
43 :
44 : #include "cpl_conv.h"
45 :
46 : #include <algorithm>
47 : #include <cctype>
48 : #include <cerrno>
49 : #include <climits>
50 : #include <clocale>
51 : #include <cmath>
52 : #include <cstdlib>
53 : #include <cstring>
54 : #include <ctime>
55 : #if HAVE_FCNTL_H
56 : #include <fcntl.h>
57 : #endif
58 : #include <mutex>
59 : #include <set>
60 :
61 : #if HAVE_UNISTD_H
62 : #include <unistd.h>
63 : #endif
64 : #if HAVE_XLOCALE_H
65 : #include <xlocale.h> // for LC_NUMERIC_MASK on MacOS
66 : #endif
67 :
68 : #ifdef _WIN32
69 : #include <io.h> // _isatty
70 : #else
71 : #include <unistd.h> // isatty
72 : #endif
73 :
74 : #include <string>
75 :
76 : #if __cplusplus >= 202002L
77 : #include <bit> // For std::endian
78 : #endif
79 :
80 : #include "cpl_config.h"
81 : #include "cpl_multiproc.h"
82 : #include "cpl_string.h"
83 : #include "cpl_vsi.h"
84 : #include "cpl_vsil_curl_priv.h"
85 : #include "cpl_known_config_options.h"
86 :
87 : #ifdef DEBUG
88 : #define OGRAPISPY_ENABLED
89 : #endif
90 : #ifdef OGRAPISPY_ENABLED
91 : // Keep in sync with ograpispy.cpp
92 : void OGRAPISPYCPLSetConfigOption(const char *, const char *);
93 : void OGRAPISPYCPLSetThreadLocalConfigOption(const char *, const char *);
94 : #endif
95 :
96 : // Uncomment to get list of options that have been fetched and set.
97 : // #define DEBUG_CONFIG_OPTIONS
98 :
99 : static CPLMutex *hConfigMutex = nullptr;
100 : static volatile char **g_papszConfigOptions = nullptr;
101 : static bool gbIgnoreEnvVariables =
102 : false; // if true, only take into account configuration options set through
103 : // configuration file or
104 : // CPLSetConfigOption()/CPLSetThreadLocalConfigOption()
105 :
106 : static std::vector<std::pair<CPLSetConfigOptionSubscriber, void *>>
107 : gSetConfigOptionSubscribers{};
108 :
109 : // Used by CPLOpenShared() and friends.
110 : static CPLMutex *hSharedFileMutex = nullptr;
111 : static int nSharedFileCount = 0;
112 : static CPLSharedFileInfo *pasSharedFileList = nullptr;
113 :
114 : // Used by CPLsetlocale().
115 : static CPLMutex *hSetLocaleMutex = nullptr;
116 :
117 : // Note: ideally this should be added in CPLSharedFileInfo*
118 : // but CPLSharedFileInfo is exposed in the API, hence that trick
119 : // to hide this detail.
120 : typedef struct
121 : {
122 : GIntBig nPID; // pid of opening thread.
123 : } CPLSharedFileInfoExtra;
124 :
125 : static volatile CPLSharedFileInfoExtra *pasSharedFileListExtra = nullptr;
126 :
127 : /************************************************************************/
128 : /* CPLCalloc() */
129 : /************************************************************************/
130 :
131 : /**
132 : * Safe version of calloc().
133 : *
134 : * This function is like the C library calloc(), but raises a CE_Fatal
135 : * error with CPLError() if it fails to allocate the desired memory. It
136 : * should be used for small memory allocations that are unlikely to fail
137 : * and for which the application is unwilling to test for out of memory
138 : * conditions. It uses VSICalloc() to get the memory, so any hooking of
139 : * VSICalloc() will apply to CPLCalloc() as well. CPLFree() or VSIFree()
140 : * can be used free memory allocated by CPLCalloc().
141 : *
142 : * @param nCount number of objects to allocate.
143 : * @param nSize size (in bytes) of object to allocate.
144 : * @return pointer to newly allocated memory, only NULL if nSize * nCount is
145 : * NULL.
146 : */
147 :
148 3186240 : void *CPLCalloc(size_t nCount, size_t nSize)
149 :
150 : {
151 3186240 : if (nSize * nCount == 0)
152 9140 : return nullptr;
153 :
154 3177100 : void *pReturn = CPLMalloc(nCount * nSize);
155 3177080 : memset(pReturn, 0, nCount * nSize);
156 3177080 : return pReturn;
157 : }
158 :
159 : /************************************************************************/
160 : /* CPLMalloc() */
161 : /************************************************************************/
162 :
163 : /**
164 : * Safe version of malloc().
165 : *
166 : * This function is like the C library malloc(), but raises a CE_Fatal
167 : * error with CPLError() if it fails to allocate the desired memory. It
168 : * should be used for small memory allocations that are unlikely to fail
169 : * and for which the application is unwilling to test for out of memory
170 : * conditions. It uses VSIMalloc() to get the memory, so any hooking of
171 : * VSIMalloc() will apply to CPLMalloc() as well. CPLFree() or VSIFree()
172 : * can be used free memory allocated by CPLMalloc().
173 : *
174 : * @param nSize size (in bytes) of memory block to allocate.
175 : * @return pointer to newly allocated memory, only NULL if nSize is zero.
176 : */
177 :
178 18929500 : void *CPLMalloc(size_t nSize)
179 :
180 : {
181 18929500 : if (nSize == 0)
182 5734 : return nullptr;
183 :
184 18923700 : if ((nSize >> (8 * sizeof(nSize) - 1)) != 0)
185 : {
186 : // coverity[dead_error_begin]
187 0 : CPLError(CE_Failure, CPLE_AppDefined,
188 : "CPLMalloc(%ld): Silly size requested.",
189 : static_cast<long>(nSize));
190 0 : return nullptr;
191 : }
192 :
193 18923700 : void *pReturn = VSIMalloc(nSize);
194 18923700 : if (pReturn == nullptr)
195 : {
196 0 : if (nSize < 2000)
197 : {
198 0 : CPLEmergencyError("CPLMalloc(): Out of memory allocating a small "
199 : "number of bytes.");
200 : }
201 :
202 0 : CPLError(CE_Fatal, CPLE_OutOfMemory,
203 : "CPLMalloc(): Out of memory allocating %ld bytes.",
204 : static_cast<long>(nSize));
205 : }
206 :
207 18923700 : return pReturn;
208 : }
209 :
210 : /************************************************************************/
211 : /* CPLRealloc() */
212 : /************************************************************************/
213 :
214 : /**
215 : * Safe version of realloc().
216 : *
217 : * This function is like the C library realloc(), but raises a CE_Fatal
218 : * error with CPLError() if it fails to allocate the desired memory. It
219 : * should be used for small memory allocations that are unlikely to fail
220 : * and for which the application is unwilling to test for out of memory
221 : * conditions. It uses VSIRealloc() to get the memory, so any hooking of
222 : * VSIRealloc() will apply to CPLRealloc() as well. CPLFree() or VSIFree()
223 : * can be used free memory allocated by CPLRealloc().
224 : *
225 : * It is also safe to pass NULL in as the existing memory block for
226 : * CPLRealloc(), in which case it uses VSIMalloc() to allocate a new block.
227 : *
228 : * @param pData existing memory block which should be copied to the new block.
229 : * @param nNewSize new size (in bytes) of memory block to allocate.
230 : * @return pointer to allocated memory, only NULL if nNewSize is zero.
231 : */
232 :
233 1842310 : void *CPLRealloc(void *pData, size_t nNewSize)
234 :
235 : {
236 1842310 : if (nNewSize == 0)
237 : {
238 45 : VSIFree(pData);
239 45 : return nullptr;
240 : }
241 :
242 1842270 : if ((nNewSize >> (8 * sizeof(nNewSize) - 1)) != 0)
243 : {
244 : // coverity[dead_error_begin]
245 0 : CPLError(CE_Failure, CPLE_AppDefined,
246 : "CPLRealloc(%ld): Silly size requested.",
247 : static_cast<long>(nNewSize));
248 0 : return nullptr;
249 : }
250 :
251 1842270 : void *pReturn = nullptr;
252 :
253 1842270 : if (pData == nullptr)
254 862906 : pReturn = VSIMalloc(nNewSize);
255 : else
256 979363 : pReturn = VSIRealloc(pData, nNewSize);
257 :
258 1842360 : if (pReturn == nullptr)
259 : {
260 0 : if (nNewSize < 2000)
261 : {
262 0 : char szSmallMsg[80] = {};
263 :
264 0 : snprintf(szSmallMsg, sizeof(szSmallMsg),
265 : "CPLRealloc(): Out of memory allocating %ld bytes.",
266 : static_cast<long>(nNewSize));
267 0 : CPLEmergencyError(szSmallMsg);
268 : }
269 : else
270 : {
271 0 : CPLError(CE_Fatal, CPLE_OutOfMemory,
272 : "CPLRealloc(): Out of memory allocating %ld bytes.",
273 : static_cast<long>(nNewSize));
274 : }
275 : }
276 :
277 1842360 : return pReturn;
278 : }
279 :
280 : /************************************************************************/
281 : /* CPLStrdup() */
282 : /************************************************************************/
283 :
284 : /**
285 : * Safe version of strdup() function.
286 : *
287 : * This function is similar to the C library strdup() function, but if
288 : * the memory allocation fails it will issue a CE_Fatal error with
289 : * CPLError() instead of returning NULL. Memory
290 : * allocated with CPLStrdup() can be freed with CPLFree() or VSIFree().
291 : *
292 : * It is also safe to pass a NULL string into CPLStrdup(). CPLStrdup()
293 : * will allocate and return a zero length string (as opposed to a NULL
294 : * string).
295 : *
296 : * @param pszString input string to be duplicated. May be NULL.
297 : * @return pointer to a newly allocated copy of the string. Free with
298 : * CPLFree() or VSIFree().
299 : */
300 :
301 7359800 : char *CPLStrdup(const char *pszString)
302 :
303 : {
304 7359800 : if (pszString == nullptr)
305 989298 : pszString = "";
306 :
307 7359800 : const size_t nLen = strlen(pszString);
308 7359800 : char *pszReturn = static_cast<char *>(CPLMalloc(nLen + 1));
309 7359800 : memcpy(pszReturn, pszString, nLen + 1);
310 7359800 : return (pszReturn);
311 : }
312 :
313 : /************************************************************************/
314 : /* CPLStrlwr() */
315 : /************************************************************************/
316 :
317 : /**
318 : * Convert each characters of the string to lower case.
319 : *
320 : * For example, "ABcdE" will be converted to "abcde".
321 : * Starting with GDAL 3.9, this function is no longer locale dependent.
322 : *
323 : * @param pszString input string to be converted.
324 : * @return pointer to the same string, pszString.
325 : */
326 :
327 3 : char *CPLStrlwr(char *pszString)
328 :
329 : {
330 3 : if (pszString == nullptr)
331 0 : return nullptr;
332 :
333 3 : char *pszTemp = pszString;
334 :
335 24 : while (*pszTemp)
336 : {
337 21 : *pszTemp =
338 21 : static_cast<char>(CPLTolower(static_cast<unsigned char>(*pszTemp)));
339 21 : pszTemp++;
340 : }
341 :
342 3 : return pszString;
343 : }
344 :
345 : /************************************************************************/
346 : /* CPLFGets() */
347 : /* */
348 : /* Note: LF = \n = ASCII 10 */
349 : /* CR = \r = ASCII 13 */
350 : /************************************************************************/
351 :
352 : // ASCII characters.
353 : constexpr char knLF = 10;
354 : constexpr char knCR = 13;
355 :
356 : /**
357 : * Reads in at most one less than nBufferSize characters from the fp
358 : * stream and stores them into the buffer pointed to by pszBuffer.
359 : * Reading stops after an EOF or a newline. If a newline is read, it
360 : * is _not_ stored into the buffer. A '\\0' is stored after the last
361 : * character in the buffer. All three types of newline terminators
362 : * recognized by the CPLFGets(): single '\\r' and '\\n' and '\\r\\n'
363 : * combination.
364 : *
365 : * @param pszBuffer pointer to the targeting character buffer.
366 : * @param nBufferSize maximum size of the string to read (not including
367 : * terminating '\\0').
368 : * @param fp file pointer to read from.
369 : * @return pointer to the pszBuffer containing a string read
370 : * from the file or NULL if the error or end of file was encountered.
371 : */
372 :
373 0 : char *CPLFGets(char *pszBuffer, int nBufferSize, FILE *fp)
374 :
375 : {
376 0 : if (nBufferSize == 0 || pszBuffer == nullptr || fp == nullptr)
377 0 : return nullptr;
378 :
379 : /* -------------------------------------------------------------------- */
380 : /* Let the OS level call read what it things is one line. This */
381 : /* will include the newline. On windows, if the file happens */
382 : /* to be in text mode, the CRLF will have been converted to */
383 : /* just the newline (LF). If it is in binary mode it may well */
384 : /* have both. */
385 : /* -------------------------------------------------------------------- */
386 0 : const long nOriginalOffset = VSIFTell(fp);
387 0 : if (VSIFGets(pszBuffer, nBufferSize, fp) == nullptr)
388 0 : return nullptr;
389 :
390 0 : int nActuallyRead = static_cast<int>(strlen(pszBuffer));
391 0 : if (nActuallyRead == 0)
392 0 : return nullptr;
393 :
394 : /* -------------------------------------------------------------------- */
395 : /* If we found \r and out buffer is full, it is possible there */
396 : /* is also a pending \n. Check for it. */
397 : /* -------------------------------------------------------------------- */
398 0 : if (nBufferSize == nActuallyRead + 1 &&
399 0 : pszBuffer[nActuallyRead - 1] == knCR)
400 : {
401 0 : const int chCheck = fgetc(fp);
402 0 : if (chCheck != knLF)
403 : {
404 : // unget the character.
405 0 : if (VSIFSeek(fp, nOriginalOffset + nActuallyRead, SEEK_SET) == -1)
406 : {
407 0 : CPLError(CE_Failure, CPLE_FileIO,
408 : "Unable to unget a character");
409 : }
410 : }
411 : }
412 :
413 : /* -------------------------------------------------------------------- */
414 : /* Trim off \n, \r or \r\n if it appears at the end. We don't */
415 : /* need to do any "seeking" since we want the newline eaten. */
416 : /* -------------------------------------------------------------------- */
417 0 : if (nActuallyRead > 1 && pszBuffer[nActuallyRead - 1] == knLF &&
418 0 : pszBuffer[nActuallyRead - 2] == knCR)
419 : {
420 0 : pszBuffer[nActuallyRead - 2] = '\0';
421 : }
422 0 : else if (pszBuffer[nActuallyRead - 1] == knLF ||
423 0 : pszBuffer[nActuallyRead - 1] == knCR)
424 : {
425 0 : pszBuffer[nActuallyRead - 1] = '\0';
426 : }
427 :
428 : /* -------------------------------------------------------------------- */
429 : /* Search within the string for a \r (MacOS convention */
430 : /* apparently), and if we find it we need to trim the string, */
431 : /* and seek back. */
432 : /* -------------------------------------------------------------------- */
433 0 : char *pszExtraNewline = strchr(pszBuffer, knCR);
434 :
435 0 : if (pszExtraNewline != nullptr)
436 : {
437 0 : nActuallyRead = static_cast<int>(pszExtraNewline - pszBuffer + 1);
438 :
439 0 : *pszExtraNewline = '\0';
440 0 : if (VSIFSeek(fp, nOriginalOffset + nActuallyRead - 1, SEEK_SET) != 0)
441 0 : return nullptr;
442 :
443 : // This hackery is necessary to try and find our correct
444 : // spot on win32 systems with text mode line translation going
445 : // on. Sometimes the fseek back overshoots, but it doesn't
446 : // "realize it" till a character has been read. Try to read till
447 : // we get to the right spot and get our CR.
448 0 : int chCheck = fgetc(fp);
449 0 : while ((chCheck != knCR && chCheck != EOF) ||
450 0 : VSIFTell(fp) < nOriginalOffset + nActuallyRead)
451 : {
452 : static bool bWarned = false;
453 :
454 0 : if (!bWarned)
455 : {
456 0 : bWarned = true;
457 0 : CPLDebug("CPL",
458 : "CPLFGets() correcting for DOS text mode translation "
459 : "seek problem.");
460 : }
461 0 : chCheck = fgetc(fp);
462 : }
463 : }
464 :
465 0 : return pszBuffer;
466 : }
467 :
468 : /************************************************************************/
469 : /* CPLReadLineBuffer() */
470 : /* */
471 : /* Fetch readline buffer, and ensure it is the desired size, */
472 : /* reallocating if needed. Manages TLS (thread local storage) */
473 : /* issues for the buffer. */
474 : /* We use a special trick to track the actual size of the buffer */
475 : /* The first 4 bytes are reserved to store it as a int, hence the */
476 : /* -4 / +4 hacks with the size and pointer. */
477 : /************************************************************************/
478 2389710 : static char *CPLReadLineBuffer(int nRequiredSize)
479 :
480 : {
481 :
482 : /* -------------------------------------------------------------------- */
483 : /* A required size of -1 means the buffer should be freed. */
484 : /* -------------------------------------------------------------------- */
485 2389710 : if (nRequiredSize == -1)
486 : {
487 2239 : int bMemoryError = FALSE;
488 2239 : void *pRet = CPLGetTLSEx(CTLS_RLBUFFERINFO, &bMemoryError);
489 2239 : if (pRet != nullptr)
490 : {
491 1987 : CPLFree(pRet);
492 1987 : CPLSetTLS(CTLS_RLBUFFERINFO, nullptr, FALSE);
493 : }
494 2239 : return nullptr;
495 : }
496 :
497 : /* -------------------------------------------------------------------- */
498 : /* If the buffer doesn't exist yet, create it. */
499 : /* -------------------------------------------------------------------- */
500 2387470 : int bMemoryError = FALSE;
501 : GUInt32 *pnAlloc =
502 2387470 : static_cast<GUInt32 *>(CPLGetTLSEx(CTLS_RLBUFFERINFO, &bMemoryError));
503 2387470 : if (bMemoryError)
504 0 : return nullptr;
505 :
506 2387470 : if (pnAlloc == nullptr)
507 : {
508 3244 : pnAlloc = static_cast<GUInt32 *>(VSI_MALLOC_VERBOSE(200));
509 3244 : if (pnAlloc == nullptr)
510 0 : return nullptr;
511 3244 : *pnAlloc = 196;
512 3244 : CPLSetTLS(CTLS_RLBUFFERINFO, pnAlloc, TRUE);
513 : }
514 :
515 : /* -------------------------------------------------------------------- */
516 : /* If it is too small, grow it bigger. */
517 : /* -------------------------------------------------------------------- */
518 2387470 : if (static_cast<int>(*pnAlloc) - 1 < nRequiredSize)
519 : {
520 705 : const int nNewSize = nRequiredSize + 4 + 500;
521 705 : if (nNewSize <= 0)
522 : {
523 0 : VSIFree(pnAlloc);
524 0 : CPLSetTLS(CTLS_RLBUFFERINFO, nullptr, FALSE);
525 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
526 : "CPLReadLineBuffer(): Trying to allocate more than "
527 : "2 GB.");
528 0 : return nullptr;
529 : }
530 :
531 : GUInt32 *pnAllocNew =
532 705 : static_cast<GUInt32 *>(VSI_REALLOC_VERBOSE(pnAlloc, nNewSize));
533 705 : if (pnAllocNew == nullptr)
534 : {
535 0 : VSIFree(pnAlloc);
536 0 : CPLSetTLS(CTLS_RLBUFFERINFO, nullptr, FALSE);
537 0 : return nullptr;
538 : }
539 705 : pnAlloc = pnAllocNew;
540 :
541 705 : *pnAlloc = nNewSize - 4;
542 705 : CPLSetTLS(CTLS_RLBUFFERINFO, pnAlloc, TRUE);
543 : }
544 :
545 2387470 : return reinterpret_cast<char *>(pnAlloc + 1);
546 : }
547 :
548 : /************************************************************************/
549 : /* CPLReadLine() */
550 : /************************************************************************/
551 :
552 : /**
553 : * Simplified line reading from text file.
554 : *
555 : * Read a line of text from the given file handle, taking care
556 : * to capture CR and/or LF and strip off ... equivalent of
557 : * DKReadLine(). Pointer to an internal buffer is returned.
558 : * The application shouldn't free it, or depend on its value
559 : * past the next call to CPLReadLine().
560 : *
561 : * Note that CPLReadLine() uses VSIFGets(), so any hooking of VSI file
562 : * services should apply to CPLReadLine() as well.
563 : *
564 : * CPLReadLine() maintains an internal buffer, which will appear as a
565 : * single block memory leak in some circumstances. CPLReadLine() may
566 : * be called with a NULL FILE * at any time to free this working buffer.
567 : *
568 : * @param fp file pointer opened with VSIFOpen().
569 : *
570 : * @return pointer to an internal buffer containing a line of text read
571 : * from the file or NULL if the end of file was encountered.
572 : */
573 :
574 5 : const char *CPLReadLine(FILE *fp)
575 :
576 : {
577 : /* -------------------------------------------------------------------- */
578 : /* Cleanup case. */
579 : /* -------------------------------------------------------------------- */
580 5 : if (fp == nullptr)
581 : {
582 5 : CPLReadLineBuffer(-1);
583 5 : return nullptr;
584 : }
585 :
586 : /* -------------------------------------------------------------------- */
587 : /* Loop reading chunks of the line till we get to the end of */
588 : /* the line. */
589 : /* -------------------------------------------------------------------- */
590 0 : size_t nBytesReadThisTime = 0;
591 0 : char *pszRLBuffer = nullptr;
592 0 : size_t nReadSoFar = 0;
593 :
594 0 : do
595 : {
596 : /* --------------------------------------------------------------------
597 : */
598 : /* Grow the working buffer if we have it nearly full. Fail out */
599 : /* of read line if we can't reallocate it big enough (for */
600 : /* instance for a _very large_ file with no newlines). */
601 : /* --------------------------------------------------------------------
602 : */
603 0 : if (nReadSoFar > 100 * 1024 * 1024)
604 : // It is dubious that we need to read a line longer than 100 MB.
605 0 : return nullptr;
606 0 : pszRLBuffer = CPLReadLineBuffer(static_cast<int>(nReadSoFar) + 129);
607 0 : if (pszRLBuffer == nullptr)
608 0 : return nullptr;
609 :
610 : /* --------------------------------------------------------------------
611 : */
612 : /* Do the actual read. */
613 : /* --------------------------------------------------------------------
614 : */
615 0 : if (CPLFGets(pszRLBuffer + nReadSoFar, 128, fp) == nullptr &&
616 : nReadSoFar == 0)
617 0 : return nullptr;
618 :
619 0 : nBytesReadThisTime = strlen(pszRLBuffer + nReadSoFar);
620 0 : nReadSoFar += nBytesReadThisTime;
621 0 : } while (nBytesReadThisTime >= 127 && pszRLBuffer[nReadSoFar - 1] != knCR &&
622 0 : pszRLBuffer[nReadSoFar - 1] != knLF);
623 :
624 0 : return pszRLBuffer;
625 : }
626 :
627 : /************************************************************************/
628 : /* CPLReadLineL() */
629 : /************************************************************************/
630 :
631 : /**
632 : * Simplified line reading from text file.
633 : *
634 : * Similar to CPLReadLine(), but reading from a large file API handle.
635 : *
636 : * @param fp file pointer opened with VSIFOpenL().
637 : *
638 : * @return pointer to an internal buffer containing a line of text read
639 : * from the file or NULL if the end of file was encountered.
640 : */
641 :
642 196360 : const char *CPLReadLineL(VSILFILE *fp)
643 : {
644 196360 : return CPLReadLine2L(fp, -1, nullptr);
645 : }
646 :
647 : /************************************************************************/
648 : /* CPLReadLine2L() */
649 : /************************************************************************/
650 :
651 : /**
652 : * Simplified line reading from text file.
653 : *
654 : * Similar to CPLReadLine(), but reading from a large file API handle.
655 : *
656 : * @param fp file pointer opened with VSIFOpenL().
657 : * @param nMaxCars maximum number of characters allowed, or -1 for no limit.
658 : * @param papszOptions NULL-terminated array of options. Unused for now.
659 :
660 : * @return pointer to an internal buffer containing a line of text read
661 : * from the file or NULL if the end of file was encountered or the maximum
662 : * number of characters allowed reached.
663 : *
664 : * @since GDAL 1.7.0
665 : */
666 :
667 1265360 : const char *CPLReadLine2L(VSILFILE *fp, int nMaxCars,
668 : CPL_UNUSED CSLConstList papszOptions)
669 :
670 : {
671 : int nBufLength;
672 2530710 : return CPLReadLine3L(fp, nMaxCars, &nBufLength, papszOptions);
673 : }
674 :
675 : /************************************************************************/
676 : /* CPLReadLine3L() */
677 : /************************************************************************/
678 :
679 : /**
680 : * Simplified line reading from text file.
681 : *
682 : * Similar to CPLReadLine(), but reading from a large file API handle.
683 : *
684 : * @param fp file pointer opened with VSIFOpenL().
685 : * @param nMaxCars maximum number of characters allowed, or -1 for no limit.
686 : * @param papszOptions NULL-terminated array of options. Unused for now.
687 : * @param[out] pnBufLength size of output string (must be non-NULL)
688 :
689 : * @return pointer to an internal buffer containing a line of text read
690 : * from the file or NULL if the end of file was encountered or the maximum
691 : * number of characters allowed reached.
692 : *
693 : * @since GDAL 2.3.0
694 : */
695 1328530 : const char *CPLReadLine3L(VSILFILE *fp, int nMaxCars, int *pnBufLength,
696 : CPL_UNUSED CSLConstList papszOptions)
697 : {
698 : /* -------------------------------------------------------------------- */
699 : /* Cleanup case. */
700 : /* -------------------------------------------------------------------- */
701 1328530 : if (fp == nullptr)
702 : {
703 2234 : CPLReadLineBuffer(-1);
704 2234 : return nullptr;
705 : }
706 :
707 : /* -------------------------------------------------------------------- */
708 : /* Loop reading chunks of the line till we get to the end of */
709 : /* the line. */
710 : /* -------------------------------------------------------------------- */
711 1326300 : char *pszRLBuffer = nullptr;
712 1326300 : const size_t nChunkSize = 40;
713 1326300 : char szChunk[nChunkSize] = {};
714 1326300 : size_t nChunkBytesRead = 0;
715 1326300 : size_t nChunkBytesConsumed = 0;
716 :
717 1326300 : *pnBufLength = 0;
718 1326300 : szChunk[0] = 0;
719 :
720 : while (true)
721 : {
722 : /* --------------------------------------------------------------------
723 : */
724 : /* Read a chunk from the input file. */
725 : /* --------------------------------------------------------------------
726 : */
727 2387470 : if (*pnBufLength > INT_MAX - static_cast<int>(nChunkSize) - 1)
728 : {
729 0 : CPLError(CE_Failure, CPLE_AppDefined,
730 : "Too big line : more than 2 billion characters!.");
731 0 : CPLReadLineBuffer(-1);
732 0 : return nullptr;
733 : }
734 :
735 : pszRLBuffer =
736 2387470 : CPLReadLineBuffer(static_cast<int>(*pnBufLength + nChunkSize + 1));
737 2387470 : if (pszRLBuffer == nullptr)
738 0 : return nullptr;
739 :
740 2387470 : if (nChunkBytesRead == nChunkBytesConsumed + 1)
741 : {
742 :
743 : // case where one character is left over from last read.
744 1061170 : szChunk[0] = szChunk[nChunkBytesConsumed];
745 :
746 1061170 : nChunkBytesConsumed = 0;
747 1061170 : nChunkBytesRead = VSIFReadL(szChunk + 1, 1, nChunkSize - 1, fp) + 1;
748 : }
749 : else
750 : {
751 1326300 : nChunkBytesConsumed = 0;
752 :
753 : // fresh read.
754 1326300 : nChunkBytesRead = VSIFReadL(szChunk, 1, nChunkSize, fp);
755 1326300 : if (nChunkBytesRead == 0)
756 : {
757 11120 : if (*pnBufLength == 0)
758 11120 : return nullptr;
759 :
760 0 : break;
761 : }
762 : }
763 :
764 : /* --------------------------------------------------------------------
765 : */
766 : /* copy over characters watching for end-of-line. */
767 : /* --------------------------------------------------------------------
768 : */
769 2376350 : bool bBreak = false;
770 63137900 : while (nChunkBytesConsumed < nChunkBytesRead - 1 && !bBreak)
771 : {
772 60761600 : if ((szChunk[nChunkBytesConsumed] == knCR &&
773 172272 : szChunk[nChunkBytesConsumed + 1] == knLF) ||
774 60589600 : (szChunk[nChunkBytesConsumed] == knLF &&
775 1131470 : szChunk[nChunkBytesConsumed + 1] == knCR))
776 : {
777 171995 : nChunkBytesConsumed += 2;
778 171995 : bBreak = true;
779 : }
780 60589600 : else if (szChunk[nChunkBytesConsumed] == knLF ||
781 59458100 : szChunk[nChunkBytesConsumed] == knCR)
782 : {
783 1131750 : nChunkBytesConsumed += 1;
784 1131750 : bBreak = true;
785 : }
786 : else
787 : {
788 59457800 : pszRLBuffer[(*pnBufLength)++] = szChunk[nChunkBytesConsumed++];
789 59457800 : if (nMaxCars >= 0 && *pnBufLength == nMaxCars)
790 : {
791 0 : CPLError(CE_Failure, CPLE_AppDefined,
792 : "Maximum number of characters allowed reached.");
793 0 : return nullptr;
794 : }
795 : }
796 : }
797 :
798 2376350 : if (bBreak)
799 1303740 : break;
800 :
801 : /* --------------------------------------------------------------------
802 : */
803 : /* If there is a remaining character and it is not a newline */
804 : /* consume it. If it is a newline, but we are clearly at the */
805 : /* end of the file then consume it. */
806 : /* --------------------------------------------------------------------
807 : */
808 1072600 : if (nChunkBytesConsumed == nChunkBytesRead - 1 &&
809 : nChunkBytesRead < nChunkSize)
810 : {
811 11431 : if (szChunk[nChunkBytesConsumed] == knLF ||
812 1658 : szChunk[nChunkBytesConsumed] == knCR)
813 : {
814 9773 : nChunkBytesConsumed++;
815 9773 : break;
816 : }
817 :
818 1658 : pszRLBuffer[(*pnBufLength)++] = szChunk[nChunkBytesConsumed++];
819 1658 : break;
820 : }
821 1061170 : }
822 :
823 : /* -------------------------------------------------------------------- */
824 : /* If we have left over bytes after breaking out, seek back to */
825 : /* ensure they remain to be read next time. */
826 : /* -------------------------------------------------------------------- */
827 1315180 : if (nChunkBytesConsumed < nChunkBytesRead)
828 : {
829 1298240 : const size_t nBytesToPush = nChunkBytesRead - nChunkBytesConsumed;
830 :
831 1298240 : if (VSIFSeekL(fp, VSIFTellL(fp) - nBytesToPush, SEEK_SET) != 0)
832 0 : return nullptr;
833 : }
834 :
835 1315180 : pszRLBuffer[*pnBufLength] = '\0';
836 :
837 1315180 : return pszRLBuffer;
838 : }
839 :
840 : /************************************************************************/
841 : /* CPLScanString() */
842 : /************************************************************************/
843 :
844 : /**
845 : * Scan up to a maximum number of characters from a given string,
846 : * allocate a buffer for a new string and fill it with scanned characters.
847 : *
848 : * @param pszString String containing characters to be scanned. It may be
849 : * terminated with a null character.
850 : *
851 : * @param nMaxLength The maximum number of character to read. Less
852 : * characters will be read if a null character is encountered.
853 : *
854 : * @param bTrimSpaces If TRUE, trim ending spaces from the input string.
855 : * Character considered as empty using isspace(3) function.
856 : *
857 : * @param bNormalize If TRUE, replace ':' symbol with the '_'. It is needed if
858 : * resulting string will be used in CPL dictionaries.
859 : *
860 : * @return Pointer to the resulting string buffer. Caller responsible to free
861 : * this buffer with CPLFree().
862 : */
863 :
864 5184 : char *CPLScanString(const char *pszString, int nMaxLength, int bTrimSpaces,
865 : int bNormalize)
866 : {
867 5184 : if (!pszString)
868 0 : return nullptr;
869 :
870 5184 : if (!nMaxLength)
871 2 : return CPLStrdup("");
872 :
873 5182 : char *pszBuffer = static_cast<char *>(CPLMalloc(nMaxLength + 1));
874 5182 : if (!pszBuffer)
875 0 : return nullptr;
876 :
877 5182 : strncpy(pszBuffer, pszString, nMaxLength);
878 5182 : pszBuffer[nMaxLength] = '\0';
879 :
880 5182 : if (bTrimSpaces)
881 : {
882 5182 : size_t i = strlen(pszBuffer);
883 6306 : while (i > 0)
884 : {
885 6272 : i--;
886 6272 : if (!isspace(static_cast<unsigned char>(pszBuffer[i])))
887 5148 : break;
888 1124 : pszBuffer[i] = '\0';
889 : }
890 : }
891 :
892 5182 : if (bNormalize)
893 : {
894 5064 : size_t i = strlen(pszBuffer);
895 38603 : while (i > 0)
896 : {
897 33539 : i--;
898 33539 : if (pszBuffer[i] == ':')
899 0 : pszBuffer[i] = '_';
900 : }
901 : }
902 :
903 5182 : return pszBuffer;
904 : }
905 :
906 : /************************************************************************/
907 : /* CPLScanLong() */
908 : /************************************************************************/
909 :
910 : /**
911 : * Scan up to a maximum number of characters from a string and convert
912 : * the result to a long.
913 : *
914 : * @param pszString String containing characters to be scanned. It may be
915 : * terminated with a null character.
916 : *
917 : * @param nMaxLength The maximum number of character to consider as part
918 : * of the number. Less characters will be considered if a null character
919 : * is encountered.
920 : *
921 : * @return Long value, converted from its ASCII form.
922 : */
923 :
924 1358 : long CPLScanLong(const char *pszString, int nMaxLength)
925 : {
926 1358 : CPLAssert(nMaxLength >= 0);
927 1358 : if (pszString == nullptr)
928 0 : return 0;
929 1358 : const size_t nLength = CPLStrnlen(pszString, nMaxLength);
930 2716 : const std::string osValue(pszString, nLength);
931 1358 : return atol(osValue.c_str());
932 : }
933 :
934 : /************************************************************************/
935 : /* CPLScanULong() */
936 : /************************************************************************/
937 :
938 : /**
939 : * Scan up to a maximum number of characters from a string and convert
940 : * the result to a unsigned long.
941 : *
942 : * @param pszString String containing characters to be scanned. It may be
943 : * terminated with a null character.
944 : *
945 : * @param nMaxLength The maximum number of character to consider as part
946 : * of the number. Less characters will be considered if a null character
947 : * is encountered.
948 : *
949 : * @return Unsigned long value, converted from its ASCII form.
950 : */
951 :
952 0 : unsigned long CPLScanULong(const char *pszString, int nMaxLength)
953 : {
954 0 : CPLAssert(nMaxLength >= 0);
955 0 : if (pszString == nullptr)
956 0 : return 0;
957 0 : const size_t nLength = CPLStrnlen(pszString, nMaxLength);
958 0 : const std::string osValue(pszString, nLength);
959 0 : return strtoul(osValue.c_str(), nullptr, 10);
960 : }
961 :
962 : /************************************************************************/
963 : /* CPLScanUIntBig() */
964 : /************************************************************************/
965 :
966 : /**
967 : * Extract big integer from string.
968 : *
969 : * Scan up to a maximum number of characters from a string and convert
970 : * the result to a GUIntBig.
971 : *
972 : * @param pszString String containing characters to be scanned. It may be
973 : * terminated with a null character.
974 : *
975 : * @param nMaxLength The maximum number of character to consider as part
976 : * of the number. Less characters will be considered if a null character
977 : * is encountered.
978 : *
979 : * @return GUIntBig value, converted from its ASCII form.
980 : */
981 :
982 16009 : GUIntBig CPLScanUIntBig(const char *pszString, int nMaxLength)
983 : {
984 16009 : CPLAssert(nMaxLength >= 0);
985 16009 : if (pszString == nullptr)
986 0 : return 0;
987 16009 : const size_t nLength = CPLStrnlen(pszString, nMaxLength);
988 32020 : const std::string osValue(pszString, nLength);
989 :
990 : /* -------------------------------------------------------------------- */
991 : /* Fetch out the result */
992 : /* -------------------------------------------------------------------- */
993 16010 : return strtoull(osValue.c_str(), nullptr, 10);
994 : }
995 :
996 : /************************************************************************/
997 : /* CPLAtoGIntBig() */
998 : /************************************************************************/
999 :
1000 : /**
1001 : * Convert a string to a 64 bit signed integer.
1002 : *
1003 : * @param pszString String containing 64 bit signed integer.
1004 : * @return 64 bit signed integer.
1005 : * @since GDAL 2.0
1006 : */
1007 :
1008 109815 : GIntBig CPLAtoGIntBig(const char *pszString)
1009 : {
1010 109815 : return atoll(pszString);
1011 : }
1012 :
1013 : #if defined(__MINGW32__) || defined(__sun__)
1014 :
1015 : // mingw atoll() doesn't return ERANGE in case of overflow
1016 : static int CPLAtoGIntBigExHasOverflow(const char *pszString, GIntBig nVal)
1017 : {
1018 : if (strlen(pszString) <= 18)
1019 : return FALSE;
1020 : while (*pszString == ' ')
1021 : pszString++;
1022 : if (*pszString == '+')
1023 : pszString++;
1024 : char szBuffer[32] = {};
1025 : /* x86_64-w64-mingw32-g++ (GCC) 4.8.2 annoyingly warns */
1026 : #ifdef HAVE_GCC_DIAGNOSTIC_PUSH
1027 : #pragma GCC diagnostic push
1028 : #pragma GCC diagnostic ignored "-Wformat"
1029 : #endif
1030 : snprintf(szBuffer, sizeof(szBuffer), CPL_FRMT_GIB, nVal);
1031 : #ifdef HAVE_GCC_DIAGNOSTIC_PUSH
1032 : #pragma GCC diagnostic pop
1033 : #endif
1034 : return strcmp(szBuffer, pszString) != 0;
1035 : }
1036 :
1037 : #endif
1038 :
1039 : /************************************************************************/
1040 : /* CPLAtoGIntBigEx() */
1041 : /************************************************************************/
1042 :
1043 : /**
1044 : * Convert a string to a 64 bit signed integer.
1045 : *
1046 : * @param pszString String containing 64 bit signed integer.
1047 : * @param bWarn Issue a warning if an overflow occurs during conversion
1048 : * @param pbOverflow Pointer to an integer to store if an overflow occurred, or
1049 : * NULL
1050 : * @return 64 bit signed integer.
1051 : * @since GDAL 2.0
1052 : */
1053 :
1054 100107 : GIntBig CPLAtoGIntBigEx(const char *pszString, int bWarn, int *pbOverflow)
1055 : {
1056 100107 : errno = 0;
1057 100107 : GIntBig nVal = strtoll(pszString, nullptr, 10);
1058 100107 : if (errno == ERANGE
1059 : #if defined(__MINGW32__) || defined(__sun__)
1060 : || CPLAtoGIntBigExHasOverflow(pszString, nVal)
1061 : #endif
1062 : )
1063 : {
1064 4 : if (pbOverflow)
1065 2 : *pbOverflow = TRUE;
1066 4 : if (bWarn)
1067 : {
1068 2 : CPLError(CE_Warning, CPLE_AppDefined,
1069 : "64 bit integer overflow when converting %s", pszString);
1070 : }
1071 4 : while (*pszString == ' ')
1072 0 : pszString++;
1073 4 : return (*pszString == '-') ? GINTBIG_MIN : GINTBIG_MAX;
1074 : }
1075 100103 : else if (pbOverflow)
1076 : {
1077 3874 : *pbOverflow = FALSE;
1078 : }
1079 100103 : return nVal;
1080 : }
1081 :
1082 : /************************************************************************/
1083 : /* CPLScanPointer() */
1084 : /************************************************************************/
1085 :
1086 : /**
1087 : * Extract pointer from string.
1088 : *
1089 : * Scan up to a maximum number of characters from a string and convert
1090 : * the result to a pointer.
1091 : *
1092 : * @param pszString String containing characters to be scanned. It may be
1093 : * terminated with a null character.
1094 : *
1095 : * @param nMaxLength The maximum number of character to consider as part
1096 : * of the number. Less characters will be considered if a null character
1097 : * is encountered.
1098 : *
1099 : * @return pointer value, converted from its ASCII form.
1100 : */
1101 :
1102 1000 : void *CPLScanPointer(const char *pszString, int nMaxLength)
1103 : {
1104 1000 : char szTemp[128] = {};
1105 :
1106 : /* -------------------------------------------------------------------- */
1107 : /* Compute string into local buffer, and terminate it. */
1108 : /* -------------------------------------------------------------------- */
1109 1000 : if (nMaxLength > static_cast<int>(sizeof(szTemp)) - 1)
1110 0 : nMaxLength = sizeof(szTemp) - 1;
1111 :
1112 1000 : strncpy(szTemp, pszString, nMaxLength);
1113 1000 : szTemp[nMaxLength] = '\0';
1114 :
1115 : /* -------------------------------------------------------------------- */
1116 : /* On MSVC we have to scanf pointer values without the 0x */
1117 : /* prefix. */
1118 : /* -------------------------------------------------------------------- */
1119 1000 : if (STARTS_WITH_CI(szTemp, "0x"))
1120 : {
1121 990 : void *pResult = nullptr;
1122 :
1123 : #if defined(__MSVCRT__) || (defined(_WIN32) && defined(_MSC_VER))
1124 : // cppcheck-suppress invalidscanf
1125 : sscanf(szTemp + 2, "%p", &pResult);
1126 : #else
1127 : // cppcheck-suppress invalidscanf
1128 990 : sscanf(szTemp, "%p", &pResult);
1129 :
1130 : // Solaris actually behaves like MSVCRT.
1131 990 : if (pResult == nullptr)
1132 : {
1133 : // cppcheck-suppress invalidscanf
1134 0 : sscanf(szTemp + 2, "%p", &pResult);
1135 : }
1136 : #endif
1137 990 : return pResult;
1138 : }
1139 :
1140 : #if SIZEOF_VOIDP == 8
1141 10 : return reinterpret_cast<void *>(CPLScanUIntBig(szTemp, nMaxLength));
1142 : #else
1143 : return reinterpret_cast<void *>(CPLScanULong(szTemp, nMaxLength));
1144 : #endif
1145 : }
1146 :
1147 : /************************************************************************/
1148 : /* CPLScanDouble() */
1149 : /************************************************************************/
1150 :
1151 : /**
1152 : * Extract double from string.
1153 : *
1154 : * Scan up to a maximum number of characters from a string and convert the
1155 : * result to a double. This function uses CPLAtof() to convert string to
1156 : * double value, so it uses a comma as a decimal delimiter.
1157 : *
1158 : * @param pszString String containing characters to be scanned. It may be
1159 : * terminated with a null character.
1160 : *
1161 : * @param nMaxLength The maximum number of character to consider as part
1162 : * of the number. Less characters will be considered if a null character
1163 : * is encountered.
1164 : *
1165 : * @return Double value, converted from its ASCII form.
1166 : */
1167 :
1168 317 : double CPLScanDouble(const char *pszString, int nMaxLength)
1169 : {
1170 317 : char szValue[32] = {};
1171 317 : char *pszValue = nullptr;
1172 :
1173 317 : if (nMaxLength + 1 < static_cast<int>(sizeof(szValue)))
1174 317 : pszValue = szValue;
1175 : else
1176 0 : pszValue = static_cast<char *>(CPLMalloc(nMaxLength + 1));
1177 :
1178 : /* -------------------------------------------------------------------- */
1179 : /* Compute string into local buffer, and terminate it. */
1180 : /* -------------------------------------------------------------------- */
1181 317 : strncpy(pszValue, pszString, nMaxLength);
1182 317 : pszValue[nMaxLength] = '\0';
1183 :
1184 : /* -------------------------------------------------------------------- */
1185 : /* Make a pass through converting 'D's to 'E's. */
1186 : /* -------------------------------------------------------------------- */
1187 6436 : for (int i = 0; i < nMaxLength; i++)
1188 6119 : if (pszValue[i] == 'd' || pszValue[i] == 'D')
1189 45 : pszValue[i] = 'E';
1190 :
1191 : /* -------------------------------------------------------------------- */
1192 : /* The conversion itself. */
1193 : /* -------------------------------------------------------------------- */
1194 317 : const double dfValue = CPLAtof(pszValue);
1195 :
1196 317 : if (pszValue != szValue)
1197 0 : CPLFree(pszValue);
1198 317 : return dfValue;
1199 : }
1200 :
1201 : /************************************************************************/
1202 : /* CPLPrintString() */
1203 : /************************************************************************/
1204 :
1205 : /**
1206 : * Copy the string pointed to by pszSrc, NOT including the terminating
1207 : * `\\0' character, to the array pointed to by pszDest.
1208 : *
1209 : * @param pszDest Pointer to the destination string buffer. Should be
1210 : * large enough to hold the resulting string.
1211 : *
1212 : * @param pszSrc Pointer to the source buffer.
1213 : *
1214 : * @param nMaxLen Maximum length of the resulting string. If string length
1215 : * is greater than nMaxLen, it will be truncated.
1216 : *
1217 : * @return Number of characters printed.
1218 : */
1219 :
1220 9383 : int CPLPrintString(char *pszDest, const char *pszSrc, int nMaxLen)
1221 : {
1222 9383 : if (!pszDest)
1223 0 : return 0;
1224 :
1225 9383 : if (!pszSrc)
1226 : {
1227 0 : *pszDest = '\0';
1228 0 : return 1;
1229 : }
1230 :
1231 9383 : int nChars = 0;
1232 9383 : char *pszTemp = pszDest;
1233 :
1234 138858 : while (nChars < nMaxLen && *pszSrc)
1235 : {
1236 129475 : *pszTemp++ = *pszSrc++;
1237 129475 : nChars++;
1238 : }
1239 :
1240 9383 : return nChars;
1241 : }
1242 :
1243 : /************************************************************************/
1244 : /* CPLPrintStringFill() */
1245 : /************************************************************************/
1246 :
1247 : /**
1248 : * Copy the string pointed to by pszSrc, NOT including the terminating
1249 : * `\\0' character, to the array pointed to by pszDest. Remainder of the
1250 : * destination string will be filled with space characters. This is only
1251 : * difference from the PrintString().
1252 : *
1253 : * @param pszDest Pointer to the destination string buffer. Should be
1254 : * large enough to hold the resulting string.
1255 : *
1256 : * @param pszSrc Pointer to the source buffer.
1257 : *
1258 : * @param nMaxLen Maximum length of the resulting string. If string length
1259 : * is greater than nMaxLen, it will be truncated.
1260 : *
1261 : * @return Number of characters printed.
1262 : */
1263 :
1264 209 : int CPLPrintStringFill(char *pszDest, const char *pszSrc, int nMaxLen)
1265 : {
1266 209 : if (!pszDest)
1267 0 : return 0;
1268 :
1269 209 : if (!pszSrc)
1270 : {
1271 0 : memset(pszDest, ' ', nMaxLen);
1272 0 : return nMaxLen;
1273 : }
1274 :
1275 209 : char *pszTemp = pszDest;
1276 1257 : while (nMaxLen && *pszSrc)
1277 : {
1278 1048 : *pszTemp++ = *pszSrc++;
1279 1048 : nMaxLen--;
1280 : }
1281 :
1282 209 : if (nMaxLen)
1283 71 : memset(pszTemp, ' ', nMaxLen);
1284 :
1285 209 : return nMaxLen;
1286 : }
1287 :
1288 : /************************************************************************/
1289 : /* CPLPrintInt32() */
1290 : /************************************************************************/
1291 :
1292 : /**
1293 : * Print GInt32 value into specified string buffer. This string will not
1294 : * be NULL-terminated.
1295 : *
1296 : * @param pszBuffer Pointer to the destination string buffer. Should be
1297 : * large enough to hold the resulting string. Note, that the string will
1298 : * not be NULL-terminated, so user should do this himself, if needed.
1299 : *
1300 : * @param iValue Numerical value to print.
1301 : *
1302 : * @param nMaxLen Maximum length of the resulting string. If string length
1303 : * is greater than nMaxLen, it will be truncated.
1304 : *
1305 : * @return Number of characters printed.
1306 : */
1307 :
1308 9 : int CPLPrintInt32(char *pszBuffer, GInt32 iValue, int nMaxLen)
1309 : {
1310 9 : if (!pszBuffer)
1311 0 : return 0;
1312 :
1313 9 : if (nMaxLen >= 64)
1314 0 : nMaxLen = 63;
1315 :
1316 9 : char szTemp[64] = {};
1317 :
1318 : #if UINT_MAX == 65535
1319 : snprintf(szTemp, sizeof(szTemp), "%*ld", nMaxLen, iValue);
1320 : #else
1321 9 : snprintf(szTemp, sizeof(szTemp), "%*d", nMaxLen, iValue);
1322 : #endif
1323 :
1324 9 : return CPLPrintString(pszBuffer, szTemp, nMaxLen);
1325 : }
1326 :
1327 : /************************************************************************/
1328 : /* CPLPrintUIntBig() */
1329 : /************************************************************************/
1330 :
1331 : /**
1332 : * Print GUIntBig value into specified string buffer. This string will not
1333 : * be NULL-terminated.
1334 : *
1335 : * @param pszBuffer Pointer to the destination string buffer. Should be
1336 : * large enough to hold the resulting string. Note, that the string will
1337 : * not be NULL-terminated, so user should do this himself, if needed.
1338 : *
1339 : * @param iValue Numerical value to print.
1340 : *
1341 : * @param nMaxLen Maximum length of the resulting string. If string length
1342 : * is greater than nMaxLen, it will be truncated.
1343 : *
1344 : * @return Number of characters printed.
1345 : */
1346 :
1347 24 : int CPLPrintUIntBig(char *pszBuffer, GUIntBig iValue, int nMaxLen)
1348 : {
1349 24 : if (!pszBuffer)
1350 0 : return 0;
1351 :
1352 24 : if (nMaxLen >= 64)
1353 0 : nMaxLen = 63;
1354 :
1355 24 : char szTemp[64] = {};
1356 :
1357 : #if defined(__MSVCRT__) || (defined(_WIN32) && defined(_MSC_VER))
1358 : /* x86_64-w64-mingw32-g++ (GCC) 4.8.2 annoyingly warns */
1359 : #ifdef HAVE_GCC_DIAGNOSTIC_PUSH
1360 : #pragma GCC diagnostic push
1361 : #pragma GCC diagnostic ignored "-Wformat"
1362 : #pragma GCC diagnostic ignored "-Wformat-extra-args"
1363 : #endif
1364 : snprintf(szTemp, sizeof(szTemp), "%*I64u", nMaxLen, iValue);
1365 : #ifdef HAVE_GCC_DIAGNOSTIC_PUSH
1366 : #pragma GCC diagnostic pop
1367 : #endif
1368 : #else
1369 24 : snprintf(szTemp, sizeof(szTemp), "%*llu", nMaxLen, iValue);
1370 : #endif
1371 :
1372 24 : return CPLPrintString(pszBuffer, szTemp, nMaxLen);
1373 : }
1374 :
1375 : /************************************************************************/
1376 : /* CPLPrintPointer() */
1377 : /************************************************************************/
1378 :
1379 : /**
1380 : * Print pointer value into specified string buffer. This string will not
1381 : * be NULL-terminated.
1382 : *
1383 : * @param pszBuffer Pointer to the destination string buffer. Should be
1384 : * large enough to hold the resulting string. Note, that the string will
1385 : * not be NULL-terminated, so user should do this himself, if needed.
1386 : *
1387 : * @param pValue Pointer to ASCII encode.
1388 : *
1389 : * @param nMaxLen Maximum length of the resulting string. If string length
1390 : * is greater than nMaxLen, it will be truncated.
1391 : *
1392 : * @return Number of characters printed.
1393 : */
1394 :
1395 9307 : int CPLPrintPointer(char *pszBuffer, void *pValue, int nMaxLen)
1396 : {
1397 9307 : if (!pszBuffer)
1398 0 : return 0;
1399 :
1400 9307 : if (nMaxLen >= 64)
1401 8310 : nMaxLen = 63;
1402 :
1403 9307 : char szTemp[64] = {};
1404 :
1405 9307 : snprintf(szTemp, sizeof(szTemp), "%p", pValue);
1406 :
1407 : // On windows, and possibly some other platforms the sprintf("%p")
1408 : // does not prefix things with 0x so it is hard to know later if the
1409 : // value is hex encoded. Fix this up here.
1410 :
1411 9307 : if (!STARTS_WITH_CI(szTemp, "0x"))
1412 0 : snprintf(szTemp, sizeof(szTemp), "0x%p", pValue);
1413 :
1414 9307 : return CPLPrintString(pszBuffer, szTemp, nMaxLen);
1415 : }
1416 :
1417 : /************************************************************************/
1418 : /* CPLPrintDouble() */
1419 : /************************************************************************/
1420 :
1421 : /**
1422 : * Print double value into specified string buffer. Exponential character
1423 : * flag 'E' (or 'e') will be replaced with 'D', as in Fortran. Resulting
1424 : * string will not to be NULL-terminated.
1425 : *
1426 : * @param pszBuffer Pointer to the destination string buffer. Should be
1427 : * large enough to hold the resulting string. Note, that the string will
1428 : * not be NULL-terminated, so user should do this himself, if needed.
1429 : *
1430 : * @param pszFormat Format specifier (for example, "%16.9E").
1431 : *
1432 : * @param dfValue Numerical value to print.
1433 : *
1434 : * @param pszLocale Unused.
1435 : *
1436 : * @return Number of characters printed.
1437 : */
1438 :
1439 0 : int CPLPrintDouble(char *pszBuffer, const char *pszFormat, double dfValue,
1440 : CPL_UNUSED const char *pszLocale)
1441 : {
1442 0 : if (!pszBuffer)
1443 0 : return 0;
1444 :
1445 0 : const int knDoubleBufferSize = 64;
1446 0 : char szTemp[knDoubleBufferSize] = {};
1447 :
1448 0 : CPLsnprintf(szTemp, knDoubleBufferSize, pszFormat, dfValue);
1449 0 : szTemp[knDoubleBufferSize - 1] = '\0';
1450 :
1451 0 : for (int i = 0; szTemp[i] != '\0'; i++)
1452 : {
1453 0 : if (szTemp[i] == 'E' || szTemp[i] == 'e')
1454 0 : szTemp[i] = 'D';
1455 : }
1456 :
1457 0 : return CPLPrintString(pszBuffer, szTemp, 64);
1458 : }
1459 :
1460 : /************************************************************************/
1461 : /* CPLPrintTime() */
1462 : /************************************************************************/
1463 :
1464 : /**
1465 : * Print specified time value accordingly to the format options and
1466 : * specified locale name. This function does following:
1467 : *
1468 : * - if locale parameter is not NULL, the current locale setting will be
1469 : * stored and replaced with the specified one;
1470 : * - format time value with the strftime(3) function;
1471 : * - restore back current locale, if was saved.
1472 : *
1473 : * @param pszBuffer Pointer to the destination string buffer. Should be
1474 : * large enough to hold the resulting string. Note, that the string will
1475 : * not be NULL-terminated, so user should do this himself, if needed.
1476 : *
1477 : * @param nMaxLen Maximum length of the resulting string. If string length is
1478 : * greater than nMaxLen, it will be truncated.
1479 : *
1480 : * @param pszFormat Controls the output format. Options are the same as
1481 : * for strftime(3) function.
1482 : *
1483 : * @param poBrokenTime Pointer to the broken-down time structure. May be
1484 : * requested with the VSIGMTime() and VSILocalTime() functions.
1485 : *
1486 : * @param pszLocale Pointer to a character string containing locale name
1487 : * ("C", "POSIX", "us_US", "ru_RU.KOI8-R" etc.). If NULL we will not
1488 : * manipulate with locale settings and current process locale will be used for
1489 : * printing. Be aware that it may be unsuitable to use current locale for
1490 : * printing time, because all names will be printed in your native language,
1491 : * as well as time format settings also may be adjusted differently from the
1492 : * C/POSIX defaults. To solve these problems this option was introduced.
1493 : *
1494 : * @return Number of characters printed.
1495 : */
1496 :
1497 34 : int CPLPrintTime(char *pszBuffer, int nMaxLen, const char *pszFormat,
1498 : const struct tm *poBrokenTime, const char *pszLocale)
1499 : {
1500 : char *pszTemp =
1501 34 : static_cast<char *>(CPLMalloc((nMaxLen + 1) * sizeof(char)));
1502 :
1503 34 : if (pszLocale && EQUAL(pszLocale, "C") &&
1504 34 : strcmp(pszFormat, "%a, %d %b %Y %H:%M:%S GMT") == 0)
1505 : {
1506 : // Particular case when formatting RFC822 datetime, to avoid locale
1507 : // change
1508 : static const char *const aszMonthStr[] = {"Jan", "Feb", "Mar", "Apr",
1509 : "May", "Jun", "Jul", "Aug",
1510 : "Sep", "Oct", "Nov", "Dec"};
1511 : static const char *const aszDayOfWeek[] = {"Sun", "Mon", "Tue", "Wed",
1512 : "Thu", "Fri", "Sat"};
1513 68 : snprintf(pszTemp, nMaxLen + 1, "%s, %02d %s %04d %02d:%02d:%02d GMT",
1514 34 : aszDayOfWeek[std::max(0, std::min(6, poBrokenTime->tm_wday))],
1515 34 : poBrokenTime->tm_mday,
1516 34 : aszMonthStr[std::max(0, std::min(11, poBrokenTime->tm_mon))],
1517 34 : poBrokenTime->tm_year + 1900, poBrokenTime->tm_hour,
1518 68 : poBrokenTime->tm_min, poBrokenTime->tm_sec);
1519 : }
1520 : else
1521 : {
1522 : #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
1523 : char *pszCurLocale = NULL;
1524 :
1525 : if (pszLocale || EQUAL(pszLocale, ""))
1526 : {
1527 : // Save the current locale.
1528 : pszCurLocale = CPLsetlocale(LC_ALL, NULL);
1529 : // Set locale to the specified value.
1530 : CPLsetlocale(LC_ALL, pszLocale);
1531 : }
1532 : #else
1533 : (void)pszLocale;
1534 : #endif
1535 :
1536 0 : if (!strftime(pszTemp, nMaxLen + 1, pszFormat, poBrokenTime))
1537 0 : memset(pszTemp, 0, nMaxLen + 1);
1538 :
1539 : #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
1540 : // Restore stored locale back.
1541 : if (pszCurLocale)
1542 : CPLsetlocale(LC_ALL, pszCurLocale);
1543 : #endif
1544 : }
1545 :
1546 34 : const int nChars = CPLPrintString(pszBuffer, pszTemp, nMaxLen);
1547 :
1548 34 : CPLFree(pszTemp);
1549 :
1550 34 : return nChars;
1551 : }
1552 :
1553 : /************************************************************************/
1554 : /* CPLVerifyConfiguration() */
1555 : /************************************************************************/
1556 :
1557 0 : void CPLVerifyConfiguration()
1558 :
1559 : {
1560 : /* -------------------------------------------------------------------- */
1561 : /* Verify data types. */
1562 : /* -------------------------------------------------------------------- */
1563 : static_assert(sizeof(short) == 2); // We unfortunately rely on this
1564 : static_assert(sizeof(int) == 4); // We unfortunately rely on this
1565 : static_assert(sizeof(float) == 4); // We unfortunately rely on this
1566 : static_assert(sizeof(double) == 8); // We unfortunately rely on this
1567 : static_assert(sizeof(GInt64) == 8);
1568 : static_assert(sizeof(GInt32) == 4);
1569 : static_assert(sizeof(GInt16) == 2);
1570 : static_assert(sizeof(GByte) == 1);
1571 :
1572 : /* -------------------------------------------------------------------- */
1573 : /* Verify byte order */
1574 : /* -------------------------------------------------------------------- */
1575 : #ifdef CPL_LSB
1576 : #if __cplusplus >= 202002L
1577 : static_assert(std::endian::native == std::endian::little);
1578 : #elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
1579 : static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
1580 : #endif
1581 : #elif defined(CPL_MSB)
1582 : #if __cplusplus >= 202002L
1583 : static_assert(std::endian::native == std::endian::big);
1584 : #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
1585 : static_assert(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__);
1586 : #endif
1587 : #else
1588 : #error "CPL_LSB or CPL_MSB must be defined"
1589 : #endif
1590 0 : }
1591 :
1592 : #ifdef DEBUG_CONFIG_OPTIONS
1593 :
1594 : static CPLMutex *hRegisterConfigurationOptionMutex = nullptr;
1595 : static std::set<CPLString> *paoGetKeys = nullptr;
1596 : static std::set<CPLString> *paoSetKeys = nullptr;
1597 :
1598 : /************************************************************************/
1599 : /* CPLShowAccessedOptions() */
1600 : /************************************************************************/
1601 :
1602 : static void CPLShowAccessedOptions()
1603 : {
1604 : std::set<CPLString>::iterator aoIter;
1605 :
1606 : printf("Configuration options accessed in reading : "); /*ok*/
1607 : aoIter = paoGetKeys->begin();
1608 : while (aoIter != paoGetKeys->end())
1609 : {
1610 : printf("%s, ", (*aoIter).c_str()); /*ok*/
1611 : ++aoIter;
1612 : }
1613 : printf("\n"); /*ok*/
1614 :
1615 : printf("Configuration options accessed in writing : "); /*ok*/
1616 : aoIter = paoSetKeys->begin();
1617 : while (aoIter != paoSetKeys->end())
1618 : {
1619 : printf("%s, ", (*aoIter).c_str()); /*ok*/
1620 : ++aoIter;
1621 : }
1622 : printf("\n"); /*ok*/
1623 :
1624 : delete paoGetKeys;
1625 : delete paoSetKeys;
1626 : paoGetKeys = nullptr;
1627 : paoSetKeys = nullptr;
1628 : }
1629 :
1630 : /************************************************************************/
1631 : /* CPLAccessConfigOption() */
1632 : /************************************************************************/
1633 :
1634 : static void CPLAccessConfigOption(const char *pszKey, bool bGet)
1635 : {
1636 : CPLMutexHolderD(&hRegisterConfigurationOptionMutex);
1637 : if (paoGetKeys == nullptr)
1638 : {
1639 : paoGetKeys = new std::set<CPLString>;
1640 : paoSetKeys = new std::set<CPLString>;
1641 : atexit(CPLShowAccessedOptions);
1642 : }
1643 : if (bGet)
1644 : paoGetKeys->insert(pszKey);
1645 : else
1646 : paoSetKeys->insert(pszKey);
1647 : }
1648 : #endif
1649 :
1650 : /************************************************************************/
1651 : /* CPLGetConfigOption() */
1652 : /************************************************************************/
1653 :
1654 : /**
1655 : * Get the value of a configuration option.
1656 : *
1657 : * The value is the value of a (key, value) option set with
1658 : * CPLSetConfigOption(), or CPLSetThreadLocalConfigOption() of the same
1659 : * thread. If the given option was no defined with
1660 : * CPLSetConfigOption(), it tries to find it in environment variables.
1661 : *
1662 : * Note: the string returned by CPLGetConfigOption() might be short-lived, and
1663 : * in particular it will become invalid after a call to CPLSetConfigOption()
1664 : * with the same key.
1665 : *
1666 : * To override temporary a potentially existing option with a new value, you
1667 : * can use the following snippet :
1668 : * \code{.cpp}
1669 : * // backup old value
1670 : * const char* pszOldValTmp = CPLGetConfigOption(pszKey, NULL);
1671 : * char* pszOldVal = pszOldValTmp ? CPLStrdup(pszOldValTmp) : NULL;
1672 : * // override with new value
1673 : * CPLSetConfigOption(pszKey, pszNewVal);
1674 : * // do something useful
1675 : * // restore old value
1676 : * CPLSetConfigOption(pszKey, pszOldVal);
1677 : * CPLFree(pszOldVal);
1678 : * \endcode
1679 : *
1680 : * @param pszKey the key of the option to retrieve
1681 : * @param pszDefault a default value if the key does not match existing defined
1682 : * options (may be NULL)
1683 : * @return the value associated to the key, or the default value if not found
1684 : *
1685 : * @see CPLSetConfigOption(), https://gdal.org/user/configoptions.html
1686 : */
1687 4811680 : const char *CPL_STDCALL CPLGetConfigOption(const char *pszKey,
1688 : const char *pszDefault)
1689 :
1690 : {
1691 4811680 : const char *pszResult = CPLGetThreadLocalConfigOption(pszKey, nullptr);
1692 :
1693 4810870 : if (pszResult == nullptr)
1694 : {
1695 4773370 : pszResult = CPLGetGlobalConfigOption(pszKey, nullptr);
1696 : }
1697 :
1698 4812790 : if (gbIgnoreEnvVariables)
1699 : {
1700 6 : const char *pszEnvVar = getenv(pszKey);
1701 6 : if (pszEnvVar != nullptr)
1702 : {
1703 1 : CPLDebug("CPL",
1704 : "Ignoring environment variable %s=%s because of "
1705 : "ignore-env-vars=yes setting in configuration file",
1706 : pszKey, pszEnvVar);
1707 : }
1708 : }
1709 4812790 : else if (pszResult == nullptr)
1710 : {
1711 4767780 : pszResult = getenv(pszKey);
1712 : }
1713 :
1714 4812770 : if (pszResult == nullptr)
1715 4758760 : return pszDefault;
1716 :
1717 54005 : return pszResult;
1718 : }
1719 :
1720 : /************************************************************************/
1721 : /* CPLGetConfigOptions() */
1722 : /************************************************************************/
1723 :
1724 : /**
1725 : * Return the list of configuration options as KEY=VALUE pairs.
1726 : *
1727 : * The list is the one set through the CPLSetConfigOption() API.
1728 : *
1729 : * Options that through environment variables or with
1730 : * CPLSetThreadLocalConfigOption() will *not* be listed.
1731 : *
1732 : * @return a copy of the list, to be freed with CSLDestroy().
1733 : * @since GDAL 2.2
1734 : */
1735 7 : char **CPLGetConfigOptions(void)
1736 : {
1737 14 : CPLMutexHolderD(&hConfigMutex);
1738 14 : return CSLDuplicate(const_cast<char **>(g_papszConfigOptions));
1739 : }
1740 :
1741 : /************************************************************************/
1742 : /* CPLSetConfigOptions() */
1743 : /************************************************************************/
1744 :
1745 : /**
1746 : * Replace the full list of configuration options with the passed list of
1747 : * KEY=VALUE pairs.
1748 : *
1749 : * This has the same effect of clearing the existing list, and setting
1750 : * individually each pair with the CPLSetConfigOption() API.
1751 : *
1752 : * This does not affect options set through environment variables or with
1753 : * CPLSetThreadLocalConfigOption().
1754 : *
1755 : * The passed list is copied by the function.
1756 : *
1757 : * @param papszConfigOptions the new list (or NULL).
1758 : *
1759 : * @since GDAL 2.2
1760 : */
1761 89 : void CPLSetConfigOptions(const char *const *papszConfigOptions)
1762 : {
1763 89 : CPLMutexHolderD(&hConfigMutex);
1764 89 : CSLDestroy(const_cast<char **>(g_papszConfigOptions));
1765 89 : g_papszConfigOptions = const_cast<volatile char **>(
1766 89 : CSLDuplicate(const_cast<char **>(papszConfigOptions)));
1767 89 : }
1768 :
1769 : /************************************************************************/
1770 : /* CPLGetThreadLocalConfigOption() */
1771 : /************************************************************************/
1772 :
1773 : /** Same as CPLGetConfigOption() but only with options set with
1774 : * CPLSetThreadLocalConfigOption() */
1775 4837700 : const char *CPL_STDCALL CPLGetThreadLocalConfigOption(const char *pszKey,
1776 : const char *pszDefault)
1777 :
1778 : {
1779 : #ifdef DEBUG_CONFIG_OPTIONS
1780 : CPLAccessConfigOption(pszKey, TRUE);
1781 : #endif
1782 :
1783 4837700 : const char *pszResult = nullptr;
1784 :
1785 4837700 : int bMemoryError = FALSE;
1786 : char **papszTLConfigOptions = reinterpret_cast<char **>(
1787 4837700 : CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
1788 4837100 : if (papszTLConfigOptions != nullptr)
1789 4441560 : pszResult = CSLFetchNameValue(papszTLConfigOptions, pszKey);
1790 :
1791 4837170 : if (pszResult == nullptr)
1792 4798990 : return pszDefault;
1793 :
1794 38177 : return pszResult;
1795 : }
1796 :
1797 : /************************************************************************/
1798 : /* CPLGetGlobalConfigOption() */
1799 : /************************************************************************/
1800 :
1801 : /** Same as CPLGetConfigOption() but excludes environment variables and
1802 : * options set with CPLSetThreadLocalConfigOption().
1803 : * This function should generally not be used by applications, which should
1804 : * use CPLGetConfigOption() instead.
1805 : * @since 3.8 */
1806 4775520 : const char *CPL_STDCALL CPLGetGlobalConfigOption(const char *pszKey,
1807 : const char *pszDefault)
1808 : {
1809 : #ifdef DEBUG_CONFIG_OPTIONS
1810 : CPLAccessConfigOption(pszKey, TRUE);
1811 : #endif
1812 :
1813 9552680 : CPLMutexHolderD(&hConfigMutex);
1814 :
1815 : const char *pszResult =
1816 4777150 : CSLFetchNameValue(const_cast<char **>(g_papszConfigOptions), pszKey);
1817 :
1818 4777150 : if (pszResult == nullptr)
1819 4769450 : return pszDefault;
1820 :
1821 7700 : return pszResult;
1822 : }
1823 :
1824 : /************************************************************************/
1825 : /* CPLSubscribeToSetConfigOption() */
1826 : /************************************************************************/
1827 :
1828 : /**
1829 : * Install a callback that will be notified of calls to CPLSetConfigOption()/
1830 : * CPLSetThreadLocalConfigOption()
1831 : *
1832 : * @param pfnCallback Callback. Must not be NULL
1833 : * @param pUserData Callback user data. May be NULL.
1834 : * @return subscriber ID that can be used with CPLUnsubscribeToSetConfigOption()
1835 : * @since GDAL 3.7
1836 : */
1837 :
1838 1192 : int CPLSubscribeToSetConfigOption(CPLSetConfigOptionSubscriber pfnCallback,
1839 : void *pUserData)
1840 : {
1841 2384 : CPLMutexHolderD(&hConfigMutex);
1842 1197 : for (int nId = 0;
1843 1197 : nId < static_cast<int>(gSetConfigOptionSubscribers.size()); ++nId)
1844 : {
1845 6 : if (!gSetConfigOptionSubscribers[nId].first)
1846 : {
1847 1 : gSetConfigOptionSubscribers[nId].first = pfnCallback;
1848 1 : gSetConfigOptionSubscribers[nId].second = pUserData;
1849 1 : return nId;
1850 : }
1851 : }
1852 1191 : int nId = static_cast<int>(gSetConfigOptionSubscribers.size());
1853 1191 : gSetConfigOptionSubscribers.push_back(
1854 1191 : std::pair<CPLSetConfigOptionSubscriber, void *>(pfnCallback,
1855 : pUserData));
1856 1191 : return nId;
1857 : }
1858 :
1859 : /************************************************************************/
1860 : /* CPLUnsubscribeToSetConfigOption() */
1861 : /************************************************************************/
1862 :
1863 : /**
1864 : * Remove a subscriber installed with CPLSubscribeToSetConfigOption()
1865 : *
1866 : * @param nId Subscriber id returned by CPLSubscribeToSetConfigOption()
1867 : * @since GDAL 3.7
1868 : */
1869 :
1870 4 : void CPLUnsubscribeToSetConfigOption(int nId)
1871 : {
1872 8 : CPLMutexHolderD(&hConfigMutex);
1873 4 : if (nId == static_cast<int>(gSetConfigOptionSubscribers.size()) - 1)
1874 : {
1875 3 : gSetConfigOptionSubscribers.resize(gSetConfigOptionSubscribers.size() -
1876 : 1);
1877 : }
1878 2 : else if (nId >= 0 &&
1879 1 : nId < static_cast<int>(gSetConfigOptionSubscribers.size()))
1880 : {
1881 1 : gSetConfigOptionSubscribers[nId].first = nullptr;
1882 : }
1883 4 : }
1884 :
1885 : /************************************************************************/
1886 : /* NotifyOtherComponentsConfigOptionChanged() */
1887 : /************************************************************************/
1888 :
1889 61908 : static void NotifyOtherComponentsConfigOptionChanged(const char *pszKey,
1890 : const char *pszValue,
1891 : bool bThreadLocal)
1892 : {
1893 : // When changing authentication parameters of virtual file systems,
1894 : // partially invalidate cached state about file availability.
1895 61908 : if (STARTS_WITH_CI(pszKey, "AWS_") || STARTS_WITH_CI(pszKey, "GS_") ||
1896 59260 : STARTS_WITH_CI(pszKey, "GOOGLE_") ||
1897 59221 : STARTS_WITH_CI(pszKey, "GDAL_HTTP_HEADER_FILE") ||
1898 59181 : STARTS_WITH_CI(pszKey, "AZURE_") ||
1899 59034 : (STARTS_WITH_CI(pszKey, "SWIFT_") && !EQUAL(pszKey, "SWIFT_MAX_KEYS")))
1900 : {
1901 2978 : VSICurlAuthParametersChanged();
1902 : }
1903 :
1904 61869 : if (!gSetConfigOptionSubscribers.empty())
1905 : {
1906 122612 : for (const auto &iter : gSetConfigOptionSubscribers)
1907 : {
1908 61379 : if (iter.first)
1909 61420 : iter.first(pszKey, pszValue, bThreadLocal, iter.second);
1910 : }
1911 : }
1912 61741 : }
1913 :
1914 : /************************************************************************/
1915 : /* CPLIsDebugEnabled() */
1916 : /************************************************************************/
1917 :
1918 : static int gnDebug = -1;
1919 :
1920 : /** Returns whether CPL_DEBUG is enabled.
1921 : *
1922 : * @since 3.11
1923 : */
1924 67250 : bool CPLIsDebugEnabled()
1925 : {
1926 67250 : if (gnDebug < 0)
1927 : {
1928 : // Check that apszKnownConfigOptions is correctly sorted with
1929 : // STRCASECMP() criterion.
1930 453784 : for (size_t i = 1; i < CPL_ARRAYSIZE(apszKnownConfigOptions); ++i)
1931 : {
1932 453351 : if (STRCASECMP(apszKnownConfigOptions[i - 1],
1933 : apszKnownConfigOptions[i]) >= 0)
1934 : {
1935 0 : CPLError(CE_Failure, CPLE_AppDefined,
1936 : "ERROR: apszKnownConfigOptions[] isn't correctly "
1937 : "sorted: %s >= %s",
1938 0 : apszKnownConfigOptions[i - 1],
1939 0 : apszKnownConfigOptions[i]);
1940 : }
1941 : }
1942 433 : gnDebug = CPLTestBool(CPLGetConfigOption("CPL_DEBUG", "OFF"));
1943 : }
1944 :
1945 67228 : return gnDebug != 0;
1946 : }
1947 :
1948 : /************************************************************************/
1949 : /* CPLDeclareKnownConfigOption() */
1950 : /************************************************************************/
1951 :
1952 : static std::mutex goMutexDeclaredKnownConfigOptions;
1953 : static std::set<CPLString> goSetKnownConfigOptions;
1954 :
1955 : /** Declare that the specified configuration option is known.
1956 : *
1957 : * This is useful to avoid a warning to be emitted on unknown configuration
1958 : * options when CPL_DEBUG is enabled.
1959 : *
1960 : * @param pszKey Name of the configuration option to declare.
1961 : * @param pszDefinition Unused for now. Must be set to nullptr.
1962 : * @since 3.11
1963 : */
1964 1 : void CPLDeclareKnownConfigOption(const char *pszKey,
1965 : [[maybe_unused]] const char *pszDefinition)
1966 : {
1967 1 : std::lock_guard oLock(goMutexDeclaredKnownConfigOptions);
1968 1 : goSetKnownConfigOptions.insert(CPLString(pszKey).toupper());
1969 1 : }
1970 :
1971 : /************************************************************************/
1972 : /* CPLGetKnownConfigOptions() */
1973 : /************************************************************************/
1974 :
1975 : /** Return the list of known configuration options.
1976 : *
1977 : * Must be freed with CSLDestroy().
1978 : * @since 3.11
1979 : */
1980 3 : char **CPLGetKnownConfigOptions()
1981 : {
1982 6 : std::lock_guard oLock(goMutexDeclaredKnownConfigOptions);
1983 6 : CPLStringList aosList;
1984 3147 : for (const char *pszKey : apszKnownConfigOptions)
1985 3144 : aosList.AddString(pszKey);
1986 4 : for (const auto &osKey : goSetKnownConfigOptions)
1987 1 : aosList.AddString(osKey);
1988 6 : return aosList.StealList();
1989 : }
1990 :
1991 : /************************************************************************/
1992 : /* CPLSetConfigOptionDetectUnknownConfigOption() */
1993 : /************************************************************************/
1994 :
1995 61926 : static void CPLSetConfigOptionDetectUnknownConfigOption(const char *pszKey,
1996 : const char *pszValue)
1997 : {
1998 61926 : if (EQUAL(pszKey, "CPL_DEBUG"))
1999 : {
2000 100 : gnDebug = pszValue ? CPLTestBool(pszValue) : false;
2001 : }
2002 61826 : else if (CPLIsDebugEnabled())
2003 : {
2004 89 : if (!std::binary_search(std::begin(apszKnownConfigOptions),
2005 : std::end(apszKnownConfigOptions), pszKey,
2006 979 : [](const char *a, const char *b)
2007 979 : { return STRCASECMP(a, b) < 0; }))
2008 : {
2009 : bool bFound;
2010 : {
2011 4 : std::lock_guard oLock(goMutexDeclaredKnownConfigOptions);
2012 8 : bFound = cpl::contains(goSetKnownConfigOptions,
2013 4 : CPLString(pszKey).toupper());
2014 : }
2015 4 : if (!bFound)
2016 : {
2017 2 : const char *pszOldValue = CPLGetConfigOption(pszKey, nullptr);
2018 2 : if (!((!pszValue && !pszOldValue) ||
2019 1 : (pszValue && pszOldValue &&
2020 0 : EQUAL(pszValue, pszOldValue))))
2021 : {
2022 2 : CPLError(CE_Warning, CPLE_AppDefined,
2023 : "Unknown configuration option '%s'.", pszKey);
2024 : }
2025 : }
2026 : }
2027 : }
2028 61915 : }
2029 :
2030 : /************************************************************************/
2031 : /* CPLSetConfigOption() */
2032 : /************************************************************************/
2033 :
2034 : /**
2035 : * Set a configuration option for GDAL/OGR use.
2036 : *
2037 : * Those options are defined as a (key, value) couple. The value corresponding
2038 : * to a key can be got later with the CPLGetConfigOption() method.
2039 : *
2040 : * This mechanism is similar to environment variables, but options set with
2041 : * CPLSetConfigOption() overrides, for CPLGetConfigOption() point of view,
2042 : * values defined in the environment.
2043 : *
2044 : * If CPLSetConfigOption() is called several times with the same key, the
2045 : * value provided during the last call will be used.
2046 : *
2047 : * Options can also be passed on the command line of most GDAL utilities
2048 : * with '\--config KEY VALUE' (or '\--config KEY=VALUE' since GDAL 3.10).
2049 : * For example, ogrinfo \--config CPL_DEBUG ON ~/data/test/point.shp
2050 : *
2051 : * This function can also be used to clear a setting by passing NULL as the
2052 : * value (note: passing NULL will not unset an existing environment variable;
2053 : * it will just unset a value previously set by CPLSetConfigOption()).
2054 : *
2055 : * Starting with GDAL 3.11, if CPL_DEBUG is enabled prior to this call, and
2056 : * CPLSetConfigOption() is called with a key that is neither a known
2057 : * configuration option of GDAL itself, or one that has been declared with
2058 : * CPLDeclareKnownConfigOption(), a warning will be emitted.
2059 : *
2060 : * @param pszKey the key of the option
2061 : * @param pszValue the value of the option, or NULL to clear a setting.
2062 : *
2063 : * @see https://gdal.org/user/configoptions.html
2064 : */
2065 4656 : void CPL_STDCALL CPLSetConfigOption(const char *pszKey, const char *pszValue)
2066 :
2067 : {
2068 : #ifdef DEBUG_CONFIG_OPTIONS
2069 : CPLAccessConfigOption(pszKey, FALSE);
2070 : #endif
2071 9312 : CPLMutexHolderD(&hConfigMutex);
2072 :
2073 : #ifdef OGRAPISPY_ENABLED
2074 4656 : OGRAPISPYCPLSetConfigOption(pszKey, pszValue);
2075 : #endif
2076 :
2077 4656 : CPLSetConfigOptionDetectUnknownConfigOption(pszKey, pszValue);
2078 :
2079 4656 : g_papszConfigOptions = const_cast<volatile char **>(CSLSetNameValue(
2080 : const_cast<char **>(g_papszConfigOptions), pszKey, pszValue));
2081 :
2082 4656 : NotifyOtherComponentsConfigOptionChanged(pszKey, pszValue,
2083 : /*bTheadLocal=*/false);
2084 4656 : }
2085 :
2086 : /************************************************************************/
2087 : /* CPLSetThreadLocalTLSFreeFunc() */
2088 : /************************************************************************/
2089 :
2090 : /* non-stdcall wrapper function for CSLDestroy() (#5590) */
2091 7 : static void CPLSetThreadLocalTLSFreeFunc(void *pData)
2092 : {
2093 7 : CSLDestroy(reinterpret_cast<char **>(pData));
2094 7 : }
2095 :
2096 : /************************************************************************/
2097 : /* CPLSetThreadLocalConfigOption() */
2098 : /************************************************************************/
2099 :
2100 : /**
2101 : * Set a configuration option for GDAL/OGR use.
2102 : *
2103 : * Those options are defined as a (key, value) couple. The value corresponding
2104 : * to a key can be got later with the CPLGetConfigOption() method.
2105 : *
2106 : * This function sets the configuration option that only applies in the
2107 : * current thread, as opposed to CPLSetConfigOption() which sets an option
2108 : * that applies on all threads. CPLSetThreadLocalConfigOption() will override
2109 : * the effect of CPLSetConfigOption) for the current thread.
2110 : *
2111 : * This function can also be used to clear a setting by passing NULL as the
2112 : * value (note: passing NULL will not unset an existing environment variable or
2113 : * a value set through CPLSetConfigOption();
2114 : * it will just unset a value previously set by
2115 : * CPLSetThreadLocalConfigOption()).
2116 : *
2117 : * @param pszKey the key of the option
2118 : * @param pszValue the value of the option, or NULL to clear a setting.
2119 : */
2120 :
2121 57312 : void CPL_STDCALL CPLSetThreadLocalConfigOption(const char *pszKey,
2122 : const char *pszValue)
2123 :
2124 : {
2125 : #ifdef DEBUG_CONFIG_OPTIONS
2126 : CPLAccessConfigOption(pszKey, FALSE);
2127 : #endif
2128 :
2129 : #ifdef OGRAPISPY_ENABLED
2130 57312 : OGRAPISPYCPLSetThreadLocalConfigOption(pszKey, pszValue);
2131 : #endif
2132 :
2133 57266 : int bMemoryError = FALSE;
2134 : char **papszTLConfigOptions = reinterpret_cast<char **>(
2135 57266 : CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
2136 57264 : if (bMemoryError)
2137 0 : return;
2138 :
2139 57264 : CPLSetConfigOptionDetectUnknownConfigOption(pszKey, pszValue);
2140 :
2141 : papszTLConfigOptions =
2142 57251 : CSLSetNameValue(papszTLConfigOptions, pszKey, pszValue);
2143 :
2144 57228 : CPLSetTLSWithFreeFunc(CTLS_CONFIGOPTIONS, papszTLConfigOptions,
2145 : CPLSetThreadLocalTLSFreeFunc);
2146 :
2147 57134 : NotifyOtherComponentsConfigOptionChanged(pszKey, pszValue,
2148 : /*bTheadLocal=*/true);
2149 : }
2150 :
2151 : /************************************************************************/
2152 : /* CPLGetThreadLocalConfigOptions() */
2153 : /************************************************************************/
2154 :
2155 : /**
2156 : * Return the list of thread local configuration options as KEY=VALUE pairs.
2157 : *
2158 : * Options that through environment variables or with
2159 : * CPLSetConfigOption() will *not* be listed.
2160 : *
2161 : * @return a copy of the list, to be freed with CSLDestroy().
2162 : * @since GDAL 2.2
2163 : */
2164 707858 : char **CPLGetThreadLocalConfigOptions(void)
2165 : {
2166 707858 : int bMemoryError = FALSE;
2167 : char **papszTLConfigOptions = reinterpret_cast<char **>(
2168 707858 : CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
2169 676455 : if (bMemoryError)
2170 0 : return nullptr;
2171 676455 : return CSLDuplicate(papszTLConfigOptions);
2172 : }
2173 :
2174 : /************************************************************************/
2175 : /* CPLSetThreadLocalConfigOptions() */
2176 : /************************************************************************/
2177 :
2178 : /**
2179 : * Replace the full list of thread local configuration options with the
2180 : * passed list of KEY=VALUE pairs.
2181 : *
2182 : * This has the same effect of clearing the existing list, and setting
2183 : * individually each pair with the CPLSetThreadLocalConfigOption() API.
2184 : *
2185 : * This does not affect options set through environment variables or with
2186 : * CPLSetConfigOption().
2187 : *
2188 : * The passed list is copied by the function.
2189 : *
2190 : * @param papszConfigOptions the new list (or NULL).
2191 : *
2192 : * @since GDAL 2.2
2193 : */
2194 1358470 : void CPLSetThreadLocalConfigOptions(const char *const *papszConfigOptions)
2195 : {
2196 1358470 : int bMemoryError = FALSE;
2197 : char **papszTLConfigOptions = reinterpret_cast<char **>(
2198 1358470 : CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
2199 1322060 : if (bMemoryError)
2200 0 : return;
2201 1322060 : CSLDestroy(papszTLConfigOptions);
2202 : papszTLConfigOptions =
2203 1301760 : CSLDuplicate(const_cast<char **>(papszConfigOptions));
2204 1350680 : CPLSetTLSWithFreeFunc(CTLS_CONFIGOPTIONS, papszTLConfigOptions,
2205 : CPLSetThreadLocalTLSFreeFunc);
2206 : }
2207 :
2208 : /************************************************************************/
2209 : /* CPLFreeConfig() */
2210 : /************************************************************************/
2211 :
2212 1342 : void CPL_STDCALL CPLFreeConfig()
2213 :
2214 : {
2215 : {
2216 2684 : CPLMutexHolderD(&hConfigMutex);
2217 :
2218 1342 : CSLDestroy(const_cast<char **>(g_papszConfigOptions));
2219 1342 : g_papszConfigOptions = nullptr;
2220 :
2221 1342 : int bMemoryError = FALSE;
2222 : char **papszTLConfigOptions = reinterpret_cast<char **>(
2223 1342 : CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
2224 1342 : if (papszTLConfigOptions != nullptr)
2225 : {
2226 201 : CSLDestroy(papszTLConfigOptions);
2227 201 : CPLSetTLS(CTLS_CONFIGOPTIONS, nullptr, FALSE);
2228 : }
2229 : }
2230 1342 : CPLDestroyMutex(hConfigMutex);
2231 1342 : hConfigMutex = nullptr;
2232 1342 : }
2233 :
2234 : /************************************************************************/
2235 : /* CPLLoadConfigOptionsFromFile() */
2236 : /************************************************************************/
2237 :
2238 : /** Load configuration from a given configuration file.
2239 :
2240 : A configuration file is a text file in a .ini style format, that lists
2241 : configuration options and their values.
2242 : Lines starting with # are comment lines.
2243 :
2244 : Example:
2245 : \verbatim
2246 : [configoptions]
2247 : # set BAR as the value of configuration option FOO
2248 : FOO=BAR
2249 : \endverbatim
2250 :
2251 : Starting with GDAL 3.5, a configuration file can also contain credentials
2252 : (or more generally options related to a virtual file system) for a given path
2253 : prefix, that can also be set with VSISetPathSpecificOption(). Credentials should
2254 : be put under a [credentials] section, and for each path prefix, under a relative
2255 : subsection whose name starts with "[." (e.g. "[.some_arbitrary_name]"), and
2256 : whose first key is "path".
2257 :
2258 : Example:
2259 : \verbatim
2260 : [credentials]
2261 :
2262 : [.private_bucket]
2263 : path=/vsis3/my_private_bucket
2264 : AWS_SECRET_ACCESS_KEY=...
2265 : AWS_ACCESS_KEY_ID=...
2266 :
2267 : [.sentinel_s2_l1c]
2268 : path=/vsis3/sentinel-s2-l1c
2269 : AWS_REQUEST_PAYER=requester
2270 : \endverbatim
2271 :
2272 : Starting with GDAL 3.6, a leading [directives] section might be added with
2273 : a "ignore-env-vars=yes" setting to indicate that, starting with that point,
2274 : all environment variables should be ignored, and only configuration options
2275 : defined in the [configoptions] sections or through the CPLSetConfigOption() /
2276 : CPLSetThreadLocalConfigOption() functions should be taken into account.
2277 :
2278 : This function is typically called by CPLLoadConfigOptionsFromPredefinedFiles()
2279 :
2280 : @param pszFilename File where to load configuration from.
2281 : @param bOverrideEnvVars Whether configuration options from the configuration
2282 : file should override environment variables.
2283 : @since GDAL 3.3
2284 : */
2285 2784 : void CPLLoadConfigOptionsFromFile(const char *pszFilename, int bOverrideEnvVars)
2286 : {
2287 2784 : VSILFILE *fp = VSIFOpenL(pszFilename, "rb");
2288 2784 : if (fp == nullptr)
2289 2775 : return;
2290 9 : CPLDebug("CPL", "Loading configuration from %s", pszFilename);
2291 : const char *pszLine;
2292 : enum class Section
2293 : {
2294 : NONE,
2295 : GENERAL,
2296 : CONFIG_OPTIONS,
2297 : CREDENTIALS,
2298 : };
2299 9 : Section eCurrentSection = Section::NONE;
2300 9 : bool bInSubsection = false;
2301 18 : std::string osPath;
2302 9 : int nSectionCounter = 0;
2303 :
2304 56 : const auto IsSpaceOnly = [](const char *pszStr)
2305 : {
2306 56 : for (; *pszStr; ++pszStr)
2307 : {
2308 47 : if (!isspace(static_cast<unsigned char>(*pszStr)))
2309 41 : return false;
2310 : }
2311 9 : return true;
2312 : };
2313 :
2314 59 : while ((pszLine = CPLReadLine2L(fp, -1, nullptr)) != nullptr)
2315 : {
2316 50 : if (IsSpaceOnly(pszLine))
2317 : {
2318 : // Blank line
2319 : }
2320 41 : else if (pszLine[0] == '#')
2321 : {
2322 : // Comment line
2323 : }
2324 35 : else if (strcmp(pszLine, "[configoptions]") == 0)
2325 : {
2326 6 : nSectionCounter++;
2327 6 : eCurrentSection = Section::CONFIG_OPTIONS;
2328 : }
2329 29 : else if (strcmp(pszLine, "[credentials]") == 0)
2330 : {
2331 4 : nSectionCounter++;
2332 4 : eCurrentSection = Section::CREDENTIALS;
2333 4 : bInSubsection = false;
2334 4 : osPath.clear();
2335 : }
2336 25 : else if (strcmp(pszLine, "[directives]") == 0)
2337 : {
2338 2 : nSectionCounter++;
2339 2 : if (nSectionCounter != 1)
2340 : {
2341 0 : CPLError(CE_Warning, CPLE_AppDefined,
2342 : "The [directives] section should be the first one in "
2343 : "the file, otherwise some its settings might not be "
2344 : "used correctly.");
2345 : }
2346 2 : eCurrentSection = Section::GENERAL;
2347 : }
2348 23 : else if (eCurrentSection == Section::GENERAL)
2349 : {
2350 2 : char *pszKey = nullptr;
2351 2 : const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
2352 2 : if (pszKey && pszValue)
2353 : {
2354 2 : if (strcmp(pszKey, "ignore-env-vars") == 0)
2355 : {
2356 2 : gbIgnoreEnvVariables = CPLTestBool(pszValue);
2357 : }
2358 : else
2359 : {
2360 0 : CPLError(CE_Warning, CPLE_AppDefined,
2361 : "Ignoring %s line in [directives] section",
2362 : pszLine);
2363 : }
2364 : }
2365 2 : CPLFree(pszKey);
2366 : }
2367 21 : else if (eCurrentSection == Section::CREDENTIALS)
2368 : {
2369 15 : if (strncmp(pszLine, "[.", 2) == 0)
2370 : {
2371 4 : bInSubsection = true;
2372 4 : osPath.clear();
2373 : }
2374 11 : else if (bInSubsection)
2375 : {
2376 10 : char *pszKey = nullptr;
2377 10 : const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
2378 10 : if (pszKey && pszValue)
2379 : {
2380 10 : if (strcmp(pszKey, "path") == 0)
2381 : {
2382 4 : if (!osPath.empty())
2383 : {
2384 1 : CPLError(
2385 : CE_Warning, CPLE_AppDefined,
2386 : "Duplicated 'path' key in the same subsection. "
2387 : "Ignoring %s=%s",
2388 : pszKey, pszValue);
2389 : }
2390 : else
2391 : {
2392 3 : osPath = pszValue;
2393 : }
2394 : }
2395 6 : else if (osPath.empty())
2396 : {
2397 1 : CPLError(CE_Warning, CPLE_AppDefined,
2398 : "First entry in a credentials subsection "
2399 : "should be 'path'.");
2400 : }
2401 : else
2402 : {
2403 5 : VSISetPathSpecificOption(osPath.c_str(), pszKey,
2404 : pszValue);
2405 : }
2406 : }
2407 10 : CPLFree(pszKey);
2408 : }
2409 1 : else if (pszLine[0] == '[')
2410 : {
2411 0 : eCurrentSection = Section::NONE;
2412 : }
2413 : else
2414 : {
2415 1 : CPLError(CE_Warning, CPLE_AppDefined,
2416 : "Ignoring content in [credential] section that is not "
2417 : "in a [.xxxxx] subsection");
2418 : }
2419 : }
2420 6 : else if (pszLine[0] == '[')
2421 : {
2422 0 : eCurrentSection = Section::NONE;
2423 : }
2424 6 : else if (eCurrentSection == Section::CONFIG_OPTIONS)
2425 : {
2426 6 : char *pszKey = nullptr;
2427 6 : const char *pszValue = CPLParseNameValue(pszLine, &pszKey);
2428 6 : if (pszKey && pszValue)
2429 : {
2430 11 : if (bOverrideEnvVars || gbIgnoreEnvVariables ||
2431 5 : getenv(pszKey) == nullptr)
2432 : {
2433 5 : CPLDebugOnly("CPL", "Setting configuration option %s=%s",
2434 : pszKey, pszValue);
2435 5 : CPLSetConfigOption(pszKey, pszValue);
2436 : }
2437 : else
2438 : {
2439 1 : CPLDebug("CPL",
2440 : "Ignoring configuration option %s=%s from "
2441 : "configuration file as it is already set "
2442 : "as an environment variable",
2443 : pszKey, pszValue);
2444 : }
2445 : }
2446 6 : CPLFree(pszKey);
2447 : }
2448 : }
2449 9 : VSIFCloseL(fp);
2450 : }
2451 :
2452 : /************************************************************************/
2453 : /* CPLLoadConfigOptionsFromPredefinedFiles() */
2454 : /************************************************************************/
2455 :
2456 : /** Load configuration from a set of predefined files.
2457 : *
2458 : * If the environment variable (or configuration option) GDAL_CONFIG_FILE is
2459 : * set, then CPLLoadConfigOptionsFromFile() will be called with the value of
2460 : * this configuration option as the file location.
2461 : *
2462 : * Otherwise, for Unix builds, CPLLoadConfigOptionsFromFile() will be called
2463 : * with ${sysconfdir}/gdal/gdalrc first where ${sysconfdir} evaluates
2464 : * to ${prefix}/etc, unless the \--sysconfdir switch of configure has been
2465 : * invoked.
2466 : *
2467 : * Then CPLLoadConfigOptionsFromFile() will be called with $(HOME)/.gdal/gdalrc
2468 : * on Unix builds (potentially overriding what was loaded with the sysconfdir)
2469 : * or $(USERPROFILE)/.gdal/gdalrc on Windows builds.
2470 : *
2471 : * CPLLoadConfigOptionsFromFile() will be called with bOverrideEnvVars = false,
2472 : * that is the value of environment variables previously set will be used
2473 : * instead of the value set in the configuration files (unless the configuration
2474 : * file contains a leading [directives] section with a "ignore-env-vars=yes"
2475 : * setting).
2476 : *
2477 : * This function is automatically called by GDALDriverManager() constructor
2478 : *
2479 : * @since GDAL 3.3
2480 : */
2481 1389 : void CPLLoadConfigOptionsFromPredefinedFiles()
2482 : {
2483 1389 : const char *pszFile = CPLGetConfigOption("GDAL_CONFIG_FILE", nullptr);
2484 1389 : if (pszFile != nullptr)
2485 : {
2486 2 : CPLLoadConfigOptionsFromFile(pszFile, false);
2487 : }
2488 : else
2489 : {
2490 : #ifdef SYSCONFDIR
2491 1387 : CPLLoadConfigOptionsFromFile(
2492 2774 : CPLFormFilenameSafe(
2493 2774 : CPLFormFilenameSafe(SYSCONFDIR, "gdal", nullptr).c_str(),
2494 : "gdalrc", nullptr)
2495 : .c_str(),
2496 : false);
2497 : #endif
2498 :
2499 : #ifdef _WIN32
2500 : const char *pszHome = CPLGetConfigOption("USERPROFILE", nullptr);
2501 : #else
2502 1387 : const char *pszHome = CPLGetConfigOption("HOME", nullptr);
2503 : #endif
2504 1387 : if (pszHome != nullptr)
2505 : {
2506 1387 : CPLLoadConfigOptionsFromFile(
2507 2774 : CPLFormFilenameSafe(
2508 2774 : CPLFormFilenameSafe(pszHome, ".gdal", nullptr).c_str(),
2509 : "gdalrc", nullptr)
2510 : .c_str(),
2511 : false);
2512 : }
2513 : }
2514 1389 : }
2515 :
2516 : /************************************************************************/
2517 : /* CPLStat() */
2518 : /************************************************************************/
2519 :
2520 : /** Same as VSIStat() except it works on "C:" as if it were "C:\". */
2521 :
2522 0 : int CPLStat(const char *pszPath, VSIStatBuf *psStatBuf)
2523 :
2524 : {
2525 0 : if (strlen(pszPath) == 2 && pszPath[1] == ':')
2526 : {
2527 0 : char szAltPath[4] = {pszPath[0], pszPath[1], '\\', '\0'};
2528 0 : return VSIStat(szAltPath, psStatBuf);
2529 : }
2530 :
2531 0 : return VSIStat(pszPath, psStatBuf);
2532 : }
2533 :
2534 : /************************************************************************/
2535 : /* proj_strtod() */
2536 : /************************************************************************/
2537 18 : static double proj_strtod(char *nptr, char **endptr)
2538 :
2539 : {
2540 18 : char c = '\0';
2541 18 : char *cp = nptr;
2542 :
2543 : // Scan for characters which cause problems with VC++ strtod().
2544 84 : while ((c = *cp) != '\0')
2545 : {
2546 72 : if (c == 'd' || c == 'D')
2547 : {
2548 : // Found one, so NUL it out, call strtod(),
2549 : // then restore it and return.
2550 6 : *cp = '\0';
2551 6 : const double result = CPLStrtod(nptr, endptr);
2552 6 : *cp = c;
2553 6 : return result;
2554 : }
2555 66 : ++cp;
2556 : }
2557 :
2558 : // No offending characters, just handle normally.
2559 :
2560 12 : return CPLStrtod(nptr, endptr);
2561 : }
2562 :
2563 : /************************************************************************/
2564 : /* CPLDMSToDec() */
2565 : /************************************************************************/
2566 :
2567 : static const char *sym = "NnEeSsWw";
2568 : constexpr double vm[] = {1.0, 0.0166666666667, 0.00027777778};
2569 :
2570 : /** CPLDMSToDec */
2571 6 : double CPLDMSToDec(const char *is)
2572 :
2573 : {
2574 : // Copy string into work space.
2575 6 : while (isspace(static_cast<unsigned char>(*is)))
2576 0 : ++is;
2577 :
2578 6 : const char *p = is;
2579 6 : char work[64] = {};
2580 6 : char *s = work;
2581 6 : int n = sizeof(work);
2582 60 : for (; isgraph(*p) && --n;)
2583 54 : *s++ = *p++;
2584 6 : *s = '\0';
2585 : // It is possible that a really odd input (like lots of leading
2586 : // zeros) could be truncated in copying into work. But...
2587 6 : s = work;
2588 6 : int sign = *s;
2589 :
2590 6 : if (sign == '+' || sign == '-')
2591 0 : s++;
2592 : else
2593 6 : sign = '+';
2594 :
2595 6 : int nl = 0;
2596 6 : double v = 0.0;
2597 24 : for (; nl < 3; nl = n + 1)
2598 : {
2599 18 : if (!(isdigit(static_cast<unsigned char>(*s)) || *s == '.'))
2600 0 : break;
2601 18 : const double tv = proj_strtod(s, &s);
2602 18 : if (tv == HUGE_VAL)
2603 0 : return tv;
2604 18 : switch (*s)
2605 : {
2606 6 : case 'D':
2607 : case 'd':
2608 6 : n = 0;
2609 6 : break;
2610 6 : case '\'':
2611 6 : n = 1;
2612 6 : break;
2613 6 : case '"':
2614 6 : n = 2;
2615 6 : break;
2616 0 : case 'r':
2617 : case 'R':
2618 0 : if (nl)
2619 : {
2620 0 : return 0.0;
2621 : }
2622 0 : ++s;
2623 0 : v = tv;
2624 0 : goto skip;
2625 0 : default:
2626 0 : v += tv * vm[nl];
2627 0 : skip:
2628 0 : n = 4;
2629 0 : continue;
2630 : }
2631 18 : if (n < nl)
2632 : {
2633 0 : return 0.0;
2634 : }
2635 18 : v += tv * vm[n];
2636 18 : ++s;
2637 : }
2638 : // Postfix sign.
2639 6 : if (*s && ((p = strchr(sym, *s))) != nullptr)
2640 : {
2641 0 : sign = (p - sym) >= 4 ? '-' : '+';
2642 0 : ++s;
2643 : }
2644 6 : if (sign == '-')
2645 0 : v = -v;
2646 :
2647 6 : return v;
2648 : }
2649 :
2650 : /************************************************************************/
2651 : /* CPLDecToDMS() */
2652 : /************************************************************************/
2653 :
2654 : /** Translate a decimal degrees value to a DMS string with hemisphere. */
2655 :
2656 550 : const char *CPLDecToDMS(double dfAngle, const char *pszAxis, int nPrecision)
2657 :
2658 : {
2659 550 : VALIDATE_POINTER1(pszAxis, "CPLDecToDMS", "");
2660 :
2661 550 : if (std::isnan(dfAngle))
2662 0 : return "Invalid angle";
2663 :
2664 550 : const double dfEpsilon = (0.5 / 3600.0) * pow(0.1, nPrecision);
2665 550 : const double dfABSAngle = std::abs(dfAngle) + dfEpsilon;
2666 550 : if (dfABSAngle > 361.0)
2667 : {
2668 0 : return "Invalid angle";
2669 : }
2670 :
2671 550 : const int nDegrees = static_cast<int>(dfABSAngle);
2672 550 : const int nMinutes = static_cast<int>((dfABSAngle - nDegrees) * 60);
2673 550 : double dfSeconds = dfABSAngle * 3600 - nDegrees * 3600 - nMinutes * 60;
2674 :
2675 550 : if (dfSeconds > dfEpsilon * 3600.0)
2676 544 : dfSeconds -= dfEpsilon * 3600.0;
2677 :
2678 550 : const char *pszHemisphere = nullptr;
2679 550 : if (EQUAL(pszAxis, "Long") && dfAngle < 0.0)
2680 238 : pszHemisphere = "W";
2681 312 : else if (EQUAL(pszAxis, "Long"))
2682 37 : pszHemisphere = "E";
2683 275 : else if (dfAngle < 0.0)
2684 22 : pszHemisphere = "S";
2685 : else
2686 253 : pszHemisphere = "N";
2687 :
2688 550 : char szFormat[30] = {};
2689 550 : CPLsnprintf(szFormat, sizeof(szFormat), "%%3dd%%2d\'%%%d.%df\"%s",
2690 : nPrecision + 3, nPrecision, pszHemisphere);
2691 :
2692 : static CPL_THREADLOCAL char szBuffer[50] = {};
2693 550 : CPLsnprintf(szBuffer, sizeof(szBuffer), szFormat, nDegrees, nMinutes,
2694 : dfSeconds);
2695 :
2696 550 : return szBuffer;
2697 : }
2698 :
2699 : /************************************************************************/
2700 : /* CPLPackedDMSToDec() */
2701 : /************************************************************************/
2702 :
2703 : /**
2704 : * Convert a packed DMS value (DDDMMMSSS.SS) into decimal degrees.
2705 : *
2706 : * This function converts a packed DMS angle to seconds. The standard
2707 : * packed DMS format is:
2708 : *
2709 : * degrees * 1000000 + minutes * 1000 + seconds
2710 : *
2711 : * Example: angle = 120025045.25 yields
2712 : * deg = 120
2713 : * min = 25
2714 : * sec = 45.25
2715 : *
2716 : * The algorithm used for the conversion is as follows:
2717 : *
2718 : * 1. The absolute value of the angle is used.
2719 : *
2720 : * 2. The degrees are separated out:
2721 : * deg = angle/1000000 (fractional portion truncated)
2722 : *
2723 : * 3. The minutes are separated out:
2724 : * min = (angle - deg * 1000000) / 1000 (fractional portion truncated)
2725 : *
2726 : * 4. The seconds are then computed:
2727 : * sec = angle - deg * 1000000 - min * 1000
2728 : *
2729 : * 5. The total angle in seconds is computed:
2730 : * sec = deg * 3600.0 + min * 60.0 + sec
2731 : *
2732 : * 6. The sign of sec is set to that of the input angle.
2733 : *
2734 : * Packed DMS values used by the USGS GCTP package and probably by other
2735 : * software.
2736 : *
2737 : * NOTE: This code does not validate input value. If you give the wrong
2738 : * value, you will get the wrong result.
2739 : *
2740 : * @param dfPacked Angle in packed DMS format.
2741 : *
2742 : * @return Angle in decimal degrees.
2743 : *
2744 : */
2745 :
2746 34 : double CPLPackedDMSToDec(double dfPacked)
2747 : {
2748 34 : const double dfSign = dfPacked < 0.0 ? -1 : 1;
2749 :
2750 34 : double dfSeconds = std::abs(dfPacked);
2751 34 : double dfDegrees = floor(dfSeconds / 1000000.0);
2752 34 : dfSeconds -= dfDegrees * 1000000.0;
2753 34 : const double dfMinutes = floor(dfSeconds / 1000.0);
2754 34 : dfSeconds -= dfMinutes * 1000.0;
2755 34 : dfSeconds = dfSign * (dfDegrees * 3600.0 + dfMinutes * 60.0 + dfSeconds);
2756 34 : dfDegrees = dfSeconds / 3600.0;
2757 :
2758 34 : return dfDegrees;
2759 : }
2760 :
2761 : /************************************************************************/
2762 : /* CPLDecToPackedDMS() */
2763 : /************************************************************************/
2764 : /**
2765 : * Convert decimal degrees into packed DMS value (DDDMMMSSS.SS).
2766 : *
2767 : * This function converts a value, specified in decimal degrees into
2768 : * packed DMS angle. The standard packed DMS format is:
2769 : *
2770 : * degrees * 1000000 + minutes * 1000 + seconds
2771 : *
2772 : * See also CPLPackedDMSToDec().
2773 : *
2774 : * @param dfDec Angle in decimal degrees.
2775 : *
2776 : * @return Angle in packed DMS format.
2777 : *
2778 : */
2779 :
2780 8 : double CPLDecToPackedDMS(double dfDec)
2781 : {
2782 8 : const double dfSign = dfDec < 0.0 ? -1 : 1;
2783 :
2784 8 : dfDec = std::abs(dfDec);
2785 8 : const double dfDegrees = floor(dfDec);
2786 8 : const double dfMinutes = floor((dfDec - dfDegrees) * 60.0);
2787 8 : const double dfSeconds = (dfDec - dfDegrees) * 3600.0 - dfMinutes * 60.0;
2788 :
2789 8 : return dfSign * (dfDegrees * 1000000.0 + dfMinutes * 1000.0 + dfSeconds);
2790 : }
2791 :
2792 : /************************************************************************/
2793 : /* CPLStringToComplex() */
2794 : /************************************************************************/
2795 :
2796 : /** Fetch the real and imaginary part of a serialized complex number */
2797 2340 : void CPL_DLL CPLStringToComplex(const char *pszString, double *pdfReal,
2798 : double *pdfImag)
2799 :
2800 : {
2801 2340 : while (*pszString == ' ')
2802 0 : pszString++;
2803 :
2804 2340 : *pdfReal = CPLAtof(pszString);
2805 2340 : *pdfImag = 0.0;
2806 :
2807 2340 : int iPlus = -1;
2808 2340 : int iImagEnd = -1;
2809 :
2810 4790 : for (int i = 0; i < 100 && pszString[i] != '\0' && pszString[i] != ' '; i++)
2811 : {
2812 2450 : if (pszString[i] == '+' && i > 0)
2813 0 : iPlus = i;
2814 2450 : if (pszString[i] == '-' && i > 0)
2815 0 : iPlus = i;
2816 2450 : if (pszString[i] == 'i')
2817 2 : iImagEnd = i;
2818 : }
2819 :
2820 2340 : if (iPlus > -1 && iImagEnd > -1 && iPlus < iImagEnd)
2821 : {
2822 0 : *pdfImag = CPLAtof(pszString + iPlus);
2823 : }
2824 :
2825 2340 : return;
2826 : }
2827 :
2828 : /************************************************************************/
2829 : /* CPLOpenShared() */
2830 : /************************************************************************/
2831 :
2832 : /**
2833 : * Open a shared file handle.
2834 : *
2835 : * Some operating systems have limits on the number of file handles that can
2836 : * be open at one time. This function attempts to maintain a registry of
2837 : * already open file handles, and reuse existing ones if the same file
2838 : * is requested by another part of the application.
2839 : *
2840 : * Note that access is only shared for access types "r", "rb", "r+" and
2841 : * "rb+". All others will just result in direct VSIOpen() calls. Keep in
2842 : * mind that a file is only reused if the file name is exactly the same.
2843 : * Different names referring to the same file will result in different
2844 : * handles.
2845 : *
2846 : * The VSIFOpen() or VSIFOpenL() function is used to actually open the file,
2847 : * when an existing file handle can't be shared.
2848 : *
2849 : * @param pszFilename the name of the file to open.
2850 : * @param pszAccess the normal fopen()/VSIFOpen() style access string.
2851 : * @param bLargeIn If TRUE VSIFOpenL() (for large files) will be used instead of
2852 : * VSIFOpen().
2853 : *
2854 : * @return a file handle or NULL if opening fails.
2855 : */
2856 :
2857 35 : FILE *CPLOpenShared(const char *pszFilename, const char *pszAccess,
2858 : int bLargeIn)
2859 :
2860 : {
2861 35 : const bool bLarge = CPL_TO_BOOL(bLargeIn);
2862 70 : CPLMutexHolderD(&hSharedFileMutex);
2863 35 : const GIntBig nPID = CPLGetPID();
2864 :
2865 : /* -------------------------------------------------------------------- */
2866 : /* Is there an existing file we can use? */
2867 : /* -------------------------------------------------------------------- */
2868 35 : const bool bReuse = EQUAL(pszAccess, "rb") || EQUAL(pszAccess, "rb+");
2869 :
2870 39 : for (int i = 0; bReuse && i < nSharedFileCount; i++)
2871 : {
2872 20 : if (strcmp(pasSharedFileList[i].pszFilename, pszFilename) == 0 &&
2873 4 : !bLarge == !pasSharedFileList[i].bLarge &&
2874 16 : EQUAL(pasSharedFileList[i].pszAccess, pszAccess) &&
2875 4 : nPID == pasSharedFileListExtra[i].nPID)
2876 : {
2877 4 : pasSharedFileList[i].nRefCount++;
2878 4 : return pasSharedFileList[i].fp;
2879 : }
2880 : }
2881 :
2882 : /* -------------------------------------------------------------------- */
2883 : /* Open the file. */
2884 : /* -------------------------------------------------------------------- */
2885 : FILE *fp = bLarge
2886 31 : ? reinterpret_cast<FILE *>(VSIFOpenL(pszFilename, pszAccess))
2887 0 : : VSIFOpen(pszFilename, pszAccess);
2888 :
2889 31 : if (fp == nullptr)
2890 8 : return nullptr;
2891 :
2892 : /* -------------------------------------------------------------------- */
2893 : /* Add an entry to the list. */
2894 : /* -------------------------------------------------------------------- */
2895 23 : nSharedFileCount++;
2896 :
2897 23 : pasSharedFileList = static_cast<CPLSharedFileInfo *>(
2898 46 : CPLRealloc(const_cast<CPLSharedFileInfo *>(pasSharedFileList),
2899 23 : sizeof(CPLSharedFileInfo) * nSharedFileCount));
2900 23 : pasSharedFileListExtra = static_cast<CPLSharedFileInfoExtra *>(
2901 46 : CPLRealloc(const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra),
2902 23 : sizeof(CPLSharedFileInfoExtra) * nSharedFileCount));
2903 :
2904 23 : pasSharedFileList[nSharedFileCount - 1].fp = fp;
2905 23 : pasSharedFileList[nSharedFileCount - 1].nRefCount = 1;
2906 23 : pasSharedFileList[nSharedFileCount - 1].bLarge = bLarge;
2907 46 : pasSharedFileList[nSharedFileCount - 1].pszFilename =
2908 23 : CPLStrdup(pszFilename);
2909 23 : pasSharedFileList[nSharedFileCount - 1].pszAccess = CPLStrdup(pszAccess);
2910 23 : pasSharedFileListExtra[nSharedFileCount - 1].nPID = nPID;
2911 :
2912 23 : return fp;
2913 : }
2914 :
2915 : /************************************************************************/
2916 : /* CPLCloseShared() */
2917 : /************************************************************************/
2918 :
2919 : /**
2920 : * Close shared file.
2921 : *
2922 : * Dereferences the indicated file handle, and closes it if the reference
2923 : * count has dropped to zero. A CPLError() is issued if the file is not
2924 : * in the shared file list.
2925 : *
2926 : * @param fp file handle from CPLOpenShared() to deaccess.
2927 : */
2928 :
2929 27 : void CPLCloseShared(FILE *fp)
2930 :
2931 : {
2932 27 : CPLMutexHolderD(&hSharedFileMutex);
2933 :
2934 : /* -------------------------------------------------------------------- */
2935 : /* Search for matching information. */
2936 : /* -------------------------------------------------------------------- */
2937 27 : int i = 0;
2938 29 : for (; i < nSharedFileCount && fp != pasSharedFileList[i].fp; i++)
2939 : {
2940 : }
2941 :
2942 27 : if (i == nSharedFileCount)
2943 : {
2944 0 : CPLError(CE_Failure, CPLE_AppDefined,
2945 : "Unable to find file handle %p in CPLCloseShared().", fp);
2946 0 : return;
2947 : }
2948 :
2949 : /* -------------------------------------------------------------------- */
2950 : /* Dereference and return if there are still some references. */
2951 : /* -------------------------------------------------------------------- */
2952 27 : if (--pasSharedFileList[i].nRefCount > 0)
2953 4 : return;
2954 :
2955 : /* -------------------------------------------------------------------- */
2956 : /* Close the file, and remove the information. */
2957 : /* -------------------------------------------------------------------- */
2958 23 : if (pasSharedFileList[i].bLarge)
2959 : {
2960 23 : if (VSIFCloseL(reinterpret_cast<VSILFILE *>(pasSharedFileList[i].fp)) !=
2961 : 0)
2962 : {
2963 0 : CPLError(CE_Failure, CPLE_FileIO, "Error while closing %s",
2964 0 : pasSharedFileList[i].pszFilename);
2965 : }
2966 : }
2967 : else
2968 : {
2969 0 : VSIFClose(pasSharedFileList[i].fp);
2970 : }
2971 :
2972 23 : CPLFree(pasSharedFileList[i].pszFilename);
2973 23 : CPLFree(pasSharedFileList[i].pszAccess);
2974 :
2975 23 : nSharedFileCount--;
2976 23 : memmove(
2977 23 : const_cast<CPLSharedFileInfo *>(pasSharedFileList + i),
2978 23 : const_cast<CPLSharedFileInfo *>(pasSharedFileList + nSharedFileCount),
2979 : sizeof(CPLSharedFileInfo));
2980 23 : memmove(const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra + i),
2981 23 : const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra +
2982 23 : nSharedFileCount),
2983 : sizeof(CPLSharedFileInfoExtra));
2984 :
2985 23 : if (nSharedFileCount == 0)
2986 : {
2987 20 : CPLFree(const_cast<CPLSharedFileInfo *>(pasSharedFileList));
2988 20 : pasSharedFileList = nullptr;
2989 20 : CPLFree(const_cast<CPLSharedFileInfoExtra *>(pasSharedFileListExtra));
2990 20 : pasSharedFileListExtra = nullptr;
2991 : }
2992 : }
2993 :
2994 : /************************************************************************/
2995 : /* CPLCleanupSharedFileMutex() */
2996 : /************************************************************************/
2997 :
2998 922 : void CPLCleanupSharedFileMutex()
2999 : {
3000 922 : if (hSharedFileMutex != nullptr)
3001 : {
3002 0 : CPLDestroyMutex(hSharedFileMutex);
3003 0 : hSharedFileMutex = nullptr;
3004 : }
3005 922 : }
3006 :
3007 : /************************************************************************/
3008 : /* CPLGetSharedList() */
3009 : /************************************************************************/
3010 :
3011 : /**
3012 : * Fetch list of open shared files.
3013 : *
3014 : * @param pnCount place to put the count of entries.
3015 : *
3016 : * @return the pointer to the first in the array of shared file info
3017 : * structures.
3018 : */
3019 :
3020 0 : CPLSharedFileInfo *CPLGetSharedList(int *pnCount)
3021 :
3022 : {
3023 0 : if (pnCount != nullptr)
3024 0 : *pnCount = nSharedFileCount;
3025 :
3026 0 : return const_cast<CPLSharedFileInfo *>(pasSharedFileList);
3027 : }
3028 :
3029 : /************************************************************************/
3030 : /* CPLDumpSharedList() */
3031 : /************************************************************************/
3032 :
3033 : /**
3034 : * Report open shared files.
3035 : *
3036 : * Dumps all open shared files to the indicated file handle. If the
3037 : * file handle is NULL information is sent via the CPLDebug() call.
3038 : *
3039 : * @param fp File handle to write to.
3040 : */
3041 :
3042 103 : void CPLDumpSharedList(FILE *fp)
3043 :
3044 : {
3045 103 : if (nSharedFileCount > 0)
3046 : {
3047 0 : if (fp == nullptr)
3048 0 : CPLDebug("CPL", "%d Shared files open.", nSharedFileCount);
3049 : else
3050 0 : fprintf(fp, "%d Shared files open.", nSharedFileCount);
3051 : }
3052 :
3053 103 : for (int i = 0; i < nSharedFileCount; i++)
3054 : {
3055 0 : if (fp == nullptr)
3056 0 : CPLDebug("CPL", "%2d %d %4s %s", pasSharedFileList[i].nRefCount,
3057 0 : pasSharedFileList[i].bLarge,
3058 0 : pasSharedFileList[i].pszAccess,
3059 0 : pasSharedFileList[i].pszFilename);
3060 : else
3061 0 : fprintf(fp, "%2d %d %4s %s", pasSharedFileList[i].nRefCount,
3062 0 : pasSharedFileList[i].bLarge, pasSharedFileList[i].pszAccess,
3063 0 : pasSharedFileList[i].pszFilename);
3064 : }
3065 103 : }
3066 :
3067 : /************************************************************************/
3068 : /* CPLUnlinkTree() */
3069 : /************************************************************************/
3070 :
3071 : /** Recursively unlink a directory.
3072 : *
3073 : * @return 0 on successful completion, -1 if function fails.
3074 : */
3075 :
3076 52 : int CPLUnlinkTree(const char *pszPath)
3077 :
3078 : {
3079 : /* -------------------------------------------------------------------- */
3080 : /* First, ensure there is such a file. */
3081 : /* -------------------------------------------------------------------- */
3082 : VSIStatBufL sStatBuf;
3083 :
3084 52 : if (VSIStatL(pszPath, &sStatBuf) != 0)
3085 : {
3086 2 : CPLError(CE_Failure, CPLE_AppDefined,
3087 : "It seems no file system object called '%s' exists.", pszPath);
3088 :
3089 2 : return -1;
3090 : }
3091 :
3092 : /* -------------------------------------------------------------------- */
3093 : /* If it is a simple file, just delete it. */
3094 : /* -------------------------------------------------------------------- */
3095 50 : if (VSI_ISREG(sStatBuf.st_mode))
3096 : {
3097 34 : if (VSIUnlink(pszPath) != 0)
3098 : {
3099 0 : CPLError(CE_Failure, CPLE_AppDefined, "Failed to unlink %s.",
3100 : pszPath);
3101 :
3102 0 : return -1;
3103 : }
3104 :
3105 34 : return 0;
3106 : }
3107 :
3108 : /* -------------------------------------------------------------------- */
3109 : /* If it is a directory recurse then unlink the directory. */
3110 : /* -------------------------------------------------------------------- */
3111 16 : else if (VSI_ISDIR(sStatBuf.st_mode))
3112 : {
3113 16 : char **papszItems = VSIReadDir(pszPath);
3114 :
3115 32 : for (int i = 0; papszItems != nullptr && papszItems[i] != nullptr; i++)
3116 : {
3117 16 : if (papszItems[i][0] == '\0' || EQUAL(papszItems[i], ".") ||
3118 16 : EQUAL(papszItems[i], ".."))
3119 0 : continue;
3120 :
3121 : const std::string osSubPath =
3122 16 : CPLFormFilenameSafe(pszPath, papszItems[i], nullptr);
3123 :
3124 16 : const int nErr = CPLUnlinkTree(osSubPath.c_str());
3125 :
3126 16 : if (nErr != 0)
3127 : {
3128 0 : CSLDestroy(papszItems);
3129 0 : return nErr;
3130 : }
3131 : }
3132 :
3133 16 : CSLDestroy(papszItems);
3134 :
3135 16 : if (VSIRmdir(pszPath) != 0)
3136 : {
3137 0 : CPLError(CE_Failure, CPLE_AppDefined, "Failed to unlink %s.",
3138 : pszPath);
3139 :
3140 0 : return -1;
3141 : }
3142 :
3143 16 : return 0;
3144 : }
3145 :
3146 : /* -------------------------------------------------------------------- */
3147 : /* otherwise report an error. */
3148 : /* -------------------------------------------------------------------- */
3149 0 : CPLError(CE_Failure, CPLE_AppDefined,
3150 : "Failed to unlink %s.\nUnrecognised filesystem object.", pszPath);
3151 0 : return 1000;
3152 : }
3153 :
3154 : /************************************************************************/
3155 : /* CPLCopyFile() */
3156 : /************************************************************************/
3157 :
3158 : /** Copy a file */
3159 2231 : int CPLCopyFile(const char *pszNewPath, const char *pszOldPath)
3160 :
3161 : {
3162 2231 : return VSICopyFile(pszOldPath, pszNewPath, nullptr,
3163 : static_cast<vsi_l_offset>(-1), nullptr, nullptr,
3164 2231 : nullptr);
3165 : }
3166 :
3167 : /************************************************************************/
3168 : /* CPLCopyTree() */
3169 : /************************************************************************/
3170 :
3171 : /** Recursively copy a tree */
3172 4 : int CPLCopyTree(const char *pszNewPath, const char *pszOldPath)
3173 :
3174 : {
3175 : VSIStatBufL sStatBuf;
3176 4 : if (VSIStatL(pszNewPath, &sStatBuf) == 0)
3177 : {
3178 1 : CPLError(
3179 : CE_Failure, CPLE_AppDefined,
3180 : "It seems that a file system object called '%s' already exists.",
3181 : pszNewPath);
3182 :
3183 1 : return -1;
3184 : }
3185 :
3186 3 : if (VSIStatL(pszOldPath, &sStatBuf) != 0)
3187 : {
3188 1 : CPLError(CE_Failure, CPLE_AppDefined,
3189 : "It seems no file system object called '%s' exists.",
3190 : pszOldPath);
3191 :
3192 1 : return -1;
3193 : }
3194 :
3195 2 : if (VSI_ISDIR(sStatBuf.st_mode))
3196 : {
3197 1 : if (VSIMkdir(pszNewPath, 0755) != 0)
3198 : {
3199 0 : CPLError(CE_Failure, CPLE_AppDefined,
3200 : "Cannot create directory '%s'.", pszNewPath);
3201 :
3202 0 : return -1;
3203 : }
3204 :
3205 1 : char **papszItems = VSIReadDir(pszOldPath);
3206 :
3207 4 : for (int i = 0; papszItems != nullptr && papszItems[i] != nullptr; i++)
3208 : {
3209 3 : if (EQUAL(papszItems[i], ".") || EQUAL(papszItems[i], ".."))
3210 2 : continue;
3211 :
3212 : const std::string osNewSubPath =
3213 1 : CPLFormFilenameSafe(pszNewPath, papszItems[i], nullptr);
3214 : const std::string osOldSubPath =
3215 1 : CPLFormFilenameSafe(pszOldPath, papszItems[i], nullptr);
3216 :
3217 : const int nErr =
3218 1 : CPLCopyTree(osNewSubPath.c_str(), osOldSubPath.c_str());
3219 :
3220 1 : if (nErr != 0)
3221 : {
3222 0 : CSLDestroy(papszItems);
3223 0 : return nErr;
3224 : }
3225 : }
3226 1 : CSLDestroy(papszItems);
3227 :
3228 1 : return 0;
3229 : }
3230 1 : else if (VSI_ISREG(sStatBuf.st_mode))
3231 : {
3232 1 : return CPLCopyFile(pszNewPath, pszOldPath);
3233 : }
3234 : else
3235 : {
3236 0 : CPLError(CE_Failure, CPLE_AppDefined,
3237 : "Unrecognized filesystem object : '%s'.", pszOldPath);
3238 0 : return -1;
3239 : }
3240 : }
3241 :
3242 : /************************************************************************/
3243 : /* CPLMoveFile() */
3244 : /************************************************************************/
3245 :
3246 : /** Move a file */
3247 184 : int CPLMoveFile(const char *pszNewPath, const char *pszOldPath)
3248 :
3249 : {
3250 184 : if (VSIRename(pszOldPath, pszNewPath) == 0)
3251 181 : return 0;
3252 :
3253 3 : const int nRet = CPLCopyFile(pszNewPath, pszOldPath);
3254 :
3255 3 : if (nRet == 0)
3256 3 : VSIUnlink(pszOldPath);
3257 3 : return nRet;
3258 : }
3259 :
3260 : /************************************************************************/
3261 : /* CPLSymlink() */
3262 : /************************************************************************/
3263 :
3264 : /** Create a symbolic link */
3265 : #ifdef _WIN32
3266 : int CPLSymlink(const char *, const char *, CSLConstList)
3267 : {
3268 : return -1;
3269 : }
3270 : #else
3271 0 : int CPLSymlink(const char *pszOldPath, const char *pszNewPath,
3272 : CSLConstList /* papszOptions */)
3273 : {
3274 0 : return symlink(pszOldPath, pszNewPath);
3275 : }
3276 : #endif
3277 :
3278 : /************************************************************************/
3279 : /* ==================================================================== */
3280 : /* CPLLocaleC */
3281 : /* ==================================================================== */
3282 : /************************************************************************/
3283 :
3284 : //! @cond Doxygen_Suppress
3285 : /************************************************************************/
3286 : /* CPLLocaleC() */
3287 : /************************************************************************/
3288 :
3289 129 : CPLLocaleC::CPLLocaleC() : pszOldLocale(nullptr)
3290 : {
3291 129 : if (CPLTestBool(CPLGetConfigOption("GDAL_DISABLE_CPLLOCALEC", "NO")))
3292 0 : return;
3293 :
3294 129 : pszOldLocale = CPLStrdup(CPLsetlocale(LC_NUMERIC, nullptr));
3295 129 : if (EQUAL(pszOldLocale, "C") || EQUAL(pszOldLocale, "POSIX") ||
3296 0 : CPLsetlocale(LC_NUMERIC, "C") == nullptr)
3297 : {
3298 129 : CPLFree(pszOldLocale);
3299 129 : pszOldLocale = nullptr;
3300 : }
3301 : }
3302 :
3303 : /************************************************************************/
3304 : /* ~CPLLocaleC() */
3305 : /************************************************************************/
3306 :
3307 0 : CPLLocaleC::~CPLLocaleC()
3308 :
3309 : {
3310 129 : if (pszOldLocale == nullptr)
3311 129 : return;
3312 :
3313 0 : CPLsetlocale(LC_NUMERIC, pszOldLocale);
3314 0 : CPLFree(pszOldLocale);
3315 129 : }
3316 :
3317 : /************************************************************************/
3318 : /* CPLThreadLocaleCPrivate */
3319 : /************************************************************************/
3320 :
3321 : #ifdef HAVE_USELOCALE
3322 :
3323 : class CPLThreadLocaleCPrivate
3324 : {
3325 : locale_t nNewLocale;
3326 : locale_t nOldLocale;
3327 :
3328 : CPL_DISALLOW_COPY_ASSIGN(CPLThreadLocaleCPrivate)
3329 :
3330 : public:
3331 : CPLThreadLocaleCPrivate();
3332 : ~CPLThreadLocaleCPrivate();
3333 : };
3334 :
3335 0 : CPLThreadLocaleCPrivate::CPLThreadLocaleCPrivate()
3336 0 : : nNewLocale(newlocale(LC_NUMERIC_MASK, "C", nullptr)),
3337 0 : nOldLocale(uselocale(nNewLocale))
3338 : {
3339 0 : }
3340 :
3341 0 : CPLThreadLocaleCPrivate::~CPLThreadLocaleCPrivate()
3342 : {
3343 0 : uselocale(nOldLocale);
3344 0 : freelocale(nNewLocale);
3345 0 : }
3346 :
3347 : #elif defined(_MSC_VER)
3348 :
3349 : class CPLThreadLocaleCPrivate
3350 : {
3351 : int nOldValConfigThreadLocale;
3352 : char *pszOldLocale;
3353 :
3354 : CPL_DISALLOW_COPY_ASSIGN(CPLThreadLocaleCPrivate)
3355 :
3356 : public:
3357 : CPLThreadLocaleCPrivate();
3358 : ~CPLThreadLocaleCPrivate();
3359 : };
3360 :
3361 : CPLThreadLocaleCPrivate::CPLThreadLocaleCPrivate()
3362 : {
3363 : nOldValConfigThreadLocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
3364 : pszOldLocale = setlocale(LC_NUMERIC, "C");
3365 : if (pszOldLocale)
3366 : pszOldLocale = CPLStrdup(pszOldLocale);
3367 : }
3368 :
3369 : CPLThreadLocaleCPrivate::~CPLThreadLocaleCPrivate()
3370 : {
3371 : if (pszOldLocale != nullptr)
3372 : {
3373 : setlocale(LC_NUMERIC, pszOldLocale);
3374 : CPLFree(pszOldLocale);
3375 : }
3376 : _configthreadlocale(nOldValConfigThreadLocale);
3377 : }
3378 :
3379 : #else
3380 :
3381 : class CPLThreadLocaleCPrivate
3382 : {
3383 : char *pszOldLocale;
3384 :
3385 : CPL_DISALLOW_COPY_ASSIGN(CPLThreadLocaleCPrivate)
3386 :
3387 : public:
3388 : CPLThreadLocaleCPrivate();
3389 : ~CPLThreadLocaleCPrivate();
3390 : };
3391 :
3392 : CPLThreadLocaleCPrivate::CPLThreadLocaleCPrivate()
3393 : : pszOldLocale(CPLStrdup(CPLsetlocale(LC_NUMERIC, nullptr)))
3394 : {
3395 : if (EQUAL(pszOldLocale, "C") || EQUAL(pszOldLocale, "POSIX") ||
3396 : CPLsetlocale(LC_NUMERIC, "C") == nullptr)
3397 : {
3398 : CPLFree(pszOldLocale);
3399 : pszOldLocale = nullptr;
3400 : }
3401 : }
3402 :
3403 : CPLThreadLocaleCPrivate::~CPLThreadLocaleCPrivate()
3404 : {
3405 : if (pszOldLocale != nullptr)
3406 : {
3407 : CPLsetlocale(LC_NUMERIC, pszOldLocale);
3408 : CPLFree(pszOldLocale);
3409 : }
3410 : }
3411 :
3412 : #endif
3413 :
3414 : /************************************************************************/
3415 : /* CPLThreadLocaleC() */
3416 : /************************************************************************/
3417 :
3418 0 : CPLThreadLocaleC::CPLThreadLocaleC() : m_private(new CPLThreadLocaleCPrivate)
3419 : {
3420 0 : }
3421 :
3422 : /************************************************************************/
3423 : /* ~CPLThreadLocaleC() */
3424 : /************************************************************************/
3425 :
3426 0 : CPLThreadLocaleC::~CPLThreadLocaleC()
3427 :
3428 : {
3429 0 : delete m_private;
3430 0 : }
3431 :
3432 : //! @endcond
3433 :
3434 : /************************************************************************/
3435 : /* CPLsetlocale() */
3436 : /************************************************************************/
3437 :
3438 : /**
3439 : * Prevents parallel executions of setlocale().
3440 : *
3441 : * Calling setlocale() concurrently from two or more threads is a
3442 : * potential data race. A mutex is used to provide a critical region so
3443 : * that only one thread at a time can be executing setlocale().
3444 : *
3445 : * The return should not be freed, and copied quickly as it may be invalidated
3446 : * by a following next call to CPLsetlocale().
3447 : *
3448 : * @param category See your compiler's documentation on setlocale.
3449 : * @param locale See your compiler's documentation on setlocale.
3450 : *
3451 : * @return See your compiler's documentation on setlocale.
3452 : */
3453 131 : char *CPLsetlocale(int category, const char *locale)
3454 : {
3455 262 : CPLMutexHolder oHolder(&hSetLocaleMutex);
3456 131 : char *pszRet = setlocale(category, locale);
3457 131 : if (pszRet == nullptr)
3458 0 : return pszRet;
3459 :
3460 : // Make it thread-locale storage.
3461 131 : return const_cast<char *>(CPLSPrintf("%s", pszRet));
3462 : }
3463 :
3464 : /************************************************************************/
3465 : /* CPLCleanupSetlocaleMutex() */
3466 : /************************************************************************/
3467 :
3468 922 : void CPLCleanupSetlocaleMutex(void)
3469 : {
3470 922 : if (hSetLocaleMutex != nullptr)
3471 5 : CPLDestroyMutex(hSetLocaleMutex);
3472 922 : hSetLocaleMutex = nullptr;
3473 922 : }
3474 :
3475 : /************************************************************************/
3476 : /* IsPowerOfTwo() */
3477 : /************************************************************************/
3478 :
3479 140 : int CPLIsPowerOfTwo(unsigned int i)
3480 : {
3481 140 : if (i == 0)
3482 0 : return FALSE;
3483 140 : return (i & (i - 1)) == 0 ? TRUE : FALSE;
3484 : }
3485 :
3486 : /************************************************************************/
3487 : /* CPLCheckForFile() */
3488 : /************************************************************************/
3489 :
3490 : /**
3491 : * Check for file existence.
3492 : *
3493 : * The function checks if a named file exists in the filesystem, hopefully
3494 : * in an efficient fashion if a sibling file list is available. It exists
3495 : * primarily to do faster file checking for functions like GDAL open methods
3496 : * that get a list of files from the target directory.
3497 : *
3498 : * If the sibling file list exists (is not NULL) it is assumed to be a list
3499 : * of files in the same directory as the target file, and it will be checked
3500 : * (case insensitively) for a match. If a match is found, pszFilename is
3501 : * updated with the correct case and TRUE is returned.
3502 : *
3503 : * If papszSiblingFiles is NULL, a VSIStatL() is used to test for the files
3504 : * existence, and no case insensitive testing is done.
3505 : *
3506 : * @param pszFilename name of file to check for - filename case updated in
3507 : * some cases.
3508 : * @param papszSiblingFiles a list of files in the same directory as
3509 : * pszFilename if available, or NULL. This list should have no path components.
3510 : *
3511 : * @return TRUE if a match is found, or FALSE if not.
3512 : */
3513 :
3514 158650 : int CPLCheckForFile(char *pszFilename, char **papszSiblingFiles)
3515 :
3516 : {
3517 : /* -------------------------------------------------------------------- */
3518 : /* Fallback case if we don't have a sibling file list. */
3519 : /* -------------------------------------------------------------------- */
3520 158650 : if (papszSiblingFiles == nullptr)
3521 : {
3522 : VSIStatBufL sStatBuf;
3523 :
3524 10700 : return VSIStatExL(pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0;
3525 : }
3526 :
3527 : /* -------------------------------------------------------------------- */
3528 : /* We have sibling files, compare the non-path filename portion */
3529 : /* of pszFilename too all entries. */
3530 : /* -------------------------------------------------------------------- */
3531 295900 : const CPLString osFileOnly = CPLGetFilename(pszFilename);
3532 :
3533 13882200 : for (int i = 0; papszSiblingFiles[i] != nullptr; i++)
3534 : {
3535 13734400 : if (EQUAL(papszSiblingFiles[i], osFileOnly))
3536 : {
3537 314 : strcpy(pszFilename + strlen(pszFilename) - osFileOnly.size(),
3538 157 : papszSiblingFiles[i]);
3539 157 : return TRUE;
3540 : }
3541 : }
3542 :
3543 147793 : return FALSE;
3544 : }
3545 :
3546 : /************************************************************************/
3547 : /* Stub implementation of zip services if we don't have libz. */
3548 : /************************************************************************/
3549 :
3550 : #if !defined(HAVE_LIBZ)
3551 :
3552 : void *CPLCreateZip(const char *, char **)
3553 :
3554 : {
3555 : CPLError(CE_Failure, CPLE_NotSupported,
3556 : "This GDAL/OGR build does not include zlib and zip services.");
3557 : return nullptr;
3558 : }
3559 :
3560 : CPLErr CPLCreateFileInZip(void *, const char *, char **)
3561 : {
3562 : return CE_Failure;
3563 : }
3564 :
3565 : CPLErr CPLWriteFileInZip(void *, const void *, int)
3566 : {
3567 : return CE_Failure;
3568 : }
3569 :
3570 : CPLErr CPLCloseFileInZip(void *)
3571 : {
3572 : return CE_Failure;
3573 : }
3574 :
3575 : CPLErr CPLCloseZip(void *)
3576 : {
3577 : return CE_Failure;
3578 : }
3579 :
3580 : void *CPLZLibDeflate(const void *, size_t, int, void *, size_t,
3581 : size_t *pnOutBytes)
3582 : {
3583 : if (pnOutBytes != nullptr)
3584 : *pnOutBytes = 0;
3585 : return nullptr;
3586 : }
3587 :
3588 : void *CPLZLibInflate(const void *, size_t, void *, size_t, size_t *pnOutBytes)
3589 : {
3590 : if (pnOutBytes != nullptr)
3591 : *pnOutBytes = 0;
3592 : return nullptr;
3593 : }
3594 :
3595 : #endif /* !defined(HAVE_LIBZ) */
3596 :
3597 : /************************************************************************/
3598 : /* ==================================================================== */
3599 : /* CPLConfigOptionSetter */
3600 : /* ==================================================================== */
3601 : /************************************************************************/
3602 :
3603 : //! @cond Doxygen_Suppress
3604 : /************************************************************************/
3605 : /* CPLConfigOptionSetter() */
3606 : /************************************************************************/
3607 :
3608 23428 : CPLConfigOptionSetter::CPLConfigOptionSetter(const char *pszKey,
3609 : const char *pszValue,
3610 23428 : bool bSetOnlyIfUndefined)
3611 23428 : : m_pszKey(CPLStrdup(pszKey)), m_pszOldValue(nullptr),
3612 23420 : m_bRestoreOldValue(false)
3613 : {
3614 23420 : const char *pszOldValue = CPLGetThreadLocalConfigOption(pszKey, nullptr);
3615 37203 : if ((bSetOnlyIfUndefined &&
3616 33067 : CPLGetConfigOption(pszKey, nullptr) == nullptr) ||
3617 9655 : !bSetOnlyIfUndefined)
3618 : {
3619 23416 : m_bRestoreOldValue = true;
3620 23416 : if (pszOldValue)
3621 646 : m_pszOldValue = CPLStrdup(pszOldValue);
3622 23416 : CPLSetThreadLocalConfigOption(pszKey, pszValue);
3623 : }
3624 23315 : }
3625 :
3626 : /************************************************************************/
3627 : /* ~CPLConfigOptionSetter() */
3628 : /************************************************************************/
3629 :
3630 46789 : CPLConfigOptionSetter::~CPLConfigOptionSetter()
3631 : {
3632 23428 : if (m_bRestoreOldValue)
3633 : {
3634 23421 : CPLSetThreadLocalConfigOption(m_pszKey, m_pszOldValue);
3635 23326 : CPLFree(m_pszOldValue);
3636 : }
3637 23295 : CPLFree(m_pszKey);
3638 23361 : }
3639 :
3640 : //! @endcond
3641 :
3642 : /************************************************************************/
3643 : /* CPLIsInteractive() */
3644 : /************************************************************************/
3645 :
3646 : /** Returns whether the provided file refers to a terminal.
3647 : *
3648 : * This function is a wrapper of the ``isatty()`` POSIX function.
3649 : *
3650 : * @param f File to test. Typically stdin, stdout or stderr
3651 : * @return true if it is an open file referring to a terminal.
3652 : * @since GDAL 3.11
3653 : */
3654 657 : bool CPLIsInteractive(FILE *f)
3655 : {
3656 : #ifndef _WIN32
3657 657 : return isatty(static_cast<int>(fileno(f)));
3658 : #else
3659 : return _isatty(_fileno(f));
3660 : #endif
3661 : }
|