RPFToc* RPFTOCReadFromBuffer(const char* pszFilename, VSILFILE* fp, const char* tocHeader) { tocHeader += 1; /* skip endian */ tocHeader += 2; /* skip header length */ tocHeader += 12; /* skip file name : this should be A.TOC (padded) */ tocHeader += 1; /* skip new */ tocHeader += 15; /* skip standard_num */ tocHeader += 8; /* skip standard_date */ tocHeader += 1; /* skip classification */ tocHeader += 2; /* skip country */ tocHeader += 2; /* skip release */ unsigned int locationSectionPhysicalLocation; memcpy(&locationSectionPhysicalLocation, tocHeader, sizeof(unsigned int)); CPL_MSBPTR32(&locationSectionPhysicalLocation); if( VSIFSeekL( fp, locationSectionPhysicalLocation, SEEK_SET ) != 0) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Unable to seek to locationSectionPhysicalLocation at offset %d.", locationSectionPhysicalLocation ); return nullptr; } int nSections; NITFLocation* pasLocations = NITFReadRPFLocationTable(fp, &nSections); unsigned int boundaryRectangleSectionSubHeaderPhysIndex = 0; unsigned int boundaryRectangleTablePhysIndex = 0; unsigned int frameFileIndexSectionSubHeaderPhysIndex = 0; unsigned int frameFileIndexSubsectionPhysIndex = 0; for( int i = 0; i < nSections; i++ ) { if (pasLocations[i].nLocId == LID_BoundaryRectangleSectionSubheader) { boundaryRectangleSectionSubHeaderPhysIndex = pasLocations[i].nLocOffset; } else if (pasLocations[i].nLocId == LID_BoundaryRectangleTable) { boundaryRectangleTablePhysIndex = pasLocations[i].nLocOffset; } else if (pasLocations[i].nLocId == LID_FrameFileIndexSectionSubHeader) { frameFileIndexSectionSubHeaderPhysIndex = pasLocations[i].nLocOffset; } else if (pasLocations[i].nLocId == LID_FrameFileIndexSubsection) { frameFileIndexSubsectionPhysIndex = pasLocations[i].nLocOffset; } } CPLFree(pasLocations); if (boundaryRectangleSectionSubHeaderPhysIndex == 0) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Can't find LID_BoundaryRectangleSectionSubheader." ); return nullptr; } if (boundaryRectangleTablePhysIndex == 0) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Can't find LID_BoundaryRectangleTable." ); return nullptr; } if (frameFileIndexSectionSubHeaderPhysIndex == 0) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Can't find LID_FrameFileIndexSectionSubHeader." ); return nullptr; } if (frameFileIndexSubsectionPhysIndex == 0) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Can't find LID_FrameFileIndexSubsection." ); return nullptr; } if( VSIFSeekL( fp, boundaryRectangleSectionSubHeaderPhysIndex, SEEK_SET ) != 0) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Unable to seek to boundaryRectangleSectionSubHeaderPhysIndex at offset %d.", boundaryRectangleSectionSubHeaderPhysIndex ); return nullptr; } unsigned int boundaryRectangleTableOffset; bool bOK = VSIFReadL( &boundaryRectangleTableOffset, sizeof(boundaryRectangleTableOffset), 1, fp) == 1; CPL_MSBPTR32( &boundaryRectangleTableOffset ); unsigned short boundaryRectangleCount; bOK &= VSIFReadL( &boundaryRectangleCount, sizeof(boundaryRectangleCount), 1, fp) == 1; CPL_MSBPTR16( &boundaryRectangleCount ); if( !bOK || VSIFSeekL( fp, boundaryRectangleTablePhysIndex, SEEK_SET ) != 0) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Unable to seek to boundaryRectangleTablePhysIndex at offset %d.", boundaryRectangleTablePhysIndex ); return nullptr; } RPFToc* toc = reinterpret_cast<RPFToc *>( CPLMalloc( sizeof( RPFToc ) ) ); toc->nEntries = boundaryRectangleCount; toc->entries = reinterpret_cast<RPFTocEntry *>( CPLMalloc( boundaryRectangleCount * sizeof(RPFTocEntry) ) ); memset(toc->entries, 0, boundaryRectangleCount * sizeof(RPFTocEntry)); for( int i = 0; i < toc->nEntries; i++ ) { toc->entries[i].isOverviewOrLegend = 0; bOK &= VSIFReadL( toc->entries[i].type, 1, 5, fp) == 5; toc->entries[i].type[5] = 0; RPFTOCTrim(toc->entries[i].type); bOK &= VSIFReadL( toc->entries[i].compression, 1, 5, fp) == 5; toc->entries[i].compression[5] = 0; RPFTOCTrim(toc->entries[i].compression); bOK &= VSIFReadL( toc->entries[i].scale, 1, 12, fp) == 12; toc->entries[i].scale[12] = 0; RPFTOCTrim(toc->entries[i].scale); if (toc->entries[i].scale[0] == '1' && toc->entries[i].scale[1] == ':') { memmove(toc->entries[i].scale, toc->entries[i].scale+2, strlen(toc->entries[i].scale+2)+1); } bOK &= VSIFReadL( toc->entries[i].zone, 1, 1, fp) == 1; toc->entries[i].zone[1] = 0; RPFTOCTrim(toc->entries[i].zone); bOK &= VSIFReadL( toc->entries[i].producer, 1, 5, fp) == 5; toc->entries[i].producer[5] = 0; RPFTOCTrim(toc->entries[i].producer); bOK &= VSIFReadL( &toc->entries[i].nwLat, sizeof(double), 1, fp) == 1; CPL_MSBPTR64( &toc->entries[i].nwLat); bOK &= VSIFReadL( &toc->entries[i].nwLong, sizeof(double), 1, fp) == 1; CPL_MSBPTR64( &toc->entries[i].nwLong); bOK &= VSIFReadL( &toc->entries[i].swLat, sizeof(double), 1, fp) == 1; CPL_MSBPTR64( &toc->entries[i].swLat); bOK &= VSIFReadL( &toc->entries[i].swLong, sizeof(double), 1, fp) == 1; CPL_MSBPTR64( &toc->entries[i].swLong); bOK &= VSIFReadL( &toc->entries[i].neLat, sizeof(double), 1, fp) == 1; CPL_MSBPTR64( &toc->entries[i].neLat); bOK &= VSIFReadL( &toc->entries[i].neLong, sizeof(double), 1, fp) == 1; CPL_MSBPTR64( &toc->entries[i].neLong); bOK &= VSIFReadL( &toc->entries[i].seLat, sizeof(double), 1, fp) == 1; CPL_MSBPTR64( &toc->entries[i].seLat); bOK &= VSIFReadL( &toc->entries[i].seLong, sizeof(double), 1, fp) == 1; CPL_MSBPTR64( &toc->entries[i].seLong); bOK &= VSIFReadL( &toc->entries[i].vertResolution, sizeof(double), 1, fp) == 1; CPL_MSBPTR64( &toc->entries[i].vertResolution); bOK &= VSIFReadL( &toc->entries[i].horizResolution, sizeof(double), 1, fp) == 1; CPL_MSBPTR64( &toc->entries[i].horizResolution); bOK &= VSIFReadL( &toc->entries[i].vertInterval, sizeof(double), 1, fp) == 1; CPL_MSBPTR64( &toc->entries[i].vertInterval); bOK &= VSIFReadL( &toc->entries[i].horizInterval, sizeof(double), 1, fp) == 1; CPL_MSBPTR64( &toc->entries[i].horizInterval); bOK &= VSIFReadL( &toc->entries[i].nVertFrames, sizeof(int), 1, fp) == 1; CPL_MSBPTR32( &toc->entries[i].nVertFrames ); bOK &= VSIFReadL( &toc->entries[i].nHorizFrames, sizeof(int), 1, fp) == 1; CPL_MSBPTR32( &toc->entries[i].nHorizFrames ); if( !bOK ) { CPLError(CE_Failure, CPLE_FileIO, "I/O error"); toc->entries[i].nVertFrames = 0; toc->entries[i].nHorizFrames = 0; RPFTOCFree(toc); return nullptr; } if( toc->entries[i].vertInterval <= 1e-10 || !CPLIsFinite(toc->entries[i].vertInterval) || toc->entries[i].horizInterval <= 1e-10 || !CPLIsFinite(toc->entries[i].horizInterval) || !(fabs(toc->entries[i].seLong) <= 360.0) || !(fabs(toc->entries[i].nwLong) <= 360.0) || !(fabs(toc->entries[i].nwLat) <= 90.0) || !(fabs(toc->entries[i].seLat) <= 90.0) || toc->entries[i].seLong < toc->entries[i].nwLong || toc->entries[i].nwLat < toc->entries[i].seLat || toc->entries[i].nHorizFrames == 0 || toc->entries[i].nVertFrames == 0 || toc->entries[i].nHorizFrames > INT_MAX / toc->entries[i].nVertFrames ) { CPLError(CE_Failure, CPLE_FileIO, "Invalid TOC entry"); toc->entries[i].nVertFrames = 0; toc->entries[i].nHorizFrames = 0; RPFTOCFree(toc); return nullptr; } // TODO: We could probably use another data structure, like a list, // instead of an array referenced by the frame coordinate... if( static_cast<int>(toc->entries[i].nHorizFrames * toc->entries[i].nVertFrames) > atoi(CPLGetConfigOption("RPFTOC_MAX_FRAME_COUNT", "1000000")) ) { CPLError(CE_Failure, CPLE_AppDefined, "nHorizFrames=%d x nVertFrames=%d > %d. Please raise " "the value of the RPFTOC_MAX_FRAME_COUNT configuration " "option to more than %d if this dataset is legitimate.", toc->entries[i].nHorizFrames, toc->entries[i].nVertFrames, atoi(CPLGetConfigOption("RPFTOC_MAX_FRAME_COUNT", "1000000")), toc->entries[i].nHorizFrames * toc->entries[i].nVertFrames ); toc->entries[i].frameEntries = nullptr; } else { toc->entries[i].frameEntries = reinterpret_cast<RPFTocFrameEntry*>( VSI_CALLOC_VERBOSE( toc->entries[i].nVertFrames * toc->entries[i].nHorizFrames, sizeof(RPFTocFrameEntry) ) ); } if (toc->entries[i].frameEntries == nullptr) { toc->entries[i].nVertFrames = 0; toc->entries[i].nHorizFrames = 0; RPFTOCFree(toc); return nullptr; } CPLDebug("RPFTOC", "[%d] type=%s, compression=%s, scale=%s, zone=%s, producer=%s, nVertFrames=%d, nHorizFrames=%d", i, toc->entries[i].type, toc->entries[i].compression, toc->entries[i].scale, toc->entries[i].zone, toc->entries[i].producer, toc->entries[i].nVertFrames, toc->entries[i].nHorizFrames); } if( VSIFSeekL( fp, frameFileIndexSectionSubHeaderPhysIndex, SEEK_SET ) != 0) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Unable to seek to frameFileIndexSectionSubHeaderPhysIndex at offset %d.", frameFileIndexSectionSubHeaderPhysIndex ); RPFTOCFree(toc); return nullptr; } /* Skip 1 byte security classification */ bOK &= VSIFSeekL( fp, 1, SEEK_CUR ) == 0; unsigned int frameIndexTableOffset; bOK &= VSIFReadL( &frameIndexTableOffset, sizeof(frameIndexTableOffset), 1, fp) == 1; CPL_MSBPTR32( &frameIndexTableOffset ); unsigned int nFrameFileIndexRecords; bOK &= VSIFReadL( &nFrameFileIndexRecords, sizeof(nFrameFileIndexRecords), 1, fp) == 1; CPL_MSBPTR32( &nFrameFileIndexRecords ); unsigned short nFrameFilePathnameRecords; bOK &= VSIFReadL( &nFrameFilePathnameRecords, sizeof(nFrameFilePathnameRecords), 1, fp) == 1; CPL_MSBPTR16( &nFrameFilePathnameRecords ); unsigned short frameFileIndexRecordLength; bOK &= VSIFReadL( &frameFileIndexRecordLength, sizeof(frameFileIndexRecordLength), 1, fp) == 1; CPL_MSBPTR16( &frameFileIndexRecordLength ); if( frameFileIndexRecordLength < 3 * sizeof(short) ) { CPLError(CE_Failure, CPLE_FileIO, "Invalid file"); RPFTOCFree(toc); return nullptr; } if( !bOK ) { CPLError(CE_Failure, CPLE_FileIO, "I/O error"); RPFTOCFree(toc); return nullptr; } int newBoundaryId = 0; for( int i = 0; i < static_cast<int>( nFrameFileIndexRecords ); i++ ) { if( VSIFSeekL( fp, frameFileIndexSubsectionPhysIndex + frameFileIndexRecordLength * i, SEEK_SET ) != 0) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Unable to seek to frameFileIndexSubsectionPhysIndex(%d) at offset %d.", i, frameFileIndexSubsectionPhysIndex + frameFileIndexRecordLength * i); RPFTOCFree(toc); return nullptr; } unsigned short boundaryId; if( VSIFReadL( &boundaryId, sizeof(boundaryId), 1, fp) != 1 ) { CPLError(CE_Failure, CPLE_FileIO, "I/O error"); RPFTOCFree(toc); return nullptr; } CPL_MSBPTR16( &boundaryId ); if (i == 0 && boundaryId == 0) newBoundaryId = 1; if (newBoundaryId == 0) boundaryId--; if (boundaryId >= toc->nEntries) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Bad boundary id (%d) for frame file index %d.", boundaryId, i); RPFTOCFree(toc); return nullptr; } RPFTocEntry* entry = &toc->entries[boundaryId]; entry->boundaryId = boundaryId; unsigned short frameRow; bOK &= VSIFReadL( &frameRow, sizeof(frameRow), 1, fp) == 1; CPL_MSBPTR16( &frameRow ); unsigned short frameCol; bOK &= VSIFReadL( &frameCol, sizeof(frameCol), 1, fp) == 1; CPL_MSBPTR16( &frameCol ); if( !bOK ) { CPLError(CE_Failure, CPLE_FileIO, "I/O error"); RPFTOCFree(toc); return nullptr; } if (newBoundaryId == 0) { frameRow--; frameCol--; } else { /* Trick so that frames are numbered north to south */ frameRow = (unsigned short)((entry->nVertFrames-1) - frameRow); } if (frameRow >= entry->nVertFrames) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Bad row num (%d) for frame file index %d.", frameRow, i); RPFTOCFree(toc); return nullptr; } if (frameCol >= entry->nHorizFrames) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Bad col num (%d) for frame file index %d.", frameCol, i); RPFTOCFree(toc); return nullptr; } RPFTocFrameEntry* frameEntry = &entry->frameEntries[frameRow * entry->nHorizFrames + frameCol ]; frameEntry->frameRow = frameRow; frameEntry->frameCol = frameCol; if (frameEntry->exists) { CPLError( CE_Warning, CPLE_AppDefined, "Frame entry(%d,%d) for frame file index %d was already found.", frameRow, frameCol, i); CPLFree(frameEntry->directory); frameEntry->directory = nullptr; CPLFree(frameEntry->fullFilePath); frameEntry->fullFilePath = nullptr; frameEntry->exists = 0; } unsigned int offsetFrameFilePathName; bOK &= VSIFReadL( &offsetFrameFilePathName, sizeof(offsetFrameFilePathName), 1, fp) == 1; CPL_MSBPTR32( &offsetFrameFilePathName ); bOK &= VSIFReadL( frameEntry->filename, 1, 12, fp) == 12; if( !bOK ) { CPLError(CE_Failure, CPLE_FileIO, "I/O error"); RPFTOCFree(toc); return nullptr; } frameEntry->filename[12] = '\0'; bOK &= strlen(frameEntry->filename) > 0; /* Check if the filename is an overview or legend */ for( int j = 0; j < 12; j++ ) { if (strcmp(&(frameEntry->filename[j]),".OVR") == 0 || strcmp(&(frameEntry->filename[j]),".ovr") == 0 || strcmp(&(frameEntry->filename[j]),".LGD") == 0 || strcmp(&(frameEntry->filename[j]),".lgd") == 0) { entry->isOverviewOrLegend = TRUE; break; } } /* Extract series code */ if (entry->seriesAbbreviation == nullptr) { const NITFSeries* series = NITFGetSeriesInfo(frameEntry->filename); if (series) { entry->seriesAbbreviation = series->abbreviation; entry->seriesName = series->name; } } /* Get file geo reference */ bOK &= VSIFReadL( frameEntry->georef, 1, 6, fp) == 6; frameEntry->georef[6] = '\0'; /* Go to start of pathname record */ /* New path_off offset from start of frame file index section of TOC?? */ /* Add pathoffset wrt frame file index table subsection (loc[3]) */ if( !bOK || VSIFSeekL( fp, frameFileIndexSubsectionPhysIndex + offsetFrameFilePathName, SEEK_SET ) != 0) { CPLError( CE_Failure, CPLE_NotSupported, "Invalid TOC file. Unable to seek to " "frameFileIndexSubsectionPhysIndex + " "offsetFrameFilePathName(%d) at offset %d.", i, frameFileIndexSubsectionPhysIndex + offsetFrameFilePathName); RPFTOCFree(toc); return nullptr; } unsigned short pathLength; bOK &= VSIFReadL( &pathLength, sizeof(pathLength), 1, fp) == 1; CPL_MSBPTR16( &pathLength ); /* if nFrameFileIndexRecords == 65535 and pathLength == 65535 for each record, this leads to 4 GB allocation... Protect against this case */ if (!bOK || pathLength == 0 || pathLength > 256) { CPLError( CE_Failure, CPLE_NotSupported, "Path length is invalid : %d. Probably corrupted TOC file.", static_cast<int>( pathLength ) ); RPFTOCFree(toc); return nullptr; } frameEntry->directory = reinterpret_cast<char *>( CPLMalloc(pathLength+1) ); bOK &= VSIFReadL( frameEntry->directory, 1, pathLength, fp) == pathLength; if( !bOK ) { CPLError(CE_Failure, CPLE_FileIO, "I/O error"); RPFTOCFree(toc); return nullptr; } frameEntry->directory[pathLength] = 0; if (pathLength > 0 && frameEntry->directory[pathLength-1] == '/') frameEntry->directory[pathLength-1] = 0; if (frameEntry->directory[0] == '.' && frameEntry->directory[1] == '/') { memmove(frameEntry->directory, frameEntry->directory+2, strlen(frameEntry->directory+2)+1); // Some A.TOC have subdirectory names like ".//X/" ... (#5979) // Check if it was not intended to be "./X/" instead. VSIStatBufL sStatBuf; if( frameEntry->directory[0] == '/' && VSIStatL(CPLFormFilename(CPLGetDirname(pszFilename), frameEntry->directory+1, nullptr), &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode) ) { memmove(frameEntry->directory, frameEntry->directory+1, strlen(frameEntry->directory+1)+1); } } { char* baseDir = CPLStrdup(CPLGetDirname(pszFilename)); VSIStatBufL sStatBuf; char* subdir = nullptr; if (CPLIsFilenameRelative(frameEntry->directory) == FALSE) subdir = CPLStrdup(frameEntry->directory); else if (frameEntry->directory[0] == '.' && frameEntry->directory[1] == 0) subdir = CPLStrdup(baseDir); else subdir = CPLStrdup(CPLFormFilename(baseDir, frameEntry->directory, nullptr)); #if !defined(_WIN32) && !defined(_WIN32_CE) if( VSIStatL( subdir, &sStatBuf ) != 0 && strlen(subdir) > strlen(baseDir) && subdir[strlen(baseDir)] != 0) { char* c = subdir + strlen(baseDir)+1; while(*c) { if (*c >= 'A' && *c <= 'Z') *c += 'a' - 'A'; c++; } } #endif frameEntry->fullFilePath = CPLStrdup(CPLFormFilename( subdir, frameEntry->filename, nullptr)); if( VSIStatL( frameEntry->fullFilePath, &sStatBuf ) != 0 ) { #if !defined(_WIN32) && !defined(_WIN32_CE) if( strlen(frameEntry->fullFilePath) > strlen(subdir) ) { char* c = frameEntry->fullFilePath + strlen(subdir)+1; while(*c) { if (*c >= 'A' && *c <= 'Z') *c += 'a' - 'A'; c++; } } if( VSIStatL( frameEntry->fullFilePath, &sStatBuf ) != 0 ) #endif { frameEntry->fileExists = 0; CPLError( CE_Warning, CPLE_AppDefined, "File %s does not exist.", frameEntry->fullFilePath ); } #if !defined(_WIN32) && !defined(_WIN32_CE) else { frameEntry->fileExists = 1; } #endif } else { frameEntry->fileExists = 1; } CPLFree(subdir); CPLFree(baseDir); } CPLDebug("RPFTOC", "Entry %d : %s,%s (%d, %d)", boundaryId, frameEntry->directory, frameEntry->filename, frameRow, frameCol); frameEntry->exists = 1; } return toc; }
GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo ) { if( Identify(poOpenInfo) == FALSE ) return NULL; bool rik3header = false; if( EQUALN((const char *) poOpenInfo->pabyHeader, "RIK3", 4) ) { rik3header = true; VSIFSeekL( poOpenInfo->fpL, 4, SEEK_SET ); } else VSIFSeekL( poOpenInfo->fpL, 0, SEEK_SET ); /* -------------------------------------------------------------------- */ /* Read the map name. */ /* -------------------------------------------------------------------- */ char name[1024]; GUInt16 nameLength = GetRikString( poOpenInfo->fpL, name, sizeof(name) ); if( nameLength > sizeof(name) - 1 ) { return NULL; } if( !rik3header ) { if( nameLength == 0 || nameLength != strlen(name) ) return NULL; } /* -------------------------------------------------------------------- */ /* Read the header. */ /* -------------------------------------------------------------------- */ RIKHeader header; double metersPerPixel; const char *headerType = "RIK3"; if( rik3header ) { /* -------------------------------------------------------------------- */ /* RIK3 header. */ /* -------------------------------------------------------------------- */ // Read projection name char projection[1024]; GUInt16 projLength = GetRikString( poOpenInfo->fpL, projection, sizeof(projection) ); if( projLength > sizeof(projection) - 1 ) { // Unreasonable string length, assume wrong format return NULL; } // Read unknown string projLength = GetRikString( poOpenInfo->fpL, projection, sizeof(projection) ); // Read map north edge char tmpStr[16]; GUInt16 tmpLength = GetRikString( poOpenInfo->fpL, tmpStr, sizeof(tmpStr) ); if( tmpLength > sizeof(tmpStr) - 1 ) { // Unreasonable string length, assume wrong format return NULL; } header.fNorth = CPLAtof( tmpStr ); // Read map west edge tmpLength = GetRikString( poOpenInfo->fpL, tmpStr, sizeof(tmpStr) ); if( tmpLength > sizeof(tmpStr) - 1 ) { // Unreasonable string length, assume wrong format return NULL; } header.fWest = CPLAtof( tmpStr ); // Read binary values VSIFReadL( &header.iScale, 1, sizeof(header.iScale), poOpenInfo->fpL ); VSIFReadL( &header.iMPPNum, 1, sizeof(header.iMPPNum), poOpenInfo->fpL ); VSIFReadL( &header.iBlockWidth, 1, sizeof(header.iBlockWidth), poOpenInfo->fpL ); VSIFReadL( &header.iBlockHeight, 1, sizeof(header.iBlockHeight), poOpenInfo->fpL ); VSIFReadL( &header.iHorBlocks, 1, sizeof(header.iHorBlocks), poOpenInfo->fpL ); VSIFReadL( &header.iVertBlocks, 1, sizeof(header.iVertBlocks), poOpenInfo->fpL ); #ifdef CPL_MSB CPL_SWAP32PTR( &header.iScale ); CPL_SWAP32PTR( &header.iMPPNum ); CPL_SWAP32PTR( &header.iBlockWidth ); CPL_SWAP32PTR( &header.iBlockHeight ); CPL_SWAP32PTR( &header.iHorBlocks ); CPL_SWAP32PTR( &header.iVertBlocks ); #endif VSIFReadL( &header.iBitsPerPixel, 1, sizeof(header.iBitsPerPixel), poOpenInfo->fpL ); VSIFReadL( &header.iOptions, 1, sizeof(header.iOptions), poOpenInfo->fpL ); header.iUnknown = header.iOptions; VSIFReadL( &header.iOptions, 1, sizeof(header.iOptions), poOpenInfo->fpL ); header.fSouth = header.fNorth - header.iVertBlocks * header.iBlockHeight * header.iMPPNum; header.fEast = header.fWest + header.iHorBlocks * header.iBlockWidth * header.iMPPNum; metersPerPixel = header.iMPPNum; } else { /* -------------------------------------------------------------------- */ /* Old RIK header. */ /* -------------------------------------------------------------------- */ VSIFReadL( &header.iUnknown, 1, sizeof(header.iUnknown), poOpenInfo->fpL ); VSIFReadL( &header.fSouth, 1, sizeof(header.fSouth), poOpenInfo->fpL ); VSIFReadL( &header.fWest, 1, sizeof(header.fWest), poOpenInfo->fpL ); VSIFReadL( &header.fNorth, 1, sizeof(header.fNorth), poOpenInfo->fpL ); VSIFReadL( &header.fEast, 1, sizeof(header.fEast), poOpenInfo->fpL ); VSIFReadL( &header.iScale, 1, sizeof(header.iScale), poOpenInfo->fpL ); VSIFReadL( &header.iMPPNum, 1, sizeof(header.iMPPNum), poOpenInfo->fpL ); #ifdef CPL_MSB CPL_SWAP64PTR( &header.fSouth ); CPL_SWAP64PTR( &header.fWest ); CPL_SWAP64PTR( &header.fNorth ); CPL_SWAP64PTR( &header.fEast ); CPL_SWAP32PTR( &header.iScale ); CPL_SWAP32PTR( &header.iMPPNum ); #endif if (!CPLIsFinite(header.fSouth) | !CPLIsFinite(header.fWest) | !CPLIsFinite(header.fNorth) | !CPLIsFinite(header.fEast)) return NULL; bool offsetBounds; offsetBounds = header.fSouth < 4000000; header.iMPPDen = 1; if( offsetBounds ) { header.fSouth += 4002995; header.fNorth += 5004000; header.fWest += 201000; header.fEast += 302005; VSIFReadL( &header.iMPPDen, 1, sizeof(header.iMPPDen), poOpenInfo->fpL ); #ifdef CPL_MSB CPL_SWAP32PTR( &header.iMPPDen ); #endif headerType = "RIK1"; } else { headerType = "RIK2"; } metersPerPixel = header.iMPPNum / double(header.iMPPDen); VSIFReadL( &header.iBlockWidth, 1, sizeof(header.iBlockWidth), poOpenInfo->fpL ); VSIFReadL( &header.iBlockHeight, 1, sizeof(header.iBlockHeight), poOpenInfo->fpL ); VSIFReadL( &header.iHorBlocks, 1, sizeof(header.iHorBlocks), poOpenInfo->fpL ); #ifdef CPL_MSB CPL_SWAP32PTR( &header.iBlockWidth ); CPL_SWAP32PTR( &header.iBlockHeight ); CPL_SWAP32PTR( &header.iHorBlocks ); #endif if(( header.iBlockWidth > 2000 ) || ( header.iBlockWidth < 10 ) || ( header.iBlockHeight > 2000 ) || ( header.iBlockHeight < 10 )) return NULL; if( !offsetBounds ) { VSIFReadL( &header.iVertBlocks, 1, sizeof(header.iVertBlocks), poOpenInfo->fpL ); #ifdef CPL_MSB CPL_SWAP32PTR( &header.iVertBlocks ); #endif } if( offsetBounds || !header.iVertBlocks ) { header.iVertBlocks = (GUInt32) ceil( (header.fNorth - header.fSouth) / (header.iBlockHeight * metersPerPixel) ); } #if RIK_HEADER_DEBUG CPLDebug( "RIK", "Original vertical blocks %d\n", header.iVertBlocks ); #endif VSIFReadL( &header.iBitsPerPixel, 1, sizeof(header.iBitsPerPixel), poOpenInfo->fpL ); if( header.iBitsPerPixel != 8 ) { CPLError( CE_Failure, CPLE_OpenFailed, "File %s has unsupported number of bits per pixel.\n", poOpenInfo->pszFilename ); return NULL; } VSIFReadL( &header.iOptions, 1, sizeof(header.iOptions), poOpenInfo->fpL ); if( !header.iHorBlocks || !header.iVertBlocks ) return NULL; if( header.iOptions != 0x00 && // Uncompressed header.iOptions != 0x40 && // Uncompressed header.iOptions != 0x01 && // RLE header.iOptions != 0x41 && // RLE header.iOptions != 0x0B && // LZW header.iOptions != 0x0D ) // ZLIB { CPLError( CE_Failure, CPLE_OpenFailed, "File %s. Unknown map options.\n", poOpenInfo->pszFilename ); return NULL; } } /* -------------------------------------------------------------------- */ /* Read the palette. */ /* -------------------------------------------------------------------- */ GByte palette[768]; GUInt16 i; for( i = 0; i < 256; i++ ) { VSIFReadL( &palette[i * 3 + 2], 1, 1, poOpenInfo->fpL ); VSIFReadL( &palette[i * 3 + 1], 1, 1, poOpenInfo->fpL ); VSIFReadL( &palette[i * 3 + 0], 1, 1, poOpenInfo->fpL ); } /* -------------------------------------------------------------------- */ /* Find block offsets. */ /* -------------------------------------------------------------------- */ GUInt32 blocks; GUInt32 *offsets; blocks = header.iHorBlocks * header.iVertBlocks; offsets = (GUInt32 *)CPLMalloc( blocks * sizeof(GUInt32) ); if( !offsets ) { CPLError( CE_Failure, CPLE_OpenFailed, "File %s. Unable to allocate offset table.\n", poOpenInfo->pszFilename ); return NULL; } if( header.iOptions == 0x00 ) { offsets[0] = VSIFTellL( poOpenInfo->fpL ); for( GUInt32 i = 1; i < blocks; i++ ) { offsets[i] = offsets[i - 1] + header.iBlockWidth * header.iBlockHeight; } } else { for( GUInt32 i = 0; i < blocks; i++ ) { VSIFReadL( &offsets[i], 1, sizeof(offsets[i]), poOpenInfo->fpL ); #ifdef CPL_MSB CPL_SWAP32PTR( &offsets[i] ); #endif if( rik3header ) { GUInt32 blockSize; VSIFReadL( &blockSize, 1, sizeof(blockSize), poOpenInfo->fpL ); #ifdef CPL_MSB CPL_SWAP32PTR( &blockSize ); #endif } } } /* -------------------------------------------------------------------- */ /* Final checks. */ /* -------------------------------------------------------------------- */ // File size if( VSIFEofL( poOpenInfo->fpL ) ) { CPLError( CE_Failure, CPLE_OpenFailed, "File %s. Read past end of file.\n", poOpenInfo->pszFilename ); return NULL; } VSIFSeekL( poOpenInfo->fpL, 0, SEEK_END ); GUInt32 fileSize = VSIFTellL( poOpenInfo->fpL ); #if RIK_HEADER_DEBUG CPLDebug( "RIK", "File size %d\n", fileSize ); #endif // Make sure the offset table is valid GUInt32 lastoffset = 0; for( GUInt32 y = 0; y < header.iVertBlocks; y++) { for( GUInt32 x = 0; x < header.iHorBlocks; x++) { if( !offsets[x + y * header.iHorBlocks] ) { continue; } if( offsets[x + y * header.iHorBlocks] >= fileSize ) { if( !y ) { CPLError( CE_Failure, CPLE_OpenFailed, "File %s too short.\n", poOpenInfo->pszFilename ); return NULL; } header.iVertBlocks = y; break; } if( offsets[x + y * header.iHorBlocks] < lastoffset ) { if( !y ) { CPLError( CE_Failure, CPLE_OpenFailed, "File %s. Corrupt offset table.\n", poOpenInfo->pszFilename ); return NULL; } header.iVertBlocks = y; break; } lastoffset = offsets[x + y * header.iHorBlocks]; } } #if RIK_HEADER_DEBUG CPLDebug( "RIK", "first offset %d\n" "last offset %d\n", offsets[0], lastoffset ); #endif const char *compression = "RLE"; if( header.iOptions == 0x00 || header.iOptions == 0x40 ) compression = "Uncompressed"; if( header.iOptions == 0x0b ) compression = "LZW"; if( header.iOptions == 0x0d ) compression = "ZLIB"; CPLDebug( "RIK", "RIK file parameters:\n" " name: %s\n" " header: %s\n" " unknown: 0x%X\n" " south: %f\n" " west: %f\n" " north: %f\n" " east: %f\n" " original scale: %d\n" " meters per pixel: %f\n" " block width: %d\n" " block height: %d\n" " horizontal blocks: %d\n" " vertical blocks: %d\n" " bits per pixel: %d\n" " options: 0x%X\n" " compression: %s\n", name, headerType, header.iUnknown, header.fSouth, header.fWest, header.fNorth, header.fEast, header.iScale, metersPerPixel, header.iBlockWidth, header.iBlockHeight, header.iHorBlocks, header.iVertBlocks, header.iBitsPerPixel, header.iOptions, compression); /* -------------------------------------------------------------------- */ /* Create a corresponding GDALDataset. */ /* -------------------------------------------------------------------- */ RIKDataset *poDS; poDS = new RIKDataset(); poDS->fp = poOpenInfo->fpL; poOpenInfo->fpL = NULL; poDS->fTransform[0] = header.fWest - metersPerPixel / 2.0; poDS->fTransform[1] = metersPerPixel; poDS->fTransform[2] = 0.0; poDS->fTransform[3] = header.fNorth + metersPerPixel / 2.0; poDS->fTransform[4] = 0.0; poDS->fTransform[5] = -metersPerPixel; poDS->nBlockXSize = header.iBlockWidth; poDS->nBlockYSize = header.iBlockHeight; poDS->nHorBlocks = header.iHorBlocks; poDS->nVertBlocks = header.iVertBlocks; poDS->pOffsets = offsets; poDS->options = header.iOptions; poDS->nFileSize = fileSize; poDS->nRasterXSize = header.iBlockWidth * header.iHorBlocks; poDS->nRasterYSize = header.iBlockHeight * header.iVertBlocks; poDS->nBands = 1; GDALColorEntry oEntry; poDS->poColorTable = new GDALColorTable(); for( i = 0; i < 256; i++ ) { oEntry.c1 = palette[i * 3 + 2]; // Red oEntry.c2 = palette[i * 3 + 1]; // Green oEntry.c3 = palette[i * 3]; // Blue oEntry.c4 = 255; poDS->poColorTable->SetColorEntry( i, &oEntry ); } /* -------------------------------------------------------------------- */ /* Create band information objects. */ /* -------------------------------------------------------------------- */ poDS->SetBand( 1, new RIKRasterBand( poDS, 1 )); /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ poDS->SetDescription( poOpenInfo->pszFilename ); poDS->TryLoadXML(); /* -------------------------------------------------------------------- */ /* Check for external overviews. */ /* -------------------------------------------------------------------- */ poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() ); /* -------------------------------------------------------------------- */ /* Confirm the requested access is supported. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->eAccess == GA_Update ) { delete poDS; CPLError( CE_Failure, CPLE_NotSupported, "The RIK driver does not support update access to existing" " datasets.\n" ); return NULL; } return( poDS ); }
CPLErr USGSDEMRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, CPL_UNUSED int nBlockYOff, void * pImage ) { /* int bad = FALSE; */ USGSDEMDataset *poGDS = reinterpret_cast<USGSDEMDataset *>( poDS ); /* -------------------------------------------------------------------- */ /* Initialize image buffer to nodata value. */ /* -------------------------------------------------------------------- */ for( int k = GetXSize() * GetYSize() - 1; k >= 0; k-- ) { if( GetRasterDataType() == GDT_Int16 ) reinterpret_cast<GInt16 *>( pImage )[k] = USGSDEM_NODATA; else reinterpret_cast<float *>( pImage )[k] = USGSDEM_NODATA; } /* -------------------------------------------------------------------- */ /* Seek to data. */ /* -------------------------------------------------------------------- */ CPL_IGNORE_RET_VAL(VSIFSeekL(poGDS->fp, poGDS->nDataStartOffset, 0)); double dfYMin = poGDS->adfGeoTransform[3] + (GetYSize()-0.5) * poGDS->adfGeoTransform[5]; /* -------------------------------------------------------------------- */ /* Read all the profiles into the image buffer. */ /* -------------------------------------------------------------------- */ Buffer sBuffer; sBuffer.max_size = 32768; sBuffer.buffer = reinterpret_cast<char *>( CPLMalloc( sBuffer.max_size + 1 ) ); sBuffer.fp = poGDS->fp; sBuffer.buffer_size = 0; sBuffer.cur_index = 0; for( int i = 0; i < GetXSize(); i++) { int bSuccess; const int nRowNumber = USGSDEMReadIntFromBuffer(&sBuffer, &bSuccess); if( nRowNumber != 1 ) CPLDebug("USGSDEM", "i = %d, nRowNumber = %d", i, nRowNumber); if( bSuccess ) { const int nColNumber = USGSDEMReadIntFromBuffer(&sBuffer, &bSuccess); if( nColNumber != i + 1 ) { CPLDebug("USGSDEM", "i = %d, nColNumber = %d", i, nColNumber); } } const int nCPoints = (bSuccess) ? USGSDEMReadIntFromBuffer(&sBuffer, &bSuccess) : 0; #ifdef DEBUG_VERBOSE CPLDebug("USGSDEM", "i = %d, nCPoints = %d", i, nCPoints); #endif if( bSuccess ) { const int nNumberOfCols = USGSDEMReadIntFromBuffer(&sBuffer, &bSuccess); if( nNumberOfCols != 1 ) { CPLDebug("USGSDEM", "i = %d, nNumberOfCols = %d", i, nNumberOfCols); } } // x-start if( bSuccess ) /* dxStart = */ USGSDEMReadDoubleFromBuffer(&sBuffer, 24, &bSuccess); double dyStart = (bSuccess) ? USGSDEMReadDoubleFromBuffer(&sBuffer, 24, &bSuccess) : 0; const double dfElevOffset = (bSuccess) ? USGSDEMReadDoubleFromBuffer(&sBuffer, 24, &bSuccess) : 0; // min z value if( bSuccess ) /* djunk = */ USGSDEMReadDoubleFromBuffer(&sBuffer, 24, &bSuccess); // max z value if( bSuccess ) /* djunk = */ USGSDEMReadDoubleFromBuffer(&sBuffer, 24, &bSuccess); if( !bSuccess ) { CPLFree(sBuffer.buffer); return CE_Failure; } if( STARTS_WITH_CI(poGDS->pszProjection, "GEOGCS") ) dyStart = dyStart / 3600.0; double dygap = (dfYMin - dyStart)/poGDS->adfGeoTransform[5]+ 0.5; if( dygap <= INT_MIN || dygap >= INT_MAX || !CPLIsFinite(dygap) ) { CPLFree(sBuffer.buffer); return CE_Failure; } int lygap = static_cast<int>(dygap); if( nCPoints <= 0 ) continue; if( lygap > INT_MAX - nCPoints ) lygap = INT_MAX - nCPoints; for (int j=lygap; j < (nCPoints + lygap); j++) { const int iY = GetYSize() - j - 1; const int nElev = USGSDEMReadIntFromBuffer(&sBuffer, &bSuccess); #ifdef DEBUG_VERBOSE CPLDebug("USGSDEM", " j - lygap = %d, nElev = %d", j - lygap, nElev); #endif if( !bSuccess ) { CPLFree(sBuffer.buffer); return CE_Failure; } if (iY < 0 || iY >= GetYSize() ) { /* bad = TRUE; */ } else if( nElev == USGSDEM_NODATA ) /* leave in output buffer as nodata */; else { const float fComputedElev = static_cast<float>(nElev * poGDS->fVRes + dfElevOffset); if( GetRasterDataType() == GDT_Int16 ) { GUInt16 nVal = ( fComputedElev < -32768 ) ? -32768 : ( fComputedElev > 32767 ) ? 32767 : static_cast<GInt16>( fComputedElev ); reinterpret_cast<GInt16 *>( pImage )[i + iY*GetXSize()] = nVal; } else { reinterpret_cast<float *>( pImage )[i + iY*GetXSize()] = fComputedElev; } } } if( poGDS->nDataStartOffset == 1024 ) { // Seek to the next 1024 byte boundary. // Some files have 'junk' profile values after the valid/declared ones vsi_l_offset nCurPos = USGSDEMGetCurrentFilePos(&sBuffer); vsi_l_offset nNewPos = (nCurPos + 1023) / 1024 * 1024; if( nNewPos > nCurPos ) { USGSDEMSetCurrentFilePos(&sBuffer, nNewPos); } } } CPLFree(sBuffer.buffer); return CE_None; }