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