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