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