GDALDataset *RDataset::Open( GDALOpenInfo * poOpenInfo ) { if( !Identify( poOpenInfo ) ) return NULL; /* -------------------------------------------------------------------- */ /* Confirm the requested access is supported. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->eAccess == GA_Update ) { CPLError( CE_Failure, CPLE_NotSupported, "The R driver does not support update access to existing" " datasets.\n" ); return NULL; } /* -------------------------------------------------------------------- */ /* Do we need to route the file through the decompression */ /* machinery? */ /* -------------------------------------------------------------------- */ CPLString osAdjustedFilename; if( memcmp(poOpenInfo->pabyHeader,"\037\213\b",3) == 0 ) osAdjustedFilename = "/vsigzip/"; osAdjustedFilename += poOpenInfo->pszFilename; /* -------------------------------------------------------------------- */ /* Establish this as a dataset and open the file using VSI*L. */ /* -------------------------------------------------------------------- */ RDataset *poDS = new RDataset(); poDS->fp = VSIFOpenL( osAdjustedFilename, "r" ); if( poDS->fp == NULL ) { delete poDS; return NULL; } poDS->bASCII = EQUALN((const char *)poOpenInfo->pabyHeader,"RDA2\nA\n",7); /* -------------------------------------------------------------------- */ /* Confirm this is a version 2 file. */ /* -------------------------------------------------------------------- */ VSIFSeekL( poDS->fp, 7, SEEK_SET ); if( poDS->ReadInteger() != R_LISTSXP ) { delete poDS; CPLError( CE_Failure, CPLE_OpenFailed, "It appears %s is not a version 2 R object file after all!", poOpenInfo->pszFilename ); return NULL; } /* -------------------------------------------------------------------- */ /* Skip the version values. */ /* -------------------------------------------------------------------- */ poDS->ReadInteger(); poDS->ReadInteger(); /* -------------------------------------------------------------------- */ /* Confirm we have a numeric vector object in a pairlist. */ /* -------------------------------------------------------------------- */ CPLString osObjName; int nObjCode; if( !poDS->ReadPair( osObjName, nObjCode ) ) { delete poDS; return NULL; } if( nObjCode % 256 != R_REALSXP ) { delete poDS; CPLError( CE_Failure, CPLE_OpenFailed, "Failed to find expected numeric vector object." ); return NULL; } poDS->SetMetadataItem( "R_OBJECT_NAME", osObjName ); /* -------------------------------------------------------------------- */ /* Read the count. */ /* -------------------------------------------------------------------- */ int nValueCount = poDS->ReadInteger(); poDS->nStartOfData = VSIFTellL( poDS->fp ); /* -------------------------------------------------------------------- */ /* Read/Skip ahead to attributes. */ /* -------------------------------------------------------------------- */ if( poDS->bASCII ) { poDS->padfMatrixValues = (double*) VSIMalloc2( nValueCount, sizeof(double) ); if (poDS->padfMatrixValues == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate %d doubles", nValueCount); delete poDS; return NULL; } for( int iValue = 0; iValue < nValueCount; iValue++ ) poDS->padfMatrixValues[iValue] = poDS->ReadFloat(); } else { VSIFSeekL( poDS->fp, 8 * nValueCount, SEEK_CUR ); } /* -------------------------------------------------------------------- */ /* Read pairs till we run out, trying to find a few items that */ /* have special meaning to us. */ /* -------------------------------------------------------------------- */ poDS->nRasterXSize = poDS->nRasterYSize = 0; int nBandCount = 0; while( poDS->ReadPair( osObjName, nObjCode ) && nObjCode != 254 ) { if( osObjName == "dim" && nObjCode % 256 == R_INTSXP ) { int nCount = poDS->ReadInteger(); if( nCount == 2 ) { poDS->nRasterXSize = poDS->ReadInteger(); poDS->nRasterYSize = poDS->ReadInteger(); nBandCount = 1; } else if( nCount == 3 ) { poDS->nRasterXSize = poDS->ReadInteger(); poDS->nRasterYSize = poDS->ReadInteger(); nBandCount = poDS->ReadInteger(); } else { CPLError( CE_Failure, CPLE_AppDefined, "R 'dim' dimension wrong." ); delete poDS; return NULL; } } else if( nObjCode % 256 == R_REALSXP ) { int nCount = poDS->ReadInteger(); while( nCount-- > 0 && !VSIFEofL(poDS->fp) ) poDS->ReadFloat(); } else if( nObjCode % 256 == R_INTSXP ) { int nCount = poDS->ReadInteger(); while( nCount-- > 0 && !VSIFEofL(poDS->fp) ) poDS->ReadInteger(); } else if( nObjCode % 256 == R_STRSXP ) { int nCount = poDS->ReadInteger(); while( nCount-- > 0 && !VSIFEofL(poDS->fp) ) poDS->ReadString(); } else if( nObjCode % 256 == R_CHARSXP ) { poDS->ReadString(); } } if( poDS->nRasterXSize == 0 ) { delete poDS; CPLError( CE_Failure, CPLE_AppDefined, "Failed to find dim dimension information for R dataset." ); return NULL; } if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) || !GDALCheckBandCount(nBandCount, TRUE)) { delete poDS; return NULL; } if( nValueCount < ((GIntBig) nBandCount) * poDS->nRasterXSize * poDS->nRasterYSize ) { CPLError( CE_Failure, CPLE_AppDefined, "Not enough pixel data." ); delete poDS; return NULL; } /* -------------------------------------------------------------------- */ /* Create the raster band object(s). */ /* -------------------------------------------------------------------- */ for( int iBand = 0; iBand < nBandCount; iBand++ ) { GDALRasterBand *poBand; if( poDS->bASCII ) poBand = new RRasterBand( poDS, iBand+1, poDS->padfMatrixValues + iBand * poDS->nRasterXSize * poDS->nRasterYSize ); else poBand = new RawRasterBand( poDS, iBand+1, poDS->fp, poDS->nStartOfData + poDS->nRasterXSize*poDS->nRasterYSize*8*iBand, 8, poDS->nRasterXSize * 8, GDT_Float64, !CPL_IS_LSB, TRUE, FALSE ); poDS->SetBand( iBand+1, poBand ); } /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ poDS->SetDescription( poOpenInfo->pszFilename ); poDS->TryLoadXML(); /* -------------------------------------------------------------------- */ /* Check for overviews. */ /* -------------------------------------------------------------------- */ poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); return( poDS ); }
GDALDataset *RDataset::Open( GDALOpenInfo * poOpenInfo ) { #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if( poOpenInfo->pabyHeader == nullptr ) return nullptr; #else // During fuzzing, do not use Identify to reject crazy content. if( !Identify(poOpenInfo) ) return nullptr; #endif // Confirm the requested access is supported. if( poOpenInfo->eAccess == GA_Update ) { CPLError(CE_Failure, CPLE_NotSupported, "The R driver does not support update access to existing" " datasets."); return nullptr; } // Do we need to route the file through the decompression machinery? const bool bCompressed = memcmp(poOpenInfo->pabyHeader, "\037\213\b", 3) == 0; const CPLString osAdjustedFilename = std::string(bCompressed ? "/vsigzip/" : "") + poOpenInfo->pszFilename; // Establish this as a dataset and open the file using VSI*L. RDataset *poDS = new RDataset(); poDS->fp = VSIFOpenL(osAdjustedFilename, "r"); if( poDS->fp == nullptr ) { delete poDS; return nullptr; } poDS->bASCII = STARTS_WITH_CI( reinterpret_cast<char *>(poOpenInfo->pabyHeader), "RDA2\nA\n"); // Confirm this is a version 2 file. VSIFSeekL(poDS->fp, 7, SEEK_SET); if( poDS->ReadInteger() != R_LISTSXP ) { delete poDS; CPLError(CE_Failure, CPLE_OpenFailed, "It appears %s is not a version 2 R object file after all!", poOpenInfo->pszFilename); return nullptr; } // Skip the version values. poDS->ReadInteger(); poDS->ReadInteger(); // Confirm we have a numeric vector object in a pairlist. CPLString osObjName; int nObjCode = 0; if( !poDS->ReadPair(osObjName, nObjCode) ) { delete poDS; return nullptr; } if( nObjCode % 256 != R_REALSXP ) { delete poDS; CPLError(CE_Failure, CPLE_OpenFailed, "Failed to find expected numeric vector object."); return nullptr; } poDS->SetMetadataItem("R_OBJECT_NAME", osObjName); // Read the count. const int nValueCount = poDS->ReadInteger(); if( nValueCount < 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "nValueCount < 0: %d", nValueCount); delete poDS; return nullptr; } poDS->nStartOfData = VSIFTellL(poDS->fp); // TODO(schwehr): Factor in the size of doubles. VSIStatBufL stat; const int dStatSuccess = VSIStatExL(osAdjustedFilename, &stat, VSI_STAT_SIZE_FLAG); if( dStatSuccess != 0 || static_cast<vsi_l_offset>(nValueCount) > stat.st_size - poDS->nStartOfData ) { CPLError( CE_Failure, CPLE_AppDefined, "Corrupt file. " "Object claims to be larger than available bytes. " "%d > " CPL_FRMT_GUIB, nValueCount, stat.st_size - poDS->nStartOfData); delete poDS; return nullptr; } // Read/Skip ahead to attributes. if( poDS->bASCII ) { poDS->padfMatrixValues = static_cast<double *>(VSIMalloc2(nValueCount, sizeof(double))); if (poDS->padfMatrixValues == nullptr) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate %d doubles", nValueCount); delete poDS; return nullptr; } for( int iValue = 0; iValue < nValueCount; iValue++ ) poDS->padfMatrixValues[iValue] = poDS->ReadFloat(); } else { VSIFSeekL(poDS->fp, 8 * nValueCount, SEEK_CUR); } // Read pairs till we run out, trying to find a few items that // have special meaning to us. poDS->nRasterXSize = 0; poDS->nRasterYSize = 0; int nBandCount = 0; while( poDS->ReadPair(osObjName, nObjCode) && nObjCode != 254 ) { if( osObjName == "dim" && nObjCode % 256 == R_INTSXP ) { const int nCount = poDS->ReadInteger(); if( nCount == 2 ) { poDS->nRasterXSize = poDS->ReadInteger(); poDS->nRasterYSize = poDS->ReadInteger(); nBandCount = 1; } else if( nCount == 3 ) { poDS->nRasterXSize = poDS->ReadInteger(); poDS->nRasterYSize = poDS->ReadInteger(); nBandCount = poDS->ReadInteger(); } else { CPLError(CE_Failure, CPLE_AppDefined, "R 'dim' dimension wrong."); delete poDS; return nullptr; } } else if( nObjCode % 256 == R_REALSXP ) { int nCount = poDS->ReadInteger(); while( nCount > 0 && !VSIFEofL(poDS->fp) ) { nCount --; poDS->ReadFloat(); } } else if( nObjCode % 256 == R_INTSXP ) { int nCount = poDS->ReadInteger(); while( nCount > 0 && !VSIFEofL(poDS->fp) ) { nCount --; poDS->ReadInteger(); } } else if( nObjCode % 256 == R_STRSXP ) { int nCount = poDS->ReadInteger(); while( nCount > 0 && !VSIFEofL(poDS->fp) ) { nCount --; poDS->ReadString(); } } else if( nObjCode % 256 == R_CHARSXP ) { poDS->ReadString(); } } if( poDS->nRasterXSize == 0 ) { delete poDS; CPLError(CE_Failure, CPLE_AppDefined, "Failed to find dim dimension information for R dataset."); return nullptr; } if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) || !GDALCheckBandCount(nBandCount, TRUE)) { delete poDS; return nullptr; } GIntBig result = 0; bool ok = SafeMult(nBandCount, poDS->nRasterXSize, &result); ok &= SafeMult(result, poDS->nRasterYSize, &result); if( !ok || nValueCount < result ) { CPLError(CE_Failure, CPLE_AppDefined, "Not enough pixel data."); delete poDS; return nullptr; } // Create the raster band object(s). for( int iBand = 0; iBand < nBandCount; iBand++ ) { GDALRasterBand *poBand = nullptr; if( poDS->bASCII ) poBand = new RRasterBand( poDS, iBand + 1, poDS->padfMatrixValues + iBand * poDS->nRasterXSize * poDS->nRasterYSize); else poBand = new RawRasterBand( poDS, iBand + 1, poDS->fp, poDS->nStartOfData + poDS->nRasterXSize * poDS->nRasterYSize * 8 * iBand, 8, poDS->nRasterXSize * 8, GDT_Float64, !CPL_IS_LSB, TRUE, FALSE); poDS->SetBand(iBand + 1, poBand); } // Initialize any PAM information. poDS->SetDescription(poOpenInfo->pszFilename); poDS->TryLoadXML(); // Check for overviews. poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename); return poDS; }