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