1 : /**********************************************************************
2 : * $Id: cpl_string.cpp 19840 2010-06-11 13:29:45Z chaitanya $
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 19840 2010-06-11 13:29:45Z chaitanya $");
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 2999309 : char **CSLAddString(char **papszStrList, const char *pszNewString)
73 : {
74 2999309 : int nItems=0;
75 :
76 2999309 : if (pszNewString == NULL)
77 0 : return papszStrList; /* Nothing to do!*/
78 :
79 : /* Allocate room for the new string */
80 2999309 : if (papszStrList == NULL)
81 250077 : papszStrList = (char**) CPLCalloc(2,sizeof(char*));
82 : else
83 : {
84 2749232 : nItems = CSLCount(papszStrList);
85 : papszStrList = (char**)CPLRealloc(papszStrList,
86 2749232 : (nItems+2)*sizeof(char*));
87 : }
88 :
89 : /* Copy the string in the list */
90 2999309 : papszStrList[nItems] = CPLStrdup(pszNewString);
91 2999309 : papszStrList[nItems+1] = NULL;
92 :
93 2999309 : 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 5049267 : int CSLCount(char **papszStrList)
117 : {
118 5049267 : int nItems=0;
119 :
120 5049267 : if (papszStrList)
121 : {
122 71386830 : while(*papszStrList != NULL)
123 : {
124 63447382 : nItems++;
125 63447382 : papszStrList++;
126 : }
127 : }
128 :
129 5049267 : 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 62361 : const char * CSLGetField( char ** papszStrList, int iField )
143 :
144 : {
145 : int i;
146 :
147 62361 : if( papszStrList == NULL || iField < 0 )
148 7095 : return( "" );
149 :
150 394930 : for( i = 0; i < iField+1; i++ )
151 : {
152 339664 : if( papszStrList[i] == NULL )
153 0 : return "";
154 : }
155 :
156 55266 : 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 2672562 : void CPL_STDCALL CSLDestroy(char **papszStrList)
172 : {
173 : char **papszPtr;
174 :
175 2672562 : if (papszStrList)
176 : {
177 939030 : papszPtr = papszStrList;
178 5188200 : while(*papszPtr != NULL)
179 : {
180 3310140 : CPLFree(*papszPtr);
181 3310140 : papszPtr++;
182 : }
183 :
184 939030 : CPLFree(papszStrList);
185 : }
186 2672562 : }
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 16240 : char **CSLDuplicate(char **papszStrList)
204 : {
205 : char **papszNewList, **papszSrc, **papszDst;
206 : int nLines;
207 :
208 16240 : nLines = CSLCount(papszStrList);
209 :
210 16240 : if (nLines == 0)
211 2348 : return NULL;
212 :
213 13892 : papszNewList = (char **)CPLMalloc((nLines+1)*sizeof(char*));
214 13892 : papszSrc = papszStrList;
215 13892 : papszDst = papszNewList;
216 :
217 155767 : while(*papszSrc != NULL)
218 : {
219 127983 : *papszDst = CPLStrdup(*papszSrc);
220 :
221 127983 : papszSrc++;
222 127983 : papszDst++;
223 : }
224 13892 : *papszDst = NULL;
225 :
226 13892 : 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 447 : char **CSLMerge( char **papszOrig, char **papszOverride )
247 :
248 : {
249 : int i;
250 :
251 447 : if( papszOrig == NULL && papszOverride != NULL )
252 3 : return CSLDuplicate( papszOverride );
253 :
254 444 : if( papszOverride == NULL )
255 306 : return papszOrig;
256 :
257 389 : for( i = 0; papszOverride[i] != NULL; i++ )
258 : {
259 251 : char *pszKey = NULL;
260 251 : const char *pszValue = CPLParseNameValue( papszOverride[i], &pszKey );
261 :
262 251 : papszOrig = CSLSetNameValue( papszOrig, pszKey, pszValue );
263 251 : CPLFree( pszKey );
264 : }
265 :
266 138 : 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 411 : char **CSLLoad2(const char *pszFname, int nMaxLines, int nMaxCols, char** papszOptions)
294 : {
295 : FILE *fp;
296 : const char *pszLine;
297 411 : char **papszStrList=NULL;
298 411 : int nLines = 0;
299 411 : int nAllocatedLines = 0;
300 :
301 411 : fp = VSIFOpenL(pszFname, "rb");
302 :
303 411 : if (fp)
304 : {
305 411 : CPLErrorReset();
306 3850 : while(!VSIFEofL(fp) && (nMaxLines == -1 || nLines < nMaxLines))
307 : {
308 3028 : if ( (pszLine = CPLReadLine2L(fp, nMaxCols, papszOptions)) != NULL )
309 : {
310 3028 : if (nLines + 1 >= nAllocatedLines)
311 : {
312 : char** papszStrListNew;
313 450 : nAllocatedLines = 16 + nAllocatedLines * 2;
314 : papszStrListNew = (char**) VSIRealloc(papszStrList,
315 450 : nAllocatedLines * sizeof(char*));
316 450 : 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 450 : papszStrList = papszStrListNew;
326 : }
327 3028 : papszStrList[nLines] = CPLStrdup(pszLine);
328 3028 : papszStrList[nLines + 1] = NULL;
329 3028 : nLines ++;
330 : }
331 0 : else if (CPLGetLastErrorType() != 0)
332 : {
333 0 : break;
334 : }
335 : }
336 :
337 411 : VSIFCloseL(fp);
338 :
339 411 : CPLReadLineL( NULL );
340 : }
341 : else
342 : {
343 : /* Unable to open file */
344 : CPLError( CE_Failure, CPLE_OpenFailed,
345 : "CSLLoad2(\"%s\") failed: unable to open output file.",
346 0 : pszFname );
347 : }
348 :
349 411 : return papszStrList;
350 : }
351 :
352 : /************************************************************************/
353 : /* CSLLoad() */
354 : /************************************************************************/
355 :
356 : /**
357 : * Load a text file into a string list.
358 : *
359 : * The VSI*L API is used, so VSIFOpenL() supported objects that aren't
360 : * physical files can also be accessed. Files are returned as a string list,
361 : * with one item in the string list per line. End of line markers are
362 : * stripped (by CPLReadLineL()).
363 : *
364 : * If reading the file fails a CPLError() will be issued and NULL returned.
365 : *
366 : * @param pszFname the name of the file to read.
367 : *
368 : * @return a string list with the files lines, now owned by caller. To be freed with CSLDestroy()
369 : */
370 :
371 391 : char **CSLLoad(const char *pszFname)
372 : {
373 391 : return CSLLoad2(pszFname, -1, -1, NULL);
374 : }
375 :
376 : /**********************************************************************
377 : * CSLSave()
378 : *
379 : * Write a stringlist to a text file.
380 : *
381 : * Returns the number of lines written, or 0 if the file could not
382 : * be written.
383 : **********************************************************************/
384 46 : int CSLSave(char **papszStrList, const char *pszFname)
385 : {
386 : FILE *fp;
387 46 : int nLines = 0;
388 :
389 46 : if (papszStrList)
390 : {
391 46 : if ((fp = VSIFOpenL(pszFname, "wt")) != NULL)
392 : {
393 415 : while(*papszStrList != NULL)
394 : {
395 323 : if( VSIFPrintfL( fp, "%s\n", *papszStrList ) < 1 )
396 : {
397 : CPLError( CE_Failure, CPLE_FileIO,
398 : "CSLSave(\"%s\") failed: unable to write to output file.",
399 0 : pszFname );
400 0 : break; /* A Problem happened... abort */
401 : }
402 :
403 323 : nLines++;
404 323 : papszStrList++;
405 : }
406 :
407 46 : VSIFCloseL(fp);
408 : }
409 : else
410 : {
411 : /* Unable to open file */
412 : CPLError( CE_Failure, CPLE_OpenFailed,
413 : "CSLSave(\"%s\") failed: unable to open output file.",
414 0 : pszFname );
415 : }
416 : }
417 :
418 46 : return nLines;
419 : }
420 :
421 : /**********************************************************************
422 : * CSLPrint()
423 : *
424 : * Print a StringList to fpOut. If fpOut==NULL, then output is sent
425 : * to stdout.
426 : *
427 : * Returns the number of lines printed.
428 : **********************************************************************/
429 0 : int CSLPrint(char **papszStrList, FILE *fpOut)
430 : {
431 0 : int nLines=0;
432 :
433 0 : if (fpOut == NULL)
434 0 : fpOut = stdout;
435 :
436 0 : if (papszStrList)
437 : {
438 0 : while(*papszStrList != NULL)
439 : {
440 0 : VSIFPrintf(fpOut, "%s\n", *papszStrList);
441 0 : nLines++;
442 0 : papszStrList++;
443 : }
444 : }
445 :
446 0 : return nLines;
447 : }
448 :
449 :
450 : /**********************************************************************
451 : * CSLInsertStrings()
452 : *
453 : * Copies the contents of a StringList inside another StringList
454 : * before the specified line.
455 : *
456 : * nInsertAtLineNo is a 0-based line index before which the new strings
457 : * should be inserted. If this value is -1 or is larger than the actual
458 : * number of strings in the list then the strings are added at the end
459 : * of the source StringList.
460 : *
461 : * Returns the modified StringList.
462 : **********************************************************************/
463 : char **CSLInsertStrings(char **papszStrList, int nInsertAtLineNo,
464 789 : char **papszNewLines)
465 : {
466 : int i, nSrcLines, nDstLines, nToInsert;
467 : char **ppszSrc, **ppszDst;
468 :
469 789 : if (papszNewLines == NULL ||
470 : ( nToInsert = CSLCount(papszNewLines) ) == 0)
471 2 : return papszStrList; /* Nothing to do!*/
472 :
473 787 : nSrcLines = CSLCount(papszStrList);
474 787 : nDstLines = nSrcLines + nToInsert;
475 :
476 : /* Allocate room for the new strings */
477 : papszStrList = (char**)CPLRealloc(papszStrList,
478 787 : (nDstLines+1)*sizeof(char*));
479 :
480 : /* Make sure the array is NULL-terminated... it may not be if
481 : * papszStrList was NULL before Realloc()
482 : */
483 787 : papszStrList[nSrcLines] = NULL;
484 :
485 : /* Make some room in the original list at the specified location
486 : * Note that we also have to move the NULL pointer at the end of
487 : * the source StringList.
488 : */
489 787 : if (nInsertAtLineNo == -1 || nInsertAtLineNo > nSrcLines)
490 155 : nInsertAtLineNo = nSrcLines;
491 :
492 787 : ppszSrc = papszStrList + nSrcLines;
493 787 : ppszDst = papszStrList + nDstLines;
494 :
495 2754 : for (i=nSrcLines; i>=nInsertAtLineNo; i--)
496 : {
497 1967 : *ppszDst = *ppszSrc;
498 1967 : ppszDst--;
499 1967 : ppszSrc--;
500 : }
501 :
502 : /* Copy the strings to the list */
503 787 : ppszSrc = papszNewLines;
504 787 : ppszDst = papszStrList + nInsertAtLineNo;
505 :
506 15119 : for (; *ppszSrc != NULL; ppszSrc++, ppszDst++)
507 : {
508 14332 : *ppszDst = CPLStrdup(*ppszSrc);
509 : }
510 :
511 787 : return papszStrList;
512 : }
513 :
514 : /**********************************************************************
515 : * CSLInsertString()
516 : *
517 : * Insert a string at a given line number inside a StringList
518 : *
519 : * nInsertAtLineNo is a 0-based line index before which the new string
520 : * should be inserted. If this value is -1 or is larger than the actual
521 : * number of strings in the list then the string is added at the end
522 : * of the source StringList.
523 : *
524 : * Returns the modified StringList.
525 : **********************************************************************/
526 : char **CSLInsertString(char **papszStrList, int nInsertAtLineNo,
527 104 : const char *pszNewLine)
528 : {
529 : char *apszList[2];
530 :
531 : /* Create a temporary StringList and call CSLInsertStrings()
532 : */
533 104 : apszList[0] = (char *) pszNewLine;
534 104 : apszList[1] = NULL;
535 :
536 104 : return CSLInsertStrings(papszStrList, nInsertAtLineNo, apszList);
537 : }
538 :
539 :
540 : /**********************************************************************
541 : * CSLRemoveStrings()
542 : *
543 : * Remove strings inside a StringList
544 : *
545 : * nFirstLineToDelete is the 0-based line index of the first line to
546 : * remove. If this value is -1 or is larger than the actual
547 : * number of strings in list then the nNumToRemove last strings are
548 : * removed.
549 : *
550 : * If ppapszRetStrings != NULL then the deleted strings won't be
551 : * free'd, they will be stored in a new StringList and the pointer to
552 : * this new list will be returned in *ppapszRetStrings.
553 : *
554 : * Returns the modified StringList.
555 : **********************************************************************/
556 : char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete,
557 25 : int nNumToRemove, char ***ppapszRetStrings)
558 : {
559 : int i, nSrcLines, nDstLines;
560 : char **ppszSrc, **ppszDst;
561 :
562 25 : nSrcLines = CSLCount(papszStrList);
563 25 : nDstLines = nSrcLines - nNumToRemove;
564 :
565 25 : if (nNumToRemove < 1 || nSrcLines == 0)
566 0 : return papszStrList; /* Nothing to do!*/
567 :
568 : /* If operation will result in an empty StringList then don't waste
569 : * time here!
570 : */
571 25 : if (nDstLines < 1)
572 : {
573 18 : CSLDestroy(papszStrList);
574 18 : return NULL;
575 : }
576 :
577 :
578 : /* Remove lines from the source StringList...
579 : * Either free() each line or store them to a new StringList depending on
580 : * the caller's choice.
581 : */
582 7 : ppszDst = papszStrList + nFirstLineToDelete;
583 :
584 7 : if (ppapszRetStrings == NULL)
585 : {
586 : /* free() all the strings that will be removed.
587 : */
588 14 : for (i=0; i < nNumToRemove; i++)
589 : {
590 7 : CPLFree(*ppszDst);
591 7 : *ppszDst = NULL;
592 : }
593 : }
594 : else
595 : {
596 : /* Store the strings to remove in a new StringList
597 : */
598 0 : *ppapszRetStrings = (char **)CPLCalloc(nNumToRemove+1, sizeof(char*));
599 :
600 0 : for (i=0; i < nNumToRemove; i++)
601 : {
602 0 : (*ppapszRetStrings)[i] = *ppszDst;
603 0 : *ppszDst = NULL;
604 0 : ppszDst++;
605 : }
606 : }
607 :
608 :
609 : /* Shift down all the lines that follow the lines to remove.
610 : */
611 7 : if (nFirstLineToDelete == -1 || nFirstLineToDelete > nSrcLines)
612 0 : nFirstLineToDelete = nDstLines;
613 :
614 7 : ppszSrc = papszStrList + nFirstLineToDelete + nNumToRemove;
615 7 : ppszDst = papszStrList + nFirstLineToDelete;
616 :
617 8 : for ( ; *ppszSrc != NULL; ppszSrc++, ppszDst++)
618 : {
619 1 : *ppszDst = *ppszSrc;
620 : }
621 : /* Move the NULL pointer at the end of the StringList */
622 7 : *ppszDst = *ppszSrc;
623 :
624 : /* At this point, we could realloc() papszStrList to a smaller size, but
625 : * since this array will likely grow again in further operations on the
626 : * StringList we'll leave it as it is.
627 : */
628 :
629 7 : return papszStrList;
630 : }
631 :
632 : /************************************************************************/
633 : /* CSLFindString() */
634 : /************************************************************************/
635 :
636 : /**
637 : * Find a string within a string list.
638 : *
639 : * Returns the index of the entry in the string list that contains the
640 : * target string. The string in the string list must be a full match for
641 : * the target, but the search is case insensitive.
642 : *
643 : * @param papszList the string list to be searched.
644 : * @param pszTarget the string to be searched for.
645 : *
646 : * @return the index of the string within the list or -1 on failure.
647 : */
648 :
649 906905 : int CSLFindString( char ** papszList, const char * pszTarget )
650 :
651 : {
652 : int i;
653 :
654 906905 : if( papszList == NULL )
655 72779 : return -1;
656 :
657 2233736 : for( i = 0; papszList[i] != NULL; i++ )
658 : {
659 1715196 : if( EQUAL(papszList[i],pszTarget) )
660 315586 : return i;
661 : }
662 :
663 518540 : return -1;
664 : }
665 :
666 : /************************************************************************/
667 : /* CSLPartialFindString() */
668 : /************************************************************************/
669 :
670 : /**
671 : * Find a substring within a string list.
672 : *
673 : * Returns the index of the entry in the string list that contains the
674 : * target string as a substring. The search is case sensitive (unlike
675 : * CSLFindString()).
676 : *
677 : * @param papszHaystack the string list to be searched.
678 : * @param pszNeedle the substring to be searched for.
679 : *
680 : * @return the index of the string within the list or -1 on failure.
681 : */
682 :
683 0 : int CSLPartialFindString( char **papszHaystack, const char * pszNeedle )
684 : {
685 : int i;
686 0 : if (papszHaystack == NULL || pszNeedle == NULL)
687 0 : return -1;
688 :
689 0 : for (i = 0; papszHaystack[i] != NULL; i++)
690 : {
691 0 : if (strstr(papszHaystack[i],pszNeedle))
692 0 : return i;
693 : }
694 :
695 0 : return -1;
696 : }
697 :
698 :
699 : /**********************************************************************
700 : * CSLTokenizeString()
701 : *
702 : * Tokenizes a string and returns a StringList with one string for
703 : * each token.
704 : **********************************************************************/
705 3350 : char **CSLTokenizeString( const char *pszString )
706 : {
707 3350 : return CSLTokenizeString2( pszString, " ", CSLT_HONOURSTRINGS );
708 : }
709 :
710 : /************************************************************************/
711 : /* CSLTokenizeStringComplex() */
712 : /* */
713 : /* Obsolete tokenizing api. */
714 : /************************************************************************/
715 :
716 : char ** CSLTokenizeStringComplex( const char * pszString,
717 : const char * pszDelimiters,
718 334774 : int bHonourStrings, int bAllowEmptyTokens )
719 :
720 : {
721 334774 : int nFlags = 0;
722 :
723 334774 : if( bHonourStrings )
724 320783 : nFlags |= CSLT_HONOURSTRINGS;
725 334774 : if( bAllowEmptyTokens )
726 451 : nFlags |= CSLT_ALLOWEMPTYTOKENS;
727 :
728 334774 : return CSLTokenizeString2( pszString, pszDelimiters, nFlags );
729 : }
730 :
731 : /************************************************************************/
732 : /* CSLTokenizeString2() */
733 : /************************************************************************/
734 :
735 : /**
736 : * Tokenize a string.
737 : *
738 : * This function will split a string into tokens based on specified'
739 : * delimeter(s) with a variety of options. The returned result is a
740 : * string list that should be freed with CSLDestroy() when no longer
741 : * needed.
742 : *
743 : * The available parsing options are:
744 : *
745 : * - CSLT_ALLOWEMPTYTOKENS: allow the return of empty tokens when two
746 : * delimiters in a row occur with no other text between them. If not set,
747 : * empty tokens will be discarded;
748 : * - CSLT_STRIPLEADSPACES: strip leading space characters from the token (as
749 : * reported by isspace());
750 : * - CSLT_STRIPENDSPACES: strip ending space characters from the token (as
751 : * reported by isspace());
752 : * - CSLT_HONOURSTRINGS: double quotes can be used to hold values that should
753 : * not be broken into multiple tokens;
754 : * - CSLT_PRESERVEQUOTES: string quotes are carried into the tokens when this
755 : * is set, otherwise they are removed;
756 : * - CSLT_PRESERVEESCAPES: if set backslash escapes (for backslash itself,
757 : * and for literal double quotes) will be preserved in the tokens, otherwise
758 : * the backslashes will be removed in processing.
759 : *
760 : * \b Example:
761 : *
762 : * Parse a string into tokens based on various white space (space, newline,
763 : * tab) and then print out results and cleanup. Quotes may be used to hold
764 : * white space in tokens.
765 :
766 : \code
767 : char **papszTokens;
768 : int i;
769 :
770 : papszTokens =
771 : CSLTokenizeString2( pszCommand, " \t\n",
772 : CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS );
773 :
774 : for( i = 0; papszTokens != NULL && papszTokens[i] != NULL; i++ )
775 : printf( "arg %d: '%s'", papszTokens[i] );
776 : CSLDestroy( papszTokens );
777 : \endcode
778 :
779 : * @param pszString the string to be split into tokens.
780 : * @param pszDelimiters one or more characters to be used as token delimeters.
781 : * @param nCSLTFlags an ORing of one or more of the CSLT_ flag values.
782 : *
783 : * @return a string list of tokens owned by the caller.
784 : */
785 :
786 : char ** CSLTokenizeString2( const char * pszString,
787 : const char * pszDelimiters,
788 339298 : int nCSLTFlags )
789 :
790 : {
791 339298 : if( pszString == NULL )
792 0 : return (char **) CPLCalloc(sizeof(char *),1);
793 339298 : char **papszRetList = NULL;
794 339298 : int nRetMax = 0, nRetLen = 0;
795 : char *pszToken;
796 : int nTokenMax, nTokenLen;
797 339298 : int bHonourStrings = (nCSLTFlags & CSLT_HONOURSTRINGS);
798 339298 : int bAllowEmptyTokens = (nCSLTFlags & CSLT_ALLOWEMPTYTOKENS);
799 339298 : int bStripLeadSpaces = (nCSLTFlags & CSLT_STRIPLEADSPACES);
800 339298 : int bStripEndSpaces = (nCSLTFlags & CSLT_STRIPENDSPACES);
801 :
802 339298 : pszToken = (char *) CPLCalloc(10,1);
803 339298 : nTokenMax = 10;
804 :
805 1124134 : while( pszString != NULL && *pszString != '\0' )
806 : {
807 445538 : int bInString = FALSE;
808 445538 : int bStartString = TRUE;
809 :
810 445538 : nTokenLen = 0;
811 :
812 : /* Try to find the next delimeter, marking end of token */
813 3014634 : for( ; *pszString != '\0'; pszString++ )
814 : {
815 :
816 : /* End if this is a delimeter skip it and break. */
817 2679944 : if( !bInString && strchr(pszDelimiters, *pszString) != NULL )
818 : {
819 110848 : pszString++;
820 110848 : 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 2569096 : if( bHonourStrings && *pszString == '"' )
827 : {
828 840 : if( nCSLTFlags & CSLT_PRESERVEQUOTES )
829 : {
830 8 : pszToken[nTokenLen] = *pszString;
831 8 : nTokenLen++;
832 : }
833 :
834 840 : if( bInString )
835 : {
836 395 : bInString = FALSE;
837 395 : continue;
838 : }
839 : else
840 : {
841 445 : bInString = TRUE;
842 445 : 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 2568256 : 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 2568256 : if ( !bInString && bStripLeadSpaces
869 : && bStartString && isspace((unsigned char)*pszString) )
870 0 : continue;
871 :
872 2568256 : bStartString = FALSE;
873 :
874 : /*
875 : * Extend token buffer if we are running close to its end.
876 : */
877 2568256 : if( nTokenLen >= nTokenMax-3 )
878 : {
879 51697 : nTokenMax = nTokenMax * 2 + 10;
880 51697 : pszToken = (char *) CPLRealloc( pszToken, nTokenMax );
881 : }
882 :
883 2568256 : pszToken[nTokenLen] = *pszString;
884 2568256 : nTokenLen++;
885 : }
886 :
887 : /*
888 : * Strip spaces at the token end if requested.
889 : */
890 445538 : if ( !bInString && bStripEndSpaces )
891 : {
892 12 : while ( nTokenLen && isspace((unsigned char)pszToken[nTokenLen - 1]) )
893 0 : nTokenLen--;
894 : }
895 :
896 445538 : pszToken[nTokenLen] = '\0';
897 :
898 : /*
899 : * Add the token.
900 : */
901 445538 : if( pszToken[0] != '\0' || bAllowEmptyTokens )
902 : {
903 414470 : if( nRetLen >= nRetMax - 1 )
904 : {
905 336963 : nRetMax = nRetMax * 2 + 10;
906 : papszRetList = (char **)
907 336963 : CPLRealloc(papszRetList, sizeof(char*) * nRetMax );
908 : }
909 :
910 414470 : papszRetList[nRetLen++] = CPLStrdup( pszToken );
911 414470 : papszRetList[nRetLen] = NULL;
912 : }
913 : }
914 :
915 : /*
916 : * If the last token was empty, then we need to capture
917 : * it now, as the loop would skip it.
918 : */
919 339298 : if( *pszString == '\0' && bAllowEmptyTokens && nRetLen > 0
920 : && strchr(pszDelimiters,*(pszString-1)) != NULL )
921 : {
922 8 : if( nRetLen >= nRetMax - 1 )
923 : {
924 0 : nRetMax = nRetMax * 2 + 10;
925 : papszRetList = (char **)
926 0 : CPLRealloc(papszRetList, sizeof(char*) * nRetMax );
927 : }
928 :
929 8 : papszRetList[nRetLen++] = CPLStrdup("");
930 8 : papszRetList[nRetLen] = NULL;
931 : }
932 :
933 339298 : if( papszRetList == NULL )
934 3431 : papszRetList = (char **) CPLCalloc(sizeof(char *),1);
935 :
936 339298 : CPLFree( pszToken );
937 :
938 339298 : return papszRetList;
939 : }
940 :
941 : /**********************************************************************
942 : * CPLSPrintf()
943 : *
944 : * My own version of CPLSPrintf() that works with 10 static buffer.
945 : *
946 : * It returns a ref. to a static buffer that should not be freed and
947 : * is valid only until the next call to CPLSPrintf().
948 : *
949 : * NOTE: This function should move to cpl_conv.cpp.
950 : **********************************************************************/
951 : /* For now, assume that a 8000 chars buffer will be enough.
952 : */
953 : #define CPLSPrintf_BUF_SIZE 8000
954 : #define CPLSPrintf_BUF_Count 10
955 :
956 24865 : const char *CPLSPrintf(const char *fmt, ...)
957 : {
958 : va_list args;
959 :
960 : /* -------------------------------------------------------------------- */
961 : /* Get the thread local buffer ring data. */
962 : /* -------------------------------------------------------------------- */
963 24865 : char *pachBufRingInfo = (char *) CPLGetTLS( CTLS_CPLSPRINTF );
964 :
965 24865 : if( pachBufRingInfo == NULL )
966 : {
967 : pachBufRingInfo = (char *)
968 28 : CPLCalloc(1,sizeof(int)+CPLSPrintf_BUF_Count*CPLSPrintf_BUF_SIZE);
969 28 : CPLSetTLS( CTLS_CPLSPRINTF, pachBufRingInfo, TRUE );
970 : }
971 :
972 : /* -------------------------------------------------------------------- */
973 : /* Work out which string in the "ring" we want to use this */
974 : /* time. */
975 : /* -------------------------------------------------------------------- */
976 24865 : int *pnBufIndex = (int *) pachBufRingInfo;
977 24865 : int nOffset = sizeof(int) + *pnBufIndex * CPLSPrintf_BUF_SIZE;
978 24865 : char *pachBuffer = pachBufRingInfo + nOffset;
979 :
980 24865 : *pnBufIndex = (*pnBufIndex + 1) % CPLSPrintf_BUF_Count;
981 :
982 : /* -------------------------------------------------------------------- */
983 : /* Format the result. */
984 : /* -------------------------------------------------------------------- */
985 :
986 24865 : va_start(args, fmt);
987 : #if defined(HAVE_VSNPRINTF)
988 24865 : vsnprintf(pachBuffer, CPLSPrintf_BUF_SIZE-1, fmt, args);
989 : #else
990 : vsprintf(pachBuffer, fmt, args);
991 : #endif
992 24865 : va_end(args);
993 :
994 24865 : return pachBuffer;
995 : }
996 :
997 : /**********************************************************************
998 : * CSLAppendPrintf()
999 : *
1000 : * Use CPLSPrintf() to append a new line at the end of a StringList.
1001 : *
1002 : * Returns the modified StringList.
1003 : **********************************************************************/
1004 0 : char **CSLAppendPrintf(char **papszStrList, const char *fmt, ...)
1005 : {
1006 0 : CPLString osWork;
1007 : va_list args;
1008 :
1009 0 : va_start( args, fmt );
1010 0 : osWork.vPrintf( fmt, args );
1011 0 : va_end( args );
1012 :
1013 0 : return CSLAddString(papszStrList, osWork);
1014 : }
1015 :
1016 : /************************************************************************/
1017 : /* CPLVASPrintf() */
1018 : /* */
1019 : /* This is intended to serve as an easy to use C callabable */
1020 : /* vasprintf() alternative. Used in the geojson library for */
1021 : /* instance. */
1022 : /************************************************************************/
1023 :
1024 1363 : int CPLVASPrintf( char **buf, const char *fmt, va_list ap )
1025 :
1026 : {
1027 1363 : CPLString osWork;
1028 :
1029 1363 : osWork.vPrintf( fmt, ap );
1030 :
1031 1363 : if( buf )
1032 1363 : *buf = strdup(osWork.c_str());
1033 :
1034 1363 : return strlen(osWork);
1035 : }
1036 :
1037 : /************************************************************************/
1038 : /* CSLTestBoolean() */
1039 : /************************************************************************/
1040 :
1041 : /**
1042 : * Test what boolean value contained in the string.
1043 : *
1044 : * If pszValue is "NO", "FALSE", "OFF" or "0" will be returned FALSE.
1045 : * Otherwise, TRUE will be returned.
1046 : *
1047 : * @param pszValue the string should be tested.
1048 : *
1049 : * @return TRUE or FALSE.
1050 : */
1051 :
1052 664608 : int CSLTestBoolean( const char *pszValue )
1053 : {
1054 664608 : if( EQUAL(pszValue,"NO")
1055 : || EQUAL(pszValue,"FALSE")
1056 : || EQUAL(pszValue,"OFF")
1057 : || EQUAL(pszValue,"0") )
1058 648006 : return FALSE;
1059 : else
1060 16602 : return TRUE;
1061 : }
1062 :
1063 : /**********************************************************************
1064 : * CSLFetchBoolean()
1065 : *
1066 : * Check for boolean key value.
1067 : *
1068 : * In a StringList of "Name=Value" pairs, look to see if there is a key
1069 : * with the given name, and if it can be interpreted as being TRUE. If
1070 : * the key appears without any "=Value" portion it will be considered true.
1071 : * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
1072 : * if the key appears in the list it will be considered TRUE. If the key
1073 : * doesn't appear at all, the indicated default value will be returned.
1074 : *
1075 : * @param papszStrList the string list to search.
1076 : * @param pszKey the key value to look for (case insensitive).
1077 : * @param bDefault the value to return if the key isn't found at all.
1078 : *
1079 : * @return TRUE or FALSE
1080 : **********************************************************************/
1081 :
1082 6581 : int CSLFetchBoolean( char **papszStrList, const char *pszKey, int bDefault )
1083 :
1084 : {
1085 : const char *pszValue;
1086 :
1087 6581 : if( CSLFindString( papszStrList, pszKey ) != -1 )
1088 0 : return TRUE;
1089 :
1090 6581 : pszValue = CSLFetchNameValue(papszStrList, pszKey );
1091 6581 : if( pszValue == NULL )
1092 6376 : return bDefault;
1093 : else
1094 205 : return CSLTestBoolean( pszValue );
1095 : }
1096 :
1097 : /************************************************************************/
1098 : /* CSLFetchNameValueDefaulted() */
1099 : /************************************************************************/
1100 :
1101 : const char *CSLFetchNameValueDef( char **papszStrList,
1102 : const char *pszName,
1103 300 : const char *pszDefault )
1104 :
1105 : {
1106 300 : const char *pszResult = CSLFetchNameValue( papszStrList, pszName );
1107 300 : if( pszResult )
1108 22 : return pszResult;
1109 : else
1110 278 : return pszDefault;
1111 : }
1112 :
1113 : /**********************************************************************
1114 : * CSLFetchNameValue()
1115 : *
1116 : * In a StringList of "Name=Value" pairs, look for the
1117 : * first value associated with the specified name. The search is not
1118 : * case sensitive.
1119 : * ("Name:Value" pairs are also supported for backward compatibility
1120 : * with older stuff.)
1121 : *
1122 : * Returns a reference to the value in the StringList that the caller
1123 : * should not attempt to free.
1124 : *
1125 : * Returns NULL if the name is not found.
1126 : **********************************************************************/
1127 881894 : const char *CSLFetchNameValue(char **papszStrList, const char *pszName)
1128 : {
1129 : size_t nLen;
1130 :
1131 881894 : if (papszStrList == NULL || pszName == NULL)
1132 49304 : return NULL;
1133 :
1134 832590 : nLen = strlen(pszName);
1135 6679814 : while(*papszStrList != NULL)
1136 : {
1137 5282024 : if (EQUALN(*papszStrList, pszName, nLen)
1138 : && ( (*papszStrList)[nLen] == '=' ||
1139 : (*papszStrList)[nLen] == ':' ) )
1140 : {
1141 267390 : return (*papszStrList)+nLen+1;
1142 : }
1143 5014634 : papszStrList++;
1144 : }
1145 565200 : return NULL;
1146 : }
1147 :
1148 : /************************************************************************/
1149 : /* CSLFindName() */
1150 : /************************************************************************/
1151 :
1152 : /**
1153 : * Find StringList entry with given key name.
1154 : *
1155 : * @param papszStrList the string list to search.
1156 : * @param pszName the key value to look for (case insensitive).
1157 : *
1158 : * @return -1 on failure or the list index of the first occurance
1159 : * matching the given key.
1160 : */
1161 :
1162 70 : int CSLFindName(char **papszStrList, const char *pszName)
1163 : {
1164 : size_t nLen;
1165 70 : int iIndex = 0;
1166 :
1167 70 : if (papszStrList == NULL || pszName == NULL)
1168 27 : return -1;
1169 :
1170 43 : nLen = strlen(pszName);
1171 121 : while(*papszStrList != NULL)
1172 : {
1173 44 : if (EQUALN(*papszStrList, pszName, nLen)
1174 : && ( (*papszStrList)[nLen] == '=' ||
1175 : (*papszStrList)[nLen] == ':' ) )
1176 : {
1177 9 : return iIndex;
1178 : }
1179 35 : iIndex++;
1180 35 : papszStrList++;
1181 : }
1182 34 : return -1;
1183 : }
1184 :
1185 : /**********************************************************************
1186 : * CPLParseNameValue()
1187 : **********************************************************************/
1188 :
1189 : /**
1190 : * Parse NAME=VALUE string into name and value components.
1191 : *
1192 : * Note that if ppszKey is non-NULL, the key (or name) portion will be
1193 : * allocated using VSIMalloc(), and returned in that pointer. It is the
1194 : * applications responsibility to free this string, but the application should
1195 : * not modify or free the returned value portion.
1196 : *
1197 : * This function also support "NAME:VALUE" strings and will strip white
1198 : * space from around the delimeter when forming name and value strings.
1199 : *
1200 : * Eventually CSLFetchNameValue() and friends may be modified to use
1201 : * CPLParseNameValue().
1202 : *
1203 : * @param pszNameValue string in "NAME=VALUE" format.
1204 : * @param ppszKey optional pointer though which to return the name
1205 : * portion.
1206 : * @return the value portion (pointing into original string).
1207 : */
1208 :
1209 7746 : const char *CPLParseNameValue(const char *pszNameValue, char **ppszKey )
1210 :
1211 : {
1212 : int i;
1213 : const char *pszValue;
1214 :
1215 99618 : for( i = 0; pszNameValue[i] != '\0'; i++ )
1216 : {
1217 99597 : if( pszNameValue[i] == '=' || pszNameValue[i] == ':' )
1218 : {
1219 7725 : pszValue = pszNameValue + i + 1;
1220 16302 : while( *pszValue == ' ' || *pszValue == '\t' )
1221 852 : pszValue++;
1222 :
1223 7725 : if( ppszKey != NULL )
1224 : {
1225 7716 : *ppszKey = (char *) CPLMalloc(i+1);
1226 7716 : strncpy( *ppszKey, pszNameValue, i );
1227 7716 : (*ppszKey)[i] = '\0';
1228 15432 : while( i > 0 &&
1229 : ( (*ppszKey)[i] == ' ' || (*ppszKey)[i] == '\t') )
1230 : {
1231 0 : (*ppszKey)[i] = '\0';
1232 0 : i--;
1233 : }
1234 : }
1235 :
1236 7725 : return pszValue;
1237 : }
1238 : }
1239 :
1240 21 : return NULL;
1241 : }
1242 :
1243 : /**********************************************************************
1244 : * CSLFetchNameValueMultiple()
1245 : *
1246 : * In a StringList of "Name=Value" pairs, look for all the
1247 : * values with the specified name. The search is not case
1248 : * sensitive.
1249 : * ("Name:Value" pairs are also supported for backward compatibility
1250 : * with older stuff.)
1251 : *
1252 : * Returns stringlist with one entry for each occurence of the
1253 : * specified name. The stringlist should eventually be destroyed
1254 : * by calling CSLDestroy().
1255 : *
1256 : * Returns NULL if the name is not found.
1257 : **********************************************************************/
1258 398 : char **CSLFetchNameValueMultiple(char **papszStrList, const char *pszName)
1259 : {
1260 : size_t nLen;
1261 398 : char **papszValues = NULL;
1262 :
1263 398 : if (papszStrList == NULL || pszName == NULL)
1264 302 : return NULL;
1265 :
1266 96 : nLen = strlen(pszName);
1267 380 : while(*papszStrList != NULL)
1268 : {
1269 188 : if (EQUALN(*papszStrList, pszName, nLen)
1270 : && ( (*papszStrList)[nLen] == '=' ||
1271 : (*papszStrList)[nLen] == ':' ) )
1272 : {
1273 : papszValues = CSLAddString(papszValues,
1274 22 : (*papszStrList)+nLen+1);
1275 : }
1276 188 : papszStrList++;
1277 : }
1278 :
1279 96 : return papszValues;
1280 : }
1281 :
1282 :
1283 : /**********************************************************************
1284 : * CSLAddNameValue()
1285 : *
1286 : * Add a new entry to a StringList of "Name=Value" pairs,
1287 : * ("Name:Value" pairs are also supported for backward compatibility
1288 : * with older stuff.)
1289 : *
1290 : * This function does not check if a "Name=Value" pair already exists
1291 : * for that name and can generate multiple entryes for the same name.
1292 : * Use CSLSetNameValue() if you want each name to have only one value.
1293 : *
1294 : * Returns the modified stringlist.
1295 : **********************************************************************/
1296 : char **CSLAddNameValue(char **papszStrList,
1297 336909 : const char *pszName, const char *pszValue)
1298 : {
1299 : char *pszLine;
1300 :
1301 336909 : if (pszName == NULL || pszValue==NULL)
1302 0 : return papszStrList;
1303 :
1304 336909 : pszLine = (char *) CPLMalloc(strlen(pszName)+strlen(pszValue)+2);
1305 336909 : sprintf( pszLine, "%s=%s", pszName, pszValue );
1306 336909 : papszStrList = CSLAddString(papszStrList, pszLine);
1307 336909 : CPLFree( pszLine );
1308 :
1309 336909 : return papszStrList;
1310 : }
1311 :
1312 : /************************************************************************/
1313 : /* CSLSetNameValue() */
1314 : /************************************************************************/
1315 :
1316 : /**
1317 : * Assign value to name in StringList.
1318 : *
1319 : * Set the value for a given name in a StringList of "Name=Value" pairs
1320 : * ("Name:Value" pairs are also supported for backward compatibility
1321 : * with older stuff.)
1322 : *
1323 : * If there is already a value for that name in the list then the value
1324 : * is changed, otherwise a new "Name=Value" pair is added.
1325 : *
1326 : * @param papszList the original list, the modified version is returned.
1327 : * @param pszName the name to be assigned a value. This should be a well
1328 : * formed token (no spaces or very special characters).
1329 : * @param pszValue the value to assign to the name. This should not contain
1330 : * any newlines (CR or LF) but is otherwise pretty much unconstrained. If
1331 : * NULL any corresponding value will be removed.
1332 : *
1333 : * @return modified stringlist.
1334 : */
1335 :
1336 : char **CSLSetNameValue(char **papszList,
1337 331192 : const char *pszName, const char *pszValue)
1338 : {
1339 : char **papszPtr;
1340 : size_t nLen;
1341 :
1342 331192 : if (pszName == NULL )
1343 6 : return papszList;
1344 :
1345 331186 : nLen = strlen(pszName);
1346 331186 : papszPtr = papszList;
1347 7217514 : while(papszPtr && *papszPtr != NULL)
1348 : {
1349 6557005 : if (EQUALN(*papszPtr, pszName, nLen)
1350 : && ( (*papszPtr)[nLen] == '=' ||
1351 : (*papszPtr)[nLen] == ':' ) )
1352 : {
1353 : /* Found it!
1354 : * Change the value... make sure to keep the ':' or '='
1355 : */
1356 : char cSep;
1357 1863 : cSep = (*papszPtr)[nLen];
1358 :
1359 1863 : CPLFree(*papszPtr);
1360 :
1361 : /*
1362 : * If the value is NULL, remove this entry completely/
1363 : */
1364 1863 : if( pszValue == NULL )
1365 : {
1366 36 : while( papszPtr[1] != NULL )
1367 : {
1368 4 : *papszPtr = papszPtr[1];
1369 4 : papszPtr++;
1370 : }
1371 16 : *papszPtr = NULL;
1372 : }
1373 :
1374 : /*
1375 : * Otherwise replace with new value.
1376 : */
1377 : else
1378 : {
1379 1847 : *papszPtr = (char *) CPLMalloc(strlen(pszName)+strlen(pszValue)+2);
1380 1847 : sprintf( *papszPtr, "%s%c%s", pszName, cSep, pszValue );
1381 : }
1382 1863 : return papszList;
1383 : }
1384 6555142 : papszPtr++;
1385 : }
1386 :
1387 329323 : if( pszValue == NULL )
1388 0 : return papszList;
1389 :
1390 : /* The name does not exist yet... create a new entry
1391 : */
1392 329323 : return CSLAddNameValue(papszList, pszName, pszValue);
1393 : }
1394 :
1395 : /************************************************************************/
1396 : /* CSLSetNameValueSeparator() */
1397 : /************************************************************************/
1398 :
1399 : /**
1400 : * Replace the default separator (":" or "=") with the passed separator
1401 : * in the given name/value list.
1402 : *
1403 : * Note that if a separator other than ":" or "=" is used, the resulting
1404 : * list will not be manipulatable by the CSL name/value functions any more.
1405 : *
1406 : * The CPLParseNameValue() function is used to break the existing lines,
1407 : * and it also strips white space from around the existing delimiter, thus
1408 : * the old separator, and any white space will be replaced by the new
1409 : * separator. For formatting purposes it may be desireable to include some
1410 : * white space in the new separator. eg. ": " or " = ".
1411 : *
1412 : * @param papszList the list to update. Component strings may be freed
1413 : * but the list array will remain at the same location.
1414 : *
1415 : * @param pszSeparator the new separator string to insert.
1416 : *
1417 : */
1418 :
1419 53 : void CSLSetNameValueSeparator( char ** papszList, const char *pszSeparator )
1420 :
1421 : {
1422 53 : int nLines = CSLCount(papszList), iLine;
1423 :
1424 1054 : for( iLine = 0; iLine < nLines; iLine++ )
1425 : {
1426 1001 : char *pszKey = NULL;
1427 : const char *pszValue;
1428 : char *pszNewLine;
1429 :
1430 1001 : pszValue = CPLParseNameValue( papszList[iLine], &pszKey );
1431 1001 : if( pszValue == NULL || pszKey == NULL )
1432 0 : continue;
1433 :
1434 : pszNewLine = (char *) CPLMalloc( strlen(pszValue) + strlen(pszKey)
1435 1001 : + strlen(pszSeparator) + 1 );
1436 1001 : strcpy( pszNewLine, pszKey );
1437 1001 : strcat( pszNewLine, pszSeparator );
1438 1001 : strcat( pszNewLine, pszValue );
1439 1001 : CPLFree( papszList[iLine] );
1440 1001 : papszList[iLine] = pszNewLine;
1441 1001 : CPLFree( pszKey );
1442 : }
1443 53 : }
1444 :
1445 : /************************************************************************/
1446 : /* CPLEscapeString() */
1447 : /************************************************************************/
1448 :
1449 : /**
1450 : * Apply escaping to string to preserve special characters.
1451 : *
1452 : * This function will "escape" a variety of special characters
1453 : * to make the string suitable to embed within a string constant
1454 : * or to write within a text stream but in a form that can be
1455 : * reconstitued to it's original form. The escaping will even preserve
1456 : * zero bytes allowing preservation of raw binary data.
1457 : *
1458 : * CPLES_BackslashQuotable(0): This scheme turns a binary string into
1459 : * a form suitable to be placed within double quotes as a string constant.
1460 : * The backslash, quote, '\\0' and newline characters are all escaped in
1461 : * the usual C style.
1462 : *
1463 : * CPLES_XML(1): This scheme converts the '<', '<' and '&' characters into
1464 : * their XML/HTML equivelent (>, < and &) making a string safe
1465 : * to embed as CDATA within an XML element. The '\\0' is not escaped and
1466 : * should not be included in the input.
1467 : *
1468 : * CPLES_URL(2): Everything except alphanumerics and the underscore are
1469 : * converted to a percent followed by a two digit hex encoding of the character
1470 : * (leading zero supplied if needed). This is the mechanism used for encoding
1471 : * values to be passed in URLs.
1472 : *
1473 : * CPLES_SQL(3): All single quotes are replaced with two single quotes.
1474 : * Suitable for use when constructing literal values for SQL commands where
1475 : * the literal will be enclosed in single quotes.
1476 : *
1477 : * CPLES_CSV(4): If the values contains commas, semicolons, tabs, double quotes, or newlines it
1478 : * placed in double quotes, and double quotes in the value are doubled.
1479 : * Suitable for use when constructing field values for .csv files. Note that
1480 : * CPLUnescapeString() currently does not support this format, only
1481 : * CPLEscapeString(). See cpl_csv.cpp for csv parsing support.
1482 : *
1483 : * @param pszInput the string to escape.
1484 : * @param nLength The number of bytes of data to preserve. If this is -1
1485 : * the strlen(pszString) function will be used to compute the length.
1486 : * @param nScheme the encoding scheme to use.
1487 : *
1488 : * @return an escaped, zero terminated string that should be freed with
1489 : * CPLFree() when no longer needed.
1490 : */
1491 :
1492 : char *CPLEscapeString( const char *pszInput, int nLength,
1493 13857 : int nScheme )
1494 :
1495 : {
1496 : char *pszOutput;
1497 : char *pszShortOutput;
1498 :
1499 13857 : if( nLength == -1 )
1500 13826 : nLength = strlen(pszInput);
1501 :
1502 13857 : pszOutput = (char *) CPLMalloc( nLength * 6 + 1 );
1503 :
1504 13857 : if( nScheme == CPLES_BackslashQuotable )
1505 : {
1506 24 : int iOut = 0, iIn;
1507 :
1508 1055878 : for( iIn = 0; iIn < nLength; iIn++ )
1509 : {
1510 1055854 : if( pszInput[iIn] == '\0' )
1511 : {
1512 351418 : pszOutput[iOut++] = '\\';
1513 351418 : pszOutput[iOut++] = '0';
1514 : }
1515 704436 : else if( pszInput[iIn] == '\n' )
1516 : {
1517 216 : pszOutput[iOut++] = '\\';
1518 216 : pszOutput[iOut++] = 'n';
1519 : }
1520 704220 : else if( pszInput[iIn] == '"' )
1521 : {
1522 1807 : pszOutput[iOut++] = '\\';
1523 1807 : pszOutput[iOut++] = '\"';
1524 : }
1525 702413 : else if( pszInput[iIn] == '\\' )
1526 : {
1527 2515 : pszOutput[iOut++] = '\\';
1528 2515 : pszOutput[iOut++] = '\\';
1529 : }
1530 : else
1531 699898 : pszOutput[iOut++] = pszInput[iIn];
1532 : }
1533 24 : pszOutput[iOut] = '\0';
1534 : }
1535 13833 : else if( nScheme == CPLES_URL ) /* Untested at implementation */
1536 : {
1537 0 : int iOut = 0, iIn;
1538 :
1539 0 : for( iIn = 0; iIn < nLength; iIn++ )
1540 : {
1541 0 : if( (pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z')
1542 : || (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z')
1543 : || (pszInput[iIn] >= '0' && pszInput[iIn] <= '9')
1544 : || pszInput[iIn] == '_' )
1545 : {
1546 0 : pszOutput[iOut++] = pszInput[iIn];
1547 : }
1548 : else
1549 : {
1550 0 : sprintf( pszOutput+iOut, "%%%02X", pszInput[iIn] );
1551 0 : iOut += 3;
1552 : }
1553 : }
1554 0 : pszOutput[iOut] = '\0';
1555 : }
1556 13833 : else if( nScheme == CPLES_XML )
1557 : {
1558 13748 : int iOut = 0, iIn;
1559 :
1560 302340 : for( iIn = 0; iIn < nLength; iIn++ )
1561 : {
1562 288592 : if( pszInput[iIn] == '<' )
1563 : {
1564 3 : pszOutput[iOut++] = '&';
1565 3 : pszOutput[iOut++] = 'l';
1566 3 : pszOutput[iOut++] = 't';
1567 3 : pszOutput[iOut++] = ';';
1568 : }
1569 288589 : else if( pszInput[iIn] == '>' )
1570 : {
1571 3 : pszOutput[iOut++] = '&';
1572 3 : pszOutput[iOut++] = 'g';
1573 3 : pszOutput[iOut++] = 't';
1574 3 : pszOutput[iOut++] = ';';
1575 : }
1576 288586 : else if( pszInput[iIn] == '&' )
1577 : {
1578 9 : pszOutput[iOut++] = '&';
1579 9 : pszOutput[iOut++] = 'a';
1580 9 : pszOutput[iOut++] = 'm';
1581 9 : pszOutput[iOut++] = 'p';
1582 9 : pszOutput[iOut++] = ';';
1583 : }
1584 288577 : else if( pszInput[iIn] == '"' )
1585 : {
1586 5814 : pszOutput[iOut++] = '&';
1587 5814 : pszOutput[iOut++] = 'q';
1588 5814 : pszOutput[iOut++] = 'u';
1589 5814 : pszOutput[iOut++] = 'o';
1590 5814 : pszOutput[iOut++] = 't';
1591 5814 : pszOutput[iOut++] = ';';
1592 : }
1593 : else
1594 282763 : pszOutput[iOut++] = pszInput[iIn];
1595 : }
1596 13748 : pszOutput[iOut] = '\0';
1597 : }
1598 85 : else if( nScheme == CPLES_SQL )
1599 : {
1600 7 : int iOut = 0, iIn;
1601 :
1602 42 : for( iIn = 0; iIn < nLength; iIn++ )
1603 : {
1604 35 : if( pszInput[iIn] == '\'' )
1605 : {
1606 0 : pszOutput[iOut++] = '\'';
1607 0 : pszOutput[iOut++] = '\'';
1608 : }
1609 : else
1610 35 : pszOutput[iOut++] = pszInput[iIn];
1611 : }
1612 7 : pszOutput[iOut] = '\0';
1613 : }
1614 78 : else if( nScheme == CPLES_CSV )
1615 : {
1616 146 : if( strchr( pszInput, '\"' ) == NULL
1617 : && strchr( pszInput, ',') == NULL
1618 : && strchr( pszInput, ';') == NULL
1619 : && strchr( pszInput, '\t') == NULL
1620 : && strchr( pszInput, 10) == NULL
1621 : && strchr( pszInput, 13) == NULL )
1622 : {
1623 68 : strcpy( pszOutput, pszInput );
1624 : }
1625 : else
1626 : {
1627 10 : int iOut = 1, iIn;
1628 :
1629 10 : pszOutput[0] = '\"';
1630 :
1631 444 : for( iIn = 0; iIn < nLength; iIn++ )
1632 : {
1633 434 : if( pszInput[iIn] == '\"' )
1634 : {
1635 6 : pszOutput[iOut++] = '\"';
1636 6 : pszOutput[iOut++] = '\"';
1637 : }
1638 428 : else if( pszInput[iIn] == 13 )
1639 : /* drop DOS LF's in strings. */;
1640 : else
1641 428 : pszOutput[iOut++] = pszInput[iIn];
1642 : }
1643 10 : pszOutput[iOut++] = '\"';
1644 10 : pszOutput[iOut++] = '\0';
1645 : }
1646 : }
1647 : else
1648 : {
1649 0 : pszOutput[0] = '\0';
1650 : CPLError( CE_Failure, CPLE_AppDefined,
1651 : "Undefined escaping scheme (%d) in CPLEscapeString()",
1652 0 : nScheme );
1653 : }
1654 :
1655 13857 : pszShortOutput = CPLStrdup( pszOutput );
1656 13857 : CPLFree( pszOutput );
1657 :
1658 13857 : return pszShortOutput;
1659 : }
1660 :
1661 : /************************************************************************/
1662 : /* CPLUnescapeString() */
1663 : /************************************************************************/
1664 :
1665 : /**
1666 : * Unescape a string.
1667 : *
1668 : * This function does the opposite of CPLEscapeString(). Given a string
1669 : * with special values escaped according to some scheme, it will return a
1670 : * new copy of the string returned to it's original form.
1671 : *
1672 : * @param pszInput the input string. This is a zero terminated string.
1673 : * @param pnLength location to return the length of the unescaped string,
1674 : * which may in some cases include embedded '\\0' characters.
1675 : * @param nScheme the escaped scheme to undo (see CPLEscapeString() for a
1676 : * list).
1677 : *
1678 : * @return a copy of the unescaped string that should be freed by the
1679 : * application using CPLFree() when no longer needed.
1680 : */
1681 :
1682 1152 : char *CPLUnescapeString( const char *pszInput, int *pnLength, int nScheme )
1683 :
1684 : {
1685 : char *pszOutput;
1686 1152 : int iOut=0, iIn;
1687 :
1688 1152 : pszOutput = (char *) CPLMalloc(strlen(pszInput)+1);
1689 1152 : pszOutput[0] = '\0';
1690 :
1691 1152 : if( nScheme == CPLES_XML )
1692 : {
1693 115125 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1694 : {
1695 114081 : if( EQUALN(pszInput+iIn,"<",4) )
1696 : {
1697 6 : pszOutput[iOut++] = '<';
1698 6 : iIn += 3;
1699 : }
1700 114075 : else if( EQUALN(pszInput+iIn,">",4) )
1701 : {
1702 6 : pszOutput[iOut++] = '>';
1703 6 : iIn += 3;
1704 : }
1705 114069 : else if( EQUALN(pszInput+iIn,"&",5) )
1706 : {
1707 32 : pszOutput[iOut++] = '&';
1708 32 : iIn += 4;
1709 : }
1710 114037 : else if( EQUALN(pszInput+iIn,""",6) )
1711 : {
1712 9558 : pszOutput[iOut++] = '"';
1713 9558 : iIn += 5;
1714 : }
1715 : else
1716 : {
1717 104479 : pszOutput[iOut++] = pszInput[iIn];
1718 : }
1719 : }
1720 : }
1721 108 : else if( nScheme == CPLES_URL )
1722 : {
1723 0 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1724 : {
1725 0 : if( pszInput[iIn] == '%'
1726 : && pszInput[iIn+1] != '\0'
1727 : && pszInput[iIn+2] != '\0' )
1728 : {
1729 0 : int nHexChar = 0;
1730 :
1731 0 : if( pszInput[iIn+1] >= 'A' && pszInput[iIn+1] <= 'F' )
1732 0 : nHexChar += 16 * (pszInput[iIn+1] - 'A' + 10);
1733 0 : else if( pszInput[iIn+1] >= 'a' && pszInput[iIn+1] <= 'f' )
1734 0 : nHexChar += 16 * (pszInput[iIn+1] - 'a' + 10);
1735 0 : else if( pszInput[iIn+1] >= '0' && pszInput[iIn+1] <= '9' )
1736 0 : nHexChar += 16 * (pszInput[iIn+1] - '0');
1737 : else
1738 : CPLDebug( "CPL",
1739 : "Error unescaping CPLES_URL text, percent not "
1740 0 : "followed by two hex digits." );
1741 :
1742 0 : if( pszInput[iIn+2] >= 'A' && pszInput[iIn+2] <= 'F' )
1743 0 : nHexChar += pszInput[iIn+2] - 'A' + 10;
1744 0 : else if( pszInput[iIn+2] >= 'a' && pszInput[iIn+2] <= 'f' )
1745 0 : nHexChar += pszInput[iIn+2] - 'a' + 10;
1746 0 : else if( pszInput[iIn+2] >= '0' && pszInput[iIn+2] <= '9' )
1747 0 : nHexChar += pszInput[iIn+2] - '0';
1748 : else
1749 : CPLDebug( "CPL",
1750 : "Error unescaping CPLES_URL text, percent not "
1751 0 : "followed by two hex digits." );
1752 :
1753 0 : pszOutput[iOut++] = (char) nHexChar;
1754 0 : iIn += 2;
1755 : }
1756 0 : else if( pszInput[iIn] == '+' )
1757 : {
1758 0 : pszOutput[iOut++] = ' ';
1759 : }
1760 : else
1761 : {
1762 0 : pszOutput[iOut++] = pszInput[iIn];
1763 : }
1764 : }
1765 : }
1766 108 : else if( nScheme == CPLES_SQL )
1767 : {
1768 0 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1769 : {
1770 0 : if( pszInput[iIn] == '\'' && pszInput[iIn+1] == '\'' )
1771 : {
1772 0 : iIn++;
1773 0 : pszOutput[iOut++] = pszInput[iIn];
1774 : }
1775 : else
1776 : {
1777 0 : pszOutput[iOut++] = pszInput[iIn];
1778 : }
1779 : }
1780 : }
1781 : else /* if( nScheme == CPLES_BackslashQuoteable ) */
1782 : {
1783 203388 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1784 : {
1785 203280 : if( pszInput[iIn] == '\\' )
1786 : {
1787 1 : iIn++;
1788 1 : if( pszInput[iIn] == 'n' )
1789 0 : pszOutput[iOut++] = '\n';
1790 1 : else if( pszInput[iIn] == '0' )
1791 1 : pszOutput[iOut++] = '\0';
1792 : else
1793 0 : pszOutput[iOut++] = pszInput[iIn];
1794 : }
1795 : else
1796 : {
1797 203279 : pszOutput[iOut++] = pszInput[iIn];
1798 : }
1799 : }
1800 : }
1801 :
1802 1152 : pszOutput[iOut] = '\0';
1803 :
1804 1152 : if( pnLength != NULL )
1805 392 : *pnLength = iOut;
1806 :
1807 1152 : return pszOutput;
1808 : }
1809 :
1810 : /************************************************************************/
1811 : /* CPLBinaryToHex() */
1812 : /************************************************************************/
1813 :
1814 : /**
1815 : * Binary to hexadecimal translation.
1816 : *
1817 : * @param nBytes number of bytes of binary data in pabyData.
1818 : * @param pabyData array of data bytes to translate.
1819 : *
1820 : * @return hexadecimal translation, zero terminated. Free with CPLFree().
1821 : */
1822 :
1823 122 : char *CPLBinaryToHex( int nBytes, const GByte *pabyData )
1824 :
1825 : {
1826 122 : char *pszHex = (char *) CPLMalloc(nBytes * 2 + 1 );
1827 : int i;
1828 : static const char achHex[] = "0123456789ABCDEF";
1829 :
1830 122 : pszHex[nBytes*2] = '\0';
1831 :
1832 16338 : for( i = 0; i < nBytes; i++ )
1833 : {
1834 16216 : int nLow = pabyData[i] & 0x0f;
1835 16216 : int nHigh = (pabyData[i] & 0xf0) >> 4;
1836 :
1837 16216 : pszHex[i*2] = achHex[nHigh];
1838 16216 : pszHex[i*2+1] = achHex[nLow];
1839 : }
1840 :
1841 122 : return pszHex;
1842 : }
1843 :
1844 :
1845 : /************************************************************************/
1846 : /* CPLHexToBinary() */
1847 : /************************************************************************/
1848 :
1849 : /**
1850 : * Hexadecimal to binary translation
1851 : *
1852 : * @param pszHex the input hex encoded string.
1853 : * @param pnBytes the returned count of decoded bytes placed here.
1854 : *
1855 : * @return returns binary buffer of data - free with CPLFree().
1856 : */
1857 :
1858 14 : GByte *CPLHexToBinary( const char *pszHex, int *pnBytes )
1859 :
1860 : {
1861 14 : int iSrc = 0, iDst = 0;
1862 14 : size_t nHexLen = strlen(pszHex);
1863 :
1864 : GByte *pabyWKB;
1865 :
1866 14 : pabyWKB = (GByte *) CPLMalloc(nHexLen / 2 + 2);
1867 :
1868 1817 : while( pszHex[iSrc] != '\0' )
1869 : {
1870 3428 : if( pszHex[iSrc] >= '0' && pszHex[iSrc] <= '9' )
1871 1639 : pabyWKB[iDst] = pszHex[iSrc] - '0';
1872 300 : else if( pszHex[iSrc] >= 'A' && pszHex[iSrc] <= 'F' )
1873 150 : pabyWKB[iDst] = pszHex[iSrc] - 'A' + 10;
1874 0 : else if( pszHex[iSrc] >= 'a' && pszHex[iSrc] <= 'f' )
1875 0 : pabyWKB[iDst] = pszHex[iSrc] - 'a' + 10;
1876 : else
1877 0 : break;
1878 :
1879 1789 : pabyWKB[iDst] *= 16;
1880 :
1881 1789 : iSrc++;
1882 :
1883 3430 : if( pszHex[iSrc] >= '0' && pszHex[iSrc] <= '9' )
1884 1641 : pabyWKB[iDst] += pszHex[iSrc] - '0';
1885 296 : else if( pszHex[iSrc] >= 'A' && pszHex[iSrc] <= 'F' )
1886 148 : pabyWKB[iDst] += pszHex[iSrc] - 'A' + 10;
1887 0 : else if( pszHex[iSrc] >= 'a' && pszHex[iSrc] <= 'f' )
1888 0 : pabyWKB[iDst] += pszHex[iSrc] - 'a' + 10;
1889 : else
1890 0 : break;
1891 :
1892 1789 : iSrc++;
1893 1789 : iDst++;
1894 : }
1895 :
1896 14 : pabyWKB[iDst] = 0;
1897 14 : *pnBytes = iDst;
1898 :
1899 14 : return pabyWKB;
1900 : }
1901 :
1902 :
1903 :
1904 : /************************************************************************/
1905 : /* CPLGetValueType() */
1906 : /************************************************************************/
1907 :
1908 : /**
1909 : * Detect the type of the value contained in a string, whether it is
1910 : * a real, an integer or a string
1911 : * Leading and trailing spaces are skipped in the analysis.
1912 : *
1913 : * @param pszValue the string to analyze
1914 : *
1915 : * @return returns the type of the value contained in the string.
1916 : */
1917 :
1918 184 : CPLValueType CPLGetValueType(const char* pszValue)
1919 : {
1920 : /*
1921 : doubles : "+25.e+3", "-25.e-3", "25.e3", "25e3", " 25e3 "
1922 : not doubles: "25e 3", "25e.3", "-2-5e3", "2-5e3", "25.25.3"
1923 : */
1924 :
1925 184 : int bFoundDot = FALSE;
1926 184 : int bFoundExponent = FALSE;
1927 184 : int bIsLastCharExponent = FALSE;
1928 184 : int bIsReal = FALSE;
1929 :
1930 184 : if (pszValue == NULL)
1931 0 : return CPL_VALUE_STRING;
1932 :
1933 : /* Skip leading + or - */
1934 184 : if (*pszValue == '+' || *pszValue == '-')
1935 0 : pszValue ++;
1936 :
1937 : /* Skip leading spaces */
1938 368 : while( isspace( (unsigned char)*pszValue ) )
1939 0 : pszValue ++;
1940 :
1941 570 : for(; *pszValue != '\0'; pszValue++ )
1942 : {
1943 419 : if( isdigit( *pszValue))
1944 : {
1945 343 : bIsLastCharExponent = FALSE;
1946 : /* do nothing */
1947 : }
1948 76 : else if ( isspace ((unsigned char)*pszValue) )
1949 : {
1950 0 : const char* pszTmp = pszValue;
1951 0 : while( isspace( (unsigned char)*pszTmp ) )
1952 0 : pszTmp ++;
1953 0 : if (*pszTmp == 0)
1954 0 : break;
1955 : else
1956 0 : return CPL_VALUE_STRING;
1957 : }
1958 76 : else if ( *pszValue == '-' || *pszValue == '+' )
1959 : {
1960 0 : if (bIsLastCharExponent)
1961 : {
1962 : /* do nothing */
1963 : }
1964 : else
1965 0 : return CPL_VALUE_STRING;
1966 0 : bIsLastCharExponent = FALSE;
1967 : }
1968 76 : else if ( *pszValue == '.')
1969 : {
1970 43 : bIsReal = TRUE;
1971 43 : if (!bFoundDot && bIsLastCharExponent == FALSE)
1972 43 : bFoundDot = TRUE;
1973 : else
1974 0 : return CPL_VALUE_STRING;
1975 43 : bIsLastCharExponent = FALSE;
1976 : }
1977 33 : else if (*pszValue == 'D' || *pszValue == 'd'
1978 : || *pszValue == 'E' || *pszValue == 'e' )
1979 : {
1980 0 : bIsReal = TRUE;
1981 0 : if (!bFoundExponent)
1982 0 : bFoundExponent = TRUE;
1983 : else
1984 0 : return CPL_VALUE_STRING;
1985 0 : bIsLastCharExponent = TRUE;
1986 : }
1987 : else
1988 : {
1989 33 : return CPL_VALUE_STRING;
1990 : }
1991 : }
1992 :
1993 151 : return (bIsReal) ? CPL_VALUE_REAL : CPL_VALUE_INTEGER;
1994 : }
1995 :
1996 : /************************************************************************/
1997 : /* CPLStrlcpy() */
1998 : /************************************************************************/
1999 :
2000 : /**
2001 : * Copy source string to a destination buffer.
2002 : *
2003 : * This function ensures that the destination buffer is always NUL terminated
2004 : * (provided that its length is at least 1).
2005 : *
2006 : * This function is designed to be a safer, more consistent, and less error
2007 : * prone replacement for strncpy. Its contract is identical to libbsd's strlcpy.
2008 : *
2009 : * Truncation can be detected by testing if the return value of CPLStrlcpy
2010 : * is greater or equal to nDestSize.
2011 :
2012 : \verbatim
2013 : char szDest[5];
2014 : if (CPLStrlcpy(szDest, "abcde", sizeof(szDest)) >= sizeof(szDest))
2015 : fprintf(stderr, "truncation occured !\n");
2016 : \endverbatim
2017 :
2018 : * @param pszDest destination buffer
2019 : * @param pszSrc source string. Must be NUL terminated
2020 : * @param nDestSize size of destination buffer (including space for the NUL terminator character)
2021 : *
2022 : * @return the length of the source string (=strlen(pszSrc))
2023 : *
2024 : * @since GDAL 1.7.0
2025 : */
2026 251157 : size_t CPLStrlcpy(char* pszDest, const char* pszSrc, size_t nDestSize)
2027 : {
2028 251157 : char* pszDestIter = pszDest;
2029 251157 : const char* pszSrcIter = pszSrc;
2030 :
2031 251157 : if (nDestSize == 0)
2032 0 : return strlen(pszSrc);
2033 :
2034 251157 : nDestSize --;
2035 1881928 : while(nDestSize != 0 && *pszSrcIter != '\0')
2036 : {
2037 1379614 : *pszDestIter = *pszSrcIter;
2038 1379614 : pszDestIter ++;
2039 1379614 : pszSrcIter ++;
2040 1379614 : nDestSize --;
2041 : }
2042 251157 : *pszDestIter = '\0';
2043 251157 : return pszSrcIter - pszSrc + strlen(pszSrcIter);
2044 : }
2045 :
2046 : /************************************************************************/
2047 : /* CPLStrlcat() */
2048 : /************************************************************************/
2049 :
2050 : /**
2051 : * Appends a source string to a destination buffer.
2052 : *
2053 : * This function ensures that the destination buffer is always NUL terminated
2054 : * (provided that its length is at least 1 and that there is at least one byte
2055 : * free in pszDest, that is to say strlen(pszDest_before) < nDestSize)
2056 : *
2057 : * This function is designed to be a safer, more consistent, and less error
2058 : * prone replacement for strncat. Its contract is identical to libbsd's strlcat.
2059 : *
2060 : * Truncation can be detected by testing if the return value of CPLStrlcat
2061 : * is greater or equal to nDestSize.
2062 :
2063 : \verbatim
2064 : char szDest[5];
2065 : CPLStrlcpy(szDest, "ab", sizeof(szDest));
2066 : if (CPLStrlcat(szDest, "cde", sizeof(szDest)) >= sizeof(szDest))
2067 : fprintf(stderr, "truncation occured !\n");
2068 : \endverbatim
2069 :
2070 : * @param pszDest destination buffer. Must be NUL terminated before running CPLStrlcat
2071 : * @param pszSrc source string. Must be NUL terminated
2072 : * @param nDestSize size of destination buffer (including space for the NUL terminator character)
2073 : *
2074 : * @return the thoretical length of the destination string after concatenation
2075 : * (=strlen(pszDest_before) + strlen(pszSrc)).
2076 : * If strlen(pszDest_before) >= nDestSize, then it returns nDestSize + strlen(pszSrc)
2077 : *
2078 : * @since GDAL 1.7.0
2079 : */
2080 109392 : size_t CPLStrlcat(char* pszDest, const char* pszSrc, size_t nDestSize)
2081 : {
2082 109392 : char* pszDestIter = pszDest;
2083 :
2084 1985322 : while(nDestSize != 0 && *pszDestIter != '\0')
2085 : {
2086 1766538 : pszDestIter ++;
2087 1766538 : nDestSize --;
2088 : }
2089 :
2090 109392 : return pszDestIter - pszDest + CPLStrlcpy(pszDestIter, pszSrc, nDestSize);
2091 : }
2092 :
2093 : /************************************************************************/
2094 : /* CPLStrnlen() */
2095 : /************************************************************************/
2096 :
2097 : /**
2098 : * Returns the length of a NUL terminated string by reading at most
2099 : * the specified number of bytes.
2100 : *
2101 : * The CPLStrnlen() function returns MIN(strlen(pszStr), nMaxLen).
2102 : * Only the first nMaxLen bytes of the string will be read. Usefull to
2103 : * test if a string contains at least nMaxLen characters without reading
2104 : * the full string up to the NUL terminating character.
2105 : *
2106 : * @param pszStr a NUL terminated string
2107 : * @param nMaxLen maximum number of bytes to read in pszStr
2108 : *
2109 : * @return strlen(pszStr) if the length is lesser than nMaxLen, otherwise
2110 : * nMaxLen if the NUL character has not been found in the first nMaxLen bytes.
2111 : *
2112 : * @since GDAL 1.7.0
2113 : */
2114 :
2115 6 : size_t CPLStrnlen (const char *pszStr, size_t nMaxLen)
2116 : {
2117 6 : size_t nLen = 0;
2118 108 : while(nLen < nMaxLen && *pszStr != '\0')
2119 : {
2120 96 : nLen ++;
2121 96 : pszStr ++;
2122 : }
2123 6 : return nLen;
2124 : }
|