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