1 : /**********************************************************************
2 : * $Id: cpl_string.cpp 23407 2011-11-21 19:35:16Z rouault $
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 23407 2011-11-21 19:35:16Z rouault $");
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 7460429 : char **CSLAddString(char **papszStrList, const char *pszNewString)
73 : {
74 7460429 : int nItems=0;
75 :
76 7460429 : if (pszNewString == NULL)
77 0 : return papszStrList; /* Nothing to do!*/
78 :
79 : /* Allocate room for the new string */
80 7460429 : if (papszStrList == NULL)
81 662930 : papszStrList = (char**) CPLCalloc(2,sizeof(char*));
82 : else
83 : {
84 6797499 : nItems = CSLCount(papszStrList);
85 : papszStrList = (char**)CPLRealloc(papszStrList,
86 6797499 : (nItems+2)*sizeof(char*));
87 : }
88 :
89 : /* Copy the string in the list */
90 7460429 : papszStrList[nItems] = CPLStrdup(pszNewString);
91 7460429 : papszStrList[nItems+1] = NULL;
92 :
93 7460429 : 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 11117752 : int CSLCount(char **papszStrList)
117 : {
118 11117752 : int nItems=0;
119 :
120 11117752 : if (papszStrList)
121 : {
122 148247359 : while(*papszStrList != NULL)
123 : {
124 128393631 : nItems++;
125 128393631 : papszStrList++;
126 : }
127 : }
128 :
129 11117752 : 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 113415 : const char * CSLGetField( char ** papszStrList, int iField )
143 :
144 : {
145 : int i;
146 :
147 113415 : if( papszStrList == NULL || iField < 0 )
148 11525 : return( "" );
149 :
150 747591 : for( i = 0; i < iField+1; i++ )
151 : {
152 645701 : if( papszStrList[i] == NULL )
153 0 : return "";
154 : }
155 :
156 101890 : 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 6783841 : void CPL_STDCALL CSLDestroy(char **papszStrList)
172 : {
173 : char **papszPtr;
174 :
175 6783841 : if (papszStrList)
176 : {
177 4916151 : papszPtr = papszStrList;
178 23075824 : while(*papszPtr != NULL)
179 : {
180 13243522 : CPLFree(*papszPtr);
181 13243522 : papszPtr++;
182 : }
183 :
184 4916151 : CPLFree(papszStrList);
185 : }
186 6783841 : }
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 102208 : char **CSLDuplicate(char **papszStrList)
204 : {
205 : char **papszNewList, **papszSrc, **papszDst;
206 : int nLines;
207 :
208 102208 : nLines = CSLCount(papszStrList);
209 :
210 102208 : if (nLines == 0)
211 77915 : return NULL;
212 :
213 24293 : papszNewList = (char **)CPLMalloc((nLines+1)*sizeof(char*));
214 24293 : papszSrc = papszStrList;
215 24293 : papszDst = papszNewList;
216 :
217 528128 : while(*papszSrc != NULL)
218 : {
219 479542 : *papszDst = CPLStrdup(*papszSrc);
220 :
221 479542 : papszSrc++;
222 479542 : papszDst++;
223 : }
224 24293 : *papszDst = NULL;
225 :
226 24293 : 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 564 : char **CSLMerge( char **papszOrig, char **papszOverride )
247 :
248 : {
249 : int i;
250 :
251 564 : if( papszOrig == NULL && papszOverride != NULL )
252 49 : return CSLDuplicate( papszOverride );
253 :
254 515 : if( papszOverride == NULL )
255 356 : return papszOrig;
256 :
257 437 : for( i = 0; papszOverride[i] != NULL; i++ )
258 : {
259 278 : char *pszKey = NULL;
260 278 : const char *pszValue = CPLParseNameValue( papszOverride[i], &pszKey );
261 :
262 278 : papszOrig = CSLSetNameValue( papszOrig, pszKey, pszValue );
263 278 : CPLFree( pszKey );
264 : }
265 :
266 159 : 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 1749 : char **CSLLoad2(const char *pszFname, int nMaxLines, int nMaxCols, char** papszOptions)
294 : {
295 : VSILFILE *fp;
296 : const char *pszLine;
297 1749 : char **papszStrList=NULL;
298 1749 : int nLines = 0;
299 1749 : int nAllocatedLines = 0;
300 :
301 1749 : fp = VSIFOpenL(pszFname, "rb");
302 :
303 1749 : if (fp)
304 : {
305 428 : CPLErrorReset();
306 428 : while(!VSIFEofL(fp) && (nMaxLines == -1 || nLines < nMaxLines))
307 : {
308 3670 : if ( (pszLine = CPLReadLine2L(fp, nMaxCols, papszOptions)) != NULL )
309 : {
310 3670 : if (nLines + 1 >= nAllocatedLines)
311 : {
312 : char** papszStrListNew;
313 485 : nAllocatedLines = 16 + nAllocatedLines * 2;
314 : papszStrListNew = (char**) VSIRealloc(papszStrList,
315 485 : nAllocatedLines * sizeof(char*));
316 485 : 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 485 : papszStrList = papszStrListNew;
326 : }
327 3670 : papszStrList[nLines] = CPLStrdup(pszLine);
328 3670 : papszStrList[nLines + 1] = NULL;
329 3670 : nLines ++;
330 : }
331 : else
332 0 : break;
333 : }
334 :
335 428 : VSIFCloseL(fp);
336 :
337 428 : CPLReadLineL( NULL );
338 : }
339 : else
340 : {
341 1321 : 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 1749 : 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 1168 : char **CSLInsertStrings(char **papszStrList, int nInsertAtLineNo,
465 : char **papszNewLines)
466 : {
467 : int i, nSrcLines, nDstLines, nToInsert;
468 : char **ppszSrc, **ppszDst;
469 :
470 1168 : if (papszNewLines == NULL ||
471 : ( nToInsert = CSLCount(papszNewLines) ) == 0)
472 2 : return papszStrList; /* Nothing to do!*/
473 :
474 1166 : nSrcLines = CSLCount(papszStrList);
475 1166 : nDstLines = nSrcLines + nToInsert;
476 :
477 : /* Allocate room for the new strings */
478 : papszStrList = (char**)CPLRealloc(papszStrList,
479 1166 : (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 1166 : 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 1166 : if (nInsertAtLineNo == -1 || nInsertAtLineNo > nSrcLines)
491 582 : nInsertAtLineNo = nSrcLines;
492 :
493 1166 : ppszSrc = papszStrList + nSrcLines;
494 1166 : ppszDst = papszStrList + nDstLines;
495 :
496 3233 : for (i=nSrcLines; i>=nInsertAtLineNo; i--)
497 : {
498 2067 : *ppszDst = *ppszSrc;
499 2067 : ppszDst--;
500 2067 : ppszSrc--;
501 : }
502 :
503 : /* Copy the strings to the list */
504 1166 : ppszSrc = papszNewLines;
505 1166 : ppszDst = papszStrList + nInsertAtLineNo;
506 :
507 19287 : for (; *ppszSrc != NULL; ppszSrc++, ppszDst++)
508 : {
509 18121 : *ppszDst = CPLStrdup(*ppszSrc);
510 : }
511 :
512 1166 : 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 24 : 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 24 : apszList[0] = (char *) pszNewLine;
535 24 : apszList[1] = NULL;
536 :
537 24 : 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 50 : char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete,
558 : int nNumToRemove, char ***ppapszRetStrings)
559 : {
560 : int i, nSrcLines, nDstLines;
561 : char **ppszSrc, **ppszDst;
562 :
563 50 : nSrcLines = CSLCount(papszStrList);
564 50 : nDstLines = nSrcLines - nNumToRemove;
565 :
566 50 : 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 50 : if (nDstLines < 1)
573 : {
574 19 : CSLDestroy(papszStrList);
575 19 : 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 31 : ppszDst = papszStrList + nFirstLineToDelete;
584 :
585 31 : if (ppapszRetStrings == NULL)
586 : {
587 : /* free() all the strings that will be removed.
588 : */
589 62 : for (i=0; i < nNumToRemove; i++)
590 : {
591 31 : CPLFree(*ppszDst);
592 31 : *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 31 : if (nFirstLineToDelete == -1 || nFirstLineToDelete > nSrcLines)
613 0 : nFirstLineToDelete = nDstLines;
614 :
615 31 : ppszSrc = papszStrList + nFirstLineToDelete + nNumToRemove;
616 31 : ppszDst = papszStrList + nFirstLineToDelete;
617 :
618 89 : for ( ; *ppszSrc != NULL; ppszSrc++, ppszDst++)
619 : {
620 58 : *ppszDst = *ppszSrc;
621 : }
622 : /* Move the NULL pointer at the end of the StringList */
623 31 : *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 31 : 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 1726173 : int CSLFindString( char ** papszList, const char * pszTarget )
651 :
652 : {
653 : int i;
654 :
655 1726173 : if( papszList == NULL )
656 188478 : return -1;
657 :
658 4655854 : for( i = 0; papszList[i] != NULL; i++ )
659 : {
660 4114833 : if( EQUAL(papszList[i],pszTarget) )
661 996674 : return i;
662 : }
663 :
664 541021 : 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 4855 : char **CSLTokenizeString( const char *pszString )
707 : {
708 4855 : return CSLTokenizeString2( pszString, " ", CSLT_HONOURSTRINGS );
709 : }
710 :
711 : /************************************************************************/
712 : /* CSLTokenizeStringComplex() */
713 : /* */
714 : /* Obsolete tokenizing api. */
715 : /************************************************************************/
716 :
717 1410958 : char ** CSLTokenizeStringComplex( const char * pszString,
718 : const char * pszDelimiters,
719 : int bHonourStrings, int bAllowEmptyTokens )
720 :
721 : {
722 1410958 : int nFlags = 0;
723 :
724 1410958 : if( bHonourStrings )
725 1385019 : nFlags |= CSLT_HONOURSTRINGS;
726 1410958 : if( bAllowEmptyTokens )
727 489 : nFlags |= CSLT_ALLOWEMPTYTOKENS;
728 :
729 1410958 : 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 1437651 : char ** CSLTokenizeString2( const char * pszString,
788 : const char * pszDelimiters,
789 : int nCSLTFlags )
790 :
791 : {
792 1437651 : if( pszString == NULL )
793 0 : return (char **) CPLCalloc(sizeof(char *),1);
794 1437651 : CPLStringList oRetList;
795 : char *pszToken;
796 : int nTokenMax, nTokenLen;
797 1437651 : int bHonourStrings = (nCSLTFlags & CSLT_HONOURSTRINGS);
798 1437651 : int bAllowEmptyTokens = (nCSLTFlags & CSLT_ALLOWEMPTYTOKENS);
799 1437651 : int bStripLeadSpaces = (nCSLTFlags & CSLT_STRIPLEADSPACES);
800 1437651 : int bStripEndSpaces = (nCSLTFlags & CSLT_STRIPENDSPACES);
801 :
802 1437651 : pszToken = (char *) CPLCalloc(10,1);
803 1437651 : nTokenMax = 10;
804 :
805 4623090 : while( pszString != NULL && *pszString != '\0' )
806 : {
807 1747788 : int bInString = FALSE;
808 1747788 : int bStartString = TRUE;
809 :
810 1747788 : nTokenLen = 0;
811 :
812 : /* Try to find the next delimeter, marking end of token */
813 12834452 : for( ; *pszString != '\0'; pszString++ )
814 : {
815 :
816 : /* End if this is a delimeter skip it and break. */
817 11409539 : if( !bInString && strchr(pszDelimiters, *pszString) != NULL )
818 : {
819 322875 : pszString++;
820 322875 : 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 11086664 : if( bHonourStrings && *pszString == '"' )
827 : {
828 1778 : if( nCSLTFlags & CSLT_PRESERVEQUOTES )
829 : {
830 170 : pszToken[nTokenLen] = *pszString;
831 170 : nTokenLen++;
832 : }
833 :
834 1778 : if( bInString )
835 : {
836 864 : bInString = FALSE;
837 864 : continue;
838 : }
839 : else
840 : {
841 914 : bInString = TRUE;
842 914 : 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 11084886 : 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 11084886 : if ( !bInString && bStripLeadSpaces
869 : && bStartString && isspace((unsigned char)*pszString) )
870 1892 : continue;
871 :
872 11082994 : bStartString = FALSE;
873 :
874 : /*
875 : * Extend token buffer if we are running close to its end.
876 : */
877 11082994 : if( nTokenLen >= nTokenMax-3 )
878 : {
879 311706 : nTokenMax = nTokenMax * 2 + 10;
880 311706 : pszToken = (char *) CPLRealloc( pszToken, nTokenMax );
881 : }
882 :
883 11082994 : pszToken[nTokenLen] = *pszString;
884 11082994 : nTokenLen++;
885 : }
886 :
887 : /*
888 : * Strip spaces at the token end if requested.
889 : */
890 1747788 : if ( !bInString && bStripEndSpaces )
891 : {
892 6530 : while ( nTokenLen && isspace((unsigned char)pszToken[nTokenLen - 1]) )
893 48 : nTokenLen--;
894 : }
895 :
896 1747788 : pszToken[nTokenLen] = '\0';
897 :
898 : /*
899 : * Add the token.
900 : */
901 1747788 : if( pszToken[0] != '\0' || bAllowEmptyTokens )
902 1714406 : 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 1437651 : if( *pszString == '\0' && bAllowEmptyTokens && oRetList.Count() > 0
910 : && strchr(pszDelimiters,*(pszString-1)) != NULL )
911 : {
912 10 : oRetList.AddString( "" );
913 : }
914 :
915 1437651 : CPLFree( pszToken );
916 :
917 1437651 : 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 10135 : oRetList.Assign( (char**) CPLCalloc(sizeof(char**),1) );
922 : }
923 :
924 1437651 : 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 22696836 : const char *CPLSPrintf(const char *fmt, ...)
943 : {
944 : va_list args;
945 :
946 : /* -------------------------------------------------------------------- */
947 : /* Get the thread local buffer ring data. */
948 : /* -------------------------------------------------------------------- */
949 22696836 : char *pachBufRingInfo = (char *) CPLGetTLS( CTLS_CPLSPRINTF );
950 :
951 22696836 : if( pachBufRingInfo == NULL )
952 : {
953 : pachBufRingInfo = (char *)
954 74 : CPLCalloc(1,sizeof(int)+CPLSPrintf_BUF_Count*CPLSPrintf_BUF_SIZE);
955 74 : 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 22696836 : int *pnBufIndex = (int *) pachBufRingInfo;
963 22696836 : int nOffset = sizeof(int) + *pnBufIndex * CPLSPrintf_BUF_SIZE;
964 22696836 : char *pachBuffer = pachBufRingInfo + nOffset;
965 :
966 22696836 : *pnBufIndex = (*pnBufIndex + 1) % CPLSPrintf_BUF_Count;
967 :
968 : /* -------------------------------------------------------------------- */
969 : /* Format the result. */
970 : /* -------------------------------------------------------------------- */
971 :
972 22696836 : va_start(args, fmt);
973 : #if defined(HAVE_VSNPRINTF)
974 22696836 : vsnprintf(pachBuffer, CPLSPrintf_BUF_SIZE-1, fmt, args);
975 : #else
976 : vsprintf(pachBuffer, fmt, args);
977 : #endif
978 22696836 : va_end(args);
979 :
980 22696836 : 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 1329 : int CPLVASPrintf( char **buf, const char *fmt, va_list ap )
1011 :
1012 : {
1013 1329 : CPLString osWork;
1014 :
1015 1329 : osWork.vPrintf( fmt, ap );
1016 :
1017 1329 : if( buf )
1018 1329 : *buf = CPLStrdup(osWork.c_str());
1019 :
1020 1329 : 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 796291 : int CSLTestBoolean( const char *pszValue )
1039 : {
1040 796291 : if( EQUAL(pszValue,"NO")
1041 : || EQUAL(pszValue,"FALSE")
1042 : || EQUAL(pszValue,"OFF")
1043 : || EQUAL(pszValue,"0") )
1044 770845 : return FALSE;
1045 : else
1046 25446 : 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 18789 : int CSLFetchBoolean( char **papszStrList, const char *pszKey, int bDefault )
1069 :
1070 : {
1071 : const char *pszValue;
1072 :
1073 18789 : if( CSLFindString( papszStrList, pszKey ) != -1 )
1074 0 : return TRUE;
1075 :
1076 18789 : pszValue = CSLFetchNameValue(papszStrList, pszKey );
1077 18789 : if( pszValue == NULL )
1078 17194 : return bDefault;
1079 : else
1080 1595 : return CSLTestBoolean( pszValue );
1081 : }
1082 :
1083 : /************************************************************************/
1084 : /* CSLFetchNameValueDefaulted() */
1085 : /************************************************************************/
1086 :
1087 891 : const char *CSLFetchNameValueDef( char **papszStrList,
1088 : const char *pszName,
1089 : const char *pszDefault )
1090 :
1091 : {
1092 891 : const char *pszResult = CSLFetchNameValue( papszStrList, pszName );
1093 891 : if( pszResult )
1094 34 : return pszResult;
1095 : else
1096 857 : 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 1912062 : const char *CSLFetchNameValue(char **papszStrList, const char *pszName)
1114 : {
1115 : size_t nLen;
1116 :
1117 1912062 : if (papszStrList == NULL || pszName == NULL)
1118 104672 : return NULL;
1119 :
1120 1807390 : nLen = strlen(pszName);
1121 12890618 : while(*papszStrList != NULL)
1122 : {
1123 10653348 : if (EQUALN(*papszStrList, pszName, nLen)
1124 688439 : && ( (*papszStrList)[nLen] == '=' ||
1125 872 : (*papszStrList)[nLen] == ':' ) )
1126 : {
1127 688199 : return (*papszStrList)+nLen+1;
1128 : }
1129 9275838 : papszStrList++;
1130 : }
1131 1119191 : 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 97 : int CSLFindName(char **papszStrList, const char *pszName)
1149 : {
1150 : size_t nLen;
1151 97 : int iIndex = 0;
1152 :
1153 97 : if (papszStrList == NULL || pszName == NULL)
1154 40 : return -1;
1155 :
1156 57 : nLen = strlen(pszName);
1157 162 : while(*papszStrList != NULL)
1158 : {
1159 68 : if (EQUALN(*papszStrList, pszName, nLen)
1160 10 : && ( (*papszStrList)[nLen] == '=' ||
1161 0 : (*papszStrList)[nLen] == ':' ) )
1162 : {
1163 10 : return iIndex;
1164 : }
1165 48 : iIndex++;
1166 48 : papszStrList++;
1167 : }
1168 47 : 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 10555 : const char *CPLParseNameValue(const char *pszNameValue, char **ppszKey )
1196 :
1197 : {
1198 : int i;
1199 : const char *pszValue;
1200 :
1201 136830 : for( i = 0; pszNameValue[i] != '\0'; i++ )
1202 : {
1203 136431 : if( pszNameValue[i] == '=' || pszNameValue[i] == ':' )
1204 : {
1205 10156 : pszValue = pszNameValue + i + 1;
1206 22623 : while( *pszValue == ' ' || *pszValue == '\t' )
1207 2311 : pszValue++;
1208 :
1209 10156 : if( ppszKey != NULL )
1210 : {
1211 10144 : *ppszKey = (char *) CPLMalloc(i+1);
1212 10144 : strncpy( *ppszKey, pszNameValue, i );
1213 10144 : (*ppszKey)[i] = '\0';
1214 40576 : while( i > 0 &&
1215 20288 : ( (*ppszKey)[i] == ' ' || (*ppszKey)[i] == '\t') )
1216 : {
1217 0 : (*ppszKey)[i] = '\0';
1218 0 : i--;
1219 : }
1220 : }
1221 :
1222 10156 : return pszValue;
1223 : }
1224 : }
1225 :
1226 399 : 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 428 : char **CSLFetchNameValueMultiple(char **papszStrList, const char *pszName)
1245 : {
1246 : size_t nLen;
1247 428 : char **papszValues = NULL;
1248 :
1249 428 : if (papszStrList == NULL || pszName == NULL)
1250 308 : return NULL;
1251 :
1252 120 : nLen = strlen(pszName);
1253 468 : while(*papszStrList != NULL)
1254 : {
1255 250 : 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 228 : papszStrList++;
1263 : }
1264 :
1265 120 : 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 171394 : char **CSLAddNameValue(char **papszStrList,
1283 : const char *pszName, const char *pszValue)
1284 : {
1285 : char *pszLine;
1286 :
1287 171394 : if (pszName == NULL || pszValue==NULL)
1288 0 : return papszStrList;
1289 :
1290 171394 : pszLine = (char *) CPLMalloc(strlen(pszName)+strlen(pszValue)+2);
1291 171394 : sprintf( pszLine, "%s=%s", pszName, pszValue );
1292 171394 : papszStrList = CSLAddString(papszStrList, pszLine);
1293 171394 : CPLFree( pszLine );
1294 :
1295 171394 : 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 165539 : char **CSLSetNameValue(char **papszList,
1323 : const char *pszName, const char *pszValue)
1324 : {
1325 : char **papszPtr;
1326 : size_t nLen;
1327 :
1328 165539 : if (pszName == NULL )
1329 384 : return papszList;
1330 :
1331 165155 : nLen = strlen(pszName);
1332 165155 : papszPtr = papszList;
1333 6610472 : while(papszPtr && *papszPtr != NULL)
1334 : {
1335 6284570 : if (EQUALN(*papszPtr, pszName, nLen)
1336 2121 : && ( (*papszPtr)[nLen] == '=' ||
1337 1461 : (*papszPtr)[nLen] == ':' ) )
1338 : {
1339 : /* Found it!
1340 : * Change the value... make sure to keep the ':' or '='
1341 : */
1342 : char cSep;
1343 826 : cSep = (*papszPtr)[nLen];
1344 :
1345 826 : CPLFree(*papszPtr);
1346 :
1347 : /*
1348 : * If the value is NULL, remove this entry completely/
1349 : */
1350 826 : if( pszValue == NULL )
1351 : {
1352 180 : while( papszPtr[1] != NULL )
1353 : {
1354 28 : *papszPtr = papszPtr[1];
1355 28 : papszPtr++;
1356 : }
1357 76 : *papszPtr = NULL;
1358 : }
1359 :
1360 : /*
1361 : * Otherwise replace with new value.
1362 : */
1363 : else
1364 : {
1365 750 : *papszPtr = (char *) CPLMalloc(strlen(pszName)+strlen(pszValue)+2);
1366 750 : sprintf( *papszPtr, "%s%c%s", pszName, cSep, pszValue );
1367 : }
1368 826 : return papszList;
1369 : }
1370 6280162 : papszPtr++;
1371 : }
1372 :
1373 164329 : if( pszValue == NULL )
1374 12 : return papszList;
1375 :
1376 : /* The name does not exist yet... create a new entry
1377 : */
1378 164317 : 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 66 : void CSLSetNameValueSeparator( char ** papszList, const char *pszSeparator )
1406 :
1407 : {
1408 66 : int nLines = CSLCount(papszList), iLine;
1409 :
1410 1396 : for( iLine = 0; iLine < nLines; iLine++ )
1411 : {
1412 1330 : char *pszKey = NULL;
1413 : const char *pszValue;
1414 : char *pszNewLine;
1415 :
1416 1330 : pszValue = CPLParseNameValue( papszList[iLine], &pszKey );
1417 1330 : if( pszValue == NULL || pszKey == NULL )
1418 0 : continue;
1419 :
1420 : pszNewLine = (char *) CPLMalloc( strlen(pszValue) + strlen(pszKey)
1421 1330 : + strlen(pszSeparator) + 1 );
1422 1330 : strcpy( pszNewLine, pszKey );
1423 1330 : strcat( pszNewLine, pszSeparator );
1424 1330 : strcat( pszNewLine, pszValue );
1425 1330 : CPLFree( papszList[iLine] );
1426 1330 : papszList[iLine] = pszNewLine;
1427 1330 : CPLFree( pszKey );
1428 : }
1429 66 : }
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 32889 : char *CPLEscapeString( const char *pszInput, int nLength,
1479 : int nScheme )
1480 :
1481 : {
1482 : char *pszOutput;
1483 : char *pszShortOutput;
1484 :
1485 32889 : if( nLength == -1 )
1486 32842 : nLength = strlen(pszInput);
1487 :
1488 32889 : pszOutput = (char *) CPLMalloc( nLength * 6 + 1 );
1489 :
1490 32889 : 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 32856 : else if( nScheme == CPLES_URL ) /* Untested at implementation */
1522 : {
1523 50 : int iOut = 0, iIn;
1524 :
1525 582 : for( iIn = 0; iIn < nLength; iIn++ )
1526 : {
1527 1450 : if( (pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z')
1528 240 : || (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z')
1529 67 : || (pszInput[iIn] >= '0' && pszInput[iIn] <= '9')
1530 85 : || pszInput[iIn] == '_' || pszInput[iIn] == '.' )
1531 : {
1532 526 : pszOutput[iOut++] = pszInput[iIn];
1533 : }
1534 : else
1535 : {
1536 6 : sprintf( pszOutput+iOut, "%%%02X", ((unsigned char*)pszInput)[iIn] );
1537 6 : iOut += 3;
1538 : }
1539 : }
1540 50 : pszOutput[iOut] = '\0';
1541 : }
1542 32806 : else if( nScheme == CPLES_XML )
1543 : {
1544 32698 : int iOut = 0, iIn;
1545 :
1546 719815 : for( iIn = 0; iIn < nLength; iIn++ )
1547 : {
1548 687117 : if( pszInput[iIn] == '<' )
1549 : {
1550 4 : pszOutput[iOut++] = '&';
1551 4 : pszOutput[iOut++] = 'l';
1552 4 : pszOutput[iOut++] = 't';
1553 4 : pszOutput[iOut++] = ';';
1554 : }
1555 687113 : else if( pszInput[iIn] == '>' )
1556 : {
1557 3 : pszOutput[iOut++] = '&';
1558 3 : pszOutput[iOut++] = 'g';
1559 3 : pszOutput[iOut++] = 't';
1560 3 : pszOutput[iOut++] = ';';
1561 : }
1562 687110 : else if( pszInput[iIn] == '&' )
1563 : {
1564 144 : pszOutput[iOut++] = '&';
1565 144 : pszOutput[iOut++] = 'a';
1566 144 : pszOutput[iOut++] = 'm';
1567 144 : pszOutput[iOut++] = 'p';
1568 144 : pszOutput[iOut++] = ';';
1569 : }
1570 686966 : else if( pszInput[iIn] == '"' )
1571 : {
1572 7962 : pszOutput[iOut++] = '&';
1573 7962 : pszOutput[iOut++] = 'q';
1574 7962 : pszOutput[iOut++] = 'u';
1575 7962 : pszOutput[iOut++] = 'o';
1576 7962 : pszOutput[iOut++] = 't';
1577 7962 : pszOutput[iOut++] = ';';
1578 : }
1579 679010 : else if( ((GByte*)pszInput)[iIn] < 0x20
1580 3 : && pszInput[iIn] != 0x9
1581 3 : && pszInput[iIn] != 0xA
1582 0 : && pszInput[iIn] != 0xD )
1583 : {
1584 : // These control characters are unrepresentable in XML format,
1585 : // so we just drop them. #4117
1586 : }
1587 : else
1588 679004 : pszOutput[iOut++] = pszInput[iIn];
1589 : }
1590 32698 : pszOutput[iOut] = '\0';
1591 : }
1592 108 : else if( nScheme == CPLES_SQL )
1593 : {
1594 14 : int iOut = 0, iIn;
1595 :
1596 70 : for( iIn = 0; iIn < nLength; iIn++ )
1597 : {
1598 56 : if( pszInput[iIn] == '\'' )
1599 : {
1600 0 : pszOutput[iOut++] = '\'';
1601 0 : pszOutput[iOut++] = '\'';
1602 : }
1603 : else
1604 56 : pszOutput[iOut++] = pszInput[iIn];
1605 : }
1606 14 : pszOutput[iOut] = '\0';
1607 : }
1608 94 : else if( nScheme == CPLES_CSV )
1609 : {
1610 178 : 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 84 : strcpy( pszOutput, pszInput );
1618 : }
1619 : else
1620 : {
1621 10 : int iOut = 1, iIn;
1622 :
1623 10 : pszOutput[0] = '\"';
1624 :
1625 444 : for( iIn = 0; iIn < nLength; iIn++ )
1626 : {
1627 434 : if( pszInput[iIn] == '\"' )
1628 : {
1629 6 : pszOutput[iOut++] = '\"';
1630 6 : pszOutput[iOut++] = '\"';
1631 : }
1632 428 : else if( pszInput[iIn] == 13 )
1633 : /* drop DOS LF's in strings. */;
1634 : else
1635 428 : pszOutput[iOut++] = pszInput[iIn];
1636 : }
1637 10 : pszOutput[iOut++] = '\"';
1638 10 : pszOutput[iOut++] = '\0';
1639 : }
1640 : }
1641 : else
1642 : {
1643 0 : pszOutput[0] = '\0';
1644 : CPLError( CE_Failure, CPLE_AppDefined,
1645 : "Undefined escaping scheme (%d) in CPLEscapeString()",
1646 0 : nScheme );
1647 : }
1648 :
1649 32889 : pszShortOutput = CPLStrdup( pszOutput );
1650 32889 : CPLFree( pszOutput );
1651 :
1652 32889 : return pszShortOutput;
1653 : }
1654 :
1655 : /************************************************************************/
1656 : /* CPLUnescapeString() */
1657 : /************************************************************************/
1658 :
1659 : /**
1660 : * Unescape a string.
1661 : *
1662 : * This function does the opposite of CPLEscapeString(). Given a string
1663 : * with special values escaped according to some scheme, it will return a
1664 : * new copy of the string returned to it's original form.
1665 : *
1666 : * @param pszInput the input string. This is a zero terminated string.
1667 : * @param pnLength location to return the length of the unescaped string,
1668 : * which may in some cases include embedded '\\0' characters.
1669 : * @param nScheme the escaped scheme to undo (see CPLEscapeString() for a
1670 : * list).
1671 : *
1672 : * @return a copy of the unescaped string that should be freed by the
1673 : * application using CPLFree() when no longer needed.
1674 : */
1675 :
1676 2658 : char *CPLUnescapeString( const char *pszInput, int *pnLength, int nScheme )
1677 :
1678 : {
1679 : char *pszOutput;
1680 2658 : int iOut=0, iIn;
1681 :
1682 2658 : pszOutput = (char *) CPLMalloc(4 * strlen(pszInput)+1);
1683 2658 : pszOutput[0] = '\0';
1684 :
1685 2658 : if( nScheme == CPLES_XML )
1686 : {
1687 : char ch;
1688 175291 : for( iIn = 0; (ch = pszInput[iIn]) != '\0'; iIn++ )
1689 : {
1690 172790 : if( ch != '&' )
1691 : {
1692 161048 : pszOutput[iOut++] = ch;
1693 : }
1694 11742 : else if( EQUALN(pszInput+iIn,"<",4) )
1695 : {
1696 6 : pszOutput[iOut++] = '<';
1697 6 : iIn += 3;
1698 : }
1699 11736 : else if( EQUALN(pszInput+iIn,">",4) )
1700 : {
1701 6 : pszOutput[iOut++] = '>';
1702 6 : iIn += 3;
1703 : }
1704 11730 : else if( EQUALN(pszInput+iIn,"&",5) )
1705 : {
1706 270 : pszOutput[iOut++] = '&';
1707 270 : iIn += 4;
1708 : }
1709 11460 : else if( EQUALN(pszInput+iIn,"'",6) )
1710 : {
1711 0 : pszOutput[iOut++] = '\'';
1712 0 : iIn += 5;
1713 : }
1714 11460 : else if( EQUALN(pszInput+iIn,""",6) )
1715 : {
1716 11446 : pszOutput[iOut++] = '"';
1717 11446 : iIn += 5;
1718 : }
1719 14 : else if( EQUALN(pszInput+iIn,"&#x",3) )
1720 : {
1721 0 : wchar_t anVal[2] = {0 , 0};
1722 0 : iIn += 3;
1723 :
1724 0 : while(TRUE)
1725 : {
1726 0 : ch = pszInput[iIn ++];
1727 0 : if (ch >= 'a' && ch <= 'f')
1728 0 : anVal[0] = anVal[0] * 16 + ch - 'a' + 10;
1729 0 : else if (ch >= 'A' && ch <= 'A')
1730 0 : anVal[0] = anVal[0] * 16 + ch - 'A' + 10;
1731 0 : else if (ch >= '0' && ch <= '9')
1732 0 : anVal[0] = anVal[0] * 16 + ch - '0';
1733 : else
1734 : break;
1735 : }
1736 0 : if (ch != ';')
1737 0 : break;
1738 0 : iIn --;
1739 :
1740 0 : char * pszUTF8 = CPLRecodeFromWChar( anVal, "WCHAR_T", CPL_ENC_UTF8);
1741 0 : int nLen = strlen(pszUTF8);
1742 0 : memcpy(pszOutput + iOut, pszUTF8, nLen);
1743 0 : CPLFree(pszUTF8);
1744 0 : iOut += nLen;
1745 : }
1746 14 : else if( EQUALN(pszInput+iIn,"&#",2) )
1747 : {
1748 : char ch;
1749 14 : wchar_t anVal[2] = {0 , 0};
1750 14 : iIn += 2;
1751 :
1752 28 : while(TRUE)
1753 : {
1754 42 : ch = pszInput[iIn ++];
1755 42 : if (ch >= '0' && ch <= '9')
1756 28 : anVal[0] = anVal[0] * 10 + ch - '0';
1757 : else
1758 : break;
1759 : }
1760 14 : if (ch != ';')
1761 0 : break;
1762 14 : iIn --;
1763 :
1764 14 : char * pszUTF8 = CPLRecodeFromWChar( anVal, "WCHAR_T", CPL_ENC_UTF8);
1765 14 : int nLen = strlen(pszUTF8);
1766 14 : memcpy(pszOutput + iOut, pszUTF8, nLen);
1767 14 : CPLFree(pszUTF8);
1768 14 : iOut += nLen;
1769 : }
1770 : else
1771 : {
1772 : /* illegal escape sequence */
1773 : CPLDebug( "CPL",
1774 0 : "Error unescaping CPLES_XML text, '&' character followed by unhandled escape sequence." );
1775 0 : break;
1776 : }
1777 : }
1778 : }
1779 157 : else if( nScheme == CPLES_URL )
1780 : {
1781 152 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1782 : {
1783 137 : if( pszInput[iIn] == '%'
1784 0 : && pszInput[iIn+1] != '\0'
1785 0 : && pszInput[iIn+2] != '\0' )
1786 : {
1787 0 : int nHexChar = 0;
1788 :
1789 0 : if( pszInput[iIn+1] >= 'A' && pszInput[iIn+1] <= 'F' )
1790 0 : nHexChar += 16 * (pszInput[iIn+1] - 'A' + 10);
1791 0 : else if( pszInput[iIn+1] >= 'a' && pszInput[iIn+1] <= 'f' )
1792 0 : nHexChar += 16 * (pszInput[iIn+1] - 'a' + 10);
1793 0 : else if( pszInput[iIn+1] >= '0' && pszInput[iIn+1] <= '9' )
1794 0 : nHexChar += 16 * (pszInput[iIn+1] - '0');
1795 : else
1796 : CPLDebug( "CPL",
1797 : "Error unescaping CPLES_URL text, percent not "
1798 0 : "followed by two hex digits." );
1799 :
1800 0 : if( pszInput[iIn+2] >= 'A' && pszInput[iIn+2] <= 'F' )
1801 0 : nHexChar += pszInput[iIn+2] - 'A' + 10;
1802 0 : else if( pszInput[iIn+2] >= 'a' && pszInput[iIn+2] <= 'f' )
1803 0 : nHexChar += pszInput[iIn+2] - 'a' + 10;
1804 0 : else if( pszInput[iIn+2] >= '0' && pszInput[iIn+2] <= '9' )
1805 0 : nHexChar += pszInput[iIn+2] - '0';
1806 : else
1807 : CPLDebug( "CPL",
1808 : "Error unescaping CPLES_URL text, percent not "
1809 0 : "followed by two hex digits." );
1810 :
1811 0 : pszOutput[iOut++] = (char) nHexChar;
1812 0 : iIn += 2;
1813 : }
1814 137 : else if( pszInput[iIn] == '+' )
1815 : {
1816 0 : pszOutput[iOut++] = ' ';
1817 : }
1818 : else
1819 : {
1820 137 : pszOutput[iOut++] = pszInput[iIn];
1821 : }
1822 : }
1823 : }
1824 142 : else if( nScheme == CPLES_SQL )
1825 : {
1826 0 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1827 : {
1828 0 : if( pszInput[iIn] == '\'' && pszInput[iIn+1] == '\'' )
1829 : {
1830 0 : iIn++;
1831 0 : pszOutput[iOut++] = pszInput[iIn];
1832 : }
1833 : else
1834 : {
1835 0 : pszOutput[iOut++] = pszInput[iIn];
1836 : }
1837 : }
1838 : }
1839 : else /* if( nScheme == CPLES_BackslashQuoteable ) */
1840 : {
1841 205225 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1842 : {
1843 205083 : if( pszInput[iIn] == '\\' )
1844 : {
1845 31 : iIn++;
1846 31 : if( pszInput[iIn] == 'n' )
1847 0 : pszOutput[iOut++] = '\n';
1848 31 : else if( pszInput[iIn] == '0' )
1849 1 : pszOutput[iOut++] = '\0';
1850 : else
1851 30 : pszOutput[iOut++] = pszInput[iIn];
1852 : }
1853 : else
1854 : {
1855 205052 : pszOutput[iOut++] = pszInput[iIn];
1856 : }
1857 : }
1858 : }
1859 :
1860 2658 : pszOutput[iOut] = '\0';
1861 :
1862 2658 : if( pnLength != NULL )
1863 629 : *pnLength = iOut;
1864 :
1865 2658 : return pszOutput;
1866 : }
1867 :
1868 : /************************************************************************/
1869 : /* CPLBinaryToHex() */
1870 : /************************************************************************/
1871 :
1872 : /**
1873 : * Binary to hexadecimal translation.
1874 : *
1875 : * @param nBytes number of bytes of binary data in pabyData.
1876 : * @param pabyData array of data bytes to translate.
1877 : *
1878 : * @return hexadecimal translation, zero terminated. Free with CPLFree().
1879 : */
1880 :
1881 495 : char *CPLBinaryToHex( int nBytes, const GByte *pabyData )
1882 :
1883 : {
1884 495 : char *pszHex = (char *) CPLMalloc(nBytes * 2 + 1 );
1885 : int i;
1886 : static const char achHex[] = "0123456789ABCDEF";
1887 :
1888 495 : pszHex[nBytes*2] = '\0';
1889 :
1890 57692 : for( i = 0; i < nBytes; i++ )
1891 : {
1892 57197 : int nLow = pabyData[i] & 0x0f;
1893 57197 : int nHigh = (pabyData[i] & 0xf0) >> 4;
1894 :
1895 57197 : pszHex[i*2] = achHex[nHigh];
1896 57197 : pszHex[i*2+1] = achHex[nLow];
1897 : }
1898 :
1899 495 : return pszHex;
1900 : }
1901 :
1902 :
1903 : /************************************************************************/
1904 : /* CPLHexToBinary() */
1905 : /************************************************************************/
1906 :
1907 : /**
1908 : * Hexadecimal to binary translation
1909 : *
1910 : * @param pszHex the input hex encoded string.
1911 : * @param pnBytes the returned count of decoded bytes placed here.
1912 : *
1913 : * @return returns binary buffer of data - free with CPLFree().
1914 : */
1915 :
1916 305 : GByte *CPLHexToBinary( const char *pszHex, int *pnBytes )
1917 :
1918 : {
1919 305 : int iSrc = 0, iDst = 0;
1920 305 : size_t nHexLen = strlen(pszHex);
1921 :
1922 : GByte *pabyWKB;
1923 :
1924 305 : pabyWKB = (GByte *) CPLMalloc(nHexLen / 2 + 2);
1925 :
1926 126379 : while( pszHex[iSrc] != '\0' )
1927 : {
1928 243117 : if( pszHex[iSrc] >= '0' && pszHex[iSrc] <= '9' )
1929 117348 : pabyWKB[iDst] = pszHex[iSrc] - '0';
1930 16842 : else if( pszHex[iSrc] >= 'A' && pszHex[iSrc] <= 'F' )
1931 8421 : pabyWKB[iDst] = pszHex[iSrc] - 'A' + 10;
1932 0 : else if( pszHex[iSrc] >= 'a' && pszHex[iSrc] <= 'f' )
1933 0 : pabyWKB[iDst] = pszHex[iSrc] - 'a' + 10;
1934 : else
1935 0 : break;
1936 :
1937 125769 : pabyWKB[iDst] *= 16;
1938 :
1939 125769 : iSrc++;
1940 :
1941 233778 : if( pszHex[iSrc] >= '0' && pszHex[iSrc] <= '9' )
1942 108009 : pabyWKB[iDst] += pszHex[iSrc] - '0';
1943 35520 : else if( pszHex[iSrc] >= 'A' && pszHex[iSrc] <= 'F' )
1944 17760 : pabyWKB[iDst] += pszHex[iSrc] - 'A' + 10;
1945 0 : else if( pszHex[iSrc] >= 'a' && pszHex[iSrc] <= 'f' )
1946 0 : pabyWKB[iDst] += pszHex[iSrc] - 'a' + 10;
1947 : else
1948 0 : break;
1949 :
1950 125769 : iSrc++;
1951 125769 : iDst++;
1952 : }
1953 :
1954 305 : pabyWKB[iDst] = 0;
1955 305 : *pnBytes = iDst;
1956 :
1957 305 : return pabyWKB;
1958 : }
1959 :
1960 :
1961 :
1962 : /************************************************************************/
1963 : /* CPLGetValueType() */
1964 : /************************************************************************/
1965 :
1966 : /**
1967 : * Detect the type of the value contained in a string, whether it is
1968 : * a real, an integer or a string
1969 : * Leading and trailing spaces are skipped in the analysis.
1970 : *
1971 : * Note: in the context of this function, integer must be understood in a
1972 : * broad sense. It does not mean that the value can fit into a 32 bit integer
1973 : * for example. It might be larger.
1974 : *
1975 : * @param pszValue the string to analyze
1976 : *
1977 : * @return returns the type of the value contained in the string.
1978 : */
1979 :
1980 1977 : CPLValueType CPLGetValueType(const char* pszValue)
1981 : {
1982 : /*
1983 : doubles : "+25.e+3", "-25.e-3", "25.e3", "25e3", " 25e3 "
1984 : not doubles: "25e 3", "25e.3", "-2-5e3", "2-5e3", "25.25.3"
1985 : */
1986 :
1987 1977 : int bFoundDot = FALSE;
1988 1977 : int bFoundExponent = FALSE;
1989 1977 : int bIsLastCharExponent = FALSE;
1990 1977 : int bIsReal = FALSE;
1991 :
1992 1977 : if (pszValue == NULL)
1993 0 : return CPL_VALUE_STRING;
1994 :
1995 : /* Skip leading + or - */
1996 1977 : if (*pszValue == '+' || *pszValue == '-')
1997 14 : pszValue ++;
1998 :
1999 : /* Skip leading spaces */
2000 3960 : while( isspace( (unsigned char)*pszValue ) )
2001 6 : pszValue ++;
2002 :
2003 4099 : for(; *pszValue != '\0'; pszValue++ )
2004 : {
2005 3319 : if( isdigit( *pszValue))
2006 : {
2007 1986 : bIsLastCharExponent = FALSE;
2008 : /* do nothing */
2009 : }
2010 1333 : else if ( isspace ((unsigned char)*pszValue) )
2011 : {
2012 4 : const char* pszTmp = pszValue;
2013 12 : while( isspace( (unsigned char)*pszTmp ) )
2014 4 : pszTmp ++;
2015 4 : if (*pszTmp == 0)
2016 0 : break;
2017 : else
2018 4 : return CPL_VALUE_STRING;
2019 : }
2020 1329 : else if ( *pszValue == '-' || *pszValue == '+' )
2021 : {
2022 7 : if (bIsLastCharExponent)
2023 : {
2024 : /* do nothing */
2025 : }
2026 : else
2027 7 : return CPL_VALUE_STRING;
2028 0 : bIsLastCharExponent = FALSE;
2029 : }
2030 1322 : else if ( *pszValue == '.')
2031 : {
2032 115 : bIsReal = TRUE;
2033 115 : if (!bFoundDot && bIsLastCharExponent == FALSE)
2034 115 : bFoundDot = TRUE;
2035 : else
2036 0 : return CPL_VALUE_STRING;
2037 115 : bIsLastCharExponent = FALSE;
2038 : }
2039 1228 : else if (*pszValue == 'D' || *pszValue == 'd'
2040 : || *pszValue == 'E' || *pszValue == 'e' )
2041 : {
2042 30 : bIsReal = TRUE;
2043 30 : if (!bFoundExponent)
2044 21 : bFoundExponent = TRUE;
2045 : else
2046 9 : return CPL_VALUE_STRING;
2047 21 : bIsLastCharExponent = TRUE;
2048 : }
2049 : else
2050 : {
2051 1177 : return CPL_VALUE_STRING;
2052 : }
2053 : }
2054 :
2055 780 : return (bIsReal) ? CPL_VALUE_REAL : CPL_VALUE_INTEGER;
2056 : }
2057 :
2058 : /************************************************************************/
2059 : /* CPLStrlcpy() */
2060 : /************************************************************************/
2061 :
2062 : /**
2063 : * Copy source string to a destination buffer.
2064 : *
2065 : * This function ensures that the destination buffer is always NUL terminated
2066 : * (provided that its length is at least 1).
2067 : *
2068 : * This function is designed to be a safer, more consistent, and less error
2069 : * prone replacement for strncpy. Its contract is identical to libbsd's strlcpy.
2070 : *
2071 : * Truncation can be detected by testing if the return value of CPLStrlcpy
2072 : * is greater or equal to nDestSize.
2073 :
2074 : \verbatim
2075 : char szDest[5];
2076 : if (CPLStrlcpy(szDest, "abcde", sizeof(szDest)) >= sizeof(szDest))
2077 : fprintf(stderr, "truncation occured !\n");
2078 : \endverbatim
2079 :
2080 : * @param pszDest destination buffer
2081 : * @param pszSrc source string. Must be NUL terminated
2082 : * @param nDestSize size of destination buffer (including space for the NUL terminator character)
2083 : *
2084 : * @return the length of the source string (=strlen(pszSrc))
2085 : *
2086 : * @since GDAL 1.7.0
2087 : */
2088 359055 : size_t CPLStrlcpy(char* pszDest, const char* pszSrc, size_t nDestSize)
2089 : {
2090 359055 : char* pszDestIter = pszDest;
2091 359055 : const char* pszSrcIter = pszSrc;
2092 :
2093 359055 : if (nDestSize == 0)
2094 0 : return strlen(pszSrc);
2095 :
2096 359055 : nDestSize --;
2097 2884414 : while(nDestSize != 0 && *pszSrcIter != '\0')
2098 : {
2099 2166304 : *pszDestIter = *pszSrcIter;
2100 2166304 : pszDestIter ++;
2101 2166304 : pszSrcIter ++;
2102 2166304 : nDestSize --;
2103 : }
2104 359055 : *pszDestIter = '\0';
2105 359055 : return pszSrcIter - pszSrc + strlen(pszSrcIter);
2106 : }
2107 :
2108 : /************************************************************************/
2109 : /* CPLStrlcat() */
2110 : /************************************************************************/
2111 :
2112 : /**
2113 : * Appends a source string to a destination buffer.
2114 : *
2115 : * This function ensures that the destination buffer is always NUL terminated
2116 : * (provided that its length is at least 1 and that there is at least one byte
2117 : * free in pszDest, that is to say strlen(pszDest_before) < nDestSize)
2118 : *
2119 : * This function is designed to be a safer, more consistent, and less error
2120 : * prone replacement for strncat. Its contract is identical to libbsd's strlcat.
2121 : *
2122 : * Truncation can be detected by testing if the return value of CPLStrlcat
2123 : * is greater or equal to nDestSize.
2124 :
2125 : \verbatim
2126 : char szDest[5];
2127 : CPLStrlcpy(szDest, "ab", sizeof(szDest));
2128 : if (CPLStrlcat(szDest, "cde", sizeof(szDest)) >= sizeof(szDest))
2129 : fprintf(stderr, "truncation occured !\n");
2130 : \endverbatim
2131 :
2132 : * @param pszDest destination buffer. Must be NUL terminated before running CPLStrlcat
2133 : * @param pszSrc source string. Must be NUL terminated
2134 : * @param nDestSize size of destination buffer (including space for the NUL terminator character)
2135 : *
2136 : * @return the thoretical length of the destination string after concatenation
2137 : * (=strlen(pszDest_before) + strlen(pszSrc)).
2138 : * If strlen(pszDest_before) >= nDestSize, then it returns nDestSize + strlen(pszSrc)
2139 : *
2140 : * @since GDAL 1.7.0
2141 : */
2142 161253 : size_t CPLStrlcat(char* pszDest, const char* pszSrc, size_t nDestSize)
2143 : {
2144 161253 : char* pszDestIter = pszDest;
2145 :
2146 3899977 : while(nDestSize != 0 && *pszDestIter != '\0')
2147 : {
2148 3577471 : pszDestIter ++;
2149 3577471 : nDestSize --;
2150 : }
2151 :
2152 161253 : return pszDestIter - pszDest + CPLStrlcpy(pszDestIter, pszSrc, nDestSize);
2153 : }
2154 :
2155 : /************************************************************************/
2156 : /* CPLStrnlen() */
2157 : /************************************************************************/
2158 :
2159 : /**
2160 : * Returns the length of a NUL terminated string by reading at most
2161 : * the specified number of bytes.
2162 : *
2163 : * The CPLStrnlen() function returns MIN(strlen(pszStr), nMaxLen).
2164 : * Only the first nMaxLen bytes of the string will be read. Usefull to
2165 : * test if a string contains at least nMaxLen characters without reading
2166 : * the full string up to the NUL terminating character.
2167 : *
2168 : * @param pszStr a NUL terminated string
2169 : * @param nMaxLen maximum number of bytes to read in pszStr
2170 : *
2171 : * @return strlen(pszStr) if the length is lesser than nMaxLen, otherwise
2172 : * nMaxLen if the NUL character has not been found in the first nMaxLen bytes.
2173 : *
2174 : * @since GDAL 1.7.0
2175 : */
2176 :
2177 2044 : size_t CPLStrnlen (const char *pszStr, size_t nMaxLen)
2178 : {
2179 2044 : size_t nLen = 0;
2180 31360 : while(nLen < nMaxLen && *pszStr != '\0')
2181 : {
2182 27272 : nLen ++;
2183 27272 : pszStr ++;
2184 : }
2185 2044 : return nLen;
2186 : }
|