1 : /**********************************************************************
2 : * $Id: mitab_miffile.cpp,v 1.49 2008/11/17 22:06:21 aboudreault Exp $
3 : *
4 : * Name: mitab_miffile.cpp
5 : * Project: MapInfo TAB Read/Write library
6 : * Language: C++
7 : * Purpose: Implementation of the MIDFile class.
8 : * To be used by external programs to handle reading/writing of
9 : * features from/to MID/MIF datasets.
10 : * Author: Stephane Villeneuve, stephane.v@videotron.ca
11 : *
12 : **********************************************************************
13 : * Copyright (c) 1999-2003, Stephane Villeneuve
14 : *
15 : * Permission is hereby granted, free of charge, to any person obtaining a
16 : * copy of this software and associated documentation files (the "Software"),
17 : * to deal in the Software without restriction, including without limitation
18 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 : * and/or sell copies of the Software, and to permit persons to whom the
20 : * Software is furnished to do so, subject to the following conditions:
21 : *
22 : * The above copyright notice and this permission notice shall be included
23 : * in all copies or substantial portions of the Software.
24 : *
25 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 : * DEALINGS IN THE SOFTWARE.
32 : **********************************************************************
33 : *
34 : * $Log: mitab_miffile.cpp,v $
35 : * Revision 1.49 2008/11/17 22:06:21 aboudreault
36 : * Added support to use OFTDateTime/OFTDate/OFTTime type when compiled with
37 : * OGR and fixed reading/writing support for these types.
38 : *
39 : * Revision 1.48 2008/09/26 14:40:24 aboudreault
40 : * Fixed bug: MITAB doesn't support writing DateTime type (bug 1948)
41 : *
42 : * Revision 1.47 2008/03/05 20:35:39 dmorissette
43 : * Replace MITAB 1.x SetFeature() with a CreateFeature() for V2.x (bug 1859)
44 : *
45 : * Revision 1.46 2008/02/01 20:30:59 dmorissette
46 : * Use %.15g instead of %.16g as number precision in .MIF output
47 : *
48 : * Revision 1.45 2008/01/29 21:56:39 dmorissette
49 : * Update dataset version properly for Date/Time/DateTime field types (#1754)
50 : *
51 : * Revision 1.44 2008/01/29 20:46:32 dmorissette
52 : * Added support for v9 Time and DateTime fields (byg 1754)
53 : *
54 : * Revision 1.43 2007/09/14 15:35:21 dmorissette
55 : * Fixed problem with MIF parser being confused by special attribute
56 : * names (bug 1795)
57 : *
58 : * Revision 1.42 2007/06/12 13:52:37 dmorissette
59 : * Added IMapInfoFile::SetCharset() method (bug 1734)
60 : *
61 : * Revision 1.41 2005/10/13 20:12:03 fwarmerdam
62 : * layers with just regions can't be set as type wkbPolygon because they may
63 : * have multipolygons (bug GDAL:958)
64 : * http://bugzilla.remotesensing.org/show_bug.cgi?id=958
65 : *
66 : * Revision 1.40 2005/10/12 14:03:02 fwarmerdam
67 : * Fixed problem with white space parsing in mitab_miffile.cpp (bug GDAL:954)
68 : *
69 : * Revision 1.39 2005/10/04 19:36:10 dmorissette
70 : * Added support for reading collections from MIF files (bug 1126)
71 : *
72 : * Revision 1.38 2004/02/27 21:04:14 fwarmerdam
73 : * dont write MIF header if file is readonly - gdal bugzilla 509
74 : *
75 : * Revision 1.37 2003/12/19 07:54:50 fwarmerdam
76 : * write mif header on close if not already written out
77 : *
78 : * Revision 1.36 2003/08/13 02:49:02 dmorissette
79 : * Use tab as default delimiter if not explicitly specified (Anthony D, bug 37)
80 : *
81 : * Revision 1.35 2003/01/30 22:42:39 daniel
82 : * Fixed crash in ParseMIFHeader() when .mif doesn't contain a DATA line
83 : *
84 : * Revision 1.34 2002/09/23 12:53:29 warmerda
85 : * fix memory leak of m_pszIndex
86 : *
87 : * Revision 1.33 2002/05/08 15:10:48 julien
88 : * Implement MIFFile::SetMIFCoordSys in mitab_capi.cpp (Bug 984)
89 : *
90 : * Revision 1.32 2002/04/26 14:16:49 julien
91 : * Finishing the implementation of Multipoint (support for MIF)
92 : *
93 : * Revision 1.31 2001/09/19 21:39:15 warmerda
94 : * get extents efficiently
95 : *
96 : * Revision 1.30 2001/09/19 14:31:22 warmerda
97 : * added m_nPreloadedId to keep track of preloaded line
98 : *
99 : * Revision 1.29 2001/09/14 19:14:43 warmerda
100 : * added attribute query support
101 : *
102 : * Revision 1.28 2001/08/10 17:49:01 warmerda
103 : * fixed a few memory leaks
104 : *
105 : * Revision 1.27 2001/03/15 03:57:51 daniel
106 : * Added implementation for new OGRLayer::GetExtent(), returning data MBR.
107 : *
108 : * Revision 1.26 2001/03/09 04:14:19 daniel
109 : * Fixed problem creating new files with mixed case extensions (e.g. ".Tab")
110 : *
111 : * Revision 1.25 2001/03/09 03:51:48 daniel
112 : * Fixed writing MIF header: missing break; for decimal fields
113 : *
114 : * Revision 1.24 2001/02/27 19:59:05 daniel
115 : * Enabled spatial filter in IMapInfoFile::GetNextFeature(), and avoid
116 : * unnecessary feature cloning in GetNextFeature() and GetFeature()
117 : *
118 : * Revision 1.23 2001/01/23 21:23:42 daniel
119 : * Added projection bounds lookup table, called from TABFile::SetProjInfo()
120 : *
121 : * Revision 1.22 2001/01/22 16:03:58 warmerda
122 : * expanded tabs
123 : *
124 : * Revision 1.21 2000/12/15 05:38:38 daniel
125 : * Produce Warning instead of an error when nWidth>254 in AddFieldNative()
126 : *
127 : * Revision 1.20 2000/11/14 06:15:37 daniel
128 : * Handle '\t' as spaces in parsing, and fixed GotoFeature() to avoid calling
129 : * ResetReading() when reading forward.
130 : *
131 : * Revision 1.19 2000/07/04 01:50:40 warmerda
132 : * Removed unprotected debugging printf.
133 : *
134 : * Revision 1.18 2000/06/28 00:32:04 warmerda
135 : * Make GetFeatureCountByType() actually work if bForce is TRUE
136 : * Collect detailed (by feature type) feature counts in PreParse().
137 : *
138 : * Revision 1.17 2000/04/27 15:46:25 daniel
139 : * Make SetFeatureDefn() use AddFieldNative(), scan field names for invalid
140 : * chars, and map field width=0 (variable length in OGR) to valid defaults
141 : *
142 : * Revision 1.16 2000/03/27 03:37:59 daniel
143 : * Handle bounds in CoordSys for read and write, + handle point SYMBOL line as
144 : * optional + fixed reading of bounds in PreParseFile()
145 : *
146 : * Revision 1.15 2000/02/28 17:05:06 daniel
147 : * Added support for index and unique directives for read and write
148 : *
149 : * Revision 1.14 2000/01/28 07:32:25 daniel
150 : * Validate char field width (must be <= 254 chars)
151 : *
152 : * Revision 1.13 2000/01/24 19:51:33 warmerda
153 : * AddFieldNative should not fail for read-only datasets
154 : *
155 : * Revision 1.12 2000/01/18 23:13:41 daniel
156 : * Implemented AddFieldNative()
157 : *
158 : * ...
159 : *
160 : * Revision 1.1 1999/11/08 04:16:07 stephane
161 : * First Revision
162 : *
163 : **********************************************************************/
164 :
165 : #include "mitab.h"
166 : #include "mitab_utils.h"
167 : #include <ctype.h>
168 :
169 : /*=====================================================================
170 : * class MIFFile
171 : *====================================================================*/
172 :
173 :
174 : /**********************************************************************
175 : * MIFFile::MIFFile()
176 : *
177 : * Constructor.
178 : **********************************************************************/
179 18 : MIFFile::MIFFile()
180 : {
181 18 : m_pszFname = NULL;
182 18 : m_nVersion = 300;
183 :
184 : // Tab is default delimiter in MIF spec if not explicitly specified. Use
185 : // that by default for read mode. In write mode, we will use "," as
186 : // delimiter since it's more common than tab (we do this in Open())
187 18 : m_pszDelimiter = CPLStrdup("\t");
188 :
189 18 : m_pszUnique = NULL;
190 18 : m_pszIndex = NULL;
191 18 : m_pszCoordSys = NULL;
192 :
193 18 : m_paeFieldType = NULL;
194 18 : m_pabFieldIndexed = NULL;
195 18 : m_pabFieldUnique = NULL;
196 :
197 18 : m_dfXMultiplier = 1.0;
198 18 : m_dfYMultiplier = 1.0;
199 18 : m_dfXDisplacement = 0.0;
200 18 : m_dfYDisplacement = 0.0;
201 :
202 18 : m_poMIDFile = NULL;
203 18 : m_poMIFFile = NULL;
204 18 : m_nPreloadedId = 0;
205 :
206 18 : m_poDefn = NULL;
207 18 : m_poSpatialRef = NULL;
208 :
209 18 : m_nCurFeatureId = 0;
210 18 : m_nFeatureCount = 0;
211 18 : m_nWriteFeatureId = -1;
212 18 : m_poCurFeature = NULL;
213 :
214 18 : m_bPreParsed = FALSE;
215 18 : m_nAttribut = 0;
216 18 : m_bHeaderWrote = FALSE;
217 18 : m_nPoints = m_nLines = m_nRegions = m_nTexts = 0;
218 :
219 18 : m_bExtentsSet = FALSE;
220 18 : }
221 :
222 : /**********************************************************************
223 : * MIFFile::~MIFFile()
224 : *
225 : * Destructor.
226 : **********************************************************************/
227 18 : MIFFile::~MIFFile()
228 : {
229 18 : Close();
230 18 : }
231 :
232 : /**********************************************************************
233 : * MIFFile::Open()
234 : *
235 : * Returns 0 on success, -1 on error.
236 : **********************************************************************/
237 : int MIFFile::Open(const char *pszFname, const char *pszAccess,
238 18 : GBool bTestOpenNoError /*=FALSE*/ )
239 : {
240 18 : char *pszTmpFname = NULL;
241 18 : int nFnameLen = 0;
242 :
243 18 : CPLErrorReset();
244 :
245 18 : if (m_poMIDFile)
246 : {
247 : CPLError(CE_Failure, CPLE_FileIO,
248 0 : "Open() failed: object already contains an open file");
249 :
250 0 : return -1;
251 : }
252 :
253 : /*-----------------------------------------------------------------
254 : * Validate access mode
255 : *----------------------------------------------------------------*/
256 18 : if (EQUALN(pszAccess, "r", 1))
257 : {
258 11 : m_eAccessMode = TABRead;
259 11 : pszAccess = "rt";
260 : }
261 7 : else if (EQUALN(pszAccess, "w", 1))
262 : {
263 7 : m_eAccessMode = TABWrite;
264 7 : pszAccess = "wt";
265 :
266 : // In write mode, use "," as delimiter since it's more common than tab
267 7 : CPLFree(m_pszDelimiter);
268 7 : m_pszDelimiter = CPLStrdup(",");
269 : }
270 : else
271 : {
272 0 : if (!bTestOpenNoError)
273 : CPLError(CE_Failure, CPLE_FileIO,
274 0 : "Open() failed: access mode \"%s\" not supported", pszAccess);
275 : else
276 0 : CPLErrorReset();
277 :
278 0 : return -1;
279 : }
280 :
281 : /*-----------------------------------------------------------------
282 : * Make sure filename has a .MIF or .MID extension...
283 : *----------------------------------------------------------------*/
284 18 : m_pszFname = CPLStrdup(pszFname);
285 18 : nFnameLen = strlen(m_pszFname);
286 18 : if (nFnameLen > 4 && (strcmp(m_pszFname+nFnameLen-4, ".MID")==0 ||
287 : strcmp(m_pszFname+nFnameLen-4, ".MIF")==0 ) )
288 0 : strcpy(m_pszFname+nFnameLen-4, ".MIF");
289 36 : else if (nFnameLen > 4 && (EQUAL(m_pszFname+nFnameLen-4, ".mid") ||
290 : EQUAL(m_pszFname+nFnameLen-4, ".mif") ) )
291 18 : strcpy(m_pszFname+nFnameLen-4, ".mif");
292 : else
293 : {
294 0 : if (!bTestOpenNoError)
295 : CPLError(CE_Failure, CPLE_FileIO,
296 : "Open() failed for %s: invalid filename extension",
297 0 : m_pszFname);
298 : else
299 0 : CPLErrorReset();
300 :
301 0 : CPLFree(m_pszFname);
302 0 : return -1;
303 : }
304 :
305 18 : pszTmpFname = CPLStrdup(m_pszFname);
306 :
307 : /*-----------------------------------------------------------------
308 : * Open .MIF file
309 : *----------------------------------------------------------------*/
310 :
311 : #ifndef _WIN32
312 : /*-----------------------------------------------------------------
313 : * On Unix, make sure extension uses the right cases
314 : * We do it even for write access because if a file with the same
315 : * extension already exists we want to overwrite it.
316 : *----------------------------------------------------------------*/
317 18 : TABAdjustFilenameExtension(pszTmpFname);
318 : #endif
319 :
320 18 : m_poMIFFile = new MIDDATAFile;
321 :
322 18 : if (m_poMIFFile->Open(pszTmpFname, pszAccess) != 0)
323 : {
324 0 : if (!bTestOpenNoError)
325 : CPLError(CE_Failure, CPLE_NotSupported,
326 0 : "Unable to open %s.", pszTmpFname);
327 : else
328 0 : CPLErrorReset();
329 :
330 0 : CPLFree(pszTmpFname);
331 0 : Close();
332 :
333 0 : return -1;
334 : }
335 :
336 : /*-----------------------------------------------------------------
337 : * Open .MID file
338 : *----------------------------------------------------------------*/
339 18 : if (nFnameLen > 4 && strcmp(pszTmpFname+nFnameLen-4, ".MIF")==0)
340 0 : strcpy(pszTmpFname+nFnameLen-4, ".MID");
341 : else
342 18 : strcpy(pszTmpFname+nFnameLen-4, ".mid");
343 :
344 : #ifndef _WIN32
345 18 : TABAdjustFilenameExtension(pszTmpFname);
346 : #endif
347 :
348 18 : m_poMIDFile = new MIDDATAFile;
349 :
350 18 : if (m_poMIDFile->Open(pszTmpFname, pszAccess) !=0)
351 : {
352 0 : if (!bTestOpenNoError)
353 : CPLError(CE_Failure, CPLE_NotSupported,
354 0 : "Unable to open %s.", pszTmpFname);
355 : else
356 0 : CPLErrorReset();
357 :
358 0 : CPLFree(pszTmpFname);
359 0 : Close();
360 :
361 0 : return -1;
362 : }
363 :
364 :
365 18 : CPLFree(pszTmpFname);
366 18 : pszTmpFname = NULL;
367 :
368 : /*-----------------------------------------------------------------
369 : * Read MIF File Header
370 : *----------------------------------------------------------------*/
371 18 : if (m_eAccessMode == TABRead && ParseMIFHeader() != 0)
372 : {
373 0 : Close();
374 :
375 0 : if (!bTestOpenNoError)
376 : CPLError(CE_Failure, CPLE_NotSupported,
377 0 : "Failed parsing header in %s.", m_pszFname);
378 : else
379 0 : CPLErrorReset();
380 :
381 0 : return -1;
382 : }
383 :
384 : /*-----------------------------------------------------------------
385 : * In write access, set some defaults
386 : *----------------------------------------------------------------*/
387 18 : if (m_eAccessMode == TABWrite)
388 : {
389 7 : m_nVersion = 300;
390 7 : m_pszCharset = CPLStrdup("Neutral");
391 : }
392 :
393 : /* Put the MID file at the correct location, on the first feature */
394 18 : if (m_eAccessMode == TABRead && (m_poMIDFile->GetLine() == NULL))
395 : {
396 0 : Close();
397 :
398 0 : if (bTestOpenNoError)
399 0 : CPLErrorReset();
400 :
401 0 : return -1;
402 : }
403 :
404 : m_poMIFFile->SetTranslation(m_dfXMultiplier,m_dfYMultiplier,
405 18 : m_dfXDisplacement, m_dfYDisplacement);
406 : m_poMIDFile->SetTranslation(m_dfXMultiplier,m_dfYMultiplier,
407 18 : m_dfXDisplacement, m_dfYDisplacement);
408 18 : m_poMIFFile->SetDelimiter(m_pszDelimiter);
409 18 : m_poMIDFile->SetDelimiter(m_pszDelimiter);
410 :
411 : /*-------------------------------------------------------------
412 : * Set geometry type if the geometry objects are uniform.
413 : *------------------------------------------------------------*/
414 18 : int numPoints=0, numRegions=0, numTexts=0, numLines=0;
415 :
416 18 : if( GetFeatureCountByType( numPoints, numLines, numRegions, numTexts,
417 : FALSE ) == 0 )
418 : {
419 0 : numPoints += numTexts;
420 0 : if( numPoints > 0 && numLines == 0 && numRegions == 0 )
421 0 : m_poDefn->SetGeomType( wkbPoint );
422 0 : else if( numPoints == 0 && numLines > 0 && numRegions == 0 )
423 0 : m_poDefn->SetGeomType( wkbLineString );
424 : else
425 : /* we leave it unknown indicating a mixture */;
426 : }
427 :
428 : /* A newly created layer should have OGRFeatureDefn */
429 18 : if (m_poDefn == NULL)
430 : {
431 7 : char *pszFeatureClassName = TABGetBasename(m_pszFname);
432 7 : m_poDefn = new OGRFeatureDefn(pszFeatureClassName);
433 7 : CPLFree(pszFeatureClassName);
434 : // Ref count defaults to 0... set it to 1
435 7 : m_poDefn->Reference();
436 : }
437 :
438 18 : return 0;
439 : }
440 :
441 : /**********************************************************************
442 : * MIFFile::ParseMIFHeader()
443 : *
444 : * Scan the header of a MIF file, and store any useful information into
445 : * class members. The main piece of information being the fields
446 : * definition that we use to build the OGRFeatureDefn for this file.
447 : *
448 : * This private method should be used only during the Open() call.
449 : *
450 : * Returns 0 on success, -1 on error.
451 : **********************************************************************/
452 11 : int MIFFile::ParseMIFHeader()
453 : {
454 11 : GBool bColumns = FALSE;
455 11 : int nColumns = 0;
456 11 : GBool bCoordSys = FALSE;
457 : char *pszTmp;
458 :
459 :
460 : const char *pszLine;
461 : char **papszToken;
462 :
463 11 : char *pszFeatureClassName = TABGetBasename(m_pszFname);
464 11 : m_poDefn = new OGRFeatureDefn(pszFeatureClassName);
465 11 : CPLFree(pszFeatureClassName);
466 : // Ref count defaults to 0... set it to 1
467 11 : m_poDefn->Reference();
468 :
469 :
470 11 : if (m_eAccessMode != TABRead)
471 : {
472 : CPLError(CE_Failure, CPLE_NotSupported,
473 0 : "ParseMIDFile() can be used only with Read access.");
474 0 : return -1;
475 : }
476 :
477 :
478 : /*-----------------------------------------------------------------
479 : * Parse header until we find the "Data" line
480 : *----------------------------------------------------------------*/
481 123 : while (((pszLine = m_poMIFFile->GetLine()) != NULL) &&
482 : !(EQUALN(pszLine,"Data",4)))
483 : {
484 296 : while(pszLine && (*pszLine == ' ' || *pszLine == '\t') )
485 94 : pszLine++; // skip leading spaces
486 :
487 148 : if (bColumns == TRUE && nColumns >0)
488 : {
489 47 : if (nColumns == 0)
490 : {
491 : // Permit to 0 columns
492 0 : bColumns = FALSE;
493 : }
494 47 : else if (AddFields(pszLine) == 0)
495 : {
496 47 : nColumns--;
497 47 : if (nColumns == 0)
498 11 : bColumns = FALSE;
499 : }
500 : else
501 : {
502 0 : bColumns = FALSE;
503 : }
504 : }
505 54 : else if (EQUALN(pszLine,"VERSION",7))
506 : {
507 11 : papszToken = CSLTokenizeStringComplex(pszLine," ()\t",TRUE,FALSE);
508 11 : bColumns = FALSE; bCoordSys = FALSE;
509 11 : if (CSLCount(papszToken) == 2)
510 11 : m_nVersion = atoi(papszToken[1]);
511 :
512 11 : CSLDestroy(papszToken);
513 :
514 : }
515 43 : else if (EQUALN(pszLine,"CHARSET",7))
516 : {
517 11 : papszToken = CSLTokenizeStringComplex(pszLine," ()\t",TRUE,FALSE);
518 11 : bColumns = FALSE; bCoordSys = FALSE;
519 :
520 11 : if (CSLCount(papszToken) == 2)
521 : {
522 11 : CPLFree(m_pszCharset);
523 11 : m_pszCharset = CPLStrdup(papszToken[1]);
524 : }
525 11 : CSLDestroy(papszToken);
526 :
527 : }
528 32 : else if (EQUALN(pszLine,"DELIMITER",9))
529 : {
530 11 : papszToken = CSLTokenizeStringComplex(pszLine," ()\t",TRUE,FALSE);
531 11 : bColumns = FALSE; bCoordSys = FALSE;
532 :
533 11 : if (CSLCount(papszToken) == 2)
534 : {
535 11 : CPLFree(m_pszDelimiter);
536 11 : m_pszDelimiter = CPLStrdup(papszToken[1]);
537 : }
538 11 : CSLDestroy(papszToken);
539 :
540 : }
541 21 : else if (EQUALN(pszLine,"UNIQUE",6))
542 : {
543 0 : bColumns = FALSE; bCoordSys = FALSE;
544 :
545 0 : m_pszUnique = CPLStrdup(pszLine + 6);
546 : }
547 21 : else if (EQUALN(pszLine,"INDEX",5))
548 : {
549 0 : bColumns = FALSE; bCoordSys = FALSE;
550 :
551 0 : m_pszIndex = CPLStrdup(pszLine + 5);
552 : }
553 21 : else if (EQUALN(pszLine,"COORDSYS",8) )
554 : {
555 5 : bCoordSys = TRUE;
556 5 : m_pszCoordSys = CPLStrdup(pszLine + 9);
557 :
558 : // Extract bounds if present
559 : char **papszFields;
560 : papszFields = CSLTokenizeStringComplex(m_pszCoordSys, " ,()\t",
561 5 : TRUE, FALSE );
562 5 : int iBounds = CSLFindString( papszFields, "Bounds" );
563 5 : if (iBounds >= 0 && iBounds + 4 < CSLCount(papszFields))
564 : {
565 5 : m_dXMin = atof(papszFields[++iBounds]);
566 5 : m_dYMin = atof(papszFields[++iBounds]);
567 5 : m_dXMax = atof(papszFields[++iBounds]);
568 5 : m_dYMax = atof(papszFields[++iBounds]);
569 5 : m_bBoundsSet = TRUE;
570 : }
571 5 : CSLDestroy( papszFields );
572 : }
573 16 : else if (EQUALN(pszLine,"TRANSFORM",9))
574 : {
575 0 : papszToken = CSLTokenizeStringComplex(pszLine," ,\t",TRUE,FALSE);
576 0 : bColumns = FALSE; bCoordSys = FALSE;
577 :
578 0 : if (CSLCount(papszToken) == 5)
579 : {
580 0 : m_dfXMultiplier = atof(papszToken[1]);
581 0 : m_dfYMultiplier = atof(papszToken[2]);
582 0 : m_dfXDisplacement = atof(papszToken[3]);
583 0 : m_dfYDisplacement = atof(papszToken[4]);
584 :
585 0 : if (m_dfXMultiplier == 0.0)
586 0 : m_dfXMultiplier = 1.0;
587 0 : if (m_dfYMultiplier == 0.0)
588 0 : m_dfYMultiplier = 1.0;
589 : }
590 0 : CSLDestroy(papszToken);
591 : }
592 16 : else if (EQUALN(pszLine,"COLUMNS",7))
593 : {
594 11 : papszToken = CSLTokenizeStringComplex(pszLine," ()\t",TRUE,FALSE);
595 11 : bCoordSys = FALSE;
596 11 : bColumns = TRUE;
597 11 : if (CSLCount(papszToken) == 2)
598 : {
599 11 : nColumns = atoi(papszToken[1]);
600 11 : m_nAttribut = nColumns;
601 : }
602 : else
603 : {
604 0 : bColumns = FALSE;
605 0 : m_nAttribut = 0;
606 : }
607 11 : CSLDestroy(papszToken);
608 : }
609 5 : else if (bCoordSys == TRUE)
610 : {
611 0 : pszTmp = m_pszCoordSys;
612 : m_pszCoordSys = CPLStrdup(CPLSPrintf("%s %s",m_pszCoordSys,
613 0 : pszLine));
614 0 : CPLFree(pszTmp);
615 : //printf("Reading CoordSys\n");
616 : // Reading CoordSys
617 : }
618 :
619 : }
620 :
621 11 : if ((pszLine = m_poMIFFile->GetLastLine()) == NULL ||
622 : EQUALN(m_poMIFFile->GetLastLine(),"DATA",4) == FALSE)
623 : {
624 : CPLError(CE_Failure, CPLE_NotSupported,
625 : "DATA keyword not found in %s. File may be corrupt.",
626 0 : m_pszFname);
627 0 : return -1;
628 : }
629 :
630 : /*-----------------------------------------------------------------
631 : * Move pointer to first line of first object
632 : *----------------------------------------------------------------*/
633 17 : while (((pszLine = m_poMIFFile->GetLine()) != NULL) &&
634 : m_poMIFFile->IsValidFeature(pszLine) == FALSE)
635 : ;
636 :
637 : /*-----------------------------------------------------------------
638 : * Check for Unique and Indexed flags
639 : *----------------------------------------------------------------*/
640 11 : if (m_pszIndex)
641 : {
642 0 : papszToken = CSLTokenizeStringComplex(m_pszIndex," ,\t",TRUE,FALSE);
643 0 : for(int i=0; papszToken && papszToken[i]; i++)
644 : {
645 0 : int nVal = atoi(papszToken[i]);
646 0 : if (nVal > 0 && nVal <= m_poDefn->GetFieldCount())
647 0 : m_pabFieldIndexed[nVal-1] = TRUE;
648 : }
649 0 : CSLDestroy(papszToken);
650 : }
651 :
652 11 : if (m_pszUnique)
653 : {
654 0 : papszToken = CSLTokenizeStringComplex(m_pszUnique," ,\t",TRUE,FALSE);
655 0 : for(int i=0; papszToken && papszToken[i]; i++)
656 : {
657 0 : int nVal = atoi(papszToken[i]);
658 0 : if (nVal > 0 && nVal <= m_poDefn->GetFieldCount())
659 0 : m_pabFieldUnique[nVal-1] = TRUE;
660 : }
661 0 : CSLDestroy(papszToken);
662 : }
663 :
664 11 : return 0;
665 :
666 : }
667 :
668 : /************************************************************************/
669 : /* AddFields() */
670 : /************************************************************************/
671 :
672 47 : int MIFFile::AddFields(const char *pszLine)
673 : {
674 : char **papszToken;
675 47 : int nStatus = 0,numTok;
676 :
677 47 : CPLAssert(m_bHeaderWrote == FALSE);
678 47 : papszToken = CSLTokenizeStringComplex(pszLine," (,)\t",TRUE,FALSE);
679 47 : numTok = CSLCount(papszToken);
680 :
681 71 : if (numTok >= 3 && EQUAL(papszToken[1], "char"))
682 : {
683 : /*-------------------------------------------------
684 : * CHAR type
685 : *------------------------------------------------*/
686 : nStatus = AddFieldNative(papszToken[0], TABFChar,
687 24 : atoi(papszToken[2]));
688 : }
689 35 : else if (numTok >= 2 && EQUAL(papszToken[1], "integer"))
690 : {
691 : /*-------------------------------------------------
692 : * INTEGER type
693 : *------------------------------------------------*/
694 12 : nStatus = AddFieldNative(papszToken[0], TABFInteger);
695 : }
696 11 : else if (numTok >= 2 && EQUAL(papszToken[1], "smallint"))
697 : {
698 : /*-------------------------------------------------
699 : * SMALLINT type
700 : *------------------------------------------------*/
701 0 : nStatus = AddFieldNative(papszToken[0], TABFSmallInt);
702 : }
703 11 : else if (numTok >= 4 && EQUAL(papszToken[1], "decimal"))
704 : {
705 : /*-------------------------------------------------
706 : * DECIMAL type
707 : *------------------------------------------------*/
708 : nStatus = AddFieldNative(papszToken[0], TABFDecimal,
709 0 : atoi(papszToken[2]), atoi(papszToken[3]));
710 : }
711 22 : else if (numTok >= 2 && EQUAL(papszToken[1], "float"))
712 : {
713 : /*-------------------------------------------------
714 : * FLOAT type
715 : *------------------------------------------------*/
716 11 : nStatus = AddFieldNative(papszToken[0], TABFFloat);
717 : }
718 0 : else if (numTok >= 2 && EQUAL(papszToken[1], "date"))
719 : {
720 : /*-------------------------------------------------
721 : * DATE type (returned as a string: "DD/MM/YYYY" or "YYYYMMDD")
722 : *------------------------------------------------*/
723 0 : nStatus = AddFieldNative(papszToken[0], TABFDate);
724 : }
725 0 : else if (numTok >= 2 && EQUAL(papszToken[1], "time"))
726 : {
727 : /*-------------------------------------------------
728 : * TIME type (v900, returned as a string: "HH:MM:SS" or "HHMMSSmmm")
729 : *------------------------------------------------*/
730 0 : nStatus = AddFieldNative(papszToken[0], TABFTime);
731 : }
732 0 : else if (numTok >= 2 && EQUAL(papszToken[1], "datetime"))
733 : {
734 : /*-------------------------------------------------
735 : * DATETIME type (v900, returned as a string: "DD/MM/YYYY HH:MM:SS",
736 : * "YYYY/MM/DD HH:MM:SS" or "YYYYMMDDHHMMSSmmm")
737 : *------------------------------------------------*/
738 0 : nStatus = AddFieldNative(papszToken[0], TABFDateTime);
739 : }
740 0 : else if (numTok >= 2 && EQUAL(papszToken[1], "logical"))
741 : {
742 : /*-------------------------------------------------
743 : * LOGICAL type (value "T" or "F")
744 : *------------------------------------------------*/
745 0 : nStatus = AddFieldNative(papszToken[0], TABFLogical);
746 : }
747 : else
748 0 : nStatus = -1; // Unrecognized field type or line corrupt
749 :
750 47 : CSLDestroy(papszToken);
751 47 : papszToken = NULL;
752 :
753 47 : if (nStatus != 0)
754 : {
755 : CPLError(CE_Failure, CPLE_FileIO,
756 0 : "Failed to parse field definition in file %s", m_pszFname);
757 0 : return -1;
758 : }
759 :
760 47 : return 0;
761 : }
762 :
763 : /************************************************************************/
764 : /* GetFeatureCount() */
765 : /************************************************************************/
766 :
767 0 : int MIFFile::GetFeatureCount (int bForce)
768 : {
769 :
770 0 : if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
771 0 : return OGRLayer::GetFeatureCount( bForce );
772 : else
773 : {
774 0 : if (bForce == TRUE)
775 0 : PreParseFile();
776 :
777 0 : if (m_bPreParsed)
778 0 : return m_nFeatureCount;
779 : else
780 0 : return -1;
781 : }
782 : }
783 :
784 : /************************************************************************/
785 : /* ResetReading() */
786 : /************************************************************************/
787 :
788 16 : void MIFFile::ResetReading()
789 :
790 : {
791 : const char *pszLine;
792 :
793 16 : m_poMIFFile->Rewind();
794 :
795 184 : while ((pszLine = m_poMIFFile->GetLine()) != NULL)
796 168 : if (EQUALN(pszLine,"DATA",4))
797 16 : break;
798 :
799 40 : while ((pszLine = m_poMIFFile->GetLine()) != NULL)
800 : {
801 24 : if (m_poMIFFile->IsValidFeature(pszLine))
802 16 : break;
803 : }
804 :
805 16 : m_poMIDFile->Rewind();
806 16 : m_poMIDFile->GetLine();
807 :
808 : // We're positioned on first feature. Feature Ids start at 1.
809 16 : if (m_poCurFeature)
810 : {
811 1 : delete m_poCurFeature;
812 1 : m_poCurFeature = NULL;
813 : }
814 :
815 16 : m_nCurFeatureId = 0;
816 16 : m_nPreloadedId = 1;
817 16 : }
818 :
819 : /************************************************************************/
820 : /* PreParseFile() */
821 : /************************************************************************/
822 :
823 0 : void MIFFile::PreParseFile()
824 : {
825 0 : char **papszToken = NULL;
826 : const char *pszLine;
827 :
828 0 : GBool bPLine = FALSE;
829 0 : GBool bText = FALSE;
830 :
831 0 : if (m_bPreParsed == TRUE)
832 0 : return;
833 :
834 0 : m_poMIFFile->Rewind();
835 :
836 0 : while ((pszLine = m_poMIFFile->GetLine()) != NULL)
837 0 : if (EQUALN(pszLine,"DATA",4))
838 0 : break;
839 :
840 0 : m_nPoints = m_nLines = m_nRegions = m_nTexts = 0;
841 :
842 0 : while ((pszLine = m_poMIFFile->GetLine()) != NULL)
843 : {
844 0 : if (m_poMIFFile->IsValidFeature(pszLine))
845 : {
846 0 : bPLine = FALSE;
847 0 : bText = FALSE;
848 0 : m_nFeatureCount++;
849 : }
850 :
851 0 : CSLDestroy(papszToken);
852 0 : papszToken = CSLTokenizeString(pszLine);
853 :
854 0 : if (EQUALN(pszLine,"POINT",5))
855 : {
856 0 : m_nPoints++;
857 0 : if (CSLCount(papszToken) == 3)
858 : {
859 : UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[1])),
860 0 : m_poMIFFile->GetYTrans(atof(papszToken[2])));
861 : }
862 :
863 : }
864 0 : else if (EQUALN(pszLine,"LINE",4) ||
865 : EQUALN(pszLine,"RECT",4) ||
866 : EQUALN(pszLine,"ROUNDRECT",9) ||
867 : EQUALN(pszLine,"ARC",3) ||
868 : EQUALN(pszLine,"ELLIPSE",7))
869 : {
870 0 : if (CSLCount(papszToken) == 5)
871 : {
872 0 : m_nLines++;
873 : UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[1])),
874 0 : m_poMIFFile->GetYTrans(atof(papszToken[2])));
875 : UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[3])),
876 0 : m_poMIFFile->GetYTrans(atof(papszToken[4])));
877 : }
878 : }
879 0 : else if (EQUALN(pszLine,"REGION",6) )
880 : {
881 0 : m_nRegions++;
882 0 : bPLine = TRUE;
883 : }
884 0 : else if( EQUALN(pszLine,"PLINE",5))
885 : {
886 0 : m_nLines++;
887 0 : bPLine = TRUE;
888 : }
889 0 : else if (EQUALN(pszLine,"TEXT",4))
890 : {
891 0 : m_nTexts++;
892 0 : bText = TRUE;
893 : }
894 0 : else if (bPLine == TRUE)
895 : {
896 0 : if (CSLCount(papszToken) == 2 &&
897 : strchr("-.0123456789", papszToken[0][0]) != NULL)
898 : {
899 : UpdateExtents( m_poMIFFile->GetXTrans(atof(papszToken[0])),
900 0 : m_poMIFFile->GetYTrans(atof(papszToken[1])));
901 : }
902 : }
903 0 : else if (bText == TRUE)
904 : {
905 0 : if (CSLCount(papszToken) == 4 &&
906 : strchr("-.0123456789", papszToken[0][0]) != NULL)
907 : {
908 : UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[0])),
909 0 : m_poMIFFile->GetYTrans(atof(papszToken[1])));
910 : UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[2])),
911 0 : m_poMIFFile->GetYTrans(atof(papszToken[3])));
912 : }
913 : }
914 :
915 : }
916 :
917 0 : CSLDestroy(papszToken);
918 :
919 0 : m_poMIFFile->Rewind();
920 :
921 0 : while ((pszLine = m_poMIFFile->GetLine()) != NULL)
922 0 : if (EQUALN(pszLine,"DATA",4))
923 0 : break;
924 :
925 0 : while ((pszLine = m_poMIFFile->GetLine()) != NULL)
926 : {
927 0 : if (m_poMIFFile->IsValidFeature(pszLine))
928 0 : break;
929 : }
930 :
931 0 : m_poMIDFile->Rewind();
932 0 : m_poMIDFile->GetLine();
933 :
934 0 : m_bPreParsed = TRUE;
935 :
936 : }
937 :
938 : /**********************************************************************
939 : * MIFFile::WriteMIFHeader()
940 : *
941 : * Generate the .MIF header.
942 : *
943 : * Returns 0 on success, -1 on error.
944 : **********************************************************************/
945 7 : int MIFFile::WriteMIFHeader()
946 : {
947 : int iField;
948 : GBool bFound;
949 :
950 7 : if (m_eAccessMode != TABWrite)
951 : {
952 : CPLError(CE_Failure, CPLE_NotSupported,
953 0 : "WriteMIFHeader() can be used only with Write access.");
954 0 : return -1;
955 : }
956 :
957 7 : if (m_poDefn==NULL || m_poDefn->GetFieldCount() == 0)
958 : {
959 : CPLError(CE_Failure, CPLE_NotSupported,
960 : "File %s must contain at least 1 attribute field.",
961 0 : m_pszFname);
962 0 : return -1;
963 : }
964 :
965 : /*-----------------------------------------------------------------
966 : * Start writing header.
967 : *----------------------------------------------------------------*/
968 7 : m_bHeaderWrote = TRUE;
969 7 : m_poMIFFile->WriteLine("Version %d\n", m_nVersion);
970 7 : m_poMIFFile->WriteLine("Charset \"%s\"\n", m_pszCharset);
971 :
972 : // Delimiter is not required if you use \t as delimiter
973 7 : if ( !EQUAL(m_pszDelimiter, "\t") )
974 7 : m_poMIFFile->WriteLine("Delimiter \"%s\"\n", m_pszDelimiter);
975 :
976 7 : bFound = FALSE;
977 20 : for(iField=0; iField<m_poDefn->GetFieldCount(); iField++)
978 : {
979 13 : if (m_pabFieldUnique[iField])
980 : {
981 0 : if (!bFound)
982 0 : m_poMIFFile->WriteLine("Unique %d", iField+1);
983 : else
984 0 : m_poMIFFile->WriteLine(",%d", iField+1);
985 0 : bFound = TRUE;
986 : }
987 : }
988 7 : if (bFound)
989 0 : m_poMIFFile->WriteLine("\n");
990 :
991 7 : bFound = FALSE;
992 20 : for(iField=0; iField<m_poDefn->GetFieldCount(); iField++)
993 : {
994 13 : if (m_pabFieldIndexed[iField])
995 : {
996 0 : if (!bFound)
997 0 : m_poMIFFile->WriteLine("Index %d", iField+1);
998 : else
999 0 : m_poMIFFile->WriteLine(",%d", iField+1);
1000 0 : bFound = TRUE;
1001 : }
1002 : }
1003 7 : if (bFound)
1004 0 : m_poMIFFile->WriteLine("\n");
1005 :
1006 7 : if (m_pszCoordSys && m_bBoundsSet)
1007 : {
1008 : m_poMIFFile->WriteLine("CoordSys %s "
1009 : "Bounds (%.15g, %.15g) (%.15g, %.15g)\n",
1010 : m_pszCoordSys,
1011 0 : m_dXMin, m_dYMin, m_dXMax, m_dYMax);
1012 : }
1013 7 : else if (m_pszCoordSys)
1014 : {
1015 0 : m_poMIFFile->WriteLine("CoordSys %s\n",m_pszCoordSys);
1016 : }
1017 :
1018 : /*-----------------------------------------------------------------
1019 : * Column definitions
1020 : *----------------------------------------------------------------*/
1021 7 : CPLAssert(m_paeFieldType);
1022 :
1023 7 : m_poMIFFile->WriteLine("Columns %d\n", m_poDefn->GetFieldCount());
1024 :
1025 20 : for(iField=0; iField<m_poDefn->GetFieldCount(); iField++)
1026 : {
1027 : OGRFieldDefn *poFieldDefn;
1028 13 : poFieldDefn = m_poDefn->GetFieldDefn(iField);
1029 :
1030 13 : switch(m_paeFieldType[iField])
1031 : {
1032 : case TABFInteger:
1033 : m_poMIFFile->WriteLine(" %s Integer\n",
1034 2 : poFieldDefn->GetNameRef());
1035 2 : break;
1036 : case TABFSmallInt:
1037 : m_poMIFFile->WriteLine(" %s SmallInt\n",
1038 0 : poFieldDefn->GetNameRef());
1039 0 : break;
1040 : case TABFFloat:
1041 : m_poMIFFile->WriteLine(" %s Float\n",
1042 2 : poFieldDefn->GetNameRef());
1043 2 : break;
1044 : case TABFDecimal:
1045 : m_poMIFFile->WriteLine(" %s Decimal(%d,%d)\n",
1046 : poFieldDefn->GetNameRef(),
1047 : poFieldDefn->GetWidth(),
1048 0 : poFieldDefn->GetPrecision());
1049 0 : break;
1050 : case TABFLogical:
1051 : m_poMIFFile->WriteLine(" %s Logical\n",
1052 0 : poFieldDefn->GetNameRef());
1053 0 : break;
1054 : case TABFDate:
1055 : m_poMIFFile->WriteLine(" %s Date\n",
1056 0 : poFieldDefn->GetNameRef());
1057 0 : break;
1058 : case TABFTime:
1059 : m_poMIFFile->WriteLine(" %s Time\n",
1060 0 : poFieldDefn->GetNameRef());
1061 0 : break;
1062 : case TABFDateTime:
1063 : m_poMIFFile->WriteLine(" %s DateTime\n",
1064 0 : poFieldDefn->GetNameRef());
1065 0 : break;
1066 : case TABFChar:
1067 : default:
1068 : m_poMIFFile->WriteLine(" %s Char(%d)\n",
1069 : poFieldDefn->GetNameRef(),
1070 9 : poFieldDefn->GetWidth());
1071 : }
1072 : }
1073 :
1074 : /*-----------------------------------------------------------------
1075 : * Ready to write objects
1076 : *----------------------------------------------------------------*/
1077 7 : m_poMIFFile->WriteLine("Data\n\n");
1078 :
1079 7 : return 0;
1080 : }
1081 :
1082 : /**********************************************************************
1083 : * MIFFile::Close()
1084 : *
1085 : * Close current file, and release all memory used.
1086 : *
1087 : * Returns 0 on success, -1 on error.
1088 : **********************************************************************/
1089 18 : int MIFFile::Close()
1090 : {
1091 : /* flush .mif header if not already written */
1092 18 : if ( m_poDefn != NULL && m_bHeaderWrote == FALSE
1093 : && m_eAccessMode != TABRead )
1094 : {
1095 1 : WriteMIFHeader();
1096 : }
1097 :
1098 18 : if (m_poMIDFile)
1099 : {
1100 18 : m_poMIDFile->Close();
1101 18 : delete m_poMIDFile;
1102 18 : m_poMIDFile = NULL;
1103 : }
1104 :
1105 18 : if (m_poMIFFile)
1106 : {
1107 18 : m_poMIFFile->Close();
1108 18 : delete m_poMIFFile;
1109 18 : m_poMIFFile = NULL;
1110 : }
1111 :
1112 18 : if (m_poCurFeature)
1113 : {
1114 0 : delete m_poCurFeature;
1115 0 : m_poCurFeature = NULL;
1116 : }
1117 :
1118 : /*-----------------------------------------------------------------
1119 : * Note: we have to check the reference count before deleting
1120 : * m_poSpatialRef and m_poDefn
1121 : *----------------------------------------------------------------*/
1122 18 : if (m_poDefn && m_poDefn->Dereference() == 0)
1123 13 : delete m_poDefn;
1124 18 : m_poDefn = NULL;
1125 :
1126 18 : if (m_poSpatialRef && m_poSpatialRef->Dereference() == 0)
1127 0 : delete m_poSpatialRef;
1128 18 : m_poSpatialRef = NULL;
1129 :
1130 18 : CPLFree(m_pszCoordSys);
1131 18 : m_pszCoordSys = NULL;
1132 :
1133 18 : CPLFree(m_pszDelimiter);
1134 18 : m_pszDelimiter = NULL;
1135 :
1136 18 : CPLFree(m_pszFname);
1137 18 : m_pszFname = NULL;
1138 :
1139 18 : m_nVersion = 0;
1140 :
1141 18 : CPLFree(m_pszCharset);
1142 18 : m_pszCharset = NULL;
1143 :
1144 18 : CPLFree(m_pabFieldIndexed);
1145 18 : m_pabFieldIndexed = NULL;
1146 18 : CPLFree(m_pabFieldUnique);
1147 18 : m_pabFieldUnique = NULL;
1148 :
1149 18 : CPLFree( m_pszIndex );
1150 18 : m_pszIndex = NULL;
1151 :
1152 18 : CPLFree(m_paeFieldType);
1153 18 : m_paeFieldType = NULL;
1154 :
1155 18 : m_nCurFeatureId = 0;
1156 18 : m_nPreloadedId = 0;
1157 18 : m_nFeatureCount =0;
1158 :
1159 18 : m_bBoundsSet = FALSE;
1160 :
1161 18 : return 0;
1162 : }
1163 :
1164 : /**********************************************************************
1165 : * MIFFile::GetNextFeatureId()
1166 : *
1167 : * Returns feature id that follows nPrevId, or -1 if it is the
1168 : * last feature id. Pass nPrevId=-1 to fetch the first valid feature id.
1169 : **********************************************************************/
1170 50 : int MIFFile::GetNextFeatureId(int nPrevId)
1171 : {
1172 50 : if (m_eAccessMode != TABRead)
1173 : {
1174 : CPLError(CE_Failure, CPLE_NotSupported,
1175 0 : "GetNextFeatureId() can be used only with Read access.");
1176 0 : return -1;
1177 : }
1178 :
1179 50 : if (nPrevId <= 0 && m_poMIFFile->GetLastLine() != NULL)
1180 12 : return 1; // Feature Ids start at 1
1181 38 : else if (nPrevId > 0 && m_poMIFFile->GetLastLine() != NULL)
1182 32 : return nPrevId + 1;
1183 : else
1184 6 : return -1;
1185 :
1186 : return 0;
1187 : }
1188 :
1189 : /**********************************************************************
1190 : * MIFFile::GotoFeature()
1191 : *
1192 : * Private method to move MIF and MID pointers ready to read specified
1193 : * feature. Note that Feature Ids start at 1.
1194 : *
1195 : * Returns 0 on success, -1 on error (likely request for invalid feature id)
1196 : **********************************************************************/
1197 44 : int MIFFile::GotoFeature(int nFeatureId)
1198 : {
1199 :
1200 44 : if (nFeatureId < 1)
1201 0 : return -1;
1202 :
1203 44 : if (nFeatureId == m_nPreloadedId) // CorrectPosition
1204 : {
1205 39 : return 0;
1206 : }
1207 : else
1208 : {
1209 5 : if (nFeatureId < m_nCurFeatureId || m_nCurFeatureId == 0)
1210 5 : ResetReading();
1211 :
1212 10 : while(m_nPreloadedId < nFeatureId)
1213 : {
1214 0 : if (NextFeature() == FALSE)
1215 0 : return -1;
1216 : }
1217 :
1218 5 : CPLAssert(m_nPreloadedId == nFeatureId);
1219 :
1220 5 : return 0;
1221 : }
1222 : }
1223 :
1224 : /**********************************************************************
1225 : * MIFFile::NextFeature()
1226 : **********************************************************************/
1227 :
1228 0 : GBool MIFFile::NextFeature()
1229 : {
1230 : const char *pszLine;
1231 0 : while ((pszLine = m_poMIFFile->GetLine()) != NULL)
1232 : {
1233 0 : if (m_poMIFFile->IsValidFeature(pszLine))
1234 : {
1235 0 : m_poMIDFile->GetLine();
1236 0 : m_nPreloadedId++;
1237 0 : return TRUE;
1238 : }
1239 : }
1240 0 : return FALSE;
1241 : }
1242 :
1243 : /**********************************************************************
1244 : * MIFFile::GetFeatureRef()
1245 : *
1246 : * Fill and return a TABFeature object for the specified feature id.
1247 : *
1248 : * The retruned pointer is a reference to an object owned and maintained
1249 : * by this MIFFile object. It should not be altered or freed by the
1250 : * caller and its contents is guaranteed to be valid only until the next
1251 : * call to GetFeatureRef() or Close().
1252 : *
1253 : * Returns NULL if the specified feature id does not exist of if an
1254 : * error happened. In any case, CPLError() will have been called to
1255 : * report the reason of the failure.
1256 : **********************************************************************/
1257 44 : TABFeature *MIFFile::GetFeatureRef(int nFeatureId)
1258 : {
1259 : const char *pszLine;
1260 :
1261 44 : if (m_eAccessMode != TABRead)
1262 : {
1263 : CPLError(CE_Failure, CPLE_NotSupported,
1264 0 : "GetFeatureRef() can be used only with Read access.");
1265 0 : return NULL;
1266 : }
1267 :
1268 : /*-----------------------------------------------------------------
1269 : * Make sure file is opened and Validate feature id by positioning
1270 : * the read pointers for the .MAP and .DAT files to this feature id.
1271 : *----------------------------------------------------------------*/
1272 44 : if (m_poMIDFile == NULL)
1273 : {
1274 : CPLError(CE_Failure, CPLE_IllegalArg,
1275 0 : "GetFeatureRef() failed: file is not opened!");
1276 0 : return NULL;
1277 : }
1278 :
1279 44 : if (GotoFeature(nFeatureId)!= 0 )
1280 : {
1281 : CPLError(CE_Failure, CPLE_IllegalArg,
1282 : "GetFeatureRef() failed: invalid feature id %d",
1283 0 : nFeatureId);
1284 0 : return NULL;
1285 : }
1286 :
1287 :
1288 : /*-----------------------------------------------------------------
1289 : * Create new feature object of the right type
1290 : *----------------------------------------------------------------*/
1291 44 : if ((pszLine = m_poMIFFile->GetLastLine()) != NULL)
1292 : {
1293 : // Delete previous feature... we'll start we a clean one.
1294 44 : if (m_poCurFeature)
1295 5 : delete m_poCurFeature;
1296 44 : m_poCurFeature = NULL;
1297 :
1298 44 : m_nCurFeatureId = m_nPreloadedId;
1299 :
1300 44 : if (EQUALN(pszLine,"NONE",4))
1301 : {
1302 12 : m_poCurFeature = new TABFeature(m_poDefn);
1303 : }
1304 32 : else if (EQUALN(pszLine,"POINT",5))
1305 : {
1306 : // Special case, we need to know two lines to decide the type
1307 : char **papszToken;
1308 4 : papszToken = CSLTokenizeString(pszLine);
1309 :
1310 4 : if (CSLCount(papszToken) !=3)
1311 : {
1312 0 : CSLDestroy(papszToken);
1313 : CPLError(CE_Failure, CPLE_NotSupported,
1314 : "GetFeatureRef() failed: invalid point line: '%s'",
1315 0 : pszLine);
1316 0 : return NULL;
1317 : }
1318 :
1319 4 : m_poMIFFile->SaveLine(pszLine);
1320 :
1321 4 : if ((pszLine = m_poMIFFile->GetLine()) != NULL)
1322 : {
1323 4 : CSLDestroy(papszToken);
1324 : papszToken = CSLTokenizeStringComplex(pszLine," ,()\t",
1325 4 : TRUE,FALSE);
1326 4 : if (CSLCount(papszToken)> 0 &&EQUALN(papszToken[0],"SYMBOL",6))
1327 : {
1328 4 : switch (CSLCount(papszToken))
1329 : {
1330 : case 4:
1331 4 : m_poCurFeature = new TABPoint(m_poDefn);
1332 4 : break;
1333 : case 7:
1334 0 : m_poCurFeature = new TABFontPoint(m_poDefn);
1335 0 : break;
1336 : case 5:
1337 0 : m_poCurFeature = new TABCustomPoint(m_poDefn);
1338 0 : break;
1339 : default:
1340 0 : CSLDestroy(papszToken);
1341 : CPLError(CE_Failure, CPLE_NotSupported,
1342 : "GetFeatureRef() failed: invalid symbol "
1343 0 : "line: '%s'", pszLine);
1344 0 : return NULL;
1345 : break;
1346 : }
1347 :
1348 : }
1349 : }
1350 4 : CSLDestroy(papszToken);
1351 :
1352 4 : if (m_poCurFeature == NULL)
1353 : {
1354 : // No symbol clause... default to TABPoint
1355 0 : m_poCurFeature = new TABPoint(m_poDefn);
1356 : }
1357 : }
1358 28 : else if (EQUALN(pszLine,"LINE",4) ||
1359 : EQUALN(pszLine,"PLINE",5))
1360 : {
1361 0 : m_poCurFeature = new TABPolyline(m_poDefn);
1362 : }
1363 28 : else if (EQUALN(pszLine,"REGION",6))
1364 : {
1365 28 : m_poCurFeature = new TABRegion(m_poDefn);
1366 : }
1367 0 : else if (EQUALN(pszLine,"ARC",3))
1368 : {
1369 0 : m_poCurFeature = new TABArc(m_poDefn);
1370 : }
1371 0 : else if (EQUALN(pszLine,"TEXT",4))
1372 : {
1373 0 : m_poCurFeature = new TABText(m_poDefn);
1374 : }
1375 0 : else if (EQUALN(pszLine,"RECT",4) ||
1376 : EQUALN(pszLine,"ROUNDRECT",9))
1377 : {
1378 0 : m_poCurFeature = new TABRectangle(m_poDefn);
1379 : }
1380 0 : else if (EQUALN(pszLine,"ELLIPSE",7))
1381 : {
1382 0 : m_poCurFeature = new TABEllipse(m_poDefn);
1383 : }
1384 0 : else if (EQUALN(pszLine,"MULTIPOINT",10))
1385 : {
1386 0 : m_poCurFeature = new TABMultiPoint(m_poDefn);
1387 : }
1388 0 : else if (EQUALN(pszLine,"COLLECTION",10))
1389 : {
1390 0 : m_poCurFeature = new TABCollection(m_poDefn);
1391 : }
1392 : else
1393 : {
1394 0 : if (!EQUAL(pszLine,""))
1395 : CPLError(CE_Failure, CPLE_NotSupported,
1396 : "Error during reading, unknown type %s.",
1397 0 : pszLine);
1398 :
1399 : //m_poCurFeature = new TABDebugFeature(m_poDefn);
1400 0 : return NULL;
1401 : }
1402 : }
1403 :
1404 44 : CPLAssert(m_poCurFeature);
1405 44 : if (m_poCurFeature == NULL)
1406 0 : return NULL;
1407 :
1408 : /*-----------------------------------------------------------------
1409 : * Read fields from the .DAT file
1410 : * GetRecordBlock() has already been called above...
1411 : *----------------------------------------------------------------*/
1412 44 : if (m_poCurFeature->ReadRecordFromMIDFile(m_poMIDFile) != 0)
1413 : {
1414 : CPLError(CE_Failure, CPLE_NotSupported,
1415 0 : "Error during reading Record.");
1416 :
1417 0 : delete m_poCurFeature;
1418 0 : m_poCurFeature = NULL;
1419 0 : return NULL;
1420 : }
1421 :
1422 : /*-----------------------------------------------------------------
1423 : * Read geometry from the .MAP file
1424 : * MoveToObjId() has already been called above...
1425 : *----------------------------------------------------------------*/
1426 44 : if (m_poCurFeature->ReadGeometryFromMIFFile(m_poMIFFile) != 0)
1427 : {
1428 : CPLError(CE_Failure, CPLE_NotSupported,
1429 0 : "Error during reading Geometry.");
1430 :
1431 0 : delete m_poCurFeature;
1432 0 : m_poCurFeature = NULL;
1433 0 : return NULL;
1434 : }
1435 :
1436 : /*---------------------------------------------------------------------
1437 : * The act of reading the geometry causes the first line of the
1438 : * next object to be preloaded. Set the preloaded id appropriately.
1439 : *--------------------------------------------------------------------- */
1440 44 : if( m_poMIFFile->GetLastLine() != NULL )
1441 32 : m_nPreloadedId++;
1442 : else
1443 12 : m_nPreloadedId = 0;
1444 :
1445 : /* Update the Current Feature ID */
1446 44 : m_poCurFeature->SetFID(m_nCurFeatureId);
1447 :
1448 44 : return m_poCurFeature;
1449 : }
1450 :
1451 : /**********************************************************************
1452 : * MIFFile::CreateFeature()
1453 : *
1454 : * Write a new feature to this dataset. The passed in feature is updated
1455 : * with the new feature id.
1456 : *
1457 : * Returns OGRERR_NONE on success, or an appropriate OGRERR_ code if an
1458 : * error happened in which case, CPLError() will have been called to
1459 : * report the reason of the failure.
1460 : **********************************************************************/
1461 20 : OGRErr MIFFile::CreateFeature(TABFeature *poFeature)
1462 : {
1463 20 : int nFeatureId = -1;
1464 :
1465 20 : if (m_eAccessMode != TABWrite)
1466 : {
1467 : CPLError(CE_Failure, CPLE_NotSupported,
1468 0 : "CreateFeature() can be used only with Write access.");
1469 0 : return OGRERR_UNSUPPORTED_OPERATION;
1470 : }
1471 :
1472 : /*-----------------------------------------------------------------
1473 : * Make sure file is opened and establish new feature id.
1474 : *----------------------------------------------------------------*/
1475 20 : if (m_poMIDFile == NULL)
1476 : {
1477 : CPLError(CE_Failure, CPLE_IllegalArg,
1478 0 : "CreateFeature() failed: file is not opened!");
1479 0 : return OGRERR_FAILURE;
1480 : }
1481 :
1482 20 : if (m_bHeaderWrote == FALSE)
1483 : {
1484 : /*-------------------------------------------------------------
1485 : * OK, this is the first feature in the dataset... make sure the
1486 : * .MID schema has been initialized.
1487 : *------------------------------------------------------------*/
1488 6 : if (m_poDefn == NULL)
1489 0 : SetFeatureDefn(poFeature->GetDefnRef(), NULL);
1490 :
1491 6 : WriteMIFHeader();
1492 6 : nFeatureId = 1;
1493 : }
1494 : else
1495 : {
1496 14 : nFeatureId = ++ m_nWriteFeatureId;
1497 : }
1498 :
1499 :
1500 : /*-----------------------------------------------------------------
1501 : * Write geometry to the .Mif file
1502 : *----------------------------------------------------------------*/
1503 20 : if (m_poMIFFile == NULL ||
1504 : poFeature->WriteGeometryToMIFFile(m_poMIFFile) != 0)
1505 : {
1506 : CPLError(CE_Failure, CPLE_FileIO,
1507 : "Failed writing geometry for feature id %d in %s",
1508 0 : nFeatureId, m_pszFname);
1509 0 : return OGRERR_FAILURE;
1510 : }
1511 :
1512 20 : if (m_poMIDFile == NULL ||
1513 : poFeature->WriteRecordToMIDFile(m_poMIDFile) != 0 )
1514 : {
1515 : CPLError(CE_Failure, CPLE_FileIO,
1516 : "Failed writing attributes for feature id %d in %s",
1517 0 : nFeatureId, m_pszFname);
1518 0 : return OGRERR_FAILURE;
1519 : }
1520 :
1521 20 : poFeature->SetFID(nFeatureId);
1522 :
1523 20 : return OGRERR_NONE;
1524 : }
1525 :
1526 :
1527 :
1528 : /**********************************************************************
1529 : * MIFFile::GetLayerDefn()
1530 : *
1531 : * Returns a reference to the OGRFeatureDefn that will be used to create
1532 : * features in this dataset.
1533 : *
1534 : * Returns a reference to an object that is maintained by this MIFFile
1535 : * object (and thus should not be modified or freed by the caller) or
1536 : * NULL if the OGRFeatureDefn has not been initialized yet (i.e. no file
1537 : * opened yet)
1538 : **********************************************************************/
1539 128 : OGRFeatureDefn *MIFFile::GetLayerDefn()
1540 : {
1541 128 : return m_poDefn;
1542 : }
1543 :
1544 : /**********************************************************************
1545 : * MIFFile::SetFeatureDefn()
1546 : *
1547 : * Pass a reference to the OGRFeatureDefn that will be used to create
1548 : * features in this dataset. This function should be called after
1549 : * creating a new dataset, but before writing the first feature.
1550 : * All features that will be written to this dataset must share this same
1551 : * OGRFeatureDefn.
1552 : *
1553 : * This function will use poFeatureDefn to create a local copy that
1554 : * will be used to build the .MID file, etc.
1555 : *
1556 : * Returns 0 on success, -1 on error.
1557 : **********************************************************************/
1558 : int MIFFile::SetFeatureDefn(OGRFeatureDefn *poFeatureDefn,
1559 0 : TABFieldType *paeMapInfoNativeFieldTypes /* =NULL */)
1560 : {
1561 : int numFields;
1562 0 : int nStatus = 0;
1563 :
1564 : /*-----------------------------------------------------------------
1565 : * Check that call happens at the right time in dataset's life.
1566 : *----------------------------------------------------------------*/
1567 0 : if ( m_eAccessMode == TABWrite && m_bHeaderWrote )
1568 : {
1569 : CPLError(CE_Failure, CPLE_AssertionFailed,
1570 : "SetFeatureDefn() must be called after opening a new "
1571 0 : "dataset, but before writing the first feature to it.");
1572 0 : return -1;
1573 : }
1574 :
1575 : /*-----------------------------------------------------------------
1576 : * Delete current feature defn if there is already one.
1577 : * AddFieldNative() will take care of creating a new one for us.
1578 : *----------------------------------------------------------------*/
1579 0 : if (m_poDefn && m_poDefn->Dereference() == 0)
1580 0 : delete m_poDefn;
1581 0 : m_poDefn = NULL;
1582 :
1583 : /*-----------------------------------------------------------------
1584 : * Copy field information
1585 : *----------------------------------------------------------------*/
1586 0 : numFields = poFeatureDefn->GetFieldCount();
1587 :
1588 0 : for(int iField=0; iField<numFields; iField++)
1589 : {
1590 : TABFieldType eMapInfoType;
1591 0 : OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
1592 :
1593 0 : if (paeMapInfoNativeFieldTypes)
1594 : {
1595 0 : eMapInfoType = paeMapInfoNativeFieldTypes[iField];
1596 : }
1597 : else
1598 : {
1599 : /*---------------------------------------------------------
1600 : * Map OGRFieldTypes to MapInfo native types
1601 : *--------------------------------------------------------*/
1602 0 : switch(poFieldDefn->GetType())
1603 : {
1604 : case OFTInteger:
1605 0 : eMapInfoType = TABFInteger;
1606 0 : break;
1607 : case OFTReal:
1608 0 : eMapInfoType = TABFFloat;
1609 0 : break;
1610 : case OFTDateTime:
1611 0 : eMapInfoType = TABFDateTime;
1612 0 : break;
1613 : case OFTDate:
1614 0 : eMapInfoType = TABFDate;
1615 0 : break;
1616 : case OFTTime:
1617 0 : eMapInfoType = TABFTime;
1618 0 : break;
1619 : case OFTString:
1620 : default:
1621 0 : eMapInfoType = TABFChar;
1622 : }
1623 : }
1624 :
1625 : nStatus = AddFieldNative(poFieldDefn->GetNameRef(), eMapInfoType,
1626 : poFieldDefn->GetWidth(),
1627 0 : poFieldDefn->GetPrecision(), FALSE, FALSE);
1628 : }
1629 :
1630 0 : return nStatus;
1631 : }
1632 :
1633 : /**********************************************************************
1634 : * MIFFile::AddFieldNative()
1635 : *
1636 : * Create a new field using a native mapinfo data type... this is an
1637 : * alternative to defining fields through the OGR interface.
1638 : * This function should be called after creating a new dataset, but before
1639 : * writing the first feature.
1640 : *
1641 : * This function will build/update the OGRFeatureDefn that will have to be
1642 : * used when writing features to this dataset.
1643 : *
1644 : * A reference to the OGRFeatureDefn can be obtained using GetLayerDefn().
1645 : *
1646 : * Returns 0 on success, -1 on error.
1647 : **********************************************************************/
1648 : int MIFFile::AddFieldNative(const char *pszName, TABFieldType eMapInfoType,
1649 : int nWidth /*=0*/, int nPrecision /*=0*/,
1650 60 : GBool bIndexed /*=FALSE*/, GBool bUnique/*=FALSE*/)
1651 : {
1652 : OGRFieldDefn *poFieldDefn;
1653 60 : char *pszCleanName = NULL;
1654 60 : int nStatus = 0;
1655 :
1656 : /*-----------------------------------------------------------------
1657 : * Check that call happens at the right time in dataset's life.
1658 : *----------------------------------------------------------------*/
1659 60 : if ( m_eAccessMode == TABWrite && m_bHeaderWrote )
1660 : {
1661 : CPLError(CE_Failure, CPLE_AssertionFailed,
1662 : "AddFieldNative() must be called after opening a new "
1663 0 : "dataset, but before writing the first feature to it.");
1664 0 : return -1;
1665 : }
1666 :
1667 : /*-----------------------------------------------------------------
1668 : * Validate field width... must be <= 254
1669 : *----------------------------------------------------------------*/
1670 60 : if (nWidth > 254)
1671 : {
1672 : CPLError(CE_Warning, CPLE_IllegalArg,
1673 : "Invalid size (%d) for field '%s'. "
1674 0 : "Size must be 254 or less.", nWidth, pszName);
1675 0 : nWidth = 254;
1676 : }
1677 :
1678 : /*-----------------------------------------------------------------
1679 : * Map fields with width=0 (variable length in OGR) to a valid default
1680 : *----------------------------------------------------------------*/
1681 60 : if (eMapInfoType == TABFDecimal && nWidth == 0)
1682 0 : nWidth=20;
1683 60 : else if (nWidth == 0)
1684 23 : nWidth=254; /* char fields */
1685 :
1686 : /*-----------------------------------------------------------------
1687 : * Create new OGRFeatureDefn if not done yet...
1688 : *----------------------------------------------------------------*/
1689 60 : if (m_poDefn == NULL)
1690 : {
1691 0 : char *pszFeatureClassName = TABGetBasename(m_pszFname);
1692 0 : m_poDefn = new OGRFeatureDefn(pszFeatureClassName);
1693 0 : CPLFree(pszFeatureClassName);
1694 : // Ref count defaults to 0... set it to 1
1695 0 : m_poDefn->Reference();
1696 : }
1697 :
1698 : /*-----------------------------------------------------------------
1699 : * Make sure field name is valid... check for special chars, etc.
1700 : * (pszCleanName will have to be freed.)
1701 : *----------------------------------------------------------------*/
1702 60 : pszCleanName = TABCleanFieldName(pszName);
1703 :
1704 : /*-----------------------------------------------------------------
1705 : * Map MapInfo native types to OGR types
1706 : *----------------------------------------------------------------*/
1707 60 : poFieldDefn = NULL;
1708 :
1709 60 : switch(eMapInfoType)
1710 : {
1711 : case TABFChar:
1712 : /*-------------------------------------------------
1713 : * CHAR type
1714 : *------------------------------------------------*/
1715 33 : poFieldDefn = new OGRFieldDefn(pszCleanName, OFTString);
1716 33 : poFieldDefn->SetWidth(nWidth);
1717 33 : break;
1718 : case TABFInteger:
1719 : /*-------------------------------------------------
1720 : * INTEGER type
1721 : *------------------------------------------------*/
1722 14 : poFieldDefn = new OGRFieldDefn(pszCleanName, OFTInteger);
1723 14 : break;
1724 : case TABFSmallInt:
1725 : /*-------------------------------------------------
1726 : * SMALLINT type
1727 : *------------------------------------------------*/
1728 0 : poFieldDefn = new OGRFieldDefn(pszCleanName, OFTInteger);
1729 0 : break;
1730 : case TABFDecimal:
1731 : /*-------------------------------------------------
1732 : * DECIMAL type
1733 : *------------------------------------------------*/
1734 0 : poFieldDefn = new OGRFieldDefn(pszCleanName, OFTReal);
1735 0 : poFieldDefn->SetWidth(nWidth);
1736 0 : poFieldDefn->SetPrecision(nPrecision);
1737 0 : break;
1738 : case TABFFloat:
1739 : /*-------------------------------------------------
1740 : * FLOAT type
1741 : *------------------------------------------------*/
1742 13 : poFieldDefn = new OGRFieldDefn(pszCleanName, OFTReal);
1743 13 : break;
1744 : case TABFDate:
1745 : /*-------------------------------------------------
1746 : * DATE type (V450, returned as a string: "DD/MM/YYYY" or "YYYYMMDD")
1747 : *------------------------------------------------*/
1748 : poFieldDefn = new OGRFieldDefn(pszCleanName,
1749 : #ifdef MITAB_USE_OFTDATETIME
1750 0 : OFTDate);
1751 : #else
1752 : OFTString);
1753 : #endif
1754 0 : poFieldDefn->SetWidth(10);
1755 0 : m_nVersion = MAX(m_nVersion, 450);
1756 0 : break;
1757 : case TABFTime:
1758 : /*-------------------------------------------------
1759 : * TIME type (v900, returned as a string: "HH:MM:SS" or "HHMMSSmmm")
1760 : *------------------------------------------------*/
1761 : poFieldDefn = new OGRFieldDefn(pszCleanName,
1762 : #ifdef MITAB_USE_OFTDATETIME
1763 0 : OFTTime);
1764 : #else
1765 : OFTString);
1766 : #endif
1767 0 : poFieldDefn->SetWidth(9);
1768 0 : m_nVersion = MAX(m_nVersion, 900);
1769 0 : break;
1770 : case TABFDateTime:
1771 : /*-------------------------------------------------
1772 : * DATETIME type (v900, returned as a string: "DD/MM/YYYY HH:MM:SS",
1773 : * "YYYY/MM/DD HH:MM:SS" or "YYYYMMDDHHMMSSmmm")
1774 : *------------------------------------------------*/
1775 : poFieldDefn = new OGRFieldDefn(pszCleanName,
1776 : #ifdef MITAB_USE_OFTDATETIME
1777 0 : OFTDateTime);
1778 : #else
1779 : OFTString);
1780 : #endif
1781 0 : poFieldDefn->SetWidth(19);
1782 0 : break;
1783 : m_nVersion = MAX(m_nVersion, 900);
1784 : case TABFLogical:
1785 : /*-------------------------------------------------
1786 : * LOGICAL type (value "T" or "F")
1787 : *------------------------------------------------*/
1788 0 : poFieldDefn = new OGRFieldDefn(pszCleanName, OFTString);
1789 0 : poFieldDefn->SetWidth(1);
1790 0 : break;
1791 : default:
1792 : CPLError(CE_Failure, CPLE_NotSupported,
1793 0 : "Unsupported type for field %s", pszName);
1794 0 : return -1;
1795 : }
1796 :
1797 : /*-----------------------------------------------------
1798 : * Add the FieldDefn to the FeatureDefn
1799 : *----------------------------------------------------*/
1800 60 : m_poDefn->AddFieldDefn(poFieldDefn);
1801 60 : delete poFieldDefn;
1802 :
1803 : /*-----------------------------------------------------------------
1804 : * Keep track of native field type
1805 : *----------------------------------------------------------------*/
1806 : m_paeFieldType = (TABFieldType *)CPLRealloc(m_paeFieldType,
1807 : m_poDefn->GetFieldCount()*
1808 60 : sizeof(TABFieldType));
1809 60 : m_paeFieldType[m_poDefn->GetFieldCount()-1] = eMapInfoType;
1810 :
1811 : /*-----------------------------------------------------------------
1812 : * Extend array of Indexed/Unique flags
1813 : *----------------------------------------------------------------*/
1814 : m_pabFieldIndexed = (GBool *)CPLRealloc(m_pabFieldIndexed,
1815 : m_poDefn->GetFieldCount()*
1816 60 : sizeof(GBool));
1817 : m_pabFieldUnique = (GBool *)CPLRealloc(m_pabFieldUnique,
1818 : m_poDefn->GetFieldCount()*
1819 60 : sizeof(GBool));
1820 60 : m_pabFieldIndexed[m_poDefn->GetFieldCount()-1] = bIndexed;
1821 60 : m_pabFieldUnique[m_poDefn->GetFieldCount()-1] = bUnique;
1822 :
1823 60 : CPLFree(pszCleanName);
1824 60 : return nStatus;
1825 : }
1826 :
1827 :
1828 : /**********************************************************************
1829 : * MIFFile::GetNativeFieldType()
1830 : *
1831 : * Returns the native MapInfo field type for the specified field.
1832 : *
1833 : * Returns TABFUnknown if file is not opened, or if specified field index is
1834 : * invalid.
1835 : **********************************************************************/
1836 0 : TABFieldType MIFFile::GetNativeFieldType(int nFieldId)
1837 : {
1838 0 : if ( m_poDefn==NULL || m_paeFieldType==NULL ||
1839 : nFieldId < 0 || nFieldId >= m_poDefn->GetFieldCount())
1840 0 : return TABFUnknown;
1841 :
1842 0 : return m_paeFieldType[nFieldId];
1843 : }
1844 :
1845 : /************************************************************************
1846 : * MIFFile::SetFieldIndexed()
1847 : ************************************************************************/
1848 :
1849 0 : int MIFFile::SetFieldIndexed( int nFieldId )
1850 :
1851 : {
1852 0 : if ( m_poDefn==NULL || m_pabFieldIndexed==NULL ||
1853 : nFieldId < 0 || nFieldId >= m_poDefn->GetFieldCount())
1854 0 : return -1;
1855 :
1856 0 : m_pabFieldIndexed[nFieldId] = TRUE;
1857 :
1858 0 : return 0;
1859 : }
1860 :
1861 : /************************************************************************
1862 : * MIFFile::IsFieldIndexed()
1863 : ************************************************************************/
1864 :
1865 0 : GBool MIFFile::IsFieldIndexed( int nFieldId )
1866 :
1867 : {
1868 0 : if ( m_poDefn==NULL || m_pabFieldIndexed==NULL ||
1869 : nFieldId < 0 || nFieldId >= m_poDefn->GetFieldCount())
1870 0 : return FALSE;
1871 :
1872 0 : return m_pabFieldIndexed[nFieldId];
1873 : }
1874 :
1875 : /************************************************************************
1876 : * MIFFile::IsFieldUnique()
1877 : ************************************************************************/
1878 :
1879 0 : GBool MIFFile::IsFieldUnique( int nFieldId )
1880 :
1881 : {
1882 0 : if ( m_poDefn==NULL || m_pabFieldUnique==NULL ||
1883 : nFieldId < 0 || nFieldId >= m_poDefn->GetFieldCount())
1884 0 : return FALSE;
1885 :
1886 0 : return m_pabFieldUnique[nFieldId];
1887 : }
1888 :
1889 :
1890 : /************************************************************************/
1891 : /* MIFFile::SetSpatialRef() */
1892 : /************************************************************************/
1893 :
1894 0 : int MIFFile::SetSpatialRef( OGRSpatialReference * poSpatialRef )
1895 :
1896 : {
1897 0 : CPLFree( m_pszCoordSys );
1898 :
1899 0 : m_pszCoordSys = MITABSpatialRef2CoordSys( poSpatialRef );
1900 :
1901 0 : return( m_pszCoordSys != NULL );
1902 : }
1903 :
1904 :
1905 : /************************************************************************/
1906 : /* MIFFile::SetMIFCoordSys() */
1907 : /************************************************************************/
1908 :
1909 0 : int MIFFile::SetMIFCoordSys(const char * pszMIFCoordSys)
1910 :
1911 : {
1912 : char **papszFields, *pszCoordSys;
1913 : int iBounds;
1914 :
1915 : // Extract the word 'COORDSYS' if present
1916 0 : if (EQUALN(pszMIFCoordSys,"COORDSYS",8) )
1917 : {
1918 0 : pszCoordSys = CPLStrdup(pszMIFCoordSys + 9);
1919 : }
1920 : else
1921 : {
1922 0 : pszCoordSys = CPLStrdup(pszMIFCoordSys);
1923 : }
1924 :
1925 : // Extract bounds if present
1926 : papszFields = CSLTokenizeStringComplex(pszCoordSys, " ,()\t",
1927 0 : TRUE, FALSE );
1928 0 : iBounds = CSLFindString( papszFields, "Bounds" );
1929 0 : if (iBounds >= 0 && iBounds + 4 < CSLCount(papszFields))
1930 : {
1931 0 : m_dXMin = atof(papszFields[++iBounds]);
1932 0 : m_dYMin = atof(papszFields[++iBounds]);
1933 0 : m_dXMax = atof(papszFields[++iBounds]);
1934 0 : m_dYMax = atof(papszFields[++iBounds]);
1935 0 : m_bBoundsSet = TRUE;
1936 :
1937 0 : pszCoordSys[strstr(pszCoordSys, "Bounds") - pszCoordSys] = '\0';
1938 : }
1939 0 : CSLDestroy( papszFields );
1940 :
1941 : // Assign the CoordSys
1942 0 : CPLFree( m_pszCoordSys );
1943 :
1944 0 : m_pszCoordSys = CPLStrdup(pszCoordSys);
1945 0 : CPLFree(pszCoordSys);
1946 :
1947 0 : return( m_pszCoordSys != NULL );
1948 : }
1949 :
1950 : /************************************************************************/
1951 : /* MIFFile::GetSpatialRef() */
1952 : /************************************************************************/
1953 :
1954 1 : OGRSpatialReference *MIFFile::GetSpatialRef()
1955 :
1956 : {
1957 1 : if( m_poSpatialRef == NULL )
1958 1 : m_poSpatialRef = MITABCoordSys2SpatialRef( m_pszCoordSys );
1959 :
1960 1 : return m_poSpatialRef;
1961 : }
1962 :
1963 : /**********************************************************************
1964 : * MIFFile::UpdateExtents()
1965 : *
1966 : * Private Methode used to update the dataset extents
1967 : **********************************************************************/
1968 0 : void MIFFile::UpdateExtents(double dfX, double dfY)
1969 : {
1970 0 : if (m_bExtentsSet == FALSE)
1971 : {
1972 0 : m_bExtentsSet = TRUE;
1973 0 : m_sExtents.MinX = m_sExtents.MaxX = dfX;
1974 0 : m_sExtents.MinY = m_sExtents.MaxY = dfY;
1975 : }
1976 : else
1977 : {
1978 0 : if (dfX < m_sExtents.MinX)
1979 0 : m_sExtents.MinX = dfX;
1980 0 : if (dfX > m_sExtents.MaxX)
1981 0 : m_sExtents.MaxX = dfX;
1982 0 : if (dfY < m_sExtents.MinY)
1983 0 : m_sExtents.MinY = dfY;
1984 0 : if (dfY > m_sExtents.MaxY)
1985 0 : m_sExtents.MaxY = dfY;
1986 : }
1987 0 : }
1988 :
1989 : /**********************************************************************
1990 : * MIFFile::SetBounds()
1991 : *
1992 : * Set projection coordinates bounds of the newly created dataset.
1993 : *
1994 : * This function must be called after creating a new dataset and before any
1995 : * feature can be written to it.
1996 : *
1997 : * Returns 0 on success, -1 on error.
1998 : **********************************************************************/
1999 : int MIFFile::SetBounds(double dXMin, double dYMin,
2000 0 : double dXMax, double dYMax)
2001 : {
2002 0 : if (m_eAccessMode != TABWrite)
2003 : {
2004 : CPLError(CE_Failure, CPLE_NotSupported,
2005 0 : "SetBounds() can be used only with Write access.");
2006 0 : return -1;
2007 : }
2008 :
2009 0 : m_dXMin = dXMin;
2010 0 : m_dXMax = dXMax;
2011 0 : m_dYMin = dYMin;
2012 0 : m_dYMax = dYMax;
2013 0 : m_bBoundsSet = TRUE;
2014 :
2015 0 : return 0;
2016 : }
2017 :
2018 :
2019 : /**********************************************************************
2020 : * MIFFile::GetFeatureCountByType()
2021 : *
2022 : * Return number of features of each type.
2023 : *
2024 : * NOTE: The current implementation always returns -1 for MIF files
2025 : * since this would require scanning the whole file.
2026 : *
2027 : * When properly implemented, the bForce flag will force scanning the
2028 : * whole file by default.
2029 : *
2030 : * Returns 0 on success, or silently returns -1 (with no error) if this
2031 : * information is not available.
2032 : **********************************************************************/
2033 : int MIFFile::GetFeatureCountByType(int &numPoints, int &numLines,
2034 : int &numRegions, int &numTexts,
2035 18 : GBool bForce )
2036 : {
2037 18 : if( m_bPreParsed || bForce )
2038 : {
2039 0 : PreParseFile();
2040 :
2041 0 : numPoints = m_nPoints;
2042 0 : numLines = m_nLines;
2043 0 : numRegions = m_nRegions;
2044 0 : numTexts = m_nTexts;
2045 0 : return 0;
2046 : }
2047 : else
2048 : {
2049 18 : numPoints = numLines = numRegions = numTexts = 0;
2050 18 : return -1;
2051 : }
2052 : }
2053 :
2054 : /**********************************************************************
2055 : * MIFFile::GetBounds()
2056 : *
2057 : * Fetch projection coordinates bounds of a dataset.
2058 : *
2059 : * Pass bForce=FALSE to avoid a scan of the whole file if the bounds
2060 : * are not already available.
2061 : *
2062 : * Returns 0 on success, -1 on error or if bounds are not available and
2063 : * bForce=FALSE.
2064 : **********************************************************************/
2065 : int MIFFile::GetBounds(double &dXMin, double &dYMin,
2066 : double &dXMax, double &dYMax,
2067 0 : GBool bForce /*= TRUE*/ )
2068 : {
2069 :
2070 0 : if (m_bBoundsSet == FALSE && bForce == FALSE)
2071 : {
2072 0 : return -1;
2073 : }
2074 0 : else if (m_bBoundsSet == FALSE)
2075 : {
2076 0 : PreParseFile();
2077 : }
2078 :
2079 0 : if (m_bBoundsSet == FALSE)
2080 : {
2081 0 : return -1;
2082 : }
2083 :
2084 0 : dXMin = m_dXMin;
2085 0 : dXMax = m_dXMax;
2086 0 : dYMin = m_dYMin;
2087 0 : dYMax = m_dYMax;
2088 :
2089 0 : return 0;
2090 : }
2091 :
2092 : /**********************************************************************
2093 : * MIFFile::GetExtent()
2094 : *
2095 : * Fetch extent of the data currently stored in the dataset. We collect
2096 : * this information while preparsing the file ... often already done for
2097 : * other reasons, and if not it is still faster than fully reading all
2098 : * the features just to count them.
2099 : *
2100 : * Returns OGRERR_NONE/OGRRERR_FAILURE.
2101 : **********************************************************************/
2102 0 : OGRErr MIFFile::GetExtent (OGREnvelope *psExtent, int bForce)
2103 : {
2104 0 : if (bForce == TRUE)
2105 0 : PreParseFile();
2106 :
2107 0 : if (m_bPreParsed)
2108 : {
2109 0 : *psExtent = m_sExtents;
2110 0 : return OGRERR_NONE;
2111 : }
2112 : else
2113 0 : return OGRERR_FAILURE;
2114 : }
2115 :
2116 : /************************************************************************/
2117 : /* TestCapability() */
2118 : /************************************************************************/
2119 :
2120 0 : int MIFFile::TestCapability( const char * pszCap )
2121 :
2122 : {
2123 0 : if( EQUAL(pszCap,OLCRandomRead) )
2124 0 : return TRUE;
2125 :
2126 0 : else if( EQUAL(pszCap,OLCSequentialWrite) )
2127 0 : return TRUE;
2128 :
2129 0 : else if( EQUAL(pszCap,OLCSequentialWrite) )
2130 0 : return FALSE;
2131 :
2132 0 : else if( EQUAL(pszCap,OLCFastFeatureCount) )
2133 0 : return m_bPreParsed;
2134 :
2135 0 : else if( EQUAL(pszCap,OLCFastSpatialFilter) )
2136 0 : return FALSE;
2137 :
2138 0 : else if( EQUAL(pszCap,OLCFastGetExtent) )
2139 0 : return m_bPreParsed;
2140 :
2141 : else
2142 0 : return FALSE;
2143 : }
|