Line data Source code
1 : /********************************************************************** 2 : * 3 : * Project: GML Reader 4 : * Purpose: Implementation of GMLFeature. 5 : * Author: Frank Warmerdam, warmerdam@pobox.com 6 : * 7 : ********************************************************************** 8 : * Copyright (c) 2002, Frank Warmerdam 9 : * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com> 10 : * 11 : * SPDX-License-Identifier: MIT 12 : ****************************************************************************/ 13 : 14 : #include "cpl_port.h" 15 : #include "gmlfeature.h" 16 : 17 : #include <cstdio> 18 : 19 : #include "cpl_conv.h" 20 : #include "cpl_error.h" 21 : #include "cpl_minixml.h" 22 : #include "cpl_string.h" 23 : 24 : /************************************************************************/ 25 : /* GMLFeature() */ 26 : /************************************************************************/ 27 : 28 2487 : GMLFeature::GMLFeature(GMLFeatureClass *poClass) 29 : : m_poClass(poClass), m_pszFID(nullptr), m_nPropertyCount(0), 30 : m_pasProperties(nullptr), m_nGeometryCount(0), 31 2487 : m_papsGeometry(m_apsGeometry) // TODO(schwehr): Allowed in init list? 32 : { 33 2487 : m_apsGeometry[0] = nullptr; 34 2487 : m_apsGeometry[1] = nullptr; 35 2487 : } 36 : 37 : /************************************************************************/ 38 : /* ~GMLFeature() */ 39 : /************************************************************************/ 40 : 41 4974 : GMLFeature::~GMLFeature() 42 : 43 : { 44 2487 : CPLFree(m_pszFID); 45 : 46 9310 : for (int i = 0; i < m_nPropertyCount; i++) 47 : { 48 6823 : const int nSubProperties = m_pasProperties[i].nSubProperties; 49 6823 : if (nSubProperties == 1) 50 : { 51 6128 : CPLFree(m_pasProperties[i].aszSubProperties[0]); 52 : } 53 695 : else if (nSubProperties > 1) 54 : { 55 710 : for (int j = 0; j < nSubProperties; j++) 56 479 : CPLFree(m_pasProperties[i].papszSubProperties[j]); 57 231 : CPLFree(m_pasProperties[i].papszSubProperties); 58 : } 59 : } 60 : 61 2487 : if (m_nGeometryCount == 1) 62 : { 63 2242 : CPLDestroyXMLNode(m_apsGeometry[0]); 64 : } 65 245 : else if (m_nGeometryCount > 1) 66 : { 67 281 : for (int i = 0; i < m_nGeometryCount; i++) 68 192 : CPLDestroyXMLNode(m_papsGeometry[i]); 69 89 : CPLFree(m_papsGeometry); 70 : } 71 : 72 2487 : if (m_psBoundedByGeometry) 73 20 : CPLDestroyXMLNode(m_psBoundedByGeometry); 74 : 75 2487 : CPLFree(m_pasProperties); 76 2487 : } 77 : 78 : /************************************************************************/ 79 : /* SetFID() */ 80 : /************************************************************************/ 81 : 82 1453 : void GMLFeature::SetFID(const char *pszFID) 83 : 84 : { 85 1453 : CPLFree(m_pszFID); 86 1453 : if (pszFID != nullptr) 87 1453 : m_pszFID = CPLStrdup(pszFID); 88 : else 89 0 : m_pszFID = nullptr; 90 1453 : } 91 : 92 : /************************************************************************/ 93 : /* SetPropertyDirectly() */ 94 : /************************************************************************/ 95 : 96 6607 : void GMLFeature::SetPropertyDirectly(int iIndex, char *pszValue) 97 : 98 : { 99 6607 : CPLAssert(pszValue); 100 6607 : if (iIndex >= m_nPropertyCount) 101 : { 102 2582 : const int nClassPropertyCount = m_poClass->GetPropertyCount(); 103 5164 : m_pasProperties = static_cast<GMLProperty *>(CPLRealloc( 104 2582 : m_pasProperties, sizeof(GMLProperty) * nClassPropertyCount)); 105 4182 : for (int i = 0; i < m_nPropertyCount; i++) 106 : { 107 : // Make sure papszSubProperties point to the right address in case 108 : // m_pasProperties has been relocated. 109 1600 : if (m_pasProperties[i].nSubProperties <= 1) 110 1372 : m_pasProperties[i].papszSubProperties = 111 1372 : m_pasProperties[i].aszSubProperties; 112 : } 113 9405 : for (int i = m_nPropertyCount; i < nClassPropertyCount; i++) 114 : { 115 6823 : m_pasProperties[i].nSubProperties = 0; 116 6823 : m_pasProperties[i].papszSubProperties = 117 6823 : m_pasProperties[i].aszSubProperties; 118 6823 : m_pasProperties[i].aszSubProperties[0] = nullptr; 119 6823 : m_pasProperties[i].aszSubProperties[1] = nullptr; 120 : } 121 2582 : m_nPropertyCount = nClassPropertyCount; 122 : } 123 : 124 6607 : GMLProperty *psProperty = &m_pasProperties[iIndex]; 125 6607 : const int nSubProperties = psProperty->nSubProperties; 126 6607 : if (nSubProperties == 0) 127 : { 128 6359 : psProperty->aszSubProperties[0] = pszValue; 129 : } 130 248 : else if (nSubProperties == 1) 131 : { 132 231 : psProperty->papszSubProperties = static_cast<char **>( 133 231 : CPLMalloc(sizeof(char *) * (nSubProperties + 2))); 134 231 : psProperty->papszSubProperties[0] = psProperty->aszSubProperties[0]; 135 231 : psProperty->aszSubProperties[0] = nullptr; 136 231 : psProperty->papszSubProperties[nSubProperties] = pszValue; 137 231 : psProperty->papszSubProperties[nSubProperties + 1] = nullptr; 138 : } 139 : else 140 : { 141 17 : psProperty->papszSubProperties = static_cast<char **>( 142 34 : CPLRealloc(psProperty->papszSubProperties, 143 17 : sizeof(char *) * (nSubProperties + 2))); 144 17 : psProperty->papszSubProperties[nSubProperties] = pszValue; 145 17 : psProperty->papszSubProperties[nSubProperties + 1] = nullptr; 146 : } 147 6607 : psProperty->nSubProperties++; 148 6607 : } 149 : 150 : /************************************************************************/ 151 : /* Dump() */ 152 : /************************************************************************/ 153 : 154 0 : void GMLFeature::Dump(CPL_UNUSED FILE *fp) 155 : { 156 0 : printf("GMLFeature(%s):\n", m_poClass->GetName()); /*ok*/ 157 : 158 0 : if (m_pszFID != nullptr) 159 0 : printf(" FID = %s\n", m_pszFID); /*ok*/ 160 : 161 0 : for (int i = 0; i < m_nPropertyCount; i++) 162 : { 163 0 : const GMLProperty *psGMLProperty = GetProperty(i); 164 0 : printf(" %s = ", m_poClass->GetProperty(i)->GetName()); /*ok*/ 165 0 : if (psGMLProperty != nullptr) 166 : { 167 0 : for (int j = 0; j < psGMLProperty->nSubProperties; j++) 168 : { 169 0 : if (j > 0) 170 0 : printf(", "); /*ok*/ 171 0 : printf("%s", psGMLProperty->papszSubProperties[j]); /*ok*/ 172 : } 173 0 : printf("\n"); /*ok*/ 174 : } 175 : } 176 : 177 0 : for (int i = 0; i < m_nGeometryCount; i++) 178 : { 179 0 : char *pszXML = CPLSerializeXMLTree(m_papsGeometry[i]); 180 0 : printf(" %s\n", pszXML); /*ok*/ 181 0 : CPLFree(pszXML); 182 : } 183 0 : } 184 : 185 : /************************************************************************/ 186 : /* SetGeometryDirectly() */ 187 : /************************************************************************/ 188 : 189 2327 : void GMLFeature::SetGeometryDirectly(CPLXMLNode *psGeom) 190 : 191 : { 192 2327 : if (m_apsGeometry[0] != nullptr) 193 16 : CPLDestroyXMLNode(m_apsGeometry[0]); 194 2327 : m_nGeometryCount = 1; 195 2327 : m_apsGeometry[0] = psGeom; 196 2327 : } 197 : 198 : /************************************************************************/ 199 : /* SetGeometryDirectly() */ 200 : /************************************************************************/ 201 : 202 172 : void GMLFeature::SetGeometryDirectly(int nIdx, CPLXMLNode *psGeom) 203 : 204 : { 205 172 : if (nIdx == 0 && m_nGeometryCount <= 1) 206 : { 207 78 : SetGeometryDirectly(psGeom); 208 78 : return; 209 : } 210 94 : else if (nIdx > 0 && m_nGeometryCount <= 1) 211 : { 212 89 : m_papsGeometry = 213 89 : static_cast<CPLXMLNode **>(CPLMalloc(2 * sizeof(CPLXMLNode *))); 214 89 : m_papsGeometry[0] = m_apsGeometry[0]; 215 89 : m_papsGeometry[1] = nullptr; 216 89 : m_apsGeometry[0] = nullptr; 217 : } 218 : 219 94 : if (nIdx >= m_nGeometryCount) 220 : { 221 92 : m_papsGeometry = static_cast<CPLXMLNode **>( 222 92 : CPLRealloc(m_papsGeometry, (nIdx + 2) * sizeof(CPLXMLNode *))); 223 307 : for (int i = m_nGeometryCount; i <= nIdx + 1; i++) 224 215 : m_papsGeometry[i] = nullptr; 225 92 : m_nGeometryCount = nIdx + 1; 226 : } 227 94 : if (m_papsGeometry[nIdx] != nullptr) 228 0 : CPLDestroyXMLNode(m_papsGeometry[nIdx]); 229 94 : m_papsGeometry[nIdx] = psGeom; 230 : } 231 : 232 : /************************************************************************/ 233 : /* GetGeometryRef() */ 234 : /************************************************************************/ 235 : 236 2625 : const CPLXMLNode *GMLFeature::GetGeometryRef(int nIdx) const 237 : { 238 2625 : if (nIdx < 0 || nIdx >= m_nGeometryCount) 239 2420 : return nullptr; 240 205 : return m_papsGeometry[nIdx]; 241 : } 242 : 243 : /************************************************************************/ 244 : /* AddGeometry() */ 245 : /************************************************************************/ 246 : 247 0 : void GMLFeature::AddGeometry(CPLXMLNode *psGeom) 248 : 249 : { 250 0 : if (m_nGeometryCount == 0) 251 : { 252 0 : m_apsGeometry[0] = psGeom; 253 : } 254 0 : else if (m_nGeometryCount == 1) 255 : { 256 0 : m_papsGeometry = static_cast<CPLXMLNode **>( 257 0 : CPLMalloc((m_nGeometryCount + 2) * sizeof(CPLXMLNode *))); 258 0 : m_papsGeometry[0] = m_apsGeometry[0]; 259 0 : m_apsGeometry[0] = nullptr; 260 0 : m_papsGeometry[m_nGeometryCount] = psGeom; 261 0 : m_papsGeometry[m_nGeometryCount + 1] = nullptr; 262 : } 263 : else 264 : { 265 0 : m_papsGeometry = static_cast<CPLXMLNode **>(CPLRealloc( 266 0 : m_papsGeometry, (m_nGeometryCount + 2) * sizeof(CPLXMLNode *))); 267 0 : m_papsGeometry[m_nGeometryCount] = psGeom; 268 0 : m_papsGeometry[m_nGeometryCount + 1] = nullptr; 269 : } 270 0 : m_nGeometryCount++; 271 0 : } 272 : 273 : /************************************************************************/ 274 : /* SetBoundedByGeometry() */ 275 : /************************************************************************/ 276 : 277 20 : void GMLFeature::SetBoundedByGeometry(CPLXMLNode *psGeom) 278 : 279 : { 280 20 : if (m_psBoundedByGeometry) 281 0 : CPLDestroyXMLNode(m_psBoundedByGeometry); 282 20 : m_psBoundedByGeometry = psGeom; 283 20 : }