コード例 #1
0
ファイル: landfireclient.cpp プロジェクト: firelab/windninja
/*
** Replace the default value srs value in the url with a utm zone.
**
** Steps:
**       Check for default SRS key/value
**       Erase it from the string
**       Add a new token with the EPSG code provided.
**
** The result should be freed using CPLFree();
*/
const char * LandfireClient::ReplaceSRS( int nEpsgCode, const char *pszUrl )
{
    int i, n;
    int nUrlSize = CPLStrnlen( pszUrl, 8192 );
    const char *pszEpsg = CPLSPrintf( "&prj=%d", nEpsgCode );
    int nEpsgSize = CPLStrnlen( pszEpsg, 8192 );
    char **papszBadTokens = CSLTokenizeString2( LF_DEFAULT_SRS_TOKENS, ",", 0 );
    int nBadTokenSize = 0;
    char *p, *q;
    char *pszNewUrl = CPLStrdup( pszUrl );

    i = 0;
    do
    {
        p = strstr( pszNewUrl, papszBadTokens[i] );
        nBadTokenSize = strlen( papszBadTokens[i] );
        i++;
    } while( i < CSLCount( papszBadTokens ) && !p );
    i--;
    if( p )
    {
        if( nBadTokenSize < nEpsgSize )
        {
            n = nUrlSize + nEpsgSize - nBadTokenSize + 1;
            CPLAssert( n > strlen( pszNewUrl ) );
            pszNewUrl = (char*)CPLRealloc( pszNewUrl, sizeof( char ) * n );
            /* reset p  after realloc */
            p = strstr( pszNewUrl, papszBadTokens[i] );
        }
        q = p + nBadTokenSize;
        while( *q != '\0' )
        {
            *(p++) = *(q++);
        }
        *p = '\0';
    }
    else
    {
        n = nUrlSize + nEpsgSize + 1;
        pszNewUrl = (char*)CPLRealloc( pszNewUrl, sizeof( char ) * n );
    }
    strcat( pszNewUrl, pszEpsg );
    CSLDestroy( papszBadTokens );
    return pszNewUrl;
}
コード例 #2
0
ファイル: gnmgenericnetwork.cpp プロジェクト: Mavrx-inc/gdal
CPLErr GNMGenericNetwork::LoadMetadataLayer(GDALDataset * const pDS)
{
    // read version, description, SRS, classes, rules
    m_poMetadataLayer = pDS->GetLayerByName(GNM_SYSLAYER_META);
    if(NULL == m_poMetadataLayer)
    {
        CPLError( CE_Failure, CPLE_AppDefined, "Loading of '%s' layer failed",
                  GNM_SYSLAYER_META );
        return CE_Failure;
    }

    std::map<int, GNMRule> moRules;
    int nRulePrefixLen = static_cast<int>(CPLStrnlen(GNM_MD_RULE, 255));
    OGRFeature *poFeature;
    m_poMetadataLayer->ResetReading();
    while ((poFeature = m_poMetadataLayer->GetNextFeature()) != NULL)
    {
        const char *pKey = poFeature->GetFieldAsString(GNM_SYSFIELD_PARAMNAME);
        const char *pValue = poFeature->GetFieldAsString(GNM_SYSFIELD_PARAMVALUE);

        CPLDebug("GNM", "Load metadata. Key: %s, value %s", pKey, pValue);

        if(EQUAL(pKey, GNM_MD_NAME))
        {
            m_soName = pValue;
        }
        else if(EQUAL(pKey, GNM_MD_DESCR))
        {
            sDescription = pValue;
        }
        else if(EQUAL(pKey, GNM_MD_SRS))
        {
            m_soSRS = pValue;
        }
        else if(EQUAL(pKey, GNM_MD_VERSION))
        {
            m_nVersion = atoi(pValue);
        }
        else if(EQUALN(pKey, GNM_MD_RULE, nRulePrefixLen))
        {
            moRules[atoi(pKey + nRulePrefixLen)] = GNMRule(pValue);
        }

        OGRFeature::DestroyFeature(poFeature);
    }

    for(std::map<int, GNMRule>::iterator it =  moRules.begin();
        it != moRules.end(); ++it)
    {
        if(it->second.IsValid())
            m_asRules.push_back(it->second);
    }

    if(m_soSRS.empty())
    {
        // cppcheck-suppress knownConditionTrueFalse
        if(LoadNetworkSrs() != CE_None)
            return CE_Failure;
    }

    return CE_None;
}
コード例 #3
0
static CPLErr Resolve( CPLXMLNode * psNode,
                CPLXMLNode *** ppapsRoot,
                char *** ppapszResourceHREF,
                char ** papszSkip,
                const int bStrict )

