1 : /******************************************************************************
2 : * $Id: vfkreader.cpp 25340 2012-12-21 20:30:21Z rouault $
3 : *
4 : * Project: VFK Reader
5 : * Purpose: Implements VFKReader class.
6 : * Author: Martin Landa, landa.martin gmail.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2009-2010, 2012, Martin Landa <landa.martin gmail.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person
12 : * obtaining a copy of this software and associated documentation
13 : * files (the "Software"), to deal in the Software without
14 : * restriction, including without limitation the rights to use, copy,
15 : * modify, merge, publish, distribute, sublicense, and/or sell copies
16 : * of the Software, and to permit persons to whom the Software is
17 : * furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be
20 : * included in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
26 : * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 : * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28 : * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 : * SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include "vfkreader.h"
33 : #include "vfkreaderp.h"
34 :
35 : #include "cpl_conv.h"
36 : #include "cpl_error.h"
37 : #include "cpl_string.h"
38 :
39 : #define SUPPORT_GEOMETRY
40 :
41 : #ifdef SUPPORT_GEOMETRY
42 : # include "ogr_geometry.h"
43 : #endif
44 :
45 : static char *GetDataBlockName(const char *);
46 :
47 : /*!
48 : \brief IVFKReader desctructor
49 : */
50 2 : IVFKReader::~IVFKReader()
51 : {
52 2 : }
53 :
54 : /*!
55 : \brief Create new instance of VFKReader
56 :
57 : \return pointer to VFKReader instance
58 : */
59 2 : IVFKReader *CreateVFKReader(const char *pszFilename)
60 : {
61 : #ifdef HAVE_SQLITE
62 2 : return new VFKReaderSQLite(pszFilename);
63 : #else
64 : return new VFKReader(pszFilename);
65 : #endif
66 : }
67 :
68 : /*!
69 : \brief VFKReader constructor
70 : */
71 2 : VFKReader::VFKReader(const char *pszFilename)
72 : {
73 2 : m_nDataBlockCount = 0;
74 2 : m_papoDataBlock = NULL;
75 2 : m_bLatin2 = TRUE; /* encoding ISO-8859-2 or WINDOWS-1250 */
76 :
77 : /* open VFK file for reading */
78 2 : CPLAssert(NULL != pszFilename);
79 2 : m_pszFilename = CPLStrdup(pszFilename);
80 2 : m_poFD = VSIFOpen(m_pszFilename, "rb");
81 2 : if (m_poFD == NULL) {
82 : CPLError(CE_Failure, CPLE_OpenFailed,
83 0 : "Failed to open file %s.", m_pszFilename);
84 : }
85 2 : }
86 :
87 : /*!
88 : \brief VFKReader destructor
89 : */
90 2 : VFKReader::~VFKReader()
91 : {
92 2 : CPLFree(m_pszFilename);
93 :
94 2 : if (m_poFD)
95 2 : VSIFClose(m_poFD);
96 :
97 : /* clear data blocks */
98 124 : for (int i = 0; i < m_nDataBlockCount; i++)
99 122 : delete m_papoDataBlock[i];
100 2 : CPLFree(m_papoDataBlock);
101 2 : }
102 :
103 273 : char *GetDataBlockName(const char *pszLine)
104 : {
105 : int n;
106 : const char *pszLineChar;
107 : char *pszBlockName;
108 :
109 273 : for (pszLineChar = pszLine + 2, n = 0; *pszLineChar != '\0' && *pszLineChar != ';'; pszLineChar++, n++)
110 : ;
111 :
112 273 : if (*pszLineChar == '\0')
113 0 : return NULL;
114 :
115 273 : pszBlockName = (char *) CPLMalloc(n + 1);
116 273 : strncpy(pszBlockName, pszLine + 2, n);
117 273 : pszBlockName[n] = '\0';
118 :
119 273 : return pszBlockName;
120 : }
121 :
122 : /*!
123 : \brief Read a line from file
124 :
125 : \param bRecode do recoding
126 :
127 : \return a NULL terminated string which should be freed with CPLFree().
128 : */
129 640 : char *VFKReader::ReadLine(bool bRecode)
130 : {
131 : const char *pszRawLine;
132 : char *pszLine;
133 :
134 640 : pszRawLine = CPLReadLine(m_poFD);
135 640 : if (pszRawLine == NULL)
136 0 : return NULL;
137 :
138 640 : if (bRecode)
139 : pszLine = CPLRecode(pszRawLine,
140 : m_bLatin2 ? "ISO-8859-2" : "WINDOWS-1250",
141 0 : CPL_ENC_UTF8);
142 : else {
143 640 : pszLine = (char *) CPLMalloc(strlen(pszRawLine) + 1);
144 640 : strcpy(pszLine, pszRawLine);
145 : }
146 :
147 640 : return pszLine;
148 : }
149 :
150 : /*!
151 : \brief Load data block definitions (&B)
152 :
153 : Call VFKReader::OpenFile() before this function.
154 :
155 : \return number of data blocks or -1 on error
156 : */
157 1 : int VFKReader::ReadDataBlocks()
158 : {
159 : char *pszLine, *pszBlockName;
160 :
161 : IVFKDataBlock *poNewDataBlock;
162 :
163 1 : CPLAssert(NULL != m_pszFilename);
164 :
165 1 : VSIFSeek(m_poFD, 0, SEEK_SET);
166 129 : while ((pszLine = ReadLine()) != NULL) {
167 128 : if (strlen(pszLine) < 2 || pszLine[0] != '&')
168 0 : continue;
169 128 : if (pszLine[1] == 'B') {
170 61 : pszBlockName = GetDataBlockName(pszLine);
171 61 : if (pszBlockName == NULL) {
172 : CPLError(CE_Failure, CPLE_NotSupported,
173 0 : "Corrupted data - line\n%s\n", pszLine);
174 0 : return -1;
175 : }
176 61 : poNewDataBlock = (IVFKDataBlock *) CreateDataBlock(pszBlockName);
177 61 : CPLFree(pszBlockName);
178 61 : poNewDataBlock->SetGeometryType();
179 61 : poNewDataBlock->SetProperties(pszLine);
180 61 : AddDataBlock(poNewDataBlock, pszLine);
181 : }
182 67 : else if (pszLine[1] == 'H') {
183 : /* header - metadata */
184 13 : AddInfo(pszLine);
185 : }
186 54 : else if (pszLine[1] == 'K' && strlen(pszLine) == 2) {
187 : /* end of file */
188 1 : CPLFree(pszLine);
189 1 : break;
190 : }
191 127 : CPLFree(pszLine);
192 : }
193 :
194 1 : return m_nDataBlockCount;
195 : }
196 :
197 :
198 : /*!
199 : \brief Load data records (&D)
200 :
201 : Call VFKReader::OpenFile() before this function.
202 :
203 : \return number of data records or -1 on error
204 : */
205 4 : int VFKReader::ReadDataRecords(IVFKDataBlock *poDataBlock)
206 : {
207 : const char *pszName;
208 : char *pszBlockName, *pszLine;
209 : int nLength, iLine;
210 :
211 4 : CPLString pszMultiLine;
212 :
213 : VFKFeature *poNewFeature;
214 :
215 4 : if (poDataBlock->GetFeatureCount() >= 0)
216 0 : return -1;
217 :
218 4 : poDataBlock->SetFeatureCount(0);
219 4 : poDataBlock->SetMaxFID(0);
220 4 : pszName = poDataBlock->GetName();
221 :
222 4 : VSIFSeek(m_poFD, 0, SEEK_SET);
223 4 : iLine = 0;
224 516 : while ((pszLine = ReadLine()) != NULL) {
225 512 : iLine++;
226 512 : nLength = strlen(pszLine);
227 512 : if (nLength < 2)
228 0 : continue;
229 :
230 512 : if (pszLine[1] == 'D') {
231 212 : pszBlockName = GetDataBlockName(pszLine);
232 212 : if (pszBlockName && EQUAL(pszBlockName, pszName)) {
233 : /* merge lines if needed */
234 53 : if (pszLine[nLength - 2] == '\302' &&
235 0 : pszLine[nLength - 1] == '\244') {
236 :
237 : /* remove 0302 0244 (currency sign) from string */
238 0 : pszLine[nLength - 2] = '\0';
239 :
240 0 : pszMultiLine.clear();
241 0 : pszMultiLine = pszLine;
242 0 : CPLFree(pszLine);
243 :
244 0 : while ((pszLine = ReadLine()) != NULL &&
245 0 : pszLine[strlen(pszLine) - 2] == '\302' &&
246 0 : pszLine[strlen(pszLine) - 1] == '\244') {
247 : /* append line */
248 0 : pszMultiLine += pszLine;
249 : /* remove 0302 0244 (currency sign) from string */
250 0 : pszMultiLine[strlen(pszLine) - 2] = '\0';
251 :
252 0 : CPLFree(pszLine);
253 : }
254 0 : pszMultiLine += pszLine;
255 0 : CPLFree(pszLine);
256 :
257 0 : nLength = pszMultiLine.size();
258 0 : pszLine = (char *) CPLMalloc(nLength + 1);
259 0 : strncpy(pszLine, pszMultiLine.c_str(), nLength);
260 0 : pszLine[nLength] = '\0';
261 : }
262 :
263 53 : poNewFeature = new VFKFeature(poDataBlock);
264 106 : if (poNewFeature->SetProperties(pszLine))
265 53 : AddFeature(poDataBlock, poNewFeature);
266 : else
267 : CPLError(CE_Warning, CPLE_AppDefined,
268 0 : "Invalid VFK data record skipped (line %d).\n%s\n", iLine, pszLine);
269 : }
270 212 : CPLFree(pszBlockName);
271 : }
272 300 : else if (pszLine[1] == 'K' && strlen(pszLine) == 2) {
273 : /* end of file */
274 4 : CPLFree(pszLine);
275 4 : break;
276 : }
277 508 : CPLFree(pszLine);
278 : }
279 :
280 : CPLDebug("OGR_VFK", "VFKReader::ReadDataRecords(): name=%s n=%d",
281 4 : poDataBlock->GetName(), poDataBlock->GetFeatureCount());
282 :
283 4 : return poDataBlock->GetFeatureCount();
284 : }
285 :
286 0 : IVFKDataBlock *VFKReader::CreateDataBlock(const char *pszBlockName)
287 : {
288 0 : return (IVFKDataBlock *) new VFKDataBlock(pszBlockName, (IVFKReader *) this);
289 : }
290 :
291 : /*!
292 : \brief Add new data block
293 :
294 : \param poNewDataBlock pointer to VFKDataBlock instance
295 : \param pszDefn unused (FIXME ?)
296 : */
297 122 : void VFKReader::AddDataBlock(IVFKDataBlock *poNewDataBlock, const char *pszDefn)
298 : {
299 122 : m_nDataBlockCount++;
300 :
301 : m_papoDataBlock = (IVFKDataBlock **)
302 122 : CPLRealloc(m_papoDataBlock, sizeof (IVFKDataBlock *) * m_nDataBlockCount);
303 122 : m_papoDataBlock[m_nDataBlockCount-1] = poNewDataBlock;
304 122 : }
305 :
306 : /*!
307 : \brief Add feature
308 :
309 : \param poDataBlock pointer to VFKDataBlock instance
310 : \param poFeature pointer to VFKFeature instance
311 : */
312 0 : void VFKReader::AddFeature(IVFKDataBlock *poDataBlock, VFKFeature *poFeature)
313 : {
314 0 : poDataBlock->AddFeature(poFeature);
315 0 : }
316 :
317 : /*!
318 : \brief Get data block
319 :
320 : \param i index (starting with 0)
321 :
322 : \return pointer to VFKDataBlock instance or NULL on failure
323 : */
324 4167 : IVFKDataBlock *VFKReader::GetDataBlock(int i) const
325 : {
326 4167 : if (i < 0 || i >= m_nDataBlockCount)
327 0 : return NULL;
328 :
329 4167 : return m_papoDataBlock[i];
330 : }
331 :
332 : /*!
333 : \brief Get data block
334 :
335 : \param pszName data block name
336 :
337 : \return pointer to VFKDataBlock instance or NULL on failure
338 : */
339 125 : IVFKDataBlock *VFKReader::GetDataBlock(const char *pszName) const
340 : {
341 3920 : for (int i = 0; i < m_nDataBlockCount; i++) {
342 3920 : if (EQUAL(GetDataBlock(i)->GetName(), pszName))
343 125 : return GetDataBlock(i);
344 : }
345 :
346 0 : return NULL;
347 : }
348 :
349 : /*!
350 : \brief Load geometry (loop datablocks)
351 :
352 : \return number of invalid features
353 : */
354 0 : int VFKReader::LoadGeometry()
355 : {
356 : long int nfeatures;
357 :
358 0 : nfeatures = 0;
359 0 : for (int i = 0; i < m_nDataBlockCount; i++) {
360 0 : nfeatures += m_papoDataBlock[i]->LoadGeometry();
361 : }
362 :
363 0 : CPLDebug("OGR_VFK", "VFKReader::LoadGeometry(): invalid=%ld", nfeatures);
364 :
365 0 : return nfeatures;
366 : }
367 :
368 : /*!
369 : \brief Add info
370 :
371 : \param pszLine pointer to line
372 : */
373 13 : void VFKReader::AddInfo(const char *pszLine)
374 : {
375 : int iKeyLength, iValueLength;
376 : char *pszKey, *pszValue;
377 : const char *poChar, *poKey, *poValue;
378 13 : CPLString key, value;
379 :
380 13 : poChar = poKey = pszLine + 2; /* &H */
381 13 : iKeyLength = 0;
382 103 : while (*poChar != '\0' && *poChar != ';') {
383 77 : iKeyLength++;
384 77 : poChar ++;
385 : }
386 13 : if (*poChar == '\0')
387 : return;
388 :
389 13 : pszKey = (char *) CPLMalloc(iKeyLength + 1);
390 13 : strncpy(pszKey, poKey, iKeyLength);
391 13 : pszKey[iKeyLength] = '\0';
392 :
393 13 : poValue = ++poChar; /* skip ';' */
394 13 : iValueLength = 0;
395 1177 : while (*poChar != '\0') {
396 1151 : iValueLength++;
397 1151 : poChar++;
398 : }
399 :
400 13 : pszValue = (char *) CPLMalloc(iValueLength + 1);
401 13 : strncpy(pszValue, poValue, iValueLength);
402 13 : pszValue[iValueLength] = '\0';
403 :
404 13 : poInfo[pszKey] = pszValue;
405 :
406 13 : if (EQUAL(pszKey, "CODEPAGE")) {
407 1 : if (!EQUAL(pszValue, "\"WE8ISO8859P2\""))
408 0 : m_bLatin2 = FALSE;
409 : }
410 :
411 13 : CPLFree(pszKey);
412 13 : CPLFree(pszValue);
413 : }
414 :
415 : /*!
416 : \brief Get info
417 :
418 : \param key key string
419 :
420 : \return pointer to value string or NULL if key not found
421 : */
422 0 : const char *VFKReader::GetInfo(const char *key)
423 : {
424 0 : if (poInfo.find(key) == poInfo.end())
425 0 : return NULL;
426 :
427 0 : return poInfo[key].c_str();
428 : }
|