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