{
    //for each sibling
    CPLXMLNode *psSibling = NULL;
    CPLXMLNode *psResource = NULL;
    CPLXMLNode *psTarget = NULL;
    CPLErr eReturn = CE_None, eReturned;
    
    for( psSibling = psNode; psSibling != NULL; psSibling = psSibling->psNext )
    {
        if( psSibling->eType != CXT_Element )
            continue;

        CPLXMLNode *psChild = psSibling->psChild;
        while( psChild != NULL &&
               !( psChild->eType == CXT_Attribute &&
                  EQUAL( psChild->pszValue, "xlink:href" ) ) )
            psChild = psChild->psNext;

        //if a child has a "xlink:href" attribute
        if( psChild != NULL && psChild->psChild != NULL )
        {
            if( CSLFindString( papszSkip, psSibling->pszValue ) >= 0 )
            {//Skipping a specified element
                eReturn = CE_Warning;
                continue;
            }

            static int i = 0;
            if( i-- == 0 )
            {//a way to track progress
                i = 256;
                CPLDebug( "GML",
                          "Resolving xlinks... (currently %s)",
                          psChild->psChild->pszValue );
            }

            char **papszTokens;
            papszTokens = CSLTokenizeString2( psChild->psChild->pszValue, "#",
                                              CSLT_ALLOWEMPTYTOKENS |
                                              CSLT_STRIPLEADSPACES |
                                              CSLT_STRIPENDSPACES );
            if( CSLCount( papszTokens ) != 2 || strlen(papszTokens[1]) <= 0 )
            {
                CPLError( bStrict ? CE_Failure : CE_Warning,
                          CPLE_NotSupported,
                          "Error parsing the href %s.%s",
                          psChild->psChild->pszValue,
                          bStrict ? "" : " Skipping..." );
                CSLDestroy( papszTokens );
                if( bStrict )
                    return CE_Failure;
                eReturn = CE_Warning;
                continue;
            }

            //look for the resource with that URL
            psResource = FindTreeByURL( ppapsRoot,
                                        ppapszResourceHREF,
                                        papszTokens[0] );
            if( psResource == NULL )
            {
                CSLDestroy( papszTokens );
                if( bStrict )
                    return CE_Failure;
                eReturn = CE_Warning;
                continue;
            }

            //look for the element with the ID
            psTarget = FindElementByID( psResource, papszTokens[1] );
            if( psTarget != NULL )
            {
                //remove the xlink:href attribute
                CPLRemoveXMLChild( psSibling, psChild );
                CPLDestroyXMLNode( psChild );

                //make a copy of psTarget
                CPLXMLNode *psCopy = CPLCreateXMLNode( NULL,
                                                       CXT_Element,
                                                       psTarget->pszValue );
                psCopy->psChild = CPLCloneXMLTree( psTarget->psChild );
                RemoveIDs( psCopy );
                //correct empty URLs in URL#id pairs
                if( CPLStrnlen( papszTokens[0], 1 ) > 0 )
                {
                    CorrectURLs( psCopy, papszTokens[0] );
                }
                CPLAddXMLChild( psSibling, psCopy );
                CSLDestroy( papszTokens );
            }
            else
            {
                //element not found
                CSLDestroy( papszTokens );
                CPLError( bStrict ? CE_Failure : CE_Warning,
                          CPLE_ObjectNull,
                          "Couldn't find the element with id %s.",
                          psChild->psChild->pszValue );
                if( bStrict )
                    return CE_Failure;
                eReturn = CE_Warning;
            }
        }

        //Recurse with the first child
        eReturned=Resolve( psSibling->psChild,
                           ppapsRoot,
                           ppapszResourceHREF,
                           papszSkip,
                           bStrict );

        if( eReturned == CE_Failure )
            return CE_Failure;

        if( eReturned == CE_Warning )
                eReturn = CE_Warning;
    }
    return eReturn;
}
コード例 #4
0
static void CorrectURLs( CPLXMLNode * psRoot, const char *pszURL )

