1 /******************************************************************************
2  *
3  * Project:  EDIGEO Translator
4  * Purpose:  Implements OGREDIGEODataSource class
5  * Author:   Even Rouault, even dot rouault at spatialys.com
6  *
7  ******************************************************************************
8  * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28 
29 #include "ogr_edigeo.h"
30 #include "cpl_conv.h"
31 #include "cpl_string.h"
32 
33 CPL_CVSID("$Id: ogredigeodatasource.cpp ac74af497ac5f6f08d69354dfcc93e79213c0ba4 2019-08-15 15:47:49 +0200 Even Rouault $")
34 
35 /************************************************************************/
36 /*                        OGREDIGEODataSource()                         */
37 /************************************************************************/
38 
OGREDIGEODataSource()39 OGREDIGEODataSource::OGREDIGEODataSource() :
40     pszName(nullptr),
41     fpTHF(nullptr),
42     papoLayers(nullptr),
43     nLayers(0),
44     poSRS(nullptr),
45     bExtentValid(FALSE),
46     dfMinX(0),
47     dfMinY(0),
48     dfMaxX(0),
49     dfMaxY(0),
50     bRecodeToUTF8(
51         CPLTestBool(CPLGetConfigOption("OGR_EDIGEO_RECODE_TO_UTF8", "YES"))),
52     bHasUTF8ContentOnly(TRUE),
53     iATR(-1),
54     iDI3(-1),
55     iDI4(-1),
56     iHEI(-1),
57     iFON(-1),
58     iATR_VAL(-1),
59     iANGLE(-1),
60     iSIZE(-1),
61     iOBJ_LNK(-1),
62     iOBJ_LNK_LAYER(-1),
63     // coverity[tainted_data]
64     dfSizeFactor(CPLAtof(
65         CPLGetConfigOption("OGR_EDIGEO_FONT_SIZE_FACTOR", "2"))),
66     bIncludeFontFamily(CPLTestBool(
67         CPLGetConfigOption("OGR_EDIGEO_INCLUDE_FONT_FAMILY", "YES"))),
68     bHasReadEDIGEO(FALSE)
69 {
70     if (dfSizeFactor <= 0 || dfSizeFactor >= 100)
71         dfSizeFactor = 2;
72 }
73 
74 /************************************************************************/
75 /*                      ~OGREDIGEODataSource()                          */
76 /************************************************************************/
77 
~OGREDIGEODataSource()78 OGREDIGEODataSource::~OGREDIGEODataSource()
79 
80 {
81     for( int i = 0; i < nLayers; i++ )
82         delete papoLayers[i];
83     CPLFree( papoLayers );
84 
85     CPLFree( pszName );
86 
87     if (fpTHF)
88         VSIFCloseL(fpTHF);
89 
90     if (poSRS)
91         poSRS->Release();
92 }
93 
94 /************************************************************************/
95 /*                           TestCapability()                           */
96 /************************************************************************/
97 
TestCapability(CPL_UNUSED const char * pszCap)98 int OGREDIGEODataSource::TestCapability( CPL_UNUSED const char * pszCap )
99 {
100     return FALSE;
101 }
102 
103 /************************************************************************/
104 /*                              GetLayer()                              */
105 /************************************************************************/
106 
GetLayer(int iLayer)107 OGRLayer *OGREDIGEODataSource::GetLayer( int iLayer )
108 
109 {
110     ReadEDIGEO();
111     if( iLayer < 0 || iLayer >= nLayers )
112         return nullptr;
113     else
114         return papoLayers[iLayer];
115 }
116 
117 /************************************************************************/
118 /*                         GetLayerCount()                              */
119 /************************************************************************/
120 
GetLayerCount()121 int OGREDIGEODataSource::GetLayerCount()
122 {
123     ReadEDIGEO();
124     return nLayers;
125 }
126 
127 /************************************************************************/
128 /*                              ReadTHF()                               */
129 /************************************************************************/
130 
ReadTHF(VSILFILE * fp)131 int OGREDIGEODataSource::ReadTHF(VSILFILE* fp)
132 {
133     const char* pszLine = nullptr;
134     while((pszLine = CPLReadLine2L(fp, 81, nullptr)) != nullptr)
135     {
136         if (strlen(pszLine) < 8 || pszLine[7] != ':')
137             continue;
138 
139         /* Cf Z 52000 tableau 56 for field list*/
140 
141         if (STARTS_WITH(pszLine, "LONSA"))
142         {
143             if (!osLON.empty())
144             {
145                 CPLDebug("EDIGEO", "We only handle one lot per THF file");
146                 break;
147             }
148             osLON = pszLine + 8;
149         }
150         else if (STARTS_WITH(pszLine, "GNNSA"))
151             osGNN = pszLine + 8;
152         else if (STARTS_WITH(pszLine, "GONSA"))
153             osGON = pszLine + 8;
154         else if (STARTS_WITH(pszLine, "QANSA"))
155             osQAN = pszLine + 8;
156         else if (STARTS_WITH(pszLine, "DINSA"))
157             osDIN = pszLine + 8;
158         else if (STARTS_WITH(pszLine, "SCNSA"))
159             osSCN = pszLine + 8;
160         else if (STARTS_WITH(pszLine, "GDNSA"))
161             aosGDN.push_back(pszLine + 8);
162     }
163     if (osLON.empty())
164     {
165         CPLDebug("EDIGEO", "LON field missing");
166         return 0;
167     }
168     if (osGON.empty())
169     {
170         CPLDebug("EDIGEO", "GON field missing");
171         return 0;
172     }
173     if (osDIN.empty())
174     {
175         CPLDebug("EDIGEO", "DIN field missing");
176         return 0;
177     }
178     if (osSCN.empty())
179     {
180         CPLDebug("EDIGEO", "SCN field missing");
181         return FALSE;
182     }
183 
184     CPLDebug("EDIGEO", "LON = %s", osLON.c_str());
185     CPLDebug("EDIGEO", "GNN = %s", osGNN.c_str());
186     CPLDebug("EDIGEO", "GON = %s", osGON.c_str());
187     CPLDebug("EDIGEO", "QAN = %s", osQAN.c_str());
188     CPLDebug("EDIGEO", "DIN = %s", osDIN.c_str());
189     CPLDebug("EDIGEO", "SCN = %s", osSCN.c_str());
190     for(int i=0;i<(int)aosGDN.size();i++)
191         CPLDebug("EDIGEO", "GDN[%d] = %s", i, aosGDN[i].c_str());
192 
193     return TRUE;
194 }
195 
196 /************************************************************************/
197 /*                             OpenFile()                               */
198 /************************************************************************/
199 
OpenFile(const char * pszType,const CPLString & osExt)200 VSILFILE* OGREDIGEODataSource::OpenFile(const char *pszType,
201                                         const CPLString& osExt)
202 {
203     CPLString osTmp = osLON + pszType;
204     CPLString osFilename = CPLFormCIFilename(CPLGetPath(pszName),
205                                              osTmp.c_str(), osExt.c_str());
206     VSILFILE* fp = VSIFOpenL(osFilename, "rb");
207     if (fp == nullptr)
208     {
209         CPLString osExtLower = osExt;
210         for(int i=0;i<(int)osExt.size();i++)
211             osExtLower[i] = (char)tolower(osExt[i]);
212         CPLString osFilename2 = CPLFormCIFilename(CPLGetPath(pszName),
213                                              osTmp.c_str(), osExtLower.c_str());
214         fp = VSIFOpenL(osFilename2, "rb");
215         if (fp == nullptr)
216         {
217             CPLDebug("EDIGEO", "Cannot open %s", osFilename.c_str());
218         }
219     }
220     return fp;
221 }
222 
223 /************************************************************************/
224 /*                              ReadGEO()                               */
225 /************************************************************************/
226 
ReadGEO()227 int OGREDIGEODataSource::ReadGEO()
228 {
229     VSILFILE* fp = OpenFile(osGON, "GEO");
230     if (fp == nullptr)
231         return FALSE;
232 
233     const char* pszLine = nullptr;
234     while( (pszLine = CPLReadLine2L(fp, 81, nullptr)) != nullptr )
235     {
236         if (strlen(pszLine) < 8 || pszLine[7] != ':')
237             continue;
238 
239         if (STARTS_WITH(pszLine, "RELSA"))
240         {
241             osREL = pszLine + 8;
242             CPLDebug("EDIGEO", "REL = %s", osREL.c_str());
243             break;
244         }
245     }
246 
247     VSIFCloseL(fp);
248 
249     if (osREL.empty())
250     {
251         CPLDebug("EDIGEO", "REL field missing");
252         return FALSE;
253     }
254 
255     /* All the SRS names mentioned in B.8.2.3 and B.8.3.1 are in the IGN file */
256     poSRS = new OGRSpatialReference();
257     poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
258     CPLString osProj4Str = "+init=IGNF:" + osREL;
259     if (poSRS->SetFromUserInput(osProj4Str.c_str()) != OGRERR_NONE)
260     {
261         /* Hard code a few common cases */
262         if (osREL == "LAMB1")
263             poSRS->importFromProj4("+proj=lcc +lat_1=49.5 +lat_0=49.5 +lon_0=0 +k_0=0.99987734 +x_0=600000 +y_0=200000 +a=6378249.2 +b=6356514.999978254 +nadgrids=ntf_r93.gsb,null +pm=paris +units=m +no_defs");
264         else if (osREL == "LAMB2")
265             poSRS->importFromProj4("+proj=lcc +lat_1=46.8 +lat_0=46.8 +lon_0=0 +k_0=0.99987742 +x_0=600000 +y_0=200000 +a=6378249.2 +b=6356514.999978254 +nadgrids=ntf_r93.gsb,null +pm=paris +units=m +no_defs");
266         else if (osREL == "LAMB3")
267             poSRS->importFromProj4("+proj=lcc +lat_1=44.1 +lat_0=44.1 +lon_0=0 +k_0=0.9998775 +x_0=600000 +y_0=200000 +a=6378249.2 +b=6356514.999978254 +nadgrids=ntf_r93.gsb,null +pm=paris +units=m +no_defs");
268         else if (osREL == "LAMB4")
269             poSRS->importFromProj4("+proj=lcc +lat_1=42.165 +lat_0=42.165 +lon_0=0 +k_0=0.99994471 +x_0=234.358 +y_0=185861.369 +a=6378249.2 +b=6356514.999978254 +nadgrids=ntf_r93.gsb,null +pm=paris +units=m +no_defs");
270         else if (osREL == "LAMB93")
271             poSRS->importFromProj4("+proj=lcc +lat_1=44 +lat_2=49 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS81 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs");
272         else
273         {
274             CPLDebug("EDIGEO", "Cannot resolve %s SRS. Check that the IGNF file is in the directory of PROJ.4 resource files", osREL.c_str());
275             delete poSRS;
276             poSRS = nullptr;
277         }
278     }
279 
280     return TRUE;
281 }
282 
283 /************************************************************************/
284 /*                              ReadGEN()                               */
285 /************************************************************************/
286 
ReadGEN()287 int OGREDIGEODataSource::ReadGEN()
288 {
289     VSILFILE* fp = OpenFile(osGNN, "GEN");
290     if (fp == nullptr)
291         return FALSE;
292 
293     const char* pszLine = nullptr;
294     CPLString osCM1;
295     CPLString osCM2;
296     while( (pszLine = CPLReadLine2L(fp, 81, nullptr)) != nullptr )
297     {
298         if (strlen(pszLine) < 8 || pszLine[7] != ':')
299             continue;
300 
301         if (STARTS_WITH(pszLine, "CM1CC"))
302         {
303             osCM1 = pszLine + 8;
304         }
305         else if (STARTS_WITH(pszLine, "CM2CC"))
306         {
307             osCM2 = pszLine + 8;
308         }
309     }
310 
311     VSIFCloseL(fp);
312 
313     if (osCM1.empty() || osCM2.empty())
314         return FALSE;
315 
316     char** papszTokens1 = CSLTokenizeString2(osCM1.c_str(), ";", 0);
317     char** papszTokens2 = CSLTokenizeString2(osCM2.c_str(), ";", 0);
318     if (CSLCount(papszTokens1) == 2 && CSLCount(papszTokens2) == 2)
319     {
320         bExtentValid = TRUE;
321         dfMinX = CPLAtof(papszTokens1[0]);
322         dfMinY = CPLAtof(papszTokens1[1]);
323         dfMaxX = CPLAtof(papszTokens2[0]);
324         dfMaxY = CPLAtof(papszTokens2[1]);
325     }
326     CSLDestroy(papszTokens1);
327     CSLDestroy(papszTokens2);
328 
329     return bExtentValid;
330 }
331 
332 /************************************************************************/
333 /*                              ReadDIC()                               */
334 /************************************************************************/
335 
ReadDIC()336 int OGREDIGEODataSource::ReadDIC()
337 {
338     VSILFILE* fp = OpenFile(osDIN, "DIC");
339     if (fp == nullptr)
340         return FALSE;
341 
342     const char* pszLine = nullptr;
343     CPLString osRTY;
344     CPLString osRID;
345     CPLString osLAB;
346     CPLString osTYP;
347     while( true )
348     {
349         pszLine = CPLReadLine2L(fp, 81, nullptr);
350         if (pszLine != nullptr)
351         {
352             if (strlen(pszLine) < 8 || pszLine[7] != ':')
353                 continue;
354         }
355 
356         if (pszLine == nullptr || STARTS_WITH(pszLine, "RTYSA"))
357         {
358             if (osRTY == "DID")
359             {
360                 //CPLDebug("EDIGEO", "Object %s = %s",
361                 //         osRID.c_str(), osLAB.c_str());
362                 mapObjects[osRID] = osLAB;
363             }
364             else if (osRTY == "DIA")
365             {
366                 //CPLDebug("EDIGEO", "Attribute %s = %s, %s",
367                 //         osRID.c_str(), osLAB.c_str(), osTYP.c_str());
368                 OGREDIGEOAttributeDef sAttributeDef;
369                 sAttributeDef.osLAB = osLAB;
370                 sAttributeDef.osTYP = osTYP;
371                 mapAttributes[osRID] = sAttributeDef;
372             }
373         }
374 
375         if (pszLine == nullptr)
376             break;
377 
378         if( STARTS_WITH(pszLine, "RTYSA") )
379         {
380             osRTY = pszLine + 8;
381             osRID = "";
382             osLAB = "";
383             osTYP = "";
384         }
385         else if (STARTS_WITH(pszLine, "RIDSA"))
386             osRID = pszLine + 8;
387         else if (STARTS_WITH(pszLine, "LABSA"))
388             osLAB = pszLine + 8;
389         else if (STARTS_WITH(pszLine, "TYPSA"))
390             osTYP = pszLine + 8;
391     }
392 
393     VSIFCloseL(fp);
394 
395     return TRUE;
396 }
397 
398 /************************************************************************/
399 /*                              ReadSCD()                               */
400 /************************************************************************/
401 
ReadSCD()402 int OGREDIGEODataSource::ReadSCD()
403 {
404     VSILFILE* fp = OpenFile(osSCN, "SCD");
405     if (fp == nullptr)
406         return FALSE;
407 
408     const char* pszLine = nullptr;
409     CPLString osRTY, osRID, osNameRID, osKND;
410     strListType aosAttrRID;
411     int nWidth = 0;
412     while( true )
413     {
414         pszLine = CPLReadLine2L(fp, 81, nullptr);
415         if (pszLine != nullptr)
416         {
417             if (strlen(pszLine) < 8 || pszLine[7] != ':')
418                 continue;
419         }
420 
421         if (pszLine == nullptr || STARTS_WITH(pszLine, "RTYSA"))
422         {
423             if (osRTY == "OBJ")
424             {
425                 if (mapObjects.find(osNameRID) == mapObjects.end())
426                 {
427                     CPLDebug("EDIGEO", "Cannot find object %s",
428                              osNameRID.c_str());
429                 }
430                 else
431                 {
432                     OGREDIGEOObjectDescriptor objDesc;
433                     objDesc.osRID = osRID;
434                     objDesc.osNameRID = osNameRID;
435                     objDesc.osKND = osKND;
436                     objDesc.aosAttrRID = aosAttrRID;
437                     /*CPLDebug("EDIGEO", "Object %s = %s, %s, %d attributes",
438                             osRID.c_str(), osNameRID.c_str(), osKND.c_str(),
439                             (int)aosAttrRID.size());*/
440 
441                     aoObjList.push_back(objDesc);
442                 }
443             }
444             else if (osRTY == "ATT")
445             {
446                 if (mapAttributes.find(osNameRID) == mapAttributes.end())
447                 {
448                     CPLDebug("EDIGEO", "Cannot find attribute %s",
449                              osNameRID.c_str());
450                 }
451                 else
452                 {
453                     OGREDIGEOAttributeDescriptor attDesc;
454                     attDesc.osRID = osRID;
455                     attDesc.osNameRID = osNameRID;
456                     attDesc.nWidth = nWidth;
457                     /*CPLDebug("EDIGEO", "Attribute %s = %s, %d",
458                             osRID.c_str(), osNameRID.c_str(), nWidth);*/
459 
460                     mapAttributesSCD[osRID] = attDesc;
461                 }
462             }
463         }
464 
465         if (pszLine == nullptr)
466             break;
467         if (STARTS_WITH(pszLine, "RTYSA"))
468         {
469             osRTY = pszLine + 8;
470             osRID = "";
471             osNameRID = "";
472             osKND = "";
473             aosAttrRID.resize(0);
474             nWidth = 0;
475         }
476         else if (STARTS_WITH(pszLine, "RIDSA"))
477             osRID = pszLine + 8;
478         else if (STARTS_WITH(pszLine, "DIPCP"))
479         {
480             const char* pszDIP = pszLine + 8;
481             char** papszTokens = CSLTokenizeString2(pszDIP, ";", 0);
482             if (CSLCount(papszTokens) == 4)
483             {
484                 osNameRID = papszTokens[3];
485             }
486             CSLDestroy(papszTokens);
487         }
488         else if (STARTS_WITH(pszLine, "KNDSA"))
489             osKND = pszLine + 8;
490         else if (STARTS_WITH(pszLine, "AAPCP"))
491         {
492             const char* pszAAP = pszLine + 8;
493             char** papszTokens = CSLTokenizeString2(pszAAP, ";", 0);
494             if (CSLCount(papszTokens) == 4)
495             {
496                 const char* pszAttRID = papszTokens[3];
497                 aosAttrRID.push_back(pszAttRID);
498             }
499             CSLDestroy(papszTokens);
500         }
501         else if (STARTS_WITH(pszLine, "CANSN"))
502             nWidth = atoi(pszLine + 8);
503     }
504 
505     VSIFCloseL(fp);
506 
507     return TRUE;
508 }
509 
510 /************************************************************************/
511 /*                              ReadQAL()                               */
512 /************************************************************************/
513 
ReadQAL()514 int OGREDIGEODataSource::ReadQAL()
515 {
516     VSILFILE* fp = OpenFile(osQAN, "QAL");
517     if (fp == nullptr)
518         return FALSE;
519 
520     const char* pszLine = nullptr;
521     CPLString osRTY;
522     CPLString osRID;
523     int nODA = 0;
524     int nUDA = 0;
525     while( true )
526     {
527         pszLine = CPLReadLine2L(fp, 81, nullptr);
528         if (pszLine != nullptr)
529         {
530             if (strlen(pszLine) < 8 || pszLine[7] != ':')
531                 continue;
532         }
533 
534         if (pszLine == nullptr || STARTS_WITH(pszLine, "RTYSA"))
535         {
536             if (osRTY == "QUP")
537             {
538                 mapQAL[osRID] = intintType(nODA, nUDA);
539             }
540             if (pszLine == nullptr)
541                 break;
542             osRTY = pszLine + 8;
543             osRID = "";
544             nODA = 0;
545             nUDA = 0;
546         }
547         else if (STARTS_WITH(pszLine, "RIDSA"))
548             osRID = pszLine + 8;
549         else if (STARTS_WITH(pszLine, "ODASD"))
550             nODA = atoi(pszLine + 8);
551         else if (STARTS_WITH(pszLine, "UDASD"))
552             nUDA = atoi(pszLine + 8);
553     }
554 
555     VSIFCloseL(fp);
556 
557     return TRUE;
558 }
559 
560 /************************************************************************/
561 /*                       CreateLayerFromObjectDesc()                    */
562 /************************************************************************/
563 
CreateLayerFromObjectDesc(const OGREDIGEOObjectDescriptor & objDesc)564 int OGREDIGEODataSource::CreateLayerFromObjectDesc(const OGREDIGEOObjectDescriptor& objDesc)
565 {
566     OGRwkbGeometryType eType = wkbUnknown;
567     if (objDesc.osKND == "ARE")
568         eType = wkbPolygon;
569     else if (objDesc.osKND == "LIN")
570         eType = wkbLineString;
571     else if (objDesc.osKND == "PCT")
572         eType = wkbPoint;
573     else
574     {
575         CPLDebug("EDIGEO", "Unknown KND : %s", objDesc.osKND.c_str());
576         return FALSE;
577     }
578 
579     const char* pszLayerName = objDesc.osRID.c_str();
580         //mapObjects.find(objDesc.osNameRID)->second.c_str();
581     OGREDIGEOLayer* poLayer = new OGREDIGEOLayer(this, pszLayerName,
582                                                     eType, poSRS);
583 
584     poLayer->AddFieldDefn("OBJECT_RID", OFTString, "");
585 
586     for(int j=0;j<(int)objDesc.aosAttrRID.size();j++)
587     {
588         std::map<CPLString,OGREDIGEOAttributeDescriptor>::iterator it =
589             mapAttributesSCD.find(objDesc.aosAttrRID[j]);
590         if (it != mapAttributesSCD.end())
591         {
592             const OGREDIGEOAttributeDescriptor& attrDesc = it->second;
593             const OGREDIGEOAttributeDef& attrDef =
594                                     mapAttributes[attrDesc.osNameRID];
595             OGRFieldType eFieldType = OFTString;
596             if (attrDef.osTYP == "R" || attrDef.osTYP == "E")
597                 eFieldType = OFTReal;
598             else if (attrDef.osTYP == "I" || attrDef.osTYP == "N")
599                 eFieldType = OFTInteger;
600 
601             poLayer->AddFieldDefn(attrDef.osLAB, eFieldType, objDesc.aosAttrRID[j]);
602         }
603     }
604 
605     if (strcmp(poLayer->GetName(), "ID_S_OBJ_Z_1_2_2") == 0)
606     {
607         OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
608 
609         iATR = poFDefn->GetFieldIndex("ATR");
610         iDI3 = poFDefn->GetFieldIndex("DI3");
611         iDI4 = poFDefn->GetFieldIndex("DI4");
612         iHEI = poFDefn->GetFieldIndex("HEI");
613         iFON = poFDefn->GetFieldIndex("FON");
614 
615         poLayer->AddFieldDefn("OGR_OBJ_LNK", OFTString, "");
616         iOBJ_LNK = poFDefn->GetFieldIndex("OGR_OBJ_LNK");
617 
618         poLayer->AddFieldDefn("OGR_OBJ_LNK_LAYER", OFTString, "");
619         iOBJ_LNK_LAYER = poFDefn->GetFieldIndex("OGR_OBJ_LNK_LAYER");
620 
621         poLayer->AddFieldDefn("OGR_ATR_VAL", OFTString, "");
622         iATR_VAL = poFDefn->GetFieldIndex("OGR_ATR_VAL");
623 
624         poLayer->AddFieldDefn("OGR_ANGLE", OFTReal, "");
625         iANGLE = poFDefn->GetFieldIndex("OGR_ANGLE");
626 
627         poLayer->AddFieldDefn("OGR_FONT_SIZE", OFTReal, "");
628         iSIZE = poFDefn->GetFieldIndex("OGR_FONT_SIZE");
629     }
630     else if (!mapQAL.empty())
631     {
632         poLayer->AddFieldDefn("CREAT_DATE", OFTInteger, "");
633         poLayer->AddFieldDefn("UPDATE_DATE", OFTInteger, "");
634     }
635 
636     mapLayer[objDesc.osRID] = poLayer;
637 
638     papoLayers = (OGRLayer**)
639         CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
640     papoLayers[nLayers] = poLayer;
641     nLayers ++;
642 
643     return TRUE;
644 }
645 
646 /************************************************************************/
647 /*                              ReadVEC()                               */
648 /************************************************************************/
649 
ReadVEC(const char * pszVECName)650 int OGREDIGEODataSource::ReadVEC(const char* pszVECName)
651 {
652     VSILFILE* fp = OpenFile(pszVECName, "VEC");
653     if (fp == nullptr)
654         return FALSE;
655 
656     const char* pszLine = nullptr;
657     CPLString osRTY, osRID;
658     xyPairListType aXY;
659     CPLString osLnkStartType, osLnkStartName, osLnkEndType, osLnkEndName;
660     strListType osLnkEndNameList;
661     CPLString osAttId;
662     std::vector< strstrType > aosAttIdVal;
663     CPLString osSCP;
664     CPLString osQUP_RID;
665     int bIso8859_1 = FALSE;
666 
667     while( true )
668     {
669         pszLine = CPLReadLine2L(fp, 81, nullptr);
670 skip_read_next_line:
671         if (pszLine != nullptr)
672         {
673             if (strlen(pszLine) < 8 || pszLine[7] != ':')
674                 continue;
675         }
676 
677         if (pszLine == nullptr || STARTS_WITH(pszLine, "RTYSA"))
678         {
679             if (osRTY == "PAR")
680             {
681                 if (aXY.size() < 2)
682                     CPLDebug("EDIGEO", "Error: ARC %s has not enough points",
683                                     osRID.c_str());
684                 else
685                     mapPAR[osRID] = aXY;
686             }
687             else if (osRTY == "LNK")
688             {
689                 if (osLnkStartType == "PAR" && osLnkEndType == "PFE")
690                 {
691                     /*CPLDebug("EDIGEO", "PFE[%s] -> PAR[%s]",
692                              osLnkEndName.c_str(), osLnkStartName.c_str());*/
693                     if (mapPFE_PAR.find(osLnkEndName) == mapPFE_PAR.end())
694                         mapPFE_PAR[osLnkEndName].push_back(osLnkStartName);
695                     else
696                     {
697                         int bAlreadyExists = FALSE;
698                         strListType& osPARList = mapPFE_PAR[osLnkEndName];
699                         for(int j=0;j<(int)osPARList.size();j++)
700                         {
701                             if (osPARList[j] == osLnkStartName)
702                                 bAlreadyExists = TRUE;
703                         }
704                         if (!bAlreadyExists)
705                             osPARList.push_back(osLnkStartName);
706                     }
707                 }
708                 else if (osLnkStartType == "FEA" && osLnkEndType == "PFE")
709                 {
710                     /*CPLDebug("EDIGEO", "FEA[%s] -> PFE[%s]",
711                              osLnkStartName.c_str(), osLnkEndName.c_str());*/
712                     listFEA_PFE.push_back(std::pair<CPLString, strListType >
713                                                 (osLnkStartName, osLnkEndNameList));
714                 }
715                 else if (osLnkStartType == "FEA" && osLnkEndType == "PAR")
716                 {
717                     /*CPLDebug("EDIGEO", "FEA[%s] -> PAR[%s]",
718                              osLnkStartName.c_str(), osLnkEndName.c_str());*/
719                     listFEA_PAR.push_back(std::pair<CPLString, strListType >
720                                                 (osLnkStartName, osLnkEndNameList));
721                 }
722                 else if (osLnkStartType == "FEA" && osLnkEndType == "PNO")
723                 {
724                     /*CPLDebug("EDIGEO", "FEA[%s] -> PNO[%s]",
725                              osLnkStartName.c_str(), osLnkEndName.c_str());*/
726                     listFEA_PNO.push_back(strstrType
727                                                 (osLnkStartName, osLnkEndName));
728                 }
729                 else if (osLnkStartType == "FEA" && osLnkEndType == "FEA")
730                 {
731                     /*CPLDebug("EDIGEO", "FEA[%s] -> FEA[%s]",
732                              osLnkStartName.c_str(), osLnkEndName.c_str());*/
733                     if (osSCP == "IS_S_REL_IWW")
734                         mapFEA_FEA[osLnkStartName] = osLnkEndName;
735                 }
736                 else if (osLnkStartType == "PAR" && osLnkEndType == "PNO")
737                 {
738                 }
739                 else
740                 {
741                     CPLDebug("EDIGEO", "Unhandled LNK(%s) %s=%s --> %s=%s",
742                              osRID.c_str(),
743                              osLnkStartType.c_str(), osLnkStartName.c_str(),
744                              osLnkEndType.c_str(), osLnkEndName.c_str());
745                 }
746             }
747             else if (osRTY == "FEA")
748             {
749                 OGREDIGEOFEADesc feaDesc;
750                 feaDesc.aosAttIdVal = aosAttIdVal;
751                 feaDesc.osSCP = osSCP;
752                 feaDesc.osQUP_RID = osQUP_RID;
753                 mapFEA[osRID] = feaDesc;
754             }
755             else if (osRTY == "PNO")
756             {
757                 if (aXY.size() == 1)
758                 {
759                     /*CPLDebug("EDIGEO", "PNO[%s] = %f, %f",
760                              osRID.c_str(), aXY[0].first, aXY[0].second);*/
761                     mapPNO[osRID] = aXY[0];
762                 }
763             }
764             if (pszLine == nullptr)
765                 break;
766             osRTY = pszLine + 8;
767             osRID = "";
768             aXY.resize(0);
769             osLnkStartType = "";
770             osLnkStartName = "";
771             osLnkEndType = "";
772             osLnkEndName = "";
773             osAttId = "";
774             aosAttIdVal.resize(0);
775             osLnkEndNameList.resize(0);
776             osSCP = "";
777             osQUP_RID = "";
778             bIso8859_1 = FALSE;
779         }
780         else if (STARTS_WITH(pszLine, "RIDSA"))
781             osRID = pszLine + 8;
782         else if (STARTS_WITH(pszLine, "CORCC"))
783         {
784             const char* pszY = strchr(pszLine+8, ';');
785             if (pszY)
786             {
787                 double dfX = CPLAtof(pszLine + 8);
788                 double dfY = CPLAtof(pszY + 1);
789                 aXY.push_back(xyPairType (dfX, dfY));
790             }
791         }
792         else if (STARTS_WITH(pszLine, "FTPCP"))
793         {
794             char** papszTokens = CSLTokenizeString2(pszLine + 8, ";", 0);
795             if (CSLCount(papszTokens) == 4)
796             {
797                 if (osLnkStartType.empty())
798                 {
799                     osLnkStartType = papszTokens[2];
800                     osLnkStartName = papszTokens[3];
801                 }
802                 else
803                 {
804                     osLnkEndType = papszTokens[2];
805                     osLnkEndName = papszTokens[3];
806                     osLnkEndNameList.push_back(osLnkEndName);
807                 }
808             }
809             CSLDestroy(papszTokens);
810         }
811         else if (STARTS_WITH(pszLine, "SCPCP"))
812         {
813             char** papszTokens = CSLTokenizeString2(pszLine + 8, ";", 0);
814             if (CSLCount(papszTokens) == 4)
815             {
816                 if (osRTY == "LNK")
817                 {
818                     if (strcmp(papszTokens[2], "ASS") == 0)
819                         osSCP = papszTokens[3];
820                 }
821                 else if (strcmp(papszTokens[2], "OBJ") == 0)
822                     osSCP = papszTokens[3];
823             }
824             CSLDestroy(papszTokens);
825         }
826         else if (STARTS_WITH(pszLine, "ATPCP"))
827         {
828             char** papszTokens = CSLTokenizeString2(pszLine + 8, ";", 0);
829             if (CSLCount(papszTokens) == 4)
830             {
831                 if (strcmp(papszTokens[2], "ATT") == 0)
832                     osAttId = papszTokens[3];
833             }
834             CSLDestroy(papszTokens);
835         }
836         else if (strcmp(pszLine, "TEXT 06:8859-1") == 0)
837         {
838             bIso8859_1 = TRUE;
839         }
840         else if (STARTS_WITH(pszLine, "ATVS"))
841         {
842             CPLString osAttVal = pszLine + 8;
843             while( true )
844             {
845                 pszLine = CPLReadLine2L(fp, 81, nullptr);
846                 if (pszLine != nullptr &&
847                     strlen(pszLine) >= 8 &&
848                     pszLine[7] == ':' &&
849                     STARTS_WITH(pszLine, "NEXT "))
850                 {
851                     osAttVal += pszLine + 8;
852                 }
853                 else
854                 {
855                     break;
856                 }
857             }
858             if (bIso8859_1 && bRecodeToUTF8)
859             {
860                 char* pszNewVal = CPLRecode(osAttVal.c_str(),
861                                             CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
862                 osAttVal = pszNewVal;
863                 CPLFree(pszNewVal);
864             }
865             else if (bHasUTF8ContentOnly)
866             {
867                 bHasUTF8ContentOnly = CPLIsUTF8(osAttVal.c_str(), -1);
868             }
869             if (!osAttId.empty())
870                 aosAttIdVal.push_back( strstrType (osAttId, osAttVal) );
871             osAttId = "";
872             bIso8859_1 = FALSE;
873             goto skip_read_next_line;
874         }
875         else if (STARTS_WITH(pszLine, "ATVCP"))
876         {
877             char** papszTokens = CSLTokenizeString2(pszLine + 8, ";", 0);
878             if (CSLCount(papszTokens) == 4)
879             {
880                 if (strcmp(papszTokens[2], "ATT") == 0)
881                 {
882                     CPLString osAttVal = papszTokens[3];
883                     if (!osAttId.empty())
884                         aosAttIdVal.push_back( strstrType (osAttId, osAttVal) );
885                     osAttId = "";
886                 }
887             }
888             CSLDestroy(papszTokens);
889         }
890         else if (STARTS_WITH(pszLine, "QAPCP"))
891         {
892             char** papszTokens = CSLTokenizeString2(pszLine + 8, ";", 0);
893             if (CSLCount(papszTokens) == 4)
894             {
895                 if (strcmp(papszTokens[2], "QUP") == 0)
896                 {
897                     osQUP_RID = papszTokens[3];
898                 }
899             }
900             CSLDestroy(papszTokens);
901         }
902     }
903 
904     VSIFCloseL(fp);
905 
906     return TRUE;
907 }
908 
909 /************************************************************************/
910 /*                        CreateFeature()                               */
911 /************************************************************************/
912 
CreateFeature(const CPLString & osFEA)913 OGRFeature* OGREDIGEODataSource::CreateFeature(const CPLString& osFEA)
914 {
915     const std::map< CPLString, OGREDIGEOFEADesc >::iterator itFEA =
916                                                         mapFEA.find(osFEA);
917     if (itFEA == mapFEA.end())
918     {
919         CPLDebug("EDIGEO", "ERROR: Cannot find FEA %s", osFEA.c_str());
920         return nullptr;
921     }
922 
923     const OGREDIGEOFEADesc& fea = itFEA->second;
924     const std::map<CPLString,OGREDIGEOLayer*>::iterator itLyr =
925                                                     mapLayer.find(fea.osSCP);
926     if (itLyr != mapLayer.end())
927     {
928         OGREDIGEOLayer* poLayer = itLyr->second;
929 
930         OGRFeature* poFeature = new OGRFeature(poLayer->GetLayerDefn());
931         poFeature->SetField(0, itFEA->first.c_str());
932         for(int i=0;i<(int)fea.aosAttIdVal.size();i++)
933         {
934             const CPLString& id = fea.aosAttIdVal[i].first;
935             const CPLString& val = fea.aosAttIdVal[i].second;
936             int iIndex = poLayer->GetAttributeIndex(id);
937             if (iIndex != -1)
938                 poFeature->SetField(iIndex, val.c_str());
939             else
940                 CPLDebug("EDIGEO",
941                          "ERROR: Cannot find attribute %s", id.c_str());
942         }
943 
944         if (strcmp(poLayer->GetName(), "ID_S_OBJ_Z_1_2_2") != 0 &&
945             !mapQAL.empty() && !fea.osQUP_RID.empty())
946         {
947             const std::map<CPLString, intintType>::iterator itQAL =
948                                                         mapQAL.find(fea.osQUP_RID);
949             if (itQAL != mapQAL.end())
950             {
951                 const intintType& creationUpdateDate = itQAL->second;
952                 if (creationUpdateDate.first != 0)
953                     poFeature->SetField("CREAT_DATE", creationUpdateDate.first);
954                 if (creationUpdateDate.second != 0)
955                     poFeature->SetField("UPDATE_DATE", creationUpdateDate.second);
956             }
957         }
958 
959         poLayer->AddFeature(poFeature);
960 
961         return poFeature;
962     }
963     else
964     {
965         CPLDebug("EDIGEO", "ERROR: Cannot find layer %s", fea.osSCP.c_str());
966         return nullptr;
967     }
968 }
969 
970 /************************************************************************/
971 /*                             SetStyle()                               */
972 /************************************************************************/
973 
SetStyle(const CPLString & osFEA,OGRFeature * poFeature)974 int OGREDIGEODataSource::SetStyle(const CPLString& osFEA,
975                                   OGRFeature* poFeature)
976 {
977     /* EDIGEO PCI specific */
978     /* See EDIGeO_PCI.pdf, chapter 3 "Principes généraux de */
979     /* positionnement de la toponymie. */
980     const char* pszATR = nullptr;
981     if (strcmp(poFeature->GetDefnRef()->GetName(), "ID_S_OBJ_Z_1_2_2") == 0 &&
982         iATR != -1 && (pszATR = poFeature->GetFieldAsString(iATR)) != nullptr)
983     {
984         const CPLString osATR = pszATR;
985         std::map< CPLString, CPLString>::iterator itFEA_FEA =
986                                                 mapFEA_FEA.find(osFEA);
987         if (itFEA_FEA != mapFEA_FEA.end())
988         {
989             const CPLString& osOBJ_LNK = itFEA_FEA->second;
990             std::map< CPLString, OGREDIGEOFEADesc >::iterator itFEA_LNK =
991                                                         mapFEA.find(osOBJ_LNK);
992             if (itFEA_LNK != mapFEA.end())
993             {
994                 const OGREDIGEOFEADesc& fea_lnk = itFEA_LNK->second;
995                 for(int j=0;j<(int)fea_lnk.aosAttIdVal.size();j++)
996                 {
997                     if (fea_lnk.aosAttIdVal[j].first == osATR)
998                     {
999                         double dfAngle = 0;
1000                         if (iDI3 != -1 && iDI4 != -1)
1001                         {
1002                             double dfBaseVectorX =
1003                                 poFeature->GetFieldAsDouble(iDI3);
1004                             double dfBaseVectorY =
1005                                 poFeature->GetFieldAsDouble(iDI4);
1006                             dfAngle = atan2(dfBaseVectorY, dfBaseVectorX)
1007                                                                 / M_PI * 180;
1008                             if (dfAngle < 0)
1009                                 dfAngle += 360;
1010                         }
1011                         double dfSize = 1;
1012                         if (iHEI != -1)
1013                             dfSize = poFeature->GetFieldAsDouble(iHEI);
1014                         if (dfSize <= 0 || dfSize >= 100)
1015                             dfSize = 1;
1016                         const char* pszFontFamily = nullptr;
1017                         if (iFON != -1)
1018                             pszFontFamily = poFeature->GetFieldAsString(iFON);
1019 
1020                         CPLString osStyle("LABEL(t:\"");
1021                         osStyle += fea_lnk.aosAttIdVal[j].second;
1022                         osStyle += "\"";
1023                         if (dfAngle != 0)
1024                         {
1025                             osStyle += ",a:";
1026                             osStyle += CPLString().Printf("%.1f", dfAngle);
1027                         }
1028                         if (pszFontFamily != nullptr && bIncludeFontFamily)
1029                         {
1030                             osStyle += ",f:\"";
1031                             osStyle += pszFontFamily;
1032                             osStyle += "\"";
1033                         }
1034                         osStyle += ",s:";
1035                         osStyle += CPLString().Printf("%.1f", dfSize);
1036                         osStyle += ",c:#000000)";
1037                         poFeature->SetStyleString(osStyle);
1038 
1039                         poFeature->SetField(iATR_VAL,
1040                                             fea_lnk.aosAttIdVal[j].second);
1041                         poFeature->SetField(iANGLE, dfAngle);
1042                         poFeature->SetField(iSIZE, dfSize * dfSizeFactor);
1043                         poFeature->SetField(iOBJ_LNK, osOBJ_LNK);
1044                         poFeature->SetField(iOBJ_LNK_LAYER, fea_lnk.osSCP);
1045 
1046                         setLayersWithLabels.insert(fea_lnk.osSCP);
1047 
1048                         break;
1049                     }
1050                 }
1051             }
1052         }
1053     }
1054 
1055     return TRUE;
1056 }
1057 
1058 /************************************************************************/
1059 /*                           BuildPoints()                              */
1060 /************************************************************************/
1061 
BuildPoints()1062 int OGREDIGEODataSource::BuildPoints()
1063 {
1064     for(int i=0;i<(int)listFEA_PNO.size();i++)
1065     {
1066         const CPLString& osFEA = listFEA_PNO[i].first;
1067         const CPLString& osPNO = listFEA_PNO[i].second;
1068         const std::map< CPLString, xyPairType >::iterator itPNO =
1069                                                         mapPNO.find(osPNO);
1070         if (itPNO == mapPNO.end())
1071         {
1072             CPLDebug("EDIGEO", "Cannot find PNO %s", osPNO.c_str());
1073         }
1074         else
1075         {
1076             OGRFeature* poFeature = CreateFeature(osFEA);
1077             if (poFeature)
1078             {
1079                 const xyPairType& pno = itPNO->second;
1080                 OGRPoint* poPoint = new OGRPoint(pno.first, pno.second);
1081                 if (poSRS)
1082                     poPoint->assignSpatialReference(poSRS);
1083                 poFeature->SetGeometryDirectly(poPoint);
1084 
1085                 SetStyle(osFEA, poFeature);
1086             }
1087         }
1088     }
1089 
1090     return TRUE;
1091 }
1092 
1093 /************************************************************************/
1094 /*                        BuildLineStrings()                            */
1095 /************************************************************************/
1096 
BuildLineStrings()1097 int OGREDIGEODataSource::BuildLineStrings()
1098 {
1099     int i, iter;
1100 
1101     for(iter=0;iter<(int)listFEA_PAR.size();iter++)
1102     {
1103         const CPLString& osFEA = listFEA_PAR[iter].first;
1104         const strListType & aosPAR = listFEA_PAR[iter].second;
1105         OGRFeature* poFeature = CreateFeature(osFEA);
1106         if (poFeature)
1107         {
1108             OGRGeometry* poGeom = nullptr;
1109             OGRMultiLineString* poMulti = nullptr;
1110             for(int k=0;k<(int)aosPAR.size();k++)
1111             {
1112                 const std::map< CPLString, xyPairListType >::iterator itPAR =
1113                                                     mapPAR.find(aosPAR[k]);
1114                 if (itPAR != mapPAR.end())
1115                 {
1116                     const xyPairListType& arc = itPAR->second;
1117 
1118                     OGRLineString* poLS = new OGRLineString();
1119                     poLS->setNumPoints((int)arc.size());
1120                     for(i=0;i<(int)arc.size();i++)
1121                     {
1122                         poLS->setPoint(i, arc[i].first, arc[i].second);
1123                     }
1124 
1125                     if (poGeom != nullptr)
1126                     {
1127                         if (poMulti == nullptr)
1128                         {
1129                             poMulti = new OGRMultiLineString();
1130                             poMulti->addGeometryDirectly(poGeom);
1131                             poGeom = poMulti;
1132                         }
1133                         poMulti->addGeometryDirectly(poLS);
1134                     }
1135                     else
1136                         poGeom = poLS;
1137                 }
1138                 else
1139                     CPLDebug("EDIGEO",
1140                              "ERROR: Cannot find ARC %s", aosPAR[k].c_str());
1141             }
1142             if( poGeom != nullptr )
1143             {
1144                 poGeom->assignSpatialReference(poSRS);
1145                 poFeature->SetGeometryDirectly(poGeom);
1146             }
1147         }
1148     }
1149 
1150     return TRUE;
1151 }
1152 
1153 /************************************************************************/
1154 /*                           BuildPolygon()                             */
1155 /************************************************************************/
1156 
BuildPolygon(const CPLString & osFEA,const strListType & aosPFE)1157 int OGREDIGEODataSource::BuildPolygon(const CPLString& osFEA,
1158                                       const strListType& aosPFE)
1159 {
1160     std::vector<xyPairListType> aoXYList;
1161 
1162     for(int k=0;k<(int)aosPFE.size();k++)
1163     {
1164         const std::map< CPLString, strListType >::iterator itPFE_PAR =
1165                                                     mapPFE_PAR.find(aosPFE[k]);
1166         if (itPFE_PAR == mapPFE_PAR.end())
1167         {
1168             CPLDebug("EDIGEO", "ERROR: Cannot find PFE %s", aosPFE[k].c_str());
1169             return FALSE;
1170         }
1171 
1172         const strListType & aosPARList = itPFE_PAR->second;
1173 
1174 /* -------------------------------------------------------------------- */
1175 /*      Resolve arc ids to arc coordinate lists.                        */
1176 /* -------------------------------------------------------------------- */
1177         std::vector< const xyPairListType *> aoPARPtrList;
1178         for( int i = 0; i < (int)aosPARList.size(); i++ )
1179         {
1180             const std::map< CPLString, xyPairListType >::iterator itPAR =
1181                                                 mapPAR.find(aosPARList[i]);
1182             if( itPAR != mapPAR.end() )
1183                 aoPARPtrList.push_back(&(itPAR->second));
1184             else
1185                 CPLDebug("EDIGEO",
1186                         "ERROR: Cannot find ARC %s", aosPARList[i].c_str());
1187         }
1188 
1189         if (aoPARPtrList.empty())
1190             return FALSE;
1191 
1192 /* -------------------------------------------------------------------- */
1193 /*      Now try to chain all arcs together.                             */
1194 /* -------------------------------------------------------------------- */
1195 
1196         for( int j = 0; j < (int)aoPARPtrList.size(); j++ )
1197         {
1198             if (aoPARPtrList[j] == nullptr)
1199                 continue;
1200             const xyPairListType& sFirstRing = *(aoPARPtrList[j]);
1201             const xyPairType* psNext = &(sFirstRing.back());
1202 
1203             xyPairListType aoXY;
1204             for( int i = 0; i < (int)sFirstRing.size(); i++ )
1205                 aoXY.push_back(sFirstRing[i]);
1206             aoPARPtrList[j] = nullptr;
1207 
1208             int nIter = 1;
1209             while(aoXY.back() != aoXY[0] && nIter < (int)aoPARPtrList.size())
1210             {
1211                 bool bFound = false;
1212                 bool bReverseSecond = false;
1213                 int i = 0;  // Used after for.
1214                 for( ; i < (int)aoPARPtrList.size(); i++ )
1215                 {
1216                     if (aoPARPtrList[i] != nullptr)
1217                     {
1218                         const xyPairListType& sSecondRing = *(aoPARPtrList[i]);
1219                         if (*psNext == sSecondRing[0])
1220                         {
1221                             bFound = true;
1222                             bReverseSecond = false;
1223                             break;
1224                         }
1225                         else if (*psNext == sSecondRing.back())
1226                         {
1227                             bFound = true;
1228                             bReverseSecond = true;
1229                             break;
1230                         }
1231                     }
1232                 }
1233 
1234                 if( !bFound )
1235                 {
1236                     CPLDebug("EDIGEO", "Cannot find ring for FEA %s / PFE %s",
1237                                 osFEA.c_str(), aosPFE[k].c_str());
1238                     break;
1239                 }
1240                 else
1241                 {
1242                     const xyPairListType& secondRing = *(aoPARPtrList[i]);
1243                     aoPARPtrList[i] = nullptr;
1244                     if( !bReverseSecond )
1245                     {
1246                         for(i=1;i<(int)secondRing.size();i++)
1247                             aoXY.push_back(secondRing[i]);
1248                         psNext = &secondRing.back();
1249                     }
1250                     else
1251                     {
1252                         for(i=1;i<(int)secondRing.size();i++)
1253                             aoXY.push_back(secondRing[secondRing.size()-1-i]);
1254                         psNext = &secondRing[0];
1255                     }
1256                 }
1257 
1258                 nIter ++;
1259             }
1260 
1261             aoXYList.push_back(aoXY);
1262         }
1263     }
1264 
1265 /* -------------------------------------------------------------------- */
1266 /*      Create feature.                                                 */
1267 /* -------------------------------------------------------------------- */
1268     OGRFeature* poFeature = CreateFeature(osFEA);
1269     if( poFeature )
1270     {
1271         std::vector<OGRGeometry*> aosPolygons;
1272         for( int j = 0; j < (int)aoXYList.size(); j++ )
1273         {
1274             const xyPairListType& aoXY = aoXYList[j];
1275             OGRLinearRing* poLS = new OGRLinearRing();
1276             poLS->setNumPoints((int)aoXY.size());
1277             for( int i = 0; i < (int)aoXY.size(); i++ )
1278                 poLS->setPoint(i, aoXY[i].first, aoXY[i].second);
1279             poLS->closeRings();
1280             OGRPolygon* poPolygon = new OGRPolygon();
1281             poPolygon->addRingDirectly(poLS);
1282             aosPolygons.push_back(poPolygon);
1283         }
1284 
1285         int bIsValidGeometry = FALSE;
1286         OGRGeometry* poGeom = OGRGeometryFactory::organizePolygons(
1287             &aosPolygons[0], (int)aosPolygons.size(),
1288             &bIsValidGeometry, nullptr);
1289         if (poGeom)
1290         {
1291             if (poSRS)
1292                 poGeom->assignSpatialReference(poSRS);
1293             poFeature->SetGeometryDirectly(poGeom);
1294         }
1295     }
1296     return TRUE;
1297 }
1298 
1299 /************************************************************************/
1300 /*                          BuildPolygons()                             */
1301 /************************************************************************/
1302 
BuildPolygons()1303 int OGREDIGEODataSource::BuildPolygons()
1304 {
1305     for( int iter = 0; iter < (int)listFEA_PFE.size(); iter++ )
1306     {
1307         const CPLString& osFEA = listFEA_PFE[iter].first;
1308         const strListType & aosPFE = listFEA_PFE[iter].second;
1309         BuildPolygon(osFEA, aosPFE);
1310     }
1311 
1312     return TRUE;
1313 }
1314 
1315 /************************************************************************/
1316 /*                  OGREDIGEOSortForQGIS()                              */
1317 /************************************************************************/
1318 
OGREDIGEOSortForQGIS(const void * a,const void * b)1319 static int OGREDIGEOSortForQGIS(const void* a, const void* b)
1320 {
1321     OGREDIGEOLayer* poLayerA = *((OGREDIGEOLayer**) a);
1322     OGREDIGEOLayer* poLayerB = *((OGREDIGEOLayer**) b);
1323     int nTypeA, nTypeB;
1324     switch (poLayerA->GetLayerDefn()->GetGeomType())
1325     {
1326         case wkbPoint: nTypeA = 1; break;
1327         case wkbLineString: nTypeA = 2; break;
1328         case wkbPolygon: nTypeA = 3; break;
1329         default: nTypeA = 4; break;
1330     }
1331     switch (poLayerB->GetLayerDefn()->GetGeomType())
1332     {
1333         case wkbPoint: nTypeB = 1; break;
1334         case wkbLineString: nTypeB = 2; break;
1335         case wkbPolygon: nTypeB = 3; break;
1336         default: nTypeB = 4; break;
1337     }
1338     if (nTypeA == nTypeB)
1339     {
1340         int nCmp = strcmp(poLayerA->GetName(), poLayerB->GetName());
1341         if (nCmp == 0)
1342             return 0;
1343 
1344         static const char* const apszPolyOrder[] =
1345             { "COMMUNE_id", "LIEUDIT_id", "SECTION_id", "SUBDSECT_id",
1346               "SUBDFISC_id", "PARCELLE_id", "BATIMENT_id" };
1347         for(int i=0;i<(int)(sizeof(apszPolyOrder)/sizeof(char*));i++)
1348         {
1349             if (strcmp(poLayerA->GetName(), apszPolyOrder[i]) == 0)
1350                 return -1;
1351             if (strcmp(poLayerB->GetName(), apszPolyOrder[i]) == 0)
1352                 return 1;
1353         }
1354         return nCmp;
1355     }
1356     else
1357         return nTypeB - nTypeA;
1358 }
1359 
1360 /************************************************************************/
1361 /*                                Open()                                */
1362 /************************************************************************/
1363 
Open(const char * pszFilename)1364 int OGREDIGEODataSource::Open( const char * pszFilename )
1365 
1366 {
1367     pszName = CPLStrdup( pszFilename );
1368 
1369     fpTHF = VSIFOpenL(pszFilename, "rb");
1370     if (fpTHF == nullptr)
1371         return FALSE;
1372 
1373     const char* pszLine = nullptr;
1374     int i = 0;
1375     bool bIsEDIGEO = false;
1376     while( i < 100 && (pszLine = CPLReadLine2L(fpTHF, 81, nullptr)) != nullptr )
1377     {
1378         if (strcmp(pszLine, "RTYSA03:GTS") == 0)
1379         {
1380             bIsEDIGEO = true;
1381             break;
1382         }
1383         i++;
1384     }
1385 
1386     if( !bIsEDIGEO )
1387     {
1388         VSIFCloseL(fpTHF);
1389         fpTHF = nullptr;
1390         return FALSE;
1391     }
1392 
1393     return TRUE;
1394 }
1395 
1396 /************************************************************************/
1397 /*                           ReadEDIGEO()                               */
1398 /************************************************************************/
1399 
ReadEDIGEO()1400 void OGREDIGEODataSource::ReadEDIGEO()
1401 {
1402     if (bHasReadEDIGEO)
1403         return;
1404 
1405     bHasReadEDIGEO = TRUE;
1406 
1407 /* -------------------------------------------------------------------- */
1408 /*      Read .THF file                                                  */
1409 /* -------------------------------------------------------------------- */
1410     VSIFSeekL(fpTHF, 0, SEEK_SET);
1411     if (!ReadTHF(fpTHF))
1412     {
1413         VSIFCloseL(fpTHF);
1414         fpTHF = nullptr;
1415         return;
1416     }
1417     VSIFCloseL(fpTHF);
1418     fpTHF = nullptr;
1419 
1420 /* -------------------------------------------------------------------- */
1421 /*      Read .GEO file                                                  */
1422 /* -------------------------------------------------------------------- */
1423     if (!ReadGEO())
1424         return;
1425 
1426 /* -------------------------------------------------------------------- */
1427 /*      Read .GEN file                                                  */
1428 /* -------------------------------------------------------------------- */
1429     if (!osGNN.empty())
1430         ReadGEN();
1431 
1432 /* -------------------------------------------------------------------- */
1433 /*      Read .DIC file                                                  */
1434 /* -------------------------------------------------------------------- */
1435     if (!ReadDIC())
1436         return;
1437 
1438 /* -------------------------------------------------------------------- */
1439 /*      Read .SCD file                                                  */
1440 /* -------------------------------------------------------------------- */
1441     if (!ReadSCD())
1442         return;
1443 
1444 /* -------------------------------------------------------------------- */
1445 /*      Read .QAL file                                                  */
1446 /* -------------------------------------------------------------------- */
1447     if (!osQAN.empty())
1448         ReadQAL();
1449 
1450 /* -------------------------------------------------------------------- */
1451 /*      Create layers from SCD definitions                              */
1452 /* -------------------------------------------------------------------- */
1453     for( int i = 0; i < (int)aoObjList.size(); i++ )
1454     {
1455         CreateLayerFromObjectDesc(aoObjList[i]);
1456     }
1457 
1458 /* -------------------------------------------------------------------- */
1459 /*      Read .VEC files and create features                             */
1460 /* -------------------------------------------------------------------- */
1461     for( int i = 0; i < (int)aosGDN.size(); i++ )
1462     {
1463         ReadVEC(aosGDN[i]);
1464 
1465         BuildPoints();
1466         BuildLineStrings();
1467         BuildPolygons();
1468 
1469         mapPNO.clear();
1470         mapPAR.clear();
1471         mapFEA.clear();
1472         mapPFE_PAR.clear();
1473         listFEA_PFE.clear();
1474         listFEA_PAR.clear();
1475         listFEA_PNO.clear();
1476         mapFEA_FEA.clear();
1477     }
1478 
1479     mapObjects.clear();
1480     mapAttributes.clear();
1481     mapAttributesSCD.clear();
1482     mapQAL.clear();
1483 
1484 /* -------------------------------------------------------------------- */
1485 /*      Delete empty layers                                             */
1486 /* -------------------------------------------------------------------- */
1487     for( int i = 0; i <nLayers; /*nothing*/ )
1488     {
1489         if (papoLayers[i]->GetFeatureCount(TRUE) == 0)
1490         {
1491             delete papoLayers[i];
1492             if (i < nLayers - 1)
1493                 memmove(papoLayers + i, papoLayers + i + 1,
1494                         (nLayers - i - 1) * sizeof(OGREDIGEOLayer*));
1495             nLayers --;
1496         }
1497         else
1498             i++;
1499     }
1500 
1501 /* -------------------------------------------------------------------- */
1502 /*      When added from QGIS, the layers must be ordered from           */
1503 /*      bottom (Polygon) to top (Point) to get nice visual effect       */
1504 /* -------------------------------------------------------------------- */
1505     if (CPLTestBool(CPLGetConfigOption("OGR_EDIGEO_SORT_FOR_QGIS", "YES")))
1506         qsort(papoLayers, nLayers, sizeof(OGREDIGEOLayer*), OGREDIGEOSortForQGIS);
1507 
1508 /* -------------------------------------------------------------------- */
1509 /*      Create a label layer for each feature layer                     */
1510 /* -------------------------------------------------------------------- */
1511     if (CPLTestBool(CPLGetConfigOption("OGR_EDIGEO_CREATE_LABEL_LAYERS", "YES")))
1512         CreateLabelLayers();
1513 
1514     return;
1515 }
1516 
1517 /************************************************************************/
1518 /*                         CreateLabelLayers()                          */
1519 /************************************************************************/
1520 
CreateLabelLayers()1521 void OGREDIGEODataSource::CreateLabelLayers()
1522 {
1523     OGRLayer* poLayer = GetLayerByName("ID_S_OBJ_Z_1_2_2");
1524     if (poLayer == nullptr)
1525         return;
1526 
1527     std::map<CPLString, OGREDIGEOLayer*> mapLayerNameToLayer;
1528 
1529     OGRFeature* poFeature = nullptr;
1530     OGRFeatureDefn* poFeatureDefn = poLayer->GetLayerDefn();
1531     while( (poFeature = poLayer->GetNextFeature()) != nullptr )
1532     {
1533         const char* pszBelongingLayerName =
1534             poFeature->GetFieldAsString(iOBJ_LNK_LAYER);
1535         if (pszBelongingLayerName)
1536         {
1537             CPLString osBelongingLayerName = pszBelongingLayerName;
1538             std::map<CPLString, OGREDIGEOLayer*>::iterator it =
1539                         mapLayerNameToLayer.find(osBelongingLayerName);
1540             OGREDIGEOLayer* poLabelLayer = nullptr;
1541 
1542             if (it == mapLayerNameToLayer.end())
1543             {
1544                 /* Create label layer if it does not already exist */
1545                 CPLString osLayerLabelName = osBelongingLayerName + "_LABEL";
1546                 poLabelLayer = new OGREDIGEOLayer(this, osLayerLabelName.c_str(),
1547                                              wkbPoint, poSRS);
1548                 OGRFeatureDefn* poLabelFeatureDefn = poLabelLayer->GetLayerDefn();
1549                 for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
1550                     poLabelFeatureDefn->AddFieldDefn(poFeatureDefn->GetFieldDefn(i));
1551                 mapLayerNameToLayer[osBelongingLayerName] = poLabelLayer;
1552 
1553                 papoLayers = (OGRLayer**)
1554                     CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
1555                 papoLayers[nLayers] = poLabelLayer;
1556                 nLayers ++;
1557             }
1558             else
1559             {
1560                 poLabelLayer = mapLayerNameToLayer[osBelongingLayerName];
1561             }
1562 
1563             OGRFeature* poNewFeature = new OGRFeature(poLabelLayer->GetLayerDefn());
1564             poNewFeature->SetFrom(poFeature);
1565             poLabelLayer->AddFeature(poNewFeature);
1566         }
1567         delete poFeature;
1568     }
1569 
1570     poLayer->ResetReading();
1571 }
1572