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 434424 : char **CSLAddString(char **papszStrList, const char *pszNewString)
69 : {
70 434424 : char **papszRet = CSLAddStringMayFail(papszStrList, pszNewString);
71 434369 : if (papszRet == nullptr && pszNewString != nullptr)
72 0 : abort();
73 434369 : return papszRet;
74 : }
75 :
76 : /** Same as CSLAddString() but may return NULL in case of (memory) failure */
77 469970 : char **CSLAddStringMayFail(char **papszStrList, const char *pszNewString)
78 : {
79 469970 : if (pszNewString == nullptr)
80 131 : return papszStrList; // Nothing to do!
81 :
82 469839 : char *pszDup = VSI_STRDUP_VERBOSE(pszNewString);
83 469815 : if (pszDup == nullptr)
84 0 : return nullptr;
85 :
86 : // Allocate room for the new string.
87 469815 : char **papszStrListNew = nullptr;
88 469815 : int nItems = 0;
89 :
90 469815 : if (papszStrList == nullptr)
91 : papszStrListNew =
92 66312 : static_cast<char **>(VSI_CALLOC_VERBOSE(2, sizeof(char *)));
93 : else
94 : {
95 403503 : nItems = CSLCount(papszStrList);
96 : papszStrListNew = static_cast<char **>(
97 403477 : VSI_REALLOC_VERBOSE(papszStrList, (nItems + 2) * sizeof(char *)));
98 : }
99 469757 : if (papszStrListNew == nullptr)
100 : {
101 0 : VSIFree(pszDup);
102 0 : return nullptr;
103 : }
104 :
105 : // Copy the string in the list.
106 469757 : papszStrListNew[nItems] = pszDup;
107 469757 : papszStrListNew[nItems + 1] = nullptr;
108 :
109 469757 : 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 4870780 : int CSLCount(CSLConstList papszStrList)
133 : {
134 4870780 : if (!papszStrList)
135 3560940 : return 0;
136 :
137 1309840 : int nItems = 0;
138 :
139 13020400 : while (*papszStrList != nullptr)
140 : {
141 11710600 : ++nItems;
142 11710600 : ++papszStrList;
143 : }
144 :
145 1309840 : 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 1239 : const char *CSLGetField(CSLConstList papszStrList, int iField)
159 :
160 : {
161 1239 : if (papszStrList == nullptr || iField < 0)
162 0 : return ("");
163 :
164 2681 : for (int i = 0; i < iField + 1; i++)
165 : {
166 1444 : if (papszStrList[i] == nullptr)
167 2 : return "";
168 : }
169 :
170 1237 : 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 12834900 : void CPL_STDCALL CSLDestroy(char **papszStrList)
186 : {
187 12834900 : if (!papszStrList)
188 9921600 : return;
189 :
190 13770700 : for (char **papszPtr = papszStrList; *papszPtr != nullptr; ++papszPtr)
191 : {
192 10859300 : CPLFree(*papszPtr);
193 : }
194 :
195 2911380 : 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 3598520 : char **CSLDuplicate(CSLConstList papszStrList)
214 : {
215 3598520 : const int nLines = CSLCount(papszStrList);
216 :
217 3577630 : if (nLines == 0)
218 3528430 : return nullptr;
219 :
220 49194 : CSLConstList papszSrc = papszStrList;
221 :
222 : char **papszNewList =
223 49194 : static_cast<char **>(VSI_MALLOC2_VERBOSE(nLines + 1, sizeof(char *)));
224 :
225 63607 : char **papszDst = papszNewList;
226 :
227 422306 : for (; *papszSrc != nullptr; ++papszSrc, ++papszDst)
228 : {
229 358698 : *papszDst = VSI_STRDUP_VERBOSE(*papszSrc);
230 358698 : if (*papszDst == nullptr)
231 : {
232 0 : CSLDestroy(papszNewList);
233 0 : return nullptr;
234 : }
235 : }
236 63608 : *papszDst = nullptr;
237 :
238 63608 : 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 748479 : char **CSLMerge(char **papszOrig, CSLConstList papszOverride)
259 :
260 : {
261 748479 : if (papszOrig == nullptr && papszOverride != nullptr)
262 621 : return CSLDuplicate(papszOverride);
263 :
264 747858 : if (papszOverride == nullptr)
265 736413 : return papszOrig;
266 :
267 6242 : for (int i = 0; papszOverride[i] != nullptr; ++i)
268 : {
269 4413 : char *pszKey = nullptr;
270 4413 : const char *pszValue = CPLParseNameValue(papszOverride[i], &pszKey);
271 :
272 4413 : papszOrig = CSLSetNameValue(papszOrig, pszKey, pszValue);
273 4413 : CPLFree(pszKey);
274 : }
275 :
276 1829 : 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 3407 : char **CSLLoad2(const char *pszFname, int nMaxLines, int nMaxCols,
307 : CSLConstList papszOptions)
308 : {
309 3407 : VSILFILE *fp = VSIFOpenL(pszFname, "rb");
310 :
311 3407 : if (!fp)
312 : {
313 2190 : 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 2190 : return nullptr;
320 : }
321 :
322 1217 : char **papszStrList = nullptr;
323 1217 : int nLines = 0;
324 1217 : int nAllocatedLines = 0;
325 :
326 9093 : while (!VSIFEofL(fp) && (nMaxLines == -1 || nLines < nMaxLines))
327 : {
328 7882 : const char *pszLine = CPLReadLine2L(fp, nMaxCols, papszOptions);
329 7882 : if (pszLine == nullptr)
330 6 : break;
331 :
332 7876 : if (nLines + 1 >= nAllocatedLines)
333 : {
334 1343 : nAllocatedLines = 16 + nAllocatedLines * 2;
335 : char **papszStrListNew = static_cast<char **>(
336 1343 : VSIRealloc(papszStrList, nAllocatedLines * sizeof(char *)));
337 1343 : 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 1343 : papszStrList = papszStrListNew;
348 : }
349 7876 : papszStrList[nLines] = CPLStrdup(pszLine);
350 7876 : papszStrList[nLines + 1] = nullptr;
351 7876 : ++nLines;
352 : }
353 :
354 1217 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
355 :
356 : // Free the internal thread local line buffer.
357 1217 : CPLReadLineL(nullptr);
358 :
359 1217 : 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 17399 : char **CSLInsertStrings(char **papszStrList, int nInsertAtLineNo,
483 : CSLConstList papszNewLines)
484 : {
485 17399 : if (papszNewLines == nullptr)
486 36 : return papszStrList; // Nothing to do!
487 :
488 17363 : const int nToInsert = CSLCount(papszNewLines);
489 17363 : if (nToInsert == 0)
490 1242 : return papszStrList; // Nothing to do!
491 :
492 16121 : const int nSrcLines = CSLCount(papszStrList);
493 16121 : const int nDstLines = nSrcLines + nToInsert;
494 :
495 : // Allocate room for the new strings.
496 : papszStrList = static_cast<char **>(
497 16121 : 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 16121 : 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 16121 : if (nInsertAtLineNo == -1 || nInsertAtLineNo > nSrcLines)
507 15331 : nInsertAtLineNo = nSrcLines;
508 :
509 : {
510 16121 : char **ppszSrc = papszStrList + nSrcLines;
511 16121 : char **ppszDst = papszStrList + nDstLines;
512 :
513 33497 : for (int i = nSrcLines; i >= nInsertAtLineNo; --i)
514 : {
515 17376 : *ppszDst = *ppszSrc;
516 17376 : --ppszDst;
517 17376 : --ppszSrc;
518 : }
519 : }
520 :
521 : // Copy the strings to the list.
522 16121 : CSLConstList ppszSrc = papszNewLines;
523 16121 : char **ppszDst = papszStrList + nInsertAtLineNo;
524 :
525 145533 : for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
526 : {
527 129412 : *ppszDst = CPLStrdup(*ppszSrc);
528 : }
529 :
530 16121 : 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 533 : char **CSLInsertString(char **papszStrList, int nInsertAtLineNo,
548 : const char *pszNewLine)
549 : {
550 533 : char *apszList[2] = {const_cast<char *>(pszNewLine), nullptr};
551 :
552 1066 : 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 6515 : char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete,
574 : int nNumToRemove, char ***ppapszRetStrings)
575 : {
576 6515 : const int nSrcLines = CSLCount(papszStrList);
577 :
578 6515 : 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 6515 : const int nDstLines = nSrcLines - nNumToRemove;
584 6515 : if (nDstLines < 1)
585 : {
586 983 : CSLDestroy(papszStrList);
587 983 : 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 5532 : char **ppszDst = papszStrList + nFirstLineToDelete;
594 :
595 5532 : if (ppapszRetStrings == nullptr)
596 : {
597 : // free() all the strings that will be removed.
598 11064 : for (int i = 0; i < nNumToRemove; ++i)
599 : {
600 5532 : CPLFree(*ppszDst);
601 5532 : *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 5532 : if (nFirstLineToDelete == -1 || nFirstLineToDelete > nSrcLines)
620 0 : nFirstLineToDelete = nDstLines;
621 :
622 5532 : char **ppszSrc = papszStrList + nFirstLineToDelete + nNumToRemove;
623 5532 : ppszDst = papszStrList + nFirstLineToDelete;
624 :
625 11809 : for (; *ppszSrc != nullptr; ++ppszSrc, ++ppszDst)
626 : {
627 6277 : *ppszDst = *ppszSrc;
628 : }
629 : // Move the NULL pointer at the end of the StringList.
630 5532 : *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 5532 : 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 4199240 : int CSLFindString(CSLConstList papszList, const char *pszTarget)
656 :
657 : {
658 4199240 : if (papszList == nullptr)
659 279448 : return -1;
660 :
661 31668200 : for (int i = 0; papszList[i] != nullptr; ++i)
662 : {
663 27938600 : if (EQUAL(papszList[i], pszTarget))
664 190153 : return i;
665 : }
666 :
667 3729630 : 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 4262 : int CSLFindStringCaseSensitive(CSLConstList papszList, const char *pszTarget)
690 :
691 : {
692 4262 : if (papszList == nullptr)
693 617 : return -1;
694 :
695 76117 : for (int i = 0; papszList[i] != nullptr; ++i)
696 : {
697 72486 : if (strcmp(papszList[i], pszTarget) == 0)
698 14 : return i;
699 : }
700 :
701 3631 : 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 22274 : int CSLPartialFindString(CSLConstList papszHaystack, const char *pszNeedle)
722 : {
723 22274 : if (papszHaystack == nullptr || pszNeedle == nullptr)
724 7208 : return -1;
725 :
726 34347 : for (int i = 0; papszHaystack[i] != nullptr; ++i)
727 : {
728 25795 : if (strstr(papszHaystack[i], pszNeedle))
729 6514 : return i;
730 : }
731 :
732 8552 : 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 170348 : char **CSLTokenizeString(const char *pszString)
743 : {
744 170348 : return CSLTokenizeString2(pszString, " ", CSLT_HONOURSTRINGS);
745 : }
746 :
747 : /************************************************************************/
748 : /* CSLTokenizeStringComplex() */
749 : /************************************************************************/
750 :
751 : /** Obsolete tokenizing api. Use CSLTokenizeString2() */
752 565069 : char **CSLTokenizeStringComplex(const char *pszString,
753 : const char *pszDelimiters, int bHonourStrings,
754 : int bAllowEmptyTokens)
755 : {
756 565069 : int nFlags = 0;
757 :
758 565069 : if (bHonourStrings)
759 124693 : nFlags |= CSLT_HONOURSTRINGS;
760 565069 : if (bAllowEmptyTokens)
761 17257 : nFlags |= CSLT_ALLOWEMPTYTOKENS;
762 :
763 565069 : 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 1270880 : char **CSLTokenizeString2(const char *pszString, const char *pszDelimiters,
820 : int nCSLTFlags)
821 : {
822 1270880 : if (pszString == nullptr)
823 4126 : return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
824 :
825 2533500 : CPLStringList oRetList;
826 1266750 : const bool bHonourStrings = (nCSLTFlags & CSLT_HONOURSTRINGS) != 0;
827 1266750 : const bool bAllowEmptyTokens = (nCSLTFlags & CSLT_ALLOWEMPTYTOKENS) != 0;
828 1266750 : const bool bStripLeadSpaces = (nCSLTFlags & CSLT_STRIPLEADSPACES) != 0;
829 1266750 : const bool bStripEndSpaces = (nCSLTFlags & CSLT_STRIPENDSPACES) != 0;
830 :
831 1266750 : char *pszToken = static_cast<char *>(CPLCalloc(10, 1));
832 1266750 : size_t nTokenMax = 10;
833 :
834 4058880 : while (*pszString != '\0')
835 : {
836 2792130 : bool bInString = false;
837 2792130 : bool bStartString = true;
838 2792130 : size_t nTokenLen = 0;
839 :
840 : // Try to find the next delimiter, marking end of token.
841 36834400 : for (; *pszString != '\0'; ++pszString)
842 : {
843 : // Extend token buffer if we are running close to its end.
844 35623700 : if (nTokenLen >= nTokenMax - 3)
845 : {
846 1065130 : 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 1065130 : nTokenMax = nTokenMax * 2;
852 : char *pszNewToken = static_cast<char *>(
853 1065130 : VSI_REALLOC_VERBOSE(pszToken, nTokenMax));
854 1065130 : if (pszNewToken == nullptr)
855 : {
856 0 : CPLFree(pszToken);
857 0 : return static_cast<char **>(CPLCalloc(sizeof(char *), 1));
858 : }
859 1065130 : pszToken = pszNewToken;
860 : }
861 :
862 : // End if this is a delimiter skip it and break.
863 35623700 : if (!bInString && strchr(pszDelimiters, *pszString) != nullptr)
864 : {
865 1581400 : ++pszString;
866 1581400 : 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 34042300 : if (bHonourStrings && *pszString == '"')
873 : {
874 73655 : if (nCSLTFlags & CSLT_PRESERVEQUOTES)
875 : {
876 4603 : pszToken[nTokenLen] = *pszString;
877 4603 : ++nTokenLen;
878 : }
879 :
880 73655 : bInString = !bInString;
881 73655 : 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 33968600 : 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 33968600 : if (!bInString && bStripLeadSpaces && bStartString &&
905 31716 : isspace(static_cast<unsigned char>(*pszString)))
906 4587 : continue;
907 :
908 33964000 : bStartString = false;
909 :
910 33964000 : pszToken[nTokenLen] = *pszString;
911 33964000 : ++nTokenLen;
912 : }
913 :
914 : // Strip spaces at the token end if requested.
915 2792130 : if (!bInString && bStripEndSpaces)
916 : {
917 32653 : while (nTokenLen &&
918 27513 : isspace(static_cast<unsigned char>(pszToken[nTokenLen - 1])))
919 38 : nTokenLen--;
920 : }
921 :
922 2792130 : pszToken[nTokenLen] = '\0';
923 :
924 : // Add the token.
925 2792130 : if (pszToken[0] != '\0' || bAllowEmptyTokens)
926 2671500 : 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 1293430 : if (*pszString == '\0' && bAllowEmptyTokens && oRetList.Count() > 0 &&
934 26682 : strchr(pszDelimiters, *(pszString - 1)) != nullptr)
935 : {
936 1250 : oRetList.AddString("");
937 : }
938 :
939 1266750 : CPLFree(pszToken);
940 :
941 1266750 : 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 25104 : oRetList.Assign(static_cast<char **>(CPLCalloc(sizeof(char *), 1)));
946 : }
947 :
948 1266750 : 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 1521190 : 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 1521190 : char *pachBufRingInfo = static_cast<char *>(CPLGetTLS(CTLS_CPLSPRINTF));
975 :
976 1521180 : if (pachBufRingInfo == nullptr)
977 : {
978 2728 : pachBufRingInfo = static_cast<char *>(CPLCalloc(
979 : 1, sizeof(int) + CPLSPrintf_BUF_Count * CPLSPrintf_BUF_SIZE));
980 2730 : 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 1521180 : int *pnBufIndex = reinterpret_cast<int *>(pachBufRingInfo);
988 1521180 : const size_t nOffset = sizeof(int) + *pnBufIndex * CPLSPrintf_BUF_SIZE;
989 1521180 : char *pachBuffer = pachBufRingInfo + nOffset;
990 :
991 1521180 : *pnBufIndex = (*pnBufIndex + 1) % CPLSPrintf_BUF_Count;
992 :
993 : /* -------------------------------------------------------------------- */
994 : /* Format the result. */
995 : /* -------------------------------------------------------------------- */
996 :
997 1521180 : va_start(args, fmt);
998 :
999 : const int ret =
1000 1521180 : CPLvsnprintf(pachBuffer, CPLSPrintf_BUF_SIZE - 1, fmt, args);
1001 1521180 : if (ret < 0 || ret >= CPLSPrintf_BUF_SIZE - 1)
1002 : {
1003 11 : CPLError(CE_Failure, CPLE_AppDefined,
1004 : "CPLSPrintf() called with too "
1005 : "big string. Output will be truncated !");
1006 : }
1007 :
1008 1521180 : va_end(args);
1009 :
1010 1521180 : 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 4275320 : static const char *CPLvsnprintf_get_end_of_formatting(const char *fmt)
1057 : {
1058 4275320 : char ch = '\0';
1059 : // Flag.
1060 5463940 : for (; (ch = *fmt) != '\0'; ++fmt)
1061 : {
1062 5463870 : if (ch == '\'')
1063 0 : continue; // Bad idea as this is locale specific.
1064 5463870 : if (ch == '-' || ch == '+' || ch == ' ' || ch == '#' || ch == '0')
1065 1188620 : continue;
1066 4275250 : break;
1067 : }
1068 :
1069 : // Field width.
1070 5619590 : for (; (ch = *fmt) != '\0'; ++fmt)
1071 : {
1072 5619580 : if (ch == '$')
1073 0 : return nullptr; // Do not support this.
1074 5619580 : if (*fmt >= '0' && *fmt <= '9')
1075 1344270 : continue;
1076 4275310 : break;
1077 : }
1078 :
1079 : // Precision.
1080 4275320 : if (ch == '.')
1081 : {
1082 694233 : ++fmt;
1083 1965050 : for (; (ch = *fmt) != '\0'; ++fmt)
1084 : {
1085 1965050 : if (ch == '$')
1086 0 : return nullptr; // Do not support this.
1087 1965050 : if (*fmt >= '0' && *fmt <= '9')
1088 1270810 : continue;
1089 694233 : break;
1090 : }
1091 : }
1092 :
1093 : // Length modifier.
1094 4359640 : for (; (ch = *fmt) != '\0'; ++fmt)
1095 : {
1096 4359640 : if (ch == 'h' || ch == 'l' || ch == 'j' || ch == 'z' || ch == 't' ||
1097 : ch == 'L')
1098 84306 : continue;
1099 4275330 : else if (ch == 'I' && fmt[1] == '6' && fmt[2] == '4')
1100 8 : fmt += 2;
1101 : else
1102 4275320 : 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 2431010 : int CPLvsnprintf(char *str, size_t size, CPL_FORMAT_STRING(const char *fmt),
1132 : va_list args)
1133 : {
1134 2431010 : if (size == 0)
1135 0 : return vsnprintf(str, size, fmt, args);
1136 :
1137 : va_list wrk_args;
1138 :
1139 : #ifdef va_copy
1140 2431010 : va_copy(wrk_args, args);
1141 : #else
1142 : wrk_args = args;
1143 : #endif
1144 :
1145 2431010 : const char *fmt_ori = fmt;
1146 2431010 : size_t offset_out = 0;
1147 2431010 : char ch = '\0';
1148 2431010 : bool bFormatUnknown = false;
1149 :
1150 35083700 : for (; (ch = *fmt) != '\0'; ++fmt)
1151 : {
1152 32654300 : if (ch == '%')
1153 : {
1154 4276110 : if (strncmp(fmt, "%.*f", 4) == 0)
1155 : {
1156 830 : const int precision = va_arg(wrk_args, int);
1157 830 : const double val = va_arg(wrk_args, double);
1158 : const int local_ret =
1159 863 : snprintf(str + offset_out, size - offset_out, "%.*f",
1160 : precision, val);
1161 : // MSVC vsnprintf() returns -1.
1162 863 : if (local_ret < 0 || offset_out + local_ret >= size)
1163 : break;
1164 15704 : for (int j = 0; j < local_ret; ++j)
1165 : {
1166 14874 : if (str[offset_out + j] == ',')
1167 : {
1168 0 : str[offset_out + j] = '.';
1169 0 : break;
1170 : }
1171 : }
1172 830 : offset_out += local_ret;
1173 830 : fmt += strlen("%.*f") - 1;
1174 830 : continue;
1175 : }
1176 :
1177 4275280 : const char *ptrend = CPLvsnprintf_get_end_of_formatting(fmt + 1);
1178 4275220 : if (ptrend == nullptr || ptrend - fmt >= 20)
1179 : {
1180 0 : bFormatUnknown = true;
1181 0 : break;
1182 : }
1183 4275320 : char end = *ptrend;
1184 4275320 : char end_m1 = ptrend[-1];
1185 :
1186 4275320 : char localfmt[22] = {};
1187 4275320 : memcpy(localfmt, fmt, ptrend - fmt + 1);
1188 4275320 : localfmt[ptrend - fmt + 1] = '\0';
1189 :
1190 4275320 : int local_ret = 0;
1191 4275320 : if (end == '%')
1192 : {
1193 15021 : if (offset_out == size - 1)
1194 0 : break;
1195 15021 : local_ret = 1;
1196 15021 : str[offset_out] = '%';
1197 : }
1198 4260300 : else if (end == 'd' || end == 'i' || end == 'c')
1199 : {
1200 1306440 : if (end_m1 == 'h')
1201 0 : call_native_snprintf(int);
1202 1306440 : else if (end_m1 == 'l' && ptrend[-2] != 'l')
1203 4165 : call_native_snprintf(long);
1204 1302270 : else if (end_m1 == 'l' && ptrend[-2] == 'l')
1205 22187 : call_native_snprintf(GIntBig);
1206 1280080 : else if (end_m1 == '4' && ptrend[-2] == '6' &&
1207 0 : ptrend[-3] == 'I')
1208 : // Microsoft I64 modifier.
1209 0 : call_native_snprintf(GIntBig);
1210 1280080 : else if (end_m1 == 'z')
1211 0 : call_native_snprintf(size_t);
1212 1280080 : 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 1280080 : call_native_snprintf(int);
1220 : }
1221 2953860 : else if (end == 'o' || end == 'u' || end == 'x' || end == 'X')
1222 : {
1223 1207000 : if (end_m1 == 'h')
1224 0 : call_native_snprintf(unsigned int);
1225 1207000 : else if (end_m1 == 'l' && ptrend[-2] != 'l')
1226 772 : call_native_snprintf(unsigned long);
1227 1206220 : else if (end_m1 == 'l' && ptrend[-2] == 'l')
1228 14477 : call_native_snprintf(GUIntBig);
1229 1191750 : else if (end_m1 == '4' && ptrend[-2] == '6' &&
1230 0 : ptrend[-3] == 'I')
1231 : // Microsoft I64 modifier.
1232 0 : call_native_snprintf(GUIntBig);
1233 1191750 : else if (end_m1 == 'z')
1234 0 : call_native_snprintf(size_t);
1235 1191750 : 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 1191750 : call_native_snprintf(unsigned int);
1243 : }
1244 1746860 : else if (end == 'e' || end == 'E' || end == 'f' || end == 'F' ||
1245 1028740 : end == 'g' || end == 'G' || end == 'a' || end == 'A')
1246 : {
1247 718098 : if (end_m1 == 'L')
1248 0 : call_native_snprintf(long double);
1249 : else
1250 718098 : call_native_snprintf(double);
1251 : // MSVC vsnprintf() returns -1.
1252 718086 : if (local_ret < 0 || offset_out + local_ret >= size)
1253 : break;
1254 10073000 : for (int j = 0; j < local_ret; ++j)
1255 : {
1256 9355020 : if (str[offset_out + j] == ',')
1257 : {
1258 0 : str[offset_out + j] = '.';
1259 0 : break;
1260 : }
1261 717998 : }
1262 : }
1263 1028760 : else if (end == 's')
1264 : {
1265 1023360 : const char *pszPtr = va_arg(wrk_args, const char *);
1266 1023350 : CPLAssert(pszPtr);
1267 1023360 : local_ret = snprintf(str + offset_out, size - offset_out,
1268 : localfmt, pszPtr);
1269 : }
1270 5407 : else if (end == 'p')
1271 : {
1272 5398 : call_native_snprintf(void *);
1273 : }
1274 : else
1275 : {
1276 9 : bFormatUnknown = true;
1277 9 : break;
1278 : }
1279 : // MSVC vsnprintf() returns -1.
1280 4275150 : if (local_ret < 0 || offset_out + local_ret >= size)
1281 : break;
1282 4274290 : offset_out += local_ret;
1283 4274290 : fmt = ptrend;
1284 : }
1285 : else
1286 : {
1287 28378100 : if (offset_out == size - 1)
1288 589 : break;
1289 28377600 : str[offset_out++] = *fmt;
1290 : }
1291 : }
1292 2430910 : if (ch == '\0' && offset_out < size)
1293 2429440 : str[offset_out] = '\0';
1294 : else
1295 : {
1296 1470 : 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 1482 : va_end(wrk_args);
1305 1482 : va_copy(wrk_args, args);
1306 : #else
1307 : wrk_args = args;
1308 : #endif
1309 : #if defined(HAVE_VSNPRINTF)
1310 1482 : 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 2430920 : va_end(wrk_args);
1318 : #endif
1319 :
1320 2430920 : 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 166722 : int CPLsnprintf(char *str, size_t size, CPL_FORMAT_STRING(const char *fmt), ...)
1352 : {
1353 : va_list args;
1354 :
1355 166722 : va_start(args, fmt);
1356 166722 : const int ret = CPLvsnprintf(str, size, fmt, args);
1357 166720 : va_end(args);
1358 166720 : 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 1817 : int CPLsscanf(const char *str, CPL_SCANF_FORMAT_STRING(const char *fmt), ...)
1471 : #endif
1472 : {
1473 1817 : bool error = false;
1474 1817 : int ret = 0;
1475 1817 : const char *fmt_ori = fmt;
1476 : va_list args;
1477 :
1478 1817 : va_start(args, fmt);
1479 14065 : for (; *fmt != '\0' && *str != '\0'; ++fmt)
1480 : {
1481 12248 : if (*fmt == '%')
1482 : {
1483 7014 : if (fmt[1] == 'l' && fmt[2] == 'f')
1484 : {
1485 7014 : fmt += 2;
1486 : char *end;
1487 7014 : *(va_arg(args, double *)) = CPLStrtod(str, &end);
1488 7014 : if (end > str)
1489 : {
1490 7014 : ++ret;
1491 7014 : str = end;
1492 : }
1493 : else
1494 7014 : 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 1817 : va_end(args);
1513 :
1514 1817 : if (error)
1515 : {
1516 0 : CPLError(CE_Failure, CPLE_NotSupported,
1517 : "Format %s not supported by CPLsscanf()", fmt_ori);
1518 : }
1519 :
1520 1817 : 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 3342190 : bool CPLTestBool(const char *pszValue)
1543 : {
1544 4175640 : return !(EQUAL(pszValue, "NO") || EQUAL(pszValue, "FALSE") ||
1545 4175640 : 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 45 : int CPLTestBoolean(const char *pszValue)
1590 : {
1591 45 : 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 343294 : bool CPLFetchBool(CSLConstList papszStrList, const char *pszKey, bool bDefault)
1615 :
1616 : {
1617 343294 : if (CSLFindString(papszStrList, pszKey) != -1)
1618 2 : return true;
1619 :
1620 343075 : const char *const pszValue = CSLFetchNameValue(papszStrList, pszKey);
1621 343194 : if (pszValue == nullptr)
1622 325435 : return bDefault;
1623 :
1624 17759 : 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 1384 : int CSLFetchBoolean(CSLConstList papszStrList, const char *pszKey, int bDefault)
1648 :
1649 : {
1650 1384 : 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 839367 : const char *CSLFetchNameValueDef(CSLConstList papszStrList, const char *pszName,
1659 : const char *pszDefault)
1660 :
1661 : {
1662 839367 : const char *pszResult = CSLFetchNameValue(papszStrList, pszName);
1663 839416 : if (pszResult != nullptr)
1664 178850 : return pszResult;
1665 :
1666 660566 : 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 17426200 : const char *CSLFetchNameValue(CSLConstList papszStrList, const char *pszName)
1686 : {
1687 17426200 : if (papszStrList == nullptr || pszName == nullptr)
1688 4634740 : return nullptr;
1689 :
1690 12791500 : const size_t nLen = strlen(pszName);
1691 19898600 : while (*papszStrList != nullptr)
1692 : {
1693 7460220 : if (EQUALN(*papszStrList, pszName, nLen) &&
1694 359943 : ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
1695 : {
1696 353029 : return (*papszStrList) + nLen + 1;
1697 : }
1698 7107190 : ++papszStrList;
1699 : }
1700 12438400 : 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 16230300 : int CSLFindName(CSLConstList papszStrList, const char *pszName)
1718 : {
1719 16230300 : if (papszStrList == nullptr || pszName == nullptr)
1720 790535 : return -1;
1721 :
1722 15439800 : const size_t nLen = strlen(pszName);
1723 15439800 : int iIndex = 0;
1724 130279000 : while (*papszStrList != nullptr)
1725 : {
1726 122366000 : if (EQUALN(*papszStrList, pszName, nLen) &&
1727 8286850 : ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
1728 : {
1729 7526820 : return iIndex;
1730 : }
1731 114840000 : ++iIndex;
1732 114840000 : ++papszStrList;
1733 : }
1734 7912990 : 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 6319 : CPLErr CPLParseMemorySize(const char *pszValue, GIntBig *pnValue,
1759 : bool *pbUnitSpecified)
1760 : {
1761 6319 : const char *start = pszValue;
1762 6319 : char *end = nullptr;
1763 :
1764 : // trim leading whitespace
1765 6323 : while (*start == ' ')
1766 : {
1767 4 : start++;
1768 : }
1769 :
1770 6319 : auto len = CPLStrnlen(start, 100);
1771 6319 : double value = CPLStrtodM(start, &end);
1772 6319 : const char *unit = nullptr;
1773 6319 : bool unitIsNotPercent = false;
1774 :
1775 6319 : 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 6316 : if (value < 0 || !std::isfinite(value))
1783 : {
1784 2 : CPLError(CE_Failure, CPLE_IllegalArg,
1785 : "Memory size must be a positive number or zero.");
1786 2 : return CE_Failure;
1787 : }
1788 :
1789 18217 : for (const char *c = end; c < start + len; c++)
1790 : {
1791 11908 : if (unit == nullptr)
1792 : {
1793 : // check various suffixes and convert number into bytes
1794 6212 : if (*c == '%')
1795 : {
1796 511 : 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 509 : auto bytes = CPLGetUsablePhysicalRAM();
1803 509 : if (bytes == 0)
1804 : {
1805 0 : CPLError(CE_Failure, CPLE_NotSupported,
1806 : "Cannot determine usable physical RAM");
1807 0 : return CE_Failure;
1808 : }
1809 509 : value *= static_cast<double>(bytes / 100);
1810 509 : unit = c;
1811 : }
1812 : else
1813 : {
1814 5701 : switch (*c)
1815 : {
1816 32 : case 'G':
1817 : case 'g':
1818 32 : value *= 1024;
1819 : [[fallthrough]];
1820 5692 : case 'M':
1821 : case 'm':
1822 5692 : value *= 1024;
1823 : [[fallthrough]];
1824 5696 : case 'K':
1825 : case 'k':
1826 5696 : value *= 1024;
1827 5696 : unit = c;
1828 5696 : unitIsNotPercent = true;
1829 5696 : break;
1830 3 : case ' ':
1831 3 : 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 5696 : else if (unitIsNotPercent && c == unit + 1 && (*c == 'b' || *c == 'B'))
1840 : {
1841 : // ignore 'B' or 'b' as part of unit
1842 5695 : 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 6309 : *pnValue = static_cast<GIntBig>(value);
1853 6309 : if (pbUnitSpecified)
1854 : {
1855 588 : *pbUnitSpecified = (unit != nullptr);
1856 : }
1857 6309 : 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 81264 : const char *CPLParseNameValue(const char *pszNameValue, char **ppszKey)
1886 : {
1887 1162230 : for (int i = 0; pszNameValue[i] != '\0'; ++i)
1888 : {
1889 1159150 : if (pszNameValue[i] == '=' || pszNameValue[i] == ':')
1890 : {
1891 78177 : const char *pszValue = pszNameValue + i + 1;
1892 86342 : while (*pszValue == ' ' || *pszValue == '\t')
1893 8165 : ++pszValue;
1894 :
1895 78177 : if (ppszKey != nullptr)
1896 : {
1897 78155 : *ppszKey = static_cast<char *>(CPLMalloc(i + 1));
1898 78155 : memcpy(*ppszKey, pszNameValue, i);
1899 78155 : (*ppszKey)[i] = '\0';
1900 78426 : while (i > 0 &&
1901 78426 : ((*ppszKey)[i - 1] == ' ' || (*ppszKey)[i - 1] == '\t'))
1902 : {
1903 271 : (*ppszKey)[i - 1] = '\0';
1904 271 : i--;
1905 : }
1906 : }
1907 :
1908 78177 : return pszValue;
1909 : }
1910 : }
1911 :
1912 3087 : 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 14544 : char **CSLFetchNameValueMultiple(CSLConstList papszStrList, const char *pszName)
1981 : {
1982 14544 : if (papszStrList == nullptr || pszName == nullptr)
1983 6581 : return nullptr;
1984 :
1985 7963 : const size_t nLen = strlen(pszName);
1986 7963 : char **papszValues = nullptr;
1987 21124 : while (*papszStrList != nullptr)
1988 : {
1989 13161 : if (EQUALN(*papszStrList, pszName, nLen) &&
1990 55 : ((*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':'))
1991 : {
1992 55 : papszValues = CSLAddString(papszValues, (*papszStrList) + nLen + 1);
1993 : }
1994 13161 : ++papszStrList;
1995 : }
1996 :
1997 7963 : 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 402055 : char **CSLAddNameValue(char **papszStrList, const char *pszName,
2016 : const char *pszValue)
2017 : {
2018 402055 : if (pszName == nullptr || pszValue == nullptr)
2019 27 : return papszStrList;
2020 :
2021 402028 : const size_t nLen = strlen(pszName) + strlen(pszValue) + 2;
2022 402028 : char *pszLine = static_cast<char *>(CPLMalloc(nLen));
2023 402048 : snprintf(pszLine, nLen, "%s=%s", pszName, pszValue);
2024 402048 : papszStrList = CSLAddString(papszStrList, pszLine);
2025 402031 : CPLFree(pszLine);
2026 :
2027 402053 : 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 432949 : char **CSLSetNameValue(char **papszList, const char *pszName,
2055 : const char *pszValue)
2056 : {
2057 432949 : if (pszName == nullptr)
2058 38 : return papszList;
2059 :
2060 432911 : size_t nLen = strlen(pszName);
2061 433585 : while (nLen > 0 && pszName[nLen - 1] == ' ')
2062 674 : nLen--;
2063 432911 : char **papszPtr = papszList;
2064 7080740 : while (papszPtr && *papszPtr != nullptr)
2065 : {
2066 6688440 : if (EQUALN(*papszPtr, pszName, nLen))
2067 : {
2068 : size_t i;
2069 43010 : for (i = nLen; (*papszPtr)[i] == ' '; ++i)
2070 : {
2071 : }
2072 42336 : if ((*papszPtr)[i] == '=' || (*papszPtr)[i] == ':')
2073 : {
2074 : // Found it.
2075 : // Change the value... make sure to keep the ':' or '='.
2076 40612 : const char cSep = (*papszPtr)[i];
2077 :
2078 40612 : CPLFree(*papszPtr);
2079 :
2080 : // If the value is NULL, remove this entry completely.
2081 40604 : if (pszValue == nullptr)
2082 : {
2083 43413 : while (papszPtr[1] != nullptr)
2084 : {
2085 10541 : *papszPtr = papszPtr[1];
2086 10541 : ++papszPtr;
2087 : }
2088 32872 : *papszPtr = nullptr;
2089 : }
2090 :
2091 : // Otherwise replace with new value.
2092 : else
2093 : {
2094 7732 : const size_t nLen2 = strlen(pszName) + strlen(pszValue) + 2;
2095 7732 : *papszPtr = static_cast<char *>(CPLMalloc(nLen2));
2096 7659 : snprintf(*papszPtr, nLen2, "%s%c%s", pszName, cSep,
2097 : pszValue);
2098 : }
2099 40531 : return papszList;
2100 : }
2101 : }
2102 6647820 : ++papszPtr;
2103 : }
2104 :
2105 392299 : if (pszValue == nullptr)
2106 4341 : return papszList;
2107 :
2108 : // The name does not exist yet. Create a new entry.
2109 387958 : 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.
2189 : *
2190 : * CPLES_SQL(3): All single quotes are replaced with two single quotes.
2191 : * Suitable for use when constructing literal values for SQL commands where
2192 : * the literal will be enclosed in single quotes.
2193 : *
2194 : * CPLES_CSV(4): If the values contains commas, semicolons, tabs, double quotes,
2195 : * or newlines it placed in double quotes, and double quotes in the value are
2196 : * doubled. Suitable for use when constructing field values for .csv files.
2197 : * Note that CPLUnescapeString() currently does not support this format, only
2198 : * CPLEscapeString(). See cpl_csv.cpp for CSV parsing support.
2199 : *
2200 : * CPLES_SQLI(7): All double quotes are replaced with two double quotes.
2201 : * Suitable for use when constructing identifiers for SQL commands where
2202 : * the literal will be enclosed in double quotes.
2203 : *
2204 : * @param pszInput the string to escape.
2205 : * @param nLength The number of bytes of data to preserve. If this is -1
2206 : * the strlen(pszString) function will be used to compute the length.
2207 : * @param nScheme the encoding scheme to use.
2208 : *
2209 : * @return an escaped, zero terminated string that should be freed with
2210 : * CPLFree() when no longer needed.
2211 : */
2212 :
2213 696720 : char *CPLEscapeString(const char *pszInput, int nLength, int nScheme)
2214 : {
2215 696720 : const size_t szLength =
2216 696720 : (nLength < 0) ? strlen(pszInput) : static_cast<size_t>(nLength);
2217 : #define nLength no_longer_use_me
2218 :
2219 696720 : size_t nSizeAlloc = 1;
2220 : #if SIZEOF_VOIDP < 8
2221 : bool bWrapAround = false;
2222 : const auto IncSizeAlloc = [&nSizeAlloc, &bWrapAround](size_t inc)
2223 : {
2224 : constexpr size_t SZ_MAX = std::numeric_limits<size_t>::max();
2225 : if (nSizeAlloc > SZ_MAX - inc)
2226 : {
2227 : bWrapAround = true;
2228 : nSizeAlloc = 0;
2229 : }
2230 : nSizeAlloc += inc;
2231 : };
2232 : #else
2233 43194900 : const auto IncSizeAlloc = [&nSizeAlloc](size_t inc) { nSizeAlloc += inc; };
2234 : #endif
2235 :
2236 696720 : if (nScheme == CPLES_BackslashQuotable)
2237 : {
2238 45751 : for (size_t iIn = 0; iIn < szLength; iIn++)
2239 : {
2240 45631 : if (pszInput[iIn] == '\0' || pszInput[iIn] == '\n' ||
2241 44877 : pszInput[iIn] == '"' || pszInput[iIn] == '\\')
2242 876 : IncSizeAlloc(2);
2243 : else
2244 44755 : IncSizeAlloc(1);
2245 : }
2246 : }
2247 696600 : else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
2248 : {
2249 43112300 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2250 : {
2251 42418800 : if (pszInput[iIn] == '<')
2252 : {
2253 1420 : IncSizeAlloc(4);
2254 : }
2255 42417300 : else if (pszInput[iIn] == '>')
2256 : {
2257 1570 : IncSizeAlloc(4);
2258 : }
2259 42415800 : else if (pszInput[iIn] == '&')
2260 : {
2261 844 : IncSizeAlloc(5);
2262 : }
2263 42414900 : else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
2264 : {
2265 2080 : IncSizeAlloc(6);
2266 : }
2267 : // Python 2 does not display the UTF-8 character corresponding
2268 : // to the byte-order mark (BOM), so escape it.
2269 42412900 : else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
2270 2 : 0xEF &&
2271 : (reinterpret_cast<const unsigned char *>(
2272 2 : pszInput))[iIn + 1] == 0xBB &&
2273 : (reinterpret_cast<const unsigned char *>(
2274 2 : pszInput))[iIn + 2] == 0xBF)
2275 : {
2276 2 : IncSizeAlloc(8);
2277 2 : iIn += 2;
2278 : }
2279 42412800 : else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
2280 22192 : 0x20 &&
2281 22192 : pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
2282 110 : pszInput[iIn] != 0xD)
2283 : {
2284 : // These control characters are unrepresentable in XML format,
2285 : // so we just drop them. #4117
2286 : }
2287 : else
2288 : {
2289 42412800 : IncSizeAlloc(1);
2290 : }
2291 693550 : }
2292 : }
2293 3050 : else if (nScheme == CPLES_URL) // Untested at implementation.
2294 : {
2295 10119 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2296 : {
2297 9628 : if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
2298 3707 : (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
2299 1868 : (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
2300 925 : pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
2301 884 : pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
2302 516 : pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
2303 494 : pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
2304 492 : pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
2305 482 : pszInput[iIn] == ',')
2306 : {
2307 9152 : IncSizeAlloc(1);
2308 : }
2309 : else
2310 : {
2311 476 : IncSizeAlloc(3);
2312 : }
2313 : }
2314 : }
2315 2559 : else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
2316 : {
2317 794 : const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
2318 11656 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2319 : {
2320 10862 : if (pszInput[iIn] == chQuote)
2321 : {
2322 5 : IncSizeAlloc(2);
2323 : }
2324 : else
2325 : {
2326 10857 : IncSizeAlloc(1);
2327 : }
2328 794 : }
2329 : }
2330 1765 : else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
2331 : {
2332 1765 : if (nScheme == CPLES_CSV && strcspn(pszInput, "\",;\t\n\r") == szLength)
2333 : {
2334 : char *pszOutput =
2335 1527 : static_cast<char *>(VSI_MALLOC_VERBOSE(szLength + 1));
2336 1527 : if (pszOutput == nullptr)
2337 0 : return nullptr;
2338 1527 : memcpy(pszOutput, pszInput, szLength + 1);
2339 1527 : return pszOutput;
2340 : }
2341 : else
2342 : {
2343 238 : IncSizeAlloc(1);
2344 13101 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2345 : {
2346 12863 : if (pszInput[iIn] == '\"')
2347 : {
2348 169 : IncSizeAlloc(2);
2349 : }
2350 : else
2351 12694 : IncSizeAlloc(1);
2352 : }
2353 238 : IncSizeAlloc(1);
2354 238 : }
2355 : }
2356 : else
2357 : {
2358 0 : CPLError(CE_Failure, CPLE_AppDefined,
2359 : "Undefined escaping scheme (%d) in CPLEscapeString()",
2360 : nScheme);
2361 0 : return CPLStrdup("");
2362 : }
2363 :
2364 : #if SIZEOF_VOIDP < 8
2365 : if (bWrapAround)
2366 : {
2367 : CPLError(CE_Failure, CPLE_OutOfMemory,
2368 : "Out of memory in CPLEscapeString()");
2369 : return nullptr;
2370 : }
2371 : #endif
2372 :
2373 695193 : char *pszOutput = static_cast<char *>(VSI_MALLOC_VERBOSE(nSizeAlloc));
2374 695193 : if (pszOutput == nullptr)
2375 0 : return nullptr;
2376 :
2377 695193 : size_t iOut = 0;
2378 :
2379 695193 : if (nScheme == CPLES_BackslashQuotable)
2380 : {
2381 45751 : for (size_t iIn = 0; iIn < szLength; iIn++)
2382 : {
2383 45631 : if (pszInput[iIn] == '\0')
2384 : {
2385 689 : pszOutput[iOut++] = '\\';
2386 689 : pszOutput[iOut++] = '0';
2387 : }
2388 44942 : else if (pszInput[iIn] == '\n')
2389 : {
2390 65 : pszOutput[iOut++] = '\\';
2391 65 : pszOutput[iOut++] = 'n';
2392 : }
2393 44877 : else if (pszInput[iIn] == '"')
2394 : {
2395 121 : pszOutput[iOut++] = '\\';
2396 121 : pszOutput[iOut++] = '\"';
2397 : }
2398 44756 : else if (pszInput[iIn] == '\\')
2399 : {
2400 1 : pszOutput[iOut++] = '\\';
2401 1 : pszOutput[iOut++] = '\\';
2402 : }
2403 : else
2404 44755 : pszOutput[iOut++] = pszInput[iIn];
2405 : }
2406 120 : pszOutput[iOut++] = '\0';
2407 : }
2408 695073 : else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
2409 : {
2410 43112300 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2411 : {
2412 42418800 : if (pszInput[iIn] == '<')
2413 : {
2414 1420 : pszOutput[iOut++] = '&';
2415 1420 : pszOutput[iOut++] = 'l';
2416 1420 : pszOutput[iOut++] = 't';
2417 1420 : pszOutput[iOut++] = ';';
2418 : }
2419 42417300 : else if (pszInput[iIn] == '>')
2420 : {
2421 1570 : pszOutput[iOut++] = '&';
2422 1570 : pszOutput[iOut++] = 'g';
2423 1570 : pszOutput[iOut++] = 't';
2424 1570 : pszOutput[iOut++] = ';';
2425 : }
2426 42415800 : else if (pszInput[iIn] == '&')
2427 : {
2428 844 : pszOutput[iOut++] = '&';
2429 844 : pszOutput[iOut++] = 'a';
2430 844 : pszOutput[iOut++] = 'm';
2431 844 : pszOutput[iOut++] = 'p';
2432 844 : pszOutput[iOut++] = ';';
2433 : }
2434 42414900 : else if (pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES)
2435 : {
2436 2080 : pszOutput[iOut++] = '&';
2437 2080 : pszOutput[iOut++] = 'q';
2438 2080 : pszOutput[iOut++] = 'u';
2439 2080 : pszOutput[iOut++] = 'o';
2440 2080 : pszOutput[iOut++] = 't';
2441 2080 : pszOutput[iOut++] = ';';
2442 : }
2443 : // Python 2 does not display the UTF-8 character corresponding
2444 : // to the byte-order mark (BOM), so escape it.
2445 42412900 : else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] ==
2446 2 : 0xEF &&
2447 : (reinterpret_cast<const unsigned char *>(
2448 2 : pszInput))[iIn + 1] == 0xBB &&
2449 : (reinterpret_cast<const unsigned char *>(
2450 2 : pszInput))[iIn + 2] == 0xBF)
2451 : {
2452 2 : pszOutput[iOut++] = '&';
2453 2 : pszOutput[iOut++] = '#';
2454 2 : pszOutput[iOut++] = 'x';
2455 2 : pszOutput[iOut++] = 'F';
2456 2 : pszOutput[iOut++] = 'E';
2457 2 : pszOutput[iOut++] = 'F';
2458 2 : pszOutput[iOut++] = 'F';
2459 2 : pszOutput[iOut++] = ';';
2460 2 : iIn += 2;
2461 : }
2462 42412800 : else if ((reinterpret_cast<const unsigned char *>(pszInput))[iIn] <
2463 22192 : 0x20 &&
2464 22192 : pszInput[iIn] != 0x9 && pszInput[iIn] != 0xA &&
2465 110 : pszInput[iIn] != 0xD)
2466 : {
2467 : // These control characters are unrepresentable in XML format,
2468 : // so we just drop them. #4117
2469 : }
2470 : else
2471 : {
2472 42412800 : pszOutput[iOut++] = pszInput[iIn];
2473 : }
2474 : }
2475 693550 : pszOutput[iOut++] = '\0';
2476 : }
2477 1523 : else if (nScheme == CPLES_URL) // Untested at implementation.
2478 : {
2479 10119 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2480 : {
2481 9628 : if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
2482 3707 : (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
2483 1868 : (pszInput[iIn] >= '0' && pszInput[iIn] <= '9') ||
2484 925 : pszInput[iIn] == '$' || pszInput[iIn] == '-' ||
2485 884 : pszInput[iIn] == '_' || pszInput[iIn] == '.' ||
2486 516 : pszInput[iIn] == '+' || pszInput[iIn] == '!' ||
2487 494 : pszInput[iIn] == '*' || pszInput[iIn] == '\'' ||
2488 492 : pszInput[iIn] == '(' || pszInput[iIn] == ')' ||
2489 482 : pszInput[iIn] == ',')
2490 : {
2491 9152 : pszOutput[iOut++] = pszInput[iIn];
2492 : }
2493 : else
2494 : {
2495 476 : snprintf(pszOutput + iOut, nSizeAlloc - iOut, "%%%02X",
2496 476 : static_cast<unsigned char>(pszInput[iIn]));
2497 476 : iOut += 3;
2498 : }
2499 : }
2500 491 : pszOutput[iOut++] = '\0';
2501 : }
2502 1032 : else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
2503 : {
2504 794 : const char chQuote = nScheme == CPLES_SQL ? '\'' : '\"';
2505 11656 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2506 : {
2507 10862 : if (pszInput[iIn] == chQuote)
2508 : {
2509 5 : pszOutput[iOut++] = chQuote;
2510 5 : pszOutput[iOut++] = chQuote;
2511 : }
2512 : else
2513 : {
2514 10857 : pszOutput[iOut++] = pszInput[iIn];
2515 : }
2516 : }
2517 794 : pszOutput[iOut++] = '\0';
2518 : }
2519 238 : else if (nScheme == CPLES_CSV || nScheme == CPLES_CSV_FORCE_QUOTING)
2520 : {
2521 238 : pszOutput[iOut++] = '\"';
2522 :
2523 13101 : for (size_t iIn = 0; iIn < szLength; ++iIn)
2524 : {
2525 12863 : if (pszInput[iIn] == '\"')
2526 : {
2527 169 : pszOutput[iOut++] = '\"';
2528 169 : pszOutput[iOut++] = '\"';
2529 : }
2530 : else
2531 12694 : pszOutput[iOut++] = pszInput[iIn];
2532 : }
2533 238 : pszOutput[iOut++] = '\"';
2534 238 : pszOutput[iOut++] = '\0';
2535 : }
2536 :
2537 695193 : return pszOutput;
2538 : #undef nLength
2539 : }
2540 :
2541 : /************************************************************************/
2542 : /* CPLUnescapeString() */
2543 : /************************************************************************/
2544 :
2545 : /**
2546 : * Unescape a string.
2547 : *
2548 : * This function does the opposite of CPLEscapeString(). Given a string
2549 : * with special values escaped according to some scheme, it will return a
2550 : * new copy of the string returned to its original form.
2551 : *
2552 : * @param pszInput the input string. This is a zero terminated string.
2553 : * @param pnLength location to return the length of the unescaped string,
2554 : * which may in some cases include embedded '\\0' characters.
2555 : * @param nScheme the escaped scheme to undo (see CPLEscapeString() for a
2556 : * list). Does not yet support CSV.
2557 : *
2558 : * @return a copy of the unescaped string that should be freed by the
2559 : * application using CPLFree() when no longer needed.
2560 : */
2561 :
2562 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
2563 37143 : char *CPLUnescapeString(const char *pszInput, int *pnLength, int nScheme)
2564 :
2565 : {
2566 37143 : int iOut = 0;
2567 :
2568 : // TODO: Why times 4?
2569 37143 : char *pszOutput = static_cast<char *>(CPLMalloc(4 * strlen(pszInput) + 1));
2570 37137 : pszOutput[0] = '\0';
2571 :
2572 37137 : if (nScheme == CPLES_BackslashQuotable)
2573 : {
2574 53012 : for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
2575 : {
2576 52566 : if (pszInput[iIn] == '\\')
2577 : {
2578 769 : ++iIn;
2579 769 : if (pszInput[iIn] == '\0')
2580 0 : break;
2581 769 : if (pszInput[iIn] == 'n')
2582 6 : pszOutput[iOut++] = '\n';
2583 763 : else if (pszInput[iIn] == '0')
2584 675 : pszOutput[iOut++] = '\0';
2585 : else
2586 88 : pszOutput[iOut++] = pszInput[iIn];
2587 : }
2588 : else
2589 : {
2590 51797 : pszOutput[iOut++] = pszInput[iIn];
2591 : }
2592 : }
2593 : }
2594 36691 : else if (nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES)
2595 : {
2596 36067 : char ch = '\0';
2597 32979500 : for (int iIn = 0; (ch = pszInput[iIn]) != '\0'; ++iIn)
2598 : {
2599 32943400 : if (ch != '&')
2600 : {
2601 32617300 : pszOutput[iOut++] = ch;
2602 : }
2603 326123 : else if (STARTS_WITH_CI(pszInput + iIn, "<"))
2604 : {
2605 5097 : pszOutput[iOut++] = '<';
2606 5097 : iIn += 3;
2607 : }
2608 321026 : else if (STARTS_WITH_CI(pszInput + iIn, ">"))
2609 : {
2610 5248 : pszOutput[iOut++] = '>';
2611 5248 : iIn += 3;
2612 : }
2613 315778 : else if (STARTS_WITH_CI(pszInput + iIn, "&"))
2614 : {
2615 227512 : pszOutput[iOut++] = '&';
2616 227512 : iIn += 4;
2617 : }
2618 88266 : else if (STARTS_WITH_CI(pszInput + iIn, "'"))
2619 : {
2620 686 : pszOutput[iOut++] = '\'';
2621 686 : iIn += 5;
2622 : }
2623 87580 : else if (STARTS_WITH_CI(pszInput + iIn, """))
2624 : {
2625 87424 : pszOutput[iOut++] = '"';
2626 87424 : iIn += 5;
2627 : }
2628 156 : else if (STARTS_WITH_CI(pszInput + iIn, "&#x"))
2629 : {
2630 3 : wchar_t anVal[2] = {0, 0};
2631 3 : iIn += 3;
2632 :
2633 3 : unsigned int nVal = 0;
2634 : while (true)
2635 : {
2636 7 : ch = pszInput[iIn++];
2637 7 : if (ch >= 'a' && ch <= 'f')
2638 1 : nVal = nVal * 16U +
2639 : static_cast<unsigned int>(ch - 'a' + 10);
2640 6 : else if (ch >= 'A' && ch <= 'F')
2641 1 : nVal = nVal * 16U +
2642 : static_cast<unsigned int>(ch - 'A' + 10);
2643 5 : else if (ch >= '0' && ch <= '9')
2644 2 : nVal = nVal * 16U + static_cast<unsigned int>(ch - '0');
2645 : else
2646 : break;
2647 : }
2648 3 : anVal[0] = static_cast<wchar_t>(nVal);
2649 3 : if (ch != ';')
2650 1 : break;
2651 2 : iIn--;
2652 :
2653 : char *pszUTF8 =
2654 2 : CPLRecodeFromWChar(anVal, "WCHAR_T", CPL_ENC_UTF8);
2655 2 : int nLen = static_cast<int>(strlen(pszUTF8));
2656 2 : memcpy(pszOutput + iOut, pszUTF8, nLen);
2657 2 : CPLFree(pszUTF8);
2658 2 : iOut += nLen;
2659 : }
2660 153 : else if (STARTS_WITH_CI(pszInput + iIn, "&#"))
2661 : {
2662 159 : wchar_t anVal[2] = {0, 0};
2663 159 : iIn += 2;
2664 :
2665 159 : unsigned int nVal = 0;
2666 : while (true)
2667 : {
2668 646 : ch = pszInput[iIn++];
2669 646 : if (ch >= '0' && ch <= '9')
2670 487 : nVal = nVal * 10U + static_cast<unsigned int>(ch - '0');
2671 : else
2672 : break;
2673 : }
2674 159 : anVal[0] = static_cast<wchar_t>(nVal);
2675 159 : if (ch != ';')
2676 1 : break;
2677 158 : iIn--;
2678 :
2679 : char *pszUTF8 =
2680 158 : CPLRecodeFromWChar(anVal, "WCHAR_T", CPL_ENC_UTF8);
2681 158 : const int nLen = static_cast<int>(strlen(pszUTF8));
2682 158 : memcpy(pszOutput + iOut, pszUTF8, nLen);
2683 158 : CPLFree(pszUTF8);
2684 158 : iOut += nLen;
2685 : }
2686 : else
2687 : {
2688 : // Illegal escape sequence.
2689 0 : CPLDebug("CPL",
2690 : "Error unescaping CPLES_XML text, '&' character "
2691 : "followed by unhandled escape sequence.");
2692 2 : break;
2693 : }
2694 36075 : }
2695 : }
2696 624 : else if (nScheme == CPLES_URL)
2697 : {
2698 31071 : for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
2699 : {
2700 30492 : if (pszInput[iIn] == '%' && pszInput[iIn + 1] != '\0' &&
2701 770 : pszInput[iIn + 2] != '\0')
2702 : {
2703 770 : int nHexChar = 0;
2704 :
2705 770 : if (pszInput[iIn + 1] >= 'A' && pszInput[iIn + 1] <= 'F')
2706 0 : nHexChar += 16 * (pszInput[iIn + 1] - 'A' + 10);
2707 770 : else if (pszInput[iIn + 1] >= 'a' && pszInput[iIn + 1] <= 'f')
2708 0 : nHexChar += 16 * (pszInput[iIn + 1] - 'a' + 10);
2709 770 : else if (pszInput[iIn + 1] >= '0' && pszInput[iIn + 1] <= '9')
2710 770 : nHexChar += 16 * (pszInput[iIn + 1] - '0');
2711 : else
2712 0 : CPLDebug("CPL",
2713 : "Error unescaping CPLES_URL text, percent not "
2714 : "followed by two hex digits.");
2715 :
2716 770 : if (pszInput[iIn + 2] >= 'A' && pszInput[iIn + 2] <= 'F')
2717 746 : nHexChar += pszInput[iIn + 2] - 'A' + 10;
2718 24 : else if (pszInput[iIn + 2] >= 'a' && pszInput[iIn + 2] <= 'f')
2719 0 : nHexChar += pszInput[iIn + 2] - 'a' + 10;
2720 24 : else if (pszInput[iIn + 2] >= '0' && pszInput[iIn + 2] <= '9')
2721 24 : nHexChar += pszInput[iIn + 2] - '0';
2722 : else
2723 0 : CPLDebug("CPL",
2724 : "Error unescaping CPLES_URL text, percent not "
2725 : "followed by two hex digits.");
2726 :
2727 770 : pszOutput[iOut++] = static_cast<char>(nHexChar);
2728 770 : iIn += 2;
2729 : }
2730 29722 : else if (pszInput[iIn] == '+')
2731 : {
2732 0 : pszOutput[iOut++] = ' ';
2733 : }
2734 : else
2735 : {
2736 29722 : pszOutput[iOut++] = pszInput[iIn];
2737 : }
2738 : }
2739 : }
2740 45 : else if (nScheme == CPLES_SQL || nScheme == CPLES_SQLI)
2741 : {
2742 45 : char szQuote = nScheme == CPLES_SQL ? '\'' : '\"';
2743 565 : for (int iIn = 0; pszInput[iIn] != '\0'; ++iIn)
2744 : {
2745 520 : if (pszInput[iIn] == szQuote && pszInput[iIn + 1] == szQuote)
2746 : {
2747 3 : ++iIn;
2748 3 : pszOutput[iOut++] = pszInput[iIn];
2749 : }
2750 : else
2751 : {
2752 517 : pszOutput[iOut++] = pszInput[iIn];
2753 : }
2754 45 : }
2755 : }
2756 0 : else if (nScheme == CPLES_CSV)
2757 : {
2758 0 : CPLError(CE_Fatal, CPLE_NotSupported,
2759 : "CSV Unescaping not yet implemented.");
2760 : }
2761 : else
2762 : {
2763 0 : CPLError(CE_Fatal, CPLE_NotSupported, "Unknown escaping style.");
2764 : }
2765 :
2766 37144 : pszOutput[iOut] = '\0';
2767 :
2768 37144 : if (pnLength != nullptr)
2769 22004 : *pnLength = iOut;
2770 :
2771 37144 : return pszOutput;
2772 : }
2773 :
2774 : /************************************************************************/
2775 : /* CPLBinaryToHex() */
2776 : /************************************************************************/
2777 :
2778 : /**
2779 : * Binary to hexadecimal translation.
2780 : *
2781 : * @param nBytes number of bytes of binary data in pabyData.
2782 : * @param pabyData array of data bytes to translate.
2783 : *
2784 : * @return hexadecimal translation, zero terminated. Free with CPLFree().
2785 : */
2786 :
2787 4213 : char *CPLBinaryToHex(int nBytes, const GByte *pabyData)
2788 :
2789 : {
2790 4213 : CPLAssert(nBytes >= 0);
2791 : char *pszHex = static_cast<char *>(
2792 4213 : VSI_MALLOC_VERBOSE(static_cast<size_t>(nBytes) * 2 + 1));
2793 4213 : if (!pszHex)
2794 : {
2795 0 : pszHex = CPLStrdup("");
2796 0 : return pszHex;
2797 : }
2798 4213 : pszHex[nBytes * 2] = '\0';
2799 :
2800 4213 : constexpr char achHex[] = "0123456789ABCDEF";
2801 :
2802 248148 : for (size_t i = 0; i < static_cast<size_t>(nBytes); ++i)
2803 : {
2804 243935 : const int nLow = pabyData[i] & 0x0f;
2805 243935 : const int nHigh = (pabyData[i] & 0xf0) >> 4;
2806 :
2807 243935 : pszHex[i * 2] = achHex[nHigh];
2808 243935 : pszHex[i * 2 + 1] = achHex[nLow];
2809 : }
2810 :
2811 4213 : return pszHex;
2812 : }
2813 :
2814 : /************************************************************************/
2815 : /* CPLHexToBinary() */
2816 : /************************************************************************/
2817 :
2818 : constexpr unsigned char hex2char[256] = {
2819 : // Not Hex characters.
2820 : 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,
2821 : 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-9
2823 : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
2824 : // A-F
2825 : 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2826 : // Not Hex characters.
2827 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2828 : // a-f
2829 : 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2830 : 0, 0, 0, 0, 0, 0, 0, 0, 0,
2831 : // Not Hex characters (upper 128 characters).
2832 : 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,
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};
2838 :
2839 : /**
2840 : * Hexadecimal to binary translation
2841 : *
2842 : * @param pszHex the input hex encoded string.
2843 : * @param pnBytes the returned count of decoded bytes placed here.
2844 : *
2845 : * @return returns binary buffer of data - free with CPLFree().
2846 : */
2847 :
2848 3903 : GByte *CPLHexToBinary(const char *pszHex, int *pnBytes)
2849 : {
2850 3903 : const GByte *pabyHex = reinterpret_cast<const GByte *>(pszHex);
2851 3903 : const size_t nHexLen = strlen(pszHex);
2852 :
2853 3903 : GByte *pabyWKB = static_cast<GByte *>(CPLMalloc(nHexLen / 2 + 2));
2854 :
2855 1046450 : for (size_t i = 0; i < nHexLen / 2; ++i)
2856 : {
2857 1042550 : const unsigned char h1 = hex2char[pabyHex[2 * i]];
2858 1042550 : const unsigned char h2 = hex2char[pabyHex[2 * i + 1]];
2859 :
2860 : // First character is high bits, second is low bits.
2861 1042550 : pabyWKB[i] = static_cast<GByte>((h1 << 4) | h2);
2862 : }
2863 3903 : pabyWKB[nHexLen / 2] = 0;
2864 3903 : *pnBytes = static_cast<int>(nHexLen / 2);
2865 :
2866 3903 : return pabyWKB;
2867 : }
2868 :
2869 : /************************************************************************/
2870 : /* CPLGetValueType() */
2871 : /************************************************************************/
2872 :
2873 : /**
2874 : * Detect the type of the value contained in a string, whether it is
2875 : * a real, an integer or a string
2876 : * Leading and trailing spaces are skipped in the analysis.
2877 : *
2878 : * Note: in the context of this function, integer must be understood in a
2879 : * broad sense. It does not mean that the value can fit into a 32 bit integer
2880 : * for example. It might be larger.
2881 : *
2882 : * @param pszValue the string to analyze
2883 : *
2884 : * @return returns the type of the value contained in the string.
2885 : */
2886 :
2887 538813 : CPLValueType CPLGetValueType(const char *pszValue)
2888 : {
2889 : // Doubles : "+25.e+3", "-25.e-3", "25.e3", "25e3", " 25e3 "
2890 : // Not doubles: "25e 3", "25e.3", "-2-5e3", "2-5e3", "25.25.3", "-3d", "d1"
2891 : // "XXeYYYYYYYYYYYYYYYYYYY" that evaluates to infinity
2892 :
2893 538813 : if (pszValue == nullptr)
2894 0 : return CPL_VALUE_STRING;
2895 :
2896 538813 : const char *pszValueInit = pszValue;
2897 :
2898 : // Skip leading spaces.
2899 538864 : while (isspace(static_cast<unsigned char>(*pszValue)))
2900 51 : ++pszValue;
2901 :
2902 538813 : if (*pszValue == '\0')
2903 376 : return CPL_VALUE_STRING;
2904 :
2905 : // Skip leading + or -.
2906 538437 : if (*pszValue == '+' || *pszValue == '-')
2907 84555 : ++pszValue;
2908 :
2909 538437 : constexpr char DIGIT_ZERO = '0';
2910 538437 : if (pszValue[0] == DIGIT_ZERO && pszValue[1] != '\0' && pszValue[1] != '.')
2911 903 : return CPL_VALUE_STRING;
2912 :
2913 537534 : bool bFoundDot = false;
2914 537534 : bool bFoundExponent = false;
2915 537534 : bool bIsLastCharExponent = false;
2916 537534 : bool bIsReal = false;
2917 537534 : const char *pszAfterExponent = nullptr;
2918 537534 : bool bFoundMantissa = false;
2919 :
2920 6903580 : for (; *pszValue != '\0'; ++pszValue)
2921 : {
2922 6409680 : if (isdigit(static_cast<unsigned char>(*pszValue)))
2923 : {
2924 5977940 : bIsLastCharExponent = false;
2925 5977940 : bFoundMantissa = true;
2926 : }
2927 431737 : else if (isspace(static_cast<unsigned char>(*pszValue)))
2928 : {
2929 772 : const char *pszTmp = pszValue;
2930 1548 : while (isspace(static_cast<unsigned char>(*pszTmp)))
2931 776 : ++pszTmp;
2932 772 : if (*pszTmp == 0)
2933 24 : break;
2934 : else
2935 748 : return CPL_VALUE_STRING;
2936 : }
2937 430965 : else if (*pszValue == '-' || *pszValue == '+')
2938 : {
2939 610 : if (bIsLastCharExponent)
2940 : {
2941 : // Do nothing.
2942 : }
2943 : else
2944 : {
2945 340 : return CPL_VALUE_STRING;
2946 : }
2947 270 : bIsLastCharExponent = false;
2948 : }
2949 430355 : else if (*pszValue == '.')
2950 : {
2951 387566 : bIsReal = true;
2952 387566 : if (!bFoundDot && !bIsLastCharExponent)
2953 387563 : bFoundDot = true;
2954 : else
2955 3 : return CPL_VALUE_STRING;
2956 387563 : bIsLastCharExponent = false;
2957 : }
2958 42789 : else if (*pszValue == 'D' || *pszValue == 'd' || *pszValue == 'E' ||
2959 38218 : *pszValue == 'e')
2960 : {
2961 4835 : if (!bFoundMantissa)
2962 4556 : return CPL_VALUE_STRING;
2963 279 : if (!(pszValue[1] == '+' || pszValue[1] == '-' ||
2964 9 : isdigit(static_cast<unsigned char>(pszValue[1]))))
2965 2 : return CPL_VALUE_STRING;
2966 :
2967 277 : bIsReal = true;
2968 277 : if (!bFoundExponent)
2969 276 : bFoundExponent = true;
2970 : else
2971 1 : return CPL_VALUE_STRING;
2972 276 : pszAfterExponent = pszValue + 1;
2973 276 : bIsLastCharExponent = true;
2974 : }
2975 : else
2976 : {
2977 37954 : return CPL_VALUE_STRING;
2978 : }
2979 : }
2980 :
2981 493930 : if (bIsReal && pszAfterExponent && strlen(pszAfterExponent) > 3)
2982 : {
2983 : // cppcheck-suppress unreadVariable
2984 15 : const double dfVal = CPLAtof(pszValueInit);
2985 15 : if (std::isinf(dfVal))
2986 1 : return CPL_VALUE_STRING;
2987 : }
2988 :
2989 493929 : return bIsReal ? CPL_VALUE_REAL : CPL_VALUE_INTEGER;
2990 : }
2991 :
2992 : /************************************************************************/
2993 : /* CPLStrlcpy() */
2994 : /************************************************************************/
2995 :
2996 : /**
2997 : * Copy source string to a destination buffer.
2998 : *
2999 : * This function ensures that the destination buffer is always NUL terminated
3000 : * (provided that its length is at least 1).
3001 : *
3002 : * This function is designed to be a safer, more consistent, and less error
3003 : * prone replacement for strncpy. Its contract is identical to libbsd's strlcpy.
3004 : *
3005 : * Truncation can be detected by testing if the return value of CPLStrlcpy
3006 : * is greater or equal to nDestSize.
3007 :
3008 : \verbatim
3009 : char szDest[5] = {};
3010 : if( CPLStrlcpy(szDest, "abcde", sizeof(szDest)) >= sizeof(szDest) )
3011 : fprintf(stderr, "truncation occurred !\n");
3012 : \endverbatim
3013 :
3014 : * @param pszDest destination buffer
3015 : * @param pszSrc source string. Must be NUL terminated
3016 : * @param nDestSize size of destination buffer (including space for the NUL
3017 : * terminator character)
3018 : *
3019 : * @return the length of the source string (=strlen(pszSrc))
3020 : *
3021 : * @since GDAL 1.7.0
3022 : */
3023 86726 : size_t CPLStrlcpy(char *pszDest, const char *pszSrc, size_t nDestSize)
3024 : {
3025 86726 : if (nDestSize == 0)
3026 0 : return strlen(pszSrc);
3027 :
3028 86726 : char *pszDestIter = pszDest;
3029 86726 : const char *pszSrcIter = pszSrc;
3030 :
3031 86726 : --nDestSize;
3032 801899 : while (nDestSize != 0 && *pszSrcIter != '\0')
3033 : {
3034 715173 : *pszDestIter = *pszSrcIter;
3035 715173 : ++pszDestIter;
3036 715173 : ++pszSrcIter;
3037 715173 : --nDestSize;
3038 : }
3039 86726 : *pszDestIter = '\0';
3040 86726 : return pszSrcIter - pszSrc + strlen(pszSrcIter);
3041 : }
3042 :
3043 : /************************************************************************/
3044 : /* CPLStrlcat() */
3045 : /************************************************************************/
3046 :
3047 : /**
3048 : * Appends a source string to a destination buffer.
3049 : *
3050 : * This function ensures that the destination buffer is always NUL terminated
3051 : * (provided that its length is at least 1 and that there is at least one byte
3052 : * free in pszDest, that is to say strlen(pszDest_before) < nDestSize)
3053 : *
3054 : * This function is designed to be a safer, more consistent, and less error
3055 : * prone replacement for strncat. Its contract is identical to libbsd's strlcat.
3056 : *
3057 : * Truncation can be detected by testing if the return value of CPLStrlcat
3058 : * is greater or equal to nDestSize.
3059 :
3060 : \verbatim
3061 : char szDest[5] = {};
3062 : CPLStrlcpy(szDest, "ab", sizeof(szDest));
3063 : if( CPLStrlcat(szDest, "cde", sizeof(szDest)) >= sizeof(szDest) )
3064 : fprintf(stderr, "truncation occurred !\n");
3065 : \endverbatim
3066 :
3067 : * @param pszDest destination buffer. Must be NUL terminated before
3068 : * running CPLStrlcat
3069 : * @param pszSrc source string. Must be NUL terminated
3070 : * @param nDestSize size of destination buffer (including space for the
3071 : * NUL terminator character)
3072 : *
3073 : * @return the theoretical length of the destination string after concatenation
3074 : * (=strlen(pszDest_before) + strlen(pszSrc)).
3075 : * If strlen(pszDest_before) >= nDestSize, then it returns
3076 : * nDestSize + strlen(pszSrc)
3077 : *
3078 : * @since GDAL 1.7.0
3079 : */
3080 362 : size_t CPLStrlcat(char *pszDest, const char *pszSrc, size_t nDestSize)
3081 : {
3082 362 : char *pszDestIter = pszDest;
3083 :
3084 25725 : while (nDestSize != 0 && *pszDestIter != '\0')
3085 : {
3086 25363 : ++pszDestIter;
3087 25363 : --nDestSize;
3088 : }
3089 :
3090 362 : return pszDestIter - pszDest + CPLStrlcpy(pszDestIter, pszSrc, nDestSize);
3091 : }
3092 :
3093 : /************************************************************************/
3094 : /* CPLStrnlen() */
3095 : /************************************************************************/
3096 :
3097 : /**
3098 : * Returns the length of a NUL terminated string by reading at most
3099 : * the specified number of bytes.
3100 : *
3101 : * The CPLStrnlen() function returns min(strlen(pszStr), nMaxLen).
3102 : * Only the first nMaxLen bytes of the string will be read. Useful to
3103 : * test if a string contains at least nMaxLen characters without reading
3104 : * the full string up to the NUL terminating character.
3105 : *
3106 : * @param pszStr a NUL terminated string
3107 : * @param nMaxLen maximum number of bytes to read in pszStr
3108 : *
3109 : * @return strlen(pszStr) if the length is lesser than nMaxLen, otherwise
3110 : * nMaxLen if the NUL character has not been found in the first nMaxLen bytes.
3111 : *
3112 : * @since GDAL 1.7.0
3113 : */
3114 :
3115 441407 : size_t CPLStrnlen(const char *pszStr, size_t nMaxLen)
3116 : {
3117 441407 : size_t nLen = 0;
3118 23844900 : while (nLen < nMaxLen && *pszStr != '\0')
3119 : {
3120 23403500 : ++nLen;
3121 23403500 : ++pszStr;
3122 : }
3123 441407 : return nLen;
3124 : }
3125 :
3126 : /************************************************************************/
3127 : /* CSLParseCommandLine() */
3128 : /************************************************************************/
3129 :
3130 : /**
3131 : * Tokenize command line arguments in a list of strings.
3132 : *
3133 : * @param pszCommandLine command line
3134 : *
3135 : * @return NULL terminated list of strings to free with CSLDestroy()
3136 : *
3137 : * @since GDAL 2.1
3138 : */
3139 884 : char **CSLParseCommandLine(const char *pszCommandLine)
3140 : {
3141 884 : return CSLTokenizeString(pszCommandLine);
3142 : }
3143 :
3144 : /************************************************************************/
3145 : /* CPLToupper() */
3146 : /************************************************************************/
3147 :
3148 : /** Converts a (ASCII) lowercase character to uppercase.
3149 : *
3150 : * Same as standard toupper(), except that it is not locale sensitive.
3151 : *
3152 : * @since GDAL 3.9
3153 : */
3154 24421900 : int CPLToupper(int c)
3155 : {
3156 24421900 : return (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c;
3157 : }
3158 :
3159 : /************************************************************************/
3160 : /* CPLTolower() */
3161 : /************************************************************************/
3162 :
3163 : /** Converts a (ASCII) uppercase character to lowercase.
3164 : *
3165 : * Same as standard tolower(), except that it is not locale sensitive.
3166 : *
3167 : * @since GDAL 3.9
3168 : */
3169 19015400 : int CPLTolower(int c)
3170 : {
3171 19015400 : return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c;
3172 : }
3173 :
3174 : /************************************************************************/
3175 : /* CPLRemoveSQLComments() */
3176 : /************************************************************************/
3177 :
3178 : /** Remove SQL comments from a string
3179 : *
3180 : * @param osInput Input string.
3181 : * @since GDAL 3.11
3182 : */
3183 33 : std::string CPLRemoveSQLComments(const std::string &osInput)
3184 : {
3185 : const CPLStringList aosLines(
3186 66 : CSLTokenizeStringComplex(osInput.c_str(), "\r\n", FALSE, FALSE));
3187 33 : std::string osSQL;
3188 77 : for (const char *pszLine : aosLines)
3189 : {
3190 44 : char chQuote = 0;
3191 44 : int i = 0;
3192 740 : for (; pszLine[i] != '\0'; ++i)
3193 : {
3194 705 : if (chQuote)
3195 : {
3196 16 : if (pszLine[i] == chQuote)
3197 : {
3198 : // Deal with escaped quote character which is repeated,
3199 : // so 'foo''bar' or "foo""bar"
3200 5 : if (pszLine[i + 1] == chQuote)
3201 : {
3202 2 : i++;
3203 : }
3204 : else
3205 : {
3206 3 : chQuote = 0;
3207 : }
3208 : }
3209 : }
3210 689 : else if (pszLine[i] == '\'' || pszLine[i] == '"')
3211 : {
3212 3 : chQuote = pszLine[i];
3213 : }
3214 686 : else if (pszLine[i] == '-' && pszLine[i + 1] == '-')
3215 : {
3216 9 : break;
3217 : }
3218 : }
3219 44 : if (i > 0)
3220 : {
3221 37 : if (!osSQL.empty())
3222 4 : osSQL += ' ';
3223 37 : osSQL.append(pszLine, i);
3224 : }
3225 : }
3226 66 : return osSQL;
3227 : }
|