1 : /******************************************************************************
2 : * $Id: cplstring.cpp 23406 2011-11-21 19:29:41Z rouault $
3 : *
4 : * Project: GDAL
5 : * Purpose: CPLString implementation.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_string.h"
31 : #include <string>
32 :
33 : CPL_CVSID("$Id: cplstring.cpp 23406 2011-11-21 19:29:41Z rouault $");
34 :
35 : /*
36 : * The CPLString class is derived from std::string, so the vast majority
37 : * of the implementation comes from that. This module is just the extensions
38 : * we add.
39 : */
40 :
41 : /************************************************************************/
42 : /* Printf() */
43 : /************************************************************************/
44 :
45 266899 : CPLString &CPLString::Printf( const char *pszFormat, ... )
46 :
47 : {
48 : va_list args;
49 :
50 266899 : va_start( args, pszFormat );
51 266899 : vPrintf( pszFormat, args );
52 266899 : va_end( args );
53 :
54 266899 : return *this;
55 : }
56 :
57 : /************************************************************************/
58 : /* vPrintf() */
59 : /************************************************************************/
60 :
61 312725 : CPLString &CPLString::vPrintf( const char *pszFormat, va_list args )
62 :
63 : {
64 : /* -------------------------------------------------------------------- */
65 : /* This implementation for platforms without vsnprintf() will */
66 : /* just plain fail if the formatted contents are too large. */
67 : /* -------------------------------------------------------------------- */
68 :
69 : #if !defined(HAVE_VSNPRINTF)
70 : char *pszBuffer = (char *) CPLMalloc(30000);
71 : if( vsprintf( pszBuffer, pszFormat, args) > 29998 )
72 : {
73 : CPLError( CE_Fatal, CPLE_AppDefined,
74 : "CPLString::vPrintf() ... buffer overrun." );
75 : }
76 : *this = pszBuffer;
77 : CPLFree( pszBuffer );
78 :
79 : /* -------------------------------------------------------------------- */
80 : /* This should grow a big enough buffer to hold any formatted */
81 : /* result. */
82 : /* -------------------------------------------------------------------- */
83 : #else
84 : char szModestBuffer[500];
85 : int nPR;
86 : va_list wrk_args;
87 :
88 : #ifdef va_copy
89 312725 : va_copy( wrk_args, args );
90 : #else
91 : wrk_args = args;
92 : #endif
93 :
94 : nPR = vsnprintf( szModestBuffer, sizeof(szModestBuffer), pszFormat,
95 312725 : wrk_args );
96 314832 : if( nPR == -1 || nPR >= (int) sizeof(szModestBuffer)-1 )
97 : {
98 2107 : int nWorkBufferSize = 2000;
99 2107 : char *pszWorkBuffer = (char *) CPLMalloc(nWorkBufferSize);
100 :
101 : #ifdef va_copy
102 2107 : va_end( wrk_args );
103 2107 : va_copy( wrk_args, args );
104 : #else
105 : wrk_args = args;
106 : #endif
107 4312 : while( (nPR=vsnprintf( pszWorkBuffer, nWorkBufferSize, pszFormat,wrk_args))
108 : >= nWorkBufferSize-1
109 : || nPR == -1 )
110 : {
111 98 : nWorkBufferSize *= 4;
112 : pszWorkBuffer = (char *) CPLRealloc(pszWorkBuffer,
113 98 : nWorkBufferSize );
114 : #ifdef va_copy
115 98 : va_end( wrk_args );
116 98 : va_copy( wrk_args, args );
117 : #else
118 : wrk_args = args;
119 : #endif
120 : }
121 2107 : *this = pszWorkBuffer;
122 2107 : CPLFree( pszWorkBuffer );
123 : }
124 : else
125 : {
126 310618 : *this = szModestBuffer;
127 : }
128 312725 : va_end( wrk_args );
129 : #endif
130 :
131 312725 : return *this;
132 : }
133 :
134 : /************************************************************************/
135 : /* FormatC() */
136 : /************************************************************************/
137 :
138 : /**
139 : * Format double in C locale.
140 : *
141 : * The passed value is formatted using the C locale (period as decimal
142 : * seperator) and appended to the target CPLString.
143 : *
144 : * @param dfValue the value to format.
145 : * @param pszFormat the sprintf() style format to use or omit for default.
146 : * Note that this format string should only include one substitution argument
147 : * and it must be for a double (%f or %g).
148 : *
149 : * @return a reference to the CPLString.
150 : */
151 :
152 846 : CPLString &CPLString::FormatC( double dfValue, const char *pszFormat )
153 :
154 : {
155 846 : if( pszFormat == NULL )
156 12 : pszFormat = "%g";
157 :
158 : char szWork[512]; // presumably long enough for any number?
159 :
160 846 : sprintf( szWork, pszFormat, dfValue );
161 846 : CPLAssert( strlen(szWork) < sizeof(szWork) );
162 :
163 846 : if( strchr( szWork, ',' ) != NULL )
164 : {
165 0 : char *pszDelim = strchr( szWork, ',' );
166 0 : *pszDelim = '.';
167 : }
168 :
169 846 : *this += szWork;
170 :
171 846 : return *this;
172 : }
173 :
174 : /************************************************************************/
175 : /* Trim() */
176 : /************************************************************************/
177 :
178 : /**
179 : * Trim white space.
180 : *
181 : * Trims white space off the let and right of the string. White space
182 : * is any of a space, a tab, a newline ('\n') or a carriage control ('\r').
183 : *
184 : * @return a reference to the CPLString.
185 : */
186 :
187 44042 : CPLString &CPLString::Trim()
188 :
189 : {
190 : size_t iLeft, iRight;
191 : static const char szWhitespace[] = " \t\r\n";
192 :
193 44042 : iLeft = find_first_not_of( szWhitespace );
194 44042 : iRight = find_last_not_of( szWhitespace );
195 :
196 44042 : if( iLeft == std::string::npos )
197 : {
198 10032 : erase();
199 10032 : return *this;
200 : }
201 :
202 34010 : assign( substr( iLeft, iRight - iLeft + 1 ) );
203 :
204 34010 : return *this;
205 : }
206 :
207 : /************************************************************************/
208 : /* Recode() */
209 : /************************************************************************/
210 :
211 604 : CPLString &CPLString::Recode( const char *pszSrcEncoding,
212 : const char *pszDstEncoding )
213 :
214 : {
215 604 : if( pszSrcEncoding == NULL )
216 0 : pszSrcEncoding = CPL_ENC_UTF8;
217 604 : if( pszDstEncoding == NULL )
218 0 : pszDstEncoding = CPL_ENC_UTF8;
219 :
220 604 : if( strcmp(pszSrcEncoding,pszDstEncoding) == 0 )
221 0 : return *this;
222 :
223 : char *pszRecoded = CPLRecode( c_str(),
224 : pszSrcEncoding,
225 604 : pszDstEncoding );
226 :
227 604 : if( pszRecoded == NULL )
228 0 : return *this;
229 :
230 604 : assign( pszRecoded );
231 604 : CPLFree( pszRecoded );
232 :
233 604 : return *this;
234 : }
235 :
236 : /************************************************************************/
237 : /* ifind() */
238 : /************************************************************************/
239 :
240 : /**
241 : * Case insensitive find() alternative.
242 : *
243 : * @param str substring to find.
244 : * @param pos offset in the string at which the search starts.
245 : * @return the position of substring in the string or std::string::npos if not found.
246 : * @since GDAL 1.9.0
247 : */
248 :
249 1300 : size_t CPLString::ifind( const std::string & str, size_t pos ) const
250 :
251 : {
252 1300 : return ifind( str.c_str(), pos );
253 : }
254 :
255 : /**
256 : * Case insensitive find() alternative.
257 : *
258 : * @param s substring to find.
259 : * @param nPos offset in the string at which the search starts.
260 : * @return the position of the substring in the string or std::string::npos if not found.
261 : * @since GDAL 1.9.0
262 : */
263 :
264 27330 : size_t CPLString::ifind( const char *s, size_t nPos ) const
265 :
266 : {
267 27330 : const char *pszHaystack = c_str();
268 27330 : char chFirst = (char) ::tolower( s[0] );
269 27330 : int nTargetLen = strlen(s);
270 :
271 27330 : if( nPos > size() )
272 0 : nPos = size();
273 :
274 27330 : pszHaystack += nPos;
275 :
276 936344 : while( *pszHaystack != '\0' )
277 : {
278 883530 : if( chFirst == ::tolower(*pszHaystack) )
279 : {
280 54456 : if( EQUALN(pszHaystack,s,nTargetLen) )
281 1846 : return nPos;
282 : }
283 :
284 881684 : nPos++;
285 881684 : pszHaystack++;
286 : }
287 :
288 25484 : return std::string::npos;
289 : }
290 :
291 : /************************************************************************/
292 : /* toupper() */
293 : /************************************************************************/
294 :
295 : /**
296 : * Convert to upper case in place.
297 : */
298 :
299 0 : CPLString &CPLString::toupper()
300 :
301 : {
302 : size_t i;
303 :
304 0 : for( i = 0; i < size(); i++ )
305 0 : (*this)[i] = (char) ::toupper( (*this)[i] );
306 :
307 0 : return *this;
308 : }
309 :
310 : /************************************************************************/
311 : /* tolower() */
312 : /************************************************************************/
313 :
314 : /**
315 : * Convert to lower case in place.
316 : */
317 :
318 8042 : CPLString &CPLString::tolower()
319 :
320 : {
321 : size_t i;
322 :
323 55030 : for( i = 0; i < size(); i++ )
324 46988 : (*this)[i] = (char) ::tolower( (*this)[i] );
325 :
326 8042 : return *this;
327 : }
328 :
329 : /************************************************************************/
330 : /* CPLURLGetValue() */
331 : /************************************************************************/
332 :
333 : /**
334 : * Return the value matching a key from a key=value pair in a URL.
335 : *
336 : * @param pszURL the URL.
337 : * @param pszKey the key to find.
338 : * @return the value of empty string if not found.
339 : * @since GDAL 1.9.0
340 : */
341 744 : CPLString CPLURLGetValue(const char* pszURL, const char* pszKey)
342 : {
343 744 : CPLString osKey(pszKey);
344 744 : osKey += "=";
345 744 : size_t nKeyPos = CPLString(pszURL).ifind(osKey);
346 776 : if (nKeyPos != std::string::npos && nKeyPos > 0 &&
347 32 : (pszURL[nKeyPos-1] == '?' || pszURL[nKeyPos-1] == '&'))
348 : {
349 20 : CPLString osValue(pszURL + nKeyPos + strlen(osKey));
350 20 : const char* pszValue = osValue.c_str();
351 20 : const char* pszSep = strchr(pszValue, '&');
352 20 : if (pszSep)
353 : {
354 16 : osValue.resize(pszSep - pszValue);
355 : }
356 20 : return osValue;
357 : }
358 724 : return "";
359 : }
360 :
361 : /************************************************************************/
362 : /* CPLURLAddKVP() */
363 : /************************************************************************/
364 :
365 : /**
366 : * Return a new URL with a new key=value pair.
367 : *
368 : * @param pszURL the URL.
369 : * @param pszKey the key to find.
370 : * @param pszValue the value of the key (may be NULL to unset an existing KVP).
371 : * @return the modified URL.
372 : * @since GDAL 1.9.0
373 : */
374 556 : CPLString CPLURLAddKVP(const char* pszURL, const char* pszKey,
375 : const char* pszValue)
376 : {
377 556 : CPLString osURL(pszURL);
378 556 : if (strchr(osURL, '?') == NULL)
379 24 : osURL += "?";
380 556 : pszURL = osURL.c_str();
381 :
382 556 : CPLString osKey(pszKey);
383 556 : osKey += "=";
384 556 : size_t nKeyPos = osURL.ifind(osKey);
385 604 : if (nKeyPos != std::string::npos && nKeyPos > 0 &&
386 48 : (pszURL[nKeyPos-1] == '?' || pszURL[nKeyPos-1] == '&'))
387 : {
388 34 : CPLString osNewURL(osURL);
389 34 : osNewURL.resize(nKeyPos);
390 34 : if (pszValue)
391 : {
392 6 : osNewURL += osKey;
393 6 : osNewURL += pszValue;
394 : }
395 34 : const char* pszNext = strchr(pszURL + nKeyPos, '&');
396 34 : if (pszNext)
397 : {
398 32 : if (osNewURL[osNewURL.size()-1] == '&'
399 : || osNewURL[osNewURL.size()-1] == '?' )
400 26 : osNewURL += pszNext + 1;
401 : else
402 6 : osNewURL += pszNext;
403 : }
404 34 : return osNewURL;
405 : }
406 : else
407 : {
408 522 : if (pszValue)
409 : {
410 314 : if (osURL[osURL.size()-1] != '&' && osURL[osURL.size()-1] != '?')
411 290 : osURL += '&';
412 314 : osURL += osKey;
413 314 : osURL += pszValue;
414 : }
415 522 : return osURL;
416 0 : }
417 : }
|