1 : /******************************************************************************
2 : * $Id: vfkreader.cpp 18566 2010-01-16 16:36:45Z 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, 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 :
38 : #define SUPPORT_GEOMETRY
39 :
40 : #ifdef SUPPORT_GEOMETRY
41 : # include "ogr_geometry.h"
42 : #endif
43 :
44 : /*!
45 : \brief IVFKReader desctructor
46 : */
47 1 : IVFKReader::~IVFKReader()
48 : {
49 1 : }
50 :
51 : /*!
52 : \brief Create new instance of VFKReader
53 :
54 : \return pointer to VFKReader instance
55 : */
56 1 : IVFKReader *CreateVFKReader()
57 : {
58 1 : return new VFKReader();
59 : }
60 :
61 : /*!
62 : \brief VFKReader constructor
63 : */
64 1 : VFKReader::VFKReader()
65 : {
66 1 : m_pszFilename = NULL;
67 :
68 1 : m_pszWholeText = NULL;
69 :
70 1 : m_nDataBlockCount = 0;
71 1 : m_papoDataBlock = NULL;
72 1 : }
73 :
74 : /*!
75 : \brief VFKReader destructor
76 : */
77 1 : VFKReader::~VFKReader()
78 : {
79 1 : CPLFree(m_pszFilename);
80 :
81 1 : VSIFree(m_pszWholeText);
82 :
83 : /* clear data blocks */
84 62 : for (int i = 0; i < m_nDataBlockCount; i++)
85 61 : delete m_papoDataBlock[i];
86 1 : CPLFree(m_papoDataBlock);
87 :
88 1 : m_nDataBlockCount = 0;
89 1 : m_papoDataBlock = NULL;
90 1 : }
91 :
92 : /*!
93 : \brief Set source file
94 :
95 : \param pszFilename source filename
96 : */
97 1 : void VFKReader::SetSourceFile(const char *pszFilename)
98 : {
99 1 : CPLFree(m_pszFilename);
100 1 : m_pszFilename = CPLStrdup(pszFilename);
101 1 : }
102 :
103 : /*!
104 : \brief Read the file & load the data
105 :
106 : \param pszFile pointer to a filename
107 :
108 : \return TRUE on success
109 : \return FALSE on error
110 : */
111 1 : int VFKReader::LoadData()
112 : {
113 : FILE *fp;
114 : long nLength;
115 :
116 1 : if (m_pszFilename == NULL)
117 0 : return FALSE;
118 :
119 : /* load vfk file */
120 1 : fp = VSIFOpen(m_pszFilename, "rb");
121 1 : if (fp == NULL) {
122 : CPLError(CE_Failure, CPLE_OpenFailed,
123 0 : "Failed to open file %s.", m_pszFilename);
124 0 : return FALSE;
125 : }
126 :
127 : /* get file length */
128 1 : VSIFSeek(fp, 0, SEEK_END);
129 1 : nLength = VSIFTell(fp);
130 1 : VSIFSeek(fp, 0, SEEK_SET);
131 :
132 : /* read file - is necessary to read the whole file? */
133 1 : m_pszWholeText = (char *) VSIMalloc(nLength+1);
134 :
135 1 : if (m_pszWholeText == NULL) {
136 : CPLError(CE_Failure, CPLE_AppDefined,
137 : "Failed to allocate %ld byte buffer for %s,\n"
138 : "is this really a VFK file?",
139 0 : nLength, m_pszFilename);
140 0 : VSIFClose(fp);
141 0 : return FALSE;
142 : }
143 :
144 1 : if (VSIFRead(m_pszWholeText, nLength, 1, fp) != 1) {
145 0 : VSIFree(m_pszWholeText);
146 0 : m_pszWholeText = NULL;
147 0 : VSIFClose(fp);
148 : CPLError(CE_Failure, CPLE_AppDefined,
149 0 : "Read failed on %s.", m_pszFilename);
150 0 : return FALSE;
151 : }
152 :
153 1 : m_pszWholeText[nLength] = '\0';
154 :
155 1 : VSIFClose(fp);
156 :
157 : /* split lines */
158 : /* TODO: reduce chars */
159 14369 : for (char *poChar = m_pszWholeText; *poChar != '\0'; poChar++) {
160 14368 : if (*poChar == '\244' && *(poChar+1) != '\0' && *(poChar+2) != '\0') {
161 0 : *(poChar++) = ' '; // \r
162 0 : *(poChar++) = ' '; // \n
163 0 : *poChar = ' ';
164 : }
165 : }
166 :
167 1 : CPLDebug("OGR_VFK", "VFKReader::LoadData(): length=%ld", nLength);
168 :
169 1 : return TRUE;
170 : }
171 :
172 114 : static char *GetDataBlockName(const char *pszLine)
173 : {
174 : int n;
175 : const char *pszLineChar;
176 : char *pszBlockName;
177 :
178 114 : for (pszLineChar = pszLine + 2, n = 0; *pszLineChar != '\0' && *pszLineChar != ';'; pszLineChar++, n++)
179 : ;
180 :
181 114 : if (*pszLineChar == '\0')
182 0 : return NULL;
183 :
184 114 : pszBlockName = (char *) CPLMalloc(n+1);
185 114 : strncpy(pszBlockName, pszLine + 2, n);
186 114 : pszBlockName[n] = '\0';
187 :
188 114 : return pszBlockName;
189 : }
190 :
191 : /*!
192 : \brief Get data blocks (&B)
193 :
194 : Call LoadData() before this function.
195 :
196 : \return FALSE on error
197 : \return TRUE on success
198 : */
199 1 : int VFKReader::LoadDataBlocks()
200 : {
201 : char *pszChar;
202 : char *pszLine;
203 : char *pszBlockName;
204 : int nRow;
205 :
206 : VFKDataBlock *poNewDataBlock;
207 :
208 1 : if (m_pszWholeText == NULL)
209 0 : return FALSE;
210 :
211 1 : poNewDataBlock = NULL;
212 1 : pszBlockName = NULL;
213 1 : nRow = 0;
214 :
215 : /* read lines */
216 1 : pszChar = m_pszWholeText;
217 1 : pszLine = m_pszWholeText;
218 14241 : while (*pszChar != '\0') {
219 14240 : if (*pszChar == '\r' && *(pszChar+1) == '\n') {
220 128 : nRow++;
221 189 : if (*pszLine == '&' && *(pszLine+1) == 'B') {
222 : /* add data block */
223 61 : pszBlockName = GetDataBlockName(pszLine);
224 61 : if (pszBlockName == NULL)
225 0 : break;
226 :
227 61 : poNewDataBlock = new VFKDataBlock(pszBlockName, this);
228 61 : CPLFree(pszBlockName);
229 61 : pszBlockName = NULL;
230 61 : poNewDataBlock->SetGeometryType();
231 61 : poNewDataBlock->SetProperties(pszLine);
232 61 : AddDataBlock(poNewDataBlock);
233 : }
234 120 : else if (*pszLine == '&' && *(pszLine+1) == 'D') {
235 : /* data row */
236 53 : pszBlockName = GetDataBlockName(pszLine);
237 53 : if (pszBlockName == NULL)
238 0 : break;
239 :
240 53 : poNewDataBlock = GetDataBlock(pszBlockName);
241 53 : if (poNewDataBlock == NULL) {
242 0 : if (!EQUAL(pszBlockName, "KATUZE")) {
243 : /* ignore KATUZE block */
244 : CPLError(CE_Warning, CPLE_AppDefined,
245 0 : "Data block '%s' not found.\n", pszBlockName);
246 : }
247 : }
248 : else
249 53 : poNewDataBlock->AddFeature(pszLine);
250 :
251 53 : CPLFree(pszBlockName);
252 53 : pszBlockName = NULL;
253 : }
254 27 : else if (*pszLine == '&' && *(pszLine+1) == 'H') {
255 : /* header - metadata */
256 13 : AddInfo(pszLine);
257 : }
258 1 : else if (*pszLine == '&' && *(pszLine+1) == 'K') {
259 : /* end of file */
260 1 : break;
261 : }
262 127 : pszChar++;
263 127 : pszLine = pszChar + 1;
264 : }
265 14239 : pszChar++;
266 : }
267 :
268 1 : return TRUE;
269 : }
270 :
271 : /*!
272 : \brief Add new data block
273 :
274 : \param poNewDataBlock pointer to VFKDataBlock instance
275 :
276 : \return number of registred data blocks
277 : */
278 61 : int VFKReader::AddDataBlock(VFKDataBlock *poNewDataBlock)
279 : {
280 61 : m_nDataBlockCount++;
281 :
282 : // CPLDebug("OGR_VFK", "VFKReader::AddDataBlock(): i=%d", m_nDataBlockCount);
283 :
284 : m_papoDataBlock = (VFKDataBlock **)
285 61 : CPLRealloc(m_papoDataBlock, sizeof (VFKDataBlock *) * m_nDataBlockCount);
286 61 : m_papoDataBlock[m_nDataBlockCount-1] = poNewDataBlock;
287 :
288 61 : return m_nDataBlockCount;
289 : }
290 :
291 : /*!
292 : \brief Get data block
293 :
294 : \param i index (starting with 0)
295 :
296 : \return pointer to VFKDataBlock instance
297 : \return NULL on failure
298 : */
299 4587 : VFKDataBlock *VFKReader::GetDataBlock(int i) const
300 : {
301 4587 : if (i < 0 || i >= m_nDataBlockCount)
302 0 : return NULL;
303 :
304 4587 : return m_papoDataBlock[i];
305 : }
306 :
307 : /*!
308 : \brief Get data block
309 :
310 : \param pszName data block name
311 :
312 : \return pointer to VFKDataBlock instance
313 : \return NULL on failure
314 : */
315 117 : VFKDataBlock *VFKReader::GetDataBlock(const char *pszName) const
316 : {
317 4409 : for (int i = 0; i < m_nDataBlockCount; i++) {
318 4409 : if (EQUAL(GetDataBlock(i)->GetName(), pszName))
319 117 : return GetDataBlock(i);
320 : }
321 :
322 0 : return NULL;
323 : }
324 :
325 : /*!
326 : \brief Load geometry (loop datablocks)
327 :
328 : \return number of processed features
329 : */
330 0 : long VFKReader::LoadGeometry()
331 : {
332 : long int nfeatures;
333 :
334 0 : nfeatures = 0;
335 0 : for (int i = 0; i < m_nDataBlockCount; i++) {
336 0 : nfeatures += m_papoDataBlock[i]->LoadGeometry();
337 : }
338 :
339 0 : CPLDebug("OGR_VFK", "VFKReader::LoadGeometry(): n=%ld", nfeatures);
340 :
341 0 : return nfeatures;
342 : }
343 :
344 : /*!
345 : \brief Add info
346 :
347 : \param pszLine pointer to line
348 : */
349 13 : void VFKReader::AddInfo(const char *pszLine)
350 : {
351 : int iKeyLength, iValueLength;
352 : char *pszKey, *pszValue;
353 : const char *poChar, *poKey, *poValue;
354 13 : std::string key, value;
355 :
356 13 : poChar = poKey = pszLine + 2; /* &H */
357 13 : iKeyLength = 0;
358 103 : while (*poChar != '\0' && *poChar != ';')
359 : {
360 77 : iKeyLength++;
361 77 : poChar ++;
362 : }
363 13 : if( *poChar == '\0' )
364 : return;
365 :
366 13 : pszKey = (char *) CPLMalloc(iKeyLength + 1);
367 13 : strncpy(pszKey, poKey, iKeyLength);
368 13 : pszKey[iKeyLength] = '\0';
369 :
370 13 : poValue = poChar;
371 13 : iValueLength = 0;
372 1190 : while(*poChar != '\0' && !(*poChar == '\r' && *(poChar+1) == '\n')) {
373 1164 : iValueLength++;
374 1164 : poChar++;
375 : }
376 13 : if( *poChar == '\0' )
377 : {
378 0 : CPLFree(pszKey);
379 : return;
380 : }
381 :
382 13 : pszValue = (char *) CPLMalloc(iValueLength + 1);
383 13 : strncpy(pszValue, poValue, iValueLength);
384 13 : pszValue[iValueLength] = '\0';
385 :
386 13 : poInfo[pszKey] = pszValue;
387 :
388 13 : CPLFree(pszKey);
389 13 : CPLFree(pszValue);
390 : }
391 :
392 : /*!
393 : \brief Get info
394 :
395 : \param key key string
396 :
397 : \return pointer to value string
398 : \return NULL if key not found
399 : */
400 0 : const char *VFKReader::GetInfo(const char *key)
401 : {
402 0 : if (poInfo.find(key) == poInfo.end())
403 0 : return NULL;
404 :
405 0 : return poInfo[key].c_str();
406 : }
|