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