1 /******************************************************************************
2  *
3  * Project:  SDTS Translator
4  * Purpose:  Implementation of SDTSTransfer class.
5  * Author:   Frank Warmerdam, warmerdam@pobox.com
6  *
7  ******************************************************************************
8  * Copyright (c) 1999, Frank Warmerdam
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 "sdts_al.h"
30 
31 #include <algorithm>
32 
33 CPL_CVSID("$Id: sdtstransfer.cpp 2ace03ec48c36dae8ba74089d85617c095643428 2018-11-02 18:02:33 +0100 Even Rouault $")
34 
35 /************************************************************************/
36 /*                            SDTSTransfer()                            */
37 /************************************************************************/
38 
SDTSTransfer()39 SDTSTransfer::SDTSTransfer() :
40     nLayers(0),
41     panLayerCATDEntry(nullptr),
42     papoLayerReader(nullptr)
43 {}
44 
45 /************************************************************************/
46 /*                           ~SDTSTransfer()                            */
47 /************************************************************************/
48 
~SDTSTransfer()49 SDTSTransfer::~SDTSTransfer()
50 
51 {
52     Close();
53 }
54 
55 /************************************************************************/
56 /*                                Open()                                */
57 /************************************************************************/
58 
59 /**
60  * Open an SDTS transfer, and establish a list of data layers in the
61  * transfer.
62  *
63  * @param pszFilename The name of the CATD file within the transfer.
64  *
65  * @return TRUE if the open success, or FALSE if it fails.
66  */
67 
Open(const char * pszFilename)68 int SDTSTransfer::Open( const char * pszFilename )
69 
70 {
71 /* -------------------------------------------------------------------- */
72 /*      Open the catalog.                                               */
73 /* -------------------------------------------------------------------- */
74     if( !oCATD.Read( pszFilename ) )
75         return FALSE;
76 
77 /* -------------------------------------------------------------------- */
78 /*      Read the IREF file.                                             */
79 /* -------------------------------------------------------------------- */
80     if( oCATD.GetModuleFilePath( "IREF" ) == nullptr )
81     {
82         CPLError( CE_Failure, CPLE_AppDefined,
83                   "Can't find IREF module in transfer `%s'.\n",
84                   pszFilename );
85         return FALSE;
86     }
87 
88     if( !oIREF.Read( oCATD.GetModuleFilePath( "IREF" ) ) )
89         return FALSE;
90 
91 /* -------------------------------------------------------------------- */
92 /*      Read the XREF file.                                             */
93 /* -------------------------------------------------------------------- */
94     if( oCATD.GetModuleFilePath( "XREF" ) == nullptr )
95     {
96         CPLError( CE_Warning, CPLE_AppDefined,
97                   "Can't find XREF module in transfer `%s'.\n",
98                   pszFilename );
99     }
100     else if( !oXREF.Read( oCATD.GetModuleFilePath( "XREF" ) ) )
101     {
102         CPLError( CE_Warning, CPLE_AppDefined,
103               "Can't read XREF module, even though found in transfer `%s'.\n",
104                   pszFilename );
105     }
106 
107 /* -------------------------------------------------------------------- */
108 /*      Build an index of layer types we recognise and care about.      */
109 /* -------------------------------------------------------------------- */
110     panLayerCATDEntry = reinterpret_cast<int *>(
111         CPLMalloc( sizeof(int) * oCATD.GetEntryCount() ) );
112 
113     for( int iCATDLayer = 0; iCATDLayer < oCATD.GetEntryCount(); iCATDLayer++ )
114     {
115         switch( oCATD.GetEntryType(iCATDLayer) )
116         {
117           case SLTPoint:
118           case SLTLine:
119           case SLTAttr:
120           case SLTPoly:
121           case SLTRaster:
122             panLayerCATDEntry[nLayers++] = iCATDLayer;
123             break;
124 
125           default:
126             /* ignore */
127             break;
128         }
129     }
130 
131 /* -------------------------------------------------------------------- */
132 /*      Initialized the related indexed readers list.                   */
133 /* -------------------------------------------------------------------- */
134     papoLayerReader = reinterpret_cast<SDTSIndexedReader **>(
135         CPLCalloc( sizeof(SDTSIndexedReader*), oCATD.GetEntryCount() ) );
136 
137     return TRUE;
138 }
139 
140 /************************************************************************/
141 /*                               Close()                                */
142 /************************************************************************/
143 
Close()144 void SDTSTransfer::Close()
145 
146 {
147     for( int i = 0; i < nLayers; i++ )
148     {
149         if( papoLayerReader[i] != nullptr )
150             delete papoLayerReader[i];
151     }
152     CPLFree( papoLayerReader );
153     papoLayerReader = nullptr;
154     CPLFree( panLayerCATDEntry );
155     panLayerCATDEntry = nullptr;
156     nLayers = 0;
157 }
158 
159 /************************************************************************/
160 /*                            GetLayerType()                            */
161 /************************************************************************/
162 
163 /**
164   Fetch type of requested feature layer.
165 
166   @param iEntry the index of the layer to fetch information on.  A value
167   from zero to GetLayerCount()-1.
168 
169   @return the layer type.
170 
171   <ul>
172   <li> SLTPoint: A point layer.  An SDTSPointReader is returned by
173   SDTSTransfer::GetLayerIndexedReader().
174 
175   <li> SLTLine: A line layer.  An SDTSLineReader is returned by
176   SDTSTransfer::GetLayerIndexedReader().
177 
178   <li> SLTAttr: An attribute primary or secondary layer.  An SDTSAttrReader
179   is returned by SDTSTransfer::GetLayerIndexedReader().
180 
181   <li> SLTPoly: A polygon layer.  An SDTSPolygonReader is returned by
182   SDTSTransfer::GetLayerIndexedReader().
183 
184   <li> SLTRaster: A raster layer.  SDTSTransfer::GetLayerIndexedReader()
185   is not implemented.  Use SDTSTransfer::GetLayerRasterReader() instead.
186   </ul>
187  */
188 
GetLayerType(int iEntry) const189 SDTSLayerType SDTSTransfer::GetLayerType( int iEntry ) const
190 
191 {
192     if( iEntry < 0 || iEntry >= nLayers )
193         return SLTUnknown;
194 
195     return oCATD.GetEntryType( panLayerCATDEntry[iEntry] );
196 }
197 
198 /************************************************************************/
199 /*                         GetLayerCATDEntry()                          */
200 /************************************************************************/
201 
202 /**
203   Fetch the CATD module index for a layer.   This can be used to fetch
204   details about the layer/module from the SDTS_CATD object, such as its
205   filename, and description.
206 
207   @param iEntry the layer index from 0 to GetLayerCount()-1.
208 
209   @return the module index suitable for use with the various SDTS_CATD
210   methods.
211  */
212 
GetLayerCATDEntry(int iEntry) const213 int SDTSTransfer::GetLayerCATDEntry( int iEntry ) const
214 
215 {
216     if( iEntry < 0 || iEntry >= nLayers )
217         return -1;
218 
219     return panLayerCATDEntry[iEntry];
220 }
221 
222 /************************************************************************/
223 /*                         GetLayerLineReader()                         */
224 /************************************************************************/
225 
GetLayerLineReader(int iEntry)226 SDTSLineReader *SDTSTransfer::GetLayerLineReader( int iEntry )
227 
228 {
229     if( iEntry < 0
230         || iEntry >= nLayers
231         || oCATD.GetEntryType( panLayerCATDEntry[iEntry] ) != SLTLine )
232     {
233         return nullptr;
234     }
235 
236     SDTSLineReader *poLineReader = new SDTSLineReader( &oIREF );
237 
238     if( !poLineReader->Open(
239                         oCATD.GetEntryFilePath( panLayerCATDEntry[iEntry] ) ) )
240     {
241         oCATD.SetEntryTypeUnknown(iEntry) ; // to prevent further attempt
242         delete poLineReader;
243         return nullptr;
244     }
245 
246     return poLineReader;
247 }
248 
249 /************************************************************************/
250 /*                        GetLayerPointReader()                         */
251 /************************************************************************/
252 
GetLayerPointReader(int iEntry)253 SDTSPointReader *SDTSTransfer::GetLayerPointReader( int iEntry )
254 
255 {
256     if( iEntry < 0
257         || iEntry >= nLayers
258         || oCATD.GetEntryType( panLayerCATDEntry[iEntry] ) != SLTPoint )
259     {
260         return nullptr;
261     }
262 
263     SDTSPointReader *poPointReader = new SDTSPointReader( &oIREF );
264 
265     if( !poPointReader->Open(
266                         oCATD.GetEntryFilePath( panLayerCATDEntry[iEntry] ) ) )
267     {
268         oCATD.SetEntryTypeUnknown(iEntry) ; // to prevent further attempt
269         delete poPointReader;
270         return nullptr;
271     }
272 
273     return poPointReader;
274 }
275 
276 /************************************************************************/
277 /*                       GetLayerPolygonReader()                        */
278 /************************************************************************/
279 
GetLayerPolygonReader(int iEntry)280 SDTSPolygonReader *SDTSTransfer::GetLayerPolygonReader( int iEntry )
281 
282 {
283     if( iEntry < 0
284         || iEntry >= nLayers
285         || oCATD.GetEntryType( panLayerCATDEntry[iEntry] ) != SLTPoly )
286     {
287         return nullptr;
288     }
289 
290     SDTSPolygonReader *poPolyReader = new SDTSPolygonReader();
291 
292     if( !poPolyReader->Open(
293                         oCATD.GetEntryFilePath( panLayerCATDEntry[iEntry] ) ) )
294     {
295         oCATD.SetEntryTypeUnknown(iEntry) ; // to prevent further attempt
296         delete poPolyReader;
297         return nullptr;
298     }
299 
300     return poPolyReader;
301 }
302 
303 /************************************************************************/
304 /*                         GetLayerAttrReader()                         */
305 /************************************************************************/
306 
GetLayerAttrReader(int iEntry)307 SDTSAttrReader *SDTSTransfer::GetLayerAttrReader( int iEntry )
308 
309 {
310     if( iEntry < 0
311         || iEntry >= nLayers
312         || oCATD.GetEntryType( panLayerCATDEntry[iEntry] ) != SLTAttr )
313     {
314         return nullptr;
315     }
316 
317     SDTSAttrReader *poAttrReader = new SDTSAttrReader();
318 
319     if( !poAttrReader->Open(
320                         oCATD.GetEntryFilePath( panLayerCATDEntry[iEntry] ) ) )
321     {
322         oCATD.SetEntryTypeUnknown(iEntry) ; // to prevent further attempt
323         delete poAttrReader;
324         return nullptr;
325     }
326 
327     return poAttrReader;
328 }
329 
330 /************************************************************************/
331 /*                        GetLayerRasterReader()                        */
332 /************************************************************************/
333 
334 /**
335   Instantiate an SDTSRasterReader for the indicated layer.
336 
337   @param iEntry the index of the layer to instantiate a reader for.  A
338   value between 0 and GetLayerCount()-1.
339 
340   @return a pointer to a new SDTSRasterReader object, or NULL if the method
341   fails.
342 
343   NOTE: The reader returned from GetLayerRasterReader() becomes the
344   responsibility of the caller to delete, and isn't automatically deleted
345   when the SDTSTransfer is destroyed.  This method is different from
346   the GetLayerIndexedReader() method in this regard.
347   */
348 
GetLayerRasterReader(int iEntry)349 SDTSRasterReader *SDTSTransfer::GetLayerRasterReader( int iEntry )
350 
351 {
352     if( iEntry < 0
353         || iEntry >= nLayers
354         || oCATD.GetEntryType( panLayerCATDEntry[iEntry] ) != SLTRaster )
355     {
356         return nullptr;
357     }
358 
359     SDTSRasterReader *poRasterReader = new SDTSRasterReader();
360 
361     if( !poRasterReader->Open( &oCATD, &oIREF,
362                          oCATD.GetEntryModule(panLayerCATDEntry[iEntry] ) ) )
363     {
364         oCATD.SetEntryTypeUnknown(iEntry) ; // to prevent further attempt
365         delete poRasterReader;
366         return nullptr;
367     }
368 
369     return poRasterReader;
370 }
371 
372 /************************************************************************/
373 /*                        GetLayerModuleReader()                        */
374 /************************************************************************/
375 
GetLayerModuleReader(int iEntry)376 DDFModule *SDTSTransfer::GetLayerModuleReader( int iEntry )
377 
378 {
379     if( iEntry < 0 || iEntry >= nLayers )
380     {
381         return nullptr;
382     }
383 
384     DDFModule *poModuleReader = new DDFModule;
385 
386     if( !poModuleReader->Open(
387                         oCATD.GetEntryFilePath( panLayerCATDEntry[iEntry] ) ) )
388     {
389         oCATD.SetEntryTypeUnknown(iEntry) ; // to prevent further attempt
390         delete poModuleReader;
391         return nullptr;
392     }
393 
394     return poModuleReader;
395 }
396 
397 /************************************************************************/
398 /*                       GetLayerIndexedReader()                        */
399 /************************************************************************/
400 
401 /**
402   Returns a pointer to a reader of the appropriate type to the requested
403   layer.
404 
405   Notes:
406   <ul>
407   <li> The returned reader remains owned by the SDTSTransfer, and will be
408   destroyed when the SDTSTransfer is destroyed.  It should not be
409   destroyed by the application.
410 
411   <li> If an indexed reader was already created for this layer using
412   GetLayerIndexedReader(), it will be returned instead of creating a new
413   reader.  Among other things this means that the returned reader may not
414   be positioned to read from the beginning of the module, and may already
415   have its index filled.
416 
417   <li> The returned reader will be of a type appropriate to the layer.
418   See SDTSTransfer::GetLayerType() to see what reader classes correspond
419   to what layer types, so it can be cast accordingly (if necessary).
420   </ul>
421 
422   @param iEntry the index of the layer to instantiate a reader for.  A
423   value between 0 and GetLayerCount()-1.
424 
425   @return a pointer to an appropriate reader or NULL if the method fails.
426   */
427 
GetLayerIndexedReader(int iEntry)428 SDTSIndexedReader *SDTSTransfer::GetLayerIndexedReader( int iEntry )
429 
430 {
431     if( papoLayerReader[iEntry] == nullptr )
432     {
433         switch( oCATD.GetEntryType( panLayerCATDEntry[iEntry] ) )
434         {
435           case SLTAttr:
436             papoLayerReader[iEntry] = GetLayerAttrReader( iEntry );
437             break;
438 
439           case SLTPoint:
440             papoLayerReader[iEntry] = GetLayerPointReader( iEntry );
441             break;
442 
443           case SLTLine:
444             papoLayerReader[iEntry] = GetLayerLineReader( iEntry );
445             break;
446 
447           case SLTPoly:
448             papoLayerReader[iEntry] = GetLayerPolygonReader( iEntry );
449             break;
450 
451           default:
452             break;
453         }
454     }
455 
456     return papoLayerReader[iEntry];
457 }
458 
459 /************************************************************************/
460 /*                             FindLayer()                              */
461 /************************************************************************/
462 
463 /**
464   Fetch the SDTSTransfer layer number corresponding to a module name.
465 
466   @param pszModule the name of the module to search for, such as "PC01".
467 
468   @return the layer number (between 0 and GetLayerCount()-1 corresponding to
469   the module, or -1 if it doesn't correspond to a layer.
470   */
471 
FindLayer(const char * pszModule)472 int SDTSTransfer::FindLayer( const char * pszModule )
473 
474 {
475     for( int iLayer = 0; iLayer < nLayers; iLayer++ )
476     {
477         if( EQUAL(pszModule,
478                   oCATD.GetEntryModule( panLayerCATDEntry[iLayer] ) ) )
479         {
480             return iLayer;
481         }
482     }
483 
484     return -1;
485 }
486 
487 /************************************************************************/
488 /*                        GetIndexedFeatureRef()                        */
489 /************************************************************************/
490 
GetIndexedFeatureRef(SDTSModId * poModId,SDTSLayerType * peType)491 SDTSFeature *SDTSTransfer::GetIndexedFeatureRef( SDTSModId *poModId,
492                                                  SDTSLayerType *peType )
493 
494 {
495 /* -------------------------------------------------------------------- */
496 /*      Find the desired layer ... this is likely a significant slow    */
497 /*      point in the whole process ... perhaps the last found could     */
498 /*      be cached or something.                                         */
499 /* -------------------------------------------------------------------- */
500     const int iLayer = FindLayer( poModId->szModule );
501     if( iLayer == -1 )
502         return nullptr;
503 
504 /* -------------------------------------------------------------------- */
505 /*      Get the reader, and read a feature from it.                     */
506 /* -------------------------------------------------------------------- */
507     SDTSIndexedReader *poReader = GetLayerIndexedReader( iLayer );
508     if( poReader == nullptr )
509         return nullptr;
510 
511 /* -------------------------------------------------------------------- */
512 /*      return type, if requested.                                      */
513 /* -------------------------------------------------------------------- */
514     if( peType != nullptr )
515         *peType = GetLayerType(iLayer);
516 
517     return poReader->GetIndexedFeatureRef( poModId->nRecord );
518 }
519 
520 /************************************************************************/
521 /*                              GetAttr()                               */
522 /*                                                                      */
523 /*      Fetch the attribute information corresponding to a given        */
524 /*      SDTSModId.                                                      */
525 /************************************************************************/
526 
527 /**
528   Fetch the attribute fields given a particular module/record id.
529 
530   @param poModId an attribute record identifier, normally taken from the
531   aoATID[] array of an SDTSIndexedFeature.
532 
533   @return a pointer to the DDFField containing the user attribute values as
534   subfields.
535   */
536 
GetAttr(SDTSModId * poModId)537 DDFField *SDTSTransfer::GetAttr( SDTSModId *poModId )
538 
539 {
540     SDTSAttrRecord *poAttrRecord = dynamic_cast<SDTSAttrRecord *>(
541         GetIndexedFeatureRef( poModId ) );
542 
543     if( poAttrRecord == nullptr )
544         return nullptr;
545 
546     return poAttrRecord->poATTR;
547 }
548 
549 /************************************************************************/
550 /*                             GetBounds()                              */
551 /************************************************************************/
552 
553 /**
554   Fetch approximate bounds for a transfer by scanning all point layers
555   and raster layers.
556 
557   For TVP datasets (where point layers are scanned) the results can, in
558   theory miss some lines that go outside the bounds of the point layers.
559   However, this isn't common since most TVP sets contain a bounding rectangle
560   whose corners will define the most extreme extents.
561 
562   @param pdfMinX western edge of dataset
563   @param pdfMinY southern edge of dataset
564   @param pdfMaxX eastern edge of dataset
565   @param pdfMaxY northern edge of dataset
566 
567   @return TRUE if success, or FALSE on a failure.
568   */
569 
GetBounds(double * pdfMinX,double * pdfMinY,double * pdfMaxX,double * pdfMaxY)570 int SDTSTransfer::GetBounds( double *pdfMinX, double *pdfMinY,
571                              double *pdfMaxX, double *pdfMaxY )
572 
573 {
574     bool bFirst = true;
575 
576     for( int iLayer = 0; iLayer < GetLayerCount(); iLayer++ )
577     {
578         if( GetLayerType( iLayer ) == SLTPoint )
579         {
580 
581             SDTSPointReader *poLayer = reinterpret_cast<SDTSPointReader *>(
582                 GetLayerIndexedReader( iLayer ) );
583             if( poLayer == nullptr )
584                 continue;
585 
586             poLayer->Rewind();
587 
588             SDTSRawPoint *poPoint = nullptr;
589             while( (poPoint = reinterpret_cast<SDTSRawPoint *>(
590                       poLayer->GetNextFeature() ) ) != nullptr )
591             {
592                 if( bFirst )
593                 {
594                     *pdfMinX = poPoint->dfX;
595                     *pdfMaxX = poPoint->dfX;
596                     *pdfMinY = poPoint->dfY;
597                     *pdfMaxY = poPoint->dfY;
598                     bFirst = false;
599                 }
600                 else
601                 {
602                     *pdfMinX = std::min( *pdfMinX, poPoint->dfX );
603                     *pdfMaxX = std::max( *pdfMaxX, poPoint->dfX );
604                     *pdfMinY = std::min( *pdfMinY, poPoint->dfY );
605                     *pdfMaxY = std::max( *pdfMaxY, poPoint->dfY );
606                 }
607 
608                 if( !poLayer->IsIndexed() )
609                     delete poPoint;
610             }
611         }
612         else if( GetLayerType( iLayer ) == SLTRaster )
613         {
614             SDTSRasterReader *poRL = GetLayerRasterReader( iLayer );
615             if( poRL == nullptr )
616                 continue;
617 
618             double adfGeoTransform[6];
619             poRL->GetTransform( adfGeoTransform );
620 
621             const double dfMinX = adfGeoTransform[0];
622             const double dfMaxY = adfGeoTransform[3];
623             const double dfMaxX = adfGeoTransform[0]
624                 + poRL->GetXSize() * adfGeoTransform[1];
625             const double dfMinY = adfGeoTransform[3]
626                 + poRL->GetYSize() * adfGeoTransform[5];
627 
628             if( bFirst )
629             {
630                 *pdfMinX = dfMinX;
631                 *pdfMaxX = dfMaxX;
632                 *pdfMinY = dfMinY;
633                 *pdfMaxY = dfMaxY;
634                 bFirst = false;
635             }
636             else
637             {
638                 *pdfMinX = std::min( dfMinX, *pdfMinX );
639                 *pdfMaxX = std::max( dfMaxX, *pdfMaxX );
640                 *pdfMinY = std::min( dfMinY, *pdfMinY );
641                 *pdfMaxY = std::max( dfMaxY, *pdfMaxY );
642             }
643 
644             delete poRL;
645         }
646     }
647 
648     return !bFirst;
649 }
650