1 /******************************************************************************
2  *
3  * Project:  SDTS Translator
4  * Purpose:  Implementation of SDTS_IREF class for reading IREF module.
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 CPL_CVSID("$Id: sdtsiref.cpp e13dcd4dc171dfeed63f912ba06b9374ce4f3bb2 2018-03-18 21:37:41Z Even Rouault $")
32 
33 /************************************************************************/
34 /*                             SDTS_IREF()                              */
35 /************************************************************************/
36 
SDTS_IREF()37 SDTS_IREF::SDTS_IREF() :
38     nDefaultSADRFormat(0),
39     pszXAxisName(CPLStrdup("")),
40     pszYAxisName(CPLStrdup("")),
41     dfXScale(1.0),
42     dfYScale(1.0),
43     dfXOffset(0.0),
44     dfYOffset(0.0),
45     dfXRes(1.0),
46     dfYRes(1.0),
47     pszCoordinateFormat(CPLStrdup(""))
48 {}
49 
50 /************************************************************************/
51 /*                             ~SDTS_IREF()                             */
52 /************************************************************************/
53 
~SDTS_IREF()54 SDTS_IREF::~SDTS_IREF()
55 {
56     CPLFree( pszXAxisName );
57     CPLFree( pszYAxisName );
58     CPLFree( pszCoordinateFormat );
59 }
60 
61 /************************************************************************/
62 /*                                Read()                                */
63 /*                                                                      */
64 /*      Read the named file to initialize this structure.               */
65 /************************************************************************/
66 
Read(const char * pszFilename)67 int SDTS_IREF::Read( const char * pszFilename )
68 
69 {
70 /* -------------------------------------------------------------------- */
71 /*      Open the file, and read the header.                             */
72 /* -------------------------------------------------------------------- */
73     DDFModule oIREFFile;
74     if( !oIREFFile.Open( pszFilename ) )
75         return FALSE;
76 
77 /* -------------------------------------------------------------------- */
78 /*      Read the first record, and verify that this is an IREF record.  */
79 /* -------------------------------------------------------------------- */
80     DDFRecord *poRecord = oIREFFile.ReadRecord();
81     if( poRecord == nullptr )
82         return FALSE;
83 
84     if( poRecord->GetStringSubfield( "IREF", 0, "MODN", 0 ) == nullptr )
85         return FALSE;
86 
87 /* -------------------------------------------------------------------- */
88 /*      Get the labels.                                                 */
89 /* -------------------------------------------------------------------- */
90     CPLFree( pszXAxisName );
91     pszXAxisName = CPLStrdup( poRecord->GetStringSubfield( "IREF", 0,
92                                                            "XLBL", 0 ) );
93     CPLFree( pszYAxisName );
94     pszYAxisName = CPLStrdup( poRecord->GetStringSubfield( "IREF", 0,
95                                                            "YLBL", 0 ) );
96 
97 /* -------------------------------------------------------------------- */
98 /*      Get the coordinate encoding.                                    */
99 /* -------------------------------------------------------------------- */
100     CPLFree( pszCoordinateFormat );
101     pszCoordinateFormat =
102         CPLStrdup( poRecord->GetStringSubfield( "IREF", 0, "HFMT", 0 ) );
103 
104 /* -------------------------------------------------------------------- */
105 /*      Get the transformation information, and resolution.             */
106 /* -------------------------------------------------------------------- */
107     dfXScale = poRecord->GetFloatSubfield( "IREF", 0, "SFAX", 0 );
108     dfYScale = poRecord->GetFloatSubfield( "IREF", 0, "SFAY", 0 );
109 
110     dfXOffset = poRecord->GetFloatSubfield( "IREF", 0, "XORG", 0 );
111     dfYOffset = poRecord->GetFloatSubfield( "IREF", 0, "YORG", 0 );
112 
113     dfXRes = poRecord->GetFloatSubfield( "IREF", 0, "XHRS", 0 );
114     dfYRes = poRecord->GetFloatSubfield( "IREF", 0, "YHRS", 0 );
115 
116     nDefaultSADRFormat = EQUAL(pszCoordinateFormat,"BI32");
117 
118     return TRUE;
119 }
120 
121 /************************************************************************/
122 /*                            GetSADRCount()                            */
123 /*                                                                      */
124 /*      Return the number of SADR'es in the passed field.               */
125 /************************************************************************/
126 
GetSADRCount(DDFField * poField) const127 int SDTS_IREF::GetSADRCount( DDFField * poField ) const
128 
129 {
130     if( nDefaultSADRFormat )
131         return poField->GetDataSize() / SDTS_SIZEOF_SADR;
132 
133     return poField->GetRepeatCount();
134 }
135 
136 /************************************************************************/
137 /*                              GetSADR()                               */
138 /************************************************************************/
139 
GetSADR(DDFField * poField,int nVertices,double * padfX,double * padfY,double * padfZ)140 int SDTS_IREF::GetSADR( DDFField * poField, int nVertices,
141                         double *padfX, double * padfY, double * padfZ )
142 
143 {
144 /* -------------------------------------------------------------------- */
145 /*      For the sake of efficiency we depend on our knowledge that      */
146 /*      the SADR field is a series of bigendian int32's and decode      */
147 /*      them directly.                                                  */
148 /* -------------------------------------------------------------------- */
149     if( nDefaultSADRFormat
150         && poField->GetFieldDefn()->GetSubfieldCount() == 2 )
151     {
152         if( poField->GetDataSize() < nVertices * SDTS_SIZEOF_SADR )
153         {
154             return FALSE;
155         }
156 
157         GInt32          anXY[2];
158         const char      *pachRawData = poField->GetData();
159 
160         for( int iVertex = 0; iVertex < nVertices; iVertex++ )
161         {
162             // we copy to a temp buffer to ensure it is world aligned.
163             memcpy( anXY, pachRawData, 8 );
164             pachRawData += 8;
165 
166             // possibly byte swap, and always apply scale factor
167             padfX[iVertex] = dfXOffset
168                 + dfXScale * static_cast<int>( CPL_MSBWORD32( anXY[0] ) );
169             padfY[iVertex] = dfYOffset
170                 + dfYScale * static_cast<int>( CPL_MSBWORD32( anXY[1] ) );
171 
172             padfZ[iVertex] = 0.0;
173         }
174     }
175 
176 /* -------------------------------------------------------------------- */
177 /*      This is the generic case.  We assume either two or three        */
178 /*      subfields, and treat these as X, Y and Z regardless of          */
179 /*      name.                                                           */
180 /* -------------------------------------------------------------------- */
181     else
182     {
183         DDFFieldDefn    *poFieldDefn = poField->GetFieldDefn();
184         int             nBytesRemaining = poField->GetDataSize();
185         const char     *pachFieldData = poField->GetData();
186 
187         if( poFieldDefn->GetSubfieldCount() != 2 &&
188             poFieldDefn->GetSubfieldCount() != 3 )
189         {
190             return FALSE;
191         }
192 
193         for( int iVertex = 0; iVertex < nVertices; iVertex++ )
194         {
195             double adfXYZ[3] = { 0.0, 0.0, 0.0 };
196 
197             for( int iEntry = 0;
198                  nBytesRemaining > 0 &&
199                  iEntry < poFieldDefn->GetSubfieldCount();
200                  iEntry++ )
201             {
202                 int nBytesConsumed = 0;
203                 DDFSubfieldDefn *poSF = poFieldDefn->GetSubfield(iEntry);
204 
205                 switch( poSF->GetType() )
206                 {
207                   case DDFInt:
208                     adfXYZ[iEntry] =
209                         poSF->ExtractIntData( pachFieldData,
210                                               nBytesRemaining,
211                                               &nBytesConsumed );
212                     break;
213 
214                   case DDFFloat:
215                     adfXYZ[iEntry] =
216                         poSF->ExtractFloatData( pachFieldData,
217                                                 nBytesRemaining,
218                                                 &nBytesConsumed );
219                     break;
220 
221                   case DDFBinaryString:
222                     {
223                       GByte *pabyBString = reinterpret_cast<GByte *> (
224                           const_cast<char *>(
225                               poSF->ExtractStringData( pachFieldData,
226                                                        nBytesRemaining,
227                                                        &nBytesConsumed ) ) );
228 
229                     if( EQUAL(pszCoordinateFormat,"BI32") )
230                     {
231                         if( nBytesConsumed < 4 )
232                             return FALSE;
233                         GInt32  nValue;
234                         memcpy( &nValue, pabyBString, 4 );
235                         adfXYZ[iEntry]
236                             = static_cast<int>( CPL_MSBWORD32( nValue ) );
237                     }
238                     else if( EQUAL(pszCoordinateFormat,"BI16") )
239                     {
240                         if( nBytesConsumed < 2 )
241                             return FALSE;
242                         GInt16  nValue;
243                         memcpy( &nValue, pabyBString, 2 );
244                         adfXYZ[iEntry]
245                             = static_cast<int>( CPL_MSBWORD16( nValue ) );
246                     }
247                     else if( EQUAL(pszCoordinateFormat,"BU32") )
248                     {
249                         if( nBytesConsumed < 4 )
250                             return FALSE;
251                         GUInt32 nValue;
252                         memcpy( &nValue, pabyBString, 4 );
253                         adfXYZ[iEntry]
254                             = static_cast<GUInt32>( CPL_MSBWORD32( nValue ) );
255                     }
256                     else if( EQUAL(pszCoordinateFormat,"BU16") )
257                     {
258                         if( nBytesConsumed < 2 )
259                             return FALSE;
260                         GUInt16 nValue;
261                         memcpy( &nValue, pabyBString, 2 );
262                         adfXYZ[iEntry]
263                             = static_cast<GUInt16>( CPL_MSBWORD16( nValue ) );
264                     }
265                     else if( EQUAL(pszCoordinateFormat,"BFP32") )
266                     {
267                         if( nBytesConsumed < 4 )
268                             return FALSE;
269                         float   fValue;
270 
271                         memcpy( &fValue, pabyBString, 4 );
272                         CPL_MSBPTR32( &fValue );
273                         adfXYZ[iEntry] = fValue;
274                     }
275                     else if( EQUAL(pszCoordinateFormat,"BFP64") )
276                     {
277                         if( nBytesConsumed < 8 )
278                             return FALSE;
279                         double  dfValue;
280 
281                         memcpy( &dfValue, pabyBString, 8 );
282                         CPL_MSBPTR64( &dfValue );
283                         adfXYZ[iEntry] = dfValue;
284                     }
285                     }
286                     break;
287 
288                   default:
289                     adfXYZ[iEntry] = 0.0;
290                     break;
291                 }
292 
293                 pachFieldData += nBytesConsumed;
294                 nBytesRemaining -= nBytesConsumed;
295             } /* next iEntry */
296 
297             padfX[iVertex] = dfXOffset + adfXYZ[0] * dfXScale;
298             padfY[iVertex] = dfYOffset + adfXYZ[1] * dfYScale;
299             padfZ[iVertex] = adfXYZ[2];
300         } /* next iVertex */
301     }
302 
303     return TRUE;
304 }
305