1 : /******************************************************************************
2 : * $Id: vfkreader.cpp 18470 2010-01-07 21:41:20Z 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 2 : 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 2 : }
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 : VSIFClose(fp);
147 : CPLError(CE_Failure, CPLE_AppDefined,
148 0 : "Read failed on %s.", m_pszFilename);
149 0 : return FALSE;
150 : }
151 :
152 1 : m_pszWholeText[nLength] = '\0';
153 :
154 1 : VSIFClose(fp);
155 :
156 : /* split lines */
157 : /* TODO: reduce chars */
158 14369 : for (char *poChar = m_pszWholeText; *poChar != '\0'; poChar++) {
159 14368 : if (*poChar == '\244') {
160 0 : *(poChar++) = ' '; // \r
161 0 : *(poChar++) = ' '; // \n
162 0 : *poChar = ' ';
163 : }
164 : }
165 :
166 1 : CPLDebug("OGR_VFK", "VFKReader::LoadData(): length=%ld", nLength);
167 :
168 1 : return TRUE;
169 : }
170 :
171 114 : static const char *GetDataBlockName(const char *pszLine)
172 : {
173 : int n;
174 : const char *pszLineChar;
175 : char *pszBlockName;
176 :
177 114 : for (pszLineChar = pszLine + 2, n = 0; *pszLineChar != ';'; pszLineChar++, n++)
178 : ;
179 114 : pszBlockName = (char *) CPLMalloc(n+1);
180 114 : strncpy(pszBlockName, pszLine + 2, n);
181 114 : pszBlockName[n] = '\0';
182 :
183 114 : return pszBlockName;
184 : }
185 :
186 : /*!
187 : \brief Get data blocks (&B)
188 :
189 : Call LoadData() before this function.
190 :
191 : \return FALSE on error
192 : \return TRUE on success
193 : */
194 1 : int VFKReader::LoadDataBlocks()
195 : {
196 : char *pszChar;
197 : char *pszLine;
198 : char *pszBlockName;
199 : int nRow;
200 :
201 : VFKDataBlock *poNewDataBlock;
202 :
203 1 : poNewDataBlock = NULL;
204 1 : pszBlockName = NULL;
205 1 : nRow = 0;
206 :
207 : /* read lines */
208 1 : pszChar = m_pszWholeText;
209 1 : pszLine = m_pszWholeText;
210 14241 : while (pszLine) {
211 14240 : if (*pszChar == '\r' && *(pszChar+1) == '\n') {
212 128 : nRow++;
213 189 : if (*pszLine == '&' && *(pszLine+1) == 'B') {
214 : /* add data block */
215 61 : pszBlockName = (char *) GetDataBlockName(pszLine);
216 61 : poNewDataBlock = new VFKDataBlock(pszBlockName, this);
217 61 : CPLFree(pszBlockName);
218 61 : pszBlockName = NULL;
219 61 : poNewDataBlock->SetGeometryType();
220 61 : poNewDataBlock->SetProperties(pszLine);
221 61 : AddDataBlock(poNewDataBlock);
222 : }
223 120 : else if (*pszLine == '&' && *(pszLine+1) == 'D') {
224 : /* data row */
225 53 : pszBlockName = (char*) GetDataBlockName(pszLine);
226 53 : poNewDataBlock = GetDataBlock(pszBlockName);
227 53 : if (poNewDataBlock == NULL) {
228 0 : if (!EQUAL(pszBlockName, "KATUZE")) {
229 : /* ignore KATUZE block */
230 : CPLError(CE_Warning, CPLE_AppDefined,
231 0 : "Data block '%s' not found.\n", pszBlockName);
232 : }
233 : }
234 : else {
235 53 : poNewDataBlock->AddFeature(pszLine);
236 53 : CPLFree(pszBlockName);
237 53 : pszBlockName = NULL;
238 : }
239 : }
240 27 : else if (*pszLine == '&' && *(pszLine+1) == 'H') {
241 : /* header - metadata */
242 13 : AddInfo(pszLine);
243 : }
244 1 : else if (*pszLine == '&' && *(pszLine+1) == 'K') {
245 : /* end of file */
246 1 : break;
247 : }
248 127 : pszChar++;
249 127 : pszLine = pszChar + 1;
250 : }
251 14239 : pszChar++;
252 : }
253 :
254 1 : if (pszBlockName)
255 0 : CPLFree(pszBlockName);
256 :
257 1 : return TRUE;
258 : }
259 :
260 : /*!
261 : \brief Add new data block
262 :
263 : \param poNewDataBlock pointer to VFKDataBlock instance
264 :
265 : \return number of registred data blocks
266 : */
267 61 : int VFKReader::AddDataBlock(VFKDataBlock *poNewDataBlock)
268 : {
269 61 : m_nDataBlockCount++;
270 :
271 : // CPLDebug("OGR_VFK", "VFKReader::AddDataBlock(): i=%d", m_nDataBlockCount);
272 :
273 : m_papoDataBlock = (VFKDataBlock **)
274 61 : CPLRealloc(m_papoDataBlock, sizeof (VFKDataBlock *) * m_nDataBlockCount);
275 61 : m_papoDataBlock[m_nDataBlockCount-1] = poNewDataBlock;
276 :
277 61 : return m_nDataBlockCount;
278 : }
279 :
280 : /*!
281 : \brief Get data block
282 :
283 : \param i index (starting with 0)
284 :
285 : \return pointer to VFKDataBlock instance
286 : \return NULL on failure
287 : */
288 4587 : VFKDataBlock *VFKReader::GetDataBlock(int i) const
289 : {
290 4587 : if (i < 0 || i >= m_nDataBlockCount)
291 0 : return NULL;
292 :
293 4587 : return m_papoDataBlock[i];
294 : }
295 :
296 : /*!
297 : \brief Get data block
298 :
299 : \param pszName data block name
300 :
301 : \return pointer to VFKDataBlock instance
302 : \return NULL on failure
303 : */
304 117 : VFKDataBlock *VFKReader::GetDataBlock(const char *pszName) const
305 : {
306 4409 : for (int i = 0; i < m_nDataBlockCount; i++) {
307 4409 : if (EQUAL(GetDataBlock(i)->GetName(), pszName))
308 117 : return GetDataBlock(i);
309 : }
310 :
311 0 : return NULL;
312 : }
313 :
314 : /*!
315 : \brief Load geometry (loop datablocks)
316 :
317 : \return number of processed features
318 : */
319 0 : long VFKReader::LoadGeometry()
320 : {
321 : long int nfeatures;
322 :
323 0 : nfeatures = 0;
324 0 : for (int i = 0; i < m_nDataBlockCount; i++) {
325 0 : nfeatures += m_papoDataBlock[i]->LoadGeometry();
326 : }
327 :
328 0 : CPLDebug("OGR_VFK", "VFKReader::LoadGeometry(): n=%ld", nfeatures);
329 :
330 0 : return nfeatures;
331 : }
332 :
333 : /*!
334 : \brief Add info
335 :
336 : \param pszLine pointer to line
337 : */
338 13 : void VFKReader::AddInfo(const char *pszLine)
339 : {
340 : int iKeyLength, iValueLength;
341 : char *pszKey, *pszValue;
342 : const char *poChar, *poKey, *poValue;
343 13 : std::string key, value;
344 :
345 13 : poChar = poKey = pszLine + 2; /* &H */
346 13 : iKeyLength = 0;
347 103 : while (*(poChar++) != ';')
348 77 : iKeyLength++;
349 13 : pszKey = (char *) CPLMalloc(iKeyLength + 1);
350 13 : strncpy(pszKey, poKey, iKeyLength);
351 13 : pszKey[iKeyLength] = '\0';
352 :
353 13 : poValue = poChar;
354 13 : iValueLength = 0;
355 1177 : while(*poChar != '\r' && *(poChar+1) != '\n') {
356 1151 : iValueLength++;
357 1151 : poChar++;
358 : }
359 13 : pszValue = (char *) CPLMalloc(iValueLength + 1);
360 13 : strncpy(pszValue, poValue, iValueLength);
361 13 : pszValue[iValueLength] = '\0';
362 :
363 13 : poInfo[pszKey] = pszValue;
364 :
365 13 : CPLFree(pszKey);
366 13 : CPLFree(pszValue);
367 13 : }
368 :
369 : /*!
370 : \brief Get info
371 :
372 : \param key key string
373 :
374 : \return pointer to value string
375 : \return NULL if key not found
376 : */
377 0 : const char *VFKReader::GetInfo(const char *key)
378 : {
379 0 : if (poInfo.find(key) == poInfo.end())
380 0 : return NULL;
381 :
382 0 : return poInfo[key].c_str();
383 : }
|