Line data Source code
1 : /**********************************************************************
2 : *
3 : * Name: cpl_string.cpp
4 : * Project: CPL - Common Portability Library
5 : * Purpose: String and Stringlist manipulation functions.
6 : * Author: Daniel Morissette, danmo@videotron.ca
7 : *
8 : **********************************************************************
9 : * Copyright (c) 1998, Daniel Morissette
10 : * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : **********************************************************************
14 : *
15 : * Independent Security Audit 2003/04/04 Andrey Kiselev:
16 : * Completed audit of this module. All functions may be used without buffer
17 : * overflows and stack corruptions with any kind of input data strings with
18 : * except of CPLSPrintf() and CSLAppendPrintf() (see note below).
19 : *
20 : * Security Audit 2003/03/28 warmerda:
21 : * Completed security audit. I believe that this module may be safely used
22 : * to parse tokenize arbitrary input strings, assemble arbitrary sets of
23 : * names values into string lists, unescape and escape text even if provided
24 : * by a potentially hostile source.
25 : *
26 : * CPLSPrintf() and CSLAppendPrintf() may not be safely invoked on
27 : * arbitrary length inputs since it has a fixed size output buffer on system
28 : * without vsnprintf().
29 : *
30 : **********************************************************************/
31 :
32 : #undef WARN_STANDARD_PRINTF
33 :
34 : #include "cpl_port.h"
35 : #include "cpl_string.h"
36 :
37 : #include <cctype>
38 : #include <climits>
39 : #include <cmath>
40 : #include <cstdlib>
41 : #include <cstring>
42 :
43 : #include <limits>
44 :
45 : #include "cpl_config.h"
46 : #include "cpl_multiproc.h"
47 : #include "cpl_vsi.h"
48 :
49 : #if !defined(va_copy) && defined(__va_copy)
50 : #define va_copy __va_copy
51 : #endif
52 :
53 : /*=====================================================================
54 : StringList manipulation functions.
55 : =====================================================================*/
56 :
57 : /**********************************************************************
58 : * CSLAddString()
59 : **********************************************************************/
60 :
61 : /** Append a string to a StringList and return a pointer to the modified
62 : * StringList.
63 : *
64 : * If the input StringList is NULL, then a new StringList is created.
65 : * Note that CSLAddString performance when building a list is in O(n^2)
66 : * which can cause noticeable slow down when n > 10000.
67 : */
68 420378 : char **CSLAddString(char **papszStrList, const char *pszNewString)
69 : {
70 420378 : char **papszRet = CSLAddStringMayFail(papszStrList, pszNewString);
71 420237 : if (papszRet == nullptr && pszNewString != nullptr)
72 0 : abort();
73 420237 : return papszRet;
74 : }
75 :
76 : /** Same as CSLAddString() but may return NULL in case of (memory) failure */
77 454991 : char **CSLAddStringMayFail(char **papszStrList, const char *pszNewString)
78 : {
79 454991 : if (pszNewString == nullptr)
80 131 : return papszStrList; // Nothing to do!
81 :
82 454860 : char *pszDup = VSI_STRDUP_VERBOSE(pszNewString);
83 454747 : if (pszDup == nullptr)
84 0 : return nullptr;
85 :
86 : // Allocate room for the new string.
87 454747 : char **papszStrListNew = nullptr;
88 454747 : int nItems = 0;
89 :
90 454747 : if (papszStrList == nullptr)
91 : papszStrListNew =
92 63892 : static_cast<char **>(VSI_CALLOC_VERBOSE(2, sizeof(char *)));
93 : else
94 : {
95 390855 : nItems = CSLCount(papszStrList);
96 : papszStrListNew = static_cast<char **>(
97 390854 : VSI_REALLOC_VERBOSE(papszStrList, (nItems + 2) * sizeof(char *)));
98 : }
99 454752 : if (papszStrListNew == nullptr)
100 : {
101 0 : VSIFree(pszDup);
102 0 : return nullptr;
103 : }
104 :
105 : // Copy the string in the list.
106 454752 : papszStrListNew[nItems] = pszDup;
107 454752 : papszStrListNew[nItems + 1] = nullptr;
108 :
109 454752 : return papszStrListNew;
110 : }
111 :
112 : /************************************************************************/
113 : /* CSLCount() */
114 : /************************************************************************/
115 :
116 : /**
117 : * Return number of items in a string list.
118 : *
119 : * Returns the number of items in a string list, not counting the
120 : * terminating NULL. Passing in NULL is safe, and will result in a count
121 : * of zero.
122 : *
123 : * Lists are counted by iterating through them so long lists will
124 : * take more time than short lists. Care should be taken to avoid using
125 : * CSLCount() as an end condition for loops as it will result in O(n^2)
126 : * behavior.
127 : *
128 : * @param papszStrList the string list to count.
129 : *
130 : * @return the number of entries.
131 : */
132 4306410 : int CSLCount(CSLConstList papszStrList)
133 : {
134 4306410 : if (!papszStrList)
135 3132780 : return 0;
136 :
137 1173640 : int nItems = 0;
138 :
139 12283100 : while (*papszStrList != nullptr)
140 : {
141 11109400 : ++nItems;
142 11109400 : ++papszStrList;
143 : }
144 :
145 1173640 : return nItems;
146 : }
147 :
148 : /************************************************************************/
149 : /* CSLGetField() */
150 : /************************************************************************/
151 :
152 : /**
153 : * Fetches the indicated field, being careful not to crash if the field
154 : * doesn't exist within this string list.
155 : *
156 : * The returned pointer should not be freed, and doesn't necessarily last long.
157 : */
158 2030 : const char *CSLGetField(CSLConstList papszStrList, int iField)
159 :
160 : {
161 2030 : if (papszStrList == nullptr || iField < 0)
162 0 : return ("");
163 :
164 4461 : for (int i = 0; i < iField + 1; i++)
165 : {
166 2433 : if (papszStrList[i] == nullptr)
167 2 : return "";
168 : }
169 :
170 2028 : return (papszStrList[iField]);
171 : }
172 :
173 : /************************************************************************/
174 : /* CSLDestroy() */
175 : /************************************************************************/
176 :
177 : /**
178 : * Free string list.
179 : *
180 : * Frees the passed string list (null terminated array of strings).
181 : * It is safe to pass NULL.
182 : *
183 : * @param papszStrList the list to free.
184 : */
185 11938100 : void CPL_STDCALL CSLDestroy(char **papszStrList)
186 : {
187 11938100 : if (!papszStrList)
188 9452490 : return;
189 :
190 12005700 : for (char **papszPtr = papszStrList; *papszPtr != nullptr; ++papszPtr)
191 : {
192 9516030 : CPLFree(*papszPtr);
193 : }
194 :
195 2489670 : CPLFree(papszStrList);
196 : }
197 :
198 : /************************************************************************/
199 : /* CSLDuplicate() */
200 : /************************************************************************/
201 :
202 : /**
203 : * Clone a string list.
204 : *
205 : * Efficiently allocates a copy of a string list. The returned list is
206 : * owned by the caller and should be freed with CSLDestroy().
207 : *
208 : * @param papszStrList the input string list.
209 : *
210 : * @return newly allocated copy.
211 : */
212 :
213 3156390 : char **CSLDuplicate(CSLConstList papszStrList)
214 : {
215 3156390 : const int nLines = CSLCount(papszStrList);
216 :
217 3139870 : if (nLines == 0)
218 3102330 : return nullptr;
219 :
220 37537 : CSLConstList papszSrc = papszStrList;
221 :
222 : char **papszNewList =
223 37537 : static_cast<char **>(VSI_MALLOC2_VERBOSE(nLines + 1, sizeof(char *)));
224 :
225 47673 : char **papszDst = papszNewList;
226 :
227 327767 : for (; *papszSrc != nullptr; ++papszSrc, ++papszDst)
228 : {
229 280094 : *papszDst = VSI_STRDUP_VERBOSE(*papszSrc);
230 280094 : if (*papszDst == nullptr)
231 : {
232 0 : CSLDestroy(papszNewList);
233 0 : return nullptr;
234 : }
235 : }
236 47673 : *papszDst = nullptr;
237 :
238 47673 : return papszNewList;
239 : }
240 :
241 : /************************************************************************/
242 : /* CSLMerge */
243 : /************************************************************************/
244 :
245 : /**
246 : * \brief Merge two lists.
247 : *
248 : * The two lists are merged, ensuring that if any keys appear in both
249 : * that the value from the second (papszOverride) list take precedence.
250 : *
251 : * @param papszOrig the original list, being modified.
252 : * @param papszOverride the list of items being merged in. This list
253 : * is unaltered and remains owned by the caller.
254 : *
255 : * @return updated list.
256 : */
257 :
258 750307 : char **CSLMerge(char **papszOrig, CSLConstList papszOverride)
259 :
260 : {
261 750307 : if (papszOrig == nullptr && papszOverride != nullptr)
262 595 : return CSLDuplicate(papszOverride);
263 :
264 749712 : if (papszOverride == nullptr)
265 745935 : return papszOrig;
266 :
267 6029 : for (int i = 0; papszOverride[i] != nullptr; ++i)
268 : {
269 4292 : char *pszKey = nullptr;
270 4292 : const char *pszValue = CPLParseNameValue(papszOverride[i], &pszKey);
271 :
272 4292 : papszOrig = CSLSetNameValue(papszOrig, pszKey, pszValue);
273 4292 : CPLFree(pszKey);
274 : }
275 :
276 1737 : return papszOrig;
277 : }
278 :
279 : /************************************************************************/
280 : /* CSLLoad2() */
281 : /************************************************************************/
282 :
283 : /**
284 : * Load a text file into a string list.
285 : *
286 : * The VSI*L API is used, so VSIFOpenL() supported objects that aren't
287 : * physical files can also be accessed. Files are returned as a string list,
288 : * with one item in the string list per line. End of line markers are
289 : * stripped (by CPLReadLineL()).
290 : *
291 : * If reading the file fails a CPLError() will be issued and NULL returned.
292 : *
293 : * @param pszFname the name of the file to read.
294 : * @param nMaxLines maximum number of lines to read before stopping, or -1 for
295 : * no limit.
296 : * @param nMaxCols maximum number of characters in a line before stopping, or -1
297 : * for no limit.
298 : * @param papszOptions NULL-terminated array of options. Unused for now.
299 : *
300 : * @return a string list with the files lines, now owned by caller. To be freed
301 : * with CSLDestroy()
302 : *
303 : * @since GDAL 1.7.0
304 : */
305 :
306 3137 : char **CSLLoad2(const char *pszFname, int nMaxLines, int nMaxCols,
307 : CSLConstList papszOptions)
308 : {
309 3137 : VSILFILE *fp = VSIFOpenL(pszFname, "rb");
310 :
311 3137 : if (!fp)
312 : {
313 1988 : if (CPLFetchBool(papszOptions, "EMIT_ERROR_IF_CANNOT_OPEN_FILE", true))
314 : {
315 : // Unable to open file.
316 1 : CPLError(CE_Failure, CPLE_OpenFailed,
317 : "CSLLoad2(\"%s\") failed: unable to open file.", pszFname);
318 : }
319 1988 : return nullptr;
320 : }
321 :
322 1149 : char **papszStrList = nullptr;
323 1149 : int nLines = 0;
324 1149 : int nAllocatedLines = 0;
325 :
326 9601 : while (!VSIFEofL(fp) && (nMaxLines == -1 || nLines < nMaxLines))
327 : {
328 8458 : const char *pszLine = CPLReadLine2L(fp, nMaxCols, papszOptions);
329 8458 : if (pszLine == nullptr)
330 6 : break;
331 :
332 8452 : if (nLines + 1 >= nAllocatedLines)
333 : {
334 1275 : nAllocatedLines = 16 + nAllocatedLines * 2;
335 : char **papszStrListNew = static_cast<char **>(
336 1275 : VSIRealloc(papszStrList, nAllocatedLines * sizeof(char *)));
337 1275 : if (papszStrListNew == nullptr)
338 : {
339 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
340 0 : CPLReadLineL(nullptr);
341 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
342 : "CSLLoad2(\"%s\") "
343 : "failed: not enough memory to allocate lines.",
344 : pszFname);
345 0 : return papszStrList;
346 : }
347 1275 : papszStrList = papszStrListNew;
348 : }
349 8452 : papszStrList[nLines] = CPLStrdup(pszLine);
350 8452 : papszStrList[nLines + 1] = nullptr;
351 8452 : ++nLines;
352 : }
353 :
354 1149 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
355 :
356 : // Free the internal thread local line buffer.
357 1149 : CPLReadLineL(nullptr);
358 :
359 1149 : return papszStrList;
360 : }
361 :
362 : /************************************************************************/
363 : /* CSLLoad() */
364 : /************************************************************************/
365 :
366 : /**
367 : * Load a text file into a string list.
368 : *
369 : * The VSI*L API is used, so VSIFOpenL() supported objects that aren't
370 : * physical files can also be accessed. Files are returned as a string list,
371 : * with one item in the string list per line. End of line markers are
372 : * stripped (by CPLReadLineL()).
373 : *
374 : * If reading the file fails a CPLError() will be issued and NULL returned.
375 : *
376 : * @param pszFname the name of the file to read.
377 : *
378 : * @return a string list with the files lines, now owned by caller. To be freed
379 : * with CSLDestroy()
380 : */
381 :
382 311 : char **CSLLoad(const char *pszFname)
383 : {
384 311 : return CSLLoad2(pszFname, -1, -1, nullptr);
385 : }
386 :
387 : /**********************************************************************
388 : * CSLSave()
389 : **********************************************************************/
390 :
391 : /** Write a StringList to a text file.
392 : *
393 : * Returns the number of lines written, or 0 if the file could not
394 : * be written.
395 : */
396 :
397 49 : int CSLSave(CSLConstList papszStrList, const char *pszFname)
398 : {
399 49 : if (papszStrList == nullptr)
400 0 : return 0;
401 :
402 49 : VSILFILE *fp = VSIFOpenL(pszFname, "wt");
403 49 : if (fp == nullptr)
404 : {
405 : // Unable to open file.
406 1 : CPLError(CE_Failure, CPLE_OpenFailed,
407 : "CSLSave(\"%s\") failed: unable to open output file.",
408 : pszFname);
409 1 : return 0;
410 : }
411 :
412 48 : int nLines = 0;
413 385 : while (*papszStrList != nullptr)
414 : {
415 337 : if (VSIFPrintfL(fp, "%s\n", *papszStrList) < 1)
416 : {
417 0 : CPLError(CE_Failure, CPLE_FileIO,
418 : "CSLSave(\"%s\") failed: unable to write to output file.",
419 : pszFname);
420 0 : break; // A Problem happened... abort.
421 : }
422 :
423 337 : ++nLines;
424 337 : ++papszStrList;
425 : }
426 :
427 48 : if (VSIFCloseL(fp) != 0)
428 : {
429 0 : CPLError(CE_Failure, CPLE_FileIO,
430 : "CSLSave(\"%s\") failed: unable to write to output file.",
431 : pszFname);
432 : }
433 :
434 48 : return nLines;
435 : }
436 :
437 : /**********************************************************************
438 : * CSLPrint()
439 : **********************************************************************/
440 :
441 : /** Print a StringList to fpOut. If fpOut==NULL, then output is sent
442 : * to stdout.
443 : *
444 : * Returns the number of lines printed.
445 : */
446 0 : int CSLPrint(CSLConstList papszStrList, FILE *fpOut)
447 : {
448 0 : if (!papszStrList)
449 0 : return 0;
450 :
451 0 : if (fpOut == nullptr)
452 0 : fpOut = stdout;
453 :
454 0 : int nLines = 0;
455 :
456 0 : while (*papszStrList != nullptr)
457 : {
458 0 : if (VSIFPrintf(fpOut, "%s\n", *papszStrList) < 0)
459 0 : return nLines;
460 0 : ++nLines;
461 0 : ++papszStrList;
462 : }
463 :
464 0 : return nLines;
465 : }
466 :
467 : /**********************************************************************
468 : * CSLInsertStrings()
469 : **********************************************************************/
470 :
471 : /** Copies the contents of a StringList inside another StringList
472 : * before the specified line.
473 : *
474 : * nInsertAtLineNo is a 0-based line index before which the new strings
475 : * should be inserted. If this value is -1 or is larger than the actual
476 : * number of strings in the list then the strings are added at the end
477 : * of the source StringList.
478 : *
479 : * Returns the modified StringList.
480 : */
481 :
482 17342 : char **CSLInsertStrings(char **papszStrList, int nInsertAtLineNo,
483 : CSLConstList papszNewLines)
484 : {
485 17342 : if (papszNewLines == nullptr)
486 36 : return papszStrList; // Nothing to do!
487 :
488 17306 : const int nToInsert = CSLCount(papszNewLines);
489 17306 : if (nToInsert == 0)
490 1242 : return papszStrList; // Nothing to do!
491 :
492 16064 : const int nSrcLines = CSLCount(papszStrList);
493 16064 : const int nDstLines = nSrcLines + nToInsert;
494 :
495 : // Allocate room for the new strings.
496 : papszStrList = static_cast<char **>(
497 16064 : CPLRealloc(papszStrList, (nDstLines + 1) * sizeof(char *)));
498 :
499 : // Make sure the array is NULL-terminated. It may not be if
500 : // papszStrList was NULL before Realloc().
501 16064 : papszStrList[nSrcLines] = nullptr;
502 :
503 : // Make some room in the original list at the specified location.
504 : // Note that we also have to move the NULL pointer at the end of
505 : // the source StringList.
506 16064 : if (nInsertAtLineNo == -1 || nInsertAtLineNo > nSrcLines)
507 15286 : nInsertAtLineNo = nSrcLines;
508 :
509 : {
510 16064 : char **ppszSrc = papszStrList + nSrcLines;
511 16064 : char **ppszDst = papszStrList + nDstLines;
512 :
513 33356 : for (int i = nSrcLines; i >= nInsertAtLineNo; --i)
514 : {
515 17292 : *ppszDst = *ppszSrc;
516 17292 : --ppszDst;
517 17292 : --ppszSrc;
518 : }
519 : }
520 :
521 : // Copy the strings to the list.
522 16064 : CSLConstList ppszSrc = papszNewLines;
523 16064 : char **ppszDst = papszStrList + nInsertAtLineNo;
524 :
525 145343 : for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
526 : {
527 129279 : *ppszDst = CPLStrdup(*ppszSrc);
528 : }
529 :
530 16064 : return papszStrList;
531 : }
532 :
533 : /**********************************************************************
534 : * CSLInsertString()
535 : **********************************************************************/
536 :
537 : /** Insert a string at a given line number inside a StringList
538 : *
539 : * nInsertAtLineNo is a 0-based line index before which the new string
540 : * should be inserted. If this value is -1 or is larger than the actual
541 : * number of strings in the list then the string is added at the end
542 : * of the source StringList.
543 : *
544 : * Returns the modified StringList.
545 : */
546 :
547 475 : char **CSLInsertString(char **papszStrList, int nInsertAtLineNo,
548 : const char *pszNewLine)
549 : {
550 475 : char *apszList[2] = {const_cast<char *>(pszNewLine), nullptr};
551 :
552 950 : return CSLInsertStrings(papszStrList, nInsertAtLineNo, apszList);
553 : }
554 :
555 : /**********************************************************************
556 : * CSLRemoveStrings()
557 : **********************************************************************/
558 :
559 : /** Remove strings inside a StringList
560 : *
561 : * nFirstLineToDelete is the 0-based line index of the first line to
562 : * remove. If this value is -1 or is larger than the actual
563 : * number of strings in list then the nNumToRemove last strings are
564 : * removed.
565 : *
566 : * If ppapszRetStrings != NULL then the deleted strings won't be
567 : * free'd, they will be stored in a new StringList and the pointer to
568 : * this new list will be returned in *ppapszRetStrings.
569 : *
570 : * Returns the modified StringList.
571 : */
572 :
573 6112 : char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete,
574 : int nNumToRemove, char ***ppapszRetStrings)
575 : {
576 6112 : const int nSrcLines = CSLCount(papszStrList);
577 :
578 6112 : if (nNumToRemove < 1 || nSrcLines == 0)
579 0 : return papszStrList; // Nothing to do!
580 :
581 : // If operation will result in an empty StringList, don't waste
582 : // time here.
583 6112 : const int nDstLines = nSrcLines - nNumToRemove;
584 6112 : if (nDstLines < 1)
585 : {
586 1491 : CSLDestroy(papszStrList);
587 1491 : return nullptr;
588 : }
589 :
590 : // Remove lines from the source StringList.
591 : // Either free() each line or store them to a new StringList depending on
592 : // the caller's choice.
593 4621 : char **ppszDst = papszStrList + nFirstLineToDelete;
594 :
595 4621 : if (ppapszRetStrings == nullptr)
596 : {
597 : // free() all the strings that will be removed.
598 9242 : for (int i = 0; i < nNumToRemove; ++i)
599 : {
600 4621 : CPLFree(*ppszDst);
601 4621 : *ppszDst = nullptr;
602 : }
603 : }
604 : else
605 : {
606 : // Store the strings to remove in a new StringList.
607 0 : *ppapszRetStrings =
608 0 : static_cast<char **>(CPLCalloc(nNumToRemove + 1, sizeof(char *)));
609 :
610 0 : for (int i = 0; i < nNumToRemove; ++i)
611 : {
612 0 : (*ppapszRetStrings)[i] = *ppszDst;
613 0 : *ppszDst = nullptr;
614 0 : ++ppszDst;
615 : }
616 : }
617 :
618 : // Shift down all the lines that follow the lines to remove.
619 4621 : if (nFirstLineToDelete == -1 || nFirstLineToDelete > nSrcLines)
620 0 : nFirstLineToDelete = nDstLines;
621 :
622 4621 : char **ppszSrc = papszStrList + nFirstLineToDelete + nNumToRemove;
623 4621 : ppszDst = papszStrList + nFirstLineToDelete;
624 :
625 9136 : for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
626 : {
627 4515 : *ppszDst = *ppszSrc;
628 : }
629 : // Move the NULL pointer at the end of the StringList.
630 4621 : *ppszDst = *ppszSrc;
631 :
632 : // At this point, we could realloc() papszStrList to a smaller size, but
633 : // since this array will likely grow again in further operations on the
634 : // StringList we'll leave it as it is.
635 4621 : return papszStrList;
636 : }
637 :
638 : /************************************************************************/
639 : /* CSLFindString() */
640 : /************************************************************************/
641 :
642 : /**
643 : * Find a string within a string list (case insensitive).
644 : *
645 : * Returns the index of the entry in the string list that contains the
646 : * target string. The string in the string list must be a full match for
647 : * the target, but the search is case insensitive.
648 : *
649 : * @param papszList the string list to be searched.
650 : * @param pszTarget the string to be searched for.
651 : *
652 : * @return the index of the string within the list or -1 on failure.
653 : */
654 :
655 4074320 : int CSLFindString(CSLConstList papszList, const char *pszTarget)
656 :
657 : {
658 4074320 : if (papszList == nullptr)
659 147159 : return -1;
660 :
661 30444300 : for (int i = 0; papszList[i] != nullptr; ++i)
662 : {
663 26690500 : if (EQUAL(papszList[i], pszTarget))
664 173314 : return i;
665 : }
666 :
667 3753840 : return -1;
668 : }
669 :
670 : /************************************************************************/
671 : /* CSLFindStringCaseSensitive() */
672 : /************************************************************************/
673 :
674 : /**
675 : * Find a string within a string list(case sensitive)
676 : *
677 : * Returns the index of the entry in the string list that contains the
678 : * target string. The string in the string list must be a full match for
679 : * the target.
680 : *
681 : * @param papszList the string list to be searched.
682 : * @param pszTarget the string to be searched for.
683 : *
684 : * @return the index of the string within the list or -1 on failure.
685 : *
686 : * @since GDAL 2.0
687 : */
688 :
689 3441 : int CSLFindStringCaseSensitive(CSLConstList papszList, const char *pszTarget)
690 :
691 : {
692 3441 : if (papszList == nullptr)
693 208 : return -1;
694 :
695 75274 : for (int i = 0; papszList[i] != nullptr; ++i)
696 : {
697 72055 : if (strcmp(papszList[i], pszTarget) == 0)
698 14 : return i;
699 : }
700 :
701 3219 : return -1;
702 : }
703 :
704 : /************************************************************************/
705 : /* CSLPartialFindString() */
706 : /************************************************************************/
707 :
708 : /**
709 : * Find a substring within a string list.
710 : *
711 : * Returns the index of the entry in the string list that contains the
712 : * target string as a substring. The search is case sensitive (unlike
713 : * CSLFindString()).
714 : *
715 : * @param papszHaystack the string list to be searched.
716 : * @param pszNeedle the substring to be searched for.
717 : *
718 : * @return the index of the string within the list or -1 on failure.
719 : */
720 :
721 21724 : int CSLPartialFindString(CSLConstList papszHaystack, const char *pszNeedle)
722 : {
723 21724 : if (papszHaystack == nullptr || pszNeedle == nullptr)
724 8100 : return -1;
725 :
726 30204 : for (int i = 0; papszHaystack[i] != nullptr; ++i)
727 : {
728 22695 : if (strstr(papszHaystack[i], pszNeedle))
729 6115 : return i;
730 : }
731 :
732 7509 : return -1;
733 : }
734 :
735 : /**********************************************************************
736 : * CSLTokenizeString()
737 : **********************************************************************/
738 :
739 : /** Tokenizes a string and returns a StringList with one string for
740 : * each token.
741 : */
742 175575 : char **CSLTokenizeString(const char *pszString)
743 : {
744 175575 : return CSLTokenizeString2(pszString, " ", CSLT_HONOURSTRINGS);
745 : }
746 :
747 : /************************************************************************/
748 : /* CSLTokenizeStringComplex() */
749 : /************************************************************************/
750 :
751 : /** Obsolete tokenizing api. Use CSLTokenizeString2() */
752 556937 : char **CSLTokenizeStringComplex(const char *pszString,
753 : const char *pszDelimiters, int bHonourStrings,
754 : int bAllowEmptyTokens)
755 : {
756 556937 : int nFlags = 0;
757 :
758 556937 : if (bHonourStrings)
759 120950 : nFlags |= CSLT_HONOURSTRINGS;
760 556937 : if (bAllowEmptyTokens)
761 17257 : nFlags |= CSLT_ALLOWEMPTYTOKENS;
762 :
763 556937 : return CSLTokenizeString2(pszString, pszDelimiters, nFlags);
764 : }
765 :
766 : /************************************************************************/
767 : /* CSLTokenizeString2() */
768 : /************************************************************************/
769 :
770 : /**
771 : * Tokenize a string.
772 : *
773 : * This function will split a string into tokens based on specified'
774 : * delimiter(s) with a variety of options. The returned result is a
775 : * string list that should be freed with CSLDestroy() when no longer
776 : * needed.
777 : *
778 : * The available parsing options are:
779 : *
780 : * - CSLT_ALLOWEMPTYTOKENS: allow the return of empty tokens when two
781 : * delimiters in a row occur with no other text between them. If not set,
782 : * empty tokens will be discarded;
783 : * - CSLT_STRIPLEADSPACES: strip leading space characters from the token (as
784 : * reported by isspace());
785 : * - CSLT_STRIPENDSPACES: strip ending space characters from the token (as
786 : * reported by isspace());
787 : * - CSLT_HONOURSTRINGS: double quotes can be used to hold values that should
788 : * not be broken into multiple tokens;
789 : * - CSLT_PRESERVEQUOTES: string quotes are carried into the tokens when this
790 : * is set, otherwise they are removed;
791 : * - CSLT_PRESERVEESCAPES: if set backslash escapes (for backslash itself,
792 : * and for literal double quotes) will be preserved in the tokens, otherwise
793 : * the backslashes will be removed in processing.
794 : *
795 : * \b Example:
796 : *
797 : * Parse a string into tokens based on various white space (space, newline,
798 : * tab) and then print out results and cleanup. Quotes may be used to hold
799 : * white space in tokens.
800 :
801 : \code
802 : char **papszTokens =
803 : CSLTokenizeString2( pszCommand, " \t\n",
804 : CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS );
805 :
806 : for( int i = 0; papszTokens != NULL && papszTokens[i] != NULL; ++i )
807 : printf( "arg %d: '%s'", papszTokens[i] ); // ok
808 :
809 : CSLDestroy( papszTokens );
810 : \endcode
811 :
812 : * @param pszString the string to be split into tokens.
813 : * @param pszDelimiters one or more characters to be used as token delimiters.
814 : * @param nCSLTFlags an ORing of one or more of the CSLT_ flag values.
815 : *
816 : * @return a string list of tokens owned by the caller.
817 : */
818 :
819 1169340 : char **CSLTokenizeString2(const char *pszString, const char *pszDelimiters,
820 : int nCSLTFlags)
821 : {
822 1169340 : if (pszString == nullptr)
823 3868 : return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
824 :
825 2330950 : CPLStringList oRetList;
826 1165470 : const bool bHonourStrings = (nCSLTFlags & CSLT_HONOURSTRINGS) != 0;
827 1165470 : const bool bAllowEmptyTokens = (nCSLTFlags & CSLT_ALLOWEMPTYTOKENS) != 0;
828 1165470 : const bool bStripLeadSpaces = (nCSLTFlags & CSLT_STRIPLEADSPACES) != 0;
829 1165470 : const bool bStripEndSpaces = (nCSLTFlags & CSLT_STRIPENDSPACES) != 0;
830 :
831 1165470 : char *pszToken = static_cast<char *>(CPLCalloc(10, 1));
832 1165470 : size_t nTokenMax = 10;
833 :
834 3826020 : while (*pszString != '\0')
835 : {
836 2660550 : bool bInString = false;
837 2660550 : bool bStartString = true;
838 2660550 : size_t nTokenLen = 0;
839 :
840 : // Try to find the next delimiter, marking end of token.
841 34984600 : for (; *pszString != '\0'; ++pszString)
842 : {
843 : // Extend token buffer if we are running close to its end.
844 33875300 : if (nTokenLen >= nTokenMax - 3)
845 : {
846 920936 : if (nTokenMax > std::numeric_limits<size_t>::max() / 2)
847 : {
848 0 : CPLFree(pszToken);
849 0 : return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
850 : }
851 920936 : nTokenMax = nTokenMax * 2;
852 : char *pszNewToken = static_cast<char *>(
853 920936 : VSI_REALLOC_VERBOSE(pszToken, nTokenMax));
854 920936 : if (pszNewToken == nullptr)
855 : {
856 0 : CPLFree(pszToken);
857 0 : return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
858 : }
859 920936 : pszToken = pszNewToken;
860 : }
861 :
862 : // End if this is a delimiter skip it and break.
863 33875300 : if (!bInString && strchr(pszDelimiters, *pszString) != nullptr)
864 : {
865 1551160 : ++pszString;
866 1551160 : break;
867 : }
868 :
869 : // If this is a quote, and we are honouring constant
870 : // strings, then process the constant strings, with out delim
871 : // but don't copy over the quotes.
872 32324100 : if (bHonourStrings && *pszString == '"')
873 : {
874 73717 : if (nCSLTFlags & CSLT_PRESERVEQUOTES)
875 : {
876 4601 : pszToken[nTokenLen] = *pszString;
877 4601 : ++nTokenLen;
878 : }
879 :
880 73717 : bInString = !bInString;
881 73717 : continue;
882 : }
883 :
884 : /*
885 : * Within string constants we allow for escaped quotes, but in
886 : * processing them we will unescape the quotes and \\ sequence
887 : * reduces to \
888 : */
889 32250400 : if (bInString && pszString[0] == '\\')
890 : {
891 112 : if (pszString[1] == '"' || pszString[1] == '\\')
892 : {
893 46 : if (nCSLTFlags & CSLT_PRESERVEESCAPES)
894 : {
895 6 : pszToken[nTokenLen] = *pszString;
896 6 : ++nTokenLen;
897 : }
898 :
899 46 : ++pszString;
900 : }
901 : }
902 :
903 : // Strip spaces at the token start if requested.
904 32250400 : if (!bInString && bStripLeadSpaces && bStartString &&
905 31736 : isspace(static_cast<unsigned char>(*pszString)))
906 4658 : continue;
907 :
908 32245700 : bStartString = false;
909 :
910 32245700 : pszToken[nTokenLen] = *pszString;
911 32245700 : ++nTokenLen;
912 : }
913 :
914 : // Strip spaces at the token end if requested.
915 2660550 : if (!bInString && bStripEndSpaces)
916 : {
917 32598 : while (nTokenLen &&
918 27462 : isspace(static_cast<unsigned char>(pszToken[nTokenLen - 1])))
919 38 : nTokenLen--;
920 : }
921 :
922 2660550 : pszToken[nTokenLen] = '\0';
923 :
924 : // Add the token.
925 2660550 : if (pszToken[0] != '\0' || bAllowEmptyTokens)
926 2541450 : oRetList.AddString(pszToken);
927 : }
928 :
929 : /*
930 : * If the last token was empty, then we need to capture
931 : * it now, as the loop would skip it.
932 : */
933 1191400 : if (*pszString == '\0' && bAllowEmptyTokens && oRetList.Count() > 0 &&
934 25929 : strchr(pszDelimiters, *(pszString - 1)) != nullptr)
935 : {
936 1235 : oRetList.AddString("");
937 : }
938 :
939 1165470 : CPLFree(pszToken);
940 :
941 1165470 : if (oRetList.List() == nullptr)
942 : {
943 : // Prefer to return empty lists as a pointer to
944 : // a null pointer since some client code might depend on this.
945 25049 : oRetList.Assign(static_cast<char **>(CPLCalloc(sizeof(char *), 1)));
946 : }
947 :
948 1165470 : return oRetList.StealList();
949 : }
950 :
951 : /**********************************************************************
952 : * CPLSPrintf()
953 : *
954 : * NOTE: This function should move to cpl_conv.cpp.
955 : **********************************************************************/
956 :
957 : // For now, assume that a 8000 chars buffer will be enough.
958 : constexpr int CPLSPrintf_BUF_SIZE = 8000;
959 : constexpr int CPLSPrintf_BUF_Count = 10;
960 :
961 : /** CPLSPrintf() that works with 10 static buffer.
962 : *
963 : * It returns a ref. to a static buffer that should not be freed and
964 : * is valid only until the next call to CPLSPrintf().
965 : */
966 :
967 1214860 : const char *CPLSPrintf(CPL_FORMAT_STRING(const char *fmt), ...)
968 : {
969 : va_list args;
970 :
971 : /* -------------------------------------------------------------------- */
972 : /* Get the thread local buffer ring data. */
973 : /* -------------------------------------------------------------------- */
974 1214860 : char *pachBufRingInfo = static_cast<char *>(CPLGetTLS(CTLS_CPLSPRINTF));
975 :
976 1214840 : if (pachBufRingInfo == nullptr)
977 : {
978 1412 : pachBufRingInfo = static_cast<char *>(CPLCalloc(
979 : 1, sizeof(int) + CPLSPrintf_BUF_Count * CPLSPrintf_BUF_SIZE));
980 1412 : CPLSetTLS(CTLS_CPLSPRINTF, pachBufRingInfo, TRUE);
981 : }
982 :
983 : /* -------------------------------------------------------------------- */
984 : /* Work out which string in the "ring" we want to use this */
985 : /* time. */
986 : /* -------------------------------------------------------------------- */
987 1214840 : int *pnBufIndex = reinterpret_cast<int *>(pachBufRingInfo);
988 1214840 : const size_t nOffset = sizeof(int) + *pnBufIndex * CPLSPrintf_BUF_SIZE;
989 1214840 : char *pachBuffer = pachBufRingInfo + nOffset;
990 :
991 1214840 : *pnBufIndex = (*pnBufIndex + 1) % CPLSPrintf_BUF_Count;
992 :
993 : /* -------------------------------------------------------------------- */
994 : /* Format the result. */
995 : /* -------------------------------------------------------------------- */
996 :
997 1214840 : va_start(args, fmt);
998 :
999 : const int ret =
1000 1214840 : CPLvsnprintf(pachBuffer, CPLSPrintf_BUF_SIZE - 1, fmt, args);
1001 1214840 : if (ret < 0 || ret >= CPLSPrintf_BUF_SIZE - 1)
1002 : {
1003 5 : CPLError(CE_Failure, CPLE_AppDefined,
1004 : "CPLSPrintf() called with too "
1005 : "big string. Output will be truncated !");
1006 : }
1007 :
1008 1214830 : va_end(args);
1009 :
1010 1214830 : return pachBuffer;
1011 : }
1012 :
1013 : /**********************************************************************
1014 : * CSLAppendPrintf()
1015 : **********************************************************************/
1016 :
1017 : /** Use CPLSPrintf() to append a new line at the end of a StringList.
1018 : * Returns the modified StringList.
1019 : */
1020 87 : char **CSLAppendPrintf(char **papszStrList, CPL_FORMAT_STRING(const char *fmt),
1021 : ...)
1022 : {
1023 : va_list args;
1024 :
1025 87 : va_start(args, fmt);
1026 174 : CPLString osWork;
1027 87 : osWork.vPrintf(fmt, args);
1028 87 : va_end(args);
1029 :
1030 174 : return CSLAddString(papszStrList, osWork);
1031 : }
1032 :
1033 : /************************************************************************/
1034 : /* CPLVASPrintf() */
1035 : /************************************************************************/
1036 :
1037 : /** This is intended to serve as an easy to use C callable vasprintf()
1038 : * alternative. Used in the GeoJSON library for instance */
1039 0 : int CPLVASPrintf(char **buf, CPL_FORMAT_STRING(const char *fmt), va_list ap)
1040 :
1041 : {
1042 0 : CPLString osWork;
1043 :
1044 0 : osWork.vPrintf(fmt, ap);
1045 :
1046 0 : if (buf)
1047 0 : *buf = CPLStrdup(osWork.c_str());
1048 :
1049 0 : return static_cast<int>(osWork.size());
1050 : }
1051 :
1052 : /************************************************************************/
1053 : /* CPLvsnprintf_get_end_of_formatting() */
1054 : /************************************************************************/
1055 :
1056 3921250 : static const char *CPLvsnprintf_get_end_of_formatting(const char *fmt)
1057 : {
1058 3921250 : char ch = '\0';
1059 : // Flag.
1060 5106040 : for (; (ch = *fmt) != '\0'; ++fmt)
1061 : {
1062 5105960 : if (ch == '\'')
1063 0 : continue; // Bad idea as this is locale specific.
1064 5105960 : if (ch == '-' || ch == '+' || ch == ' ' || ch == '#' || ch == '0')
1065 1184790 : continue;
1066 3921170 : break;
1067 : }
1068 :
1069 : // Field width.
1070 5274570 : for (; (ch = *fmt) != '\0'; ++fmt)
1071 : {
1072 5274540 : if (ch == '$')
1073 0 : return nullptr; // Do not support this.
1074 5274540 : if (*fmt >= '0' && *fmt <= '9')
1075 1353310 : continue;
1076 3921230 : break;
1077 : }
1078 :
1079 : // Precision.
1080 3921250 : if (ch == '.')
1081 : {
1082 692044 : ++fmt;
1083 1959130 : for (; (ch = *fmt) != '\0'; ++fmt)
1084 : {
1085 1959130 : if (ch == '$')
1086 0 : return nullptr; // Do not support this.
1087 1959130 : if (*fmt >= '0' && *fmt <= '9')
1088 1267090 : continue;
1089 692044 : break;
1090 : }
1091 : }
1092 :
1093 : // Length modifier.
1094 4002140 : for (; (ch = *fmt) != '\0'; ++fmt)
1095 : {
1096 4002140 : if (ch == 'h' || ch == 'l' || ch == 'j' || ch == 'z' || ch == 't' ||
1097 : ch == 'L')
1098 80997 : continue;
1099 3921140 : else if (ch == 'I' && fmt[1] == '6' && fmt[2] == '4')
1100 0 : fmt += 2;
1101 : else
1102 3921250 : return fmt;
1103 : }
1104 :
1105 0 : return nullptr;
1106 : }
1107 :
1108 : /************************************************************************/
1109 : /* CPLvsnprintf() */
1110 : /************************************************************************/
1111 :
1112 : #define call_native_snprintf(type) \
1113 : local_ret = snprintf(str + offset_out, size - offset_out, localfmt, \
1114 : va_arg(wrk_args, type))
1115 :
1116 : /** vsnprintf() wrapper that is not sensitive to LC_NUMERIC settings.
1117 : *
1118 : * This function has the same contract as standard vsnprintf(), except that
1119 : * formatting of floating-point numbers will use decimal point, whatever the
1120 : * current locale is set.
1121 : *
1122 : * @param str output buffer
1123 : * @param size size of the output buffer (including space for terminating nul)
1124 : * @param fmt formatting string
1125 : * @param args arguments
1126 : * @return the number of characters (excluding terminating nul) that would be
1127 : * written if size is big enough. Or potentially -1 with Microsoft C runtime
1128 : * for Visual Studio < 2015.
1129 : * @since GDAL 2.0
1130 : */
1131 2108840 : int CPLvsnprintf(char *str, size_t size, CPL_FORMAT_STRING(const char *fmt),
1132 : va_list args)
1133 : {
1134 2108840 : if (size == 0)
1135 0 : return vsnprintf(str, size, fmt, args);
1136 :
1137 : va_list wrk_args;
1138 :
1139 : #ifdef va_copy
1140 2108840 : va_copy(wrk_args, args);
1141 : #else
1142 : wrk_args = args;
1143 : #endif
1144 :
1145 2108840 : const char *fmt_ori = fmt;
1146 2108840 : size_t offset_out = 0;
1147 2108840 : char ch = '\0';
1148 2108840 : bool bFormatUnknown = false;
1149 :
1150 32599400 : for (; (ch = *fmt) != '\0'; ++fmt)
1151 : {
1152 30493000 : if (ch == '%')
1153 : {
1154 3922020 : if (strncmp(fmt, "%.*f", 4) == 0)
1155 : {
1156 792 : const int precision = va_arg(wrk_args, int);
1157 792 : const double val = va_arg(wrk_args, double);
1158 : const int local_ret =
1159 871 : snprintf(str + offset_out, size - offset_out, "%.*f",
1160 : precision, val);
1161 : // MSVC vsnprintf() returns -1.
1162 871 : if (local_ret < 0 || offset_out + local_ret >= size)
1163 : break;
1164 15926 : for (int j = 0; j < local_ret; ++j)
1165 : {
1166 15134 : if (str[offset_out + j] == ',')
1167 : {
1168 0 : str[offset_out + j] = '.';
1169 0 : break;
1170 : }
1171 : }
1172 792 : offset_out += local_ret;
1173 792 : fmt += strlen("%.*f") - 1;
1174 792 : continue;
1175 : }
1176 :
1177 3921220 : const char *ptrend = CPLvsnprintf_get_end_of_formatting(fmt + 1);
1178 3921140 : if (ptrend == nullptr || ptrend - fmt >= 20)
1179 : {
1180 0 : bFormatUnknown = true;
1181 0 : break;
1182 : }
1183 3921250 : char end = *ptrend;
1184 3921250 : char end_m1 = ptrend[-1];
1185 :
1186 3921250 : char localfmt[22] = {};
1187 3921250 : memcpy(localfmt, fmt, ptrend - fmt + 1);
1188 3921250 : localfmt[ptrend - fmt + 1] = '\0';
1189 :
1190 3921250 : int local_ret = 0;
1191 3921250 : if (end == '%')
1192 : {
1193 14387 : if (offset_out == size - 1)
1194 0 : break;
1195 14387 : local_ret = 1;
1196 14387 : str[offset_out] = '%';
1197 : }
1198 3906860 : else if (end == 'd' || end == 'i' || end == 'c')
1199 : {
1200 932680 : if (end_m1 == 'h')
1201 0 : call_native_snprintf(int);
1202 932680 : else if (end_m1 == 'l' && ptrend[-2] != 'l')
1203 2149 : call_native_snprintf(long);
1204 930531 : else if (end_m1 == 'l' && ptrend[-2] == 'l')
1205 23473 : call_native_snprintf(GIntBig);
1206 907058 : else if (end_m1 == '4' && ptrend[-2] == '6' &&
1207 0 : ptrend[-3] == 'I')
1208 : // Microsoft I64 modifier.
1209 0 : call_native_snprintf(GIntBig);
1210 907058 : else if (end_m1 == 'z')
1211 0 : call_native_snprintf(size_t);
1212 907058 : else if ((end_m1 >= 'a' && end_m1 <= 'z') ||
1213 0 : (end_m1 >= 'A' && end_m1 <= 'Z'))
1214 : {
1215 0 : bFormatUnknown = true;
1216 0 : break;
1217 : }
1218 : else
1219 907058 : call_native_snprintf(int);
1220 : }
1221 2974180 : else if (end == 'o' || end == 'u' || end == 'x' || end == 'X')
1222 : {
1223 1201010 : if (end_m1 == 'h')
1224 0 : call_native_snprintf(unsigned int);
1225 1201010 : else if (end_m1 == 'l' && ptrend[-2] != 'l')
1226 428 : call_native_snprintf(unsigned long);
1227 1200580 : else if (end_m1 == 'l' && ptrend[-2] == 'l')
1228 12730 : call_native_snprintf(GUIntBig);
1229 1187850 : else if (end_m1 == '4' && ptrend[-2] == '6' &&
1230 0 : ptrend[-3] == 'I')
1231 : // Microsoft I64 modifier.
1232 0 : call_native_snprintf(GUIntBig);
1233 1187850 : else if (end_m1 == 'z')
1234 0 : call_native_snprintf(size_t);
1235 1187850 : else if ((end_m1 >= 'a' && end_m1 <= 'z') ||
1236 0 : (end_m1 >= 'A' && end_m1 <= 'Z'))
1237 : {
1238 0 : bFormatUnknown = true;
1239 0 : break;
1240 : }
1241 : else
1242 1187850 : call_native_snprintf(unsigned int);
1243 : }
1244 1773180 : else if (end == 'e' || end == 'E' || end == 'f' || end == 'F' ||
1245 1058020 : end == 'g' || end == 'G' || end == 'a' || end == 'A')
1246 : {
1247 715090 : if (end_m1 == 'L')
1248 0 : call_native_snprintf(long double);
1249 : else
1250 715090 : call_native_snprintf(double);
1251 : // MSVC vsnprintf() returns -1.
1252 715129 : if (local_ret < 0 || offset_out + local_ret >= size)
1253 : break;
1254 10186300 : for (int j = 0; j < local_ret; ++j)
1255 : {
1256 9471300 : if (str[offset_out + j] == ',')
1257 : {
1258 0 : str[offset_out + j] = '.';
1259 0 : break;
1260 : }
1261 715037 : }
1262 : }
1263 1058080 : else if (end == 's')
1264 : {
1265 1054110 : const char *pszPtr = va_arg(wrk_args, const char *);
1266 1054140 : CPLAssert(pszPtr);
1267 1054070 : local_ret = snprintf(str + offset_out, size - offset_out,
1268 : localfmt, pszPtr);
1269 : }
1270 3978 : else if (end == 'p')
1271 : {
1272 3160 : call_native_snprintf(void *);
1273 : }
1274 : else
1275 : {
1276 818 : bFormatUnknown = true;
1277 818 : break;
1278 : }
1279 : // MSVC vsnprintf() returns -1.
1280 3920240 : if (local_ret < 0 || offset_out + local_ret >= size)
1281 : break;
1282 3919400 : offset_out += local_ret;
1283 3919400 : fmt = ptrend;
1284 : }
1285 : else
1286 : {
1287 26571000 : if (offset_out == size - 1)
1288 587 : break;
1289 26570400 : str[offset_out++] = *fmt;
1290 : }
1291 : }
1292 2108740 : if (ch == '\0' && offset_out < size)
1293 2106430 : str[offset_out] = '\0';
1294 : else
1295 : {
1296 2309 : if (bFormatUnknown)
1297 : {
1298 784 : CPLDebug("CPL",
1299 : "CPLvsnprintf() called with unsupported "
1300 : "formatting string: %s",
1301 : fmt_ori);
1302 : }
1303 : #ifdef va_copy
1304 2300 : va_end(wrk_args);
1305 2300 : va_copy(wrk_args, args);
1306 : #else
1307 : wrk_args = args;
1308 : #endif
1309 : #if defined(HAVE_VSNPRINTF)
1310 2300 : offset_out = vsnprintf(str, size, fmt_ori, wrk_args);
1311 : #else
1312 : offset_out = vsprintf(str, fmt_ori, wrk_args);
1313 : #endif
1314 : }
1315 :
1316 : #ifdef va_copy
1317 2108730 : va_end(wrk_args);
1318 : #endif
1319 :
1320 2108730 : return static_cast<int>(offset_out);
1321 : }
1322 :
1323 : /************************************************************************/
1324 : /* CPLsnprintf() */
1325 : /************************************************************************/
1326 :
1327 : #if !defined(ALIAS_CPLSNPRINTF_AS_SNPRINTF)
1328 :
1329 : #if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ <= 2
1330 : #pragma clang diagnostic push
1331 : #pragma clang diagnostic ignored "-Wunknown-pragmas"
1332 : #pragma clang diagnostic ignored "-Wdocumentation"
1333 : #endif
1334 :
1335 : /** snprintf() wrapper that is not sensitive to LC_NUMERIC settings.
1336 : *
1337 : * This function has the same contract as standard snprintf(), except that
1338 : * formatting of floating-point numbers will use decimal point, whatever the
1339 : * current locale is set.
1340 : *
1341 : * @param str output buffer
1342 : * @param size size of the output buffer (including space for terminating nul)
1343 : * @param fmt formatting string
1344 : * @param ... arguments
1345 : * @return the number of characters (excluding terminating nul) that would be
1346 : * written if size is big enough. Or potentially -1 with Microsoft C runtime
1347 : * for Visual Studio < 2015.
1348 : * @since GDAL 2.0
1349 : */
1350 :
1351 172695 : int CPLsnprintf(char *str, size_t size, CPL_FORMAT_STRING(const char *fmt), ...)
1352 : {
1353 : va_list args;
1354 :
1355 172695 : va_start(args, fmt);
1356 172695 : const int ret = CPLvsnprintf(str, size, fmt, args);
1357 172694 : va_end(args);
1358 172694 : return ret;
1359 : }
1360 :
1361 : #endif // !defined(ALIAS_CPLSNPRINTF_AS_SNPRINTF)
1362 :
1363 : /************************************************************************/
1364 : /* CPLsprintf() */
1365 : /************************************************************************/
1366 :
1367 : /** sprintf() wrapper that is not sensitive to LC_NUMERIC settings.
1368 : *
1369 : * This function has the same contract as standard sprintf(), except that
1370 : * formatting of floating-point numbers will use decimal point, whatever the
1371 : * current locale is set.
1372 : *
1373 : * @param str output buffer (must be large enough to hold the result)
1374 : * @param fmt formatting string
1375 : * @param ... arguments
1376 : * @return the number of characters (excluding terminating nul) written in
1377 : ` * output buffer.
1378 : * @since GDAL 2.0
1379 : */
1380 0 : int CPLsprintf(char *str, CPL_FORMAT_STRING(const char *fmt), ...)
1381 : {
1382 : va_list args;
1383 :
1384 0 : va_start(args, fmt);
1385 0 : const int ret = CPLvsnprintf(str, INT_MAX, fmt, args);
1386 0 : va_end(args);
1387 0 : return ret;
1388 : }
1389 :
1390 : /************************************************************************/
1391 : /* CPLprintf() */
1392 : /************************************************************************/
1393 :
1394 : /** printf() wrapper that is not sensitive to LC_NUMERIC settings.
1395 : *
1396 : * This function has the same contract as standard printf(), except that
1397 : * formatting of floating-point numbers will use decimal point, whatever the
1398 : * current locale is set.
1399 : *
1400 : * @param fmt formatting string
1401 : * @param ... arguments
1402 : * @return the number of characters (excluding terminating nul) written in
1403 : * output buffer.
1404 : * @since GDAL 2.0
1405 : */
1406 157 : int CPLprintf(CPL_FORMAT_STRING(const char *fmt), ...)
1407 : {
1408 : va_list wrk_args, args;
1409 :
1410 157 : va_start(args, fmt);
1411 :
1412 : #ifdef va_copy
1413 157 : va_copy(wrk_args, args);
1414 : #else
1415 : wrk_args = args;
1416 : #endif
1417 :
1418 157 : char szBuffer[4096] = {};
1419 : // Quiet coverity by staring off nul terminated.
1420 157 : int ret = CPLvsnprintf(szBuffer, sizeof(szBuffer), fmt, wrk_args);
1421 :
1422 : #ifdef va_copy
1423 157 : va_end(wrk_args);
1424 : #endif
1425 :
1426 157 : if (ret < int(sizeof(szBuffer)) - 1)
1427 157 : ret = printf("%s", szBuffer); /*ok*/
1428 : else
1429 : {
1430 : #ifdef va_copy
1431 0 : va_copy(wrk_args, args);
1432 : #else
1433 : wrk_args = args;
1434 : #endif
1435 :
1436 0 : ret = vfprintf(stdout, fmt, wrk_args);
1437 :
1438 : #ifdef va_copy
1439 0 : va_end(wrk_args);
1440 : #endif
1441 : }
1442 :
1443 157 : va_end(args);
1444 :
1445 157 : return ret;
1446 : }
1447 :
1448 : /************************************************************************/
1449 : /* CPLsscanf() */
1450 : /************************************************************************/
1451 :
1452 : /** \brief sscanf() wrapper that is not sensitive to LC_NUMERIC settings.
1453 : *
1454 : * This function has the same contract as standard sscanf(), except that
1455 : * formatting of floating-point numbers will use decimal point, whatever the
1456 : * current locale is set.
1457 : *
1458 : * CAUTION: only works with a very limited number of formatting strings,
1459 : * consisting only of "%lf" and regular characters.
1460 : *
1461 : * @param str input string
1462 : * @param fmt formatting string
1463 : * @param ... arguments
1464 : * @return the number of matched patterns;
1465 : * @since GDAL 2.0
1466 : */
1467 : #ifdef DOXYGEN_XML
1468 : int CPLsscanf(const char *str, const char *fmt, ...)
1469 : #else
1470 1806 : int CPLsscanf(const char *str, CPL_SCANF_FORMAT_STRING(const char *fmt), ...)
1471 : #endif
1472 : {
1473 1806 : bool error = false;
1474 1806 : int ret = 0;
1475 1806 : const char *fmt_ori = fmt;
1476 : va_list args;
1477 :
1478 1806 : va_start(args, fmt);
1479 13891 : for (; *fmt != '\0' && *str != '\0'; ++fmt)
1480 : {
1481 12085 : if (*fmt == '%')
1482 : {
1483 6927 : if (fmt[1] == 'l' && fmt[2] == 'f')
1484 : {
1485 6927 : fmt += 2;
1486 : char *end;
1487 6927 : *(va_arg(args, double *)) = CPLStrtod(str, &end);
1488 6927 : if (end > str)
1489 : {
1490 6927 : ++ret;
1491 6927 : str = end;
1492 : }
1493 : else
1494 6927 : break;
1495 : }
1496 : else
1497 : {
1498 0 : error = true;
1499 0 : break;
1500 : }
1501 : }
1502 5158 : else if (isspace(static_cast<unsigned char>(*fmt)))
1503 : {
1504 1754 : while (*str != '\0' && isspace(static_cast<unsigned char>(*str)))
1505 877 : ++str;
1506 : }
1507 4281 : else if (*str != *fmt)
1508 0 : break;
1509 : else
1510 4281 : ++str;
1511 : }
1512 1806 : va_end(args);
1513 :
1514 1806 : if (error)
1515 : {
1516 0 : CPLError(CE_Failure, CPLE_NotSupported,
1517 : "Format %s not supported by CPLsscanf()", fmt_ori);
1518 : }
1519 :
1520 1806 : return ret;
1521 : }
1522 :
1523 : #if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ <= 2
1524 : #pragma clang diagnostic pop
1525 : #endif
1526 :
1527 : /************************************************************************/
1528 : /* CPLTestBool() */
1529 : /************************************************************************/
1530 :
1531 : /**
1532 : * Test what boolean value contained in the string.
1533 : *
1534 : * If pszValue is "NO", "FALSE", "OFF" or "0" will be returned false.
1535 : * Otherwise, true will be returned.
1536 : *
1537 : * @param pszValue the string should be tested.
1538 : *
1539 : * @return true or false.
1540 : */
1541 :
1542 2445460 : bool CPLTestBool(const char *pszValue)
1543 : {
1544 3148000 : return !(EQUAL(pszValue, "NO") || EQUAL(pszValue, "FALSE") ||
1545 3148000 : EQUAL(pszValue, "OFF") || EQUAL(pszValue, "0"));
1546 : }
1547 :
1548 : /************************************************************************/
1549 : /* CSLTestBoolean() */
1550 : /************************************************************************/
1551 :
1552 : /**
1553 : * Test what boolean value contained in the string.
1554 : *
1555 : * If pszValue is "NO", "FALSE", "OFF" or "0" will be returned FALSE.
1556 : * Otherwise, TRUE will be returned.
1557 : *
1558 : * Deprecated. Removed in GDAL 3.x.
1559 : *
1560 : * Use CPLTestBoolean() for C and CPLTestBool() for C++.
1561 : *
1562 : * @param pszValue the string should be tested.
1563 : *
1564 : * @return TRUE or FALSE.
1565 : */
1566 :
1567 655 : int CSLTestBoolean(const char *pszValue)
1568 : {
1569 655 : return CPLTestBool(pszValue) ? TRUE : FALSE;
1570 : }
1571 :
1572 : /************************************************************************/
1573 : /* CPLTestBoolean() */
1574 : /************************************************************************/
1575 :
1576 : /**
1577 : * Test what boolean value contained in the string.
1578 : *
1579 : * If pszValue is "NO", "FALSE", "OFF" or "0" will be returned FALSE.
1580 : * Otherwise, TRUE will be returned.
1581 : *
1582 : * Use this only in C code. In C++, prefer CPLTestBool().
1583 : *
1584 : * @param pszValue the string should be tested.
1585 : *
1586 : * @return TRUE or FALSE.
1587 : */
1588 :
1589 40 : int CPLTestBoolean(const char *pszValue)
1590 : {
1591 40 : return CPLTestBool(pszValue) ? TRUE : FALSE;
1592 : }
1593 :
1594 : /**********************************************************************
1595 : * CPLFetchBool()
1596 : **********************************************************************/
1597 :
1598 : /** Check for boolean key value.
1599 : *
1600 : * In a StringList of "Name=Value" pairs, look to see if there is a key
1601 : * with the given name, and if it can be interpreted as being TRUE. If
1602 : * the key appears without any "=Value" portion it will be considered true.
1603 : * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
1604 : * if the key appears in the list it will be considered TRUE. If the key
1605 : * doesn't appear at all, the indicated default value will be returned.
1606 : *
1607 : * @param papszStrList the string list to search.
1608 : * @param pszKey the key value to look for (case insensitive).
1609 : * @param bDefault the value to return if the key isn't found at all.
1610 : *
1611 : * @return true or false
1612 : */
1613 :
1614 222498 : bool CPLFetchBool(CSLConstList papszStrList, const char *pszKey, bool bDefault)
1615 :
1616 : {
1617 222498 : if (CSLFindString(papszStrList, pszKey) != -1)
1618 2 : return true;
1619 :
1620 222381 : const char *const pszValue = CSLFetchNameValue(papszStrList, pszKey);
1621 222430 : if (pszValue == nullptr)
1622 207921 : return bDefault;
1623 :
1624 14509 : return CPLTestBool(pszValue);
1625 : }
1626 :
1627 : /**********************************************************************
1628 : * CSLFetchBoolean()
1629 : **********************************************************************/
1630 :
1631 : /** DEPRECATED. Check for boolean key value.
1632 : *
1633 : * In a StringList of "Name=Value" pairs, look to see if there is a key
1634 : * with the given name, and if it can be interpreted as being TRUE. If
1635 : * the key appears without any "=Value" portion it will be considered true.
1636 : * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
1637 : * if the key appears in the list it will be considered TRUE. If the key
1638 : * doesn't appear at all, the indicated default value will be returned.
1639 : *
1640 : * @param papszStrList the string list to search.
1641 : * @param pszKey the key value to look for (case insensitive).
1642 : * @param bDefault the value to return if the key isn't found at all.
1643 : *
1644 : * @return TRUE or FALSE
1645 : */
1646 :
1647 1366 : int CSLFetchBoolean(CSLConstList papszStrList, const char *pszKey, int bDefault)
1648 :
1649 : {
1650 1366 : return CPLFetchBool(papszStrList, pszKey, CPL_TO_BOOL(bDefault));
1651 : }
1652 :
1653 : /************************************************************************/
1654 : /* CSLFetchNameValueDefaulted() */
1655 : /************************************************************************/
1656 :
1657 : /** Same as CSLFetchNameValue() but return pszDefault in case of no match */
1658 449950 : const char *CSLFetchNameValueDef(CSLConstList papszStrList, const char *pszName,
1659 : const char *pszDefault)
1660 :
1661 : {
1662 449950 : const char *pszResult = CSLFetchNameValue(papszStrList, pszName);
1663 449910 : if (pszResult != nullptr)
1664 41087 : return pszResult;
1665 :
1666 408823 : return pszDefault;
1667 : }
1668 :
1669 : /**********************************************************************
1670 : * CSLFetchNameValue()
1671 : **********************************************************************/
1672 :
1673 : /** In a StringList of "Name=Value" pairs, look for the
1674 : * first value associated with the specified name. The search is not
1675 : * case sensitive.
1676 : * ("Name:Value" pairs are also supported for backward compatibility
1677 : * with older stuff.)
1678 : *
1679 : * Returns a reference to the value in the StringList that the caller
1680 : * should not attempt to free.
1681 : *
1682 : * Returns NULL if the name is not found.
1683 : */
1684 :
1685 13112600 : const char *CSLFetchNameValue(CSLConstList papszStrList, const char *pszName)
1686 : {
1687 13112600 : if (papszStrList == nullptr || pszName == nullptr)
1688 3975570 : return nullptr;
1689 :
1690 9137000 : const size_t nLen = strlen(pszName);
1691 13806500 : while (*papszStrList != nullptr)
1692 : {
1693 4851570 : if (EQUALN(*papszStrList, pszName, nLen) &&
1694 185057 : ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
1695 : {
1696 182093 : return (*papszStrList) + nLen + 1;
1697 : }
1698 4669480 : ++papszStrList;
1699 : }
1700 8954900 : return nullptr;
1701 : }
1702 :
1703 : /************************************************************************/
1704 : /* CSLFindName() */
1705 : /************************************************************************/
1706 :
1707 : /**
1708 : * Find StringList entry with given key name.
1709 : *
1710 : * @param papszStrList the string list to search.
1711 : * @param pszName the key value to look for (case insensitive).
1712 : *
1713 : * @return -1 on failure or the list index of the first occurrence
1714 : * matching the given key.
1715 : */
1716 :
1717 15341800 : int CSLFindName(CSLConstList papszStrList, const char *pszName)
1718 : {
1719 15341800 : if (papszStrList == nullptr || pszName == nullptr)
1720 475363 : return -1;
1721 :
1722 14866400 : const size_t nLen = strlen(pszName);
1723 14866400 : int iIndex = 0;
1724 118955000 : while (*papszStrList != nullptr)
1725 : {
1726 111888000 : if (EQUALN(*papszStrList, pszName, nLen) &&
1727 8433920 : ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
1728 : {
1729 7799200 : return iIndex;
1730 : }
1731 104088000 : ++iIndex;
1732 104088000 : ++papszStrList;
1733 : }
1734 7067190 : return -1;
1735 : }
1736 :
1737 : /************************************************************************/
1738 : /* CPLParseMemorySize() */
1739 : /************************************************************************/
1740 :
1741 : /** Parse a memory size from a string.
1742 : *
1743 : * The string may indicate the units of the memory (e.g., "230k", "500 MB"),
1744 : * using the prefixes "k", "m", or "g" in either lower or upper-case,
1745 : * optionally followed by a "b" or "B". The string may alternatively specify
1746 : * memory as a fraction of the usable RAM (e.g., "25%"). Spaces before the
1747 : * number, between the number and the units, or after the units are ignored,
1748 : * but other characters will cause a parsing failure. If the string cannot
1749 : * be understood, the function will return CE_Failure.
1750 : *
1751 : * @param pszValue the string to parse
1752 : * @param[out] pnValue the parsed size, converted to bytes (if unit was specified)
1753 : * @param[out] pbUnitSpecified whether the string indicated the units
1754 : *
1755 : * @return CE_None on success, CE_Failure otherwise
1756 : * @since 3.10
1757 : */
1758 624 : CPLErr CPLParseMemorySize(const char *pszValue, GIntBig *pnValue,
1759 : bool *pbUnitSpecified)
1760 : {
1761 624 : const char *start = pszValue;
1762 624 : char *end = nullptr;
1763 :
1764 : // trim leading whitespace
1765 628 : while (*start == ' ')
1766 : {
1767 4 : start++;
1768 : }
1769 :
1770 624 : auto len = CPLStrnlen(start, 100);
1771 624 : double value = CPLStrtodM(start, &end);
1772 624 : const char *unit = nullptr;
1773 624 : bool unitIsNotPercent = false;
1774 :
1775 624 : if (end == start)
1776 : {
1777 3 : CPLError(CE_Failure, CPLE_IllegalArg, "Received non-numeric value: %s",
1778 : pszValue);
1779 3 : return CE_Failure;
1780 : }
1781 :
1782 621 : if (value < 0 || !std::isfinite(value))
1783 : {
1784 2 : CPLError(CE_Failure, CPLE_IllegalArg,
1785 : "Memory size must be a positive number or zero.");
1786 2 : return CE_Failure;
1787 : }
1788 :
1789 1179 : for (const char *c = end; c < start + len; c++)
1790 : {
1791 565 : if (unit == nullptr)
1792 : {
1793 : // check various suffixes and convert number into bytes
1794 557 : if (*c == '%')
1795 : {
1796 544 : if (value < 0 || value > 100)
1797 : {
1798 2 : CPLError(CE_Failure, CPLE_IllegalArg,
1799 : "Memory percentage must be between 0 and 100.");
1800 2 : return CE_Failure;
1801 : }
1802 542 : auto bytes = CPLGetUsablePhysicalRAM();
1803 542 : if (bytes == 0)
1804 : {
1805 0 : CPLError(CE_Failure, CPLE_NotSupported,
1806 : "Cannot determine usable physical RAM");
1807 0 : return CE_Failure;
1808 : }
1809 542 : value *= static_cast<double>(bytes / 100);
1810 542 : unit = c;
1811 : }
1812 : else
1813 : {
1814 13 : switch (*c)
1815 : {
1816 0 : case 'G':
1817 : case 'g':
1818 0 : value *= 1024; // fall-through
1819 4 : case 'M':
1820 : case 'm':
1821 4 : value *= 1024; // fall-through
1822 8 : case 'K':
1823 : case 'k':
1824 8 : value *= 1024;
1825 8 : unit = c;
1826 8 : unitIsNotPercent = true;
1827 8 : break;
1828 3 : case ' ':
1829 3 : break;
1830 2 : default:
1831 2 : CPLError(CE_Failure, CPLE_IllegalArg,
1832 : "Unexpected value: %s", pszValue);
1833 2 : return CE_Failure;
1834 : }
1835 : }
1836 : }
1837 8 : else if (unitIsNotPercent && c == unit + 1 && (*c == 'b' || *c == 'B'))
1838 : {
1839 : // ignore 'B' or 'b' as part of unit
1840 7 : continue;
1841 : }
1842 1 : else if (*c != ' ')
1843 : {
1844 1 : CPLError(CE_Failure, CPLE_IllegalArg, "Unexpected value: %s",
1845 : pszValue);
1846 1 : return CE_Failure;
1847 : }
1848 : }
1849 :
1850 614 : *pnValue = static_cast<GIntBig>(value);
1851 614 : if (pbUnitSpecified)
1852 : {
1853 614 : *pbUnitSpecified = (unit != nullptr);
1854 : }
1855 614 : return CE_None;
1856 : }
1857 :
1858 : /**********************************************************************
1859 : * CPLParseNameValue()
1860 : **********************************************************************/
1861 :
1862 : /**
1863 : * Parse NAME=VALUE string into name and value components.
1864 : *
1865 : * Note that if ppszKey is non-NULL, the key (or name) portion will be
1866 : * allocated using CPLMalloc(), and returned in that pointer. It is the
1867 : * applications responsibility to free this string, but the application should
1868 : * not modify or free the returned value portion.
1869 : *
1870 : * This function also support "NAME:VALUE" strings and will strip white
1871 : * space from around the delimiter when forming name and value strings.
1872 : *
1873 : * Eventually CSLFetchNameValue() and friends may be modified to use
1874 : * CPLParseNameValue().
1875 : *
1876 : * @param pszNameValue string in "NAME=VALUE" format.
1877 : * @param ppszKey optional pointer though which to return the name
1878 : * portion.
1879 : *
1880 : * @return the value portion (pointing into original string).
1881 : */
1882 :
1883 72271 : const char *CPLParseNameValue(const char *pszNameValue, char **ppszKey)
1884 : {
1885 1019700 : for (int i = 0; pszNameValue[i] != '\0'; ++i)
1886 : {
1887 1016660 : if (pszNameValue[i] == '=' || pszNameValue[i] == ':')
1888 : {
1889 69233 : const char *pszValue = pszNameValue + i + 1;
1890 77051 : while (*pszValue == ' ' || *pszValue == '\t')
1891 7818 : ++pszValue;
1892 :
1893 69233 : if (ppszKey != nullptr)
1894 : {
1895 69211 : *ppszKey = static_cast<char *>(CPLMalloc(i + 1));
1896 69211 : memcpy(*ppszKey, pszNameValue, i);
1897 69211 : (*ppszKey)[i] = '\0';
1898 69475 : while (i > 0 &&
1899 69475 : ((*ppszKey)[i - 1] == ' ' || (*ppszKey)[i - 1] == '\t'))
1900 : {
1901 264 : (*ppszKey)[i - 1] = '\0';
1902 264 : i--;
1903 : }
1904 : }
1905 :
1906 69233 : return pszValue;
1907 : }
1908 : }
1909 :
1910 3038 : return nullptr;
1911 : }
1912 :
1913 : /**********************************************************************
1914 : * CPLParseNameValueSep()
1915 : **********************************************************************/
1916 : /**
1917 : * Parse NAME<Sep>VALUE string into name and value components.
1918 : *
1919 : * This is derived directly from CPLParseNameValue() which will separate
1920 : * on '=' OR ':', here chSep is required for specifying the separator
1921 : * explicitly.
1922 : *
1923 : * @param pszNameValue string in "NAME=VALUE" format.
1924 : * @param ppszKey optional pointer though which to return the name
1925 : * portion.
1926 : * @param chSep required single char separator
1927 : * @return the value portion (pointing into original string).
1928 : */
1929 :
1930 17 : const char *CPLParseNameValueSep(const char *pszNameValue, char **ppszKey,
1931 : char chSep)
1932 : {
1933 140 : for (int i = 0; pszNameValue[i] != '\0'; ++i)
1934 : {
1935 138 : if (pszNameValue[i] == chSep)
1936 : {
1937 15 : const char *pszValue = pszNameValue + i + 1;
1938 15 : while (*pszValue == ' ' || *pszValue == '\t')
1939 0 : ++pszValue;
1940 :
1941 15 : if (ppszKey != nullptr)
1942 : {
1943 15 : *ppszKey = static_cast<char *>(CPLMalloc(i + 1));
1944 15 : memcpy(*ppszKey, pszNameValue, i);
1945 15 : (*ppszKey)[i] = '\0';
1946 15 : while (i > 0 &&
1947 15 : ((*ppszKey)[i - 1] == ' ' || (*ppszKey)[i - 1] == '\t'))
1948 : {
1949 0 : (*ppszKey)[i - 1] = '\0';
1950 0 : i--;
1951 : }
1952 : }
1953 :
1954 15 : return pszValue;
1955 : }
1956 : }
1957 :
1958 2 : return nullptr;
1959 : }
1960 :
1961 : /**********************************************************************
1962 : * CSLFetchNameValueMultiple()
1963 : **********************************************************************/
1964 :
1965 : /** In a StringList of "Name=Value" pairs, look for all the
1966 : * values with the specified name. The search is not case
1967 : * sensitive.
1968 : * ("Name:Value" pairs are also supported for backward compatibility
1969 : * with older stuff.)
1970 : *
1971 : * Returns StringList with one entry for each occurrence of the
1972 : * specified name. The StringList should eventually be destroyed
1973 : * by calling CSLDestroy().
1974 : *
1975 : * Returns NULL if the name is not found.
1976 : */
1977 :
1978 11480 : char **CSLFetchNameValueMultiple(CSLConstList papszStrList, const char *pszName)
1979 : {
1980 11480 : if (papszStrList == nullptr || pszName == nullptr)
1981 4635 : return nullptr;
1982 :
1983 6845 : const size_t nLen = strlen(pszName);
1984 6845 : char **papszValues = nullptr;
1985 17507 : while (*papszStrList != nullptr)
1986 : {
1987 10662 : if (EQUALN(*papszStrList, pszName, nLen) &&
1988 55 : ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
1989 : {
1990 55 : papszValues = CSLAddString(papszValues, (*papszStrList) + nLen + 1);
1991 : }
1992 10662 : ++papszStrList;
1993 : }
1994 :
1995 6845 : return papszValues;
1996 : }
1997 :
1998 : /**********************************************************************
1999 : * CSLAddNameValue()
2000 : **********************************************************************/
2001 :
2002 : /** Add a new entry to a StringList of "Name=Value" pairs,
2003 : * ("Name:Value" pairs are also supported for backward compatibility
2004 : * with older stuff.)
2005 : *
2006 : * This function does not check if a "Name=Value" pair already exists
2007 : * for that name and can generate multiple entries for the same name.
2008 : * Use CSLSetNameValue() if you want each name to have only one value.
2009 : *
2010 : * Returns the modified StringList.
2011 : */
2012 :
2013 393378 : char **CSLAddNameValue(char **papszStrList, const char *pszName,
2014 : const char *pszValue)
2015 : {
2016 393378 : if (pszName == nullptr || pszValue == nullptr)
2017 34 : return papszStrList;
2018 :
2019 393344 : const size_t nLen = strlen(pszName) + strlen(pszValue) + 2;
2020 393344 : char *pszLine = static_cast<char *>(CPLMalloc(nLen));
2021 393354 : snprintf(pszLine, nLen, "%s=%s", pszName, pszValue);
2022 393354 : papszStrList = CSLAddString(papszStrList, pszLine);
2023 393299 : CPLFree(pszLine);
2024 :
2025 393394 : return papszStrList;
2026 : }
2027 :
2028 : /************************************************************************/
2029 : /* CSLSetNameValue() */
2030 : /************************************************************************/
2031 :
2032 : /**
2033 : * Assign value to name in StringList.
2034 : *
2035 : * Set the value for a given name in a StringList of "Name=Value" pairs
2036 : * ("Name:Value" pairs are also supported for backward compatibility
2037 : * with older stuff.)
2038 : *
2039 : * If there is already a value for that name in the list then the value
2040 : * is changed, otherwise a new "Name=Value" pair is added.
2041 : *
2042 : * @param papszList the original list, the modified version is returned.
2043 : * @param pszName the name to be assigned a value. This should be a well
2044 : * formed token (no spaces or very special characters).
2045 : * @param pszValue the value to assign to the name. This should not contain
2046 : * any newlines (CR or LF) but is otherwise pretty much unconstrained. If
2047 : * NULL any corresponding value will be removed.
2048 : *
2049 : * @return modified StringList.
2050 : */
2051 :
2052 421020 : char **CSLSetNameValue(char **papszList, const char *pszName,
2053 : const char *pszValue)
2054 : {
2055 421020 : if (pszName == nullptr)
2056 38 : return papszList;
2057 :
2058 420982 : size_t nLen = strlen(pszName);
2059 421656 : while (nLen > 0 && pszName[nLen - 1] == ' ')
2060 674 : nLen--;
2061 420982 : char **papszPtr = papszList;
2062 7052420 : while (papszPtr && *papszPtr != nullptr)
2063 : {
2064 6668300 : if (EQUALN(*papszPtr, pszName, nLen))
2065 : {
2066 : size_t i;
2067 39254 : for (i = nLen; (*papszPtr)[i] == ' '; ++i)
2068 : {
2069 : }
2070 38580 : if ((*papszPtr)[i] == '=' || (*papszPtr)[i] == ':')
2071 : {
2072 : // Found it.
2073 : // Change the value... make sure to keep the ':' or '='.
2074 36867 : const char cSep = (*papszPtr)[i];
2075 :
2076 36867 : CPLFree(*papszPtr);
2077 :
2078 : // If the value is NULL, remove this entry completely.
2079 36849 : if (pszValue == nullptr)
2080 : {
2081 39748 : while (papszPtr[1] != nullptr)
2082 : {
2083 10420 : *papszPtr = papszPtr[1];
2084 10420 : ++papszPtr;
2085 : }
2086 29328 : *papszPtr = nullptr;
2087 : }
2088 :
2089 : // Otherwise replace with new value.
2090 : else
2091 : {
2092 7521 : const size_t nLen2 = strlen(pszName) + strlen(pszValue) + 2;
2093 7521 : *papszPtr = static_cast<char *>(CPLMalloc(nLen2));
2094 7499 : snprintf(*papszPtr, nLen2, "%s%c%s", pszName, cSep,
2095 : pszValue);
2096 : }
2097 36827 : return papszList;
2098 : }
2099 : }
2100 6631440 : ++papszPtr;
2101 : }
2102 :
2103 384115 : if (pszValue == nullptr)
2104 4281 : return papszList;
2105 :
2106 : // The name does not exist yet. Create a new entry.
2107 379834 : return CSLAddNameValue(papszList, pszName, pszValue);
2108 : }
2109 :
2110 : /************************************************************************/
2111 : /* CSLSetNameValueSeparator() */
2112 : /************************************************************************/
2113 :
2114 : /**
2115 : * Replace the default separator (":" or "=") with the passed separator
2116 : * in the given name/value list.
2117 : *
2118 : * Note that if a separator other than ":" or "=" is used, the resulting
2119 : * list will not be manipulable by the CSL name/value functions any more.
2120 : *
2121 : * The CPLParseNameValue() function is used to break the existing lines,
2122 : * and it also strips white space from around the existing delimiter, thus
2123 : * the old separator, and any white space will be replaced by the new
2124 : * separator. For formatting purposes it may be desirable to include some
2125 : * white space in the new separator. e.g. ": " or " = ".
2126 : *
2127 : * @param papszList the list to update. Component strings may be freed
2128 : * but the list array will remain at the same location.
2129 : *
2130 : * @param pszSeparator the new separator string to insert.
2131 : */
2132 :
2133 89 : void CSLSetNameValueSeparator(char **papszList, const char *pszSeparator)
2134 :
2135 : {
2136 89 : const int nLines = CSLCount(papszList);
2137 :
2138 777 : for (int iLine = 0; iLine < nLines; ++iLine)
2139 : {
2140 688 : char *pszKey = nullptr;
2141 688 : const char *pszValue = CPLParseNameValue(papszList[iLine], &pszKey);
2142 688 : if (pszValue == nullptr || pszKey == nullptr)
2143 : {
2144 0 : CPLFree(pszKey);
2145 0 : continue;
2146 : }
2147 :
2148 1376 : char *pszNewLine = static_cast<char *>(CPLMalloc(
2149 688 : strlen(pszValue) + strlen(pszKey) + strlen(pszSeparator) + 1));
2150 688 : strcpy(pszNewLine, pszKey);
2151 688 : strcat(pszNewLine, pszSeparator);
2152 688 : strcat(pszNewLine, pszValue);
2153 688 : CPLFree(papszList[iLine]);
2154 688 : papszList[iLine] = pszNewLine;
2155 688 : CPLFree(pszKey);
2156 : }
2157 89 : }
2158 :
2159 : /************************************************************************/
2160 : /* CPLEscapeString() */
2161 : /************************************************************************/
2162 :
2163 : /**
2164 : * Apply escaping to string to preserve special characters.
2165 : *
2166 : * This function will "escape" a variety of special characters
2167 : * to make the string suitable to embed within a string constant
2168 : * or to write within a text stream but in a form that can be
2169 : * reconstituted to its original form. The escaping will even preserve
2170 : * zero bytes allowing preservation of raw binary data.
2171 : *
2172 : * CPLES_BackslashQuotable(0): This scheme turns a binary string into
2173 : * a form suitable to be placed within double quotes as a string constant.
2174 : * The backslash, quote, '\\0' and newline characters are all escaped in
2175 : * the usual C style.
2176 : *
2177 : * CPLES_XML(1): This scheme converts the '<', '>', '"' and '&' characters into
2178 : * their XML/HTML equivalent (<, >, " and &) making a string safe
2179 : * to embed as CDATA within an XML element. The '\\0' is not escaped and
2180 : * should not be included in the input.
2181 : *
2182 : * CPLES_URL(2): Everything except alphanumerics and the characters
2183 : * '$', '-', '_', '.', '+', '!', '*', ''', '(', ')' and ',' (see RFC1738) are
2184 : * converted to a percent followed by a two digit hex encoding of the character
2185 : * (leading zero supplied if needed). This is the mechanism used for encoding
2186 : * values to be passed in URLs.
2187 : *
2188 : * CPLES_SQL(3): All single quotes are replaced with two single quotes.
2189 : * Suitable for use when constructing literal values for SQL commands where
2190 : * the literal will be enclosed in single quotes.
2191 : *
2192 : * CPLES_CSV(4): If the values contains commas, semicolons, tabs, double quotes,
2193 : * or newlines it placed in double quotes, and double quotes in the value are
2194 : * doubled. Suitable for use when constructing field values for .csv files.
2195 : * Note that CPLUnescapeString() currently does not support this format, only
2196 : * CPLEscapeString(). See cpl_csv.cpp for CSV parsing support.
2197 : *
2198 : * CPLES_SQLI(7): All double quotes are replaced with two double quotes.
2199 : * Suitable for use when constructing identifiers for SQL commands where
2200 : * the literal will be enclosed in double quotes.
2201 : *
2202 : * @param pszInput the string to escape.
2203 : * @param nLength The number of bytes of data to preserve. If this is -1
2204 : * the strlen(pszString) function will be used to compute the length.
2205 : * @param nScheme the encoding scheme to use.
2206 : *
2207 : * @return an escaped, zero terminated string that should be freed with
2208 : * CPLFree() when no longer needed.
2209 : */
2210 :
2211 610151 : char *CPLEscapeString(const char *pszInput, int nLength, int nScheme)
2212 : {
2213 610151 : const size_t szLength =
2214 610151 : (nLength < 0) ? strlen(pszInput) : static_cast<size_t>(nLength);
2215 : #define nLength no_longer_use_me
2216 :
2217 610151 : size_t nSizeAlloc = 1;
2218 : #if SIZEOF_VOIDP < 8
2219 : bool bWrapAround = false;
2220 : const auto IncSizeAlloc = [&nSizeAlloc, &bWrapAround](size_t inc)
2221 : {
2222 : constexpr size_t SZ_MAX = std::numeric_limits<size_t>::max();
2223 : if (nSizeAlloc > SZ_MAX - inc)
2224 : {
2225 : bWrapAround = true;
2226 : nSizeAlloc = 0;
2227 : }
2228 : nSizeAlloc += inc;
2229 : };
2230 : #else
2231 41964800 : const auto IncSizeAlloc = [&nSizeAlloc](size_t inc) { nSizeAlloc += inc; };
2232 : #endif
2233 :
2234 610151 : if (nScheme == CPLES_BackslashQuotable)
2235 : {
2236 45751 : for (size_t iIn = 0; iIn < szLength; iIn++)
2237 : {
2238 45631 : if (pszInput[iIn] == '\0' || pszInput[iIn] == '\n' ||
2239 44877 : pszInput[iIn] == '"' || pszInput[iIn] == '\\')
2240 876 : IncSizeAlloc(2);
2241 : else
2242 44755 : IncSizeAlloc(1);
2243 : }
2244 : }
2245 610031 : else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
2246 : {
2247 41884400 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2248 : {
2249 41277300 : if (pszInput[iIn] == '<')
2250 : {
2251 1420 : IncSizeAlloc(4);
2252 : }
2253 41275900 : else if (pszInput[iIn] == '>')
2254 : {
2255 1570 : IncSizeAlloc(4);
2256 : }
2257 41274400 : else if (pszInput[iIn] == '&')
2258 : {
2259 845 : IncSizeAlloc(5);
2260 : }
2261 41273500 : else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
2262 : {
2263 1910 : IncSizeAlloc(6);
2264 : }
2265 : // Python 2 does not display the UTF-8 character corresponding
2266 : // to the byte-order mark (BOM), so escape it.
2267 41271600 : else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
2268 2 : 0xEF &&
2269 : (reinterpret_cast<const unsigned char *>(
2270 2 : pszInput))[iIn + 1] == 0xBB &&
2271 : (reinterpret_cast<const unsigned char *>(
2272 2 : pszInput))[iIn + 2] == 0xBF)
2273 : {
2274 2 : IncSizeAlloc(8);
2275 2 : iIn += 2;
2276 : }
2277 41271600 : else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
2278 22180 : 0x20 &&
2279 22180 : pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
2280 110 : pszInput[iIn] != 0xD)
2281 : {
2282 : // These control characters are unrepresentable in XML format,
2283 : // so we just drop them. #4117
2284 : }
2285 : else
2286 : {
2287 41271600 : IncSizeAlloc(1);
2288 : }
2289 607053 : }
2290 : }
2291 2978 : else if (nScheme == CPLES_URL) // Untested at implementation.
2292 : {
2293 8086 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2294 : {
2295 7633 : if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
2296 3004 : (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
2297 1351 : (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
2298 603 : pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
2299 563 : pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
2300 281 : pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
2301 259 : pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
2302 257 : pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
2303 247 : pszInput[iIn] == ',')
2304 : {
2305 7392 : IncSizeAlloc(1);
2306 : }
2307 : else
2308 : {
2309 241 : IncSizeAlloc(3);
2310 : }
2311 : }
2312 : }
2313 2525 : else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
2314 : {
2315 785 : const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
2316 11632 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2317 : {
2318 10847 : if (pszInput[iIn] == chQuote)
2319 : {
2320 7 : IncSizeAlloc(2);
2321 : }
2322 : else
2323 : {
2324 10840 : IncSizeAlloc(1);
2325 : }
2326 785 : }
2327 : }
2328 1740 : else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
2329 : {
2330 1740 : if (nScheme == CPLES_CSV && strcspn(pszInput, "\",;\t\n\r") == szLength)
2331 : {
2332 : char *pszOutput =
2333 1517 : static_cast<char *>(VSI_MALLOC_VERBOSE(szLength + 1));
2334 1517 : if (pszOutput == nullptr)
2335 0 : return nullptr;
2336 1517 : memcpy(pszOutput, pszInput, szLength + 1);
2337 1517 : return pszOutput;
2338 : }
2339 : else
2340 : {
2341 223 : IncSizeAlloc(1);
2342 12991 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2343 : {
2344 12768 : if (pszInput[iIn] == '\"')
2345 : {
2346 169 : IncSizeAlloc(2);
2347 : }
2348 : else
2349 12599 : IncSizeAlloc(1);
2350 : }
2351 223 : IncSizeAlloc(1);
2352 223 : }
2353 : }
2354 : else
2355 : {
2356 0 : CPLError(CE_Failure, CPLE_AppDefined,
2357 : "Undefined escaping scheme (%d) in CPLEscapeString()",
2358 : nScheme);
2359 0 : return CPLStrdup("");
2360 : }
2361 :
2362 : #if SIZEOF_VOIDP < 8
2363 : if (bWrapAround)
2364 : {
2365 : CPLError(CE_Failure, CPLE_OutOfMemory,
2366 : "Out of memory in CPLEscapeString()");
2367 : return nullptr;
2368 : }
2369 : #endif
2370 :
2371 608634 : char *pszOutput = static_cast<char *>(VSI_MALLOC_VERBOSE(nSizeAlloc));
2372 608634 : if (pszOutput == nullptr)
2373 0 : return nullptr;
2374 :
2375 608634 : size_t iOut = 0;
2376 :
2377 608634 : if (nScheme == CPLES_BackslashQuotable)
2378 : {
2379 45751 : for (size_t iIn = 0; iIn < szLength; iIn++)
2380 : {
2381 45631 : if (pszInput[iIn] == '\0')
2382 : {
2383 689 : pszOutput[iOut++] = '\\';
2384 689 : pszOutput[iOut++] = '0';
2385 : }
2386 44942 : else if (pszInput[iIn] == '\n')
2387 : {
2388 65 : pszOutput[iOut++] = '\\';
2389 65 : pszOutput[iOut++] = 'n';
2390 : }
2391 44877 : else if (pszInput[iIn] == '"')
2392 : {
2393 121 : pszOutput[iOut++] = '\\';
2394 121 : pszOutput[iOut++] = '\"';
2395 : }
2396 44756 : else if (pszInput[iIn] == '\\')
2397 : {
2398 1 : pszOutput[iOut++] = '\\';
2399 1 : pszOutput[iOut++] = '\\';
2400 : }
2401 : else
2402 44755 : pszOutput[iOut++] = pszInput[iIn];
2403 : }
2404 120 : pszOutput[iOut++] = '\0';
2405 : }
2406 608514 : else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
2407 : {
2408 41884400 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2409 : {
2410 41277300 : if (pszInput[iIn] == '<')
2411 : {
2412 1420 : pszOutput[iOut++] = '&';
2413 1420 : pszOutput[iOut++] = 'l';
2414 1420 : pszOutput[iOut++] = 't';
2415 1420 : pszOutput[iOut++] = ';';
2416 : }
2417 41275900 : else if (pszInput[iIn] == '>')
2418 : {
2419 1570 : pszOutput[iOut++] = '&';
2420 1570 : pszOutput[iOut++] = 'g';
2421 1570 : pszOutput[iOut++] = 't';
2422 1570 : pszOutput[iOut++] = ';';
2423 : }
2424 41274400 : else if (pszInput[iIn] == '&')
2425 : {
2426 845 : pszOutput[iOut++] = '&';
2427 845 : pszOutput[iOut++] = 'a';
2428 845 : pszOutput[iOut++] = 'm';
2429 845 : pszOutput[iOut++] = 'p';
2430 845 : pszOutput[iOut++] = ';';
2431 : }
2432 41273500 : else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
2433 : {
2434 1910 : pszOutput[iOut++] = '&';
2435 1910 : pszOutput[iOut++] = 'q';
2436 1910 : pszOutput[iOut++] = 'u';
2437 1910 : pszOutput[iOut++] = 'o';
2438 1910 : pszOutput[iOut++] = 't';
2439 1910 : pszOutput[iOut++] = ';';
2440 : }
2441 : // Python 2 does not display the UTF-8 character corresponding
2442 : // to the byte-order mark (BOM), so escape it.
2443 41271600 : else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
2444 2 : 0xEF &&
2445 : (reinterpret_cast<const unsigned char *>(
2446 2 : pszInput))[iIn + 1] == 0xBB &&
2447 : (reinterpret_cast<const unsigned char *>(
2448 2 : pszInput))[iIn + 2] == 0xBF)
2449 : {
2450 2 : pszOutput[iOut++] = '&';
2451 2 : pszOutput[iOut++] = '#';
2452 2 : pszOutput[iOut++] = 'x';
2453 2 : pszOutput[iOut++] = 'F';
2454 2 : pszOutput[iOut++] = 'E';
2455 2 : pszOutput[iOut++] = 'F';
2456 2 : pszOutput[iOut++] = 'F';
2457 2 : pszOutput[iOut++] = ';';
2458 2 : iIn += 2;
2459 : }
2460 41271600 : else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
2461 22180 : 0x20 &&
2462 22180 : pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
2463 110 : pszInput[iIn] != 0xD)
2464 : {
2465 : // These control characters are unrepresentable in XML format,
2466 : // so we just drop them. #4117
2467 : }
2468 : else
2469 : {
2470 41271600 : pszOutput[iOut++] = pszInput[iIn];
2471 : }
2472 : }
2473 607053 : pszOutput[iOut++] = '\0';
2474 : }
2475 1461 : else if (nScheme == CPLES_URL) // Untested at implementation.
2476 : {
2477 8086 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2478 : {
2479 7633 : if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
2480 3004 : (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
2481 1351 : (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
2482 603 : pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
2483 563 : pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
2484 281 : pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
2485 259 : pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
2486 257 : pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
2487 247 : pszInput[iIn] == ',')
2488 : {
2489 7392 : pszOutput[iOut++] = pszInput[iIn];
2490 : }
2491 : else
2492 : {
2493 241 : snprintf(pszOutput + iOut, nSizeAlloc - iOut, "%%%02X",
2494 241 : static_cast<unsigned char>(pszInput[iIn]));
2495 241 : iOut += 3;
2496 : }
2497 : }
2498 453 : pszOutput[iOut++] = '\0';
2499 : }
2500 1008 : else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
2501 : {
2502 785 : const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
2503 11632 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2504 : {
2505 10847 : if (pszInput[iIn] == chQuote)
2506 : {
2507 7 : pszOutput[iOut++] = chQuote;
2508 7 : pszOutput[iOut++] = chQuote;
2509 : }
2510 : else
2511 : {
2512 10840 : pszOutput[iOut++] = pszInput[iIn];
2513 : }
2514 : }
2515 785 : pszOutput[iOut++] = '\0';
2516 : }
2517 223 : else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
2518 : {
2519 223 : pszOutput[iOut++] = '\"';
2520 :
2521 12991 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2522 : {
2523 12768 : if (pszInput[iIn] == '\"')
2524 : {
2525 169 : pszOutput[iOut++] = '\"';
2526 169 : pszOutput[iOut++] = '\"';
2527 : }
2528 : else
2529 12599 : pszOutput[iOut++] = pszInput[iIn];
2530 : }
2531 223 : pszOutput[iOut++] = '\"';
2532 223 : pszOutput[iOut++] = '\0';
2533 : }
2534 :
2535 608634 : return pszOutput;
2536 : #undef nLength
2537 : }
2538 :
2539 : /************************************************************************/
2540 : /* CPLUnescapeString() */
2541 : /************************************************************************/
2542 :
2543 : /**
2544 : * Unescape a string.
2545 : *
2546 : * This function does the opposite of CPLEscapeString(). Given a string
2547 : * with special values escaped according to some scheme, it will return a
2548 : * new copy of the string returned to its original form.
2549 : *
2550 : * @param pszInput the input string. This is a zero terminated string.
2551 : * @param pnLength location to return the length of the unescaped string,
2552 : * which may in some cases include embedded '\\0' characters.
2553 : * @param nScheme the escaped scheme to undo (see CPLEscapeString() for a
2554 : * list). Does not yet support CSV.
2555 : *
2556 : * @return a copy of the unescaped string that should be freed by the
2557 : * application using CPLFree() when no longer needed.
2558 : */
2559 :
2560 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
2561 33366 : char *CPLUnescapeString(const char *pszInput, int *pnLength, int nScheme)
2562 :
2563 : {
2564 33366 : int iOut = 0;
2565 :
2566 : // TODO: Why times 4?
2567 33366 : char *pszOutput = static_cast<char *>(CPLMalloc(4 * strlen(pszInput) + 1));
2568 33366 : pszOutput[0] = '\0';
2569 :
2570 33366 : if (nScheme == CPLES_BackslashQuotable)
2571 : {
2572 53012 : for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
2573 : {
2574 52566 : if (pszInput[iIn] == '\\')
2575 : {
2576 769 : ++iIn;
2577 769 : if (pszInput[iIn] == '\0')
2578 0 : break;
2579 769 : if (pszInput[iIn] == 'n')
2580 6 : pszOutput[iOut++] = '\n';
2581 763 : else if (pszInput[iIn] == '0')
2582 675 : pszOutput[iOut++] = '\0';
2583 : else
2584 88 : pszOutput[iOut++] = pszInput[iIn];
2585 : }
2586 : else
2587 : {
2588 51797 : pszOutput[iOut++] = pszInput[iIn];
2589 : }
2590 : }
2591 : }
2592 32920 : else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
2593 : {
2594 32354 : char ch = '\0';
2595 32906800 : for (int iIn = 0; (ch = pszInput[iIn]) != '\0'; ++iIn)
2596 : {
2597 32874500 : if (ch != '&')
2598 : {
2599 32540800 : pszOutput[iOut++] = ch;
2600 : }
2601 333714 : else if (STARTS_WITH_CI(pszInput + iIn, "<"))
2602 : {
2603 20563 : pszOutput[iOut++] = '<';
2604 20563 : iIn += 3;
2605 : }
2606 313151 : else if (STARTS_WITH_CI(pszInput + iIn, ">"))
2607 : {
2608 20714 : pszOutput[iOut++] = '>';
2609 20714 : iIn += 3;
2610 : }
2611 292437 : else if (STARTS_WITH_CI(pszInput + iIn, "&"))
2612 : {
2613 206603 : pszOutput[iOut++] = '&';
2614 206603 : iIn += 4;
2615 : }
2616 85834 : else if (STARTS_WITH_CI(pszInput + iIn, "'"))
2617 : {
2618 686 : pszOutput[iOut++] = '\'';
2619 686 : iIn += 5;
2620 : }
2621 85148 : else if (STARTS_WITH_CI(pszInput + iIn, """))
2622 : {
2623 84984 : pszOutput[iOut++] = '"';
2624 84984 : iIn += 5;
2625 : }
2626 164 : else if (STARTS_WITH_CI(pszInput + iIn, "&#x"))
2627 : {
2628 3 : wchar_t anVal[2] = {0, 0};
2629 3 : iIn += 3;
2630 :
2631 3 : unsigned int nVal = 0;
2632 : while (true)
2633 : {
2634 7 : ch = pszInput[iIn++];
2635 7 : if (ch >= 'a' && ch <= 'f')
2636 1 : nVal = nVal * 16U +
2637 : static_cast<unsigned int>(ch - 'a' + 10);
2638 6 : else if (ch >= 'A' && ch <= 'F')
2639 1 : nVal = nVal * 16U +
2640 : static_cast<unsigned int>(ch - 'A' + 10);
2641 5 : else if (ch >= '0' && ch <= '9')
2642 2 : nVal = nVal * 16U + static_cast<unsigned int>(ch - '0');
2643 : else
2644 : break;
2645 : }
2646 3 : anVal[0] = static_cast<wchar_t>(nVal);
2647 3 : if (ch != ';')
2648 1 : break;
2649 2 : iIn--;
2650 :
2651 : char *pszUTF8 =
2652 2 : CPLRecodeFromWChar(anVal, "WCHAR_T", CPL_ENC_UTF8);
2653 2 : int nLen = static_cast<int>(strlen(pszUTF8));
2654 2 : memcpy(pszOutput + iOut, pszUTF8, nLen);
2655 2 : CPLFree(pszUTF8);
2656 2 : iOut += nLen;
2657 : }
2658 161 : else if (STARTS_WITH_CI(pszInput + iIn, "&#"))
2659 : {
2660 159 : wchar_t anVal[2] = {0, 0};
2661 159 : iIn += 2;
2662 :
2663 159 : unsigned int nVal = 0;
2664 : while (true)
2665 : {
2666 646 : ch = pszInput[iIn++];
2667 646 : if (ch >= '0' && ch <= '9')
2668 487 : nVal = nVal * 10U + static_cast<unsigned int>(ch - '0');
2669 : else
2670 : break;
2671 : }
2672 159 : anVal[0] = static_cast<wchar_t>(nVal);
2673 159 : if (ch != ';')
2674 1 : break;
2675 158 : iIn--;
2676 :
2677 : char *pszUTF8 =
2678 158 : CPLRecodeFromWChar(anVal, "WCHAR_T", CPL_ENC_UTF8);
2679 158 : const int nLen = static_cast<int>(strlen(pszUTF8));
2680 158 : memcpy(pszOutput + iOut, pszUTF8, nLen);
2681 158 : CPLFree(pszUTF8);
2682 158 : iOut += nLen;
2683 : }
2684 : else
2685 : {
2686 : // Illegal escape sequence.
2687 2 : CPLDebug("CPL",
2688 : "Error unescaping CPLES_XML text, '&' character "
2689 : "followed by unhandled escape sequence.");
2690 2 : break;
2691 : }
2692 32354 : }
2693 : }
2694 566 : else if (nScheme == CPLES_URL)
2695 : {
2696 26928 : for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
2697 : {
2698 26409 : if (pszInput[iIn] == '%' && pszInput[iIn + 1] != '\0' &&
2699 294 : pszInput[iIn + 2] != '\0')
2700 : {
2701 294 : int nHexChar = 0;
2702 :
2703 294 : if (pszInput[iIn + 1] >= 'A' && pszInput[iIn + 1] <= 'F')
2704 0 : nHexChar += 16 * (pszInput[iIn + 1] - 'A' + 10);
2705 294 : else if (pszInput[iIn + 1] >= 'a' && pszInput[iIn + 1] <= 'f')
2706 0 : nHexChar += 16 * (pszInput[iIn + 1] - 'a' + 10);
2707 294 : else if (pszInput[iIn + 1] >= '0' && pszInput[iIn + 1] <= '9')
2708 294 : nHexChar += 16 * (pszInput[iIn + 1] - '0');
2709 : else
2710 0 : CPLDebug("CPL",
2711 : "Error unescaping CPLES_URL text, percent not "
2712 : "followed by two hex digits.");
2713 :
2714 294 : if (pszInput[iIn + 2] >= 'A' && pszInput[iIn + 2] <= 'F')
2715 273 : nHexChar += pszInput[iIn + 2] - 'A' + 10;
2716 21 : else if (pszInput[iIn + 2] >= 'a' && pszInput[iIn + 2] <= 'f')
2717 0 : nHexChar += pszInput[iIn + 2] - 'a' + 10;
2718 21 : else if (pszInput[iIn + 2] >= '0' && pszInput[iIn + 2] <= '9')
2719 21 : nHexChar += pszInput[iIn + 2] - '0';
2720 : else
2721 0 : CPLDebug("CPL",
2722 : "Error unescaping CPLES_URL text, percent not "
2723 : "followed by two hex digits.");
2724 :
2725 294 : pszOutput[iOut++] = static_cast<char>(nHexChar);
2726 294 : iIn += 2;
2727 : }
2728 26115 : else if (pszInput[iIn] == '+')
2729 : {
2730 0 : pszOutput[iOut++] = ' ';
2731 : }
2732 : else
2733 : {
2734 26115 : pszOutput[iOut++] = pszInput[iIn];
2735 : }
2736 : }
2737 : }
2738 47 : else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
2739 : {
2740 47 : char szQuote = nScheme == CPLES_SQL ? '\'' : '\"';
2741 573 : for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
2742 : {
2743 526 : if (pszInput[iIn] == szQuote && pszInput[iIn + 1] == szQuote)
2744 : {
2745 5 : ++iIn;
2746 5 : pszOutput[iOut++] = pszInput[iIn];
2747 : }
2748 : else
2749 : {
2750 521 : pszOutput[iOut++] = pszInput[iIn];
2751 : }
2752 47 : }
2753 : }
2754 0 : else if (nScheme == CPLES_CSV)
2755 : {
2756 0 : CPLError(CE_Fatal, CPLE_NotSupported,
2757 : "CSV Unescaping not yet implemented.");
2758 : }
2759 : else
2760 : {
2761 0 : CPLError(CE_Fatal, CPLE_NotSupported, "Unknown escaping style.");
2762 : }
2763 :
2764 33366 : pszOutput[iOut] = '\0';
2765 :
2766 33366 : if (pnLength != nullptr)
2767 21778 : *pnLength = iOut;
2768 :
2769 33366 : return pszOutput;
2770 : }
2771 :
2772 : /************************************************************************/
2773 : /* CPLBinaryToHex() */
2774 : /************************************************************************/
2775 :
2776 : /**
2777 : * Binary to hexadecimal translation.
2778 : *
2779 : * @param nBytes number of bytes of binary data in pabyData.
2780 : * @param pabyData array of data bytes to translate.
2781 : *
2782 : * @return hexadecimal translation, zero terminated. Free with CPLFree().
2783 : */
2784 :
2785 4208 : char *CPLBinaryToHex(int nBytes, const GByte *pabyData)
2786 :
2787 : {
2788 4208 : char *pszHex = static_cast<char *>(CPLMalloc(nBytes * 2 + 1));
2789 4208 : pszHex[nBytes * 2] = '\0';
2790 :
2791 4208 : constexpr char achHex[] = "0123456789ABCDEF";
2792 :
2793 247498 : for (int i = 0; i < nBytes; ++i)
2794 : {
2795 243290 : const int nLow = pabyData[i] & 0x0f;
2796 243290 : const int nHigh = (pabyData[i] & 0xf0) >> 4;
2797 :
2798 243290 : pszHex[i * 2] = achHex[nHigh];
2799 243290 : pszHex[i * 2 + 1] = achHex[nLow];
2800 : }
2801 :
2802 4208 : return pszHex;
2803 : }
2804 :
2805 : /************************************************************************/
2806 : /* CPLHexToBinary() */
2807 : /************************************************************************/
2808 :
2809 : constexpr unsigned char hex2char[256] = {
2810 : // Not Hex characters.
2811 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2812 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2813 : // 0-9
2814 : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
2815 : // A-F
2816 : 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2817 : // Not Hex characters.
2818 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2819 : // a-f
2820 : 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2821 : 0, 0, 0, 0, 0, 0, 0, 0, 0,
2822 : // Not Hex characters (upper 128 characters).
2823 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2824 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2825 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2826 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2827 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2828 : 0, 0, 0};
2829 :
2830 : /**
2831 : * Hexadecimal to binary translation
2832 : *
2833 : * @param pszHex the input hex encoded string.
2834 : * @param pnBytes the returned count of decoded bytes placed here.
2835 : *
2836 : * @return returns binary buffer of data - free with CPLFree().
2837 : */
2838 :
2839 3913 : GByte *CPLHexToBinary(const char *pszHex, int *pnBytes)
2840 : {
2841 3913 : const GByte *pabyHex = reinterpret_cast<const GByte *>(pszHex);
2842 3913 : const size_t nHexLen = strlen(pszHex);
2843 :
2844 3913 : GByte *pabyWKB = static_cast<GByte *>(CPLMalloc(nHexLen / 2 + 2));
2845 :
2846 1046540 : for (size_t i = 0; i < nHexLen / 2; ++i)
2847 : {
2848 1042630 : const unsigned char h1 = hex2char[pabyHex[2 * i]];
2849 1042630 : const unsigned char h2 = hex2char[pabyHex[2 * i + 1]];
2850 :
2851 : // First character is high bits, second is low bits.
2852 1042630 : pabyWKB[i] = static_cast<GByte>((h1 << 4) | h2);
2853 : }
2854 3913 : pabyWKB[nHexLen / 2] = 0;
2855 3913 : *pnBytes = static_cast<int>(nHexLen / 2);
2856 :
2857 3913 : return pabyWKB;
2858 : }
2859 :
2860 : /************************************************************************/
2861 : /* CPLGetValueType() */
2862 : /************************************************************************/
2863 :
2864 : /**
2865 : * Detect the type of the value contained in a string, whether it is
2866 : * a real, an integer or a string
2867 : * Leading and trailing spaces are skipped in the analysis.
2868 : *
2869 : * Note: in the context of this function, integer must be understood in a
2870 : * broad sense. It does not mean that the value can fit into a 32 bit integer
2871 : * for example. It might be larger.
2872 : *
2873 : * @param pszValue the string to analyze
2874 : *
2875 : * @return returns the type of the value contained in the string.
2876 : */
2877 :
2878 548543 : CPLValueType CPLGetValueType(const char *pszValue)
2879 : {
2880 : // Doubles : "+25.e+3", "-25.e-3", "25.e3", "25e3", " 25e3 "
2881 : // Not doubles: "25e 3", "25e.3", "-2-5e3", "2-5e3", "25.25.3", "-3d", "d1"
2882 : // "XXeYYYYYYYYYYYYYYYYYYY" that evaluates to infinity
2883 :
2884 548543 : if (pszValue == nullptr)
2885 0 : return CPL_VALUE_STRING;
2886 :
2887 548543 : const char *pszValueInit = pszValue;
2888 :
2889 : // Skip leading spaces.
2890 548594 : while (isspace(static_cast<unsigned char>(*pszValue)))
2891 51 : ++pszValue;
2892 :
2893 548543 : if (*pszValue == '\0')
2894 370 : return CPL_VALUE_STRING;
2895 :
2896 : // Skip leading + or -.
2897 548173 : if (*pszValue == '+' || *pszValue == '-')
2898 85312 : ++pszValue;
2899 :
2900 548173 : constexpr char DIGIT_ZERO = '0';
2901 548173 : if (pszValue[0] == DIGIT_ZERO && pszValue[1] != '\0' && pszValue[1] != '.')
2902 901 : return CPL_VALUE_STRING;
2903 :
2904 547272 : bool bFoundDot = false;
2905 547272 : bool bFoundExponent = false;
2906 547272 : bool bIsLastCharExponent = false;
2907 547272 : bool bIsReal = false;
2908 547272 : const char *pszAfterExponent = nullptr;
2909 547272 : bool bFoundMantissa = false;
2910 :
2911 6953790 : for (; *pszValue != '\0'; ++pszValue)
2912 : {
2913 6453800 : if (isdigit(static_cast<unsigned char>(*pszValue)))
2914 : {
2915 6017810 : bIsLastCharExponent = false;
2916 6017810 : bFoundMantissa = true;
2917 : }
2918 435995 : else if (isspace(static_cast<unsigned char>(*pszValue)))
2919 : {
2920 764 : const char *pszTmp = pszValue;
2921 1532 : while (isspace(static_cast<unsigned char>(*pszTmp)))
2922 768 : ++pszTmp;
2923 764 : if (*pszTmp == 0)
2924 24 : break;
2925 : else
2926 740 : return CPL_VALUE_STRING;
2927 : }
2928 435231 : else if (*pszValue == '-' || *pszValue == '+')
2929 : {
2930 833 : if (bIsLastCharExponent)
2931 : {
2932 : // Do nothing.
2933 : }
2934 : else
2935 : {
2936 320 : return CPL_VALUE_STRING;
2937 : }
2938 513 : bIsLastCharExponent = false;
2939 : }
2940 434398 : else if (*pszValue == '.')
2941 : {
2942 387684 : bIsReal = true;
2943 387684 : if (!bFoundDot && !bIsLastCharExponent)
2944 387681 : bFoundDot = true;
2945 : else
2946 3 : return CPL_VALUE_STRING;
2947 387681 : bIsLastCharExponent = false;
2948 : }
2949 46714 : else if (*pszValue == 'D' || *pszValue == 'd' || *pszValue == 'E' ||
2950 42252 : *pszValue == 'e')
2951 : {
2952 4726 : if (!bFoundMantissa)
2953 4204 : return CPL_VALUE_STRING;
2954 522 : if (!(pszValue[1] == '+' || pszValue[1] == '-' ||
2955 9 : isdigit(static_cast<unsigned char>(pszValue[1]))))
2956 2 : return CPL_VALUE_STRING;
2957 :
2958 520 : bIsReal = true;
2959 520 : if (!bFoundExponent)
2960 519 : bFoundExponent = true;
2961 : else
2962 1 : return CPL_VALUE_STRING;
2963 519 : pszAfterExponent = pszValue + 1;
2964 519 : bIsLastCharExponent = true;
2965 : }
2966 : else
2967 : {
2968 41988 : return CPL_VALUE_STRING;
2969 : }
2970 : }
2971 :
2972 500014 : if (bIsReal && pszAfterExponent && strlen(pszAfterExponent) > 3)
2973 : {
2974 : // cppcheck-suppress unreadVariable
2975 15 : const double dfVal = CPLAtof(pszValueInit);
2976 15 : if (std::isinf(dfVal))
2977 1 : return CPL_VALUE_STRING;
2978 : }
2979 :
2980 500013 : return bIsReal ? CPL_VALUE_REAL : CPL_VALUE_INTEGER;
2981 : }
2982 :
2983 : /************************************************************************/
2984 : /* CPLStrlcpy() */
2985 : /************************************************************************/
2986 :
2987 : /**
2988 : * Copy source string to a destination buffer.
2989 : *
2990 : * This function ensures that the destination buffer is always NUL terminated
2991 : * (provided that its length is at least 1).
2992 : *
2993 : * This function is designed to be a safer, more consistent, and less error
2994 : * prone replacement for strncpy. Its contract is identical to libbsd's strlcpy.
2995 : *
2996 : * Truncation can be detected by testing if the return value of CPLStrlcpy
2997 : * is greater or equal to nDestSize.
2998 :
2999 : \verbatim
3000 : char szDest[5] = {};
3001 : if( CPLStrlcpy(szDest, "abcde", sizeof(szDest)) >= sizeof(szDest) )
3002 : fprintf(stderr, "truncation occurred !\n");
3003 : \endverbatim
3004 :
3005 : * @param pszDest destination buffer
3006 : * @param pszSrc source string. Must be NUL terminated
3007 : * @param nDestSize size of destination buffer (including space for the NUL
3008 : * terminator character)
3009 : *
3010 : * @return the length of the source string (=strlen(pszSrc))
3011 : *
3012 : * @since GDAL 1.7.0
3013 : */
3014 4473140 : size_t CPLStrlcpy(char *pszDest, const char *pszSrc, size_t nDestSize)
3015 : {
3016 4473140 : if (nDestSize == 0)
3017 0 : return strlen(pszSrc);
3018 :
3019 4473140 : char *pszDestIter = pszDest;
3020 4473140 : const char *pszSrcIter = pszSrc;
3021 :
3022 4473140 : --nDestSize;
3023 36146800 : while (nDestSize != 0 && *pszSrcIter != '\0')
3024 : {
3025 31673700 : *pszDestIter = *pszSrcIter;
3026 31673700 : ++pszDestIter;
3027 31673700 : ++pszSrcIter;
3028 31673700 : --nDestSize;
3029 : }
3030 4473140 : *pszDestIter = '\0';
3031 4473140 : return pszSrcIter - pszSrc + strlen(pszSrcIter);
3032 : }
3033 :
3034 : /************************************************************************/
3035 : /* CPLStrlcat() */
3036 : /************************************************************************/
3037 :
3038 : /**
3039 : * Appends a source string to a destination buffer.
3040 : *
3041 : * This function ensures that the destination buffer is always NUL terminated
3042 : * (provided that its length is at least 1 and that there is at least one byte
3043 : * free in pszDest, that is to say strlen(pszDest_before) < nDestSize)
3044 : *
3045 : * This function is designed to be a safer, more consistent, and less error
3046 : * prone replacement for strncat. Its contract is identical to libbsd's strlcat.
3047 : *
3048 : * Truncation can be detected by testing if the return value of CPLStrlcat
3049 : * is greater or equal to nDestSize.
3050 :
3051 : \verbatim
3052 : char szDest[5] = {};
3053 : CPLStrlcpy(szDest, "ab", sizeof(szDest));
3054 : if( CPLStrlcat(szDest, "cde", sizeof(szDest)) >= sizeof(szDest) )
3055 : fprintf(stderr, "truncation occurred !\n");
3056 : \endverbatim
3057 :
3058 : * @param pszDest destination buffer. Must be NUL terminated before
3059 : * running CPLStrlcat
3060 : * @param pszSrc source string. Must be NUL terminated
3061 : * @param nDestSize size of destination buffer (including space for the
3062 : * NUL terminator character)
3063 : *
3064 : * @return the theoretical length of the destination string after concatenation
3065 : * (=strlen(pszDest_before) + strlen(pszSrc)).
3066 : * If strlen(pszDest_before) >= nDestSize, then it returns
3067 : * nDestSize + strlen(pszSrc)
3068 : *
3069 : * @since GDAL 1.7.0
3070 : */
3071 1795020 : size_t CPLStrlcat(char *pszDest, const char *pszSrc, size_t nDestSize)
3072 : {
3073 1795020 : char *pszDestIter = pszDest;
3074 :
3075 77876500 : while (nDestSize != 0 && *pszDestIter != '\0')
3076 : {
3077 76081500 : ++pszDestIter;
3078 76081500 : --nDestSize;
3079 : }
3080 :
3081 1795020 : return pszDestIter - pszDest + CPLStrlcpy(pszDestIter, pszSrc, nDestSize);
3082 : }
3083 :
3084 : /************************************************************************/
3085 : /* CPLStrnlen() */
3086 : /************************************************************************/
3087 :
3088 : /**
3089 : * Returns the length of a NUL terminated string by reading at most
3090 : * the specified number of bytes.
3091 : *
3092 : * The CPLStrnlen() function returns min(strlen(pszStr), nMaxLen).
3093 : * Only the first nMaxLen bytes of the string will be read. Useful to
3094 : * test if a string contains at least nMaxLen characters without reading
3095 : * the full string up to the NUL terminating character.
3096 : *
3097 : * @param pszStr a NUL terminated string
3098 : * @param nMaxLen maximum number of bytes to read in pszStr
3099 : *
3100 : * @return strlen(pszStr) if the length is lesser than nMaxLen, otherwise
3101 : * nMaxLen if the NUL character has not been found in the first nMaxLen bytes.
3102 : *
3103 : * @since GDAL 1.7.0
3104 : */
3105 :
3106 413352 : size_t CPLStrnlen(const char *pszStr, size_t nMaxLen)
3107 : {
3108 413352 : size_t nLen = 0;
3109 18059700 : while (nLen < nMaxLen && *pszStr != '\0')
3110 : {
3111 17646400 : ++nLen;
3112 17646400 : ++pszStr;
3113 : }
3114 413352 : return nLen;
3115 : }
3116 :
3117 : /************************************************************************/
3118 : /* CSLParseCommandLine() */
3119 : /************************************************************************/
3120 :
3121 : /**
3122 : * Tokenize command line arguments in a list of strings.
3123 : *
3124 : * @param pszCommandLine command line
3125 : *
3126 : * @return NULL terminated list of strings to free with CSLDestroy()
3127 : *
3128 : * @since GDAL 2.1
3129 : */
3130 824 : char **CSLParseCommandLine(const char *pszCommandLine)
3131 : {
3132 824 : return CSLTokenizeString(pszCommandLine);
3133 : }
3134 :
3135 : /************************************************************************/
3136 : /* CPLToupper() */
3137 : /************************************************************************/
3138 :
3139 : /** Converts a (ASCII) lowercase character to uppercase.
3140 : *
3141 : * Same as standard toupper(), except that it is not locale sensitive.
3142 : *
3143 : * @since GDAL 3.9
3144 : */
3145 21931300 : int CPLToupper(int c)
3146 : {
3147 21931300 : return (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c;
3148 : }
3149 :
3150 : /************************************************************************/
3151 : /* CPLTolower() */
3152 : /************************************************************************/
3153 :
3154 : /** Converts a (ASCII) uppercase character to lowercase.
3155 : *
3156 : * Same as standard tolower(), except that it is not locale sensitive.
3157 : *
3158 : * @since GDAL 3.9
3159 : */
3160 17808800 : int CPLTolower(int c)
3161 : {
3162 17808800 : return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c;
3163 : }
|