int OGRSOSIDataSource::Open( const char *pszFilename, int bUpdate ) { papoBuiltGeometries = NULL; poFileadm = NULL; poBaseadm = NULL; char *pszPos; if ( bUpdate ) { CPLError( CE_Failure, CPLE_OpenFailed, "Update access not supported by the SOSI driver." ); return FALSE; } /* Check that the file exists otherwise HO_TestSOSI() emits an error */ VSIStatBuf sStat; if( VSIStat(pszFilename, &sStat) != 0 ) return FALSE; pszName = CPLStrdup( pszFilename ); /* We ignore any layer parameters for now. */ pszPos = strchr(pszName, ','); if (pszPos != NULL) { pszPos[0] = '\0'; } /* Confirm that we are dealing with a SOSI file. Used also by data * format auto-detection in some ogr utilities. */ UT_INT64 nEnd = 0; int bIsSosi = HO_TestSOSI ( pszName, &nEnd ); if ( bIsSosi == UT_FALSE ) { return FALSE; /* No error message: This is used by file format auto-detection */ } short nStatus = 0, nDetStatus = 0; /* immediate status, detailed status */ /* open index base and sosi file */ poBaseadm = LC_OpenBase(LC_BASE); nStatus = LC_OpenSos(pszName, LC_BASE_FRAMGR, LC_GML_IDX, LC_INGEN_STATUS, &poFileadm, &nDetStatus); if ( nStatus == UT_FALSE ) { char *pszErrorMessage; LC_StrError(nDetStatus, &pszErrorMessage); CPLError( CE_Failure, CPLE_OpenFailed, "File %s could not be opened by SOSI Driver: %s", pszName, pszErrorMessage ); return FALSE; } /* --------------------------------------------------------------------* * Prefetch all the information needed to determine layers * * and prebuild LineString features for later assembly. * * --------------------------------------------------------------------*/ /* allocate room for one pointer per feature */ nNumFeatures = static_cast<unsigned int>(poFileadm->lAntGr); void* mem = VSI_MALLOC2_VERBOSE(nNumFeatures, sizeof(void*)); if (mem == NULL) { return FALSE; } else { papoBuiltGeometries = (OGRGeometry**)mem; } for (unsigned int i=0; i<nNumFeatures; i++) papoBuiltGeometries[i] = NULL; /* Various iterators and return values used to iterate through SOSI features */ short nName, nNumLines; long nNumCoo; unsigned short nInfo; LC_SNR_ADM oSnradm; LC_BGR oNextSerial; LC_BGR *poNextSerial; poNextSerial =&oNextSerial; bool bPointLayer = FALSE; /* Initialize four layers for the different geometry types */ bool bCurveLayer = FALSE; bool bPolyLayer = FALSE; bool bTextLayer = FALSE; poPolyHeaders = new S2I(); poPointHeaders = new S2I(); poCurveHeaders = new S2I(); poTextHeaders = new S2I(); LC_SBSn(&oSnradm, poFileadm, 0, nNumFeatures); /* Set FYBA search limits */ LC_InitNextBgr(poNextSerial); /* Prebuilding simple features and extracting layer information. */ while (LC_NextBgr(poNextSerial,LC_FRAMGR)) { /* Fetch next group information */ nName = LC_RxGr(poNextSerial, LES_OPTIMALT, &nNumLines, &nNumCoo, &nInfo); S2S oHeaders; S2S::iterator iHeaders; int iH; /* Extract all strings from group header. */ for (short i=1; i<=nNumLines; i++) { char *pszLine = LC_GetGi(i); /* Get one header line */ if ((pszLine[0] == ':')||(pszLine[0] == '(')) continue; /* If we have a continued REF line, skip it. */ if (pszLine[0] == '!') continue; /* If we have a comment line, skip it. */ char *pszUTFLine = CPLRecode(pszLine, pszEncoding, CPL_ENC_UTF8); /* switch to UTF encoding here, if it is known. */ char *pszUTFLineIter = pszUTFLine; while (pszUTFLineIter[0] == '.') pszUTFLineIter++; /* Skipping the dots at the beginning of a SOSI line */ char *pszPos2 = strstr(pszUTFLineIter, " "); /* Split header and value */ if (pszPos2 != NULL) { CPLString osKey = CPLString(std::string(pszUTFLineIter,pszPos2)); /* FIXME: clean instantiation of CPLString? */ CPLString osValue = CPLString(pszPos2+1); oHeaders[osKey]=osValue; /* Add to header map */ switch (nName) { /* Add to header list for the corresponding layer, if it is not */ case L_FLATE: { /* in there already */ if (poPolyHeaders->find(osKey) == poPolyHeaders->end()) { iH = static_cast<int>(poPolyHeaders->size()); (*poPolyHeaders)[osKey] = iH; } break; } case L_KURVE: case L_LINJE: case L_BUEP: { /* FIXME: maybe not use the same headers for both */ if (poCurveHeaders->find(osKey) == poCurveHeaders->end()) { iH = static_cast<int>(poCurveHeaders->size()); (*poCurveHeaders)[osKey] = iH; } break; } case L_PUNKT: case L_SYMBOL: { if (poPointHeaders->find(osKey) == poPointHeaders->end()) { iH = static_cast<int>(poPointHeaders->size()); (*poPointHeaders)[osKey] = iH; } break; } case L_TEKST: { if (poTextHeaders->find(osKey) == poTextHeaders->end()) { iH = static_cast<int>(poTextHeaders->size()); (*poTextHeaders)[osKey] = iH; } break; } } } CPLFree(pszUTFLine); } /* Feature-specific tasks */ switch (nName) { case L_PUNKT: { /* Pre-build a point feature. Activate point layer. */ bPointLayer = TRUE; buildOGRPoint(oNextSerial.lNr); break; } case L_FLATE: { /* Activate polygon layer. */ bPolyLayer = TRUE; /* cannot build geometries that reference others yet */ break; } case L_KURVE: case L_LINJE: { /* Pre-build a line feature. Activate line/curve layer. */ bCurveLayer = TRUE; buildOGRLineString(static_cast<int>(nNumCoo), oNextSerial.lNr); break; } case L_BUEP: { /* Pre-build a line feature as interpolation from an arc. Activate line/curve layer. */ bCurveLayer = TRUE; buildOGRLineStringFromArc(oNextSerial.lNr); break; } case L_TEKST: { /* Pre-build a text line contour feature. Activate text layer. */ /* Todo: observe only points 2ff if more than one point is given for follow mode */ bTextLayer = TRUE; buildOGRMultiPoint(static_cast<int>(nNumCoo), oNextSerial.lNr); break; } case L_HODE: { /* Get SRS from SOSI header. */ unsigned short nMask = LC_TR_ALLT; LC_TRANSPAR oTrans; if (LC_GetTransEx(&nMask,&oTrans) == UT_FALSE) { CPLError( CE_Failure, CPLE_OpenFailed, "TRANSPAR section not found - No reference system information available."); return FALSE; } poSRS = new OGRSpatialReference(); /* Get coordinate system from SOSI header. */ int nEPSG = sosi2epsg(oTrans.sKoordsys); if (poSRS->importFromEPSG(nEPSG) != OGRERR_NONE) { CPLError( CE_Failure, CPLE_OpenFailed, "OGR could not load coordinate system definition EPSG:%i.", nEPSG); return FALSE; } /* Get character encoding from SOSI header. */ iHeaders = oHeaders.find("TEGNSETT"); if (iHeaders != oHeaders.end()) { CPLString osLine = iHeaders->second; if (osLine.compare("ISO8859-1")==0) { pszEncoding = CPL_ENC_ISO8859_1; } else if (osLine.compare("ISO8859-10")==0) { pszEncoding = CPL_ENC_ISO8859_10; } else if (osLine.compare("UTF-8")==0) { pszEncoding = CPL_ENC_UTF8; } } break; } default: { break; } } } /* -------------------------------------------------------------------- * * Create a corresponding layers. One per geometry type * * -------------------------------------------------------------------- */ int l_nLayers = 0; if (bPolyLayer) l_nLayers++; if (bCurveLayer) l_nLayers++; if (bPointLayer) l_nLayers++; if (bTextLayer) l_nLayers++; this->nLayers = l_nLayers; /* allocate some memory for up to three layers */ papoLayers = (OGRSOSILayer **) VSI_MALLOC2_VERBOSE(sizeof(void*), l_nLayers); if( papoLayers == NULL ) { this->nLayers = 0; return FALSE; } /* Define each layer, using a proper feature definition, geometry type, * and adding every SOSI header encountered in the file as field. */ S2I::iterator i; if (bPolyLayer) { S2I * poHeadersNew = new S2I(); OGRFeatureDefn *poFeatureDefn = defineLayer("polygons", wkbPolygon, poPolyHeaders, &poHeadersNew); delete poPolyHeaders; poPolyHeaders = poHeadersNew; poFeatureDefn->Reference(); papoLayers[--l_nLayers] = new OGRSOSILayer( this, poFeatureDefn, poFileadm, poPolyHeaders ); } else { delete poPolyHeaders; poPolyHeaders = NULL; } if (bCurveLayer) { S2I * poHeadersNew = new S2I(); OGRFeatureDefn *poFeatureDefn = defineLayer("lines", wkbLineString, poCurveHeaders, &poHeadersNew); delete poCurveHeaders; poCurveHeaders = poHeadersNew; poFeatureDefn->Reference(); papoLayers[--l_nLayers] = new OGRSOSILayer( this, poFeatureDefn, poFileadm, poCurveHeaders ); } else { delete poCurveHeaders; poCurveHeaders = NULL; } if (bPointLayer) { S2I * poHeadersNew = new S2I(); OGRFeatureDefn *poFeatureDefn = defineLayer("points", wkbPoint, poPointHeaders, &poHeadersNew); delete poPointHeaders; poPointHeaders = poHeadersNew; poFeatureDefn->Reference(); papoLayers[--l_nLayers] = new OGRSOSILayer( this, poFeatureDefn, poFileadm, poPointHeaders ); } else { delete poPointHeaders; poPointHeaders = NULL; } if (bTextLayer) { S2I * poHeadersNew = new S2I(); OGRFeatureDefn *poFeatureDefn = defineLayer("text", wkbMultiPoint, poTextHeaders, &poHeadersNew); delete poTextHeaders; poTextHeaders = poHeadersNew; poFeatureDefn->Reference(); papoLayers[--l_nLayers] = new OGRSOSILayer( this, poFeatureDefn, poFileadm, poTextHeaders ); } else { delete poTextHeaders; poTextHeaders = NULL; } return TRUE; }
OGRFeature *OGRSOSILayer::GetNextFeature() { short nName, nNumLines; long nNumCoo; unsigned short nInfo; /* iterate through the SOSI groups*/ while (LC_NextBgr(poNextSerial,LC_FRAMGR)) { nName = LC_RxGr(&oNextSerial, LES_OPTIMALT, &nNumLines, &nNumCoo, &nInfo); S2S oHeaders; S2S::iterator iHeaders; /* extract reference strings from group header */ CPLString osKey, osValue; for (short i=1; i<=nNumLines; i++) { char *pszLine = LC_GetGi(i); if (pszLine[0] == '!') continue; /* If we have a comment line, skip it. */ if ((pszLine[0] == ':')||(pszLine[0] == '(')) { /* if we have a continued REF line... */ osValue.append(CPLString(pszLine)); /* append to previous line. */ oHeaders.insert(std::pair<CPLString,CPLString>(osKey,osValue)); continue; } while (pszLine[0] == '.') pszLine++; /* skipping the dots at the beginning of a SOSI line */ char *pszUTFLine = CPLRecode(pszLine, poParent->pszEncoding, CPL_ENC_UTF8); /* switch to UTF encoding here */ char *pszPos = strstr(pszUTFLine, " "); if (pszPos != NULL) { osKey = CPLString(std::string(pszUTFLine,pszPos)); osValue = CPLString(pszPos+1); oHeaders.insert(std::pair<CPLString,CPLString>(osKey,osValue)); } CPLFree(pszUTFLine); } /* get Feature from fyba, according to feature definition */ OGRGeometry *poGeom = NULL; OGRwkbGeometryType oGType = wkbUnknown; switch (nName) { case INGEN_GRUPPE: { /* No group */ CPLDebug( "[GetNextFeature]", "Could not load further groups - FYBA reported INGEN_GRUPPE."); break; } case L_FLATE: { /* Area */ oGType = wkbPolygon; OGRLinearRing *poOuter = new OGRLinearRing(); /* Initialize a new closed polygon */ long nRefNr; unsigned char nRefStatus; long nRefCount; bool correct = true; LC_GRF_STATUS oGrfStat; // Iterate through all objects that constitute this area. LC_InitGetRefFlate(&oGrfStat); nRefCount = LC_GetRefFlate(&oGrfStat, GRF_YTRE, &nRefNr, &nRefStatus, 1); while (nRefCount > 0) { if (poParent->papoBuiltGeometries[nRefNr] == NULL) { // This should not happen under normal operation. CPLError( CE_Warning, CPLE_AppDefined, "Feature %li referenced by %li, but it was not initialized. Geometry may be broken.", nRefNr, oNextSerial.lNr); correct = false; //return NULL; break; } OGRGeometry *geom = poParent->papoBuiltGeometries[nRefNr]; if (geom->getGeometryType() == wkbLineString) { OGRLineString *poCurve = (OGRLineString*)geom; if (nRefStatus == LC_MED_DIG) { /* clockwise */ poOuter->addSubLineString(poCurve); } else if (nRefStatus == LC_MOT_DIG) { /* counter-clockwise */ poOuter->addSubLineString(poCurve,poCurve->getNumPoints()-1,0); } else { CPLError( CE_Failure, CPLE_OpenFailed, "Internal error: GRF_*_OY encountered."); return NULL; } } else { CPLError( CE_Warning, CPLE_AppDefined, "Element %li composed of non-linestrings (REF %li of type %i). Ignored.", oNextSerial.lNr, nRefNr, geom->getGeometryType()); } nRefCount = LC_GetRefFlate(&oGrfStat, GRF_YTRE, &nRefNr, &nRefStatus, 1); } if (correct) { OGRPolygon *poLy = new OGRPolygon(); poOuter->closeRings(); poLy->addRingDirectly(poOuter); OGRLinearRing *poInner = 0; nRefCount = LC_GetRefFlate(&oGrfStat, GRF_INDRE, &nRefNr, &nRefStatus, 1); while (nRefCount > 0) { if (nRefNr == -1) { if (poInner && (poInner->getNumPoints()>2)) { /* If this is not the first polygon, terminate and add the last */ poInner->closeRings(); poLy->addRingDirectly(poInner); } poInner = new OGRLinearRing(); /* Initialize a new closed polygon */ } else { if (poParent->papoBuiltGeometries[nRefNr] == NULL) { /* this shouldn't happen under normal operation */ CPLError( CE_Fatal, CPLE_AppDefined, "Feature %li referenced by %li, but it was not initialized.", nRefNr, oNextSerial.lNr); return NULL; } OGRGeometry *geom = poParent->papoBuiltGeometries[nRefNr]; if (geom->getGeometryType() == wkbLineString) { OGRLineString *poCurve = (OGRLineString*)geom; if (nRefStatus == LC_MED_DIG) { /* clockwise */ poInner->addSubLineString(poCurve); } else if (nRefStatus == LC_MOT_DIG) { /* counter-clockwise */ poInner->addSubLineString(poCurve,poCurve->getNumPoints()-1,0); } else { CPLError( CE_Failure, CPLE_OpenFailed, "Internal error: GRF_*_OY encountered."); return NULL; } } else { CPLError( CE_Warning, CPLE_AppDefined, "Element %li composed of non-linestrings (REF %li of type %i). Ignored.", oNextSerial.lNr, nRefNr, geom->getGeometryType()); } } nRefCount = LC_GetRefFlate(&oGrfStat, GRF_INDRE, &nRefNr, &nRefStatus, 1); } poGeom = poLy; } break; } case L_KURVE: /* curve */ case L_LINJE: /* curve, not simplifyable */ case L_BUEP: { /* curve, interpolated from circular arc */ oGType = wkbLineString; OGRLineString *poCurve = (OGRLineString*)(poParent->papoBuiltGeometries[oNextSerial.lNr]); if (poCurve == NULL) { CPLError( CE_Fatal, CPLE_AppDefined, "Curve %li was not initialized.", oNextSerial.lNr); return NULL; } poGeom = poCurve->clone(); break; } case L_TEKST: { /* text */ oGType = wkbMultiPoint; OGRMultiPoint *poMP = (OGRMultiPoint*)(poParent->papoBuiltGeometries[oNextSerial.lNr]); if (poMP == NULL) { CPLError( CE_Fatal, CPLE_AppDefined, "Tekst %li was not initialized.", oNextSerial.lNr); return NULL; } poGeom = poMP->clone(); break; } case L_SYMBOL: { //CPLError( CE_Warning, CPLE_OpenFailed, "Geometry of type SYMBOL treated as point (PUNKT)."); } case L_PUNKT: { /* point */ oGType = wkbPoint; OGRPoint *poPoint = (OGRPoint*)(poParent->papoBuiltGeometries[oNextSerial.lNr]); if (poPoint == NULL) { CPLError( CE_Fatal, CPLE_AppDefined, "Point %li was not initialized.", oNextSerial.lNr); return NULL; } poGeom = poPoint->clone(); break; } case L_DEF: /* skip user definitions and headers here */ case L_HODE: { break; } default: { /* complain a bit about anything else that is not implemented */ CPLError( CE_Failure, CPLE_OpenFailed, "Unrecognized geometry of type %i.", nName); break; } } if (poGeom == NULL) continue; /* skipping L_HODE and unrecognized groups */ if (oGType != poFeatureDefn->GetGeomType()) { if (poGeom != NULL) delete poGeom; continue; /* skipping features that are not the correct geometry */ } OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); /* set all headers found in this group - we export everything, just in case */ for (iHeaders = oHeaders.begin(); iHeaders != oHeaders.end(); iHeaders++) { OGRSOSIDataType *poType = SOSIGetType(iHeaders->first); OGRSOSISimpleDataType *poElements = poType->getElements(); const char *pszLine = iHeaders->second.c_str(); char** tokens = CSLTokenizeString(iHeaders->second.c_str()); for (int k=0; k<poType->getElementCount(); k++) { if (tokens[k] == 0) break; if (strcmp(poElements[k].GetName(),"")==0) continue; int iHNr = poHeaderDefn->find(poElements[k].GetName())->second; if (iHNr == -1) { CPLError( CE_Warning, CPLE_AppDefined, "Could not find field definition for %s.", poElements[k].GetName()); continue; } OGRFieldType nType = poElements[k].GetType(); switch (nType) { case OFTInteger: { poFeature->SetField( iHNr, SOSITypeToInt(tokens[k])); break; } case OFTDate: { int date[3]; SOSITypeToDate(tokens[k], date); poFeature->SetField( iHNr, date[0], date[1], date[2]); break; } case OFTDateTime: { int date[6]; SOSITypeToDateTime(tokens[k], date); if (date[0]>0) poFeature->SetField( iHNr, date[0], date[1], date[2], date[3], date[4], static_cast<float>(date[5]), 1); break; } case OFTReal: { poFeature->SetField( iHNr, SOSITypeToReal(tokens[k])); break; } default: { if ((k==0)&&((pszLine[0] == '\'')||(pszLine[0] == '\"'))) { /* If the value is quoted, ignore these */ int nLen = static_cast<int>(strlen(pszLine)); char *pszNline = (char*)CPLMalloc(nLen-1); strncpy(pszNline, pszLine+1, nLen-2); pszNline[nLen-2] = '\0'; poFeature->SetField( iHNr, pszNline); CPLFree(pszNline); } else { poFeature->SetField( iHNr, tokens[k]); } break; } } } CSLDestroy(tokens); } if( poGeom != NULL ) poGeom->assignSpatialReference(poParent->poSRS); poFeature->SetGeometryDirectly( poGeom ); poFeature->SetFID( nNextFID++ ); /* Loop until we have a feature that matches the definition */ if ( (m_poFilterGeom == NULL || FilterGeometry( poFeature->GetGeometryRef() ) ) && (m_poAttrQuery == NULL || m_poAttrQuery->Evaluate( poFeature )) ) return poFeature; delete poFeature; } return NULL; }