LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/jml - ogrjmlwriterlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 162 180 90.0 %
Date: 2024-11-21 22:18:42 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  JML Translator
       4             :  * Purpose:  Implements OGRJMLWriterLayer class.
       5             :  *
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  ****************************************************************************/
      11             : 
      12             : #include "ogr_jml.h"
      13             : #include "cpl_conv.h"
      14             : #include "ogr_p.h"
      15             : 
      16             : #include <cstdlib>
      17             : 
      18             : /************************************************************************/
      19             : /*                           OGRJMLWriterLayer()                        */
      20             : /************************************************************************/
      21             : 
      22          38 : OGRJMLWriterLayer::OGRJMLWriterLayer(const char *pszLayerName,
      23             :                                      OGRSpatialReference *poSRS,
      24             :                                      OGRJMLDataset *poDSIn, VSILFILE *fpIn,
      25             :                                      bool bAddRGBFieldIn,
      26             :                                      bool bAddOGRStyleFieldIn,
      27          38 :                                      bool bClassicGMLIn)
      28          38 :     : poDS(poDSIn), poFeatureDefn(new OGRFeatureDefn(pszLayerName)), fp(fpIn),
      29             :       bFeaturesWritten(false), bAddRGBField(bAddRGBFieldIn),
      30             :       bAddOGRStyleField(bAddOGRStyleFieldIn), bClassicGML(bClassicGMLIn),
      31          76 :       nNextFID(0), nBBoxOffset(0)
      32             : {
      33          38 :     SetDescription(poFeatureDefn->GetName());
      34          38 :     poFeatureDefn->Reference();
      35             : 
      36          38 :     if (poSRS)
      37             :     {
      38           1 :         const char *pszAuthName = poSRS->GetAuthorityName(nullptr);
      39           1 :         const char *pszAuthCode = poSRS->GetAuthorityCode(nullptr);
      40           1 :         if (pszAuthName != nullptr && EQUAL(pszAuthName, "EPSG") &&
      41             :             pszAuthCode != nullptr)
      42             :         {
      43           1 :             osSRSAttr = " srsName=\"http://www.opengis.net/gml/srs/epsg.xml#";
      44           1 :             osSRSAttr += pszAuthCode;
      45           1 :             osSRSAttr += "\"";
      46             :         }
      47             :     }
      48             : 
      49          38 :     VSIFPrintfL(fp,
      50             :                 "<?xml version='1.0' encoding='UTF-8'?>\n"
      51             :                 "<JCSDataFile xmlns:gml=\"http://www.opengis.net/gml\" "
      52             :                 "xmlns:xsi=\"http://www.w3.org/2000/10/XMLSchema-instance\" >\n"
      53             :                 "<JCSGMLInputTemplate>\n"
      54             :                 "<CollectionElement>featureCollection</CollectionElement>\n"
      55             :                 "<FeatureElement>feature</FeatureElement>\n"
      56             :                 "<GeometryElement>geometry</GeometryElement>\n"
      57             :                 "<CRSElement>boundedBy</CRSElement>\n"
      58             :                 "<ColumnDefinitions>\n");
      59          38 : }
      60             : 
      61             : /************************************************************************/
      62             : /*                        ~OGRJMLWriterLayer()                          */
      63             : /************************************************************************/
      64             : 
      65          76 : OGRJMLWriterLayer::~OGRJMLWriterLayer()
      66             : {
      67          38 :     if (!bFeaturesWritten)
      68             :     {
      69          17 :         VSIFPrintfL(fp,
      70             :                     "</ColumnDefinitions>\n</JCSGMLInputTemplate>\n"
      71             :                     "<featureCollection>\n"
      72             :                     "  <gml:boundedBy>\n"
      73             :                     "    <gml:Box%s>\n"
      74             :                     "      <gml:coordinates decimal=\".\" cs=\",\" ts=\" "
      75             :                     "\">0.00,0.00 -1.00,-1.00</gml:coordinates>\n"
      76             :                     "    </gml:Box>\n"
      77             :                     "  </gml:boundedBy>\n",
      78             :                     osSRSAttr.c_str());
      79             :     }
      80          21 :     else if (nBBoxOffset > 0)
      81             :     {
      82          21 :         VSIFSeekL(fp, nBBoxOffset, SEEK_SET);
      83          21 :         if (sLayerExtent.IsInit())
      84             :         {
      85             :             char szBuffer[101];
      86          19 :             CPLsnprintf(szBuffer, sizeof(szBuffer), "%.10f,%.10f %.10f,%.10f",
      87             :                         sLayerExtent.MinX, sLayerExtent.MinY, sLayerExtent.MaxX,
      88             :                         sLayerExtent.MaxY);
      89          19 :             VSIFPrintfL(fp, "%s", szBuffer);
      90             :         }
      91             :         else
      92             :         {
      93           2 :             VSIFPrintfL(fp, "0.00,0.00 -1.00,-1.00");
      94             :         }
      95          21 :         VSIFSeekL(fp, 0, SEEK_END);
      96             :     }
      97          38 :     VSIFPrintfL(fp, "</featureCollection>\n</JCSDataFile>\n");
      98          38 :     poFeatureDefn->Release();
      99          76 : }
     100             : 
     101             : /************************************************************************/
     102             : /*                         WriteColumnDeclaration()                     */
     103             : /************************************************************************/
     104             : 
     105         111 : void OGRJMLWriterLayer::WriteColumnDeclaration(const char *pszName,
     106             :                                                const char *pszType)
     107             : {
     108         111 :     char *pszEscapedName = OGRGetXML_UTF8_EscapedString(pszName);
     109         111 :     if (bClassicGML)
     110             :     {
     111           0 :         VSIFPrintfL(fp,
     112             :                     "     <column>\n"
     113             :                     "          <name>%s</name>\n"
     114             :                     "          <type>%s</type>\n"
     115             :                     "          <valueElement elementName=\"%s\"/>\n"
     116             :                     "          <valueLocation position=\"body\"/>\n"
     117             :                     "     </column>\n",
     118             :                     pszEscapedName, pszType, pszEscapedName);
     119             :     }
     120             :     else
     121             :     {
     122         111 :         VSIFPrintfL(fp,
     123             :                     "     <column>\n"
     124             :                     "          <name>%s</name>\n"
     125             :                     "          <type>%s</type>\n"
     126             :                     "          <valueElement elementName=\"property\" "
     127             :                     "attributeName=\"name\" attributeValue=\"%s\"/>\n"
     128             :                     "          <valueLocation position=\"body\"/>\n"
     129             :                     "     </column>\n",
     130             :                     pszEscapedName, pszType, pszEscapedName);
     131             :     }
     132         111 :     CPLFree(pszEscapedName);
     133         111 : }
     134             : 
     135             : /************************************************************************/
     136             : /*                           ICreateFeature()                            */
     137             : /************************************************************************/
     138             : 
     139          72 : OGRErr OGRJMLWriterLayer::ICreateFeature(OGRFeature *poFeature)
     140             : 
     141             : {
     142             :     /* Finish column declaration if we haven't yet created a feature */
     143          72 :     if (!bFeaturesWritten)
     144             :     {
     145          21 :         if (bAddOGRStyleField && poFeatureDefn->GetFieldIndex("OGR_STYLE") < 0)
     146             :         {
     147           2 :             WriteColumnDeclaration("OGR_STYLE", "STRING");
     148             :         }
     149          21 :         if (bAddRGBField && poFeatureDefn->GetFieldIndex("R_G_B") < 0)
     150             :         {
     151          18 :             WriteColumnDeclaration("R_G_B", "STRING");
     152             :         }
     153          21 :         VSIFPrintfL(fp,
     154             :                     "</ColumnDefinitions>\n</JCSGMLInputTemplate>\n"
     155             :                     "<featureCollection>\n"
     156             :                     "  <gml:boundedBy>\n"
     157             :                     "    <gml:Box%s>\n"
     158             :                     "      <gml:coordinates decimal=\".\" cs=\",\" ts=\" \">",
     159             :                     osSRSAttr.c_str());
     160          21 :         if (EQUAL(poDS->GetDescription(), "/vsistdout/"))
     161             :         {
     162           0 :             VSIFPrintfL(fp, "0.00,0.00 -1.00,-1.00");
     163             :         }
     164             :         else
     165             :         {
     166          21 :             nBBoxOffset = VSIFTellL(fp);
     167          21 :             VSIFPrintfL(fp,
     168             :                         // 100 characters reserved
     169             :                         "                                                  "
     170             :                         "                                                  ");
     171             :         }
     172          21 :         VSIFPrintfL(fp, "</gml:coordinates>\n"
     173             :                         "    </gml:Box>\n"
     174             :                         "  </gml:boundedBy>\n");
     175          21 :         bFeaturesWritten = true;
     176             :     }
     177             : 
     178          72 :     if (bClassicGML)
     179           0 :         VSIFPrintfL(fp, "   <featureMember>\n");
     180          72 :     VSIFPrintfL(fp, "     <feature>\n");
     181             : 
     182             :     /* Add geometry */
     183          72 :     VSIFPrintfL(fp, "          <geometry>\n");
     184          72 :     OGRGeometry *poGeom = poFeature->GetGeometryRef();
     185          72 :     if (poGeom != nullptr)
     186             :     {
     187          36 :         if (!poGeom->IsEmpty())
     188             :         {
     189          36 :             OGREnvelope sExtent;
     190          36 :             poGeom->getEnvelope(&sExtent);
     191          36 :             sLayerExtent.Merge(sExtent);
     192             :         }
     193          36 :         char *pszGML = poGeom->exportToGML();
     194          36 :         VSIFPrintfL(fp, "                %s\n", pszGML);
     195          36 :         CPLFree(pszGML);
     196             :     }
     197             :     else
     198             :     {
     199          36 :         VSIFPrintfL(fp, "                %s\n",
     200             :                     "<gml:MultiGeometry></gml:MultiGeometry>");
     201             :     }
     202          72 :     VSIFPrintfL(fp, "          </geometry>\n");
     203             : 
     204             :     /* Add fields */
     205         418 :     for (int i = 0; i < poFeature->GetFieldCount(); i++)
     206             :     {
     207         346 :         char *pszName = OGRGetXML_UTF8_EscapedString(
     208         346 :             poFeatureDefn->GetFieldDefn(i)->GetNameRef());
     209         346 :         if (bClassicGML)
     210           0 :             VSIFPrintfL(fp, "          <%s>", pszName);
     211             :         else
     212         346 :             VSIFPrintfL(fp, "          <property name=\"%s\">", pszName);
     213         346 :         if (poFeature->IsFieldSetAndNotNull(i))
     214             :         {
     215             :             const OGRFieldType eType =
     216         250 :                 poFeatureDefn->GetFieldDefn(i)->GetType();
     217         250 :             if (eType == OFTString)
     218             :             {
     219          52 :                 char *pszValue = OGRGetXML_UTF8_EscapedString(
     220             :                     poFeature->GetFieldAsString(i));
     221          52 :                 VSIFPrintfL(fp, "%s", pszValue);
     222          52 :                 CPLFree(pszValue);
     223             :             }
     224         198 :             else if (eType == OFTDateTime)
     225             :             {
     226          50 :                 int nYear = 0;
     227          50 :                 int nMonth = 0;
     228          50 :                 int nDay = 0;
     229          50 :                 int nHour = 0;
     230          50 :                 int nMinute = 0;
     231          50 :                 int nTZFlag = 0;
     232          50 :                 float fSecond = 0.0f;
     233          50 :                 poFeature->GetFieldAsDateTime(i, &nYear, &nMonth, &nDay, &nHour,
     234             :                                               &nMinute, &fSecond, &nTZFlag);
     235             :                 /* When writing time zone, OpenJUMP expects .XXX seconds */
     236             :                 /* to be written */
     237          50 :                 if (nTZFlag > 1 || OGR_GET_MS(fSecond) != 0)
     238           1 :                     VSIFPrintfL(fp, "%04d-%02d-%02dT%02d:%02d:%06.3f", nYear,
     239             :                                 nMonth, nDay, nHour, nMinute, fSecond);
     240             :                 else
     241          49 :                     VSIFPrintfL(fp, "%04d-%02d-%02dT%02d:%02d:%02d", nYear,
     242             :                                 nMonth, nDay, nHour, nMinute, (int)fSecond);
     243          50 :                 if (nTZFlag > 1)
     244             :                 {
     245           1 :                     int nOffset = (nTZFlag - 100) * 15;
     246           1 :                     int nHours = (int)(nOffset / 60);  // round towards zero
     247           1 :                     int nMinutes = std::abs(nOffset - nHours * 60);
     248             : 
     249           1 :                     if (nOffset < 0)
     250             :                     {
     251           0 :                         VSIFPrintfL(fp, "-");
     252           0 :                         nHours = std::abs(nHours);
     253             :                     }
     254             :                     else
     255           1 :                         VSIFPrintfL(fp, "+");
     256             : 
     257           1 :                     VSIFPrintfL(fp, "%02d%02d", nHours, nMinutes);
     258             :                 }
     259             :             }
     260             :             else
     261             :             {
     262         148 :                 VSIFPrintfL(fp, "%s", poFeature->GetFieldAsString(i));
     263             :             }
     264             :         }
     265         346 :         if (bClassicGML)
     266           0 :             VSIFPrintfL(fp, "</%s>\n", pszName);
     267             :         else
     268         346 :             VSIFPrintfL(fp, "</property>\n");
     269         346 :         CPLFree(pszName);
     270             :     }
     271             : 
     272             :     /* Add OGR_STYLE from feature style string (if asked) */
     273          72 :     if (bAddOGRStyleField && poFeatureDefn->GetFieldIndex("OGR_STYLE") < 0)
     274             :     {
     275           2 :         if (bClassicGML)
     276           0 :             VSIFPrintfL(fp, "          <OGR_STYLE>");
     277             :         else
     278           2 :             VSIFPrintfL(fp, "          <property name=\"%s\">", "OGR_STYLE");
     279           2 :         if (poFeature->GetStyleString() != nullptr)
     280             :         {
     281             :             char *pszValue =
     282           2 :                 OGRGetXML_UTF8_EscapedString(poFeature->GetStyleString());
     283           2 :             VSIFPrintfL(fp, "%s", pszValue);
     284           2 :             CPLFree(pszValue);
     285             :         }
     286           2 :         if (bClassicGML)
     287           0 :             VSIFPrintfL(fp, "</OGR_STYLE>\n");
     288             :         else
     289           2 :             VSIFPrintfL(fp, "</property>\n");
     290             :     }
     291             : 
     292             :     /* Derive R_G_B field from feature style string */
     293          72 :     if (bAddRGBField && poFeatureDefn->GetFieldIndex("R_G_B") < 0)
     294             :     {
     295          68 :         if (bClassicGML)
     296           0 :             VSIFPrintfL(fp, "          <R_G_B>");
     297             :         else
     298          68 :             VSIFPrintfL(fp, "          <property name=\"%s\">", "R_G_B");
     299          68 :         if (poFeature->GetStyleString() != nullptr)
     300             :         {
     301             :             OGRwkbGeometryType eGeomType =
     302           3 :                 poGeom ? wkbFlatten(poGeom->getGeometryType()) : wkbUnknown;
     303           6 :             OGRStyleMgr oMgr;
     304           3 :             oMgr.InitFromFeature(poFeature);
     305           6 :             for (int i = 0; i < oMgr.GetPartCount(); i++)
     306             :             {
     307           3 :                 OGRStyleTool *poTool = oMgr.GetPart(i);
     308           3 :                 if (poTool != nullptr)
     309             :                 {
     310           3 :                     const char *pszColor = nullptr;
     311           5 :                     if (poTool->GetType() == OGRSTCPen &&
     312           5 :                         eGeomType != wkbPolygon && eGeomType != wkbMultiPolygon)
     313             :                     {
     314             :                         GBool bIsNull;
     315           2 :                         pszColor = ((OGRStylePen *)poTool)->Color(bIsNull);
     316           2 :                         if (bIsNull)
     317           0 :                             pszColor = nullptr;
     318             :                     }
     319           1 :                     else if (poTool->GetType() == OGRSTCBrush)
     320             :                     {
     321             :                         GBool bIsNull;
     322             :                         pszColor =
     323           1 :                             ((OGRStyleBrush *)poTool)->ForeColor(bIsNull);
     324           1 :                         if (bIsNull)
     325           0 :                             pszColor = nullptr;
     326             :                     }
     327             :                     int R, G, B, A;
     328           6 :                     if (pszColor != nullptr &&
     329           6 :                         poTool->GetRGBFromString(pszColor, R, G, B, A) &&
     330           3 :                         A != 0)
     331             :                     {
     332           3 :                         VSIFPrintfL(fp, "%02X%02X%02X", R, G, B);
     333             :                     }
     334           3 :                     delete poTool;
     335             :                 }
     336             :             }
     337             :         }
     338          68 :         if (bClassicGML)
     339           0 :             VSIFPrintfL(fp, "</R_G_B>\n");
     340             :         else
     341          68 :             VSIFPrintfL(fp, "</property>\n");
     342             :     }
     343             : 
     344          72 :     VSIFPrintfL(fp, "     </feature>\n");
     345          72 :     if (bClassicGML)
     346           0 :         VSIFPrintfL(fp, "   </featureMember>\n");
     347             : 
     348          72 :     poFeature->SetFID(nNextFID++);
     349             : 
     350          72 :     return OGRERR_NONE;
     351             : }
     352             : 
     353             : /************************************************************************/
     354             : /*                            CreateField()                             */
     355             : /************************************************************************/
     356             : 
     357          92 : OGRErr OGRJMLWriterLayer::CreateField(const OGRFieldDefn *poFieldDefn,
     358             :                                       int bApproxOK)
     359             : {
     360          92 :     if (bFeaturesWritten)
     361           1 :         return OGRERR_FAILURE;
     362             : 
     363          91 :     if (!bAddRGBField && strcmp(poFieldDefn->GetNameRef(), "R_G_B") == 0)
     364           0 :         return OGRERR_FAILURE;
     365             : 
     366          91 :     const char *pszType = nullptr;
     367          91 :     OGRFieldType eType = poFieldDefn->GetType();
     368          91 :     if (eType == OFTInteger)
     369             :     {
     370          17 :         pszType = "INTEGER";
     371             :     }
     372          74 :     else if (eType == OFTInteger64)
     373             :     {
     374           0 :         pszType = "OBJECT";
     375             :     }
     376          74 :     else if (eType == OFTReal)
     377             :     {
     378          17 :         pszType = "DOUBLE";
     379             :     }
     380          57 :     else if (eType == OFTDate || eType == OFTDateTime)
     381             :     {
     382          35 :         pszType = "DATE";
     383             :     }
     384             :     else
     385             :     {
     386          22 :         if (eType != OFTString)
     387             :         {
     388           1 :             if (bApproxOK)
     389             :             {
     390           1 :                 CPLError(
     391             :                     CE_Warning, CPLE_AppDefined,
     392             :                     "Field of type %s unhandled natively. Converting to string",
     393             :                     OGRFieldDefn::GetFieldTypeName(eType));
     394             :             }
     395             :             else
     396             :             {
     397           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     398             :                          "Field of type %s unhandled natively.",
     399             :                          OGRFieldDefn::GetFieldTypeName(eType));
     400           0 :                 return OGRERR_FAILURE;
     401             :             }
     402             :         }
     403          22 :         pszType = "STRING";
     404             :     }
     405          91 :     WriteColumnDeclaration(poFieldDefn->GetNameRef(), pszType);
     406             : 
     407          91 :     poFeatureDefn->AddFieldDefn(poFieldDefn);
     408          91 :     return OGRERR_NONE;
     409             : }
     410             : 
     411             : /************************************************************************/
     412             : /*                           TestCapability()                           */
     413             : /************************************************************************/
     414             : 
     415          79 : int OGRJMLWriterLayer::TestCapability(const char *pszCap)
     416             : 
     417             : {
     418          79 :     if (EQUAL(pszCap, OLCStringsAsUTF8))
     419           1 :         return TRUE;
     420          78 :     if (EQUAL(pszCap, OLCSequentialWrite))
     421          17 :         return TRUE;
     422          61 :     if (EQUAL(pszCap, OLCCreateField))
     423          18 :         return !bFeaturesWritten;
     424             : 
     425          43 :     return FALSE;
     426             : }
     427             : 
     428             : /************************************************************************/
     429             : /*                             GetDataset()                             */
     430             : /************************************************************************/
     431             : 
     432          17 : GDALDataset *OGRJMLWriterLayer::GetDataset()
     433             : {
     434          17 :     return poDS;
     435             : }

Generated by: LCOV version 1.14