1 : /******************************************************************************
2 : * $Id: vfkreader.cpp 24217 2012-04-11 14:25:09Z martinl $
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 : \return a NULL terminated string which should be freed with CPLFree().
126 : */
127 640 : char *VFKReader::ReadLine()
128 : {
129 : const char *pszRawLine;
130 : char *pszLine;
131 :
132 640 : pszRawLine = CPLReadLine(m_poFD);
133 640 : if (pszRawLine == NULL)
134 0 : return NULL;
135 :
136 : pszLine = CPLRecode(pszRawLine,
137 : m_bLatin2 ? "ISO-8859-2" : "WINDOWS-1250",
138 640 : CPL_ENC_UTF8);
139 :
140 640 : return pszLine;
141 : }
142 :
143 : /*!
144 : \brief Load data block definitions (&B)
145 :
146 : Call VFKReader::OpenFile() before this function.
147 :
148 : \return number of data blocks
149 : \return -1 on error
150 : */
151 1 : int VFKReader::ReadDataBlocks()
152 : {
153 : char *pszLine, *pszBlockName;
154 :
155 : IVFKDataBlock *poNewDataBlock;
156 :
157 1 : CPLAssert(NULL != m_pszFilename);
158 :
159 1 : VSIFSeek(m_poFD, 0, SEEK_SET);
160 129 : while ((pszLine = ReadLine()) != NULL) {
161 128 : if (strlen(pszLine) < 2 || pszLine[0] != '&')
162 0 : continue;
163 128 : if (pszLine[1] == 'B') {
164 61 : pszBlockName = GetDataBlockName(pszLine);
165 61 : if (pszBlockName == NULL) {
166 : CPLError(CE_Failure, CPLE_NotSupported,
167 0 : "Corrupted data - line\n%s\n", pszLine);
168 0 : return -1;
169 : }
170 61 : poNewDataBlock = (IVFKDataBlock *) CreateDataBlock(pszBlockName);
171 61 : CPLFree(pszBlockName);
172 61 : poNewDataBlock->SetGeometryType();
173 61 : poNewDataBlock->SetProperties(pszLine);
174 61 : AddDataBlock(poNewDataBlock, pszLine);
175 : }
176 67 : else if (pszLine[1] == 'H') {
177 : /* header - metadata */
178 13 : AddInfo(pszLine);
179 : }
180 54 : else if (pszLine[1] == 'K' && strlen(pszLine) == 2) {
181 : /* end of file */
182 1 : CPLFree(pszLine);
183 1 : break;
184 : }
185 127 : CPLFree(pszLine);
186 : }
187 :
188 1 : return m_nDataBlockCount;
189 : }
190 :
191 :
192 : /*!
193 : \brief Load data records (&D)
194 :
195 : Call VFKReader::OpenFile() before this function.
196 :
197 : \return number of data records
198 : \return -1 on error
199 : */
200 4 : int VFKReader::ReadDataRecords(IVFKDataBlock *poDataBlock)
201 : {
202 : const char *pszName;
203 : char *pszBlockName, *pszLine;
204 : int nLength;
205 :
206 : VFKFeature *poNewFeature;
207 :
208 4 : if (poDataBlock->GetFeatureCount() >= 0)
209 0 : return -1;
210 :
211 4 : poDataBlock->SetFeatureCount(0);
212 4 : poDataBlock->SetMaxFID(0);
213 4 : pszName = poDataBlock->GetName();
214 :
215 4 : VSIFSeek(m_poFD, 0, SEEK_SET);
216 516 : while ((pszLine = ReadLine()) != NULL) {
217 512 : nLength = strlen(pszLine);
218 512 : if (nLength < 2)
219 0 : continue;
220 :
221 512 : if (pszLine[1] == 'D') {
222 212 : pszBlockName = GetDataBlockName(pszLine);
223 212 : if (pszBlockName && EQUAL(pszBlockName, pszName)) {
224 : /* merge lines if needed */
225 53 : if (pszLine[nLength - 2] == '\302' &&
226 0 : pszLine[nLength - 1] == '\244') {
227 :
228 : /* remove 0302 0244 (currency sign) from string */
229 0 : pszLine[nLength - 2] = '\0';
230 :
231 0 : CPLString pszMultiLine(pszLine);
232 0 : CPLFree(pszLine);
233 :
234 0 : while ((pszLine = ReadLine()) != NULL &&
235 0 : pszLine[strlen(pszLine) - 2] == '\302' &&
236 0 : pszLine[strlen(pszLine) - 1] == '\244') {
237 : /* remove 0302 0244 (currency sign) from string */
238 0 : pszLine[strlen(pszLine) - 2] = '\0';
239 :
240 : /* append line */
241 0 : pszMultiLine += pszLine;
242 0 : CPLFree(pszLine);
243 : }
244 0 : pszMultiLine += pszLine;
245 0 : CPLFree(pszLine);
246 :
247 0 : nLength = pszMultiLine.size();
248 0 : pszLine = (char *) CPLMalloc(nLength + 1);
249 0 : strncpy(pszLine, pszMultiLine.c_str(), nLength);
250 0 : pszLine[nLength] = '\0';
251 : }
252 :
253 53 : poNewFeature = new VFKFeature(poDataBlock);
254 53 : poNewFeature->SetProperties(pszLine);
255 53 : AddFeature(poDataBlock, poNewFeature);
256 : }
257 212 : CPLFree(pszBlockName);
258 : }
259 300 : else if (pszLine[1] == 'K' && strlen(pszLine) == 2) {
260 : /* end of file */
261 4 : CPLFree(pszLine);
262 4 : break;
263 : }
264 508 : CPLFree(pszLine);
265 : }
266 :
267 4 : return poDataBlock->GetFeatureCount();
268 : }
269 :
270 0 : IVFKDataBlock *VFKReader::CreateDataBlock(const char *pszBlockName)
271 : {
272 0 : return (IVFKDataBlock *) new VFKDataBlock(pszBlockName, (IVFKReader *) this);
273 : }
274 :
275 : /*!
276 : \brief Add new data block
277 :
278 : \param poNewDataBlock pointer to VFKDataBlock instance
279 :
280 : \return number of registred data blocks
281 : */
282 122 : void VFKReader::AddDataBlock(IVFKDataBlock *poNewDataBlock, const char *pszDefn)
283 : {
284 122 : m_nDataBlockCount++;
285 :
286 : m_papoDataBlock = (IVFKDataBlock **)
287 122 : CPLRealloc(m_papoDataBlock, sizeof (IVFKDataBlock *) * m_nDataBlockCount);
288 122 : m_papoDataBlock[m_nDataBlockCount-1] = poNewDataBlock;
289 122 : }
290 :
291 : /*!
292 : \brief Add feature
293 :
294 : \param poNewDataBlock pointer to VFKDataBlock instance
295 : \param poNewFeature pointer to VFKFeature instance
296 : */
297 0 : void VFKReader::AddFeature(IVFKDataBlock *poDataBlock, VFKFeature *poFeature)
298 : {
299 0 : poDataBlock->AddFeature(poFeature);
300 0 : }
301 :
302 : /*!
303 : \brief Get data block
304 :
305 : \param i index (starting with 0)
306 :
307 : \return pointer to VFKDataBlock instance
308 : \return NULL on failure
309 : */
310 4308 : IVFKDataBlock *VFKReader::GetDataBlock(int i) const
311 : {
312 4308 : if (i < 0 || i >= m_nDataBlockCount)
313 0 : return NULL;
314 :
315 4308 : return m_papoDataBlock[i];
316 : }
317 :
318 : /*!
319 : \brief Get data block
320 :
321 : \param pszName data block name
322 :
323 : \return pointer to VFKDataBlock instance
324 : \return NULL on failure
325 : */
326 128 : IVFKDataBlock *VFKReader::GetDataBlock(const char *pszName) const
327 : {
328 4058 : for (int i = 0; i < m_nDataBlockCount; i++) {
329 4058 : if (EQUAL(GetDataBlock(i)->GetName(), pszName))
330 128 : return GetDataBlock(i);
331 : }
332 :
333 0 : return NULL;
334 : }
335 :
336 : /*!
337 : \brief Load geometry (loop datablocks)
338 :
339 : \return number of invalid features
340 : */
341 0 : int VFKReader::LoadGeometry()
342 : {
343 : long int nfeatures;
344 :
345 0 : nfeatures = 0;
346 0 : for (int i = 0; i < m_nDataBlockCount; i++) {
347 0 : nfeatures += m_papoDataBlock[i]->LoadGeometry();
348 : }
349 :
350 0 : CPLDebug("OGR_VFK", "VFKReader::LoadGeometry(): invalid=%ld", nfeatures);
351 :
352 0 : return nfeatures;
353 : }
354 :
355 : /*!
356 : \brief Add info
357 :
358 : \param pszLine pointer to line
359 : */
360 13 : void VFKReader::AddInfo(const char *pszLine)
361 : {
362 : int iKeyLength, iValueLength;
363 : char *pszKey, *pszValue;
364 : const char *poChar, *poKey, *poValue;
365 13 : CPLString key, value;
366 :
367 13 : poChar = poKey = pszLine + 2; /* &H */
368 13 : iKeyLength = 0;
369 103 : while (*poChar != '\0' && *poChar != ';') {
370 77 : iKeyLength++;
371 77 : poChar ++;
372 : }
373 13 : if (*poChar == '\0')
374 : return;
375 :
376 13 : pszKey = (char *) CPLMalloc(iKeyLength + 1);
377 13 : strncpy(pszKey, poKey, iKeyLength);
378 13 : pszKey[iKeyLength] = '\0';
379 :
380 13 : poValue = ++poChar; /* skip ';' */
381 13 : iValueLength = 0;
382 1178 : while (*poChar != '\0') {
383 1152 : iValueLength++;
384 1152 : poChar++;
385 : }
386 :
387 13 : pszValue = (char *) CPLMalloc(iValueLength + 1);
388 13 : strncpy(pszValue, poValue, iValueLength);
389 13 : pszValue[iValueLength] = '\0';
390 :
391 13 : poInfo[pszKey] = pszValue;
392 :
393 13 : if (EQUAL(pszKey, "CODEPAGE")) {
394 1 : if (!EQUAL(pszValue, "\"WE8ISO8859P2\""))
395 0 : m_bLatin2 = FALSE;
396 : }
397 :
398 13 : CPLFree(pszKey);
399 13 : CPLFree(pszValue);
400 : }
401 :
402 : /*!
403 : \brief Get info
404 :
405 : \param key key string
406 :
407 : \return pointer to value string
408 : \return NULL if key not found
409 : */
410 0 : const char *VFKReader::GetInfo(const char *key)
411 : {
412 0 : if (poInfo.find(key) == poInfo.end())
413 0 : return NULL;
414 :
415 0 : return poInfo[key].c_str();
416 : }
|