1 : /******************************************************************************
2 : * $Id: ogrgtmdatasource.cpp 21684 2011-02-11 22:14:01Z warmerdam $
3 : *
4 : * Project: GTM Driver
5 : * Purpose: Implementation of OGRGTMDataSource class.
6 : * Author: Leonardo de Paula Rosa Piga; http://lampiao.lsc.ic.unicamp.br/~piga
7 : *
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2009, Leonardo de Paula Rosa Piga
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 : #include "ogr_gtm.h"
31 :
32 : /************************************************************************/
33 : /* OGRGTMDataSource() */
34 : /************************************************************************/
35 :
36 84 : OGRGTMDataSource::OGRGTMDataSource()
37 : {
38 84 : pszName = NULL;
39 84 : papoLayers = NULL;
40 84 : nLayers = 0;
41 84 : bIssuedCTError = FALSE;
42 84 : poGTMFile = NULL;
43 84 : fpOutput = NULL;
44 84 : fpTmpTrackpoints = NULL;
45 84 : pszTmpTrackpoints = NULL;
46 84 : fpTmpTracks = NULL;
47 84 : pszTmpTracks = NULL;
48 :
49 84 : minlat = 0;
50 84 : maxlat = 0;
51 84 : minlon = 0;
52 84 : maxlon = 0;
53 :
54 84 : numWaypoints = 0;
55 84 : numTracks = 0;
56 84 : numTrackpoints = 0;
57 :
58 84 : }
59 :
60 : /************************************************************************/
61 : /* AppendTemporaryFiles() */
62 : /************************************************************************/
63 84 : void OGRGTMDataSource::AppendTemporaryFiles()
64 : {
65 84 : if( fpOutput == NULL )
66 81 : return;
67 :
68 3 : if (numTrackpoints != 0 || numTracks != 0)
69 : {
70 1 : void* pBuffer = CPLMalloc(2048);
71 : size_t bytes;
72 :
73 : // Append Trackpoints to the output file
74 1 : fpTmpTrackpoints = VSIFOpenL( pszTmpTrackpoints, "r" );
75 1 : if (fpTmpTrackpoints != NULL)
76 : {
77 3 : while ( !VSIFEofL(fpTmpTrackpoints) )
78 : {
79 1 : bytes = VSIFReadL(pBuffer, 1, 2048, fpTmpTrackpoints);
80 1 : VSIFWriteL(pBuffer, bytes, 1, fpOutput);
81 : }
82 1 : VSIFCloseL( fpTmpTrackpoints );
83 1 : fpTmpTrackpoints = NULL;
84 : }
85 :
86 : // Append Tracks to the output file
87 1 : fpTmpTracks = VSIFOpenL( pszTmpTracks, "r" );
88 1 : if (fpTmpTracks != NULL)
89 : {
90 3 : while ( !VSIFEofL(fpTmpTracks) )
91 : {
92 1 : bytes = VSIFReadL(pBuffer, 1, 2048, fpTmpTracks);
93 1 : VSIFWriteL(pBuffer, bytes, 1, fpOutput);
94 : }
95 1 : VSIFCloseL( fpTmpTracks );
96 1 : fpTmpTracks = NULL;
97 : }
98 1 : CPLFree(pBuffer);
99 : }
100 : }
101 :
102 : /************************************************************************/
103 : /* WriteWaypointStyles() */
104 : /************************************************************************/
105 84 : void OGRGTMDataSource::WriteWaypointStyles()
106 : {
107 84 : if( fpOutput != NULL )
108 : {
109 : // We have waypoints, thus we need to write the default
110 : // waypoint style as defined by the specification
111 3 : if ( numWaypoints != 0)
112 : {
113 3 : void* pBuffer = CPLMalloc(35);
114 3 : void* pBufferAux = pBuffer;
115 15 : for (int i = 0; i < 4; ++i)
116 : {
117 : // height
118 12 : appendInt(pBufferAux, -11);
119 12 : pBufferAux = ((char*)pBufferAux) + 4;
120 : // facename size
121 12 : appendUShort(pBufferAux, 5);
122 12 : pBufferAux = ((char*)pBufferAux) + 2;
123 : // facename
124 12 : strncpy((char*)pBufferAux, "Arial", 5);
125 12 : pBufferAux = ((char*)pBufferAux) + 5;
126 : // dspl
127 12 : appendUChar(pBufferAux, (unsigned char) i);
128 12 : pBufferAux = ((char*)pBufferAux) + 1;
129 : // color
130 12 : appendInt(pBufferAux, 0);
131 12 : pBufferAux = ((char*)pBufferAux) + 4;
132 : // weight
133 12 : appendInt(pBufferAux, 400);
134 12 : pBufferAux = ((char*)pBufferAux) + 4;
135 : // scale1
136 12 : appendInt(pBufferAux, 0);
137 12 : pBufferAux = ((char*)pBufferAux) + 4;
138 : // border
139 12 : appendUChar(pBufferAux, (i != 3) ? 0 : 139);
140 12 : pBufferAux = ((char*)pBufferAux) + 1;
141 : // background
142 12 : appendUShort(pBufferAux, (i != 3) ? 0 : 0xFF);
143 12 : pBufferAux = ((char*)pBufferAux) + 2;
144 : // backcolor
145 12 : appendInt(pBufferAux, (i != 3) ? 0 : 0xFFFF);
146 12 : pBufferAux = ((char*)pBufferAux) + 4;
147 : // italic, underline, strikeout
148 12 : appendInt(pBufferAux, 0);
149 12 : pBufferAux = ((char*)pBufferAux) + 3;
150 : // alignment
151 12 : appendUChar(pBufferAux, (i != 3) ? 0 : 1);
152 12 : pBufferAux = pBuffer;
153 12 : VSIFWriteL(pBuffer, 35, 1, fpOutput);
154 : }
155 3 : CPLFree(pBuffer);
156 : }
157 : }
158 84 : }
159 :
160 :
161 : /************************************************************************/
162 : /* ~OGRGTMDataSource() */
163 : /************************************************************************/
164 :
165 84 : OGRGTMDataSource::~OGRGTMDataSource()
166 : {
167 84 : if (fpTmpTrackpoints != NULL)
168 3 : VSIFCloseL( fpTmpTrackpoints );
169 :
170 84 : if (fpTmpTracks != NULL)
171 3 : VSIFCloseL( fpTmpTracks );
172 :
173 84 : WriteWaypointStyles();
174 84 : AppendTemporaryFiles();
175 :
176 84 : if( fpOutput != NULL )
177 : {
178 : /* Adjust header counters */
179 3 : VSIFSeekL(fpOutput, NWPTS_OFFSET, SEEK_SET);
180 3 : writeInt(fpOutput, numWaypoints);
181 3 : writeInt(fpOutput, numTrackpoints);
182 :
183 3 : VSIFSeekL(fpOutput, NTK_OFFSET, SEEK_SET);
184 3 : writeInt(fpOutput, numTracks);
185 :
186 : /* Adjust header bounds */
187 3 : VSIFSeekL(fpOutput, BOUNDS_OFFSET, SEEK_SET);
188 3 : writeFloat(fpOutput, maxlon);
189 3 : writeFloat(fpOutput, minlon);
190 3 : writeFloat(fpOutput, maxlat);
191 3 : writeFloat(fpOutput, minlat);
192 3 : VSIFCloseL( fpOutput );
193 : }
194 :
195 :
196 84 : if (papoLayers != NULL)
197 : {
198 19 : for( int i = 0; i < nLayers; i++ )
199 12 : delete papoLayers[i];
200 7 : CPLFree( papoLayers );
201 : }
202 :
203 84 : if (pszName != NULL)
204 7 : CPLFree( pszName );
205 :
206 84 : if (pszTmpTracks != NULL)
207 : {
208 3 : VSIUnlink( pszTmpTracks );
209 3 : CPLFree( pszTmpTracks );
210 : }
211 :
212 84 : if (pszTmpTrackpoints != NULL)
213 : {
214 3 : VSIUnlink( pszTmpTrackpoints );
215 3 : CPLFree( pszTmpTrackpoints );
216 : }
217 :
218 84 : if (poGTMFile != NULL)
219 4 : delete poGTMFile;
220 84 : }
221 :
222 :
223 :
224 : /************************************************************************/
225 : /* Open() */
226 : /************************************************************************/
227 :
228 81 : int OGRGTMDataSource::Open(const char* pszFilename, int bUpdate)
229 : {
230 81 : CPLAssert( pszFilename != NULL );
231 :
232 : /* Should not happen as the driver already returned if bUpdate == NULL */
233 81 : if (bUpdate)
234 : {
235 : CPLError(CE_Failure, CPLE_NotSupported,
236 0 : "GTM driver does not support opening in update mode");
237 0 : return FALSE;
238 : }
239 :
240 : /* -------------------------------------------------------------------- */
241 : /* Create a GTM object and open the source file. */
242 : /* -------------------------------------------------------------------- */
243 81 : poGTMFile = new GTM();
244 :
245 81 : if ( !poGTMFile->Open( pszFilename ) )
246 : {
247 37 : delete poGTMFile;
248 37 : poGTMFile = NULL;
249 37 : return FALSE;
250 : }
251 :
252 : /* -------------------------------------------------------------------- */
253 : /* Validate it by start parsing */
254 : /* -------------------------------------------------------------------- */
255 44 : if( !poGTMFile->isValid() )
256 : {
257 40 : delete poGTMFile;
258 40 : poGTMFile = NULL;
259 40 : return FALSE;
260 : }
261 :
262 4 : pszName = CPLStrdup( pszFilename );
263 : /* -------------------------------------------------------------------- */
264 : /* Now, we are able to read the file header and find the position */
265 : /* of the first waypoint and the position of the first track. */
266 : /* -------------------------------------------------------------------- */
267 4 : if ( !poGTMFile->readHeaderNumbers() )
268 0 : return FALSE;
269 :
270 : /* -------------------------------------------------------------------- */
271 : /* We can start reading the file elements */
272 : /* We are going to translate GTM features into layers */
273 : /* -------------------------------------------------------------------- */
274 4 : char* pszBaseFileName = CPLStrdup( CPLGetBasename(pszFilename) );
275 : /* We are going to create two layers, one for storing waypoints and
276 : another for storing tracks */
277 4 : papoLayers = (OGRGTMLayer **) CPLMalloc(sizeof(void*) * 2);
278 :
279 :
280 : /* Create a spatial reference for WGS8*/
281 4 : OGRSpatialReference* poSRS = new OGRSpatialReference(NULL);
282 4 : poSRS->SetWellKnownGeogCS( "WGS84" );
283 :
284 :
285 : /* Waypoint layer */
286 4 : size_t layerNameSize = strlen(pszBaseFileName) + sizeof("_waypoints");
287 4 : char* pszLayerName = (char*) CPLMalloc(layerNameSize);
288 : /* The layer name will be "<basename>_waypoints" */
289 4 : strcpy (pszLayerName, pszBaseFileName);
290 4 : CPLStrlcat (pszLayerName, "_waypoints", layerNameSize);
291 :
292 : /* Store the layer of waypoints */
293 :
294 : GTMWaypointLayer* poWaypointLayer = new GTMWaypointLayer ( pszLayerName,
295 : poSRS,
296 : FALSE,
297 8 : this );
298 4 : papoLayers[nLayers++] = poWaypointLayer;
299 4 : CPLFree(pszLayerName);
300 :
301 : /* Track layer */
302 4 : layerNameSize = strlen(pszBaseFileName) + sizeof("_tracks");
303 4 : pszLayerName = (char*) CPLMalloc(layerNameSize);
304 : /* The layer name will be "<basename>_tracks" */
305 4 : strcpy (pszLayerName, pszBaseFileName);
306 4 : CPLStrlcat (pszLayerName, "_tracks", layerNameSize);
307 :
308 4 : CPLFree(pszBaseFileName);
309 : /* Store the layer of tracks */
310 : GTMTrackLayer* poTrackLayer = new GTMTrackLayer ( pszLayerName,
311 : poSRS,
312 : FALSE,
313 8 : this );
314 4 : papoLayers[nLayers++] = poTrackLayer;
315 4 : CPLFree(pszLayerName);
316 :
317 4 : poSRS->Release();
318 4 : return TRUE;
319 :
320 : }
321 :
322 :
323 : /************************************************************************/
324 : /* Create() */
325 : /************************************************************************/
326 :
327 3 : int OGRGTMDataSource::Create( const char* pszFilename, char** papszOptions )
328 : {
329 3 : CPLAssert( NULL != pszFilename );
330 :
331 3 : if( fpOutput != NULL )
332 : {
333 0 : CPLAssert( FALSE );
334 0 : return FALSE;
335 : }
336 :
337 :
338 : /* -------------------------------------------------------------------- */
339 : /* Do not override exiting file. */
340 : /* -------------------------------------------------------------------- */
341 : VSIStatBufL sStatBuf;
342 :
343 3 : if( VSIStatL( pszFilename, &sStatBuf ) == 0 )
344 : {
345 : CPLError(CE_Failure, CPLE_NotSupported,
346 : "You have to delete %s before being able to create it with the GTM driver",
347 0 : pszFilename);
348 0 : return FALSE;
349 : }
350 :
351 :
352 : /* -------------------------------------------------------------------- */
353 : /* Create the output file. */
354 : /* -------------------------------------------------------------------- */
355 3 : pszName = CPLStrdup( pszFilename );
356 :
357 3 : fpOutput = VSIFOpenL( pszFilename, "w" );
358 3 : if( fpOutput == NULL )
359 : {
360 : CPLError( CE_Failure, CPLE_OpenFailed,
361 : "Failed to create GTM file %s.",
362 0 : pszFilename );
363 0 : return FALSE;
364 : }
365 :
366 : // Generate a temporary file for Trackpoints
367 3 : const char* pszTmpName = CPLGenerateTempFilename(NULL);
368 3 : pszTmpTrackpoints = CPLStrdup( pszTmpName );
369 3 : fpTmpTrackpoints = VSIFOpenL(pszTmpName , "w" );
370 3 : if( fpTmpTrackpoints == NULL )
371 : {
372 : CPLError( CE_Failure, CPLE_OpenFailed,
373 : "Failed to create temporary file %s.",
374 0 : pszTmpName );
375 0 : return FALSE;
376 : }
377 : // Generate a temporary file for Tracks
378 3 : pszTmpName = CPLGenerateTempFilename(NULL);
379 3 : pszTmpTracks = CPLStrdup( pszTmpName );
380 3 : fpTmpTracks = VSIFOpenL(pszTmpName , "w" );
381 3 : if( fpTmpTracks == NULL )
382 : {
383 : CPLError( CE_Failure, CPLE_OpenFailed,
384 : "Failed to create temporary file %s.",
385 0 : pszTmpName );
386 0 : return FALSE;
387 : }
388 :
389 : /* -------------------------------------------------------------------- */
390 : /* Output header of GTM file. */
391 : /* -------------------------------------------------------------------- */
392 3 : char* pszBaseFileName = CPLStrdup( CPLGetBasename(pszFilename) );
393 3 : int sizeBuffer = 175 + strlen(pszBaseFileName);
394 3 : void* pBuffer = CPLCalloc(1, sizeBuffer);
395 3 : void* pCurrentPos = pBuffer;
396 :
397 : // Write version number
398 3 : appendUShort(pCurrentPos, 211);
399 3 : pCurrentPos = ((char*)pCurrentPos) + 2;
400 : // Write code
401 3 : strcpy((char*)pCurrentPos, "TrackMaker");
402 : // gradnum
403 3 : pCurrentPos = (char*) pBuffer + 14;
404 3 : appendUChar(pCurrentPos, 8);
405 : // bcolor
406 3 : pCurrentPos = (char*) pBuffer + 23;
407 3 : appendInt(pCurrentPos, 0xffffff);
408 : // nwptstyles -- We just create the defaults, so four
409 3 : pCurrentPos = (char*) pBuffer + 27;
410 3 : appendInt(pCurrentPos, 4);
411 : // gradfont, labelfont
412 3 : pCurrentPos = (char*) pBuffer + 99;
413 9 : for (int i = 0; i < 2; i++)
414 : {
415 6 : appendUShort(pCurrentPos, 5);
416 6 : pCurrentPos = ((char*)pCurrentPos) + 2;
417 6 : strcpy((char*)pCurrentPos, "Arial");
418 6 : pCurrentPos = ((char*)pCurrentPos) + 5;
419 : }
420 3 : appendUShort(pCurrentPos, (unsigned short) strlen(pszBaseFileName));
421 3 : pCurrentPos = ((char*)pCurrentPos) + 2;
422 3 : strcpy((char*)pCurrentPos, pszBaseFileName);
423 :
424 : // write ndatum. We are implementing just WGS84, so write the
425 : // correspondig value for WGS84
426 3 : pCurrentPos = ((char*) pBuffer) + 151 + strlen(pszBaseFileName);
427 3 : appendInt(pCurrentPos, 217);
428 :
429 3 : VSIFWriteL(pBuffer, sizeBuffer, 1, fpOutput);
430 :
431 3 : CPLFree(pszBaseFileName);
432 3 : CPLFree(pBuffer);
433 3 : return TRUE;
434 : }
435 :
436 :
437 : /************************************************************************/
438 : /* GetLayer() */
439 : /************************************************************************/
440 10 : OGRLayer* OGRGTMDataSource::GetLayer( int iLayer )
441 : {
442 10 : if( iLayer < 0 || iLayer >= nLayers )
443 0 : return NULL;
444 : else
445 10 : return papoLayers[iLayer];
446 : }
447 :
448 :
449 : /************************************************************************/
450 : /* CreateLayer() */
451 : /************************************************************************/
452 :
453 4 : OGRLayer * OGRGTMDataSource::CreateLayer( const char * pszLayerName,
454 : OGRSpatialReference *poSRS,
455 : OGRwkbGeometryType eType,
456 : char ** papszOptions )
457 :
458 : {
459 4 : if (eType == wkbPoint || eType == wkbPoint25D)
460 : {
461 : // Waypoints
462 3 : nLayers++;
463 3 : papoLayers = (OGRGTMLayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRGTMLayer*));
464 3 : papoLayers[nLayers-1] = new GTMWaypointLayer( pszName, poSRS, TRUE, this );
465 3 : return papoLayers[nLayers-1];
466 :
467 : }
468 1 : else if (eType == wkbLineString || eType == wkbLineString25D ||
469 : eType == wkbMultiLineString || eType == wkbMultiLineString25D)
470 : {
471 : // Tracks
472 1 : nLayers++;
473 1 : papoLayers = (OGRGTMLayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRGTMLayer*));
474 1 : papoLayers[nLayers-1] = new GTMTrackLayer( pszName, poSRS, TRUE, this );
475 1 : return papoLayers[nLayers-1];
476 : }
477 0 : else if (eType == wkbUnknown)
478 : {
479 : CPLError(CE_Failure, CPLE_NotSupported,
480 0 : "Cannot create GTM layer %s with unknown geometry type", pszLayerName);
481 0 : return NULL;
482 : }
483 : else
484 : {
485 : CPLError( CE_Failure, CPLE_NotSupported,
486 : "Geometry type of `%s' not supported in GTM.\n",
487 0 : OGRGeometryTypeToName(eType) );
488 0 : return NULL;
489 : }
490 :
491 : }
492 :
493 :
494 : /************************************************************************/
495 : /* TestCapability() */
496 : /************************************************************************/
497 :
498 2 : int OGRGTMDataSource::TestCapability( const char * pszCap )
499 :
500 : {
501 2 : if( EQUAL(pszCap,ODsCCreateLayer) )
502 2 : return TRUE;
503 : else
504 0 : return FALSE;
505 : }
506 :
507 : /************************************************************************/
508 : /* Methods for creating a new gtm file */
509 : /************************************************************************/
510 12 : void OGRGTMDataSource::checkBounds(float newLat,
511 : float newLon)
512 : {
513 15 : if (minlat == 0 && maxlat == 0 &&
514 : minlon == 0 && maxlon == 0)
515 : {
516 3 : minlat = newLat;
517 3 : maxlat = newLat;
518 3 : minlon = newLon;
519 3 : maxlon = newLon;
520 : }
521 : else
522 : {
523 9 : minlat = MIN(newLat, minlat);
524 9 : maxlat = MAX(newLat, maxlat);
525 9 : minlon = MIN(newLon, minlon);
526 9 : maxlon = MAX(newLon, maxlon);
527 : }
528 12 : }
529 :
530 :
531 :
532 : /************************************************************************/
533 : /* Methods for reading existent file */
534 : /************************************************************************/
535 :
536 :
537 : /*======================================================================*/
538 : /* Waypoint Methods */
539 : /*======================================================================*/
540 :
541 :
542 : /*----------------------------------------------------------------------*/
543 : /* getNWpts() */
544 : /*----------------------------------------------------------------------*/
545 :
546 9 : int OGRGTMDataSource::getNWpts()
547 : {
548 9 : if (poGTMFile == NULL)
549 3 : return 0;
550 :
551 6 : return poGTMFile->getNWpts();
552 : }
553 :
554 :
555 : /*----------------------------------------------------------------------*/
556 : /* hasNextWaypoint() */
557 : /*----------------------------------------------------------------------*/
558 7 : bool OGRGTMDataSource::hasNextWaypoint()
559 : {
560 7 : if (poGTMFile == NULL)
561 0 : return FALSE;
562 :
563 7 : return poGTMFile->hasNextWaypoint();
564 : }
565 :
566 :
567 : /*----------------------------------------------------------------------*/
568 : /* fetchNextWaypoint() */
569 : /*----------------------------------------------------------------------*/
570 7 : Waypoint* OGRGTMDataSource::fetchNextWaypoint()
571 : {
572 7 : if (poGTMFile == NULL)
573 0 : return NULL;
574 :
575 7 : return poGTMFile->fetchNextWaypoint();
576 : }
577 :
578 :
579 : /*----------------------------------------------------------------------*/
580 : /* rewindWaypoint() */
581 : /*----------------------------------------------------------------------*/
582 0 : void OGRGTMDataSource::rewindWaypoint()
583 : {
584 0 : if (poGTMFile == NULL)
585 0 : return;
586 :
587 0 : poGTMFile->rewindWaypoint();
588 : }
589 :
590 :
591 :
592 : /*======================================================================*/
593 : /* Tracks Methods */
594 : /*======================================================================*/
595 :
596 :
597 : /*----------------------------------------------------------------------*/
598 : /* getNTracks() */
599 : /*----------------------------------------------------------------------*/
600 :
601 7 : int OGRGTMDataSource::getNTracks()
602 : {
603 7 : if (poGTMFile == NULL)
604 1 : return 0;
605 :
606 6 : return poGTMFile->getNTracks();
607 : }
608 :
609 :
610 : /*----------------------------------------------------------------------*/
611 : /* hasNextTrack() */
612 : /*----------------------------------------------------------------------*/
613 7 : bool OGRGTMDataSource::hasNextTrack()
614 : {
615 7 : if (poGTMFile == NULL)
616 0 : return FALSE;
617 :
618 7 : return poGTMFile->hasNextTrack();
619 : }
620 :
621 :
622 : /*----------------------------------------------------------------------*/
623 : /* fetchNextTrack() */
624 : /*----------------------------------------------------------------------*/
625 7 : Track* OGRGTMDataSource::fetchNextTrack()
626 : {
627 7 : if (poGTMFile == NULL)
628 0 : return NULL;
629 :
630 7 : return poGTMFile->fetchNextTrack();
631 : }
632 :
633 :
634 : /*----------------------------------------------------------------------*/
635 : /* rewindTrack() */
636 : /*----------------------------------------------------------------------*/
637 0 : void OGRGTMDataSource::rewindTrack()
638 : {
639 0 : if (poGTMFile == NULL)
640 0 : return;
641 :
642 0 : poGTMFile->rewindTrack();
643 1947 : }
644 :
|