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