1 : /**********************************************************************
2 : * $Id: cpl_string.cpp 18179 2009-12-05 00:40:04Z warmerdam $
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 18179 2009-12-05 00:40:04Z warmerdam $");
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 981142 : char **CSLAddString(char **papszStrList, const char *pszNewString)
73 : {
74 981142 : int nItems=0;
75 :
76 981142 : if (pszNewString == NULL)
77 0 : return papszStrList; /* Nothing to do!*/
78 :
79 : /* Allocate room for the new string */
80 981142 : if (papszStrList == NULL)
81 176879 : papszStrList = (char**) CPLCalloc(2,sizeof(char*));
82 : else
83 : {
84 804263 : nItems = CSLCount(papszStrList);
85 : papszStrList = (char**)CPLRealloc(papszStrList,
86 804263 : (nItems+2)*sizeof(char*));
87 : }
88 :
89 : /* Copy the string in the list */
90 981142 : papszStrList[nItems] = CPLStrdup(pszNewString);
91 981142 : papszStrList[nItems+1] = NULL;
92 :
93 981142 : 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 2064766 : int CSLCount(char **papszStrList)
117 : {
118 2064766 : int nItems=0;
119 :
120 2064766 : if (papszStrList)
121 : {
122 13823814 : while(*papszStrList != NULL)
123 : {
124 11761654 : nItems++;
125 11761654 : papszStrList++;
126 : }
127 : }
128 :
129 2064766 : 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 453 : const char * CSLGetField( char ** papszStrList, int iField )
143 :
144 : {
145 : int i;
146 :
147 453 : if( papszStrList == NULL || iField < 0 )
148 44 : return( "" );
149 :
150 3125 : for( i = 0; i < iField+1; i++ )
151 : {
152 2716 : if( papszStrList[i] == NULL )
153 0 : return "";
154 : }
155 :
156 409 : 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 1949509 : void CPL_STDCALL CSLDestroy(char **papszStrList)
172 : {
173 : char **papszPtr;
174 :
175 1949509 : if (papszStrList)
176 : {
177 310646 : papszPtr = papszStrList;
178 2133755 : while(*papszPtr != NULL)
179 : {
180 1512463 : CPLFree(*papszPtr);
181 1512463 : papszPtr++;
182 : }
183 :
184 310646 : CPLFree(papszStrList);
185 : }
186 1949509 : }
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 5541 : char **CSLDuplicate(char **papszStrList)
204 : {
205 : char **papszNewList, **papszSrc, **papszDst;
206 : int nLines;
207 :
208 5541 : nLines = CSLCount(papszStrList);
209 :
210 5541 : if (nLines == 0)
211 1827 : return NULL;
212 :
213 3714 : papszNewList = (char **)CPLMalloc((nLines+1)*sizeof(char*));
214 3714 : papszSrc = papszStrList;
215 3714 : papszDst = papszNewList;
216 :
217 44947 : while(*papszSrc != NULL)
218 : {
219 37519 : *papszDst = CPLStrdup(*papszSrc);
220 :
221 37519 : papszSrc++;
222 37519 : papszDst++;
223 : }
224 3714 : *papszDst = NULL;
225 :
226 3714 : 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 342 : char **CSLMerge( char **papszOrig, char **papszOverride )
247 :
248 : {
249 : int i;
250 :
251 342 : if( papszOrig == NULL && papszOverride != NULL )
252 3 : return CSLDuplicate( papszOverride );
253 :
254 339 : if( papszOverride == NULL )
255 227 : return papszOrig;
256 :
257 293 : for( i = 0; papszOverride[i] != NULL; i++ )
258 : {
259 181 : char *pszKey = NULL;
260 181 : const char *pszValue = CPLParseNameValue( papszOverride[i], &pszKey );
261 :
262 181 : papszOrig = CSLSetNameValue( papszOrig, pszKey, pszValue );
263 181 : CPLFree( pszKey );
264 : }
265 :
266 112 : 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 247 : char **CSLLoad2(const char *pszFname, int nMaxLines, int nMaxCols, char** papszOptions)
294 : {
295 : FILE *fp;
296 : const char *pszLine;
297 247 : char **papszStrList=NULL;
298 247 : int nLines = 0;
299 247 : int nAllocatedLines = 0;
300 :
301 247 : fp = VSIFOpenL(pszFname, "rb");
302 :
303 247 : if (fp)
304 : {
305 247 : CPLErrorReset();
306 247 : while(!VSIFEofL(fp) && (nMaxLines == -1 || nLines < nMaxLines))
307 : {
308 2305 : if ( (pszLine = CPLReadLine2L(fp, nMaxCols, papszOptions)) != NULL )
309 : {
310 2305 : if (nLines + 1 >= nAllocatedLines)
311 : {
312 : char** papszStrListNew;
313 276 : nAllocatedLines = 16 + nAllocatedLines * 2;
314 : papszStrListNew = (char**) VSIRealloc(papszStrList,
315 276 : nAllocatedLines * sizeof(char*));
316 276 : 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 276 : papszStrList = papszStrListNew;
326 : }
327 2305 : papszStrList[nLines] = CPLStrdup(pszLine);
328 2305 : papszStrList[nLines + 1] = NULL;
329 2305 : nLines ++;
330 : }
331 0 : else if (CPLGetLastErrorType() != 0)
332 : {
333 0 : break;
334 : }
335 : }
336 :
337 247 : VSIFCloseL(fp);
338 :
339 247 : 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 247 : 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 234 : char **CSLLoad(const char *pszFname)
372 : {
373 234 : 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 20 : int CSLSave(char **papszStrList, const char *pszFname)
385 : {
386 : FILE *fp;
387 20 : int nLines = 0;
388 :
389 20 : if (papszStrList)
390 : {
391 20 : if ((fp = VSIFOpenL(pszFname, "wt")) != NULL)
392 : {
393 240 : while(*papszStrList != NULL)
394 : {
395 200 : 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 200 : nLines++;
404 200 : papszStrList++;
405 : }
406 :
407 20 : 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 20 : 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 391 : char **CSLInsertStrings(char **papszStrList, int nInsertAtLineNo,
464 : char **papszNewLines)
465 : {
466 : int i, nSrcLines, nDstLines, nToInsert;
467 : char **ppszSrc, **ppszDst;
468 :
469 391 : if (papszNewLines == NULL ||
470 : ( nToInsert = CSLCount(papszNewLines) ) == 0)
471 4 : return papszStrList; /* Nothing to do!*/
472 :
473 387 : nSrcLines = CSLCount(papszStrList);
474 387 : nDstLines = nSrcLines + nToInsert;
475 :
476 : /* Allocate room for the new strings */
477 : papszStrList = (char**)CPLRealloc(papszStrList,
478 387 : (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 387 : 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 387 : if (nInsertAtLineNo == -1 || nInsertAtLineNo > nSrcLines)
490 92 : nInsertAtLineNo = nSrcLines;
491 :
492 387 : ppszSrc = papszStrList + nSrcLines;
493 387 : ppszDst = papszStrList + nDstLines;
494 :
495 1198 : for (i=nSrcLines; i>=nInsertAtLineNo; i--)
496 : {
497 811 : *ppszDst = *ppszSrc;
498 811 : ppszDst--;
499 811 : ppszSrc--;
500 : }
501 :
502 : /* Copy the strings to the list */
503 387 : ppszSrc = papszNewLines;
504 387 : ppszDst = papszStrList + nInsertAtLineNo;
505 :
506 5525 : for (; *ppszSrc != NULL; ppszSrc++, ppszDst++)
507 : {
508 5138 : *ppszDst = CPLStrdup(*ppszSrc);
509 : }
510 :
511 387 : 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 104 : char **CSLInsertString(char **papszStrList, int nInsertAtLineNo,
527 : 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 20 : char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete,
557 : int nNumToRemove, char ***ppapszRetStrings)
558 : {
559 : int i, nSrcLines, nDstLines;
560 : char **ppszSrc, **ppszDst;
561 :
562 20 : nSrcLines = CSLCount(papszStrList);
563 20 : nDstLines = nSrcLines - nNumToRemove;
564 :
565 20 : 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 20 : if (nDstLines < 1)
572 : {
573 13 : CSLDestroy(papszStrList);
574 13 : 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 560993 : int CSLFindString( char ** papszList, const char * pszTarget )
650 :
651 : {
652 : int i;
653 :
654 560993 : if( papszList == NULL )
655 62861 : return -1;
656 :
657 1269176 : for( i = 0; papszList[i] != NULL; i++ )
658 : {
659 947453 : if( EQUAL(papszList[i],pszTarget) )
660 176409 : return i;
661 : }
662 :
663 321723 : 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 3167 : char **CSLTokenizeString( const char *pszString )
706 : {
707 3167 : return CSLTokenizeString2( pszString, " ", CSLT_HONOURSTRINGS );
708 : }
709 :
710 : /************************************************************************/
711 : /* CSLTokenizeStringComplex() */
712 : /* */
713 : /* Obsolete tokenizing api. */
714 : /************************************************************************/
715 :
716 53457 : char ** CSLTokenizeStringComplex( const char * pszString,
717 : const char * pszDelimiters,
718 : int bHonourStrings, int bAllowEmptyTokens )
719 :
720 : {
721 53457 : int nFlags = 0;
722 :
723 53457 : if( bHonourStrings )
724 43232 : nFlags |= CSLT_HONOURSTRINGS;
725 53457 : if( bAllowEmptyTokens )
726 450 : nFlags |= CSLT_ALLOWEMPTYTOKENS;
727 :
728 53457 : 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 57220 : char ** CSLTokenizeString2( const char * pszString,
787 : const char * pszDelimiters,
788 : int nCSLTFlags )
789 :
790 : {
791 57220 : char **papszRetList = NULL;
792 57220 : int nRetMax = 0, nRetLen = 0;
793 : char *pszToken;
794 : int nTokenMax, nTokenLen;
795 57220 : int bHonourStrings = (nCSLTFlags & CSLT_HONOURSTRINGS);
796 57220 : int bAllowEmptyTokens = (nCSLTFlags & CSLT_ALLOWEMPTYTOKENS);
797 57220 : int bStripLeadSpaces = (nCSLTFlags & CSLT_STRIPLEADSPACES);
798 57220 : int bStripEndSpaces = (nCSLTFlags & CSLT_STRIPENDSPACES);
799 :
800 57220 : pszToken = (char *) CPLCalloc(10,1);
801 57220 : nTokenMax = 10;
802 :
803 241391 : while( pszString != NULL && *pszString != '\0' )
804 : {
805 126951 : int bInString = FALSE;
806 126951 : int bStartString = TRUE;
807 :
808 126951 : nTokenLen = 0;
809 :
810 : /* Try to find the next delimeter, marking end of token */
811 766871 : for( ; *pszString != '\0'; pszString++ )
812 : {
813 :
814 : /* End if this is a delimeter skip it and break. */
815 712639 : if( !bInString && strchr(pszDelimiters, *pszString) != NULL )
816 : {
817 72719 : pszString++;
818 72719 : break;
819 : }
820 :
821 : /* If this is a quote, and we are honouring constant
822 : strings, then process the constant strings, with out delim
823 : but don't copy over the quotes */
824 639920 : if( bHonourStrings && *pszString == '"' )
825 : {
826 610 : if( nCSLTFlags & CSLT_PRESERVEQUOTES )
827 : {
828 8 : pszToken[nTokenLen] = *pszString;
829 8 : nTokenLen++;
830 : }
831 :
832 610 : if( bInString )
833 : {
834 305 : bInString = FALSE;
835 305 : continue;
836 : }
837 : else
838 : {
839 305 : bInString = TRUE;
840 305 : continue;
841 : }
842 : }
843 :
844 : /*
845 : * Within string constants we allow for escaped quotes, but in
846 : * processing them we will unescape the quotes and \\ sequence
847 : * reduces to \
848 : */
849 639310 : if( bInString && pszString[0] == '\\' )
850 : {
851 0 : if ( pszString[1] == '"' || pszString[1] == '\\' )
852 : {
853 0 : if( nCSLTFlags & CSLT_PRESERVEESCAPES )
854 : {
855 0 : pszToken[nTokenLen] = *pszString;
856 0 : nTokenLen++;
857 : }
858 :
859 0 : pszString++;
860 : }
861 : }
862 :
863 : /*
864 : * Strip spaces at the token start if requested.
865 : */
866 639310 : if ( !bInString && bStripLeadSpaces
867 : && bStartString && isspace((unsigned char)*pszString) )
868 0 : continue;
869 :
870 639310 : bStartString = FALSE;
871 :
872 : /*
873 : * Extend token buffer if we are running close to its end.
874 : */
875 639310 : if( nTokenLen >= nTokenMax-3 )
876 : {
877 16560 : nTokenMax = nTokenMax * 2 + 10;
878 16560 : pszToken = (char *) CPLRealloc( pszToken, nTokenMax );
879 : }
880 :
881 639310 : pszToken[nTokenLen] = *pszString;
882 639310 : nTokenLen++;
883 : }
884 :
885 : /*
886 : * Strip spaces at the token end if requested.
887 : */
888 126951 : if ( !bInString && bStripEndSpaces )
889 : {
890 12 : while ( nTokenLen && isspace((unsigned char)pszToken[nTokenLen - 1]) )
891 0 : nTokenLen--;
892 : }
893 :
894 126951 : pszToken[nTokenLen] = '\0';
895 :
896 : /*
897 : * Add the token.
898 : */
899 126951 : if( pszToken[0] != '\0' || bAllowEmptyTokens )
900 : {
901 105216 : if( nRetLen >= nRetMax - 1 )
902 : {
903 56165 : nRetMax = nRetMax * 2 + 10;
904 : papszRetList = (char **)
905 56165 : CPLRealloc(papszRetList, sizeof(char*) * nRetMax );
906 : }
907 :
908 105216 : papszRetList[nRetLen++] = CPLStrdup( pszToken );
909 105216 : papszRetList[nRetLen] = NULL;
910 : }
911 : }
912 :
913 : /*
914 : * If the last token was empty, then we need to capture
915 : * it now, as the loop would skip it.
916 : */
917 57220 : if( *pszString == '\0' && bAllowEmptyTokens && nRetLen > 0
918 : && strchr(pszDelimiters,*(pszString-1)) != NULL )
919 : {
920 8 : if( nRetLen >= nRetMax - 1 )
921 : {
922 0 : nRetMax = nRetMax * 2 + 10;
923 : papszRetList = (char **)
924 0 : CPLRealloc(papszRetList, sizeof(char*) * nRetMax );
925 : }
926 :
927 8 : papszRetList[nRetLen++] = CPLStrdup("");
928 8 : papszRetList[nRetLen] = NULL;
929 : }
930 :
931 57220 : if( papszRetList == NULL )
932 1982 : papszRetList = (char **) CPLCalloc(sizeof(char *),1);
933 :
934 57220 : CPLFree( pszToken );
935 :
936 57220 : return papszRetList;
937 : }
938 :
939 : /**********************************************************************
940 : * CPLSPrintf()
941 : *
942 : * My own version of CPLSPrintf() that works with 10 static buffer.
943 : *
944 : * It returns a ref. to a static buffer that should not be freed and
945 : * is valid only until the next call to CPLSPrintf().
946 : *
947 : * NOTE: This function should move to cpl_conv.cpp.
948 : **********************************************************************/
949 : /* For now, assume that a 8000 chars buffer will be enough.
950 : */
951 : #define CPLSPrintf_BUF_SIZE 8000
952 : #define CPLSPrintf_BUF_Count 10
953 :
954 20255 : const char *CPLSPrintf(const char *fmt, ...)
955 : {
956 : va_list args;
957 :
958 : /* -------------------------------------------------------------------- */
959 : /* Get the thread local buffer ring data. */
960 : /* -------------------------------------------------------------------- */
961 20255 : char *pachBufRingInfo = (char *) CPLGetTLS( CTLS_CPLSPRINTF );
962 :
963 20255 : if( pachBufRingInfo == NULL )
964 : {
965 : pachBufRingInfo = (char *)
966 25 : CPLCalloc(1,sizeof(int)+CPLSPrintf_BUF_Count*CPLSPrintf_BUF_SIZE);
967 25 : CPLSetTLS( CTLS_CPLSPRINTF, pachBufRingInfo, TRUE );
968 : }
969 :
970 : /* -------------------------------------------------------------------- */
971 : /* Work out which string in the "ring" we want to use this */
972 : /* time. */
973 : /* -------------------------------------------------------------------- */
974 20255 : int *pnBufIndex = (int *) pachBufRingInfo;
975 20255 : int nOffset = sizeof(int) + *pnBufIndex * CPLSPrintf_BUF_SIZE;
976 20255 : char *pachBuffer = pachBufRingInfo + nOffset;
977 :
978 20255 : *pnBufIndex = (*pnBufIndex + 1) % CPLSPrintf_BUF_Count;
979 :
980 : /* -------------------------------------------------------------------- */
981 : /* Format the result. */
982 : /* -------------------------------------------------------------------- */
983 :
984 20255 : va_start(args, fmt);
985 : #if defined(HAVE_VSNPRINTF)
986 20255 : vsnprintf(pachBuffer, CPLSPrintf_BUF_SIZE-1, fmt, args);
987 : #else
988 : vsprintf(pachBuffer, fmt, args);
989 : #endif
990 20255 : va_end(args);
991 :
992 20255 : return pachBuffer;
993 : }
994 :
995 : /**********************************************************************
996 : * CSLAppendPrintf()
997 : *
998 : * Use CPLSPrintf() to append a new line at the end of a StringList.
999 : *
1000 : * Returns the modified StringList.
1001 : **********************************************************************/
1002 0 : char **CSLAppendPrintf(char **papszStrList, const char *fmt, ...)
1003 : {
1004 0 : CPLString osWork;
1005 : va_list args;
1006 :
1007 0 : va_start( args, fmt );
1008 0 : osWork.vPrintf( fmt, args );
1009 0 : va_end( args );
1010 :
1011 0 : return CSLAddString(papszStrList, osWork);
1012 : }
1013 :
1014 : /************************************************************************/
1015 : /* CPLVASPrintf() */
1016 : /* */
1017 : /* This is intended to serve as an easy to use C callabable */
1018 : /* vasprintf() alternative. Used in the geojson library for */
1019 : /* instance. */
1020 : /************************************************************************/
1021 :
1022 425 : int CPLVASPrintf( char **buf, const char *fmt, va_list ap )
1023 :
1024 : {
1025 425 : CPLString osWork;
1026 :
1027 425 : osWork.vPrintf( fmt, ap );
1028 :
1029 425 : if( buf )
1030 425 : *buf = strdup(osWork.c_str());
1031 :
1032 425 : return strlen(osWork);
1033 : }
1034 :
1035 : /************************************************************************/
1036 : /* CSLTestBoolean() */
1037 : /************************************************************************/
1038 :
1039 : /**
1040 : * Test what boolean value contained in the string.
1041 : *
1042 : * If pszValue is "NO", "FALSE", "OFF" or "0" will be returned FALSE.
1043 : * Otherwise, TRUE will be returned.
1044 : *
1045 : * @param pszValue the string should be tested.
1046 : *
1047 : * @return TRUE or FALSE.
1048 : */
1049 :
1050 655288 : int CSLTestBoolean( const char *pszValue )
1051 : {
1052 655288 : if( EQUAL(pszValue,"NO")
1053 : || EQUAL(pszValue,"FALSE")
1054 : || EQUAL(pszValue,"OFF")
1055 : || EQUAL(pszValue,"0") )
1056 642040 : return FALSE;
1057 : else
1058 13248 : return TRUE;
1059 : }
1060 :
1061 : /**********************************************************************
1062 : * CSLFetchBoolean()
1063 : *
1064 : * Check for boolean key value.
1065 : *
1066 : * In a StringList of "Name=Value" pairs, look to see if there is a key
1067 : * with the given name, and if it can be interpreted as being TRUE. If
1068 : * the key appears without any "=Value" portion it will be considered true.
1069 : * If the value is NO, FALSE or 0 it will be considered FALSE otherwise
1070 : * if the key appears in the list it will be considered TRUE. If the key
1071 : * doesn't appear at all, the indicated default value will be returned.
1072 : *
1073 : * @param papszStrList the string list to search.
1074 : * @param pszKey the key value to look for (case insensitive).
1075 : * @param bDefault the value to return if the key isn't found at all.
1076 : *
1077 : * @return TRUE or FALSE
1078 : **********************************************************************/
1079 :
1080 5033 : int CSLFetchBoolean( char **papszStrList, const char *pszKey, int bDefault )
1081 :
1082 : {
1083 : const char *pszValue;
1084 :
1085 5033 : if( CSLFindString( papszStrList, pszKey ) != -1 )
1086 0 : return TRUE;
1087 :
1088 5033 : pszValue = CSLFetchNameValue(papszStrList, pszKey );
1089 5033 : if( pszValue == NULL )
1090 4941 : return bDefault;
1091 : else
1092 92 : return CSLTestBoolean( pszValue );
1093 : }
1094 :
1095 : /************************************************************************/
1096 : /* CSLFetchNameValueDefaulted() */
1097 : /************************************************************************/
1098 :
1099 86 : const char *CSLFetchNameValueDef( char **papszStrList,
1100 : const char *pszName,
1101 : const char *pszDefault )
1102 :
1103 : {
1104 86 : const char *pszResult = CSLFetchNameValue( papszStrList, pszName );
1105 86 : if( pszResult )
1106 1 : return pszResult;
1107 : else
1108 85 : return pszDefault;
1109 : }
1110 :
1111 : /**********************************************************************
1112 : * CSLFetchNameValue()
1113 : *
1114 : * In a StringList of "Name=Value" pairs, look for the
1115 : * first value associated with the specified name. The search is not
1116 : * case sensitive.
1117 : * ("Name:Value" pairs are also supported for backward compatibility
1118 : * with older stuff.)
1119 : *
1120 : * Returns a reference to the value in the StringList that the caller
1121 : * should not attempt to free.
1122 : *
1123 : * Returns NULL if the name is not found.
1124 : **********************************************************************/
1125 806572 : const char *CSLFetchNameValue(char **papszStrList, const char *pszName)
1126 : {
1127 : size_t nLen;
1128 :
1129 806572 : if (papszStrList == NULL || pszName == NULL)
1130 33251 : return NULL;
1131 :
1132 773321 : nLen = strlen(pszName);
1133 6805970 : while(*papszStrList != NULL)
1134 : {
1135 5744796 : if (EQUALN(*papszStrList, pszName, nLen)
1136 242602 : && ( (*papszStrList)[nLen] == '=' ||
1137 354 : (*papszStrList)[nLen] == ':' ) )
1138 : {
1139 242512 : return (*papszStrList)+nLen+1;
1140 : }
1141 5259328 : papszStrList++;
1142 : }
1143 530809 : return NULL;
1144 : }
1145 :
1146 : /************************************************************************/
1147 : /* CSLFindName() */
1148 : /************************************************************************/
1149 :
1150 : /**
1151 : * Find StringList entry with given key name.
1152 : *
1153 : * @param papszStrList the string list to search.
1154 : * @param pszName the key value to look for (case insensitive).
1155 : *
1156 : * @return -1 on failure or the list index of the first occurance
1157 : * matching the given key.
1158 : */
1159 :
1160 10 : int CSLFindName(char **papszStrList, const char *pszName)
1161 : {
1162 : size_t nLen;
1163 10 : int iIndex = 0;
1164 :
1165 10 : if (papszStrList == NULL || pszName == NULL)
1166 4 : return -1;
1167 :
1168 6 : nLen = strlen(pszName);
1169 17 : while(*papszStrList != NULL)
1170 : {
1171 9 : if (EQUALN(*papszStrList, pszName, nLen)
1172 2 : && ( (*papszStrList)[nLen] == '=' ||
1173 0 : (*papszStrList)[nLen] == ':' ) )
1174 : {
1175 2 : return iIndex;
1176 : }
1177 5 : iIndex++;
1178 5 : papszStrList++;
1179 : }
1180 4 : return -1;
1181 : }
1182 :
1183 : /**********************************************************************
1184 : * CPLParseNameValue()
1185 : **********************************************************************/
1186 :
1187 : /**
1188 : * Parse NAME=VALUE string into name and value components.
1189 : *
1190 : * Note that if ppszKey is non-NULL, the key (or name) portion will be
1191 : * allocated using VSIMalloc(), and returned in that pointer. It is the
1192 : * applications responsibility to free this string, but the application should
1193 : * not modify or free the returned value portion.
1194 : *
1195 : * This function also support "NAME:VALUE" strings and will strip white
1196 : * space from around the delimeter when forming name and value strings.
1197 : *
1198 : * Eventually CSLFetchNameValue() and friends may be modified to use
1199 : * CPLParseNameValue().
1200 : *
1201 : * @param pszNameValue string in "NAME=VALUE" format.
1202 : * @param ppszKey optional pointer though which to return the name
1203 : * portion.
1204 : * @return the value portion (pointing into original string).
1205 : */
1206 :
1207 3864 : const char *CPLParseNameValue(const char *pszNameValue, char **ppszKey )
1208 :
1209 : {
1210 : int i;
1211 : const char *pszValue;
1212 :
1213 55179 : for( i = 0; pszNameValue[i] != '\0'; i++ )
1214 : {
1215 55168 : if( pszNameValue[i] == '=' || pszNameValue[i] == ':' )
1216 : {
1217 3853 : pszValue = pszNameValue + i + 1;
1218 8197 : while( *pszValue == ' ' || *pszValue == '\t' )
1219 491 : pszValue++;
1220 :
1221 3853 : if( ppszKey != NULL )
1222 : {
1223 3850 : *ppszKey = (char *) CPLMalloc(i+1);
1224 3850 : strncpy( *ppszKey, pszNameValue, i );
1225 3850 : (*ppszKey)[i] = '\0';
1226 15400 : while( i > 0 &&
1227 7700 : ( (*ppszKey)[i] == ' ' || (*ppszKey)[i] == '\t') )
1228 : {
1229 0 : (*ppszKey)[i] = '\0';
1230 0 : i--;
1231 : }
1232 : }
1233 :
1234 3853 : return pszValue;
1235 : }
1236 : }
1237 :
1238 11 : return NULL;
1239 : }
1240 :
1241 : /**********************************************************************
1242 : * CSLFetchNameValueMultiple()
1243 : *
1244 : * In a StringList of "Name=Value" pairs, look for all the
1245 : * values with the specified name. The search is not case
1246 : * sensitive.
1247 : * ("Name:Value" pairs are also supported for backward compatibility
1248 : * with older stuff.)
1249 : *
1250 : * Returns stringlist with one entry for each occurence of the
1251 : * specified name. The stringlist should eventually be destroyed
1252 : * by calling CSLDestroy().
1253 : *
1254 : * Returns NULL if the name is not found.
1255 : **********************************************************************/
1256 0 : char **CSLFetchNameValueMultiple(char **papszStrList, const char *pszName)
1257 : {
1258 : size_t nLen;
1259 0 : char **papszValues = NULL;
1260 :
1261 0 : if (papszStrList == NULL || pszName == NULL)
1262 0 : return NULL;
1263 :
1264 0 : nLen = strlen(pszName);
1265 0 : while(*papszStrList != NULL)
1266 : {
1267 0 : if (EQUALN(*papszStrList, pszName, nLen)
1268 0 : && ( (*papszStrList)[nLen] == '=' ||
1269 0 : (*papszStrList)[nLen] == ':' ) )
1270 : {
1271 : papszValues = CSLAddString(papszValues,
1272 0 : (*papszStrList)+nLen+1);
1273 : }
1274 0 : papszStrList++;
1275 : }
1276 :
1277 0 : return papszValues;
1278 : }
1279 :
1280 :
1281 : /**********************************************************************
1282 : * CSLAddNameValue()
1283 : *
1284 : * Add a new entry to a StringList of "Name=Value" pairs,
1285 : * ("Name:Value" pairs are also supported for backward compatibility
1286 : * with older stuff.)
1287 : *
1288 : * This function does not check if a "Name=Value" pair already exists
1289 : * for that name and can generate multiple entryes for the same name.
1290 : * Use CSLSetNameValue() if you want each name to have only one value.
1291 : *
1292 : * Returns the modified stringlist.
1293 : **********************************************************************/
1294 299126 : char **CSLAddNameValue(char **papszStrList,
1295 : const char *pszName, const char *pszValue)
1296 : {
1297 : char *pszLine;
1298 :
1299 299126 : if (pszName == NULL || pszValue==NULL)
1300 0 : return papszStrList;
1301 :
1302 299126 : pszLine = (char *) CPLMalloc(strlen(pszName)+strlen(pszValue)+2);
1303 299126 : sprintf( pszLine, "%s=%s", pszName, pszValue );
1304 299126 : papszStrList = CSLAddString(papszStrList, pszLine);
1305 299126 : CPLFree( pszLine );
1306 :
1307 299126 : return papszStrList;
1308 : }
1309 :
1310 : /************************************************************************/
1311 : /* CSLSetNameValue() */
1312 : /************************************************************************/
1313 :
1314 : /**
1315 : * Assign value to name in StringList.
1316 : *
1317 : * Set the value for a given name in a StringList of "Name=Value" pairs
1318 : * ("Name:Value" pairs are also supported for backward compatibility
1319 : * with older stuff.)
1320 : *
1321 : * If there is already a value for that name in the list then the value
1322 : * is changed, otherwise a new "Name=Value" pair is added.
1323 : *
1324 : * @param papszList the original list, the modified version is returned.
1325 : * @param pszName the name to be assigned a value. This should be a well
1326 : * formed token (no spaces or very special characters).
1327 : * @param pszValue the value to assign to the name. This should not contain
1328 : * any newlines (CR or LF) but is otherwise pretty much unconstrained. If
1329 : * NULL any corresponding value will be removed.
1330 : *
1331 : * @return modified stringlist.
1332 : */
1333 :
1334 298351 : char **CSLSetNameValue(char **papszList,
1335 : const char *pszName, const char *pszValue)
1336 : {
1337 : char **papszPtr;
1338 : size_t nLen;
1339 :
1340 298351 : if (pszName == NULL )
1341 0 : return papszList;
1342 :
1343 298351 : nLen = strlen(pszName);
1344 298351 : papszPtr = papszList;
1345 6841470 : while(papszPtr && *papszPtr != NULL)
1346 : {
1347 6247315 : if (EQUALN(*papszPtr, pszName, nLen)
1348 1256 : && ( (*papszPtr)[nLen] == '=' ||
1349 246 : (*papszPtr)[nLen] == ':' ) )
1350 : {
1351 : /* Found it!
1352 : * Change the value... make sure to keep the ':' or '='
1353 : */
1354 : char cSep;
1355 1045 : cSep = (*papszPtr)[nLen];
1356 :
1357 1045 : CPLFree(*papszPtr);
1358 :
1359 : /*
1360 : * If the value is NULL, remove this entry completely/
1361 : */
1362 1045 : if( pszValue == NULL )
1363 : {
1364 2 : while( papszPtr[1] != NULL )
1365 : {
1366 0 : *papszPtr = papszPtr[1];
1367 0 : papszPtr++;
1368 : }
1369 1 : *papszPtr = NULL;
1370 : }
1371 :
1372 : /*
1373 : * Otherwise replace with new value.
1374 : */
1375 : else
1376 : {
1377 1044 : *papszPtr = (char *) CPLMalloc(strlen(pszName)+strlen(pszValue)+2);
1378 1044 : sprintf( *papszPtr, "%s%c%s", pszName, cSep, pszValue );
1379 : }
1380 1045 : return papszList;
1381 : }
1382 6244768 : papszPtr++;
1383 : }
1384 :
1385 297306 : if( pszValue == NULL )
1386 0 : return papszList;
1387 :
1388 : /* The name does not exist yet... create a new entry
1389 : */
1390 297306 : return CSLAddNameValue(papszList, pszName, pszValue);
1391 : }
1392 :
1393 : /************************************************************************/
1394 : /* CSLSetNameValueSeparator() */
1395 : /************************************************************************/
1396 :
1397 : /**
1398 : * Replace the default separator (":" or "=") with the passed separator
1399 : * in the given name/value list.
1400 : *
1401 : * Note that if a separator other than ":" or "=" is used, the resulting
1402 : * list will not be manipulatable by the CSL name/value functions any more.
1403 : *
1404 : * The CPLParseNameValue() function is used to break the existing lines,
1405 : * and it also strips white space from around the existing delimiter, thus
1406 : * the old separator, and any white space will be replaced by the new
1407 : * separator. For formatting purposes it may be desireable to include some
1408 : * white space in the new separator. eg. ": " or " = ".
1409 : *
1410 : * @param papszList the list to update. Component strings may be freed
1411 : * but the list array will remain at the same location.
1412 : *
1413 : * @param pszSeparator the new separator string to insert.
1414 : *
1415 : */
1416 :
1417 30 : void CSLSetNameValueSeparator( char ** papszList, const char *pszSeparator )
1418 :
1419 : {
1420 30 : int nLines = CSLCount(papszList), iLine;
1421 :
1422 626 : for( iLine = 0; iLine < nLines; iLine++ )
1423 : {
1424 596 : char *pszKey = NULL;
1425 : const char *pszValue;
1426 : char *pszNewLine;
1427 :
1428 596 : pszValue = CPLParseNameValue( papszList[iLine], &pszKey );
1429 596 : if( pszValue == NULL || pszKey == NULL )
1430 0 : continue;
1431 :
1432 : pszNewLine = (char *) CPLMalloc( strlen(pszValue) + strlen(pszKey)
1433 596 : + strlen(pszSeparator) + 1 );
1434 596 : strcpy( pszNewLine, pszKey );
1435 596 : strcat( pszNewLine, pszSeparator );
1436 596 : strcat( pszNewLine, pszValue );
1437 596 : CPLFree( papszList[iLine] );
1438 596 : papszList[iLine] = pszNewLine;
1439 596 : CPLFree( pszKey );
1440 : }
1441 30 : }
1442 :
1443 : /************************************************************************/
1444 : /* CPLEscapeString() */
1445 : /************************************************************************/
1446 :
1447 : /**
1448 : * Apply escaping to string to preserve special characters.
1449 : *
1450 : * This function will "escape" a variety of special characters
1451 : * to make the string suitable to embed within a string constant
1452 : * or to write within a text stream but in a form that can be
1453 : * reconstitued to it's original form. The escaping will even preserve
1454 : * zero bytes allowing preservation of raw binary data.
1455 : *
1456 : * CPLES_BackslashQuotable(0): This scheme turns a binary string into
1457 : * a form suitable to be placed within double quotes as a string constant.
1458 : * The backslash, quote, '\\0' and newline characters are all escaped in
1459 : * the usual C style.
1460 : *
1461 : * CPLES_XML(1): This scheme converts the '<', '<' and '&' characters into
1462 : * their XML/HTML equivelent (>, < and &) making a string safe
1463 : * to embed as CDATA within an XML element. The '\\0' is not escaped and
1464 : * should not be included in the input.
1465 : *
1466 : * CPLES_URL(2): Everything except alphanumerics and the underscore are
1467 : * converted to a percent followed by a two digit hex encoding of the character
1468 : * (leading zero supplied if needed). This is the mechanism used for encoding
1469 : * values to be passed in URLs.
1470 : *
1471 : * CPLES_SQL(3): All single quotes are replaced with two single quotes.
1472 : * Suitable for use when constructing literal values for SQL commands where
1473 : * the literal will be enclosed in single quotes.
1474 : *
1475 : * CPLES_CSV(4): If the values contains commas, semicolons, tabs, double quotes, or newlines it
1476 : * placed in double quotes, and double quotes in the value are doubled.
1477 : * Suitable for use when constructing field values for .csv files. Note that
1478 : * CPLUnescapeString() currently does not support this format, only
1479 : * CPLEscapeString(). See cpl_csv.cpp for csv parsing support.
1480 : *
1481 : * @param pszInput the string to escape.
1482 : * @param nLength The number of bytes of data to preserve. If this is -1
1483 : * the strlen(pszString) function will be used to compute the length.
1484 : * @param nScheme the encoding scheme to use.
1485 : *
1486 : * @return an escaped, zero terminated string that should be freed with
1487 : * CPLFree() when no longer needed.
1488 : */
1489 :
1490 10005 : char *CPLEscapeString( const char *pszInput, int nLength,
1491 : int nScheme )
1492 :
1493 : {
1494 : char *pszOutput;
1495 : char *pszShortOutput;
1496 :
1497 10005 : if( nLength == -1 )
1498 9990 : nLength = strlen(pszInput);
1499 :
1500 10005 : pszOutput = (char *) CPLMalloc( nLength * 6 + 1 );
1501 :
1502 10005 : if( nScheme == CPLES_BackslashQuotable )
1503 : {
1504 15 : int iOut = 0, iIn;
1505 :
1506 1049837 : for( iIn = 0; iIn < nLength; iIn++ )
1507 : {
1508 1049822 : if( pszInput[iIn] == '\0' )
1509 : {
1510 351418 : pszOutput[iOut++] = '\\';
1511 351418 : pszOutput[iOut++] = '0';
1512 : }
1513 698404 : else if( pszInput[iIn] == '\n' )
1514 : {
1515 216 : pszOutput[iOut++] = '\\';
1516 216 : pszOutput[iOut++] = 'n';
1517 : }
1518 698188 : else if( pszInput[iIn] == '"' )
1519 : {
1520 1807 : pszOutput[iOut++] = '\\';
1521 1807 : pszOutput[iOut++] = '\"';
1522 : }
1523 696381 : else if( pszInput[iIn] == '\\' )
1524 : {
1525 2515 : pszOutput[iOut++] = '\\';
1526 2515 : pszOutput[iOut++] = '\\';
1527 : }
1528 : else
1529 693866 : pszOutput[iOut++] = pszInput[iIn];
1530 : }
1531 15 : pszOutput[iOut] = '\0';
1532 : }
1533 9990 : else if( nScheme == CPLES_URL ) /* Untested at implementation */
1534 : {
1535 0 : int iOut = 0, iIn;
1536 :
1537 0 : for( iIn = 0; iIn < nLength; iIn++ )
1538 : {
1539 0 : if( (pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z')
1540 0 : || (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z')
1541 0 : || (pszInput[iIn] >= '0' && pszInput[iIn] <= '9')
1542 0 : || pszInput[iIn] == '_' )
1543 : {
1544 0 : pszOutput[iOut++] = pszInput[iIn];
1545 : }
1546 : else
1547 : {
1548 0 : sprintf( pszOutput+iOut, "%%%02X", pszInput[iIn] );
1549 0 : iOut += 3;
1550 : }
1551 : }
1552 0 : pszOutput[iOut] = '\0';
1553 : }
1554 9990 : else if( nScheme == CPLES_XML )
1555 : {
1556 9912 : int iOut = 0, iIn;
1557 :
1558 240787 : for( iIn = 0; iIn < nLength; iIn++ )
1559 : {
1560 230875 : if( pszInput[iIn] == '<' )
1561 : {
1562 3 : pszOutput[iOut++] = '&';
1563 3 : pszOutput[iOut++] = 'l';
1564 3 : pszOutput[iOut++] = 't';
1565 3 : pszOutput[iOut++] = ';';
1566 : }
1567 230872 : else if( pszInput[iIn] == '>' )
1568 : {
1569 3 : pszOutput[iOut++] = '&';
1570 3 : pszOutput[iOut++] = 'g';
1571 3 : pszOutput[iOut++] = 't';
1572 3 : pszOutput[iOut++] = ';';
1573 : }
1574 230869 : else if( pszInput[iIn] == '&' )
1575 : {
1576 9 : pszOutput[iOut++] = '&';
1577 9 : pszOutput[iOut++] = 'a';
1578 9 : pszOutput[iOut++] = 'm';
1579 9 : pszOutput[iOut++] = 'p';
1580 9 : pszOutput[iOut++] = ';';
1581 : }
1582 230860 : else if( pszInput[iIn] == '"' )
1583 : {
1584 4842 : pszOutput[iOut++] = '&';
1585 4842 : pszOutput[iOut++] = 'q';
1586 4842 : pszOutput[iOut++] = 'u';
1587 4842 : pszOutput[iOut++] = 'o';
1588 4842 : pszOutput[iOut++] = 't';
1589 4842 : pszOutput[iOut++] = ';';
1590 : }
1591 : else
1592 226018 : pszOutput[iOut++] = pszInput[iIn];
1593 : }
1594 9912 : pszOutput[iOut] = '\0';
1595 : }
1596 78 : else if( nScheme == CPLES_SQL )
1597 : {
1598 0 : int iOut = 0, iIn;
1599 :
1600 0 : for( iIn = 0; iIn < nLength; iIn++ )
1601 : {
1602 0 : if( pszInput[iIn] == '\'' )
1603 : {
1604 0 : pszOutput[iOut++] = '\'';
1605 0 : pszOutput[iOut++] = '\'';
1606 : }
1607 : else
1608 0 : pszOutput[iOut++] = pszInput[iIn];
1609 : }
1610 0 : pszOutput[iOut] = '\0';
1611 : }
1612 78 : else if( nScheme == CPLES_CSV )
1613 : {
1614 146 : if( strchr( pszInput, '\"' ) == NULL
1615 : && strchr( pszInput, ',') == NULL
1616 : && strchr( pszInput, ';') == NULL
1617 : && strchr( pszInput, '\t') == NULL
1618 : && strchr( pszInput, 10) == NULL
1619 : && strchr( pszInput, 13) == NULL )
1620 : {
1621 68 : strcpy( pszOutput, pszInput );
1622 : }
1623 : else
1624 : {
1625 10 : int iOut = 1, iIn;
1626 :
1627 10 : pszOutput[0] = '\"';
1628 :
1629 444 : for( iIn = 0; iIn < nLength; iIn++ )
1630 : {
1631 434 : if( pszInput[iIn] == '\"' )
1632 : {
1633 6 : pszOutput[iOut++] = '\"';
1634 6 : pszOutput[iOut++] = '\"';
1635 : }
1636 428 : else if( pszInput[iIn] == 13 )
1637 : /* drop DOS LF's in strings. */;
1638 : else
1639 428 : pszOutput[iOut++] = pszInput[iIn];
1640 : }
1641 10 : pszOutput[iOut++] = '\"';
1642 10 : pszOutput[iOut++] = '\0';
1643 : }
1644 : }
1645 : else
1646 : {
1647 0 : pszOutput[0] = '\0';
1648 : CPLError( CE_Failure, CPLE_AppDefined,
1649 : "Undefined escaping scheme (%d) in CPLEscapeString()",
1650 0 : nScheme );
1651 : }
1652 :
1653 10005 : pszShortOutput = CPLStrdup( pszOutput );
1654 10005 : CPLFree( pszOutput );
1655 :
1656 10005 : return pszShortOutput;
1657 : }
1658 :
1659 : /************************************************************************/
1660 : /* CPLUnescapeString() */
1661 : /************************************************************************/
1662 :
1663 : /**
1664 : * Unescape a string.
1665 : *
1666 : * This function does the opposite of CPLEscapeString(). Given a string
1667 : * with special values escaped according to some scheme, it will return a
1668 : * new copy of the string returned to it's original form.
1669 : *
1670 : * @param pszInput the input string. This is a zero terminated string.
1671 : * @param pnLength location to return the length of the unescaped string,
1672 : * which may in some cases include embedded '\\0' characters.
1673 : * @param nScheme the escaped scheme to undo (see CPLEscapeString() for a
1674 : * list).
1675 : *
1676 : * @return a copy of the unescaped string that should be freed by the
1677 : * application using CPLFree() when no longer needed.
1678 : */
1679 :
1680 862 : char *CPLUnescapeString( const char *pszInput, int *pnLength, int nScheme )
1681 :
1682 : {
1683 : char *pszOutput;
1684 862 : int iOut=0, iIn;
1685 :
1686 862 : pszOutput = (char *) CPLMalloc(strlen(pszInput)+1);
1687 862 : pszOutput[0] = '\0';
1688 :
1689 862 : if( nScheme == CPLES_XML )
1690 : {
1691 94614 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1692 : {
1693 93841 : if( EQUALN(pszInput+iIn,"<",4) )
1694 : {
1695 6 : pszOutput[iOut++] = '<';
1696 6 : iIn += 3;
1697 : }
1698 93835 : else if( EQUALN(pszInput+iIn,">",4) )
1699 : {
1700 6 : pszOutput[iOut++] = '>';
1701 6 : iIn += 3;
1702 : }
1703 93829 : else if( EQUALN(pszInput+iIn,"&",5) )
1704 : {
1705 24 : pszOutput[iOut++] = '&';
1706 24 : iIn += 4;
1707 : }
1708 93805 : else if( EQUALN(pszInput+iIn,""",6) )
1709 : {
1710 8058 : pszOutput[iOut++] = '"';
1711 8058 : iIn += 5;
1712 : }
1713 : else
1714 : {
1715 85747 : pszOutput[iOut++] = pszInput[iIn];
1716 : }
1717 : }
1718 : }
1719 89 : else if( nScheme == CPLES_URL )
1720 : {
1721 0 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1722 : {
1723 0 : if( pszInput[iIn] == '%'
1724 0 : && pszInput[iIn+1] != '\0'
1725 0 : && pszInput[iIn+2] != '\0' )
1726 : {
1727 0 : int nHexChar = 0;
1728 :
1729 0 : if( pszInput[iIn+1] >= 'A' && pszInput[iIn+1] <= 'F' )
1730 0 : nHexChar += 16 * (pszInput[iIn+1] - 'A' + 10);
1731 0 : else 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] >= '0' && pszInput[iIn+1] <= '9' )
1734 0 : nHexChar += 16 * (pszInput[iIn+1] - '0');
1735 : else
1736 : CPLDebug( "CPL",
1737 : "Error unescaping CPLES_URL text, percent not "
1738 0 : "followed by two hex digits." );
1739 :
1740 0 : if( pszInput[iIn+2] >= 'A' && pszInput[iIn+2] <= 'F' )
1741 0 : nHexChar += pszInput[iIn+2] - 'A' + 10;
1742 0 : else if( pszInput[iIn+2] >= 'a' && pszInput[iIn+2] <= 'f' )
1743 0 : nHexChar += pszInput[iIn+2] - 'a' + 10;
1744 0 : else if( pszInput[iIn+2] >= '0' && pszInput[iIn+2] <= '9' )
1745 0 : nHexChar += pszInput[iIn+2] - '0';
1746 : else
1747 : CPLDebug( "CPL",
1748 : "Error unescaping CPLES_URL text, percent not "
1749 0 : "followed by two hex digits." );
1750 :
1751 0 : pszOutput[iOut++] = (char) nHexChar;
1752 0 : iIn += 2;
1753 : }
1754 0 : else if( pszInput[iIn] == '+' )
1755 : {
1756 0 : pszOutput[iOut++] = ' ';
1757 : }
1758 : else
1759 : {
1760 0 : pszOutput[iOut++] = pszInput[iIn];
1761 : }
1762 : }
1763 : }
1764 89 : else if( nScheme == CPLES_SQL )
1765 : {
1766 0 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1767 : {
1768 0 : if( pszInput[iIn] == '\'' && pszInput[iIn+1] == '\'' )
1769 : {
1770 0 : iIn++;
1771 0 : pszOutput[iOut++] = pszInput[iIn];
1772 : }
1773 : else
1774 : {
1775 0 : pszOutput[iOut++] = pszInput[iIn];
1776 : }
1777 : }
1778 : }
1779 : else /* if( nScheme == CPLES_BackslashQuoteable ) */
1780 : {
1781 1179 : for( iIn = 0; pszInput[iIn] != '\0'; iIn++ )
1782 : {
1783 1090 : if( pszInput[iIn] == '\\' )
1784 : {
1785 1 : iIn++;
1786 1 : if( pszInput[iIn] == 'n' )
1787 0 : pszOutput[iOut++] = '\n';
1788 1 : else if( pszInput[iIn] == '0' )
1789 1 : pszOutput[iOut++] = '\0';
1790 : else
1791 0 : pszOutput[iOut++] = pszInput[iIn];
1792 : }
1793 : else
1794 : {
1795 1089 : pszOutput[iOut++] = pszInput[iIn];
1796 : }
1797 : }
1798 : }
1799 :
1800 862 : pszOutput[iOut] = '\0';
1801 :
1802 862 : if( pnLength != NULL )
1803 263 : *pnLength = iOut;
1804 :
1805 862 : return pszOutput;
1806 : }
1807 :
1808 : /************************************************************************/
1809 : /* CPLBinaryToHex() */
1810 : /************************************************************************/
1811 :
1812 : /**
1813 : * Binary to hexadecimal translation.
1814 : *
1815 : * @param nBytes number of bytes of binary data in pabyData.
1816 : * @param pabyData array of data bytes to translate.
1817 : *
1818 : * @return hexadecimal translation, zero terminated. Free with CPLFree().
1819 : */
1820 :
1821 51 : char *CPLBinaryToHex( int nBytes, const GByte *pabyData )
1822 :
1823 : {
1824 51 : char *pszHex = (char *) CPLMalloc(nBytes * 2 + 1 );
1825 : int i;
1826 : static const char achHex[] = "0123456789ABCDEF";
1827 :
1828 51 : pszHex[nBytes*2] = '\0';
1829 :
1830 6159 : for( i = 0; i < nBytes; i++ )
1831 : {
1832 6108 : int nLow = pabyData[i] & 0x0f;
1833 6108 : int nHigh = (pabyData[i] & 0xf0) >> 4;
1834 :
1835 6108 : pszHex[i*2] = achHex[nHigh];
1836 6108 : pszHex[i*2+1] = achHex[nLow];
1837 : }
1838 :
1839 51 : return pszHex;
1840 : }
1841 :
1842 :
1843 : /************************************************************************/
1844 : /* CPLHexToBinary() */
1845 : /************************************************************************/
1846 :
1847 : /**
1848 : * Hexadecimal to binary translation
1849 : *
1850 : * @param pszHex the input hex encoded string.
1851 : * @param pnBytes the returned count of decoded bytes placed here.
1852 : *
1853 : * @return returns binary buffer of data - free with CPLFree().
1854 : */
1855 :
1856 2 : GByte *CPLHexToBinary( const char *pszHex, int *pnBytes )
1857 :
1858 : {
1859 2 : int iSrc = 0, iDst = 0;
1860 2 : size_t nHexLen = strlen(pszHex);
1861 :
1862 : GByte *pabyWKB;
1863 :
1864 2 : pabyWKB = (GByte *) CPLMalloc(nHexLen / 2 + 2);
1865 :
1866 33 : while( pszHex[iSrc] != '\0' )
1867 : {
1868 53 : if( pszHex[iSrc] >= '0' && pszHex[iSrc] <= '9' )
1869 24 : pabyWKB[iDst] = pszHex[iSrc] - '0';
1870 10 : else if( pszHex[iSrc] >= 'A' && pszHex[iSrc] <= 'F' )
1871 5 : pabyWKB[iDst] = pszHex[iSrc] - 'A' + 10;
1872 0 : else if( pszHex[iSrc] >= 'a' && pszHex[iSrc] <= 'f' )
1873 0 : pabyWKB[iDst] = pszHex[iSrc] - 'a' + 10;
1874 : else
1875 0 : break;
1876 :
1877 29 : pabyWKB[iDst] *= 16;
1878 :
1879 29 : iSrc++;
1880 :
1881 55 : if( pszHex[iSrc] >= '0' && pszHex[iSrc] <= '9' )
1882 26 : pabyWKB[iDst] += pszHex[iSrc] - '0';
1883 6 : else if( pszHex[iSrc] >= 'A' && pszHex[iSrc] <= 'F' )
1884 3 : pabyWKB[iDst] += pszHex[iSrc] - 'A' + 10;
1885 0 : else if( pszHex[iSrc] >= 'a' && pszHex[iSrc] <= 'f' )
1886 0 : pabyWKB[iDst] += pszHex[iSrc] - 'a' + 10;
1887 : else
1888 0 : break;
1889 :
1890 29 : iSrc++;
1891 29 : iDst++;
1892 : }
1893 :
1894 2 : pabyWKB[iDst] = 0;
1895 2 : *pnBytes = iDst;
1896 :
1897 2 : return pabyWKB;
1898 : }
1899 :
1900 :
1901 :
1902 : /************************************************************************/
1903 : /* CPLGetValueType() */
1904 : /************************************************************************/
1905 :
1906 : /**
1907 : * Detect the type of the value contained in a string, whether it is
1908 : * a real, an integer or a string
1909 : * Leading and trailing spaces are skipped in the analysis.
1910 : *
1911 : * @param pszValue the string to analyze
1912 : *
1913 : * @return returns the type of the value contained in the string.
1914 : */
1915 :
1916 126 : CPLValueType CPLGetValueType(const char* pszValue)
1917 : {
1918 : /*
1919 : doubles : "+25.e+3", "-25.e-3", "25.e3", "25e3", " 25e3 "
1920 : not doubles: "25e 3", "25e.3", "-2-5e3", "2-5e3", "25.25.3"
1921 : */
1922 :
1923 126 : int bFoundDot = FALSE;
1924 126 : int bFoundExponent = FALSE;
1925 126 : int bIsLastCharExponent = FALSE;
1926 126 : int bIsReal = FALSE;
1927 :
1928 126 : if (pszValue == NULL)
1929 0 : return CPL_VALUE_STRING;
1930 :
1931 : /* Skip leading + or - */
1932 126 : if (*pszValue == '+' || *pszValue == '-')
1933 0 : pszValue ++;
1934 :
1935 : /* Skip leading spaces */
1936 252 : while( isspace( (unsigned char)*pszValue ) )
1937 0 : pszValue ++;
1938 :
1939 414 : for(; *pszValue != '\0'; pszValue++ )
1940 : {
1941 298 : if( isdigit( *pszValue))
1942 : {
1943 252 : bIsLastCharExponent = FALSE;
1944 : /* do nothing */
1945 : }
1946 46 : else if ( isspace ((unsigned char)*pszValue) )
1947 : {
1948 0 : const char* pszTmp = pszValue;
1949 0 : while( isspace( (unsigned char)*pszTmp ) )
1950 0 : pszTmp ++;
1951 0 : if (*pszTmp == 0)
1952 0 : break;
1953 : else
1954 0 : return CPL_VALUE_STRING;
1955 : }
1956 46 : else if ( *pszValue == '-' || *pszValue == '+' )
1957 : {
1958 0 : if (bIsLastCharExponent)
1959 : {
1960 : /* do nothing */
1961 : }
1962 : else
1963 0 : return CPL_VALUE_STRING;
1964 0 : bIsLastCharExponent = FALSE;
1965 : }
1966 46 : else if ( *pszValue == '.')
1967 : {
1968 36 : bIsReal = TRUE;
1969 36 : if (!bFoundDot && bIsLastCharExponent == FALSE)
1970 36 : bFoundDot = TRUE;
1971 : else
1972 0 : return CPL_VALUE_STRING;
1973 36 : bIsLastCharExponent = FALSE;
1974 : }
1975 10 : else if (*pszValue == 'D' || *pszValue == 'd'
1976 : || *pszValue == 'E' || *pszValue == 'e' )
1977 : {
1978 0 : bIsReal = TRUE;
1979 0 : if (!bFoundExponent)
1980 0 : bFoundExponent = TRUE;
1981 : else
1982 0 : return CPL_VALUE_STRING;
1983 0 : bIsLastCharExponent = TRUE;
1984 : }
1985 : else
1986 : {
1987 10 : return CPL_VALUE_STRING;
1988 : }
1989 : }
1990 :
1991 116 : return (bIsReal) ? CPL_VALUE_REAL : CPL_VALUE_INTEGER;
1992 : }
1993 :
1994 : /************************************************************************/
1995 : /* CPLStrlcpy() */
1996 : /************************************************************************/
1997 :
1998 : /**
1999 : * Copy source string to a destination buffer.
2000 : *
2001 : * This function ensures that the destination buffer is always NUL terminated
2002 : * (provided that its length is at least 1).
2003 : *
2004 : * This function is designed to be a safer, more consistent, and less error
2005 : * prone replacement for strncpy. Its contract is identical to libbsd's strlcpy.
2006 : *
2007 : * Truncation can be detected by testing if the return value of CPLStrlcpy
2008 : * is greater or equal to nDestSize.
2009 :
2010 : \verbatim
2011 : char szDest[5];
2012 : if (CPLStrlcpy(szDest, "abcde", sizeof(szDest)) >= sizeof(szDest))
2013 : fprintf(stderr, "truncation occured !\n");
2014 : \endverbatim
2015 :
2016 : * @param pszDest destination buffer
2017 : * @param pszSrc source string. Must be NUL terminated
2018 : * @param nDestSize size of destination buffer (including space for the NUL terminator character)
2019 : *
2020 : * @return the length of the source string (=strlen(pszSrc))
2021 : *
2022 : * @since GDAL 1.7.0
2023 : */
2024 194520 : size_t CPLStrlcpy(char* pszDest, const char* pszSrc, size_t nDestSize)
2025 : {
2026 194520 : char* pszDestIter = pszDest;
2027 194520 : const char* pszSrcIter = pszSrc;
2028 :
2029 194520 : if (nDestSize == 0)
2030 0 : return strlen(pszSrc);
2031 :
2032 194520 : nDestSize --;
2033 1536732 : while(nDestSize != 0 && *pszSrcIter != '\0')
2034 : {
2035 1147692 : *pszDestIter = *pszSrcIter;
2036 1147692 : pszDestIter ++;
2037 1147692 : pszSrcIter ++;
2038 1147692 : nDestSize --;
2039 : }
2040 194520 : *pszDestIter = '\0';
2041 194520 : return pszSrcIter - pszSrc + strlen(pszSrcIter);
2042 : }
2043 :
2044 : /************************************************************************/
2045 : /* CPLStrlcat() */
2046 : /************************************************************************/
2047 :
2048 : /**
2049 : * Appends a source string to a destination buffer.
2050 : *
2051 : * This function ensures that the destination buffer is always NUL terminated
2052 : * (provided that its length is at least 1 and that there is at least one byte
2053 : * free in pszDest, that is to say strlen(pszDest_before) < nDestSize)
2054 : *
2055 : * This function is designed to be a safer, more consistent, and less error
2056 : * prone replacement for strncat. Its contract is identical to libbsd's strlcat.
2057 : *
2058 : * Truncation can be detected by testing if the return value of CPLStrlcat
2059 : * is greater or equal to nDestSize.
2060 :
2061 : \verbatim
2062 : char szDest[5];
2063 : CPLStrlcpy(szDest, "ab", sizeof(szDest));
2064 : if (CPLStrlcat(szDest, "cde", sizeof(szDest)) >= sizeof(szDest))
2065 : fprintf(stderr, "truncation occured !\n");
2066 : \endverbatim
2067 :
2068 : * @param pszDest destination buffer. Must be NUL terminated before running CPLStrlcat
2069 : * @param pszSrc source string. Must be NUL terminated
2070 : * @param nDestSize size of destination buffer (including space for the NUL terminator character)
2071 : *
2072 : * @return the thoretical length of the destination string after concatenation
2073 : * (=strlen(pszDest_before) + strlen(pszSrc)).
2074 : * If strlen(pszDest_before) >= nDestSize, then it returns nDestSize + strlen(pszSrc)
2075 : *
2076 : * @since GDAL 1.7.0
2077 : */
2078 99797 : size_t CPLStrlcat(char* pszDest, const char* pszSrc, size_t nDestSize)
2079 : {
2080 99797 : char* pszDestIter = pszDest;
2081 :
2082 1637761 : while(nDestSize != 0 && *pszDestIter != '\0')
2083 : {
2084 1438167 : pszDestIter ++;
2085 1438167 : nDestSize --;
2086 : }
2087 :
2088 99797 : return pszDestIter - pszDest + CPLStrlcpy(pszDestIter, pszSrc, nDestSize);
2089 : }
2090 :
2091 : /************************************************************************/
2092 : /* CPLStrnlen() */
2093 : /************************************************************************/
2094 :
2095 : /**
2096 : * Returns the length of a NUL terminated string by reading at most
2097 : * the specified number of bytes.
2098 : *
2099 : * The CPLStrnlen() function returns MIN(strlen(pszStr), nMaxLen).
2100 : * Only the first nMaxLen bytes of the string will be read. Usefull to
2101 : * test if a string contains at least nMaxLen characters without reading
2102 : * the full string up to the NUL terminating character.
2103 : *
2104 : * @param pszStr a NUL terminated string
2105 : * @param nMaxLen maximum number of bytes to read in pszStr
2106 : *
2107 : * @return strlen(pszStr) if the length is lesser than nMaxLen, otherwise
2108 : * nMaxLen if the NUL character has not been found in the first nMaxLen bytes.
2109 : *
2110 : * @since GDAL 1.7.0
2111 : */
2112 :
2113 3 : size_t CPLStrnlen (const char *pszStr, size_t nMaxLen)
2114 : {
2115 3 : size_t nLen = 0;
2116 54 : while(nLen < nMaxLen && *pszStr != '\0')
2117 : {
2118 48 : nLen ++;
2119 48 : pszStr ++;
2120 : }
2121 3 : return nLen;
2122 : }
|