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