void OGRBNALayer::FastParseUntil ( int interestFID) { if (partialIndexTable) { ResetReading(); BNARecord* record; if (nFeatures > 0) { VSIFSeekL( fpBNA, offsetAndLineFeaturesTable[nFeatures-1].offset, SEEK_SET ); curLine = offsetAndLineFeaturesTable[nFeatures-1].line; /* Just skip the last read one */ int ok = FALSE; record = BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, BNA_READ_NONE); BNA_FreeRecord(record); } while(1) { int ok = FALSE; int offset = (int) VSIFTellL(fpBNA); int line = curLine; record = BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, BNA_READ_NONE); if (ok == FALSE) { failed = TRUE; return; } if (record == NULL) { /* end of file */ eof = TRUE; /* and we have finally build the whole index table */ partialIndexTable = FALSE; return; } if (record->featureType == bnaFeatureType) { nFeatures++; offsetAndLineFeaturesTable = (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable, nFeatures * sizeof(OffsetAndLine)); offsetAndLineFeaturesTable[nFeatures-1].offset = offset; offsetAndLineFeaturesTable[nFeatures-1].line = line; BNA_FreeRecord(record); if (nFeatures - 1 == interestFID) return; } else { BNA_FreeRecord(record); } } } }
OGRFeature * OGRBNALayer::GetFeature( long nFID ) { OGRFeature *poFeature; BNARecord* record; int ok; if (nFID < 0) return NULL; FastParseUntil(nFID); if (nFID >= nFeatures) return NULL; VSIFSeekL( fpBNA, offsetAndLineFeaturesTable[nFID].offset, SEEK_SET ); curLine = offsetAndLineFeaturesTable[nFID].line; record = BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, bnaFeatureType); poFeature = BuildFeatureFromBNARecord(record, nFID); BNA_FreeRecord(record); return poFeature; }
OGRFeature * OGRBNALayer::GetFeature( GIntBig nFID ) { if (nFID < 0 || !CPL_INT64_FITS_ON_INT32(nFID)) return NULL; FastParseUntil( static_cast<int>( nFID ) ); if (nFID >= nFeatures) return NULL; int ok; if( VSIFSeekL( fpBNA, offsetAndLineFeaturesTable[nFID].offset, SEEK_SET ) < 0 ) return NULL; curLine = offsetAndLineFeaturesTable[nFID].line; BNARecord* record = BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, bnaFeatureType); OGRFeature *poFeature = BuildFeatureFromBNARecord(record, (int)nFID); BNA_FreeRecord(record); return poFeature; }
OGRFeature *OGRBNALayer::GetNextFeature() { OGRFeature *poFeature; BNARecord* record; int offset, line; if (failed || eof) return NULL; while(1) { int ok = FALSE; offset = (int) VSIFTellL(fpBNA); line = curLine; if (nNextFID < nFeatures) { VSIFSeekL( fpBNA, offsetAndLineFeaturesTable[nNextFID].offset, SEEK_SET ); curLine = offsetAndLineFeaturesTable[nNextFID].line; } record = BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, bnaFeatureType); if (ok == FALSE) { BNA_FreeRecord(record); failed = TRUE; return NULL; } if (record == NULL) { /* end of file */ eof = TRUE; /* and we have finally build the whole index table */ partialIndexTable = FALSE; return NULL; } if (record->featureType == bnaFeatureType) { if (nNextFID >= nFeatures) { nFeatures++; offsetAndLineFeaturesTable = (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable, nFeatures * sizeof(OffsetAndLine)); offsetAndLineFeaturesTable[nFeatures-1].offset = offset; offsetAndLineFeaturesTable[nFeatures-1].line = line; } poFeature = BuildFeatureFromBNARecord(record, nNextFID++); BNA_FreeRecord(record); if( (m_poFilterGeom == NULL || FilterGeometry( poFeature->GetGeometryRef() ) ) && (m_poAttrQuery == NULL || m_poAttrQuery->Evaluate( poFeature )) ) { return poFeature; } delete poFeature; } else { BNA_FreeRecord(record); } } }
int OGRBNADataSource::Open( const char * pszFilename, int bUpdateIn) { int ok = FALSE; pszName = CPLStrdup( pszFilename ); bUpdate = bUpdateIn; /* -------------------------------------------------------------------- */ /* Determine what sort of object this is. */ /* -------------------------------------------------------------------- */ VSIStatBufL sStatBuf; if( VSIStatL( pszFilename, &sStatBuf ) != 0 ) return FALSE; // -------------------------------------------------------------------- // Does this appear to be a .bna file? // -------------------------------------------------------------------- if( !(EQUAL( CPLGetExtension(pszFilename), "bna" ) || ((EQUALN( pszFilename, "/vsigzip/", 9) || EQUALN( pszFilename, "/vsizip/", 8)) && (strstr( pszFilename, ".bna") || strstr( pszFilename, ".BNA")))) ) return FALSE; VSILFILE* fp = VSIFOpenL(pszFilename, "rb"); if (fp) { BNARecord* record; int curLine = 0; const char* layerRadixName[] = { "points", "polygons", "lines", "ellipses"}; OGRwkbGeometryType wkbGeomTypes[] = { wkbPoint, wkbMultiPolygon, wkbLineString, wkbPolygon }; int i; #if defined(BNA_FAST_DS_OPEN) record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE); BNA_FreeRecord(record); if (ok) { nLayers = 4; papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*)); for(i=0;i<4;i++) papoLayers[i] = new OGRBNALayer( pszFilename, layerRadixName[i], (BNAFeatureType)i, wkbGeomTypes[i], FALSE, this ); } #else int nFeatures[4] = { 0, 0, 0, 0 }; OffsetAndLine* offsetAndLineFeaturesTable[4] = { NULL, NULL, NULL, NULL }; int nIDs[4] = {0, 0, 0, 0}; int partialIndexTable = TRUE; while(1) { int offset = VSIFTellL(fp); int line = curLine; record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE); if (ok == FALSE) { BNA_FreeRecord(record); if (line != 0) ok = TRUE; break; } if (record == NULL) { /* end of file */ ok = TRUE; /* and we have finally build the whole index table */ partialIndexTable = FALSE; break; } if (record->nIDs > nIDs[record->featureType]) nIDs[record->featureType] = record->nIDs; nFeatures[record->featureType]++; offsetAndLineFeaturesTable[record->featureType] = (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable[record->featureType], nFeatures[record->featureType] * sizeof(OffsetAndLine)); offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].offset = offset; offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].line = line; BNA_FreeRecord(record); } nLayers = (nFeatures[0] != 0) + (nFeatures[1] != 0) + (nFeatures[2] != 0) + (nFeatures[3] != 0); papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*)); int iLayer = 0; for(i=0;i<4;i++) { if (nFeatures[i]) { papoLayers[iLayer] = new OGRBNALayer( pszFilename, layerRadixName[i], (BNAFeatureType)i, wkbGeomTypes[i], FALSE, this, nIDs[i]); papoLayers[iLayer]->SetFeatureIndexTable(nFeatures[i], offsetAndLineFeaturesTable[i], partialIndexTable); iLayer++; } } #endif VSIFCloseL(fp); } return ok; }
BNARecord* BNA_GetNextRecord(VSILFILE* f, int* ok, int* curLine, int verbose, BNAFeatureType interestFeatureType) { BNARecord* record; char c; int inQuotes = FALSE; int numField = 0; char* ptrBeginningOfNumber = NULL; int exponentFound = 0; int exponentSignFound = 0; int dotFound = 0; int numChar = 0; const char* detailedErrorMsg = NULL; BNAFeatureType currentFeatureType = BNA_UNKNOWN; int nbExtraId = 0; char tmpBuffer[NB_MAX_BNA_IDS][TMP_BUFFER_SIZE+1]; int tmpBufferLength[NB_MAX_BNA_IDS] = {0, 0, 0}; char szLineBuffer[LINE_BUFFER_SIZE + 1]; record = (BNARecord*)CPLMalloc(sizeof(BNARecord)); memset(record, 0, sizeof(BNARecord)); while (TRUE) { numChar = 0; (*curLine)++; int retGetLine = BNA_GetLine(szLineBuffer, f); if (retGetLine == BNA_LINE_TOO_LONG) { detailedErrorMsg = LINE_TOO_LONG; goto error; } else if (retGetLine == BNA_LINE_EOF) { break; } char* ptrCurLine = szLineBuffer; const char* ptrBeginLine = szLineBuffer; if (*ptrCurLine == 0) continue; while(1) { numChar = ptrCurLine - ptrBeginLine; c = *ptrCurLine; if (c == 0) c = 10; if (inQuotes) { if (c == 10) { detailedErrorMsg = STRING_NOT_TERMINATED; goto error; } else if (c == '"' && ptrCurLine[1] == '"') { if (tmpBufferLength[numField] == TMP_BUFFER_SIZE) { detailedErrorMsg = TOO_LONG_ID; goto error; } tmpBuffer[numField][tmpBufferLength[numField]++] = c; ptrCurLine++; } else if (c == '"') { inQuotes = FALSE; } else { if (tmpBufferLength[numField] == TMP_BUFFER_SIZE) { detailedErrorMsg = TOO_LONG_ID; goto error; } tmpBuffer[numField][tmpBufferLength[numField]++] = c; } } else if (c == ' ' || c == '\t') { if (numField > NB_MIN_BNA_IDS + nbExtraId && ptrBeginningOfNumber != NULL) { do { ptrCurLine++; numChar = ptrCurLine - ptrBeginLine; c = *ptrCurLine; if (!(c == ' ' || c == '\t')) break; } while(c); if (c == 0) c = 10; if (interestFeatureType == BNA_READ_ALL || interestFeatureType == currentFeatureType) { char* pszComma = strchr(ptrBeginningOfNumber, ','); if (pszComma) *pszComma = '\0'; record->tabCoords[(numField - nbExtraId - NB_MIN_BNA_IDS - 1) / 2] [1 - ((numField - nbExtraId) % 2)] = CPLAtof(ptrBeginningOfNumber); if (pszComma) *pszComma = ','; } if (numField == NB_MIN_BNA_IDS + 1 + nbExtraId + 2 * record->nCoords - 1) { if (c != 10) { if (verbose) { CPLError(CE_Warning, CPLE_AppDefined, "At line %d, at char %d, extra data will be ignored!\n", *curLine, numChar+1); } } *ok = 1; return record; } ptrBeginningOfNumber = NULL; exponentFound = 0; exponentSignFound = 0; dotFound = 0; numField++; if (c == 10) break; if (c != ',') { /* don't increment ptrCurLine */ continue; } } else { /* ignore */ } } else if (c == 10 || c == ',') { /* Eat a comma placed at end of line */ if (c == ',') { const char* ptr = ptrCurLine+1; while(*ptr) { if (*ptr != ' ' && *ptr != '\t') break; ptr++; } if (*ptr == 0) { c = 10; } } if (numField == 0) { /* Maybe not so mandatory.. Atlas MapMaker(TM) exports BNA files with empty primaryID */ /* if (record->primaryID == NULL || *(record->primaryID) == 0) { detailedErrorMsg = PRIMARY_ID_MANDATORY; goto error; } */ } else if (numField == NB_MIN_BNA_IDS + nbExtraId) { int nCoords; if (ptrBeginningOfNumber == NULL) { detailedErrorMsg = INTEGER_NUMBER_EXPECTED; goto error; } nCoords = atoi(ptrBeginningOfNumber); if (nCoords == 0 || nCoords == -1) { detailedErrorMsg = INVALID_GEOMETRY_TYPE; goto error; } else if (nCoords == 1) { currentFeatureType = record->featureType = BNA_POINT; record->nCoords = 1; } else if (nCoords == 2) { currentFeatureType = record->featureType = BNA_ELLIPSE; record->nCoords = 2; } else if (nCoords > 0) { currentFeatureType = record->featureType = BNA_POLYGON; record->nCoords = nCoords; } else { currentFeatureType = record->featureType = BNA_POLYLINE; record->nCoords = -nCoords; } record->nIDs = NB_MIN_BNA_IDS + nbExtraId; if (interestFeatureType == BNA_READ_ALL || interestFeatureType == currentFeatureType) { int i; for(i=0;i<NB_MAX_BNA_IDS;i++) { if (tmpBufferLength[i] && tmpBuffer[i][0]) { record->ids[i] = (char*)CPLMalloc(tmpBufferLength[i] + 1); tmpBuffer[i][tmpBufferLength[i]] = 0; memcpy(record->ids[i], tmpBuffer[i], tmpBufferLength[i] + 1); } } record->tabCoords = (double(*)[2])VSIMalloc(record->nCoords * 2 * sizeof(double)); if (record->tabCoords == NULL) { detailedErrorMsg = NOT_ENOUGH_MEMORY; goto error; } } } else if (numField > NB_MIN_BNA_IDS + nbExtraId) { if (ptrBeginningOfNumber == NULL) { detailedErrorMsg = FLOAT_NUMBER_EXPECTED; goto error; } if (interestFeatureType == BNA_READ_ALL || interestFeatureType == currentFeatureType) { char* pszComma = strchr(ptrBeginningOfNumber, ','); if (pszComma) *pszComma = '\0'; record->tabCoords[(numField - nbExtraId - NB_MIN_BNA_IDS - 1) / 2] [1 - ((numField - nbExtraId) % 2)] = CPLAtof(ptrBeginningOfNumber); if (pszComma) *pszComma = ','; } if (numField == NB_MIN_BNA_IDS + 1 + nbExtraId + 2 * record->nCoords - 1) { if (c != 10) { if (verbose) { CPLError(CE_Warning, CPLE_AppDefined, "At line %d, at char %d, extra data will be ignored!\n", *curLine, numChar+1); } } *ok = 1; return record; } } ptrBeginningOfNumber = NULL; exponentFound = 0; exponentSignFound = 0; dotFound = 0; numField++; if (c == 10) break; } else if (c == '"') { if (numField < NB_MIN_BNA_IDS) { inQuotes = TRUE; } else if (numField >= NB_MIN_BNA_IDS && currentFeatureType == BNA_UNKNOWN) { if (ptrBeginningOfNumber == NULL) { if (nbExtraId == NB_MAX_BNA_IDS - NB_MIN_BNA_IDS) { detailedErrorMsg = MAX_BNA_IDS_REACHED; goto error; } nbExtraId ++; inQuotes = TRUE; } else { detailedErrorMsg = BAD_INTEGER_NUMBER_FORMAT; goto error; } } else { detailedErrorMsg = NUMBER_EXPECTED; goto error; } } else { if (numField < NB_MIN_BNA_IDS || (numField == NB_MIN_BNA_IDS + nbExtraId - 1)) { detailedErrorMsg = STRING_EXPECTED; goto error; } else if (numField == NB_MIN_BNA_IDS + nbExtraId) { if (c >= '0' && c <= '9') { } else if (c == '+' || c == '-') { if (ptrBeginningOfNumber != NULL) { detailedErrorMsg = BAD_INTEGER_NUMBER_FORMAT; goto error; } } else { detailedErrorMsg = BAD_INTEGER_NUMBER_FORMAT; goto error; } if (ptrBeginningOfNumber == NULL) ptrBeginningOfNumber = ptrCurLine; } else { if (c >= '0' && c <= '9') { } else if (c == '.') { if (dotFound || exponentFound) { detailedErrorMsg = BAD_FLOAT_NUMBER_FORMAT; goto error; } dotFound = 1; } else if (c == '+' || c == '-') { if (ptrBeginningOfNumber == NULL) { } else if (exponentFound) { if (exponentSignFound == 0 && ptrCurLine > ptrBeginLine && (ptrCurLine[-1] == 'e' || ptrCurLine[-1] == 'E' || ptrCurLine[-1] == 'd' || ptrCurLine[-1] == 'D')) { exponentSignFound = 1; } else { detailedErrorMsg = BAD_FLOAT_NUMBER_FORMAT; goto error; } } else { detailedErrorMsg = BAD_FLOAT_NUMBER_FORMAT; goto error; } } else if (c == 'e' || c == 'E' || c == 'd' || c == 'D') { if (ptrBeginningOfNumber == NULL || !(ptrCurLine[-1] >= '0' && ptrCurLine[-1] <= '9') || exponentFound == 1) { detailedErrorMsg = BAD_FLOAT_NUMBER_FORMAT; goto error; } exponentFound = 1; } else { detailedErrorMsg = BAD_FLOAT_NUMBER_FORMAT; goto error; } if (ptrBeginningOfNumber == NULL) ptrBeginningOfNumber = ptrCurLine; } } ptrCurLine++; } } if (numField == 0) { /* End of file */ *ok = 1; BNA_FreeRecord(record); return NULL; } else { detailedErrorMsg = MISSING_FIELDS; goto error; } error: if (verbose) { if (detailedErrorMsg) { CPLError(CE_Failure, CPLE_AppDefined, "Parsing failed at line %d, at char %d : %s!\n", *curLine, numChar+1, detailedErrorMsg); } else { CPLError(CE_Failure, CPLE_AppDefined, "Parsing failed at line %d, at char %d!\n", *curLine, numChar+1); } } BNA_FreeRecord(record); return NULL; }
int OGRBNADataSource::Open( const char * pszFilename ) { int ok = FALSE; pszName = CPLStrdup( pszFilename ); VSILFILE* fp = VSIFOpenL(pszFilename, "rb"); if (fp) { int curLine = 0; static const char* const layerRadixName[] = { "points", "polygons", "lines", "ellipses"}; static const OGRwkbGeometryType wkbGeomTypes[] = { wkbPoint, wkbMultiPolygon, wkbLineString, wkbPolygon }; #if defined(BNA_FAST_DS_OPEN) BNARecord* record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE); BNA_FreeRecord(record); if (ok) { nLayers = 4; papoLayers = static_cast<OGRBNALayer **>( CPLMalloc(nLayers * sizeof(OGRBNALayer*))); for( i = 0; i < 4; i++ ) papoLayers[i] = new OGRBNALayer( pszFilename, layerRadixName[i], static_cast<BNAFeatureType>( i ), wkbGeomTypes[i], FALSE, this ); } #else int nFeatures[4] = { 0, 0, 0, 0 }; OffsetAndLine* offsetAndLineFeaturesTable[4] = { nullptr, nullptr, nullptr, nullptr }; int nIDs[4] = {0, 0, 0, 0}; bool partialIndexTable = true; BNARecord* record = nullptr; while(1) { int offset = static_cast<int>( VSIFTellL(fp) ); int line = curLine; record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE); if (ok == FALSE) { BNA_FreeRecord(record); if (line != 0) ok = TRUE; break; } if (record == nullptr) { /* end of file */ ok = TRUE; /* and we have finally build the whole index table */ partialIndexTable = false; break; } if (record->nIDs > nIDs[record->featureType]) nIDs[record->featureType] = record->nIDs; nFeatures[record->featureType]++; offsetAndLineFeaturesTable[record->featureType] = static_cast<OffsetAndLine *>( CPLRealloc( offsetAndLineFeaturesTable[record->featureType], nFeatures[record->featureType] * sizeof(OffsetAndLine) ) ); offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].offset = offset; offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].line = line; BNA_FreeRecord(record); } nLayers = (nFeatures[0] != 0) + (nFeatures[1] != 0) + (nFeatures[2] != 0) + (nFeatures[3] != 0); papoLayers = static_cast<OGRBNALayer **>( CPLMalloc(nLayers * sizeof(OGRBNALayer*)) ); int iLayer = 0; for( int i = 0; i < 4; i++ ) { if (nFeatures[i]) { papoLayers[iLayer] = new OGRBNALayer( pszFilename, layerRadixName[i], (BNAFeatureType)i, wkbGeomTypes[i], FALSE, this, nIDs[i]); papoLayers[iLayer]->SetFeatureIndexTable(nFeatures[i], offsetAndLineFeaturesTable[i], partialIndexTable); iLayer++; } } #endif VSIFCloseL(fp); } return ok; }