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