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