{
    if( psRoot == NULL || pszURL == NULL )
        return;
    if( pszURL[0] == '\0' )
        return;

    CPLXMLNode *psChild = psRoot->psChild;

// check for xlink:href attribute
    while( psChild != NULL && !( ( psChild->eType == CXT_Attribute ) &&
                                 ( EQUAL(psChild->pszValue, "xlink:href") )) )
        psChild = psChild->psNext;

    if( psChild != NULL &&
        !( strstr( psChild->psChild->pszValue, pszURL ) == psChild->psChild->pszValue
        && psChild->psChild->pszValue[strlen(pszURL)] == '#' ) )
    {
    //href has a different url
        size_t nLen;
        char *pszNew;
        if( psChild->psChild->pszValue[0] == '#' )
        {
        //empty URL: prepend the given URL
            nLen = CPLStrnlen( pszURL, 1024 ) +
                   CPLStrnlen( psChild->psChild->pszValue, 1024 ) + 1;
            pszNew = (char *)CPLMalloc( nLen * sizeof(char));
            CPLStrlcpy( pszNew, pszURL, nLen );
            CPLStrlcat( pszNew, psChild->psChild->pszValue, nLen );
            CPLSetXMLValue( psRoot, "#xlink:href", pszNew );
            CPLFree( pszNew );
        }
        else
        {
            size_t nPathLen;
            for( nPathLen = strlen(pszURL);
                 nPathLen > 0 && pszURL[nPathLen - 1] != '/'
                              && pszURL[nPathLen - 1] != '\\';
                 nPathLen--);

            if( strncmp( pszURL, psChild->psChild->pszValue, nPathLen ) != 0 )
            {
            //different path
                int nURLLen = strchr( psChild->psChild->pszValue, '#' ) -
                              psChild->psChild->pszValue;
                char *pszURLWithoutID = (char *)CPLMalloc( (nURLLen+1) * sizeof(char));
                strncpy( pszURLWithoutID, psChild->psChild->pszValue, nURLLen );
                pszURLWithoutID[nURLLen] = '\0';

                if( CPLIsFilenameRelative( pszURLWithoutID ) &&
                    strstr( pszURLWithoutID, ":" ) == NULL )
                {
                    //relative URL: prepend the path of pszURL
                    nLen = nPathLen +
                           CPLStrnlen( psChild->psChild->pszValue, 1024 ) + 1;
                    pszNew = (char *)CPLMalloc( nLen * sizeof(char));
                    size_t i;
                    for( i = 0; i < nPathLen; i++ )
                        pszNew[i] = pszURL[i];
                    pszNew[nPathLen] = '\0';
                    CPLStrlcat( pszNew, psChild->psChild->pszValue, nLen );
                    CPLSetXMLValue( psRoot, "#xlink:href", pszNew );
                    CPLFree( pszNew );
                }
                CPLFree( pszURLWithoutID );
            }
        }
    }

// search the child elements of psRoot
    for( psChild = psRoot->psChild; psChild != NULL; psChild = psChild->psNext)
        if( psChild->eType == CXT_Element )
            CorrectURLs( psChild, pszURL );
}
コード例 #5
0
ファイル: ogrsource.cpp プロジェクト: rforge/rgdal
SEXP ogrReadColumn(OGRLayer *poLayer, SEXP FIDs, int iField, int int64, int ENC_DEBUG) {
    // read feature data and return something according to the type
    OGRFeatureDefn *poDefn;
    OGRFieldDefn *poField;
    OGRFeature *poFeature;
    int iRow,nRows;
    SEXP ans = R_NilValue;

    nRows=length(FIDs);
    // get field data from layer
    installErrorHandler();
    poDefn = poLayer->GetLayerDefn();
    poField = poDefn->GetFieldDefn(iField);
    uninstallErrorHandlerAndTriggerError();
    if(poField == NULL) {
        error("Error getting field %d ",iField);
    }
    // allocate an object for the result depending on the feature type:
    installErrorHandler();
    switch(poField->GetType()) {
    case OFTInteger:
        PROTECT(ans=allocVector(INTSXP,nRows));
        break;
#ifdef GDALV2
    case OFTInteger64:
        if (int64 ==3) {
            PROTECT(ans=allocVector(STRSXP,nRows));
        } else {
            PROTECT(ans=allocVector(INTSXP,nRows));
        }
        break;
#endif
    case OFTReal:
        PROTECT(ans=allocVector(REALSXP,nRows));
        break;
    case OFTString:
        PROTECT(ans=allocVector(STRSXP,nRows));
        break;
    case OFTDate:
        PROTECT(ans=allocVector(STRSXP,nRows));
        break;
    case OFTDateTime:
        PROTECT(ans=allocVector(STRSXP,nRows));
        break;
    case OFTTime:
        PROTECT(ans=allocVector(STRSXP,nRows));
        break;
    default:
        const char *desc = poField->GetFieldTypeName(poField->GetType());
        uninstallErrorHandlerAndTriggerError();
        error("unsupported field type: %s", desc);
        break;
    }
    uninstallErrorHandlerAndTriggerError();

    // now go over each row and retrieve data. iRow is an index in a
    // vector of FIDs
    /*#ifndef EJP
        installErrorHandler();
        for(iRow=0;iRow<nRows;iRow++){
          poFeature=poLayer->GetFeature(INTEGER(FIDs)[iRow]);
          if(poFeature == NULL){
    	error("Error getting feature FID: %d",(INTEGER(FIDs)[iRow]));
          }
        }
        uninstallErrorHandlerAndTriggerError();
    #else*/
    // EJP, changed into:
    installErrorHandler();
    poLayer->ResetReading();
    iRow = 0;
    while((poFeature = poLayer->GetNextFeature()) != NULL) {
//#endif
        // now get the value using the right type:
        switch(poField->GetType()) {
        case OFTInteger:
            if (poFeature->IsFieldSet(iField))
                INTEGER(ans)[iRow]=poFeature->GetFieldAsInteger(iField);
            else INTEGER(ans)[iRow]=NA_INTEGER;
            break;
#ifdef GDALV2
        case OFTInteger64:
            if (poFeature->IsFieldSet(iField)) {
                if (int64 == 3) {
                    SET_STRING_ELT(ans, iRow,
                                   mkChar(poFeature->GetFieldAsString(iField)));
                } else {
                    GIntBig nVal64 = poFeature->GetFieldAsInteger64(iField);
                    int nVal = (nVal64 > INT_MAX) ? INT_MAX :
                               (nVal64 < INT_MIN) ? INT_MIN : (int) nVal64;
                    INTEGER(ans)[iRow]=nVal;
                    if (((GIntBig)nVal != nVal64) && int64 == 2) {
                        warning("Integer64 value clamped: feature %d", iRow);
                    }
                }
            } else {
                if (int64 == 3) {
                    SET_STRING_ELT(ans, iRow, NA_STRING);
                } else {
                    INTEGER(ans)[iRow]=NA_INTEGER;
                }
            }
            break;
#endif
        case OFTReal:
            if (poFeature->IsFieldSet(iField))
                REAL(ans)[iRow]=poFeature->GetFieldAsDouble(iField);
            else REAL(ans)[iRow]=NA_REAL;
            break;
        case OFTString:
// ENC
            char str[4096];
            size_t stln;
            if (poFeature->IsFieldSet(iField)) {
                stln = CPLStrnlen(poFeature->GetFieldAsString(iField), 4096);
                CPLStrlcpy(str, (const char *) poFeature->GetFieldAsString(iField),
                           4096);
                SET_STRING_ELT(ans, iRow, mkChar(str));
            } else SET_STRING_ELT(ans, iRow, NA_STRING);
            if (ENC_DEBUG) {
                Rprintf("iField: %d, iRow: %d stln %u Enc %s ", iField,
                        iRow, stln, CPLIsUTF8(str, (int) stln)?"UTF-8":"other");
                for (int si=0; si < (int) stln; si++)
                    Rprintf("%x ", (unsigned char) str[si]);
                Rprintf("\n");
            } /* FIXME */
            break;
        case OFTDate:
            if (poFeature->IsFieldSet(iField))
                SET_STRING_ELT(ans,iRow,mkChar(poFeature->GetFieldAsString(iField)));
            else SET_STRING_ELT(ans, iRow, NA_STRING);
            break;
        case OFTDateTime:
            if (poFeature->IsFieldSet(iField))
                SET_STRING_ELT(ans,iRow,mkChar(poFeature->GetFieldAsString(iField)));
            else SET_STRING_ELT(ans, iRow, NA_STRING);
            break;
        case OFTTime:
            if (poFeature->IsFieldSet(iField))
                SET_STRING_ELT(ans,iRow,mkChar(poFeature->GetFieldAsString(iField)));
            else SET_STRING_ELT(ans, iRow, NA_STRING);
            break;

        default:
            OGRFeature::DestroyFeature( poFeature );
//        delete poFeature;
            uninstallErrorHandlerAndTriggerError();
            error("Unsupported field type. should have been caught before");
        }
        OGRFeature::DestroyFeature( poFeature );
//      delete poFeature;
//#ifdef EJP
        // according to tutorial: OGRFeature::DestroyFeature(poFeature);
        // see comment FW in OGR tutorial: We could just "delete" it,
        // but this can cause problems in windows builds where the GDAL DLL
        // has a different "heap" from the main program. To be on the safe
        // side we use a GDAL function to delete the feature.
        iRow++;
//#endif
    }
    uninstallErrorHandlerAndTriggerError();
    UNPROTECT(1);
    return(ans);
}
コード例 #6
0
ファイル: ogrkmllayer.cpp プロジェクト: Wedjaa/node-gdal
OGRErr OGRKMLLayer::ICreateFeature( OGRFeature* poFeature )
{
    CPLAssert( NULL != poFeature );
    CPLAssert( NULL != poDS_ );

    if( !bWriter_ )
        return OGRERR_FAILURE;

    if( bClosedForWriting )
    {
        CPLError(CE_Failure, CPLE_NotSupported,
                 "Interleaved feature adding to different layers is not supported");
        return OGRERR_FAILURE;
    }

    VSILFILE *fp = poDS_->GetOutputFP();
    CPLAssert( NULL != fp );

    if( poDS_->GetLayerCount() == 1 && nWroteFeatureCount_ == 0 )
    {
        CPLString osRet = WriteSchema();
        if( osRet.size() )
            VSIFPrintfL( fp, "%s", osRet.c_str() );
        bSchemaWritten_ = TRUE;

        VSIFPrintfL( fp, "<Folder><name>%s</name>\n", pszName_);
    }

    VSIFPrintfL( fp, "  <Placemark>\n" );

    if( poFeature->GetFID() == OGRNullFID )
        poFeature->SetFID( iNextKMLId_++ );

    // Find and write the name element
    if (NULL != poDS_->GetNameField())
    {
        for( int iField = 0; iField < poFeatureDefn_->GetFieldCount(); iField++ )
        {
            OGRFieldDefn *poField = poFeatureDefn_->GetFieldDefn( iField );

            if( poFeature->IsFieldSet( iField )
                && EQUAL(poField->GetNameRef(), poDS_->GetNameField()) )
            {
                const char *pszRaw = poFeature->GetFieldAsString( iField );
                while( *pszRaw == ' ' )
                    pszRaw++;

                char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );

                VSIFPrintfL( fp, "\t<name>%s</name>\n", pszEscaped);
                CPLFree( pszEscaped );
            }
        }
    }

    if (NULL != poDS_->GetDescriptionField())
    {
        for( int iField = 0; iField < poFeatureDefn_->GetFieldCount(); iField++ )
        {
            OGRFieldDefn *poField = poFeatureDefn_->GetFieldDefn( iField );

            if( poFeature->IsFieldSet( iField )
                && EQUAL(poField->GetNameRef(), poDS_->GetDescriptionField()) )
            {
                const char *pszRaw = poFeature->GetFieldAsString( iField );
                while( *pszRaw == ' ' )
                    pszRaw++;

                char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );

                VSIFPrintfL( fp, "\t<description>%s</description>\n", pszEscaped);
                CPLFree( pszEscaped );
            }
        }
    }

    OGRwkbGeometryType eGeomType = wkbNone;
    if (poFeature->GetGeometryRef() != NULL)
        eGeomType = wkbFlatten(poFeature->GetGeometryRef()->getGeometryType());
    if ( wkbPolygon == eGeomType
         || wkbMultiPolygon == eGeomType
         || wkbLineString == eGeomType
         || wkbMultiLineString == eGeomType )
    {
        OGRStylePen *poPen = NULL;
        OGRStyleMgr oSM;

        if( poFeature->GetStyleString() != NULL )
        {
            oSM.InitFromFeature( poFeature );

            int i;
            for(i=0; i<oSM.GetPartCount();i++)
            {
                OGRStyleTool *poTool = oSM.GetPart(i);
                if (poTool && poTool->GetType() == OGRSTCPen )
                {
                    poPen = (OGRStylePen*) poTool;
                    break;
                }
                delete poTool;
            }
        }

        VSIFPrintfL( fp, "\t<Style>");
        if( poPen != NULL )
        {
            GBool  bDefault;
            int    bHasWidth = FALSE;

            /* Require width to be returned in pixel */
            poPen->SetUnit(OGRSTUPixel);
            double fW = poPen->Width(bDefault);
            if( bDefault )
                fW = 1;
            else
                bHasWidth = TRUE;
            const char* pszColor = poPen->Color(bDefault);
            int nColorLen = static_cast<int>(CPLStrnlen(pszColor, 10));
            if( pszColor != NULL && pszColor[0] == '#' && !bDefault && nColorLen >= 7)
            {
                char acColor[9] = {0};
                /* Order of KML color is aabbggrr, whereas OGR color is #rrggbb[aa] ! */
                if(nColorLen == 9)
                {
                    acColor[0] = pszColor[7]; /* A */
                    acColor[1] = pszColor[8];
                }
                else
                {
                    acColor[0] = 'F';
                    acColor[1] = 'F';
                }
                acColor[2] = pszColor[5]; /* B */
                acColor[3] = pszColor[6];
                acColor[4] = pszColor[3]; /* G */
                acColor[5] = pszColor[4];
                acColor[6] = pszColor[1]; /* R */
                acColor[7] = pszColor[2];
                VSIFPrintfL( fp, "<LineStyle><color>%s</color>", acColor);
                if (bHasWidth)
                    VSIFPrintfL( fp, "<width>%g</width>", fW);
                VSIFPrintfL( fp, "</LineStyle>");
            }
            else
                VSIFPrintfL( fp, "<LineStyle><color>ff0000ff</color></LineStyle>");
        }
        else
            VSIFPrintfL( fp, "<LineStyle><color>ff0000ff</color></LineStyle>");
        delete poPen;
        //If we're dealing with a polygon, add a line style that will stand out a bit
        VSIFPrintfL( fp, "<PolyStyle><fill>0</fill></PolyStyle></Style>\n" );
    }

    int bHasFoundOtherField = FALSE;

    // Write all fields as SchemaData
    for( int iField = 0; iField < poFeatureDefn_->GetFieldCount(); iField++ )
    {
        OGRFieldDefn *poField = poFeatureDefn_->GetFieldDefn( iField );

        if( poFeature->IsFieldSet( iField ))
        {
            if (NULL != poDS_->GetNameField() &&
                EQUAL(poField->GetNameRef(), poDS_->GetNameField()) )
                continue;

            if (NULL != poDS_->GetDescriptionField() &&
                EQUAL(poField->GetNameRef(), poDS_->GetDescriptionField()) )
                continue;

            if (!bHasFoundOtherField)
            {
                VSIFPrintfL( fp, "\t<ExtendedData><SchemaData schemaUrl=\"#%s\">\n", pszName_ );
                bHasFoundOtherField = TRUE;
            }
            const char *pszRaw = poFeature->GetFieldAsString( iField );

            while( *pszRaw == ' ' )
                pszRaw++;

            char *pszEscaped;
            if (poFeatureDefn_->GetFieldDefn(iField)->GetType() == OFTReal)
            {
                pszEscaped = CPLStrdup( pszRaw );
            }
            else
            {
                pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
            }

            VSIFPrintfL( fp, "\t\t<SimpleData name=\"%s\">%s</SimpleData>\n",
                        poField->GetNameRef(), pszEscaped);

            CPLFree( pszEscaped );
        }
    }

    if (bHasFoundOtherField)
    {
        VSIFPrintfL( fp, "\t</SchemaData></ExtendedData>\n" );
    }

    // Write out Geometry - for now it isn't indented properly.
    if( poFeature->GetGeometryRef() != NULL )
    {
        char* pszGeometry = NULL;
        OGREnvelope sGeomBounds;
        OGRGeometry* poWGS84Geom;

        if (NULL != poCT_)
        {
            poWGS84Geom = poFeature->GetGeometryRef()->clone();
            poWGS84Geom->transform( poCT_ );
        }
        else
        {
            poWGS84Geom = poFeature->GetGeometryRef();
        }

        // TODO - porting
        // pszGeometry = poFeature->GetGeometryRef()->exportToKML();
        pszGeometry =
            OGR_G_ExportToKML( (OGRGeometryH)poWGS84Geom,
                               poDS_->GetAltitudeMode());

        VSIFPrintfL( fp, "      %s\n", pszGeometry );
        CPLFree( pszGeometry );

        poWGS84Geom->getEnvelope( &sGeomBounds );
        poDS_->GrowExtents( &sGeomBounds );

        if (NULL != poCT_)
        {
            delete poWGS84Geom;
        }
    }

    VSIFPrintfL( fp, "  </Placemark>\n" );
    nWroteFeatureCount_++;
    return OGRERR_NONE;
}