1 /******************************************************************************
2  *
3  * Project:  EPIInfo .REC Reader
4  * Purpose:  Implements OGRRECLayer class.
5  * Author:   Frank Warmerdam <warmerdam@pobox.com>
6  *
7  ******************************************************************************
8  * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.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 "cpl_conv.h"
30 #include "cpl_string.h"
31 #include "ogr_rec.h"
32 
33 CPL_CVSID("$Id: ogrreclayer.cpp 7e07230bbff24eb333608de4dbd460b7312839d0 2017-12-11 19:08:47Z Even Rouault $")
34 
35 /************************************************************************/
36 /*                            OGRRECLayer()                             */
37 /*                                                                      */
38 /*      Note that the OGRRECLayer assumes ownership of the passed       */
39 /*      file pointer.                                                   */
40 /************************************************************************/
41 
OGRRECLayer(const char * pszLayerNameIn,FILE * fp,int nFieldCountIn)42 OGRRECLayer::OGRRECLayer( const char *pszLayerNameIn,
43                           FILE * fp, int nFieldCountIn ) :
44     poFeatureDefn(new OGRFeatureDefn( pszLayerNameIn )),
45     fpREC(fp),
46     nStartOfData(0),
47     bIsValid(FALSE),
48     nFieldCount(0),
49     panFieldOffset(static_cast<int *>(CPLCalloc(sizeof(int),nFieldCountIn))),
50     panFieldWidth(static_cast<int *>(CPLCalloc(sizeof(int),nFieldCountIn))),
51     nRecordLength(0),
52     nNextFID(1)
53 {
54     SetDescription( poFeatureDefn->GetName() );
55     poFeatureDefn->Reference();
56     poFeatureDefn->SetGeomType( wkbNone );
57 
58 /* -------------------------------------------------------------------- */
59 /*      Read field definition lines.                                    */
60 /* -------------------------------------------------------------------- */
61     for( int iField = 0; iField < nFieldCountIn; iField++ )
62     {
63         const char *pszLine = CPLReadLine( fp );
64 
65         if( pszLine == nullptr )
66             return;
67 
68         if( strlen(pszLine) < 44 )
69             return;
70 
71         // Extract field width.
72         panFieldWidth[nFieldCount] = atoi( RECGetField( pszLine, 37, 4 ) );
73         if( panFieldWidth[nFieldCount] < 0 )
74             return;
75 
76         // Is this an real, integer or string field?  Default to string.
77         int nTypeCode = atoi(RECGetField(pszLine,33,4));
78         OGRFieldType eFType = OFTString;
79         if( nTypeCode == 12 )
80             eFType = OFTInteger;
81         else if( nTypeCode > 100 && nTypeCode < 120 )
82         {
83             eFType = OFTReal;
84         }
85         else if( nTypeCode == 0 || nTypeCode == 6 || nTypeCode == 102 )
86         {
87             if( panFieldWidth[nFieldCount] < 3 )
88                 eFType = OFTInteger;
89             else
90                 eFType = OFTReal;
91         }
92         else
93             eFType = OFTString;
94 
95         OGRFieldDefn oField( RECGetField( pszLine, 2, 10 ), eFType );
96 
97         // Establish field offset.
98         if( nFieldCount > 0 )
99             panFieldOffset[nFieldCount]
100                 = panFieldOffset[nFieldCount-1] + panFieldWidth[nFieldCount-1];
101 
102         if( nTypeCode > 100 && nTypeCode < 120 )
103         {
104             oField.SetWidth( panFieldWidth[nFieldCount] );
105             oField.SetPrecision( nTypeCode - 100 );
106         }
107         else if( eFType == OFTReal )
108         {
109             oField.SetWidth( panFieldWidth[nFieldCount]*2 );
110             oField.SetPrecision( panFieldWidth[nFieldCount]-1 );
111         }
112         else
113             oField.SetWidth( panFieldWidth[nFieldCount] );
114 
115         // Skip fields that are only screen labels.
116         if( panFieldWidth[nFieldCount] == 0 )
117             continue;
118 
119         poFeatureDefn->AddFieldDefn( &oField );
120         nFieldCount++;
121     }
122 
123     if( nFieldCount == 0 )
124         return;
125 
126     nRecordLength = panFieldOffset[nFieldCount-1]+panFieldWidth[nFieldCount-1];
127     bIsValid = TRUE;
128 
129     nStartOfData = static_cast<int>(VSIFTell( fp ));
130 }
131 
132 /************************************************************************/
133 /*                           ~OGRRECLayer()                           */
134 /************************************************************************/
135 
~OGRRECLayer()136 OGRRECLayer::~OGRRECLayer()
137 
138 {
139     if( m_nFeaturesRead > 0 && poFeatureDefn != nullptr )
140     {
141         CPLDebug( "REC", "%d features read on layer '%s'.",
142                   static_cast<int>(m_nFeaturesRead),
143                   poFeatureDefn->GetName() );
144     }
145 
146     if( fpREC != nullptr )
147         VSIFClose( fpREC );
148 
149     if( poFeatureDefn )
150         poFeatureDefn->Release();
151 
152     CPLFree( panFieldOffset );
153     CPLFree( panFieldWidth );
154 }
155 
156 /************************************************************************/
157 /*                            ResetReading()                            */
158 /************************************************************************/
159 
ResetReading()160 void OGRRECLayer::ResetReading()
161 
162 {
163     CPL_IGNORE_RET_VAL(VSIFSeek( fpREC, nStartOfData, SEEK_SET ));
164     nNextFID = 1;
165 }
166 
167 /************************************************************************/
168 /*                      GetNextUnfilteredFeature()                      */
169 /************************************************************************/
170 
GetNextUnfilteredFeature()171 OGRFeature * OGRRECLayer::GetNextUnfilteredFeature()
172 
173 {
174 /* -------------------------------------------------------------------- */
175 /*      Read and assemble the source data record.                       */
176 /* -------------------------------------------------------------------- */
177     int        nDataLen = 0;
178     char       *pszRecord = static_cast<char *>(CPLMalloc(nRecordLength + 2 ));
179 
180     while( nDataLen < nRecordLength )
181     {
182         const char *pszLine = CPLReadLine( fpREC );
183 
184         if( pszLine == nullptr )
185         {
186             CPLFree( pszRecord );
187             return nullptr;
188         }
189 
190         if( *pszLine == 0 || *pszLine == 26 /* Cntl-Z - DOS EOF */ )
191         {
192             CPLFree( pszRecord );
193             return nullptr;
194         }
195 
196         // If the end-of-line markers is '?' the record is deleted.
197         int iSegLen = static_cast<int>(strlen(pszLine));
198         if( pszLine[iSegLen-1] == '?' )
199         {
200             pszRecord[0] = '\0';
201             nDataLen = 0;
202             continue;
203         }
204 
205         // Strip off end-of-line '!' marker.
206         if( pszLine[iSegLen-1] != '!'
207             && pszLine[iSegLen-1] != '^' )
208         {
209             CPLError( CE_Failure, CPLE_AppDefined,
210                       "Apparent corrupt data line .. record FID=%d",
211                       nNextFID );
212             CPLFree( pszRecord );
213             return nullptr;
214         }
215 
216         iSegLen--;
217         if( nDataLen + iSegLen > nRecordLength )
218         {
219             CPLError( CE_Failure, CPLE_AppDefined,
220                       "Too much data for record %d.",
221                       nNextFID );
222             CPLFree( pszRecord );
223             return nullptr;
224         }
225 
226         memcpy( pszRecord+nDataLen, pszLine, iSegLen );
227         pszRecord[nDataLen+iSegLen] = '\0';
228         nDataLen += iSegLen;
229     }
230 
231 /* -------------------------------------------------------------------- */
232 /*      Create the OGR feature.                                         */
233 /* -------------------------------------------------------------------- */
234     OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
235 
236 /* -------------------------------------------------------------------- */
237 /*      Set attributes for any indicated attribute records.             */
238 /* -------------------------------------------------------------------- */
239     for( int iAttr = 0; iAttr < nFieldCount; iAttr++)
240     {
241         const char *pszFieldText =
242             RECGetField( pszRecord,
243                          panFieldOffset[iAttr] + 1,
244                          panFieldWidth[iAttr] );
245 
246         if( strlen(pszFieldText) != 0 )
247         {
248             /* coverity[tainted_data] */
249             poFeature->SetField( iAttr, pszFieldText );
250         }
251     }
252 
253 /* -------------------------------------------------------------------- */
254 /*      Translate the record id.                                        */
255 /* -------------------------------------------------------------------- */
256     poFeature->SetFID( nNextFID++ );
257     m_nFeaturesRead++;
258 
259     CPLFree( pszRecord );
260 
261     return poFeature;
262 }
263 
264 /************************************************************************/
265 /*                           GetNextFeature()                           */
266 /************************************************************************/
267 
GetNextFeature()268 OGRFeature *OGRRECLayer::GetNextFeature()
269 
270 {
271     OGRFeature  *poFeature = nullptr;
272 
273 /* -------------------------------------------------------------------- */
274 /*      Read features till we find one that satisfies our current       */
275 /*      spatial criteria.                                               */
276 /* -------------------------------------------------------------------- */
277     while( true )
278     {
279         poFeature = GetNextUnfilteredFeature();
280         if( poFeature == nullptr )
281             break;
282 
283         if( m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate( poFeature ) )
284             break;
285 
286         delete poFeature;
287     }
288 
289     return poFeature;
290 }
291 
292 /************************************************************************/
293 /*                           TestCapability()                           */
294 /************************************************************************/
295 
TestCapability(const char *)296 int OGRRECLayer::TestCapability( const char * /* pszCap */)
297 {
298     return FALSE;
299 }
300