1 : /******************************************************************************
2 : * $Id: ecwdataset.cpp 23321 2011-11-05 13:20:20Z rouault $
3 : *
4 : * Project: GDAL
5 : * Purpose: ECW (ERDAS Wavelet Compression Format) Driver
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2001, 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 "gdal_ecw.h"
31 : #include "cpl_minixml.h"
32 : #include "ogr_spatialref.h"
33 : #include "ogr_api.h"
34 : #include "ogr_geometry.h"
35 :
36 : CPL_CVSID("$Id: ecwdataset.cpp 23321 2011-11-05 13:20:20Z rouault $");
37 :
38 : #undef NOISY_DEBUG
39 :
40 : #ifdef FRMT_ecw
41 :
42 : static const unsigned char jpc_header[] = {0xff,0x4f};
43 : static const unsigned char jp2_header[] =
44 : {0x00,0x00,0x00,0x0c,0x6a,0x50,0x20,0x20,0x0d,0x0a,0x87,0x0a};
45 :
46 : static void *hECWDatasetMutex = NULL;
47 : static int bNCSInitialized = FALSE;
48 :
49 : void ECWInitialize( void );
50 :
51 : GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo);
52 :
53 : /************************************************************************/
54 : /* ECWRasterBand() */
55 : /************************************************************************/
56 :
57 386 : ECWRasterBand::ECWRasterBand( ECWDataset *poDS, int nBand, int iOverview )
58 :
59 : {
60 386 : this->poDS = poDS;
61 386 : poGDS = poDS;
62 :
63 386 : this->iOverview = iOverview;
64 386 : this->nBand = nBand;
65 386 : eDataType = poDS->eRasterDataType;
66 :
67 386 : nRasterXSize = poDS->GetRasterXSize() / ( 1 << (iOverview+1));
68 386 : nRasterYSize = poDS->GetRasterYSize() / ( 1 << (iOverview+1));
69 :
70 386 : nBlockXSize = nRasterXSize;
71 386 : nBlockYSize = 1;
72 :
73 : /* -------------------------------------------------------------------- */
74 : /* Work out band color interpretation. */
75 : /* -------------------------------------------------------------------- */
76 386 : if( poDS->psFileInfo->eColorSpace == NCSCS_NONE )
77 0 : eBandInterp = GCI_Undefined;
78 386 : else if( poDS->psFileInfo->eColorSpace == NCSCS_GREYSCALE )
79 70 : eBandInterp = GCI_GrayIndex;
80 316 : else if( poDS->psFileInfo->eColorSpace == NCSCS_MULTIBAND )
81 56 : eBandInterp = GCI_Undefined;
82 260 : else if( poDS->psFileInfo->eColorSpace == NCSCS_sRGB )
83 : {
84 260 : if( nBand == 1 )
85 86 : eBandInterp = GCI_RedBand;
86 174 : else if( nBand == 2 )
87 86 : eBandInterp = GCI_GreenBand;
88 88 : else if( nBand == 3 )
89 86 : eBandInterp = GCI_BlueBand;
90 2 : else if( nBand == 4 )
91 2 : eBandInterp = GCI_AlphaBand;
92 : else
93 0 : eBandInterp = GCI_Undefined;
94 : }
95 0 : else if( poDS->psFileInfo->eColorSpace == NCSCS_YCbCr )
96 : {
97 0 : if( CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ))
98 : {
99 0 : if( nBand == 1 )
100 0 : eBandInterp = GCI_RedBand;
101 0 : else if( nBand == 2 )
102 0 : eBandInterp = GCI_GreenBand;
103 0 : else if( nBand == 3 )
104 0 : eBandInterp = GCI_BlueBand;
105 : else
106 0 : eBandInterp = GCI_Undefined;
107 : }
108 : else
109 : {
110 0 : if( nBand == 1 )
111 0 : eBandInterp = GCI_YCbCr_YBand;
112 0 : else if( nBand == 2 )
113 0 : eBandInterp = GCI_YCbCr_CbBand;
114 0 : else if( nBand == 3 )
115 0 : eBandInterp = GCI_YCbCr_CrBand;
116 : else
117 0 : eBandInterp = GCI_Undefined;
118 : }
119 : }
120 : else
121 0 : eBandInterp = GCI_Undefined;
122 :
123 : /* -------------------------------------------------------------------- */
124 : /* If this is the base level, create a set of overviews. */
125 : /* -------------------------------------------------------------------- */
126 386 : if( iOverview == -1 )
127 : {
128 : int i;
129 386 : for( i = 0;
130 : nRasterXSize / (1 << (i+1)) > 128
131 : && nRasterYSize / (1 << (i+1)) > 128;
132 : i++ )
133 : {
134 156 : apoOverviews.push_back( new ECWRasterBand( poDS, nBand, i ) );
135 : }
136 : }
137 :
138 386 : if( (poDS->psFileInfo->pBands[nBand-1].nBits % 8) != 0 )
139 : SetMetadataItem("NBITS",
140 8 : CPLString().Printf("%d",poDS->psFileInfo->pBands[nBand-1].nBits),
141 8 : "IMAGE_STRUCTURE" );
142 386 : }
143 :
144 : /************************************************************************/
145 : /* ~ECWRasterBand() */
146 : /************************************************************************/
147 :
148 386 : ECWRasterBand::~ECWRasterBand()
149 :
150 : {
151 386 : FlushCache();
152 :
153 928 : while( apoOverviews.size() > 0 )
154 : {
155 156 : delete apoOverviews.back();
156 156 : apoOverviews.pop_back();
157 : }
158 386 : }
159 :
160 : /************************************************************************/
161 : /* GetOverview() */
162 : /************************************************************************/
163 :
164 2 : GDALRasterBand *ECWRasterBand::GetOverview( int iOverview )
165 :
166 : {
167 2 : if( iOverview >= 0 && iOverview < (int) apoOverviews.size() )
168 2 : return apoOverviews[iOverview];
169 : else
170 0 : return NULL;
171 : }
172 :
173 : /************************************************************************/
174 : /* GetColorInterpretation() */
175 : /************************************************************************/
176 :
177 122 : GDALColorInterp ECWRasterBand::GetColorInterpretation()
178 :
179 : {
180 122 : return eBandInterp;
181 : }
182 :
183 : /************************************************************************/
184 : /* SetColorInterpretation() */
185 : /* */
186 : /* This would normally just be used by folks using the ECW code */
187 : /* to read JP2 streams in other formats (such as NITF) and */
188 : /* providing their own color interpretation regardless of what */
189 : /* ECW might think the stream itself says. */
190 : /************************************************************************/
191 :
192 0 : CPLErr ECWRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
193 :
194 : {
195 0 : eBandInterp = eNewInterp;
196 :
197 0 : return CE_None;
198 : }
199 :
200 : /************************************************************************/
201 : /* AdviseRead() */
202 : /************************************************************************/
203 :
204 62 : CPLErr ECWRasterBand::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
205 : int nBufXSize, int nBufYSize,
206 : GDALDataType eDT,
207 : char **papszOptions )
208 : {
209 62 : int nResFactor = 1 << (iOverview+1);
210 :
211 : return poGDS->AdviseRead( nXOff * nResFactor,
212 : nYOff * nResFactor,
213 : nXSize * nResFactor,
214 : nYSize * nResFactor,
215 : nBufXSize, nBufYSize, eDT,
216 62 : 1, &nBand, papszOptions );
217 : }
218 :
219 : /************************************************************************/
220 : /* IRasterIO() */
221 : /************************************************************************/
222 :
223 25450 : CPLErr ECWRasterBand::IRasterIO( GDALRWFlag eRWFlag,
224 : int nXOff, int nYOff, int nXSize, int nYSize,
225 : void * pData, int nBufXSize, int nBufYSize,
226 : GDALDataType eBufType,
227 : int nPixelSpace, int nLineSpace )
228 :
229 : {
230 : int iBand, bDirect;
231 25450 : GByte *pabyWorkBuffer = NULL;
232 25450 : int nResFactor = 1 << (iOverview+1);
233 :
234 : /* -------------------------------------------------------------------- */
235 : /* Try to do it based on existing "advised" access. */
236 : /* -------------------------------------------------------------------- */
237 25450 : if( poGDS->TryWinRasterIO( eRWFlag,
238 : nXOff * nResFactor, nYOff * nResFactor,
239 : nXSize * nResFactor, nYSize * nResFactor,
240 : (GByte *) pData, nBufXSize, nBufYSize,
241 : eBufType, 1, &nBand,
242 : nPixelSpace, nLineSpace, 0 ) )
243 25382 : return CE_None;
244 :
245 : /* -------------------------------------------------------------------- */
246 : /* We will drop down to the block oriented API if only a single */
247 : /* scanline was requested. This is based on the assumption that */
248 : /* doing lots of single scanline windows is expensive. */
249 : /* -------------------------------------------------------------------- */
250 68 : if( nYSize == 1 )
251 : {
252 : #ifdef NOISY_DEBUG
253 : CPLDebug( "ECWRasterBand",
254 : "RasterIO(%d,%d,%d,%d -> %dx%d) - redirected.",
255 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
256 : #endif
257 : return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
258 : pData, nBufXSize, nBufYSize,
259 62 : eBufType, nPixelSpace, nLineSpace );
260 : }
261 :
262 : /* -------------------------------------------------------------------- */
263 : /* The ECW SDK doesn't supersample, so adjust for this case. */
264 : /* -------------------------------------------------------------------- */
265 : CPLDebug( "ECWRasterBand",
266 : "RasterIO(nXOff=%d,nYOff=%d,nXSize=%d,nYSize=%d -> %dx%d)",
267 6 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
268 :
269 6 : nXOff *= nResFactor;
270 6 : nYOff *= nResFactor;
271 6 : nXSize *= nResFactor;
272 6 : nYSize *= nResFactor;
273 :
274 6 : int nNewXSize = nBufXSize, nNewYSize = nBufYSize;
275 :
276 6 : if ( nXSize < nBufXSize )
277 0 : nNewXSize = nXSize;
278 :
279 6 : if ( nYSize < nBufYSize )
280 0 : nNewYSize = nYSize;
281 :
282 : /* -------------------------------------------------------------------- */
283 : /* Default line and pixel spacing if needed. */
284 : /* -------------------------------------------------------------------- */
285 6 : if ( nPixelSpace == 0 )
286 0 : nPixelSpace = GDALGetDataTypeSize( eBufType ) / 8;
287 :
288 6 : if ( nLineSpace == 0 )
289 0 : nLineSpace = nPixelSpace * nBufXSize;
290 :
291 : /* -------------------------------------------------------------------- */
292 : /* Can we perform direct loads, or must we load into a working */
293 : /* buffer, and transform? */
294 : /* -------------------------------------------------------------------- */
295 6 : int nRawPixelSize = GDALGetDataTypeSize(poGDS->eRasterDataType) / 8;
296 :
297 : bDirect = nPixelSpace == 1 && eBufType == GDT_Byte
298 6 : && nNewXSize == nBufXSize && nNewYSize == nBufYSize;
299 6 : if( !bDirect )
300 2 : pabyWorkBuffer = (GByte *) CPLMalloc(nNewXSize * nRawPixelSize);
301 :
302 : /* -------------------------------------------------------------------- */
303 : /* Establish access at the desired resolution. */
304 : /* -------------------------------------------------------------------- */
305 6 : CNCSError oErr;
306 :
307 6 : poGDS->CleanupWindow();
308 :
309 6 : iBand = nBand-1;
310 : oErr = poGDS->poFileView->SetView( 1, (unsigned int *) (&iBand),
311 : nXOff, nYOff,
312 : nXOff + nXSize - 1,
313 : nYOff + nYSize - 1,
314 6 : nNewXSize, nNewYSize );
315 6 : if( oErr.GetErrorNumber() != NCS_SUCCESS )
316 : {
317 0 : CPLFree( pabyWorkBuffer );
318 0 : char* pszErrorMessage = oErr.GetErrorMessage();
319 : CPLError( CE_Failure, CPLE_AppDefined,
320 0 : "%s", pszErrorMessage );
321 0 : NCSFree(pszErrorMessage);
322 :
323 0 : return CE_Failure;
324 : }
325 :
326 : /* -------------------------------------------------------------------- */
327 : /* Read back one scanline at a time, till request is satisfied. */
328 : /* Supersampling is not supported by the ECW API, so we will do */
329 : /* it ourselves. */
330 : /* -------------------------------------------------------------------- */
331 6 : double dfSrcYInc = (double)nNewYSize / nBufYSize;
332 6 : double dfSrcXInc = (double)nNewXSize / nBufXSize;
333 : int iSrcLine, iDstLine;
334 :
335 1518 : for( iSrcLine = 0, iDstLine = 0; iDstLine < nBufYSize; iDstLine++ )
336 : {
337 : NCSEcwReadStatus eRStatus;
338 1512 : int iDstLineOff = iDstLine * nLineSpace;
339 : unsigned char *pabySrcBuf;
340 :
341 1512 : if( bDirect )
342 1472 : pabySrcBuf = ((GByte *)pData) + iDstLineOff;
343 : else
344 40 : pabySrcBuf = pabyWorkBuffer;
345 :
346 3024 : if ( nNewYSize == nBufYSize || iSrcLine == (int)(iDstLine * dfSrcYInc) )
347 : {
348 : eRStatus = poGDS->poFileView->ReadLineBIL(
349 1512 : poGDS->eNCSRequestDataType, 1, (void **) &pabySrcBuf );
350 :
351 1512 : if( eRStatus != NCSECW_READ_OK )
352 : {
353 0 : CPLFree( pabyWorkBuffer );
354 0 : CPLDebug( "ECW", "ReadLineBIL status=%d", (int) eRStatus );
355 : CPLError( CE_Failure, CPLE_AppDefined,
356 0 : "NCScbmReadViewLineBIL failed." );
357 0 : return CE_Failure;
358 : }
359 :
360 1512 : if( !bDirect )
361 : {
362 40 : if ( nNewXSize == nBufXSize )
363 : {
364 : GDALCopyWords( pabyWorkBuffer, poGDS->eRasterDataType,
365 : nRawPixelSize,
366 : ((GByte *)pData) + iDstLine * nLineSpace,
367 40 : eBufType, nPixelSpace, nBufXSize );
368 : }
369 : else
370 : {
371 : int iPixel;
372 :
373 0 : for ( iPixel = 0; iPixel < nBufXSize; iPixel++ )
374 : {
375 : GDALCopyWords( pabyWorkBuffer
376 : + nRawPixelSize*((int)(iPixel*dfSrcXInc)),
377 : poGDS->eRasterDataType, nRawPixelSize,
378 : (GByte *)pData + iDstLineOff
379 : + iPixel * nPixelSpace,
380 0 : eBufType, nPixelSpace, 1 );
381 : }
382 : }
383 : }
384 :
385 1512 : iSrcLine++;
386 : }
387 : else
388 : {
389 : // Just copy the previous line in this case
390 : GDALCopyWords( (GByte *)pData + (iDstLineOff - nLineSpace),
391 : eBufType, nPixelSpace,
392 : (GByte *)pData + iDstLineOff,
393 0 : eBufType, nPixelSpace, nBufXSize );
394 : }
395 : }
396 :
397 6 : CPLFree( pabyWorkBuffer );
398 :
399 6 : return CE_None;
400 : }
401 :
402 : /************************************************************************/
403 : /* IReadBlock() */
404 : /************************************************************************/
405 :
406 62 : CPLErr ECWRasterBand::IReadBlock( int, int nBlockYOff, void * pImage )
407 :
408 : {
409 62 : CPLErr eErr = CE_None;
410 62 : int nXOff = 0, nYOff = nBlockYOff, nXSize = nBlockXSize, nYSize = 1;
411 62 : int nResFactor = 1 << (iOverview+1);
412 : int nDSXOff, nDSYOff, nDSXSize, nDSYSize;
413 :
414 62 : nDSXOff = nXOff * nResFactor;
415 62 : nDSYOff = nYOff * nResFactor;
416 62 : nDSXSize = nXSize * nResFactor;
417 62 : nDSYSize = nYSize * nResFactor;
418 :
419 : #ifdef NOISY_DEBUG
420 : CPLDebug( "ECW",
421 : "ECWRasterBand::IReadBlock(0,%d) from overview %d, size %dx%d",
422 : nBlockYOff,
423 : iOverview, nRasterXSize, nRasterYSize );
424 : #endif
425 :
426 62 : if( poGDS->TryWinRasterIO( GF_Read, nDSXOff, nDSYOff, nDSXSize, nDSYSize,
427 : (GByte *) pImage, nBlockXSize, 1,
428 : eDataType, 1, &nBand, 0, 0, 0 ) )
429 0 : return CE_None;
430 :
431 : eErr = AdviseRead( 0, nYOff,
432 : nRasterXSize, nRasterYSize - nYOff,
433 : nRasterXSize, nRasterYSize - nBlockYOff,
434 62 : eDataType, NULL );
435 62 : if( eErr != CE_None )
436 0 : return eErr;
437 :
438 62 : if( poGDS->TryWinRasterIO( GF_Read,
439 : nDSXOff, nDSYOff, nDSXSize, nDSYSize,
440 : (GByte *) pImage, nBlockXSize, 1,
441 : eDataType, 1, &nBand, 0, 0, 0 ) )
442 62 : return CE_None;
443 :
444 : CPLError( CE_Failure, CPLE_AppDefined,
445 : "TryWinRasterIO() failed for blocked scanline %d of band %d.",
446 0 : nBlockYOff, nBand );
447 :
448 0 : return CE_Failure;
449 : }
450 :
451 : /************************************************************************/
452 : /* ==================================================================== */
453 : /* ECWDataset */
454 : /* ==================================================================== */
455 : /************************************************************************/
456 :
457 :
458 : /************************************************************************/
459 : /* ECWDataset() */
460 : /************************************************************************/
461 :
462 118 : ECWDataset::ECWDataset(int bIsJPEG2000)
463 :
464 : {
465 118 : this->bIsJPEG2000 = bIsJPEG2000;
466 118 : bUsingCustomStream = FALSE;
467 118 : pszProjection = NULL;
468 118 : poFileView = NULL;
469 118 : bWinActive = FALSE;
470 118 : panWinBandList = NULL;
471 118 : eRasterDataType = GDT_Byte;
472 118 : nGCPCount = 0;
473 118 : pasGCPList = NULL;
474 118 : papszGMLMetadata = NULL;
475 :
476 118 : bGeoTransformValid = FALSE;
477 118 : adfGeoTransform[0] = 0.0;
478 118 : adfGeoTransform[1] = 1.0;
479 118 : adfGeoTransform[2] = 0.0;
480 118 : adfGeoTransform[3] = 0.0;
481 118 : adfGeoTransform[4] = 0.0;
482 118 : adfGeoTransform[5] = 1.0;
483 :
484 118 : bHdrDirty = FALSE;
485 118 : bGeoTransformChanged = FALSE;
486 118 : bProjectionChanged = FALSE;
487 118 : bProjCodeChanged = FALSE;
488 118 : bDatumCodeChanged = FALSE;
489 118 : bUnitsCodeChanged = FALSE;
490 :
491 118 : poDriver = (GDALDriver*) GDALGetDriverByName( bIsJPEG2000 ? "JP2ECW" : "ECW" );
492 118 : }
493 :
494 : /************************************************************************/
495 : /* ~ECWDataset() */
496 : /************************************************************************/
497 :
498 118 : ECWDataset::~ECWDataset()
499 :
500 : {
501 118 : FlushCache();
502 118 : CleanupWindow();
503 :
504 : /* -------------------------------------------------------------------- */
505 : /* Release / dereference iostream. */
506 : /* -------------------------------------------------------------------- */
507 : // The underlying iostream of the CNCSJP2FileView (poFileView) object may
508 : // also be the underlying iostream of other CNCSJP2FileView (poFileView)
509 : // objects. Consequently, when we delete the CNCSJP2FileView (poFileView)
510 : // object, we must decrement the nFileViewCount attribute of the underlying
511 : // VSIIOStream object, and only delete the VSIIOStream object when
512 : // nFileViewCount is equal to zero.
513 :
514 118 : CPLMutexHolder oHolder( &hECWDatasetMutex );
515 :
516 118 : if( poFileView != NULL )
517 : {
518 118 : VSIIOStream *poUnderlyingIOStream = (VSIIOStream *)NULL;
519 :
520 118 : poUnderlyingIOStream = ((VSIIOStream *)(poFileView->GetStream()));
521 118 : delete poFileView;
522 :
523 118 : if( bUsingCustomStream )
524 : {
525 30 : if( --poUnderlyingIOStream->nFileViewCount == 0 )
526 30 : delete poUnderlyingIOStream;
527 : }
528 : }
529 :
530 : /* WriteHeader() must be called after closing the file handle to work */
531 : /* on Windows */
532 118 : if( bHdrDirty )
533 6 : WriteHeader();
534 :
535 118 : CPLFree( pszProjection );
536 118 : CSLDestroy( papszGMLMetadata );
537 :
538 118 : if( nGCPCount > 0 )
539 : {
540 8 : GDALDeinitGCPs( nGCPCount, pasGCPList );
541 8 : CPLFree( pasGCPList );
542 118 : }
543 118 : }
544 :
545 : /************************************************************************/
546 : /* AdviseRead() */
547 : /************************************************************************/
548 :
549 12 : CPLErr ECWDataset::SetGeoTransform( double * padfGeoTransform )
550 : {
551 12 : if ( bIsJPEG2000 || eAccess == GA_ReadOnly )
552 10 : return GDALPamDataset::SetGeoTransform(padfGeoTransform);
553 :
554 4 : if ( !bGeoTransformValid ||
555 2 : adfGeoTransform[0] != padfGeoTransform[0] ||
556 0 : adfGeoTransform[1] != padfGeoTransform[1] ||
557 0 : adfGeoTransform[2] != padfGeoTransform[2] ||
558 0 : adfGeoTransform[3] != padfGeoTransform[3] ||
559 0 : adfGeoTransform[4] != padfGeoTransform[4] ||
560 0 : adfGeoTransform[5] != padfGeoTransform[5] )
561 : {
562 2 : memcpy(adfGeoTransform, padfGeoTransform, 6 * sizeof(double));
563 2 : bGeoTransformValid = TRUE;
564 2 : bHdrDirty = TRUE;
565 2 : bGeoTransformChanged = TRUE;
566 : }
567 :
568 2 : return CE_None;
569 : }
570 :
571 : /************************************************************************/
572 : /* SetProjection() */
573 : /************************************************************************/
574 :
575 12 : CPLErr ECWDataset::SetProjection( const char* pszProjectionIn )
576 : {
577 12 : if ( bIsJPEG2000 || eAccess == GA_ReadOnly )
578 10 : return GDALPamDataset::SetProjection(pszProjectionIn);
579 :
580 2 : if ( !( (pszProjection == NULL && pszProjectionIn == NULL) ||
581 : (pszProjection != NULL && pszProjectionIn != NULL &&
582 : strcmp(pszProjection, pszProjectionIn) == 0) ) )
583 : {
584 2 : CPLFree(pszProjection);
585 2 : pszProjection = pszProjectionIn ? CPLStrdup(pszProjectionIn) : NULL;
586 2 : bHdrDirty = TRUE;
587 2 : bProjectionChanged = TRUE;
588 : }
589 :
590 2 : return CE_None;
591 : }
592 :
593 : /************************************************************************/
594 : /* SetMetadataItem() */
595 : /************************************************************************/
596 :
597 6 : CPLErr ECWDataset::SetMetadataItem( const char * pszName,
598 : const char * pszValue,
599 : const char * pszDomain )
600 : {
601 6 : if ( !bIsJPEG2000 && eAccess == GA_Update &&
602 : (pszDomain == NULL || EQUAL(pszDomain, "") ||
603 : (pszDomain != NULL && EQUAL(pszDomain, "ECW"))) &&
604 : pszName != NULL &&
605 : (strcmp(pszName, "PROJ") == 0 || strcmp( pszName, "DATUM") == 0 ||
606 : strcmp( pszName, "UNITS") == 0 ) )
607 : {
608 6 : CPLString osNewVal = pszValue ? pszValue : "";
609 6 : if (osNewVal.size() > 31)
610 0 : osNewVal.resize(31);
611 6 : if (strcmp(pszName, "PROJ") == 0)
612 : {
613 2 : bProjCodeChanged = (osNewVal != m_osProjCode);
614 2 : m_osProjCode = osNewVal;
615 2 : bHdrDirty |= bProjCodeChanged;
616 : }
617 4 : else if (strcmp( pszName, "DATUM") == 0)
618 : {
619 2 : bDatumCodeChanged |= (osNewVal != m_osDatumCode);
620 2 : m_osDatumCode = osNewVal;
621 2 : bHdrDirty |= bDatumCodeChanged;
622 : }
623 : else
624 : {
625 2 : bUnitsCodeChanged |= (osNewVal != m_osUnitsCode);
626 2 : m_osUnitsCode = osNewVal;
627 2 : bHdrDirty |= bUnitsCodeChanged;
628 : }
629 6 : return CE_None;
630 : }
631 : else
632 0 : return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
633 : }
634 :
635 : /************************************************************************/
636 : /* SetMetadata() */
637 : /************************************************************************/
638 :
639 30 : CPLErr ECWDataset::SetMetadata( char ** papszMetadata,
640 : const char * pszDomain )
641 : {
642 30 : if ( (pszDomain == NULL || EQUAL(pszDomain, "") || EQUAL(pszDomain, "ECW")) &&
643 : (CSLFetchNameValue(papszMetadata, "PROJ") != NULL ||
644 : CSLFetchNameValue(papszMetadata, "DATUM") != NULL ||
645 : CSLFetchNameValue(papszMetadata, "UNITS") != NULL) )
646 : {
647 0 : CPLStringList osNewMetadata;
648 0 : char** papszIter = papszMetadata;
649 0 : while(*papszIter)
650 : {
651 0 : if (strncmp(*papszIter, "PROJ=", 5) == 0 ||
652 : strncmp(*papszIter, "DATUM=", 6) == 0 ||
653 : strncmp(*papszIter, "UNITS=", 6) == 0)
654 : {
655 0 : char* pszKey = NULL;
656 0 : const char* pszValue = CPLParseNameValue(*papszIter, &pszKey );
657 0 : SetMetadataItem(pszKey, pszValue, pszDomain);
658 0 : CPLFree(pszKey);
659 : }
660 : else
661 0 : osNewMetadata.AddString(*papszIter);
662 0 : papszIter ++;
663 : }
664 0 : if (osNewMetadata.size() != 0)
665 0 : return GDALPamDataset::SetMetadata(osNewMetadata.List(), pszDomain);
666 : else
667 0 : return CE_None;
668 : }
669 : else
670 30 : return GDALPamDataset::SetMetadata(papszMetadata, pszDomain);
671 : }
672 :
673 : /************************************************************************/
674 : /* WriteHeader() */
675 : /************************************************************************/
676 :
677 6 : void ECWDataset::WriteHeader()
678 : {
679 6 : if (!bHdrDirty)
680 0 : return;
681 :
682 6 : CPLAssert(eAccess == GA_Update);
683 6 : CPLAssert(!bIsJPEG2000);
684 :
685 6 : bHdrDirty = FALSE;
686 :
687 6 : NCSEcwEditInfo *psEditInfo = NULL;
688 : NCSError eErr;
689 :
690 : /* Load original header info */
691 6 : eErr = NCSEcwEditReadInfo((char*) GetDescription(), &psEditInfo);
692 6 : if (eErr != NCS_SUCCESS)
693 : {
694 0 : CPLError(CE_Failure, CPLE_AppDefined, "NCSEcwEditReadInfo() failed");
695 0 : return;
696 : }
697 :
698 : /* To avoid potential cross-heap issues, we keep the original */
699 : /* strings, and restore them before freeing the structure */
700 6 : char* pszOriginalCode = psEditInfo->szDatum;
701 6 : char* pszOriginalProj = psEditInfo->szProjection;
702 :
703 : /* Alter the structure with user modified information */
704 : char szProjCode[32], szDatumCode[32], szUnits[32];
705 6 : if (bProjectionChanged)
706 : {
707 2 : if (ECWTranslateFromWKT( pszProjection, szProjCode, sizeof(szProjCode),
708 : szDatumCode, sizeof(szDatumCode), szUnits ) )
709 : {
710 2 : psEditInfo->szDatum = szDatumCode;
711 2 : psEditInfo->szProjection = szProjCode;
712 2 : psEditInfo->eCellSizeUnits = ECWTranslateToCellSizeUnits(szUnits);
713 2 : CPLDebug("ECW", "Rewrite DATUM : %s", psEditInfo->szDatum);
714 2 : CPLDebug("ECW", "Rewrite PROJ : %s", psEditInfo->szProjection);
715 : CPLDebug("ECW", "Rewrite UNITS : %s",
716 2 : ECWTranslateFromCellSizeUnits(psEditInfo->eCellSizeUnits));
717 : }
718 : }
719 :
720 6 : if (bDatumCodeChanged)
721 : {
722 2 : psEditInfo->szDatum = (char*) ((m_osDatumCode.size()) ? m_osDatumCode.c_str() : "RAW");
723 2 : CPLDebug("ECW", "Rewrite DATUM : %s", psEditInfo->szDatum);
724 : }
725 6 : if (bProjCodeChanged)
726 : {
727 2 : psEditInfo->szProjection = (char*) ((m_osProjCode.size()) ? m_osProjCode.c_str() : "RAW");
728 2 : CPLDebug("ECW", "Rewrite PROJ : %s", psEditInfo->szProjection);
729 : }
730 6 : if (bUnitsCodeChanged)
731 : {
732 2 : psEditInfo->eCellSizeUnits = ECWTranslateToCellSizeUnits(m_osUnitsCode.c_str());
733 : CPLDebug("ECW", "Rewrite UNITS : %s",
734 2 : ECWTranslateFromCellSizeUnits(psEditInfo->eCellSizeUnits));
735 : }
736 :
737 6 : if (bGeoTransformChanged)
738 : {
739 2 : psEditInfo->fOriginX = adfGeoTransform[0];
740 2 : psEditInfo->fCellIncrementX = adfGeoTransform[1];
741 2 : psEditInfo->fOriginY = adfGeoTransform[3];
742 2 : psEditInfo->fCellIncrementY = adfGeoTransform[5];
743 2 : CPLDebug("ECW", "Rewrite Geotransform");
744 : }
745 :
746 : /* Write modified header info */
747 6 : eErr = NCSEcwEditWriteInfo((char*) GetDescription(), psEditInfo, NULL, NULL, NULL);
748 6 : if (eErr != NCS_SUCCESS)
749 : {
750 0 : CPLError(CE_Failure, CPLE_AppDefined, "NCSEcwEditWriteInfo() failed");
751 : }
752 :
753 : /* Restore original pointers before free'ing */
754 6 : psEditInfo->szDatum = pszOriginalCode;
755 6 : psEditInfo->szProjection = pszOriginalProj;
756 :
757 6 : NCSEcwEditFreeInfo(psEditInfo);
758 : }
759 :
760 : /************************************************************************/
761 : /* AdviseRead() */
762 : /************************************************************************/
763 :
764 64 : CPLErr ECWDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
765 : int nBufXSize, int nBufYSize,
766 : GDALDataType eDT,
767 : int nBandCount, int *panBandList,
768 : char **papszOptions )
769 :
770 : {
771 64 : int *panAdjustedBandList = NULL;
772 :
773 : CPLDebug( "ECW",
774 : "ECWDataset::AdviseRead(%d,%d,%d,%d->%d,%d)",
775 64 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
776 :
777 64 : if( nBufXSize > nXSize || nBufYSize > nYSize )
778 : {
779 : CPLError( CE_Warning, CPLE_AppDefined,
780 : "Supersampling not directly supported by ECW toolkit,\n"
781 0 : "ignoring AdviseRead() request." );
782 0 : return CE_Warning;
783 : }
784 :
785 : /* -------------------------------------------------------------------- */
786 : /* Adjust band numbers to be zero based. */
787 : /* -------------------------------------------------------------------- */
788 : panAdjustedBandList = (int *)
789 64 : CPLMalloc(sizeof(int) * nBandCount );
790 132 : for( int ii= 0; ii < nBandCount; ii++ )
791 68 : panAdjustedBandList[ii] = panBandList[ii] - 1;
792 :
793 : /* -------------------------------------------------------------------- */
794 : /* Cleanup old window cache information. */
795 : /* -------------------------------------------------------------------- */
796 64 : CleanupWindow();
797 :
798 : /* -------------------------------------------------------------------- */
799 : /* Set the new requested window. */
800 : /* -------------------------------------------------------------------- */
801 64 : CNCSError oErr;
802 :
803 : oErr = poFileView->SetView( nBandCount, (UINT32 *) panAdjustedBandList,
804 : nXOff, nYOff,
805 : nXOff + nXSize-1, nYOff + nYSize-1,
806 64 : nBufXSize, nBufYSize );
807 :
808 64 : CPLFree( panAdjustedBandList );
809 64 : if( oErr.GetErrorNumber() != NCS_SUCCESS )
810 : {
811 0 : char* pszErrorMessage = oErr.GetErrorMessage();
812 : CPLError( CE_Failure, CPLE_AppDefined,
813 0 : "%s", pszErrorMessage );
814 0 : NCSFree(pszErrorMessage);
815 0 : bWinActive = FALSE;
816 0 : return CE_Failure;
817 : }
818 :
819 64 : bWinActive = TRUE;
820 :
821 : /* -------------------------------------------------------------------- */
822 : /* Record selected window. */
823 : /* -------------------------------------------------------------------- */
824 64 : nWinXOff = nXOff;
825 64 : nWinYOff = nYOff;
826 64 : nWinXSize = nXSize;
827 64 : nWinYSize = nYSize;
828 64 : nWinBufXSize = nBufXSize;
829 64 : nWinBufYSize = nBufYSize;
830 :
831 64 : panWinBandList = (int *) CPLMalloc(sizeof(int)*nBandCount);
832 64 : memcpy( panWinBandList, panBandList, sizeof(int)* nBandCount);
833 64 : nWinBandCount = nBandCount;
834 :
835 64 : nWinBufLoaded = -1;
836 :
837 : /* -------------------------------------------------------------------- */
838 : /* Allocate current scanline buffer. */
839 : /* -------------------------------------------------------------------- */
840 64 : papCurLineBuf = (void **) CPLMalloc(sizeof(void*) * nWinBandCount );
841 132 : for( int iBand = 0; iBand < nWinBandCount; iBand++ )
842 68 : papCurLineBuf[iBand] =
843 68 : CPLMalloc(nBufXSize * (GDALGetDataTypeSize(eRasterDataType)/8) );
844 :
845 64 : return CE_None;
846 : }
847 :
848 : /************************************************************************/
849 : /* TryWinRasterIO() */
850 : /* */
851 : /* Try to satisfy the given request based on the currently */
852 : /* defined window. Return TRUE on success or FALSE on */
853 : /* failure. On failure, the caller should satisfy the request */
854 : /* another way (not report an error). */
855 : /************************************************************************/
856 :
857 26380 : int ECWDataset::TryWinRasterIO( GDALRWFlag eFlag,
858 : int nXOff, int nYOff, int nXSize, int nYSize,
859 : GByte *pabyData, int nBufXSize, int nBufYSize,
860 : GDALDataType eDT,
861 : int nBandCount, int *panBandList,
862 : int nPixelSpace, int nLineSpace,
863 : int nBandSpace )
864 :
865 : {
866 : int iBand, i;
867 :
868 : /* -------------------------------------------------------------------- */
869 : /* Provide default buffer organization. */
870 : /* -------------------------------------------------------------------- */
871 26380 : if( nPixelSpace == 0 )
872 124 : nPixelSpace = GDALGetDataTypeSize( eDT ) / 8;
873 26380 : if( nLineSpace == 0 )
874 124 : nLineSpace = nPixelSpace * nBufXSize;
875 26380 : if( nBandSpace == 0 )
876 25574 : nBandSpace = nLineSpace * nBufYSize;
877 :
878 : /* -------------------------------------------------------------------- */
879 : /* Do some simple tests to see if the current window can */
880 : /* satisfy our requirement. */
881 : /* -------------------------------------------------------------------- */
882 : #ifdef NOISY_DEBUG
883 : CPLDebug( "ECW", "TryWinRasterIO(%d,%d,%d,%d,%d,%d)",
884 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
885 : #endif
886 :
887 26380 : if( !bWinActive )
888 104 : return FALSE;
889 :
890 26276 : if( nXOff != nWinXOff || nXSize != nWinXSize )
891 0 : return FALSE;
892 :
893 26276 : if( nBufXSize != nWinBufXSize )
894 0 : return FALSE;
895 :
896 54120 : for( iBand = 0; iBand < nBandCount; iBand++ )
897 : {
898 30308 : for( i = 0; i < nWinBandCount; i++ )
899 : {
900 30276 : if( panWinBandList[i] == panBandList[iBand] )
901 27844 : break;
902 : }
903 :
904 27876 : if( i == nWinBandCount )
905 32 : return FALSE;
906 : }
907 :
908 26244 : if( nYOff < nWinYOff || nYOff + nYSize > nWinYOff + nWinYSize )
909 0 : return FALSE;
910 :
911 : /* -------------------------------------------------------------------- */
912 : /* Now we try more subtle tests. */
913 : /* -------------------------------------------------------------------- */
914 : {
915 : static int nDebugCount = 0;
916 :
917 26244 : if( nDebugCount < 30 )
918 : CPLDebug( "ECWDataset",
919 : "TryWinRasterIO(%d,%d,%d,%d -> %dx%d) - doing advised read.",
920 60 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
921 :
922 26244 : if( nDebugCount == 29 )
923 2 : CPLDebug( "ECWDataset", "No more TryWinRasterIO messages will be reported" );
924 :
925 26244 : nDebugCount++;
926 : }
927 :
928 : /* -------------------------------------------------------------------- */
929 : /* Actually load data one buffer line at a time. */
930 : /* -------------------------------------------------------------------- */
931 : int iBufLine;
932 :
933 52488 : for( iBufLine = 0; iBufLine < nBufYSize; iBufLine++ )
934 : {
935 26244 : double fFileLine = ((iBufLine+0.5) / nBufYSize) * nYSize + nYOff;
936 : int iWinLine =
937 26244 : (int) (((fFileLine - nWinYOff) / nWinYSize) * nWinBufYSize);
938 :
939 26244 : if( iWinLine == nWinBufLoaded + 1 )
940 26244 : LoadNextLine();
941 :
942 26244 : if( iWinLine != nWinBufLoaded )
943 0 : return FALSE;
944 :
945 : /* -------------------------------------------------------------------- */
946 : /* Copy out all our target bands. */
947 : /* -------------------------------------------------------------------- */
948 : int iWinBand;
949 54088 : for( iBand = 0; iBand < nBandCount; iBand++ )
950 : {
951 30244 : for( iWinBand = 0; iWinBand < nWinBandCount; iWinBand++ )
952 : {
953 30244 : if( panWinBandList[iWinBand] == panBandList[iBand] )
954 27844 : break;
955 : }
956 :
957 : GDALCopyWords( papCurLineBuf[iWinBand], eRasterDataType,
958 : GDALGetDataTypeSize( eRasterDataType ) / 8,
959 : pabyData + nBandSpace * iBand
960 : + iBufLine * nLineSpace, eDT, nPixelSpace,
961 27844 : nBufXSize );
962 : }
963 : }
964 :
965 26244 : return TRUE;
966 : }
967 :
968 : /************************************************************************/
969 : /* LoadNextLine() */
970 : /************************************************************************/
971 :
972 26244 : CPLErr ECWDataset::LoadNextLine()
973 :
974 : {
975 26244 : if( !bWinActive )
976 0 : return CE_Failure;
977 :
978 26244 : if( nWinBufLoaded == nWinBufYSize-1 )
979 : {
980 0 : CleanupWindow();
981 0 : return CE_Failure;
982 : }
983 :
984 : NCSEcwReadStatus eRStatus;
985 : eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType,
986 : (UINT16) nWinBandCount,
987 26244 : papCurLineBuf );
988 26244 : if( eRStatus != NCSECW_READ_OK )
989 0 : return CE_Failure;
990 :
991 26244 : nWinBufLoaded++;
992 :
993 26244 : return CE_None;
994 : }
995 :
996 : /************************************************************************/
997 : /* CleanupWindow() */
998 : /************************************************************************/
999 :
1000 192 : void ECWDataset::CleanupWindow()
1001 :
1002 : {
1003 192 : if( !bWinActive )
1004 128 : return;
1005 :
1006 64 : bWinActive = FALSE;
1007 64 : CPLFree( panWinBandList );
1008 64 : panWinBandList = NULL;
1009 :
1010 132 : for( int iBand = 0; iBand < nWinBandCount; iBand++ )
1011 68 : CPLFree( papCurLineBuf[iBand] );
1012 64 : CPLFree( papCurLineBuf );
1013 64 : papCurLineBuf = NULL;
1014 : }
1015 :
1016 : /************************************************************************/
1017 : /* IRasterIO() */
1018 : /************************************************************************/
1019 :
1020 804 : CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
1021 : int nXOff, int nYOff, int nXSize, int nYSize,
1022 : void * pData, int nBufXSize, int nBufYSize,
1023 : GDALDataType eBufType,
1024 : int nBandCount, int *panBandMap,
1025 : int nPixelSpace, int nLineSpace, int nBandSpace)
1026 :
1027 : {
1028 : /* -------------------------------------------------------------------- */
1029 : /* Try to do it based on existing "advised" access. */
1030 : /* -------------------------------------------------------------------- */
1031 804 : if( TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
1032 : (GByte *) pData, nBufXSize, nBufYSize,
1033 : eBufType, nBandCount, panBandMap,
1034 : nPixelSpace, nLineSpace, nBandSpace ) )
1035 798 : return CE_None;
1036 :
1037 : /* -------------------------------------------------------------------- */
1038 : /* If we are requesting a single line at 1:1, we do a multi-band */
1039 : /* AdviseRead() and then TryWinRasterIO() again. */
1040 : /* -------------------------------------------------------------------- */
1041 6 : if( nYSize == 1 && nBufYSize == 1 && nBandCount > 1 )
1042 : {
1043 : CPLErr eErr;
1044 :
1045 : eErr = AdviseRead( nXOff, nYOff, nXSize, GetRasterYSize() - nYOff,
1046 : nBufXSize, GetRasterYSize() - nYOff, eBufType,
1047 2 : nBandCount, panBandMap, NULL );
1048 2 : if( eErr == CE_None
1049 : && TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
1050 : (GByte *) pData, nBufXSize, nBufYSize,
1051 : eBufType, nBandCount, panBandMap,
1052 : nPixelSpace, nLineSpace, nBandSpace ) )
1053 2 : return CE_None;
1054 : }
1055 :
1056 : /* -------------------------------------------------------------------- */
1057 : /* If we are supersampling we need to fall into the general */
1058 : /* purpose logic. We also use the general logic if we are in */
1059 : /* some cases unlikely to benefit from interleaved access. */
1060 : /* */
1061 : /* The one case we would like to handle better here is the */
1062 : /* nBufYSize == 1 case (requesting a scanline at a time). We */
1063 : /* should eventually have some logic similiar to the band by */
1064 : /* band case where we post a big window for the view, and allow */
1065 : /* sequential reads. */
1066 : /* -------------------------------------------------------------------- */
1067 4 : if( nXSize < nBufXSize || nYSize < nBufYSize || nYSize == 1
1068 : || nBandCount > 100 || nBandCount == 1 || nBufYSize == 1
1069 : || nBandCount > GetRasterCount() )
1070 : {
1071 : return
1072 : GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
1073 : pData, nBufXSize, nBufYSize,
1074 : eBufType,
1075 : nBandCount, panBandMap,
1076 0 : nPixelSpace, nLineSpace, nBandSpace);
1077 : }
1078 :
1079 : CPLDebug( "ECWDataset",
1080 : "RasterIO(%d,%d,%d,%d -> %dx%d) - doing interleaved read.",
1081 4 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
1082 :
1083 : /* -------------------------------------------------------------------- */
1084 : /* Setup view. */
1085 : /* -------------------------------------------------------------------- */
1086 : UINT32 anBandIndices[100];
1087 : int i;
1088 : NCSError eNCSErr;
1089 4 : CNCSError oErr;
1090 :
1091 16 : for( i = 0; i < nBandCount; i++ )
1092 12 : anBandIndices[i] = panBandMap[i] - 1;
1093 :
1094 4 : CleanupWindow();
1095 :
1096 : oErr = poFileView->SetView( nBandCount, anBandIndices,
1097 : nXOff, nYOff,
1098 : nXOff + nXSize - 1,
1099 : nYOff + nYSize - 1,
1100 4 : nBufXSize, nBufYSize );
1101 4 : eNCSErr = oErr.GetErrorNumber();
1102 :
1103 4 : if( eNCSErr != NCS_SUCCESS )
1104 : {
1105 : CPLError( CE_Failure, CPLE_AppDefined,
1106 0 : "%s", NCSGetErrorText(eNCSErr) );
1107 :
1108 0 : return CE_Failure;
1109 : }
1110 :
1111 : /* -------------------------------------------------------------------- */
1112 : /* Setup working scanline, and the pointers into it. */
1113 : /* -------------------------------------------------------------------- */
1114 4 : int nDataTypeSize = (GDALGetDataTypeSize(eRasterDataType) / 8);
1115 : GByte *pabyBILScanline = (GByte *) CPLMalloc(nBufXSize * nDataTypeSize *
1116 4 : nBandCount);
1117 4 : GByte **papabyBIL = (GByte **) CPLMalloc(nBandCount * sizeof(void*));
1118 :
1119 16 : for( i = 0; i < nBandCount; i++ )
1120 12 : papabyBIL[i] = pabyBILScanline + i * nBufXSize * nDataTypeSize;
1121 :
1122 : /* -------------------------------------------------------------------- */
1123 : /* Read back all the data for the requested view. */
1124 : /* -------------------------------------------------------------------- */
1125 884 : for( int iScanline = 0; iScanline < nBufYSize; iScanline++ )
1126 : {
1127 : NCSEcwReadStatus eRStatus;
1128 :
1129 : eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType,
1130 : (UINT16) nBandCount,
1131 880 : (void **) papabyBIL );
1132 880 : if( eRStatus != NCSECW_READ_OK )
1133 : {
1134 0 : CPLFree( papabyBIL );
1135 0 : CPLFree( pabyBILScanline );
1136 : CPLError( CE_Failure, CPLE_AppDefined,
1137 0 : "NCScbmReadViewLineBIL failed." );
1138 0 : return CE_Failure;
1139 : }
1140 :
1141 3520 : for( i = 0; i < nBandCount; i++ )
1142 : {
1143 : GDALCopyWords(
1144 : pabyBILScanline + i * nDataTypeSize * nBufXSize,
1145 : eRasterDataType, nDataTypeSize,
1146 : ((GByte *) pData) + nLineSpace * iScanline + nBandSpace * i,
1147 : eBufType, nPixelSpace,
1148 2640 : nBufXSize );
1149 : }
1150 : }
1151 :
1152 4 : CPLFree( pabyBILScanline );
1153 4 : CPLFree( papabyBIL );
1154 :
1155 4 : return CE_None;
1156 : }
1157 :
1158 : /************************************************************************/
1159 : /* IdentifyJPEG2000() */
1160 : /* */
1161 : /* Open method that only supports JPEG2000 files. */
1162 : /************************************************************************/
1163 :
1164 22680 : int ECWDataset::IdentifyJPEG2000( GDALOpenInfo * poOpenInfo )
1165 :
1166 : {
1167 22680 : if( EQUALN(poOpenInfo->pszFilename,"J2K_SUBFILE:",12) )
1168 0 : return TRUE;
1169 :
1170 22680 : else if( poOpenInfo->nHeaderBytes >= 16
1171 : && (memcmp( poOpenInfo->pabyHeader, jpc_header,
1172 : sizeof(jpc_header) ) == 0
1173 : || memcmp( poOpenInfo->pabyHeader, jp2_header,
1174 : sizeof(jp2_header) ) == 0) )
1175 86 : return TRUE;
1176 :
1177 : else
1178 22594 : return FALSE;
1179 : }
1180 :
1181 : /************************************************************************/
1182 : /* OpenJPEG2000() */
1183 : /* */
1184 : /* Open method that only supports JPEG2000 files. */
1185 : /************************************************************************/
1186 :
1187 3802 : GDALDataset *ECWDataset::OpenJPEG2000( GDALOpenInfo * poOpenInfo )
1188 :
1189 : {
1190 3802 : if (!IdentifyJPEG2000(poOpenInfo))
1191 3716 : return NULL;
1192 :
1193 86 : return Open( poOpenInfo, TRUE );
1194 : }
1195 :
1196 : /************************************************************************/
1197 : /* IdentifyECW() */
1198 : /* */
1199 : /* Identify method that only supports ECW files. */
1200 : /************************************************************************/
1201 :
1202 23890 : int ECWDataset::IdentifyECW( GDALOpenInfo * poOpenInfo )
1203 :
1204 : {
1205 : /* -------------------------------------------------------------------- */
1206 : /* This has to either be a file on disk ending in .ecw or a */
1207 : /* ecwp: protocol url. */
1208 : /* -------------------------------------------------------------------- */
1209 23890 : if( (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"ecw")
1210 : || poOpenInfo->nHeaderBytes == 0)
1211 : && !EQUALN(poOpenInfo->pszFilename,"ecwp:",5)
1212 : && !EQUALN(poOpenInfo->pszFilename,"ecwps:",5) )
1213 23856 : return FALSE;
1214 :
1215 34 : return TRUE;
1216 : }
1217 :
1218 : /************************************************************************/
1219 : /* OpenECW() */
1220 : /* */
1221 : /* Open method that only supports ECW files. */
1222 : /************************************************************************/
1223 :
1224 4980 : GDALDataset *ECWDataset::OpenECW( GDALOpenInfo * poOpenInfo )
1225 :
1226 : {
1227 4980 : if (!IdentifyECW(poOpenInfo))
1228 4946 : return NULL;
1229 :
1230 34 : return Open( poOpenInfo, FALSE );
1231 : }
1232 :
1233 : /************************************************************************/
1234 : /* OpenFileView() */
1235 : /************************************************************************/
1236 :
1237 120 : CNCSJP2FileView *ECWDataset::OpenFileView( const char *pszDatasetName,
1238 : bool bProgressive,
1239 : int &bUsingCustomStream )
1240 :
1241 : {
1242 : /* -------------------------------------------------------------------- */
1243 : /* First we try to open it as a normal CNCSFile, letting the */
1244 : /* ECW SDK manage the IO itself. This will only work for real */
1245 : /* files, and ecwp: or ecwps: sources. */
1246 : /* -------------------------------------------------------------------- */
1247 120 : CNCSJP2FileView *poFileView = NULL;
1248 : NCSError eErr;
1249 120 : CNCSError oErr;
1250 :
1251 120 : bUsingCustomStream = FALSE;
1252 120 : poFileView = new CNCSFile();
1253 240 : oErr = poFileView->Open( (char *) pszDatasetName, bProgressive );
1254 120 : eErr = oErr.GetErrorNumber();
1255 :
1256 : /* -------------------------------------------------------------------- */
1257 : /* If that did not work, trying opening as a virtual file. */
1258 : /* -------------------------------------------------------------------- */
1259 120 : if( eErr != NCS_SUCCESS )
1260 : {
1261 : CPLDebug( "ECW",
1262 : "NCScbmOpenFileView(%s): eErr=%d, will try VSIL stream.",
1263 32 : pszDatasetName, (int) eErr );
1264 :
1265 32 : delete poFileView;
1266 :
1267 32 : VSILFILE *fpVSIL = VSIFOpenL( pszDatasetName, "rb" );
1268 32 : if( fpVSIL == NULL )
1269 : {
1270 : CPLError( CE_Failure, CPLE_OpenFailed,
1271 0 : "Failed to open %s.", pszDatasetName );
1272 0 : return NULL;
1273 : }
1274 :
1275 32 : if( hECWDatasetMutex == NULL )
1276 : {
1277 0 : hECWDatasetMutex = CPLCreateMutex();
1278 : }
1279 32 : else if( !CPLAcquireMutex( hECWDatasetMutex, 60.0 ) )
1280 : {
1281 0 : CPLDebug( "ECW", "Failed to acquire mutex in 60s." );
1282 : }
1283 : else
1284 : {
1285 32 : CPLDebug( "ECW", "Got mutex." );
1286 : }
1287 32 : VSIIOStream *poIOStream = new VSIIOStream();
1288 64 : poIOStream->Access( fpVSIL, FALSE, pszDatasetName, 0, -1 );
1289 :
1290 32 : poFileView = new CNCSJP2FileView();
1291 64 : oErr = poFileView->Open( poIOStream, bProgressive );
1292 :
1293 : // The CNCSJP2FileView (poFileView) object may not use the iostream
1294 : // (poIOStream) passed to the CNCSJP2FileView::Open() method if an
1295 : // iostream is already available to the ECW JPEG 2000 SDK for a given
1296 : // file. Consequently, if the iostream passed to
1297 : // CNCSJP2FileView::Open() does not become the underlying iostream
1298 : // of the CNCSJP2FileView object, then it should be deleted.
1299 : //
1300 : // In addition, the underlying iostream of the CNCSJP2FileView object
1301 : // should not be deleted until all CNCSJP2FileView objects using the
1302 : // underlying iostream are deleted. Consequently, each time a
1303 : // CNCSJP2FileView object is created, the nFileViewCount attribute
1304 : // of the underlying VSIIOStream object must be incremented for use
1305 : // in the ECWDataset destructor.
1306 :
1307 : VSIIOStream * poUnderlyingIOStream =
1308 32 : ((VSIIOStream *)(poFileView->GetStream()));
1309 :
1310 32 : if ( poUnderlyingIOStream )
1311 30 : poUnderlyingIOStream->nFileViewCount++;
1312 :
1313 32 : if ( poIOStream != poUnderlyingIOStream )
1314 : {
1315 2 : delete poIOStream;
1316 : }
1317 : else
1318 : {
1319 30 : bUsingCustomStream = TRUE;
1320 : }
1321 :
1322 32 : CPLReleaseMutex( hECWDatasetMutex );
1323 :
1324 32 : if( oErr.GetErrorNumber() != NCS_SUCCESS )
1325 : {
1326 2 : if (poFileView)
1327 2 : delete poFileView;
1328 :
1329 2 : char* pszErrorMessage = oErr.GetErrorMessage();
1330 : CPLError( CE_Failure, CPLE_AppDefined,
1331 2 : "%s", pszErrorMessage );
1332 2 : NCSFree(pszErrorMessage);
1333 :
1334 2 : return NULL;
1335 : }
1336 : }
1337 :
1338 118 : return poFileView;
1339 : }
1340 :
1341 : /************************************************************************/
1342 : /* Open() */
1343 : /************************************************************************/
1344 :
1345 120 : GDALDataset *ECWDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJPEG2000 )
1346 :
1347 : {
1348 120 : CNCSJP2FileView *poFileView = NULL;
1349 : int i;
1350 120 : int bUsingCustomStream = FALSE;
1351 120 : CPLString osFilename = poOpenInfo->pszFilename;
1352 :
1353 120 : ECWInitialize();
1354 :
1355 : /* -------------------------------------------------------------------- */
1356 : /* If we get a J2K_SUBFILE style name, convert it into the */
1357 : /* corresponding /vsisubfile/ path. */
1358 : /* */
1359 : /* From: J2K_SUBFILE:offset,size,filename */
1360 : /* To: /vsisubfile/offset_size,filename */
1361 : /* -------------------------------------------------------------------- */
1362 120 : if (EQUALN(osFilename,"J2K_SUBFILE:",12))
1363 : {
1364 0 : char** papszTokens = CSLTokenizeString2(osFilename.c_str()+12, ",", 0);
1365 0 : if (CSLCount(papszTokens) >= 2)
1366 : {
1367 : osFilename.Printf( "/vsisubfile/%s_%s,%s",
1368 0 : papszTokens[0], papszTokens[1], papszTokens[2]);
1369 : }
1370 : else
1371 : {
1372 : CPLError( CE_Failure, CPLE_OpenFailed,
1373 0 : "Failed to parse J2K_SUBFILE specification." );
1374 0 : CSLDestroy(papszTokens);
1375 0 : return NULL;
1376 : }
1377 0 : CSLDestroy(papszTokens);
1378 : }
1379 :
1380 : /* -------------------------------------------------------------------- */
1381 : /* Open the client interface. */
1382 : /* -------------------------------------------------------------------- */
1383 120 : poFileView = OpenFileView( osFilename, false, bUsingCustomStream );
1384 120 : if( poFileView == NULL )
1385 2 : return NULL;
1386 :
1387 : /* -------------------------------------------------------------------- */
1388 : /* Create a corresponding GDALDataset. */
1389 : /* -------------------------------------------------------------------- */
1390 : ECWDataset *poDS;
1391 :
1392 118 : poDS = new ECWDataset(bIsJPEG2000);
1393 118 : poDS->poFileView = poFileView;
1394 118 : poDS->eAccess = poOpenInfo->eAccess;
1395 :
1396 : // Disable .aux.xml writing for subfiles and such. Unfortunately
1397 : // this will also disable it in some cases where it might be
1398 : // applicable.
1399 118 : if( bUsingCustomStream )
1400 30 : poDS->nPamFlags |= GPF_DISABLED;
1401 :
1402 118 : poDS->bUsingCustomStream = bUsingCustomStream;
1403 :
1404 : /* -------------------------------------------------------------------- */
1405 : /* Fetch general file information. */
1406 : /* -------------------------------------------------------------------- */
1407 118 : poDS->psFileInfo = poFileView->GetFileInfo();
1408 :
1409 : CPLDebug( "ECW", "FileInfo: SizeXY=%d,%d Bands=%d\n"
1410 : " OriginXY=%g,%g CellIncrementXY=%g,%g\n"
1411 : " ColorSpace=%d, eCellType=%d\n",
1412 : poDS->psFileInfo->nSizeX,
1413 : poDS->psFileInfo->nSizeY,
1414 : poDS->psFileInfo->nBands,
1415 : poDS->psFileInfo->fOriginX,
1416 : poDS->psFileInfo->fOriginY,
1417 : poDS->psFileInfo->fCellIncrementX,
1418 : poDS->psFileInfo->fCellIncrementY,
1419 : (int) poDS->psFileInfo->eColorSpace,
1420 118 : (int) poDS->psFileInfo->eCellType );
1421 :
1422 : /* -------------------------------------------------------------------- */
1423 : /* Establish raster info. */
1424 : /* -------------------------------------------------------------------- */
1425 118 : poDS->nRasterXSize = poDS->psFileInfo->nSizeX;
1426 118 : poDS->nRasterYSize = poDS->psFileInfo->nSizeY;
1427 :
1428 : /* -------------------------------------------------------------------- */
1429 : /* Establish the GDAL data type that corresponds. A few NCS */
1430 : /* data types have no direct corresponding value in GDAL so we */
1431 : /* will coerce to something sufficiently similar. */
1432 : /* -------------------------------------------------------------------- */
1433 118 : poDS->eNCSRequestDataType = poDS->psFileInfo->eCellType;
1434 118 : switch( poDS->psFileInfo->eCellType )
1435 : {
1436 : case NCSCT_UINT8:
1437 96 : poDS->eRasterDataType = GDT_Byte;
1438 96 : break;
1439 :
1440 : case NCSCT_UINT16:
1441 10 : poDS->eRasterDataType = GDT_UInt16;
1442 10 : break;
1443 :
1444 : case NCSCT_UINT32:
1445 : case NCSCT_UINT64:
1446 2 : poDS->eRasterDataType = GDT_UInt32;
1447 2 : poDS->eNCSRequestDataType = NCSCT_UINT32;
1448 2 : break;
1449 :
1450 : case NCSCT_INT8:
1451 : case NCSCT_INT16:
1452 6 : poDS->eRasterDataType = GDT_Int16;
1453 6 : poDS->eNCSRequestDataType = NCSCT_INT16;
1454 6 : break;
1455 :
1456 : case NCSCT_INT32:
1457 : case NCSCT_INT64:
1458 4 : poDS->eRasterDataType = GDT_Int32;
1459 4 : poDS->eNCSRequestDataType = NCSCT_INT32;
1460 4 : break;
1461 :
1462 : case NCSCT_IEEE4:
1463 0 : poDS->eRasterDataType = GDT_Float32;
1464 0 : break;
1465 :
1466 : case NCSCT_IEEE8:
1467 0 : poDS->eRasterDataType = GDT_Float64;
1468 : break;
1469 : }
1470 :
1471 : /* -------------------------------------------------------------------- */
1472 : /* Create band information objects. */
1473 : /* -------------------------------------------------------------------- */
1474 348 : for( i=0; i < poDS->psFileInfo->nBands; i++ )
1475 230 : poDS->SetBand( i+1, new ECWRasterBand( poDS, i+1 ) );
1476 :
1477 : /* -------------------------------------------------------------------- */
1478 : /* Look for supporting coordinate system information. */
1479 : /* -------------------------------------------------------------------- */
1480 118 : if( bIsJPEG2000 )
1481 : {
1482 86 : GDALJP2Metadata oJP2Geo;
1483 86 : if ( oJP2Geo.ReadAndParse( osFilename ) )
1484 : {
1485 46 : poDS->pszProjection = CPLStrdup(oJP2Geo.pszProjection);
1486 46 : poDS->bGeoTransformValid = oJP2Geo.bHaveGeoTransform;
1487 : memcpy( poDS->adfGeoTransform, oJP2Geo.adfGeoTransform,
1488 46 : sizeof(double) * 6 );
1489 46 : poDS->nGCPCount = oJP2Geo.nGCPCount;
1490 46 : poDS->pasGCPList = oJP2Geo.pasGCPList;
1491 46 : oJP2Geo.pasGCPList = NULL;
1492 46 : oJP2Geo.nGCPCount = 0;
1493 : }
1494 :
1495 86 : if (oJP2Geo.pszXMPMetadata)
1496 : {
1497 : char *apszMDList[2];
1498 2 : apszMDList[0] = (char *) oJP2Geo.pszXMPMetadata;
1499 2 : apszMDList[1] = NULL;
1500 2 : poDS->SetMetadata(apszMDList, "xml:XMP");
1501 86 : }
1502 : }
1503 : else
1504 : {
1505 32 : poDS->ECW2WKTProjection();
1506 : }
1507 :
1508 : /* -------------------------------------------------------------------- */
1509 : /* Check for world file for ecw files. */
1510 : /* -------------------------------------------------------------------- */
1511 118 : if( !poDS->bGeoTransformValid
1512 : && EQUAL(CPLGetExtension(osFilename),"ecw") )
1513 : {
1514 : poDS->bGeoTransformValid |=
1515 : GDALReadWorldFile( osFilename, ".eww",
1516 : poDS->adfGeoTransform )
1517 : || GDALReadWorldFile( osFilename, ".ecww",
1518 : poDS->adfGeoTransform )
1519 : || GDALReadWorldFile( osFilename, ".wld",
1520 0 : poDS->adfGeoTransform );
1521 : }
1522 :
1523 : /* -------------------------------------------------------------------- */
1524 : /* Initialize any PAM information. */
1525 : /* -------------------------------------------------------------------- */
1526 118 : poDS->SetDescription( osFilename );
1527 118 : poDS->TryLoadXML();
1528 :
1529 118 : return( poDS );
1530 : }
1531 :
1532 : /************************************************************************/
1533 : /* GetGCPCount() */
1534 : /************************************************************************/
1535 :
1536 14 : int ECWDataset::GetGCPCount()
1537 :
1538 : {
1539 14 : if( nGCPCount != 0 )
1540 6 : return nGCPCount;
1541 : else
1542 8 : return GDALPamDataset::GetGCPCount();
1543 : }
1544 :
1545 : /************************************************************************/
1546 : /* GetGCPProjection() */
1547 : /************************************************************************/
1548 :
1549 4 : const char *ECWDataset::GetGCPProjection()
1550 :
1551 : {
1552 4 : if( nGCPCount > 0 )
1553 4 : return pszProjection;
1554 : else
1555 0 : return GDALPamDataset::GetGCPProjection();
1556 : }
1557 :
1558 : /************************************************************************/
1559 : /* GetGCP() */
1560 : /************************************************************************/
1561 :
1562 6 : const GDAL_GCP *ECWDataset::GetGCPs()
1563 :
1564 : {
1565 6 : if( nGCPCount != 0 )
1566 4 : return pasGCPList;
1567 : else
1568 2 : return GDALPamDataset::GetGCPs();
1569 : }
1570 :
1571 : /************************************************************************/
1572 : /* GetProjectionRef() */
1573 : /* */
1574 : /* We let PAM coordinate system override the one stored inside */
1575 : /* our file. */
1576 : /************************************************************************/
1577 :
1578 86 : const char *ECWDataset::GetProjectionRef()
1579 :
1580 : {
1581 86 : const char* pszPamPrj = GDALPamDataset::GetProjectionRef();
1582 :
1583 86 : if( pszProjection != NULL && strlen(pszPamPrj) == 0 )
1584 56 : return pszProjection;
1585 : else
1586 30 : return pszPamPrj;
1587 : }
1588 :
1589 : /************************************************************************/
1590 : /* GetGeoTransform() */
1591 : /* */
1592 : /* Let the PAM geotransform override the native one if it is */
1593 : /* available. */
1594 : /************************************************************************/
1595 :
1596 56 : CPLErr ECWDataset::GetGeoTransform( double * padfTransform )
1597 :
1598 : {
1599 56 : CPLErr eErr = GDALPamDataset::GetGeoTransform( padfTransform );
1600 :
1601 56 : if( eErr != CE_None && bGeoTransformValid )
1602 : {
1603 46 : memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
1604 46 : return( CE_None );
1605 : }
1606 : else
1607 10 : return eErr;
1608 : }
1609 :
1610 : /************************************************************************/
1611 : /* GetMetadataItem() */
1612 : /************************************************************************/
1613 :
1614 26 : const char *ECWDataset::GetMetadataItem( const char * pszName,
1615 : const char * pszDomain )
1616 : {
1617 26 : if (!bIsJPEG2000 && pszDomain != NULL && EQUAL(pszDomain, "ECW") && pszName != NULL)
1618 : {
1619 12 : if (EQUAL(pszName, "PROJ"))
1620 4 : return m_osProjCode.size() ? m_osProjCode.c_str() : "RAW";
1621 8 : if (EQUAL(pszName, "DATUM"))
1622 4 : return m_osDatumCode.size() ? m_osDatumCode.c_str() : "RAW";
1623 4 : if (EQUAL(pszName, "UNITS"))
1624 4 : return m_osUnitsCode.size() ? m_osUnitsCode.c_str() : "METERS";
1625 : }
1626 14 : return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
1627 : }
1628 :
1629 : /************************************************************************/
1630 : /* GetMetadata() */
1631 : /************************************************************************/
1632 :
1633 38 : char **ECWDataset::GetMetadata( const char *pszDomain )
1634 :
1635 : {
1636 38 : if( !bIsJPEG2000 && pszDomain != NULL && EQUAL(pszDomain, "ECW") )
1637 : {
1638 0 : oECWMetadataList.Clear();
1639 0 : oECWMetadataList.AddString(CPLSPrintf("%s=%s", "PROJ", GetMetadataItem("PROJ", "ECW")));
1640 0 : oECWMetadataList.AddString(CPLSPrintf("%s=%s", "DATUM", GetMetadataItem("DATUM", "ECW")));
1641 0 : oECWMetadataList.AddString(CPLSPrintf("%s=%s", "UNITS", GetMetadataItem("UNITS", "ECW")));
1642 0 : return oECWMetadataList.List();
1643 : }
1644 38 : else if( pszDomain == NULL || !EQUAL(pszDomain,"GML") )
1645 38 : return GDALPamDataset::GetMetadata( pszDomain );
1646 : else
1647 0 : return papszGMLMetadata;
1648 : }
1649 :
1650 : /************************************************************************/
1651 : /* ECW2WKTProjection() */
1652 : /* */
1653 : /* Set the dataset pszProjection string in OGC WKT format by */
1654 : /* looking up the ECW (GDT) coordinate system info in */
1655 : /* ecw_cs.dat support data file. */
1656 : /* */
1657 : /* This code is likely still broken in some circumstances. For */
1658 : /* instance, I haven't been careful about changing the linear */
1659 : /* projection parameters (false easting/northing) if the units */
1660 : /* is feet. Lots of cases missing here, and in ecw_cs.dat. */
1661 : /************************************************************************/
1662 :
1663 32 : void ECWDataset::ECW2WKTProjection()
1664 :
1665 : {
1666 32 : if( psFileInfo == NULL )
1667 0 : return;
1668 :
1669 : /* -------------------------------------------------------------------- */
1670 : /* Capture Geotransform. */
1671 : /* */
1672 : /* We will try to ignore the provided file information if it is */
1673 : /* origin (0,0) and pixel size (1,1). I think sometimes I have */
1674 : /* also seen pixel increments of 0 on invalid datasets. */
1675 : /* -------------------------------------------------------------------- */
1676 32 : if( psFileInfo->fOriginX != 0.0
1677 : || psFileInfo->fOriginY != 0.0
1678 : || (psFileInfo->fCellIncrementX != 0.0
1679 : && psFileInfo->fCellIncrementX != 1.0)
1680 : || (psFileInfo->fCellIncrementY != 0.0
1681 : && psFileInfo->fCellIncrementY != 1.0) )
1682 : {
1683 32 : bGeoTransformValid = TRUE;
1684 :
1685 32 : adfGeoTransform[0] = psFileInfo->fOriginX;
1686 32 : adfGeoTransform[1] = psFileInfo->fCellIncrementX;
1687 32 : adfGeoTransform[2] = 0.0;
1688 :
1689 32 : adfGeoTransform[3] = psFileInfo->fOriginY;
1690 32 : adfGeoTransform[4] = 0.0;
1691 32 : adfGeoTransform[5] = -fabs(psFileInfo->fCellIncrementY);
1692 : }
1693 :
1694 : /* -------------------------------------------------------------------- */
1695 : /* do we have projection and datum? */
1696 : /* -------------------------------------------------------------------- */
1697 32 : CPLString osUnits = ECWTranslateFromCellSizeUnits(psFileInfo->eCellSizeUnits);
1698 :
1699 : CPLDebug( "ECW", "projection=%s, datum=%s, units=%s",
1700 : psFileInfo->szProjection, psFileInfo->szDatum,
1701 32 : osUnits.c_str());
1702 :
1703 32 : if( EQUAL(psFileInfo->szProjection,"RAW") )
1704 : return;
1705 :
1706 : /* -------------------------------------------------------------------- */
1707 : /* Set projection if we have it. */
1708 : /* -------------------------------------------------------------------- */
1709 18 : OGRSpatialReference oSRS;
1710 :
1711 : /* For backward-compatible with previous behaviour. Should we only */
1712 : /* restrict to those 2 values ? */
1713 18 : if (psFileInfo->eCellSizeUnits != ECW_CELL_UNITS_METERS &&
1714 : psFileInfo->eCellSizeUnits != ECW_CELL_UNITS_FEET)
1715 0 : osUnits = ECWTranslateFromCellSizeUnits(ECW_CELL_UNITS_METERS);
1716 :
1717 18 : m_osDatumCode = psFileInfo->szDatum;
1718 18 : m_osProjCode = psFileInfo->szProjection;
1719 18 : m_osUnitsCode = osUnits;
1720 18 : if( oSRS.importFromERM( psFileInfo->szProjection,
1721 : psFileInfo->szDatum,
1722 : osUnits ) == OGRERR_NONE )
1723 : {
1724 18 : oSRS.exportToWkt( &pszProjection );
1725 : }
1726 :
1727 18 : CPLErrorReset(); /* see #4187 */
1728 : }
1729 :
1730 : /************************************************************************/
1731 : /* ECWTranslateFromWKT() */
1732 : /************************************************************************/
1733 :
1734 48 : int ECWTranslateFromWKT( const char *pszWKT,
1735 : char *pszProjection,
1736 : int nProjectionLen,
1737 : char *pszDatum,
1738 : int nDatumLen,
1739 : char *pszUnits)
1740 :
1741 : {
1742 48 : OGRSpatialReference oSRS;
1743 48 : char *pszWKTIn = (char *) pszWKT;
1744 :
1745 48 : strcpy( pszProjection, "RAW" );
1746 48 : strcpy( pszDatum, "RAW" );
1747 48 : strcpy( pszUnits, "METERS" );
1748 :
1749 48 : if( pszWKT == NULL || strlen(pszWKT) == 0 )
1750 2 : return FALSE;
1751 :
1752 46 : oSRS.importFromWkt( &pszWKTIn );
1753 :
1754 46 : if( oSRS.IsLocal() )
1755 0 : return TRUE;
1756 :
1757 : /* -------------------------------------------------------------------- */
1758 : /* Do we have an overall EPSG number for this coordinate system? */
1759 : /* -------------------------------------------------------------------- */
1760 46 : const char *pszAuthorityCode = NULL;
1761 46 : const char *pszAuthorityName = NULL;
1762 46 : UINT32 nEPSGCode = 0;
1763 :
1764 46 : if( oSRS.IsProjected() )
1765 : {
1766 12 : pszAuthorityCode = oSRS.GetAuthorityCode( "PROJCS" );
1767 12 : pszAuthorityName = oSRS.GetAuthorityName( "PROJCS" );
1768 : }
1769 34 : else if( oSRS.IsGeographic() )
1770 : {
1771 34 : pszAuthorityCode = oSRS.GetAuthorityCode( "GEOGCS" );
1772 34 : pszAuthorityName = oSRS.GetAuthorityName( "GEOGCS" );
1773 : }
1774 :
1775 46 : if( pszAuthorityName != NULL && EQUAL(pszAuthorityName,"EPSG")
1776 : && pszAuthorityCode != NULL && atoi(pszAuthorityCode) > 0 )
1777 36 : nEPSGCode = (UINT32) atoi(pszAuthorityCode);
1778 :
1779 46 : if( nEPSGCode != 0 )
1780 : {
1781 36 : char *pszEPSGProj = NULL, *pszEPSGDatum = NULL;
1782 36 : CNCSError oErr;
1783 :
1784 : oErr =
1785 : CNCSJP2FileView::GetProjectionAndDatum( atoi(pszAuthorityCode),
1786 36 : &pszEPSGProj, &pszEPSGDatum );
1787 :
1788 : CPLDebug( "ECW", "GetGDTProjDat(%d) = %s/%s",
1789 36 : atoi(pszAuthorityCode), pszEPSGProj, pszEPSGDatum );
1790 :
1791 36 : if( oErr.GetErrorNumber() == NCS_SUCCESS
1792 : && pszEPSGProj != NULL && pszEPSGDatum != NULL )
1793 : {
1794 36 : strncpy( pszProjection, pszEPSGProj, nProjectionLen );
1795 36 : strncpy( pszDatum, pszEPSGDatum, nDatumLen );
1796 36 : pszProjection[nProjectionLen - 1] = 0;
1797 36 : pszDatum[nDatumLen - 1] = 0;
1798 36 : NCSFree( pszEPSGProj );
1799 36 : NCSFree( pszEPSGDatum );
1800 36 : return TRUE;
1801 : }
1802 :
1803 0 : NCSFree( pszEPSGProj );
1804 0 : NCSFree( pszEPSGDatum );
1805 :
1806 : }
1807 :
1808 : /* -------------------------------------------------------------------- */
1809 : /* Fallback to translating based on the ecw_cs.wkt file, and */
1810 : /* various jiffy rules. */
1811 : /* -------------------------------------------------------------------- */
1812 :
1813 10 : return oSRS.exportToERM( pszProjection, pszDatum, pszUnits ) == OGRERR_NONE;
1814 : }
1815 :
1816 : /************************************************************************/
1817 : /* ECWTranslateToCellSizeUnits() */
1818 : /************************************************************************/
1819 :
1820 50 : CellSizeUnits ECWTranslateToCellSizeUnits(const char* pszUnits)
1821 : {
1822 50 : if (EQUAL(pszUnits, "METERS"))
1823 46 : return ECW_CELL_UNITS_METERS;
1824 4 : else if (EQUAL(pszUnits, "DEGREES"))
1825 0 : return ECW_CELL_UNITS_DEGREES;
1826 4 : else if (EQUAL(pszUnits, "FEET"))
1827 4 : return ECW_CELL_UNITS_FEET;
1828 0 : else if (EQUAL(pszUnits, "UNKNOWN"))
1829 0 : return ECW_CELL_UNITS_UNKNOWN;
1830 0 : else if (EQUAL(pszUnits, "INVALID"))
1831 0 : return ECW_CELL_UNITS_INVALID;
1832 : else
1833 : {
1834 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unrecognized value for UNITS : %s", pszUnits);
1835 0 : return ECW_CELL_UNITS_INVALID;
1836 : }
1837 : }
1838 :
1839 : /************************************************************************/
1840 : /* ECWTranslateFromCellSizeUnits() */
1841 : /************************************************************************/
1842 :
1843 84 : const char* ECWTranslateFromCellSizeUnits(CellSizeUnits eUnits)
1844 : {
1845 84 : if (eUnits == ECW_CELL_UNITS_METERS)
1846 76 : return "METERS";
1847 8 : else if (eUnits == ECW_CELL_UNITS_DEGREES)
1848 0 : return "DEGREES";
1849 8 : else if (eUnits == ECW_CELL_UNITS_FEET)
1850 8 : return "FEET";
1851 0 : else if (eUnits == ECW_CELL_UNITS_UNKNOWN)
1852 0 : return "UNKNOWN";
1853 : else
1854 0 : return "INVALID";
1855 : }
1856 :
1857 : #endif /* def FRMT_ecw */
1858 :
1859 : /************************************************************************/
1860 : /* ECWInitialize() */
1861 : /* */
1862 : /* Initialize NCS library. We try to defer this as late as */
1863 : /* possible since de-initializing it seems to be expensive/slow */
1864 : /* on some system. */
1865 : /************************************************************************/
1866 :
1867 220 : void ECWInitialize()
1868 :
1869 : {
1870 220 : CPLMutexHolder oHolder( &hECWDatasetMutex );
1871 :
1872 220 : if( bNCSInitialized )
1873 : return;
1874 :
1875 6 : NCSecwInit();
1876 6 : bNCSInitialized = TRUE;
1877 :
1878 : /* -------------------------------------------------------------------- */
1879 : /* This will disable automatic conversion of YCbCr to RGB by */
1880 : /* the toolkit. */
1881 : /* -------------------------------------------------------------------- */
1882 6 : if( !CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ) )
1883 0 : NCSecwSetConfig(NCSCFG_JP2_MANAGE_ICC, FALSE);
1884 :
1885 : /* -------------------------------------------------------------------- */
1886 : /* Initialize cache memory limit. Default is apparently 1/4 RAM. */
1887 : /* -------------------------------------------------------------------- */
1888 : const char *pszEcwCacheSize =
1889 6 : CPLGetConfigOption("GDAL_ECW_CACHE_MAXMEM",NULL);
1890 6 : if( pszEcwCacheSize == NULL )
1891 6 : pszEcwCacheSize = CPLGetConfigOption("ECW_CACHE_MAXMEM",NULL);
1892 :
1893 6 : if( pszEcwCacheSize != NULL )
1894 0 : NCSecwSetConfig(NCSCFG_CACHE_MAXMEM, (UINT32) atoi(pszEcwCacheSize) );
1895 :
1896 : /* -------------------------------------------------------------------- */
1897 : /* Allow configuration of a local cache based on configuration */
1898 : /* options. Setting the location turns things on. */
1899 : /* -------------------------------------------------------------------- */
1900 : const char *pszOpt;
1901 :
1902 : #if ECWSDK_VERSION >= 40
1903 : pszOpt = CPLGetConfigOption( "ECWP_CACHE_SIZE_MB", NULL );
1904 : if( pszOpt )
1905 : NCSecwSetConfig( NCSCFG_ECWP_CACHE_SIZE_MB, (INT32) atoi( pszOpt ) );
1906 :
1907 : pszOpt = CPLGetConfigOption( "ECWP_CACHE_LOCATION", NULL );
1908 : if( pszOpt )
1909 : {
1910 : NCSecwSetConfig( NCSCFG_ECWP_CACHE_LOCATION, pszOpt );
1911 : NCSecwSetConfig( NCSCFG_ECWP_CACHE_ENABLED, (BOOLEAN) TRUE );
1912 : }
1913 : #endif
1914 :
1915 : /* -------------------------------------------------------------------- */
1916 : /* Various other configuration items. */
1917 : /* -------------------------------------------------------------------- */
1918 6 : pszOpt = CPLGetConfigOption( "ECWP_BLOCKING_TIME_MS", NULL );
1919 6 : if( pszOpt )
1920 : NCSecwSetConfig( NCSCFG_BLOCKING_TIME_MS,
1921 0 : (NCSTimeStampMs) atoi(pszOpt) );
1922 :
1923 : // I believe 10s means we wait for complete data back from
1924 : // ECWP almost all the time which is good for our blocking model.
1925 6 : pszOpt = CPLGetConfigOption( "ECWP_REFRESH_TIME_MS", "10000" );
1926 6 : if( pszOpt )
1927 : NCSecwSetConfig( NCSCFG_REFRESH_TIME_MS,
1928 6 : (NCSTimeStampMs) atoi(pszOpt) );
1929 :
1930 6 : pszOpt = CPLGetConfigOption( "ECW_TEXTURE_DITHER", NULL );
1931 6 : if( pszOpt )
1932 : NCSecwSetConfig( NCSCFG_TEXTURE_DITHER,
1933 0 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
1934 :
1935 :
1936 6 : pszOpt = CPLGetConfigOption( "ECW_FORCE_FILE_REOPEN", NULL );
1937 6 : if( pszOpt )
1938 : NCSecwSetConfig( NCSCFG_FORCE_FILE_REOPEN,
1939 0 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
1940 :
1941 6 : pszOpt = CPLGetConfigOption( "ECW_CACHE_MAXOPEN", NULL );
1942 6 : if( pszOpt )
1943 0 : NCSecwSetConfig( NCSCFG_CACHE_MAXOPEN, (UINT32) atoi(pszOpt) );
1944 :
1945 : #if ECWSDK_VERSION >= 40
1946 : pszOpt = CPLGetConfigOption( "ECW_AUTOGEN_J2I", NULL );
1947 : if( pszOpt )
1948 : NCSecwSetConfig( NCSCFG_JP2_AUTOGEN_J2I,
1949 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
1950 :
1951 : pszOpt = CPLGetConfigOption( "ECW_OPTIMIZE_USE_NEAREST_NEIGHBOUR", NULL );
1952 : if( pszOpt )
1953 : NCSecwSetConfig( NCSCFG_OPTIMIZE_USE_NEAREST_NEIGHBOUR,
1954 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
1955 :
1956 :
1957 : pszOpt = CPLGetConfigOption( "ECW_RESILIENT_DECODING", NULL );
1958 : if( pszOpt )
1959 : NCSecwSetConfig( NCSCFG_RESILIENT_DECODING,
1960 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
1961 : #endif
1962 : }
1963 :
1964 : /************************************************************************/
1965 : /* GDALDeregister_ECW() */
1966 : /************************************************************************/
1967 :
1968 1057 : void GDALDeregister_ECW( GDALDriver * )
1969 :
1970 : {
1971 : /* For unknown reason, this cleanup can take up to 3 seconds (see #3134). */
1972 : /* Not worth it */
1973 : #ifdef notdef
1974 : if( bNCSInitialized )
1975 : {
1976 : bNCSInitialized = FALSE;
1977 : NCSecwShutdown();
1978 : }
1979 :
1980 : if( hECWDatasetMutex != NULL )
1981 : {
1982 : CPLDestroyMutex( hECWDatasetMutex );
1983 : hECWDatasetMutex = NULL;
1984 : }
1985 : #endif
1986 1057 : }
1987 :
1988 : /************************************************************************/
1989 : /* GDALRegister_ECW() */
1990 : /************************************************************************/
1991 :
1992 1135 : void GDALRegister_ECW()
1993 :
1994 : {
1995 : #ifdef FRMT_ecw
1996 : GDALDriver *poDriver;
1997 :
1998 1135 : if (! GDAL_CHECK_VERSION("ECW driver"))
1999 0 : return;
2000 :
2001 1135 : if( GDALGetDriverByName( "ECW" ) == NULL )
2002 : {
2003 1093 : poDriver = new GDALDriver();
2004 :
2005 1093 : poDriver->SetDescription( "ECW" );
2006 :
2007 1093 : CPLString osLongName = "ERDAS Compressed Wavelets (SDK ";
2008 :
2009 : #ifdef NCS_ECWSDK_VERSION_STRING
2010 : osLongName += NCS_ECWSDK_VERSION_STRING;
2011 : #else
2012 1093 : osLongName += "3.x";
2013 : #endif
2014 1093 : osLongName += ")";
2015 :
2016 1093 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, osLongName );
2017 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
2018 1093 : "frmt_ecw.html" );
2019 1093 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "ecw" );
2020 :
2021 1093 : poDriver->pfnIdentify = ECWDataset::IdentifyECW;
2022 1093 : poDriver->pfnOpen = ECWDataset::OpenECW;
2023 1093 : poDriver->pfnUnloadDriver = GDALDeregister_ECW;
2024 : #ifdef HAVE_COMPRESS
2025 : // The create method seems not to work properly.
2026 : // poDriver->pfnCreate = ECWCreateECW;
2027 1093 : poDriver->pfnCreateCopy = ECWCreateCopyECW;
2028 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
2029 1093 : "Byte" );
2030 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
2031 : "<CreationOptionList>"
2032 : " <Option name='TARGET' type='float' description='Compression Percentage' />"
2033 : " <Option name='PROJ' type='string' description='ECW Projection Name'/>"
2034 : " <Option name='DATUM' type='string' description='ECW Datum Name' />"
2035 :
2036 : #if ECWSDK_VERSION < 40
2037 : " <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
2038 : #else
2039 : " <Option name='ECW_ENCODE_KEY' type='string' description='OEM Compress Key from ERDAS.'/>"
2040 : " <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM Company Name.'/>"
2041 : #endif
2042 :
2043 1093 : "</CreationOptionList>" );
2044 : #else
2045 : /* In read-only mode, we support VirtualIO. This is not the case */
2046 : /* for ECWCreateCopyECW() */
2047 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
2048 : #endif
2049 :
2050 1093 : GetGDALDriverManager()->RegisterDriver( poDriver );
2051 : }
2052 : #endif /* def FRMT_ecw */
2053 : }
2054 :
2055 : /************************************************************************/
2056 : /* GDALRegister_ECW_JP2ECW() */
2057 : /* */
2058 : /* This function exists so that when built as a plugin, there */
2059 : /* is a function that will register both drivers. */
2060 : /************************************************************************/
2061 :
2062 0 : void GDALRegister_ECW_JP2ECW()
2063 :
2064 : {
2065 0 : GDALRegister_ECW();
2066 0 : GDALRegister_JP2ECW();
2067 0 : }
2068 :
2069 : /************************************************************************/
2070 : /* ECWDatasetOpenJPEG2000() */
2071 : /************************************************************************/
2072 34 : GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo)
2073 : {
2074 34 : return ECWDataset::OpenJPEG2000(poOpenInfo);
2075 : }
2076 :
2077 : /************************************************************************/
2078 : /* GDALRegister_JP2ECW() */
2079 : /************************************************************************/
2080 1135 : void GDALRegister_JP2ECW()
2081 :
2082 : {
2083 : #ifdef FRMT_ecw
2084 : GDALDriver *poDriver;
2085 :
2086 1135 : if (! GDAL_CHECK_VERSION("JP2ECW driver"))
2087 0 : return;
2088 :
2089 1135 : if( GDALGetDriverByName( "JP2ECW" ) == NULL )
2090 : {
2091 1093 : poDriver = new GDALDriver();
2092 :
2093 1093 : poDriver->SetDescription( "JP2ECW" );
2094 :
2095 1093 : CPLString osLongName = "ERDAS JPEG2000 (SDK ";
2096 :
2097 : #ifdef NCS_ECWSDK_VERSION_STRING
2098 : osLongName += NCS_ECWSDK_VERSION_STRING;
2099 : #else
2100 1093 : osLongName += "3.x";
2101 : #endif
2102 1093 : osLongName += ")";
2103 :
2104 1093 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, osLongName );
2105 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
2106 1093 : "frmt_jp2ecw.html" );
2107 1093 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
2108 1093 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
2109 :
2110 1093 : poDriver->pfnIdentify = ECWDataset::IdentifyJPEG2000;
2111 1093 : poDriver->pfnOpen = ECWDataset::OpenJPEG2000;
2112 : #ifdef HAVE_COMPRESS
2113 1093 : poDriver->pfnCreate = ECWCreateJPEG2000;
2114 1093 : poDriver->pfnCreateCopy = ECWCreateCopyJPEG2000;
2115 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
2116 1093 : "Byte UInt16 Int16 UInt32 Int32 Float32 Float64" );
2117 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
2118 : "<CreationOptionList>"
2119 : " <Option name='TARGET' type='float' description='Compression Percentage' />"
2120 : " <Option name='PROJ' type='string' description='ECW Projection Name'/>"
2121 : " <Option name='DATUM' type='string' description='ECW Datum Name' />"
2122 : " <Option name='UNITS' type='string-select' description='ECW Projection Units'>"
2123 : " <Value>METERS</Value>"
2124 : " <Value>FEET</Value>"
2125 : " </Option>"
2126 :
2127 : #if ECWSDK_VERSION < 40
2128 : " <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
2129 : #else
2130 : " <Option name='ECW_ENCODE_KEY' type='string' description='OEM Compress Key from ERDAS.'/>"
2131 : " <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM Company Name.'/>"
2132 : #endif
2133 :
2134 : " <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
2135 : " <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
2136 : " <Option name='PROFILE' type='string-select'>"
2137 : " <Value>BASELINE_0</Value>"
2138 : " <Value>BASELINE_1</Value>"
2139 : " <Value>BASELINE_2</Value>"
2140 : " <Value>NPJE</Value>"
2141 : " <Value>EPJE</Value>"
2142 : " </Option>"
2143 : " <Option name='PROGRESSION' type='string-select'>"
2144 : " <Value>LRCP</Value>"
2145 : " <Value>RLCP</Value>"
2146 : " <Value>RPCL</Value>"
2147 : " </Option>"
2148 : " <Option name='CODESTREAM_ONLY' type='boolean' description='No JP2 wrapper'/>"
2149 : " <Option name='LEVELS' type='int'/>"
2150 : " <Option name='LAYERS' type='int'/>"
2151 : " <Option name='PRECINCT_WIDTH' type='int'/>"
2152 : " <Option name='PRECINCT_HEIGHT' type='int'/>"
2153 : " <Option name='TILE_WIDTH' type='int'/>"
2154 : " <Option name='TILE_HEIGHT' type='int'/>"
2155 : " <Option name='INCLUDE_SOP' type='boolean'/>"
2156 : " <Option name='INCLUDE_EPH' type='boolean'/>"
2157 : " <Option name='DECOMPRESS_LAYERS' type='int'/>"
2158 : " <Option name='DECOMPRESS_RECONSTRUCTION_PARAMETER' type='float'/>"
2159 1093 : "</CreationOptionList>" );
2160 : #endif
2161 :
2162 1093 : GetGDALDriverManager()->RegisterDriver( poDriver );
2163 : }
2164 : #endif /* def FRMT_ecw */
2165 4029 : }
|