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