Line data Source code
1 : /******************************************************************************
2 : *
3 : * Purpose: Various private (undocumented) utility functions.
4 : *
5 : ******************************************************************************
6 : * Copyright (c) 2009
7 : * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
8 : *
9 : * Permission is hereby granted, free of charge, to any person obtaining a
10 : * copy of this software and associated documentation files (the "Software"),
11 : * to deal in the Software without restriction, including without limitation
12 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 : * and/or sell copies of the Software, and to permit persons to whom the
14 : * Software is furnished to do so, subject to the following conditions:
15 : *
16 : * The above copyright notice and this permission notice shall be included
17 : * in all copies or substantial portions of the Software.
18 : *
19 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 : * DEALINGS IN THE SOFTWARE.
26 : ****************************************************************************/
27 :
28 : #include "pcidsk_config.h"
29 : #include "pcidsk_types.h"
30 : #include "pcidsk_buffer.h"
31 : #include "pcidsk_exception.h"
32 : #include "pcidsk_georef.h"
33 : #include "pcidsk_io.h"
34 : #include "core/pcidsk_utils.h"
35 : #include <cstdlib>
36 : #include <cstring>
37 : #include <cctype>
38 : #include <cstdio>
39 : #include <cmath>
40 : #include <cstdarg>
41 : #include <iostream>
42 :
43 : extern "C"
44 : {
45 : int CPL_DLL CPLToupper(int c);
46 : int CPL_DLL CPLTolower(int c);
47 : }
48 :
49 : #if !defined(va_copy) && defined(__va_copy)
50 : #define va_copy __va_copy
51 : #endif
52 :
53 : using namespace PCIDSK;
54 :
55 : /************************************************************************/
56 : /* GetCurrentDateTime() */
57 : /************************************************************************/
58 :
59 : // format we want: "HH:MM DDMMMYYYY \0"
60 :
61 : #include <time.h>
62 : #include <sys/types.h>
63 :
64 1365 : void PCIDSK::GetCurrentDateTime( char *out_time )
65 :
66 : {
67 : time_t clock;
68 1365 : char ctime_out[26] = {0};
69 :
70 1365 : time( &clock );
71 : #ifdef HAVE_CTIME_R
72 1365 : ctime_r(&clock, ctime_out);
73 : #elif defined(_WIN32)
74 : ctime_s(ctime_out, sizeof(ctime_out), &clock);
75 : #else
76 : strncpy( ctime_out, ctime(&clock), 25 );
77 : #endif
78 :
79 : // ctime() products: "Wed Jun 30 21:49:08 1993\n"
80 :
81 1365 : ctime_out[24] = '\0';
82 :
83 1365 : out_time[0] = ctime_out[11];
84 1365 : out_time[1] = ctime_out[12];
85 1365 : out_time[2] = ':';
86 1365 : out_time[3] = ctime_out[14];
87 1365 : out_time[4] = ctime_out[15];
88 1365 : out_time[5] = ' ';
89 1365 : out_time[6] = ctime_out[8];
90 1365 : out_time[7] = ctime_out[9];
91 1365 : out_time[8] = ctime_out[4];
92 1365 : out_time[9] = ctime_out[5];
93 1365 : out_time[10] = ctime_out[6];
94 1365 : out_time[11] = ctime_out[20];
95 1365 : out_time[12] = ctime_out[21];
96 1365 : out_time[13] = ctime_out[22];
97 1365 : out_time[14] = ctime_out[23];
98 1365 : out_time[15] = ' ';
99 1365 : out_time[16] = '\0';
100 1365 : }
101 :
102 : /************************************************************************/
103 : /* UCaseStr() */
104 : /* */
105 : /* Force a string into upper case "in place". */
106 : /************************************************************************/
107 :
108 130 : std::string &PCIDSK::UCaseStr( std::string &target )
109 :
110 : {
111 778 : for( unsigned int i = 0; i < target.size(); i++ )
112 : {
113 648 : target[i] = (char) CPLToupper(static_cast<unsigned char>(target[i]));
114 : }
115 :
116 130 : return target;
117 : }
118 :
119 : /************************************************************************/
120 : /* atouint64() */
121 : /************************************************************************/
122 :
123 541894 : uint64 PCIDSK::atouint64( const char *str_value )
124 :
125 : {
126 : #if defined(__MSVCRT__) || defined(_MSC_VER)
127 : return (uint64) _atoi64( str_value );
128 : #else
129 541894 : return (uint64) atoll( str_value );
130 : #endif
131 : }
132 :
133 : /************************************************************************/
134 : /* atoint64() */
135 : /************************************************************************/
136 :
137 0 : int64 PCIDSK::atoint64( const char *str_value )
138 :
139 : {
140 : #if defined(__MSVCRT__) || defined(_MSC_VER)
141 : return (int64) _atoi64( str_value );
142 : #else
143 0 : return (int64) atoll( str_value );
144 : #endif
145 : }
146 :
147 : /************************************************************************/
148 : /* SwapPixels() */
149 : /************************************************************************/
150 : /**
151 : * @brief Perform an endianness swap for a given buffer of pixels
152 : *
153 : * Baed on the provided data type, do an appropriate endianness swap for
154 : * a buffer of pixels. Deals with the Complex case specially, in
155 : * particular.
156 : *
157 : * @param data the pixels to be swapped
158 : * @param type the data type of the pixels
159 : * @param count the count of pixels (not bytes, words, etc.)
160 : */
161 184 : void PCIDSK::SwapPixels(void* const data,
162 : const eChanType type,
163 : const std::size_t count)
164 : {
165 184 : switch(type) {
166 144 : case CHN_8U:
167 : case CHN_16U:
168 : case CHN_16S:
169 : case CHN_32U:
170 : case CHN_32S:
171 : case CHN_32R:
172 : case CHN_64U:
173 : case CHN_64S:
174 : case CHN_64R:
175 144 : SwapData(data, DataTypeSize(type), static_cast<int>(count));
176 144 : break;
177 40 : case CHN_C16U:
178 : case CHN_C16S:
179 : case CHN_C32U:
180 : case CHN_C32S:
181 : case CHN_C32R:
182 40 : SwapData(data, DataTypeSize(type) / 2, static_cast<int>(count) * 2);
183 40 : break;
184 0 : default:
185 0 : return ThrowPCIDSKException("Unknown data type passed to SwapPixels."
186 0 : "This is a software bug. Please contact your vendor.");
187 : }
188 : }
189 :
190 : /************************************************************************/
191 : /* SwapData() */
192 : /************************************************************************/
193 : #if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ > 3
194 16051 : void PCIDSK::SwapData( void* const data, const int size, const int wcount )
195 : {
196 16051 : if(size == 2)
197 : {
198 2749 : uint16 * data16 = reinterpret_cast<uint16*>(data);
199 25792 : for(int i = 0; i < wcount; i++)
200 23043 : data16[i] = __builtin_bswap16(data16[i]);
201 : }
202 13302 : else if(size == 4)
203 : {
204 11850 : uint32 * data32 = reinterpret_cast<uint32*>(data);
205 51377 : for(int i = 0; i < wcount; i++)
206 39527 : data32[i] = __builtin_bswap32(data32[i]);
207 : }
208 1452 : else if(size == 8)
209 : {
210 1446 : uint64 * data64 = reinterpret_cast<uint64*>(data);
211 6538 : for(int i = 0; i < wcount; i++)
212 5092 : data64[i] = __builtin_bswap64(data64[i]);
213 : }
214 16051 : }
215 : #elif defined(_MSC_VER)
216 : #pragma intrinsic(_byteswap_ushort, _byteswap_ulong, _byteswap_uint64)
217 :
218 : void PCIDSK::SwapData( void* const data, const int size, const int wcount )
219 : {
220 : if(size == 2)
221 : {
222 : uint16 * data16 = reinterpret_cast<uint16*>(data);
223 : for(int i = 0; i < wcount; i++)
224 : data16[i] = _byteswap_ushort(data16[i]);
225 : }
226 : else if(size == 4)
227 : {
228 : uint32 * data32 = reinterpret_cast<uint32*>(data);
229 : for(int i = 0; i < wcount; i++)
230 : data32[i] = _byteswap_ulong(data32[i]);
231 : }
232 : else if(size == 8)
233 : {
234 : uint64 * data64 = reinterpret_cast<uint64*>(data);
235 : for(int i = 0; i < wcount; i++)
236 : data64[i] = _byteswap_uint64(data64[i]);
237 : }
238 : }
239 :
240 : #else
241 :
242 : void PCIDSK::SwapData( void* const data, const int size, const int wcount )
243 :
244 : {
245 : uint8* data8 = reinterpret_cast<uint8*>(data);
246 : std::size_t count = wcount;
247 :
248 : if( size == 2 )
249 : {
250 : uint8 t;
251 :
252 : for( ; count; count-- )
253 : {
254 : t = data8[0];
255 : data8[0] = data8[1];
256 : data8[1] = t;
257 :
258 : data8 += 2;
259 : }
260 : }
261 : else if( size == 1 )
262 : /* do nothing */;
263 : else if( size == 4 )
264 : {
265 : uint8 t;
266 :
267 : for( ; count; count-- )
268 : {
269 : t = data8[0];
270 : data8[0] = data8[3];
271 : data8[3] = t;
272 :
273 : t = data8[1];
274 : data8[1] = data8[2];
275 : data8[2] = t;
276 :
277 : data8 += 4;
278 : }
279 : }
280 : else if( size == 8 )
281 : {
282 : uint8 t;
283 :
284 : for( ; count; count-- )
285 : {
286 : t = data8[0];
287 : data8[0] = data8[7];
288 : data8[7] = t;
289 :
290 : t = data8[1];
291 : data8[1] = data8[6];
292 : data8[6] = t;
293 :
294 : t = data8[2];
295 : data8[2] = data8[5];
296 : data8[5] = t;
297 :
298 : t = data8[3];
299 : data8[3] = data8[4];
300 : data8[4] = t;
301 :
302 : data8 += 8;
303 : }
304 : }
305 : else
306 : return ThrowPCIDSKException( "Unsupported data size in SwapData()" );
307 : }
308 :
309 : #endif
310 :
311 : /************************************************************************/
312 : /* BigEndianSystem() */
313 : /************************************************************************/
314 :
315 6676 : bool PCIDSK::BigEndianSystem()
316 :
317 : {
318 6676 : unsigned short test_value = 1;
319 : char test_char_value[2];
320 :
321 6676 : memcpy( test_char_value, &test_value, 2 );
322 :
323 6676 : return test_char_value[0] == 0;
324 : }
325 :
326 :
327 : /************************************************************************/
328 : /* ParseTileFormat() */
329 : /* */
330 : /* Parse blocksize and compression out of a TILED interleaving */
331 : /* string as passed to the Create() function or stored in */
332 : /* _DBLayout metadata. */
333 : /************************************************************************/
334 :
335 7 : void PCIDSK::ParseTileFormat(const std::string& oOptionsIn,
336 : int & nTileSize, std::string & oCompress)
337 : {
338 7 : nTileSize = PCIDSK_DEFAULT_TILE_SIZE;
339 7 : oCompress = "NONE";
340 :
341 14 : std::string oOptions(oOptionsIn);
342 7 : UCaseStr(oOptions);
343 :
344 7 : std::string::size_type nStart = oOptions.find_first_not_of(" ");
345 7 : std::string::size_type nEnd = oOptions.find_first_of(" ", nStart);
346 :
347 22 : while (nStart != std::string::npos || nEnd != std::string::npos)
348 : {
349 30 : const std::string oToken = oOptions.substr(nStart, nEnd - nStart);
350 :
351 15 : if (oToken.size() > 5 && STARTS_WITH(oToken.c_str(), "TILED"))
352 : {
353 : // the TILED entry can be TILED# or TILED=#
354 6 : int nPos = oToken[5] == '=' ? 6 : 5;
355 :
356 6 : nTileSize = atoi(oToken.substr(nPos).c_str());
357 :
358 6 : if (nTileSize <= 0)
359 0 : ThrowPCIDSKException("Invalid tile option: %s", oToken.c_str());
360 : }
361 18 : else if (oToken == "NONE" || oToken == "RLE" ||
362 23 : STARTS_WITH(oToken.c_str(), "JPEG") ||
363 5 : STARTS_WITH(oToken.c_str(), "QUADTREE"))
364 : {
365 4 : oCompress = oToken;
366 : }
367 :
368 15 : nStart = oOptions.find_first_not_of(" ", nEnd);
369 15 : nEnd = oOptions.find_first_of(" ", nStart);
370 : }
371 7 : }
372 :
373 : /************************************************************************/
374 : /* ParseLinkedFilename() */
375 : /************************************************************************/
376 :
377 0 : std::string PCIDSK::ParseLinkedFilename(std::string oOptions)
378 : {
379 0 : std::string oToFind = "FILENOCREATE=";
380 0 : std::string oLinkedFileName;
381 :
382 0 : std::string::size_type nStart = oOptions.find_first_not_of(" ");
383 0 : std::string::size_type nEnd = oOptions.find_first_of(" ", nStart);
384 :
385 0 : while (nStart != std::string::npos || nEnd != std::string::npos)
386 : {
387 0 : std::string oToken = oOptions.substr(nStart, nEnd - nStart);
388 :
389 0 : if (oToken.size() > oToFind.size() &&
390 0 : strncmp(oToken.c_str(), oToFind.c_str(), oToFind.size()) == 0)
391 : {
392 0 : oLinkedFileName = oOptions.substr(nStart+oToFind.size());
393 0 : break;
394 : }
395 :
396 0 : nStart = oOptions.find_first_not_of(" ", nEnd);
397 0 : nEnd = oOptions.find_first_of(" ", nStart);
398 : }
399 :
400 0 : return oLinkedFileName;
401 : }
402 :
403 : /************************************************************************/
404 : /* pci_strcasecmp() */
405 : /************************************************************************/
406 :
407 0 : int PCIDSK::pci_strcasecmp( const char *string1, const char *string2 )
408 :
409 : {
410 : int i;
411 :
412 0 : for( i = 0; string1[i] != '\0' && string2[i] != '\0'; i++ )
413 : {
414 0 : char c1 = string1[i];
415 0 : char c2 = string2[i];
416 :
417 0 : c1 = (char) CPLToupper(static_cast<unsigned char>(c1));
418 0 : c2 = (char) CPLToupper(static_cast<unsigned char>(c2));
419 :
420 0 : if( c1 < c2 )
421 0 : return -1;
422 0 : else if( c1 > c2 )
423 0 : return 1;
424 : }
425 :
426 0 : if( string1[i] == '\0' && string2[i] == '\0' )
427 0 : return 0;
428 0 : else if( string1[i] == '\0' )
429 0 : return 1;
430 : else
431 0 : return -1;
432 : }
433 :
434 : /************************************************************************/
435 : /* pci_strncasecmp() */
436 : /************************************************************************/
437 :
438 0 : int PCIDSK::pci_strncasecmp( const char *string1, const char *string2, size_t len )
439 :
440 : {
441 0 : for( size_t i = 0; i < len; i++ )
442 : {
443 0 : if( string1[i] == '\0' && string2[i] == '\0' )
444 0 : return 0;
445 0 : else if( string1[i] == '\0' )
446 0 : return 1;
447 0 : else if( string2[i] == '\0' )
448 0 : return -1;
449 :
450 0 : char c1 = string1[i];
451 0 : char c2 = string2[i];
452 :
453 0 : c1 = (char) CPLToupper(static_cast<unsigned char>(c1));
454 0 : c2 = (char) CPLToupper(static_cast<unsigned char>(c2));
455 :
456 0 : if( c1 < c2 )
457 0 : return -1;
458 0 : else if( c1 > c2 )
459 0 : return 1;
460 : }
461 :
462 0 : return 0;
463 : }
464 :
465 : /************************************************************************/
466 : /* ProjParamsFromText() */
467 : /* */
468 : /* function to turn a ProjParams string (17 floating point */
469 : /* numbers) into an array, as well as attaching the units code */
470 : /* derived from the geosys string. */
471 : /************************************************************************/
472 :
473 1183 : std::vector<double> PCIDSK::ProjParamsFromText( std::string geosys,
474 : std::string sparms )
475 :
476 : {
477 1183 : std::vector<double> dparms;
478 :
479 1404 : for( const char* next = sparms.c_str(); *next != '\0'; )
480 : {
481 221 : dparms.push_back( CPLAtof(next) );
482 :
483 : // move past this token
484 442 : while( *next != '\0' && *next != ' ' )
485 221 : next++;
486 :
487 : // move past white space.
488 429 : while( *next == ' ' )
489 208 : next++;
490 : }
491 :
492 1183 : dparms.resize(18);
493 :
494 : // This is rather iffy!
495 1183 : if( STARTS_WITH_CI(geosys.c_str(), "DEG" /* "DEGREE" */) )
496 0 : dparms[17] = (double) (int) UNIT_DEGREE;
497 1183 : else if( STARTS_WITH_CI(geosys.c_str(), "MET") )
498 1171 : dparms[17] = (double) (int) UNIT_METER;
499 12 : else if( STARTS_WITH_CI(geosys.c_str(), "FOOT") )
500 0 : dparms[17] = (double) (int) UNIT_US_FOOT;
501 12 : else if( STARTS_WITH_CI(geosys.c_str(), "FEET") )
502 0 : dparms[17] = (double) (int) UNIT_US_FOOT;
503 12 : else if( STARTS_WITH_CI(geosys.c_str(), "INTL " /* "INTL FOOT" */) )
504 0 : dparms[17] = (double) (int) UNIT_INTL_FOOT;
505 12 : else if( STARTS_WITH_CI(geosys.c_str(), "SPCS") )
506 0 : dparms[17] = (double) (int) UNIT_METER;
507 12 : else if( STARTS_WITH_CI(geosys.c_str(), "SPIF") )
508 0 : dparms[17] = (double) (int) UNIT_INTL_FOOT;
509 12 : else if( STARTS_WITH_CI(geosys.c_str(), "SPAF") )
510 0 : dparms[17] = (double) (int) UNIT_US_FOOT;
511 : else
512 12 : dparms[17] = -1.0; /* unknown */
513 :
514 1183 : return dparms;
515 : }
516 :
517 : /************************************************************************/
518 : /* ProjParamsToText() */
519 : /************************************************************************/
520 :
521 6 : std::string PCIDSK::ProjParamsToText( std::vector<double> dparms )
522 :
523 : {
524 6 : std::string sparms;
525 :
526 108 : for( unsigned int i = 0; i < 17; i++ )
527 : {
528 : char value[64];
529 : double dvalue;
530 :
531 102 : if( i < dparms.size() )
532 102 : dvalue = dparms[i];
533 : else
534 0 : dvalue = 0.0;
535 :
536 102 : if( dvalue == floor(dvalue) )
537 102 : CPLsnprintf( value, sizeof(value), "%d", (int) dvalue );
538 : else
539 0 : CPLsnprintf( value, sizeof(value), "%.15g", dvalue );
540 :
541 102 : if( i > 0 )
542 96 : sparms += " ";
543 :
544 102 : sparms += value;
545 : }
546 :
547 6 : return sparms;
548 : }
549 :
550 : /************************************************************************/
551 : /* ExtractPath() */
552 : /* */
553 : /* Extract the directory path portion of the passed filename. */
554 : /* It assumes the last component is a filename and should not */
555 : /* be passed a bare path. The trailing directory delimiter is */
556 : /* removed from the result. The return result is an empty */
557 : /* string for a simple filename passed in with no directory */
558 : /* component. */
559 : /************************************************************************/
560 :
561 6 : std::string PCIDSK::ExtractPath( std::string filename )
562 :
563 : {
564 : int i;
565 :
566 90 : for( i = static_cast<int>(filename.size())-1; i >= 0; i-- )
567 : {
568 90 : if( filename[i] == '\\' || filename[i] == '/' )
569 6 : break;
570 : }
571 :
572 6 : if( i > 0 )
573 6 : return filename.substr(0,i);
574 : else
575 0 : return "";
576 : }
577 :
578 : /************************************************************************/
579 : /* DefaultMergeRelativePath() */
580 : /* */
581 : /* This attempts to take src_filename and make it relative to */
582 : /* the base of the file "base", if this evaluates to a new file */
583 : /* in the filesystem. It will not make any change if */
584 : /* src_filename appears to be absolute or if the altered path */
585 : /* does not resolve to a file in the filesystem. */
586 : /************************************************************************/
587 :
588 6 : std::string PCIDSK::DefaultMergeRelativePath(const PCIDSK::IOInterfaces *io_interfaces,
589 : const std::string& base,
590 : const std::string& src_filename)
591 :
592 : {
593 : /* -------------------------------------------------------------------- */
594 : /* Does src_filename appear to be absolute? */
595 : /* -------------------------------------------------------------------- */
596 6 : if( src_filename.empty() )
597 0 : return src_filename; // we can't do anything with a blank.
598 6 : else if( src_filename.size() > 2 && src_filename[1] == ':' )
599 0 : return src_filename; // has a drive letter?
600 6 : else if( src_filename[0] == '/' || src_filename[0] == '\\' )
601 0 : return src_filename; // has a leading dir marker.
602 :
603 : /* -------------------------------------------------------------------- */
604 : /* Figure out what path split char we want to use. */
605 : /* -------------------------------------------------------------------- */
606 : #if defined(__MSVCRT__) || defined(_MSC_VER)
607 : const static char path_split = '\\';
608 : #else
609 : const static char path_split = '/';
610 : #endif
611 :
612 : /* -------------------------------------------------------------------- */
613 : /* Merge paths. */
614 : /* -------------------------------------------------------------------- */
615 12 : std::string result = ExtractPath( base );
616 :
617 6 : if( result.empty() )
618 0 : return src_filename;
619 :
620 6 : result += path_split;
621 6 : result += src_filename;
622 :
623 : /* -------------------------------------------------------------------- */
624 : /* Check if the target exists by this name. */
625 : /* -------------------------------------------------------------------- */
626 : try
627 : {
628 8 : void *hFile = io_interfaces->Open( result, "r" );
629 : // should throw an exception on failure.
630 5 : io_interfaces->Close( hFile );
631 5 : return result;
632 : }
633 2 : catch( ... )
634 : {
635 1 : return src_filename;
636 : }
637 : }
638 :
639 :
640 : /************************************************************************/
641 : /* DefaultDebug() */
642 : /* */
643 : /* Default implementation of the Debug() output interface. */
644 : /************************************************************************/
645 :
646 0 : void PCIDSK::DefaultDebug( const char * message )
647 :
648 : {
649 : static bool initialized = false;
650 : static bool enabled = false;
651 :
652 0 : if( !initialized )
653 : {
654 0 : if( getenv( "PCIDSK_DEBUG" ) != nullptr )
655 0 : enabled = true;
656 :
657 0 : initialized = true;
658 : }
659 :
660 0 : if( enabled )
661 0 : std::cerr << message;
662 0 : }
663 :
664 : /************************************************************************/
665 : /* vDebug() */
666 : /* */
667 : /* Helper function for Debug(). */
668 : /************************************************************************/
669 :
670 0 : static void vDebug( void (*pfnDebug)(const char *),
671 : const char *fmt, std::va_list args )
672 :
673 : {
674 0 : std::string message;
675 :
676 : /* -------------------------------------------------------------------- */
677 : /* This implementation for platforms without vsnprintf() will */
678 : /* just plain fail if the formatted contents are too large. */
679 : /* -------------------------------------------------------------------- */
680 : #if defined(MISSING_VSNPRINTF)
681 : char *pszBuffer = (char *) malloc(30000);
682 : if( vsprintf( pszBuffer, fmt, args) > 29998 )
683 : {
684 : message = "PCIDSK::Debug() ... buffer overrun.";
685 : }
686 : else
687 : message = pszBuffer;
688 :
689 : free( pszBuffer );
690 :
691 : /* -------------------------------------------------------------------- */
692 : /* This should grow a big enough buffer to hold any formatted */
693 : /* result. */
694 : /* -------------------------------------------------------------------- */
695 : #else
696 : char szModestBuffer[500];
697 : int nPR;
698 : va_list wrk_args;
699 :
700 : #ifdef va_copy
701 0 : va_copy( wrk_args, args );
702 : #else
703 : wrk_args = args;
704 : #endif
705 :
706 0 : nPR = vsnprintf( szModestBuffer, sizeof(szModestBuffer), fmt,
707 : wrk_args );
708 0 : if( nPR == -1 || nPR >= (int) sizeof(szModestBuffer)-1 )
709 : {
710 0 : int nWorkBufferSize = 2000;
711 0 : PCIDSKBuffer oWorkBuffer(nWorkBufferSize);
712 :
713 : #ifdef va_copy
714 0 : va_end( wrk_args );
715 0 : va_copy( wrk_args, args );
716 : #else
717 : wrk_args = args;
718 : #endif
719 0 : while( (nPR=vsnprintf( oWorkBuffer.buffer, nWorkBufferSize, fmt, wrk_args))
720 0 : >= nWorkBufferSize-1
721 0 : || nPR == -1 )
722 : {
723 0 : nWorkBufferSize *= 4;
724 0 : oWorkBuffer.SetSize(nWorkBufferSize);
725 : #ifdef va_copy
726 0 : va_end( wrk_args );
727 0 : va_copy( wrk_args, args );
728 : #else
729 : wrk_args = args;
730 : #endif
731 : }
732 0 : message = oWorkBuffer.buffer;
733 : }
734 : else
735 : {
736 0 : message = szModestBuffer;
737 : }
738 0 : va_end( wrk_args );
739 : #endif
740 :
741 : /* -------------------------------------------------------------------- */
742 : /* Forward the message. */
743 : /* -------------------------------------------------------------------- */
744 0 : pfnDebug( message.c_str() );
745 0 : }
746 :
747 : /************************************************************************/
748 : /* Debug() */
749 : /* */
750 : /* Function to write output to a debug stream if one is */
751 : /* enabled. This is intended to be widely called in the */
752 : /* library. */
753 : /************************************************************************/
754 :
755 0 : void PCIDSK::Debug( void (*pfnDebug)(const char *), const char *fmt, ... )
756 :
757 : {
758 0 : if( pfnDebug == nullptr )
759 0 : return;
760 :
761 : std::va_list args;
762 :
763 0 : va_start( args, fmt );
764 0 : vDebug( pfnDebug, fmt, args );
765 0 : va_end( args );
766 : }
|