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