1 : /**********************************************************************
2 : * $Id: cpl_string.cpp 25044 2012-10-04 01:54:26Z rcoup $
3 : *
4 : * Name: cpl_string.cpp
5 : * Project: CPL - Common Portability Library
6 : * Purpose: String and Stringlist manipulation functions.
7 : * Author: Daniel Morissette, danmo@videotron.ca
8 : *
9 : **********************************************************************
10 : * Copyright (c) 1998, Daniel Morissette
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : **********************************************************************
30 : *
31 : * Independent Security Audit 2003/04/04 Andrey Kiselev:
32 : * Completed audit of this module. All functions may be used without buffer
33 : * overflows and stack corruptions with any kind of input data strings with
34 : * except of CPLSPrintf() and CSLAppendPrintf() (see note below).
35 : *
36 : * Security Audit 2003/03/28 warmerda:
37 : * Completed security audit. I believe that this module may be safely used
38 : * to parse tokenize arbitrary input strings, assemble arbitrary sets of
39 : * names values into string lists, unescape and escape text even if provided
40 : * by a potentially hostile source.
41 : *
42 : * CPLSPrintf() and CSLAppendPrintf() may not be safely invoked on
43 : * arbitrary length inputs since it has a fixed size output buffer on system
44 : * without vsnprintf().
45 : *
46 : **********************************************************************/
47 :
48 : #include "cpl_string.h"
49 : #include "cpl_vsi.h"
50 : #include "cpl_multiproc.h"
51 :
52 : #if defined(WIN32CE)
53 : # include <wce_errno.h>
54 : # include <wce_string.h>
55 : #endif
56 :
57 : CPL_CVSID("$Id: cpl_string.cpp 25044 2012-10-04 01:54:26Z rcoup $");
58 :
59 : /*=====================================================================
60 : StringList manipulation functions.
61 : =====================================================================*/
62 :
63 : /**********************************************************************
64 : * CSLAddString()
65 : *
66 : * Append a string to a StringList and return a pointer to the modified
67 : * StringList.
68 : * If the input StringList is NULL, then a new StringList is created.
69 : * Note that CSLAddString performance when building a list is in O(n^2)
70 : * which can cause noticable slow down when n > 10000.
71 : **********************************************************************/
72 8698191 : char **CSLAddString(char **papszStrList, const char *pszNewString)
73 : {
74 8698191 : int nItems=0;
75 :
76 8698191 : if (pszNewString == NULL)
77 0 : return papszStrList; /* Nothing to do!*/
78 :
79 : /* Allocate room for the new string */
80 8698191 : if (papszStrList == NULL)
81 797337 : papszStrList = (char**) CPLCalloc(2,sizeof(char*));
82 : else
83 : {
84 7900854 : nItems = CSLCount(papszStrList);
85 : papszStrList = (char**)CPLRealloc(papszStrList,
86 7900854 : (nItems+2)*sizeof(char*));
87 : }
88 :
89 : /* Copy the string in the list */
90 8698191 : papszStrList[nItems] = CPLStrdup(pszNewString);
91 8698191 : papszStrList[nItems+1] = NULL;
92 :
93 8698191 : return papszStrList;
94 : }
95 :
96 : /************************************************************************/
97 : /* CSLCount() */
98 : /************************************************************************/
99 :
100 : /**
101 : * Return number of items in a string list.
102 : *
103 : * Returns the number of items in a string list, not counting the
104 : * terminating NULL. Passing in NULL is safe, and will result in a count
105 : * of zero.
106 : *
107 : * Lists are counted by iterating through them so long lists will
108 : * take more time than short lists. Care should be taken to avoid using
109 : * CSLCount() as an end condition for loops as it will result in O(n^2)
110 : * behavior.
111 : *
112 : * @param papszStrList the string list to count.
113 : *
114 : * @return the number of entries.
115 : */
116 12955602 : int CSLCount(char **papszStrList)
117 : {
118 12955602 : int nItems=0;
119 :
120 12955602 : if (papszStrList)
121 : {
122 176201879 : while(*papszStrList != NULL)
123 : {
124 152748375 : nItems++;
125 152748375 : papszStrList++;
126 : }
127 : }
128 :
129 12955602 : return nItems;
130 : }
131 :
132 :
133 : /************************************************************************/
134 : /* CSLGetField() */
135 : /* */
136 : /* Fetches the indicated field, being careful not to crash if */
137 : /* the field doesn't exist within this string list. The */
138 : /* returned pointer should not be freed, and doesn't */
139 : /* necessarily last long. */
140 : /************************************************************************/
141 :
142 148731 : const char * CSLGetField( char ** papszStrList, int iField )
143 :
144 : {
145 : int i;
146 :
147 148731 : if( papszStrList == NULL || iField < 0 )
148 16036 : return( "" );
149 :
150 950861 : for( i = 0; i < iField+1; i++ )
151 : {
152 818167 : if( papszStrList[i] == NULL )
153 1 : return "";
154 : }
155 :
156 132694 : return( papszStrList[iField] );
157 : }
158 :
159 : /************************************************************************/
160 : /* CSLDestroy() */
161 : /************************************************************************/
162 :
163 : /**
164 : * Free string list.
165 : *
166 : * Frees the passed string list (null terminated array of strings).
167 : * It is safe to pass NULL.
168 : *
169 : * @param papszStrList the list to free.
170 : */
171 7740379 : void CPL_STDCALL CSLDestroy(char **papszStrList)
172 : {
173 : char **papszPtr;
174 :
175 7740379 : if (papszStrList)
176 : {
177 5756630 : papszPtr = papszStrList;
178 27025722 : while(*papszPtr != NULL)
179 : {
180 15512462 : CPLFree(*papszPtr);
181 15512462 : papszPtr++;
182 : }
183 :
184 5756630 : CPLFree(papszStrList);
185 : }
186 7740379 : }
187 :
188 : /************************************************************************/
189 : /* CSLDuplicate() */
190 : /************************************************************************/
191 :
192 : /**
193 : * Clone a string list.
194 : *
195 : * Efficiently allocates a copy of a string list. The returned list is
196 : * owned by the caller and should be freed with CSLDestroy().
197 : *
198 : * @param papszStrList the input string list.
199 : *
200 : * @return newly allocated copy.
201 : */
202 :
203 116215 : char **CSLDuplicate(char **papszStrList)
204 : {
205 : char **papszNewList, **papszSrc, **papszDst;
206 : int nLines;
207 :
208 116215 : nLines = CSLCount(papszStrList);
209 :
210 116215 : if (nLines == 0)
211 85219 : return NULL;
212 :
213 30996 : papszNewList = (char **)CPLMalloc((nLines+1)*sizeof(char*));
214 30996 : papszSrc = papszStrList;
215 30996 : papszDst = papszNewList;
216 :
217 669975 : while(*papszSrc != NULL)
218 : {
219 607983 : *papszDst = CPLStrdup(*papszSrc);
220 :
221 607983 : papszSrc++;
222 607983 : papszDst++;
223 : }
224 30996 : *papszDst = NULL;
225 :
226 30996 : return papszNewList;
227 : }
228 :
229 : /************************************************************************/
230 : /* CSLMerge */
231 : /************************************************************************/
232 :
233 : /**
234 : * \brief Merge two lists.
235 : *
236 : * The two lists are merged, ensuring that if any keys appear in both
237 : * that the value from the second (papszOverride) list take precidence.
238 : *
239 : * @param papszOrig the original list, being modified.
240 : * @param papszOverride the list of items being merged in. This list
241 : * is unaltered and remains owned by the caller.
242 : *
243 : * @return updated list.
244 : */
245 :
246 666 : char **CSLMerge( char **papszOrig, char **papszOverride )
247 :
248 : {
249 : int i;
250 :
251 666 : if( papszOrig == NULL && papszOverride != NULL )
252 68 : return CSLDuplicate( papszOverride );
253 :
254 598 : if( papszOverride == NULL )
255 418 : return papszOrig;
256 :
257 527 : for( i = 0; papszOverride[i] != NULL; i++ )
258 : {
259 347 : char *pszKey = NULL;
260 347 : const char *pszValue = CPLParseNameValue( papszOverride[i], &pszKey );
261 :
262 347 : papszOrig = CSLSetNameValue( papszOrig, pszKey, pszValue );
263 347 : CPLFree( pszKey );
264 : }
265 :
266 180 : return papszOrig;
267 : }
268 :
269 : /************************************************************************/
270 : /* CSLLoad2() */
271 : /************************************************************************/
272 :
273 : /**
274 : * Load a text file into a string list.
275 : *
276 : * The VSI*L API is used, so VSIFOpenL() supported objects that aren't
277 : * physical files can also be accessed. Files are returned as a string list,
278 : * with one item in the string list per line. End of line markers are
279 : * stripped (by CPLReadLineL()).
280 : *
281 : * If reading the file fails a CPLError() will be issued and NULL returned.
282 : *
283 : * @param pszFname the name of the file to read.
284 : * @param nMaxLines maximum number of lines to read before stopping, or -1 for no limit.
285 : * @param nMaxCols maximum number of characters in a line before stopping, or -1 for no limit.
286 : * @param papszOptions NULL-terminated array of options. Unused for now.
287 : *
288 : * @return a string list with the files lines, now owned by caller. To be freed with CSLDestroy()
289 : *
290 : * @since GDAL 1.7.0
291 : */
292 :
293 1974 : char **CSLLoad2(const char *pszFname, int nMaxLines, int nMaxCols, char** papszOptions)
294 : {
295 : VSILFILE *fp;
296 : const char *pszLine;
297 1974 : char **papszStrList=NULL;
298 1974 : int nLines = 0;
299 1974 : int nAllocatedLines = 0;
300 :
301 1974 : fp = VSIFOpenL(pszFname, "rb");
302 :
303 1974 : if (fp)
304 : {
305 582 : CPLErrorReset();
306 582 : while(!VSIFEofL(fp) && (nMaxLines == -1 || nLines < nMaxLines))
307 : {
308 3864 : if ( (pszLine = CPLReadLine2L(fp, nMaxCols, papszOptions)) != NULL )
309 : {
310 3861 : if (nLines + 1 >= nAllocatedLines)
311 : {
312 : char** papszStrListNew;
313 639 : nAllocatedLines = 16 + nAllocatedLines * 2;
314 : papszStrListNew = (char**) VSIRealloc(papszStrList,
315 639 : nAllocatedLines * sizeof(char*));
316 639 : if (papszStrListNew == NULL)
317 : {
318 0 : VSIFCloseL(fp);
319 0 : CPLReadLineL( NULL );
320 : CPLError( CE_Failure, CPLE_OutOfMemory,
321 : "CSLLoad2(\"%s\") failed: not enough memory to allocate lines.",
322 0 : pszFname );
323 0 : return papszStrList;
324 : }
325 639 : papszStrList = papszStrListNew;
326 : }
327 3861 : papszStrList[nLines] = CPLStrdup(pszLine);
328 3861 : papszStrList[nLines + 1] = NULL;
329 3861 : nLines ++;
330 : }
331 : else
332 3 : break;
333 : }
334 :
335 582 : VSIFCloseL(fp);
336 :
337 582 : CPLReadLineL( NULL );
338 : }
339 : else
340 : {
341 1392 : if (CSLFetchBoolean(papszOptions, "EMIT_ERROR_IF_CANNOT_OPEN_FILE", TRUE))
342 : {
343 : /* Unable to open file */
344 : CPLError( CE_Failure, CPLE_OpenFailed,
345 : "CSLLoad2(\"%s\") failed: unable to open file.",
346 0 : pszFname );
347 : }
348 : }
349 :
350 1974 : return papszStrList;
351 : }
352 :
353 : /************************************************************************/
354 : /* CSLLoad() */
355 : /************************************************************************/
356 :
357 : /**
358 : * Load a text file into a string list.
359 : *
360 : * The VSI*L API is used, so VSIFOpenL() supported objects that aren't
361 : * physical files can also be accessed. Files are returned as a string list,
362 : * with one item in the string list per line. End of line markers are
363 : * stripped (by CPLReadLineL()).
364 : *
365 : * If reading the file fails a CPLError() will be issued and NULL returned.
366 : *
367 : * @param pszFname the name of the file to read.
368 : *
369 : * @return a string list with the files lines, now owned by caller. To be freed with CSLDestroy()
370 : */
371 :
372 231 : char **CSLLoad(const char *pszFname)
373 : {
374 231 : return CSLLoad2(pszFname, -1, -1, NULL);
375 : }
376 :
377 : /**********************************************************************
378 : * CSLSave()
379 : *
380 : * Write a stringlist to a text file.
381 : *
382 : * Returns the number of lines written, or 0 if the file could not
383 : * be written.
384 : **********************************************************************/
385 46 : int CSLSave(char **papszStrList, const char *pszFname)
386 : {
387 : VSILFILE *fp;
388 46 : int nLines = 0;
389 :
390 46 : if (papszStrList)
391 : {
392 46 : if ((fp = VSIFOpenL(pszFname, "wt")) != NULL)
393 : {
394 415 : while(*papszStrList != NULL)
395 : {
396 323 : if( VSIFPrintfL( fp, "%s\n", *papszStrList ) < 1 )
397 : {
398 : CPLError( CE_Failure, CPLE_FileIO,
399 : "CSLSave(\"%s\") failed: unable to write to output file.",
400 0 : pszFname );
401 0 : break; /* A Problem happened... abort */
402 : }
403 :
404 323 : nLines++;
405 323 : papszStrList++;
406 : }
407 :
408 46 : VSIFCloseL(fp);
409 : }
410 : else
411 : {
412 : /* Unable to open file */
413 : CPLError( CE_Failure, CPLE_OpenFailed,
414 : "CSLSave(\"%s\") failed: unable to open output file.",
415 0 : pszFname );
416 : }
417 : }
418 :
419 46 : return nLines;
420 : }
421 :
422 : /**********************************************************************
423 : * CSLPrint()
424 : *
425 : * Print a StringList to fpOut. If fpOut==NULL, then output is sent
426 : * to stdout.
427 : *
428 : * Returns the number of lines printed.
429 : **********************************************************************/
430 0 : int CSLPrint(char **papszStrList, FILE *fpOut)
431 : {
432 0 : int nLines=0;
433 :
434 0 : if (fpOut == NULL)
435 0 : fpOut = stdout;
436 :
437 0 : if (papszStrList)
438 : {
439 0 : while(*papszStrList != NULL)
440 : {
441 0 : VSIFPrintf(fpOut, "%s\n", *papszStrList);
442 0 : nLines++;
443 0 : papszStrList++;
444 : }
445 : }
446 :
447 0 : return nLines;
448 : }
449 :
450 :
451 : /**********************************************************************
452 : * CSLInsertStrings()
453 : *
454 : * Copies the contents of a StringList inside another StringList
455 : * before the specified line.
456 : *
457 : * nInsertAtLineNo is a 0-based line index before which the new strings
458 : * should be inserted. If this value is -1 or is larger than the actual
459 : * number of strings in the list then the strings are added at the end
460 : * of the source StringList.
461 : *
462 : * Returns the modified StringList.
463 : **********************************************************************/
464 1194 : char **CSLInsertStrings(char **papszStrList, int nInsertAtLineNo,
465 : char **papszNewLines)
466 : {
467 : int i, nSrcLines, nDstLines, nToInsert;
468 : char **ppszSrc, **ppszDst;
469 :
470 1194 : if (papszNewLines == NULL ||
471 : ( nToInsert = CSLCount(papszNewLines) ) == 0)
472 2 : return papszStrList; /* Nothing to do!*/
473 :
474 1192 : nSrcLines = CSLCount(papszStrList);
475 1192 : nDstLines = nSrcLines + nToInsert;
476 :
477 : /* Allocate room for the new strings */
478 : papszStrList = (char**)CPLRealloc(papszStrList,
479 1192 : (nDstLines+1)*sizeof(char*));
480 :
481 : /* Make sure the array is NULL-terminated... it may not be if
482 : * papszStrList was NULL before Realloc()
483 : */
484 1192 : papszStrList[nSrcLines] = NULL;
485 :
486 : /* Make some room in the original list at the specified location
487 : * Note that we also have to move the NULL pointer at the end of
488 : * the source StringList.
489 : */
490 1192 : if (nInsertAtLineNo == -1 || nInsertAtLineNo > nSrcLines)
491 587 : nInsertAtLineNo = nSrcLines;
492 :
493 1192 : ppszSrc = papszStrList + nSrcLines;
494 1192 : ppszDst = papszStrList + nDstLines;
495 :
496 3390 : for (i=nSrcLines; i>=nInsertAtLineNo; i--)
497 : {
498 2198 : *ppszDst = *ppszSrc;
499 2198 : ppszDst--;
500 2198 : ppszSrc--;
501 : }
502 :
503 : /* Copy the strings to the list */
504 1192 : ppszSrc = papszNewLines;
505 1192 : ppszDst = papszStrList + nInsertAtLineNo;
506 :
507 19509 : for (; *ppszSrc != NULL; ppszSrc++, ppszDst++)
508 : {
509 18317 : *ppszDst = CPLStrdup(*ppszSrc);
510 : }
511 :
512 1192 : return papszStrList;
513 : }
514 :
515 : /**********************************************************************
516 : * CSLInsertString()
517 : *
518 : * Insert a string at a given line number inside a StringList
519 : *
520 : * nInsertAtLineNo is a 0-based line index before which the new string
521 : * should be inserted. If this value is -1 or is larger than the actual
522 : * number of strings in the list then the string is added at the end
523 : * of the source StringList.
524 : *
525 : * Returns the modified StringList.
526 : **********************************************************************/
527 39 : char **CSLInsertString(char **papszStrList, int nInsertAtLineNo,
528 : const char *pszNewLine)
529 : {
530 : char *apszList[2];
531 :
532 : /* Create a temporary StringList and call CSLInsertStrings()
533 : */
534 39 : apszList[0] = (char *) pszNewLine;
535 39 : apszList[1] = NULL;
536 :
537 39 : return CSLInsertStrings(papszStrList, nInsertAtLineNo, apszList);
538 : }
539 :
540 :
541 : /**********************************************************************
542 : * CSLRemoveStrings()
543 : *
544 : * Remove strings inside a StringList
545 : *
546 : * nFirstLineToDelete is the 0-based line index of the first line to
547 : * remove. If this value is -1 or is larger than the actual
548 : * number of strings in list then the nNumToRemove last strings are
549 : * removed.
550 : *
551 : * If ppapszRetStrings != NULL then the deleted strings won't be
552 : * free'd, they will be stored in a new StringList and the pointer to
553 : * this new list will be returned in *ppapszRetStrings.
554 : *
555 : * Returns the modified StringList.
556 : **********************************************************************/
557 68 : char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete,
558 : int nNumToRemove, char ***ppapszRetStrings)
559 : {
560 : int i, nSrcLines, nDstLines;
561 : char **ppszSrc, **ppszDst;
562 :
563 68 : nSrcLines = CSLCount(papszStrList);
564 68 : nDstLines = nSrcLines - nNumToRemove;
565 :
566 68 : if (nNumToRemove < 1 || nSrcLines == 0)
567 0 : return papszStrList; /* Nothing to do!*/
568 :
569 : /* If operation will result in an empty StringList then don't waste
570 : * time here!
571 : */
572 68 : if (nDstLines < 1)
573 : {
574 20 : CSLDestroy(papszStrList);
575 20 : return NULL;
576 : }
577 :
578 :
579 : /* Remove lines from the source StringList...
580 : * Either free() each line or store them to a new StringList depending on
581 : * the caller's choice.
582 : */
583 48 : ppszDst = papszStrList + nFirstLineToDelete;
584 :
585 48 : if (ppapszRetStrings == NULL)
586 : {
587 : /* free() all the strings that will be removed.
588 : */
589 96 : for (i=0; i < nNumToRemove; i++)
590 : {
591 48 : CPLFree(*ppszDst);
592 48 : *ppszDst = NULL;
593 : }
594 : }
595 : else
596 : {
597 : /* Store the strings to remove in a new StringList
598 : */
599 0 : *ppapszRetStrings = (char **)CPLCalloc(nNumToRemove+1, sizeof(char*));
600 :
601 0 : for (i=0; i < nNumToRemove; i++)
602 : {
603 0 : (*ppapszRetStrings)[i] = *ppszDst;
604 0 : *ppszDst = NULL;
605 0 : ppszDst++;
606 : }
607 : }
608 :
609 :
610 : /* Shift down all the lines that follow the lines to remove.
611 : */
612 48 : if (nFirstLineToDelete == -1 || nFirstLineToDelete > nSrcLines)
613 0 : nFirstLineToDelete = nDstLines;
614 :
615 48 : ppszSrc = papszStrList + nFirstLineToDelete + nNumToRemove;
616 48 : ppszDst = papszStrList + nFirstLineToDelete;
617 :
618 211 : for ( ; *ppszSrc != NULL; ppszSrc++, ppszDst++)
619 : {
620 163 : *ppszDst = *ppszSrc;
621 : }
622 : /* Move the NULL pointer at the end of the StringList */
623 48 : *ppszDst = *ppszSrc;
624 :
625 : /* At this point, we could realloc() papszStrList to a smaller size, but
626 : * since this array will likely grow again in further operations on the
627 : * StringList we'll leave it as it is.
628 : */
629 :
630 48 : return papszStrList;
631 : }
632 :
633 : /************************************************************************/
634 : /* CSLFindString() */
635 : /************************************************************************/
636 :
637 : /**
638 : * Find a string within a string list.
639 : *
640 : * Returns the index of the entry in the string list that contains the
641 : * target string. The string in the string list must be a full match for
642 : * the target, but the search is case insensitive.
643 : *
644 : * @param papszList the string list to be searched.
645 : * @param pszTarget the string to be searched for.
646 : *
647 : * @return the index of the string within the list or -1 on failure.
648 : */
649 :
650 1913822 : int CSLFindString( char ** papszList, const char * pszTarget )
651 :
652 : {
653 : int i;
654 :
655 1913822 : if( papszList == NULL )
656 217632 : return -1;
657 :
658 5488732 : for( i = 0; papszList[i] != NULL; i++ )
659 : {
660 4934154 : if( EQUAL(papszList[i],pszTarget) )
661 1141612 : return i;
662 : }
663 :
664 554578 : return -1;
665 : }
666 :
667 : /************************************************************************/
668 : /* CSLPartialFindString() */
669 : /************************************************************************/
670 :
671 : /**
672 : * Find a substring within a string list.
673 : *
674 : * Returns the index of the entry in the string list that contains the
675 : * target string as a substring. The search is case sensitive (unlike
676 : * CSLFindString()).
677 : *
678 : * @param papszHaystack the string list to be searched.
679 : * @param pszNeedle the substring to be searched for.
680 : *
681 : * @return the index of the string within the list or -1 on failure.
682 : */
683 :
684 3 : int CSLPartialFindString( char **papszHaystack, const char * pszNeedle )
685 : {
686 : int i;
687 3 : if (papszHaystack == NULL || pszNeedle == NULL)
688 0 : return -1;
689 :
690 11 : for (i = 0; papszHaystack[i] != NULL; i++)
691 : {
692 8 : if (strstr(papszHaystack[i],pszNeedle))
693 0 : return i;
694 : }
695 :
696 3 : return -1;
697 : }
698 :
699 :
700 : /**********************************************************************
701 : * CSLTokenizeString()
702 : *
703 : * Tokenizes a string and returns a StringList with one string for
704 : * each token.
705 : **********************************************************************/
706 5265 : char **CSLTokenizeString( const char *pszString )
707 : {
708 5265 : return CSLTokenizeString2( pszString, " ", CSLT_HONOURSTRINGS );
709 : }
710 :
711 : /************************************************************************/
712 : /* CSLTokenizeStringComplex() */
713 : /* */
714 : /* Obsolete tokenizing api. */
715 : /************************************************************************/
716 :
717 1613978 : char ** CSLTokenizeStringComplex( const char * pszString,
718 : const char * pszDelimiters,
719 : int bHonourStrings, int bAllowEmptyTokens )
720 :
721 : {
722 1613978 : int nFlags = 0;
723 :
724 1613978 : if( bHonourStrings )
725 1574966 : nFlags |= CSLT_HONOURSTRINGS;
726 1613978 : if( bAllowEmptyTokens )
727 507 : nFlags |= CSLT_ALLOWEMPTYTOKENS;
728 :
729 1613978 : return CSLTokenizeString2( pszString, pszDelimiters, nFlags );
730 : }
731 :
732 : /************************************************************************/
733 : /* CSLTokenizeString2() */
734 : /************************************************************************/
735 :
736 : /**
737 : * Tokenize a string.
738 : *
739 : * This function will split a string into tokens based on specified'
740 : * delimeter(s) with a variety of options. The returned result is a
741 : * string list that should be freed with CSLDestroy() when no longer
742 : * needed.
743 : *
744 : * The available parsing options are:
745 : *
746 : * - CSLT_ALLOWEMPTYTOKENS: allow the return of empty tokens when two
747 : * delimiters in a row occur with no other text between them. If not set,
748 : * empty tokens will be discarded;
749 : * - CSLT_STRIPLEADSPACES: strip leading space characters from the token (as
750 : * reported by isspace());
751 : * - CSLT_STRIPENDSPACES: strip ending space characters from the token (as
752 : * reported by isspace());
753 : * - CSLT_HONOURSTRINGS: double quotes can be used to hold values that should
754 : * not be broken into multiple tokens;
755 : * - CSLT_PRESERVEQUOTES: string quotes are carried into the tokens when this
756 : * is set, otherwise they are removed;
757 : * - CSLT_PRESERVEESCAPES: if set backslash escapes (for backslash itself,
758 : * and for literal double quotes) will be preserved in the tokens, otherwise
759 : * the backslashes will be removed in processing.
760 : *
761 : * \b Example:
762 : *
763 : * Parse a string into tokens based on various white space (space, newline,
764 : * tab) and then print out results and cleanup. Quotes may be used to hold
765 : * white space in tokens.
766 :
767 : \code
768 : char **papszTokens;
769 : int i;
770 :
771 : papszTokens =
772 : CSLTokenizeString2( pszCommand, " \t\n",
773 : CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS );
774 :
775 : for( i = 0; papszTokens != NULL && papszTokens[i] != NULL; i++ )
776 : printf( "arg %d: '%s'", papszTokens[i] );
777 : CSLDestroy( papszTokens );
778 : \endcode
779 :
780 : * @param pszString the string to be split into tokens.
781 : * @param pszDelimiters one or more characters to be used as token delimeters.
782 : * @param nCSLTFlags an ORing of one or more of the CSLT_ flag values.
783 : *
784 : * @return a string list of tokens owned by the caller.
785 : */
786 :
787 1644591 : char ** CSLTokenizeString2( const char * pszString,
788 : const char * pszDelimiters,
789 : int nCSLTFlags )
790 :
791 : {
792 1644591 : if( pszString == NULL )
793 2 : return (char **) CPLCalloc(sizeof(char *),1);
794 1644589 : CPLStringList oRetList;
795 : char *pszToken;
796 : int nTokenMax, nTokenLen;
797 1644589 : int bHonourStrings = (nCSLTFlags & CSLT_HONOURSTRINGS);
798 1644589 : int bAllowEmptyTokens = (nCSLTFlags & CSLT_ALLOWEMPTYTOKENS);
799 1644589 : int bStripLeadSpaces = (nCSLTFlags & CSLT_STRIPLEADSPACES);
800 1644589 : int bStripEndSpaces = (nCSLTFlags & CSLT_STRIPENDSPACES);
801 :
802 1644589 : pszToken = (char *) CPLCalloc(10,1);
803 1644589 : nTokenMax = 10;
804 :
805 5260020 : while( pszString != NULL && *pszString != '\0' )
806 : {
807 1970842 : int bInString = FALSE;
808 1970842 : int bStartString = TRUE;
809 :
810 1970842 : nTokenLen = 0;
811 :
812 : /* Try to find the next delimeter, marking end of token */
813 14434647 : for( ; *pszString != '\0'; pszString++ )
814 : {
815 :
816 : /* End if this is a delimeter skip it and break. */
817 12806899 : if( !bInString && strchr(pszDelimiters, *pszString) != NULL )
818 : {
819 343094 : pszString++;
820 343094 : break;
821 : }
822 :
823 : /* If this is a quote, and we are honouring constant
824 : strings, then process the constant strings, with out delim
825 : but don't copy over the quotes */
826 12463805 : if( bHonourStrings && *pszString == '"' )
827 : {
828 2092 : if( nCSLTFlags & CSLT_PRESERVEQUOTES )
829 : {
830 394 : pszToken[nTokenLen] = *pszString;
831 394 : nTokenLen++;
832 : }
833 :
834 2092 : if( bInString )
835 : {
836 1021 : bInString = FALSE;
837 1021 : continue;
838 : }
839 : else
840 : {
841 1071 : bInString = TRUE;
842 1071 : continue;
843 : }
844 : }
845 :
846 : /*
847 : * Within string constants we allow for escaped quotes, but in
848 : * processing them we will unescape the quotes and \\ sequence
849 : * reduces to \
850 : */
851 12461713 : if( bInString && pszString[0] == '\\' )
852 : {
853 0 : if ( pszString[1] == '"' || pszString[1] == '\\' )
854 : {
855 0 : if( nCSLTFlags & CSLT_PRESERVEESCAPES )
856 : {
857 0 : pszToken[nTokenLen] = *pszString;
858 0 : nTokenLen++;
859 : }
860 :
861 0 : pszString++;
862 : }
863 : }
864 :
865 : /*
866 : * Strip spaces at the token start if requested.
867 : */
868 12461713 : if ( !bInString && bStripLeadSpaces
869 : && bStartString && isspace((unsigned char)*pszString) )
870 1804 : continue;
871 :
872 12459909 : bStartString = FALSE;
873 :
874 : /*
875 : * Extend token buffer if we are running close to its end.
876 : */
877 12459909 : if( nTokenLen >= nTokenMax-3 )
878 : {
879 339409 : nTokenMax = nTokenMax * 2 + 10;
880 339409 : pszToken = (char *) CPLRealloc( pszToken, nTokenMax );
881 : }
882 :
883 12459909 : pszToken[nTokenLen] = *pszString;
884 12459909 : nTokenLen++;
885 : }
886 :
887 : /*
888 : * Strip spaces at the token end if requested.
889 : */
890 1970842 : if ( !bInString && bStripEndSpaces )
891 : {
892 11552 : while ( nTokenLen && isspace((unsigned char)pszToken[nTokenLen - 1]) )
893 0 : nTokenLen--;
894 : }
895 :
896 1970842 : pszToken[nTokenLen] = '\0';
897 :
898 : /*
899 : * Add the token.
900 : */
901 1970842 : if( pszToken[0] != '\0' || bAllowEmptyTokens )
902 1940631 : oRetList.AddString( pszToken );
903 : }
904 :
905 : /*
906 : * If the last token was empty, then we need to capture
907 : * it now, as the loop would skip it.
908 : */
909 1644589 : if( *pszString == '\0' && bAllowEmptyTokens && oRetList.Count() > 0
910 : && strchr(pszDelimiters,*(pszString-1)) != NULL )
911 : {
912 77 : oRetList.AddString( "" );
913 : }
914 :
915 1644589 : CPLFree( pszToken );
916 :
917 1644589 : if( oRetList.List() == NULL )
918 : {
919 : // we prefer to return empty lists as a pointer to
920 : // a null pointer since some client code might depend on this.
921 14181 : oRetList.Assign( (char**) CPLCalloc(sizeof(char**),1) );
922 : }
923 :
924 1644589 : return oRetList.StealList();
925 : }
926 :
927 : /**********************************************************************
928 : * CPLSPrintf()
929 : *
930 : * My own version of CPLSPrintf() that works with 10 static buffer.
931 : *
932 : * It returns a ref. to a static buffer that should not be freed and
933 : * is valid only until the next call to CPLSPrintf().
934 : *
935 : * NOTE: This function should move to cpl_conv.cpp.
936 : **********************************************************************/
937 : /* For now, assume that a 8000 chars buffer will be enough.
938 : */
939 : #define CPLSPrintf_BUF_SIZE 8000
940 : #define CPLSPrintf_BUF_Count 10
941 :
942 27925994 : const char *CPLSPrintf(const char *fmt, ...)
943 : {
944 : va_list args;
945 :
946 : /* -------------------------------------------------------------------- */
947 : /* Get the thread local buffer ring data. */
948 : /* -------------------------------------------------------------------- */
949 27925994 : char *pachBufRingInfo = (char *) CPLGetTLS( CTLS_CPLSPRINTF );
950 :
951 27925994 : if( pachBufRingInfo == NULL )
952 : {
953 : pachBufRingInfo = (char *)
954 395 : CPLCalloc(1,sizeof(int)+CPLSPrintf_BUF_Count*CPLSPrintf_BUF_SIZE);
955 395 : CPLSetTLS( CTLS_CPLSPRINTF, pachBufRingInfo, TRUE );
956 : }
957 :
958 : /* -------------------------------------------------------------------- */
959 : /* Work out which string in the "ring" we want to use this */
960 : /* time. */
961 : /* -------------------------------------------------------------------- */
962 27925994 : int *pnBufIndex = (int *) pachBufRingInfo;
963 27925994 : int nOffset = sizeof(int) + *pnBufIndex * CPLSPrintf_BUF_SIZE;
964 27925994 : char *pachBuffer = pachBufRingInfo + nOffset;
965 :
966 27925994 : *pnBufIndex = (*pnBufIndex + 1) % CPLSPrintf_BUF_Count;
967 :
968 : /* -------------------------------------------------------------------- */
969 : /* Format the result. */
970 : /* -------------------------------------------------------------------- */
971 :
972 27925994 : va_start(args, fmt);
973 : #if defined(HAVE_VSNPRINTF)
974 27925994 : vsnprintf(pachBuffer, CPLSPrintf_BUF_SIZE-1, fmt, args);
975 : #else
976 : vsprintf(pachBuffer, fmt, args);
977 : #endif
978 27925994 : va_end(args);
979 :
980 27925994 : return pachBuffer;
981 : }
982 :
983 : /**********************************************************************
984 : * CSLAppendPrintf()
985 : *
986 : * Use CPLSPrintf() to append a new line at the end of a StringList.
987 : *
988 : * Returns the modified StringList.
989 : **********************************************************************/
990 0 : char **CSLAppendPrintf(char **papszStrList, const char *fmt, ...)
991 : {
992 0 : CPLString osWork;
993 : va_list args;
994 :
995 0 : va_start( args, fmt );
996 0 : osWork.vPrintf( fmt, args );
997 0 : va_end( args );
998 :
999 0 : return CSLAddString(papszStrList, osWork);
1000 : }
1001 :
1002 : /************************************************************************/
1003 : /* CPLVASPrintf() */
1004 : /* */
1005 : /* This is intended to serve as an easy to use C callabable */
1006 : /* vasprintf() alternative. Used in the geojson library for */
1007 : /* instance. */
1008 : /************************************************************************/
1009 :
1010 2484 : int CPLVASPrintf( char **buf, const char *fmt, va_list ap )
1011 :
1012 : {
1013 2484 : CPLString osWork;
1014 :
1015 2484 : osWork.vPrintf( fmt, ap );
1016 :
1017 2484 : if( buf )
1018 2484 : *buf = CPLStrdup(osWork.c_str());
1019 :
1020 2484 : return strlen(osWork);
1021 : }
1022 :
1023 : /************************************************************************/
1024 : /* CSLTestBoolean() */
1025 : /************************************************************************/
1026 :
1027 : /**
1028 : * Test what boolean value contained in the string.
1029 : *
1030 : * If pszValue is "NO", "FALSE", "OFF" or "0" will be returned FALSE.
1031 : * Otherwise, TRUE will be returned.
1032 : *
1033 : * @param pszValue the string should be tested.
1034 : *
1035 : * @return TRUE or FALSE.
1036 : */
1037 :
1038 847148 : int CSLTestBoolean( const char *pszValue )
1039 : {
1040 847148 : if( EQUAL(pszValue,"NO")
1041 : || EQUAL(pszValue,"FALSE")
1042 : || EQUAL(pszValue,"OFF")
1043 : || EQUAL(pszValue,"0") )
1044 805526 : return FALSE;
1045 : else
1046 41622 : return TRUE;
1047 : }
1048 :
1049 : /**********************************************************************
1050 : * CSLFetchBoolean()
1051 : *
1052 : * Check for boolean key value.
1053 : *
1054 : * In a StringList of "Name=Value" pairs, look to see if there is a key
1055 : * with the given name, and if it can be interpreted as being TRUE. If
1056 : * the key appears without any "=Value" portion it will be considered true.
1057 : * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
1058 : * if the key appears in the list it will be considered TRUE. If the key
1059 : * doesn't appear at all, the indicated default value will be returned.
1060 : *
1061 : * @param papszStrList the string list to search.
1062 : * @param pszKey the key value to look for (case insensitive).
1063 : * @param bDefault the value to return if the key isn't found at all.
1064 : *
1065 : * @return TRUE or FALSE
1066 : **********************************************************************/
1067 :
1068 22163 : int CSLFetchBoolean( char **papszStrList, const char *pszKey, int bDefault )
1069 :
1070 : {
1071 : const char *pszValue;
1072 :
1073 22163 : if( CSLFindString( papszStrList, pszKey ) != -1 )
1074 0 : return TRUE;
1075 :
1076 22163 : pszValue = CSLFetchNameValue(papszStrList, pszKey );
1077 22163 : if( pszValue == NULL )
1078 20450 : return bDefault;
1079 : else
1080 1713 : return CSLTestBoolean( pszValue );
1081 : }
1082 :
1083 : /************************************************************************/
1084 : /* CSLFetchNameValueDefaulted() */
1085 : /************************************************************************/
1086 :
1087 1801 : const char *CSLFetchNameValueDef( char **papszStrList,
1088 : const char *pszName,
1089 : const char *pszDefault )
1090 :
1091 : {
1092 1801 : const char *pszResult = CSLFetchNameValue( papszStrList, pszName );
1093 1801 : if( pszResult )
1094 234 : return pszResult;
1095 : else
1096 1567 : return pszDefault;
1097 : }
1098 :
1099 : /**********************************************************************
1100 : * CSLFetchNameValue()
1101 : *
1102 : * In a StringList of "Name=Value" pairs, look for the
1103 : * first value associated with the specified name. The search is not
1104 : * case sensitive.
1105 : * ("Name:Value" pairs are also supported for backward compatibility
1106 : * with older stuff.)
1107 : *
1108 : * Returns a reference to the value in the StringList that the caller
1109 : * should not attempt to free.
1110 : *
1111 : * Returns NULL if the name is not found.
1112 : **********************************************************************/
1113 2163823 : const char *CSLFetchNameValue(char **papszStrList, const char *pszName)
1114 : {
1115 : size_t nLen;
1116 :
1117 2163823 : if (papszStrList == NULL || pszName == NULL)
1118 128813 : return NULL;
1119 :
1120 2035010 : nLen = strlen(pszName);
1121 16742814 : while(*papszStrList != NULL)
1122 : {
1123 14071724 : if (EQUALN(*papszStrList, pszName, nLen)
1124 698917 : && ( (*papszStrList)[nLen] == '=' ||
1125 1362 : (*papszStrList)[nLen] == ':' ) )
1126 : {
1127 698651 : return (*papszStrList)+nLen+1;
1128 : }
1129 12672794 : papszStrList++;
1130 : }
1131 1336359 : return NULL;
1132 : }
1133 :
1134 : /************************************************************************/
1135 : /* CSLFindName() */
1136 : /************************************************************************/
1137 :
1138 : /**
1139 : * Find StringList entry with given key name.
1140 : *
1141 : * @param papszStrList the string list to search.
1142 : * @param pszName the key value to look for (case insensitive).
1143 : *
1144 : * @return -1 on failure or the list index of the first occurance
1145 : * matching the given key.
1146 : */
1147 :
1148 133 : int CSLFindName(char **papszStrList, const char *pszName)
1149 : {
1150 : size_t nLen;
1151 133 : int iIndex = 0;
1152 :
1153 133 : if (papszStrList == NULL || pszName == NULL)
1154 48 : return -1;
1155 :
1156 85 : nLen = strlen(pszName);
1157 260 : while(*papszStrList != NULL)
1158 : {
1159 132 : if (EQUALN(*papszStrList, pszName, nLen)
1160 21 : && ( (*papszStrList)[nLen] == '=' ||
1161 0 : (*papszStrList)[nLen] == ':' ) )
1162 : {
1163 21 : return iIndex;
1164 : }
1165 90 : iIndex++;
1166 90 : papszStrList++;
1167 : }
1168 64 : return -1;
1169 : }
1170 :
1171 : /**********************************************************************
1172 : * CPLParseNameValue()
1173 : **********************************************************************/
1174 :
1175 : /**
1176 : * Parse NAME=VALUE string into name and value components.
1177 : *
1178 : * Note that if ppszKey is non-NULL, the key (or name) portion will be
1179 : * allocated using VSIMalloc(), and returned in that pointer. It is the
1180 : * applications responsibility to free this string, but the application should
1181 : * not modify or free the returned value portion.
1182 : *
1183 : * This function also support "NAME:VALUE" strings and will strip white
1184 : * space from around the delimeter when forming name and value strings.
1185 : *
1186 : * Eventually CSLFetchNameValue() and friends may be modified to use
1187 : * CPLParseNameValue().
1188 : *
1189 : * @param pszNameValue string in "NAME=VALUE" format.
1190 : * @param ppszKey optional pointer though which to return the name
1191 : * portion.
1192 : * @return the value portion (pointing into original string).
1193 : */
1194 :
1195 11077 : const char *CPLParseNameValue(const char *pszNameValue, char **ppszKey )
1196 :
1197 : {
1198 : int i;
1199 : const char *pszValue;
1200 :
1201 143512 : for( i = 0; pszNameValue[i] != '\0'; i++ )
1202 : {
1203 143168 : if( pszNameValue[i] == '=' || pszNameValue[i] == ':' )
1204 : {
1205 10733 : pszValue = pszNameValue + i + 1;
1206 23494 : while( *pszValue == ' ' || *pszValue == '\t' )
1207 2028 : pszValue++;
1208 :
1209 10733 : if( ppszKey != NULL )
1210 : {
1211 10718 : *ppszKey = (char *) CPLMalloc(i+1);
1212 10718 : strncpy( *ppszKey, pszNameValue, i );
1213 10718 : (*ppszKey)[i] = '\0';
1214 42872 : while( i > 0 &&
1215 21436 : ( (*ppszKey)[i] == ' ' || (*ppszKey)[i] == '\t') )
1216 : {
1217 0 : (*ppszKey)[i] = '\0';
1218 0 : i--;
1219 : }
1220 : }
1221 :
1222 10733 : return pszValue;
1223 : }
1224 : }
1225 :
1226 344 : return NULL;
1227 : }
1228 :
1229 : /**********************************************************************
1230 : * CSLFetchNameValueMultiple()
1231 : *
1232 : * In a StringList of "Name=Value" pairs, look for all the
1233 : * values with the specified name. The search is not case
1234 : * sensitive.
1235 : * ("Name:Value" pairs are also supported for backward compatibility
1236 : * with older stuff.)
1237 : *
1238 : * Returns stringlist with one entry for each occurence of the
1239 : * specified name. The stringlist should eventually be destroyed
1240 : * by calling CSLDestroy().
1241 : *
1242 : * Returns NULL if the name is not found.
1243 : **********************************************************************/
1244 456 : char **CSLFetchNameValueMultiple(char **papszStrList, const char *pszName)
1245 : {
1246 : size_t nLen;
1247 456 : char **papszValues = NULL;
1248 :
1249 456 : if (papszStrList == NULL || pszName == NULL)
1250 334 : return NULL;
1251 :
1252 122 : nLen = strlen(pszName);
1253 474 : while(*papszStrList != NULL)
1254 : {
1255 252 : if (EQUALN(*papszStrList, pszName, nLen)
1256 22 : && ( (*papszStrList)[nLen] == '=' ||
1257 0 : (*papszStrList)[nLen] == ':' ) )
1258 : {
1259 : papszValues = CSLAddString(papszValues,
1260 22 : (*papszStrList)+nLen+1);
1261 : }
1262 230 : papszStrList++;
1263 : }
1264 :
1265 122 : return papszValues;
1266 : }
1267 :
1268 :
1269 : /**********************************************************************
1270 : * CSLAddNameValue()
1271 : *
1272 : * Add a new entry to a StringList of "Name=Value" pairs,
1273 : * ("Name:Value" pairs are also supported for backward compatibility
1274 : * with older stuff.)
1275 : *
1276 : * This function does not check if a "Name=Value" pair already exists
1277 : * for that name and can generate multiple entryes for the same name.
1278 : * Use CSLSetNameValue() if you want each name to have only one value.
1279 : *
1280 : * Returns the modified stringlist.
1281 : **********************************************************************/
1282 173053 : char **CSLAddNameValue(char **papszStrList,
1283 : const char *pszName, const char *pszValue)
1284 : {
1285 : char *pszLine;
1286 :
1287 173053 : if (pszName == NULL || pszValue==NULL)
1288 0 : return papszStrList;
1289 :
1290 173053 : pszLine = (char *) CPLMalloc(strlen(pszName)+strlen(pszValue)+2);
1291 173053 : sprintf( pszLine, "%s=%s", pszName, pszValue );
1292 173053 : papszStrList = CSLAddString(papszStrList, pszLine);
1293 173053 : CPLFree( pszLine );
1294 :
1295 173053 : return papszStrList;
1296 : }
1297 :
1298 : /************************************************************************/
1299 : /* CSLSetNameValue() */
1300 : /************************************************************************/
1301 :
1302 : /**
1303 : * Assign value to name in StringList.
1304 : *
1305 : * Set the value for a given name in a StringList of "Name=Value" pairs
1306 : * ("Name:Value" pairs are also supported for backward compatibility
1307 : * with older stuff.)
1308 : *
1309 : * If there is already a value for that name in the list then the value
1310 : * is changed, otherwise a new "Name=Value" pair is added.
1311 : *
1312 : * @param papszList the original list, the modified version is returned.
1313 : * @param pszName the name to be assigned a value. This should be a well
1314 : * formed token (no spaces or very special characters).
1315 : * @param pszValue the value to assign to the name. This should not contain
1316 : * any newlines (CR or LF) but is otherwise pretty much unconstrained. If
1317 : * NULL any corresponding value will be removed.
1318 : *
1319 : * @return modified stringlist.
1320 : */
1321 :
1322 166905 : char **CSLSetNameValue(char **papszList,
1323 : const char *pszName, const char *pszValue)
1324 : {
1325 : char **papszPtr;
1326 : size_t nLen;
1327 :
1328 166905 : if (pszName == NULL )
1329 328 : return papszList;
1330 :
1331 166577 : nLen = strlen(pszName);
1332 166577 : papszPtr = papszList;
1333 6628893 : while(papszPtr && *papszPtr != NULL)
1334 : {
1335 6300717 : if (EQUALN(*papszPtr, pszName, nLen)
1336 2406 : && ( (*papszPtr)[nLen] == '=' ||
1337 1485 : (*papszPtr)[nLen] == ':' ) )
1338 : {
1339 : /* Found it!
1340 : * Change the value... make sure to keep the ':' or '='
1341 : */
1342 : char cSep;
1343 1087 : cSep = (*papszPtr)[nLen];
1344 :
1345 1087 : CPLFree(*papszPtr);
1346 :
1347 : /*
1348 : * If the value is NULL, remove this entry completely/
1349 : */
1350 1087 : if( pszValue == NULL )
1351 : {
1352 384 : while( papszPtr[1] != NULL )
1353 : {
1354 40 : *papszPtr = papszPtr[1];
1355 40 : papszPtr++;
1356 : }
1357 172 : *papszPtr = NULL;
1358 : }
1359 :
1360 : /*
1361 : * Otherwise replace with new value.
1362 : */
1363 : else
1364 : {
1365 915 : *papszPtr = (char *) CPLMalloc(strlen(pszName)+strlen(pszValue)+2);
1366 915 : sprintf( *papszPtr, "%s%c%s", pszName, cSep, pszValue );
1367 : }
1368 1087 : return papszList;
1369 : }
1370 6295739 : papszPtr++;
1371 : }
1372 :
1373 165490 : if( pszValue == NULL )
1374 18 : return papszList;
1375 :
1376 : /* The name does not exist yet... create a new entry
1377 : */
1378 165472 : return CSLAddNameValue(papszList, pszName, pszValue);
1379 : }
1380 :
1381 : /************************************************************************/
1382 : /* CSLSetNameValueSeparator() */
1383 : /************************************************************************/
1384 :
1385 : /**
1386 : * Replace the default separator (":" or "=") with the passed separator
1387 : * in the given name/value list.
1388 : *
1389 : * Note that if a separator other than ":" or "=" is used, the resulting
1390 : * list will not be manipulatable by the CSL name/value functions any more.
1391 : *
1392 : * The CPLParseNameValue() function is used to break the existing lines,
1393 : * and it also strips white space from around the existing delimiter, thus
1394 : * the old separator, and any white space will be replaced by the new
1395 : * separator. For formatting purposes it may be desireable to include some
1396 : * white space in the new separator. eg. ": " or " = ".
1397 : *
1398 : * @param papszList the list to update. Component strings may be freed
1399 : * but the list array will remain at the same location.
1400 : *
1401 : * @param pszSeparator the new separator string to insert.
1402 : *
1403 : */
1404 :
1405 67 : void CSLSetNameValueSeparator( char ** papszList, const char *pszSeparator )
1406 :
1407 : {
1408 67 : int nLines = CSLCount(papszList), iLine;
1409 :
1410 1410 : for( iLine = 0; iLine < nLines; iLine++ )
1411 : {
1412 1343 : char *pszKey = NULL;
1413 : const char *pszValue;
1414 : char *pszNewLine;
1415 :
1416 1343 : pszValue = CPLParseNameValue( papszList[iLine], &pszKey );
1417 1343 : if( pszValue == NULL || pszKey == NULL )
1418 0 : continue;
1419 :
1420 : pszNewLine = (char *) CPLMalloc( strlen(pszValue) + strlen(pszKey)
1421 1343 : + strlen(pszSeparator) + 1 );
1422 1343 : strcpy( pszNewLine, pszKey );
1423 1343 : strcat( pszNewLine, pszSeparator );
1424 1343 : strcat( pszNewLine, pszValue );
1425 1343 : CPLFree( papszList[iLine] );
1426 1343 : papszList[iLine] = pszNewLine;
1427 1343 : CPLFree( pszKey );
1428 : }
1429 67 : }
1430 :
1431 : /************************************************************************/
1432 : /* CPLEscapeString() */
1433 : /************************************************************************/
1434 :
1435 : /**
1436 : * Apply escaping to string to preserve special characters.
1437 : *
1438 : * This function will "escape" a variety of special characters
1439 : * to make the string suitable to embed within a string constant
1440 : * or to write within a text stream but in a form that can be
1441 : * reconstitued to it's original form. The escaping will even preserve
1442 : * zero bytes allowing preservation of raw binary data.
1443 : *
1444 : * CPLES_BackslashQuotable(0): This scheme turns a binary string into
1445 : * a form suitable to be placed within double quotes as a string constant.
1446 : * The backslash, quote, '\\0' and newline characters are all escaped in
1447 : * the usual C style.
1448 : *
1449 : * CPLES_XML(1): This scheme converts the '<', '>', '"' and '&' characters into
1450 : * their XML/HTML equivelent (<, >, " and &) making a string safe
1451 : * to embed as CDATA within an XML element. The '\\0' is not escaped and
1452 : * should not be included in the input.
1453 : *
1454 : * CPLES_URL(2): Everything except alphanumerics and the underscore are
1455 : * converted to a percent followed by a two digit hex encoding of the character
1456 : * (leading zero supplied if needed). This is the mechanism used for encoding
1457 : * values to be passed in URLs.
1458 : *
1459 : * CPLES_SQL(3): All single quotes are replaced with two single quotes.
1460 : * Suitable for use when constructing literal values for SQL commands where
1461 : * the literal will be enclosed in single quotes.
1462 : *
1463 : * CPLES_CSV(4): If the values contains commas, semicolons, tabs, double quotes, or newlines it
1464 : * placed in double quotes, and double quotes in the value are doubled.
1465 : * Suitable for use when constructing field values for .csv files. Note that
1466 : * CPLUnescapeString() currently does not support this format, only
1467 : * CPLEscapeString(). See cpl_csv.cpp for csv parsing support.
1468 : *
1469 : * @param pszInput the string to escape.
1470 : * @param nLength The number of bytes of data to preserve. If this is -1
1471 : * the strlen(pszString) function will be used to compute the length.
1472 : * @param nScheme the encoding scheme to use.
1473 : *
1474 : * @return an escaped, zero terminated string that should be freed with
1475 : * CPLFree() when no longer needed.
1476 : */
1477 :
1478 225811 : char *CPLEscapeString( const char *pszInput, int nLength,
1479 : int nScheme )
1480 :
1481 : {
1482 : char *pszOutput;
1483 : char *pszShortOutput;
1484 :
1485 225811 : if( nLength == -1 )
1486 225762 : nLength = strlen(pszInput);
1487 :
1488 225811 : pszOutput = (char *) CPLMalloc( nLength * 6 + 1 );
1489 :
1490 225811 : if( nScheme == CPLES_BackslashQuotable )
1491 : {
1492 33 : int iOut = 0, iIn;
1493 :
1494 1229666 : for( iIn = 0; iIn < nLength; iIn++ )
1495 : {
1496 1229633 : if( pszInput[iIn] == '\0' )
1497 : {
1498 351418 : pszOutput[iOut++] = '\\';
1499 351418 : pszOutput[iOut++] = '0';
1500 : }
1501 878215 : else if( pszInput[iIn] == '\n' )
1502 : {
1503 3787 : pszOutput[iOut++] = '\\';
1504 3787 : pszOutput[iOut++] = 'n';
1505 : }
1506 874428 : else if( pszInput[iIn] == '"' )
1507 : {
1508 2469 : pszOutput[iOut++] = '\\';
1509 2469 : pszOutput[iOut++] = '\"';
1510 : }
1511 871959 : else if( pszInput[iIn] == '\\' )
1512 : {
1513 2515 : pszOutput[iOut++] = '\\';
1514 2515 : pszOutput[iOut++] = '\\';
1515 : }
1516 : else
1517 869444 : pszOutput[iOut++] = pszInput[iIn];
1518 : }
1519 33 : pszOutput[iOut] = '\0';
1520 : }
1521 225778 : else if( nScheme == CPLES_URL ) /* Untested at implementation */
1522 : {
1523 79 : int iOut = 0, iIn;
1524 :
1525 1477 : for( iIn = 0; iIn < nLength; iIn++ )
1526 : {
1527 3511 : if( (pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z')
1528 330 : || (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z')
1529 161 : || (pszInput[iIn] >= '0' && pszInput[iIn] <= '9')
1530 257 : || pszInput[iIn] == '_' || pszInput[iIn] == '.' )
1531 : {
1532 1365 : pszOutput[iOut++] = pszInput[iIn];
1533 : }
1534 : else
1535 : {
1536 33 : sprintf( pszOutput+iOut, "%%%02X", ((unsigned char*)pszInput)[iIn] );
1537 33 : iOut += 3;
1538 : }
1539 : }
1540 79 : pszOutput[iOut] = '\0';
1541 : }
1542 450090 : else if( nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES )
1543 : {
1544 224391 : int iOut = 0, iIn;
1545 :
1546 9023095 : for( iIn = 0; iIn < nLength; iIn++ )
1547 : {
1548 8798704 : if( pszInput[iIn] == '<' )
1549 : {
1550 12 : pszOutput[iOut++] = '&';
1551 12 : pszOutput[iOut++] = 'l';
1552 12 : pszOutput[iOut++] = 't';
1553 12 : pszOutput[iOut++] = ';';
1554 : }
1555 8798692 : else if( pszInput[iIn] == '>' )
1556 : {
1557 29 : pszOutput[iOut++] = '&';
1558 29 : pszOutput[iOut++] = 'g';
1559 29 : pszOutput[iOut++] = 't';
1560 29 : pszOutput[iOut++] = ';';
1561 : }
1562 8798663 : else if( pszInput[iIn] == '&' )
1563 : {
1564 252 : pszOutput[iOut++] = '&';
1565 252 : pszOutput[iOut++] = 'a';
1566 252 : pszOutput[iOut++] = 'm';
1567 252 : pszOutput[iOut++] = 'p';
1568 252 : pszOutput[iOut++] = ';';
1569 : }
1570 8798501 : else if( pszInput[iIn] == '"' && nScheme != CPLES_XML_BUT_QUOTES )
1571 : {
1572 90 : pszOutput[iOut++] = '&';
1573 90 : pszOutput[iOut++] = 'q';
1574 90 : pszOutput[iOut++] = 'u';
1575 90 : pszOutput[iOut++] = 'o';
1576 90 : pszOutput[iOut++] = 't';
1577 90 : pszOutput[iOut++] = ';';
1578 : }
1579 8861996 : else if( ((GByte*)pszInput)[iIn] < 0x20
1580 40961 : && pszInput[iIn] != 0x9
1581 22706 : && pszInput[iIn] != 0xA
1582 8 : && pszInput[iIn] != 0xD )
1583 : {
1584 : // These control characters are unrepresentable in XML format,
1585 : // so we just drop them. #4117
1586 : }
1587 : else
1588 8798321 : pszOutput[iOut++] = pszInput[iIn];
1589 : }
1590 224391 : pszOutput[iOut] = '\0';
1591 : }
1592 1308 : else if( nScheme == CPLES_SQL )
1593 : {
1594 16 : int iOut = 0, iIn;
1595 :
1596 78 : for( iIn = 0; iIn < nLength; iIn++ )
1597 : {
1598 62 : if( pszInput[iIn] == '\'' )
1599 : {
1600 0 : pszOutput[iOut++] = '\'';
1601 0 : pszOutput[iOut++] = '\'';
1602 : }
1603 : else
1604 62 : pszOutput[iOut++] = pszInput[iIn];
1605 : }
1606 16 : pszOutput[iOut] = '\0';
1607 : }
1608 1292 : else if( nScheme == CPLES_CSV )
1609 : {
1610 2542 : if( strchr( pszInput, '\"' ) == NULL
1611 : && strchr( pszInput, ',') == NULL
1612 : && strchr( pszInput, ';') == NULL
1613 : && strchr( pszInput, '\t') == NULL
1614 : && strchr( pszInput, 10) == NULL
1615 : && strchr( pszInput, 13) == NULL )
1616 : {
1617 1250 : strcpy( pszOutput, pszInput );
1618 : }
1619 : else
1620 : {
1621 42 : int iOut = 1, iIn;
1622 :
1623 42 : pszOutput[0] = '\"';
1624 :
1625 3514 : for( iIn = 0; iIn < nLength; iIn++ )
1626 : {
1627 3472 : if( pszInput[iIn] == '\"' )
1628 : {
1629 6 : pszOutput[iOut++] = '\"';
1630 6 : pszOutput[iOut++] = '\"';
1631 : }
1632 : else
1633 3466 : pszOutput[iOut++] = pszInput[iIn];
1634 : }
1635 42 : pszOutput[iOut++] = '\"';
1636 42 : pszOutput[iOut++] = '\0';
1637 : }
1638 : }
1639 : else
1640 : {
1641 0 : pszOutput[0] = '\0';
1642 : CPLError( CE_Failure, CPLE_AppDefined,
1643 : "Undefined escaping scheme (%d) in CPLEscapeString()",
1644 0 : nScheme );
1645 : }
1646 :
1647 225811 : pszShortOutput = CPLStrdup( pszOutput );
1648 225811 : CPLFree( pszOutput );
1649 :
1650 225811 : return pszShortOutput;
1651 : }
1652 :
1653 : /************************************************************************/
1654 : /* CPLUnescapeString() */
1655 : /************************************************************************/
1656 :
1657 : /**
1658 : * Unescape a string.
1659 : *
1660 : * This function does the opposite of CPLEscapeString(). Given a string
1661 : * with special values escaped according to some scheme, it will return a
1662 : * new copy of the string returned to it's original form.
1663 : *
1664 : * @param pszInput the input string. This is a zero terminated string.
1665 : * @param pnLength location to return the length of the unescaped string,
1666 : * which may in some cases include embedded '\\0' characters.
1667 : * @param nScheme the escaped scheme to undo (see CPLEscapeString() for a
1668 : * list).
1669 : *
1670 : * @return a copy of the unescaped string that should be freed by the
1671 : * application using CPLFree() when no longer needed.
1672 : */
1673 :
1674 4442 : char *CPLUnescapeString( const char *pszInput, int *pnLength, int nScheme )
1675 :
1676 : {
1677 : char *pszOutput;
1678 4442 : int iOut=0, iIn;
1679 :
1680 4442 : pszOutput = (char *) CPLMalloc(4 * strlen(pszInput)+1);
1681 4442 : pszOutput[0] = '\0';
1682 :
1683 8637 : if( nScheme == CPLES_XML || nScheme == CPLES_XML_BUT_QUOTES )
1684 : {
1685 : char ch;
1686 174838 : for( iIn = 0; (ch = pszInput[iIn]) != '\0'; iIn++ )
1687 : {
1688 170643 : if( ch != '&' )
1689 : {
1690 163864 : pszOutput[iOut++] = ch;
1691 : }
1692 6779 : else if( EQUALN(pszInput+iIn,"<",4) )
1693 : {
1694 11 : pszOutput[iOut++] = '<';
1695 11 : iIn += 3;
1696 : }
1697 6768 : else if( EQUALN(pszInput+iIn,">",4) )
1698 : {
1699 11 : pszOutput[iOut++] = '>';
1700 11 : iIn += 3;
1701 : }
1702 6757 : else if( EQUALN(pszInput+iIn,"&",5) )
1703 : {
1704 799 : pszOutput[iOut++] = '&';
1705 799 : iIn += 4;
1706 : }
1707 5958 : else if( EQUALN(pszInput+iIn,"'",6) )
1708 : {
1709 0 : pszOutput[iOut++] = '\'';
1710 0 : iIn += 5;
1711 : }
1712 5958 : else if( EQUALN(pszInput+iIn,""",6) )
1713 : {
1714 5904 : pszOutput[iOut++] = '"';
1715 5904 : iIn += 5;
1716 : }
1717 54 : else if( EQUALN(pszInput+iIn,"&#x",3) )
1718 : {
1719 38 : wchar_t anVal[2] = {0 , 0};
1720 38 : iIn += 3;
1721 :
1722 76 : while(TRUE)
1723 : {
1724 114 : ch = pszInput[iIn ++];
1725 114 : if (ch >= 'a' && ch <= 'f')
1726 0 : anVal[0] = anVal[0] * 16 + ch - 'a' + 10;
1727 114 : else if (ch >= 'A' && ch <= 'A')
1728 0 : anVal[0] = anVal[0] * 16 + ch - 'A' + 10;
1729 190 : else if (ch >= '0' && ch <= '9')
1730 76 : anVal[0] = anVal[0] * 16 + ch - '0';
1731 : else
1732 : break;
1733 : }
1734 38 : if (ch != ';')
1735 0 : break;
1736 38 : iIn --;
1737 :
1738 38 : char * pszUTF8 = CPLRecodeFromWChar( anVal, "WCHAR_T", CPL_ENC_UTF8);
1739 38 : int nLen = strlen(pszUTF8);
1740 38 : memcpy(pszOutput + iOut, pszUTF8, nLen);
1741 38 : CPLFree(pszUTF8);
1742 38 : iOut += nLen;
1743 : }
1744 16 : else if( EQUALN(pszInput+iIn,"&#",2) )
1745 : {
1746 : char ch;
1747 16 : wchar_t anVal[2] = {0 , 0};
1748 16 : iIn += 2;
1749 :
1750 32 : while(TRUE)
1751 : {
1752 48 : ch = pszInput[iIn ++];
1753 48 : if (ch >= '0' && ch <= '9')
1754 32 : anVal[0] = anVal[0] * 10 + ch - '0';
1755 : else
1756 : break;
1757 : }
1758 16 : if (ch != ';')
1759 0 : break;
1760 16 : iIn --;
1761 :
1762 16 : char * pszUTF8 = CPLRecodeFromWChar( anVal, "WCHAR_T", CPL_ENC_UTF8);
1763 16 : int nLen = strlen(pszUTF8);
1764 16 : memcpy(pszOutput + iOut, pszUTF8, nLen);
1765 16 : CPLFree(pszUTF8);
1766 16 : iOut += nLen;
1767 : }
1768 : else
1769 : {
1770 : /* illegal escape sequence */
1771 : CPLDebug( "CPL",
1772 0 : "Error unescaping CPLES_XML text, '&' character followed by unhandled escape sequence." );
1773 0 : break;
1774 : }
1775 : }
1776 : }
1777 247 : else if( nScheme == CPLES_URL )
1778 : {
1779 9395 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1780 : {
1781 9434 : if( pszInput[iIn] == '%'
1782 48 : && pszInput[iIn+1] != '\0'
1783 48 : && pszInput[iIn+2] != '\0' )
1784 : {
1785 48 : int nHexChar = 0;
1786 :
1787 48 : if( pszInput[iIn+1] >= 'A' && pszInput[iIn+1] <= 'F' )
1788 0 : nHexChar += 16 * (pszInput[iIn+1] - 'A' + 10);
1789 48 : else if( pszInput[iIn+1] >= 'a' && pszInput[iIn+1] <= 'f' )
1790 0 : nHexChar += 16 * (pszInput[iIn+1] - 'a' + 10);
1791 96 : else if( pszInput[iIn+1] >= '0' && pszInput[iIn+1] <= '9' )
1792 48 : nHexChar += 16 * (pszInput[iIn+1] - '0');
1793 : else
1794 : CPLDebug( "CPL",
1795 : "Error unescaping CPLES_URL text, percent not "
1796 0 : "followed by two hex digits." );
1797 :
1798 94 : if( pszInput[iIn+2] >= 'A' && pszInput[iIn+2] <= 'F' )
1799 46 : nHexChar += pszInput[iIn+2] - 'A' + 10;
1800 2 : else if( pszInput[iIn+2] >= 'a' && pszInput[iIn+2] <= 'f' )
1801 0 : nHexChar += pszInput[iIn+2] - 'a' + 10;
1802 4 : else if( pszInput[iIn+2] >= '0' && pszInput[iIn+2] <= '9' )
1803 2 : nHexChar += pszInput[iIn+2] - '0';
1804 : else
1805 : CPLDebug( "CPL",
1806 : "Error unescaping CPLES_URL text, percent not "
1807 0 : "followed by two hex digits." );
1808 :
1809 48 : pszOutput[iOut++] = (char) nHexChar;
1810 48 : iIn += 2;
1811 : }
1812 9242 : else if( pszInput[iIn] == '+' )
1813 : {
1814 5 : pszOutput[iOut++] = ' ';
1815 : }
1816 : else
1817 : {
1818 9237 : pszOutput[iOut++] = pszInput[iIn];
1819 : }
1820 : }
1821 : }
1822 142 : else if( nScheme == CPLES_SQL )
1823 : {
1824 0 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1825 : {
1826 0 : if( pszInput[iIn] == '\'' && pszInput[iIn+1] == '\'' )
1827 : {
1828 0 : iIn++;
1829 0 : pszOutput[iOut++] = pszInput[iIn];
1830 : }
1831 : else
1832 : {
1833 0 : pszOutput[iOut++] = pszInput[iIn];
1834 : }
1835 : }
1836 : }
1837 : else /* if( nScheme == CPLES_BackslashQuoteable ) */
1838 : {
1839 205225 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1840 : {
1841 205083 : if( pszInput[iIn] == '\\' )
1842 : {
1843 31 : iIn++;
1844 31 : if( pszInput[iIn] == 'n' )
1845 0 : pszOutput[iOut++] = '\n';
1846 31 : else if( pszInput[iIn] == '0' )
1847 1 : pszOutput[iOut++] = '\0';
1848 : else
1849 30 : pszOutput[iOut++] = pszInput[iIn];
1850 : }
1851 : else
1852 : {
1853 205052 : pszOutput[iOut++] = pszInput[iIn];
1854 : }
1855 : }
1856 : }
1857 :
1858 4442 : pszOutput[iOut] = '\0';
1859 :
1860 4442 : if( pnLength != NULL )
1861 484 : *pnLength = iOut;
1862 :
1863 4442 : return pszOutput;
1864 : }
1865 :
1866 : /************************************************************************/
1867 : /* CPLBinaryToHex() */
1868 : /************************************************************************/
1869 :
1870 : /**
1871 : * Binary to hexadecimal translation.
1872 : *
1873 : * @param nBytes number of bytes of binary data in pabyData.
1874 : * @param pabyData array of data bytes to translate.
1875 : *
1876 : * @return hexadecimal translation, zero terminated. Free with CPLFree().
1877 : */
1878 :
1879 507 : char *CPLBinaryToHex( int nBytes, const GByte *pabyData )
1880 :
1881 : {
1882 507 : char *pszHex = (char *) CPLMalloc(nBytes * 2 + 1 );
1883 : int i;
1884 : static const char achHex[] = "0123456789ABCDEF";
1885 :
1886 507 : pszHex[nBytes*2] = '\0';
1887 :
1888 57763 : for( i = 0; i < nBytes; i++ )
1889 : {
1890 57256 : int nLow = pabyData[i] & 0x0f;
1891 57256 : int nHigh = (pabyData[i] & 0xf0) >> 4;
1892 :
1893 57256 : pszHex[i*2] = achHex[nHigh];
1894 57256 : pszHex[i*2+1] = achHex[nLow];
1895 : }
1896 :
1897 507 : return pszHex;
1898 : }
1899 :
1900 :
1901 : /************************************************************************/
1902 : /* CPLHexToBinary() */
1903 : /************************************************************************/
1904 :
1905 : /**
1906 : * Hexadecimal to binary translation
1907 : *
1908 : * @param pszHex the input hex encoded string.
1909 : * @param pnBytes the returned count of decoded bytes placed here.
1910 : *
1911 : * @return returns binary buffer of data - free with CPLFree().
1912 : */
1913 :
1914 344 : GByte *CPLHexToBinary( const char *pszHex, int *pnBytes )
1915 :
1916 : {
1917 344 : int iSrc = 0, iDst = 0;
1918 344 : size_t nHexLen = strlen(pszHex);
1919 :
1920 : GByte *pabyWKB;
1921 :
1922 344 : pabyWKB = (GByte *) CPLMalloc(nHexLen / 2 + 2);
1923 :
1924 141107 : while( pszHex[iSrc] != '\0' )
1925 : {
1926 271382 : if( pszHex[iSrc] >= '0' && pszHex[iSrc] <= '9' )
1927 130963 : pabyWKB[iDst] = pszHex[iSrc] - '0';
1928 18912 : else if( pszHex[iSrc] >= 'A' && pszHex[iSrc] <= 'F' )
1929 9456 : pabyWKB[iDst] = pszHex[iSrc] - 'A' + 10;
1930 0 : else if( pszHex[iSrc] >= 'a' && pszHex[iSrc] <= 'f' )
1931 0 : pabyWKB[iDst] = pszHex[iSrc] - 'a' + 10;
1932 : else
1933 0 : break;
1934 :
1935 140419 : pabyWKB[iDst] *= 16;
1936 :
1937 140419 : iSrc++;
1938 :
1939 260943 : if( pszHex[iSrc] >= '0' && pszHex[iSrc] <= '9' )
1940 120524 : pabyWKB[iDst] += pszHex[iSrc] - '0';
1941 39790 : else if( pszHex[iSrc] >= 'A' && pszHex[iSrc] <= 'F' )
1942 19895 : pabyWKB[iDst] += pszHex[iSrc] - 'A' + 10;
1943 0 : else if( pszHex[iSrc] >= 'a' && pszHex[iSrc] <= 'f' )
1944 0 : pabyWKB[iDst] += pszHex[iSrc] - 'a' + 10;
1945 : else
1946 0 : break;
1947 :
1948 140419 : iSrc++;
1949 140419 : iDst++;
1950 : }
1951 :
1952 344 : pabyWKB[iDst] = 0;
1953 344 : *pnBytes = iDst;
1954 :
1955 344 : return pabyWKB;
1956 : }
1957 :
1958 :
1959 :
1960 : /************************************************************************/
1961 : /* CPLGetValueType() */
1962 : /************************************************************************/
1963 :
1964 : /**
1965 : * Detect the type of the value contained in a string, whether it is
1966 : * a real, an integer or a string
1967 : * Leading and trailing spaces are skipped in the analysis.
1968 : *
1969 : * Note: in the context of this function, integer must be understood in a
1970 : * broad sense. It does not mean that the value can fit into a 32 bit integer
1971 : * for example. It might be larger.
1972 : *
1973 : * @param pszValue the string to analyze
1974 : *
1975 : * @return returns the type of the value contained in the string.
1976 : */
1977 :
1978 4287 : CPLValueType CPLGetValueType(const char* pszValue)
1979 : {
1980 : /*
1981 : doubles : "+25.e+3", "-25.e-3", "25.e3", "25e3", " 25e3 "
1982 : not doubles: "25e 3", "25e.3", "-2-5e3", "2-5e3", "25.25.3", "-3d"
1983 : */
1984 :
1985 4287 : int bFoundDot = FALSE;
1986 4287 : int bFoundExponent = FALSE;
1987 4287 : int bIsLastCharExponent = FALSE;
1988 4287 : int bIsReal = FALSE;
1989 :
1990 4287 : if (pszValue == NULL)
1991 0 : return CPL_VALUE_STRING;
1992 :
1993 : /* Skip leading spaces */
1994 8574 : while( isspace( (unsigned char)*pszValue ) )
1995 0 : pszValue ++;
1996 :
1997 4287 : if (*pszValue == '\0')
1998 96 : return CPL_VALUE_STRING;
1999 :
2000 : /* Skip leading + or - */
2001 4191 : if (*pszValue == '+' || *pszValue == '-')
2002 29 : pszValue ++;
2003 :
2004 17008 : for(; *pszValue != '\0'; pszValue++ )
2005 : {
2006 14531 : if( isdigit( *pszValue))
2007 : {
2008 11887 : bIsLastCharExponent = FALSE;
2009 : /* do nothing */
2010 : }
2011 2644 : else if ( isspace ((unsigned char)*pszValue) )
2012 : {
2013 6 : const char* pszTmp = pszValue;
2014 18 : while( isspace( (unsigned char)*pszTmp ) )
2015 6 : pszTmp ++;
2016 6 : if (*pszTmp == 0)
2017 0 : break;
2018 : else
2019 6 : return CPL_VALUE_STRING;
2020 : }
2021 2638 : else if ( *pszValue == '-' || *pszValue == '+' )
2022 : {
2023 7 : if (bIsLastCharExponent)
2024 : {
2025 : /* do nothing */
2026 : }
2027 : else
2028 7 : return CPL_VALUE_STRING;
2029 0 : bIsLastCharExponent = FALSE;
2030 : }
2031 2631 : else if ( *pszValue == '.')
2032 : {
2033 930 : bIsReal = TRUE;
2034 930 : if (!bFoundDot && bIsLastCharExponent == FALSE)
2035 930 : bFoundDot = TRUE;
2036 : else
2037 0 : return CPL_VALUE_STRING;
2038 930 : bIsLastCharExponent = FALSE;
2039 : }
2040 1701 : else if (*pszValue == 'D' || *pszValue == 'd'
2041 : || *pszValue == 'E' || *pszValue == 'e' )
2042 : {
2043 74 : if (!(pszValue[1] == '+' || pszValue[1] == '-' ||
2044 37 : isdigit(pszValue[1])))
2045 37 : return CPL_VALUE_STRING;
2046 :
2047 0 : bIsReal = TRUE;
2048 0 : if (!bFoundExponent)
2049 0 : bFoundExponent = TRUE;
2050 : else
2051 0 : return CPL_VALUE_STRING;
2052 0 : bIsLastCharExponent = TRUE;
2053 : }
2054 : else
2055 : {
2056 1664 : return CPL_VALUE_STRING;
2057 : }
2058 : }
2059 :
2060 2477 : return (bIsReal) ? CPL_VALUE_REAL : CPL_VALUE_INTEGER;
2061 : }
2062 :
2063 : /************************************************************************/
2064 : /* CPLStrlcpy() */
2065 : /************************************************************************/
2066 :
2067 : /**
2068 : * Copy source string to a destination buffer.
2069 : *
2070 : * This function ensures that the destination buffer is always NUL terminated
2071 : * (provided that its length is at least 1).
2072 : *
2073 : * This function is designed to be a safer, more consistent, and less error
2074 : * prone replacement for strncpy. Its contract is identical to libbsd's strlcpy.
2075 : *
2076 : * Truncation can be detected by testing if the return value of CPLStrlcpy
2077 : * is greater or equal to nDestSize.
2078 :
2079 : \verbatim
2080 : char szDest[5];
2081 : if (CPLStrlcpy(szDest, "abcde", sizeof(szDest)) >= sizeof(szDest))
2082 : fprintf(stderr, "truncation occured !\n");
2083 : \endverbatim
2084 :
2085 : * @param pszDest destination buffer
2086 : * @param pszSrc source string. Must be NUL terminated
2087 : * @param nDestSize size of destination buffer (including space for the NUL terminator character)
2088 : *
2089 : * @return the length of the source string (=strlen(pszSrc))
2090 : *
2091 : * @since GDAL 1.7.0
2092 : */
2093 730951 : size_t CPLStrlcpy(char* pszDest, const char* pszSrc, size_t nDestSize)
2094 : {
2095 730951 : char* pszDestIter = pszDest;
2096 730951 : const char* pszSrcIter = pszSrc;
2097 :
2098 730951 : if (nDestSize == 0)
2099 0 : return strlen(pszSrc);
2100 :
2101 730951 : nDestSize --;
2102 6346603 : while(nDestSize != 0 && *pszSrcIter != '\0')
2103 : {
2104 4884701 : *pszDestIter = *pszSrcIter;
2105 4884701 : pszDestIter ++;
2106 4884701 : pszSrcIter ++;
2107 4884701 : nDestSize --;
2108 : }
2109 730951 : *pszDestIter = '\0';
2110 730951 : return pszSrcIter - pszSrc + strlen(pszSrcIter);
2111 : }
2112 :
2113 : /************************************************************************/
2114 : /* CPLStrlcat() */
2115 : /************************************************************************/
2116 :
2117 : /**
2118 : * Appends a source string to a destination buffer.
2119 : *
2120 : * This function ensures that the destination buffer is always NUL terminated
2121 : * (provided that its length is at least 1 and that there is at least one byte
2122 : * free in pszDest, that is to say strlen(pszDest_before) < nDestSize)
2123 : *
2124 : * This function is designed to be a safer, more consistent, and less error
2125 : * prone replacement for strncat. Its contract is identical to libbsd's strlcat.
2126 : *
2127 : * Truncation can be detected by testing if the return value of CPLStrlcat
2128 : * is greater or equal to nDestSize.
2129 :
2130 : \verbatim
2131 : char szDest[5];
2132 : CPLStrlcpy(szDest, "ab", sizeof(szDest));
2133 : if (CPLStrlcat(szDest, "cde", sizeof(szDest)) >= sizeof(szDest))
2134 : fprintf(stderr, "truncation occured !\n");
2135 : \endverbatim
2136 :
2137 : * @param pszDest destination buffer. Must be NUL terminated before running CPLStrlcat
2138 : * @param pszSrc source string. Must be NUL terminated
2139 : * @param nDestSize size of destination buffer (including space for the NUL terminator character)
2140 : *
2141 : * @return the thoretical length of the destination string after concatenation
2142 : * (=strlen(pszDest_before) + strlen(pszSrc)).
2143 : * If strlen(pszDest_before) >= nDestSize, then it returns nDestSize + strlen(pszSrc)
2144 : *
2145 : * @since GDAL 1.7.0
2146 : */
2147 210047 : size_t CPLStrlcat(char* pszDest, const char* pszSrc, size_t nDestSize)
2148 : {
2149 210047 : char* pszDestIter = pszDest;
2150 :
2151 5374679 : while(nDestSize != 0 && *pszDestIter != '\0')
2152 : {
2153 4954585 : pszDestIter ++;
2154 4954585 : nDestSize --;
2155 : }
2156 :
2157 210047 : return pszDestIter - pszDest + CPLStrlcpy(pszDestIter, pszSrc, nDestSize);
2158 : }
2159 :
2160 : /************************************************************************/
2161 : /* CPLStrnlen() */
2162 : /************************************************************************/
2163 :
2164 : /**
2165 : * Returns the length of a NUL terminated string by reading at most
2166 : * the specified number of bytes.
2167 : *
2168 : * The CPLStrnlen() function returns MIN(strlen(pszStr), nMaxLen).
2169 : * Only the first nMaxLen bytes of the string will be read. Usefull to
2170 : * test if a string contains at least nMaxLen characters without reading
2171 : * the full string up to the NUL terminating character.
2172 : *
2173 : * @param pszStr a NUL terminated string
2174 : * @param nMaxLen maximum number of bytes to read in pszStr
2175 : *
2176 : * @return strlen(pszStr) if the length is lesser than nMaxLen, otherwise
2177 : * nMaxLen if the NUL character has not been found in the first nMaxLen bytes.
2178 : *
2179 : * @since GDAL 1.7.0
2180 : */
2181 :
2182 2701 : size_t CPLStrnlen (const char *pszStr, size_t nMaxLen)
2183 : {
2184 2701 : size_t nLen = 0;
2185 41154 : while(nLen < nMaxLen && *pszStr != '\0')
2186 : {
2187 35752 : nLen ++;
2188 35752 : pszStr ++;
2189 : }
2190 2701 : return nLen;
2191 : }
|