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

Generated by: LCOV version 1.14