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 226 : OGRGTMDataSource::OGRGTMDataSource()
37 : {
38 226 : pszName = NULL;
39 226 : papoLayers = NULL;
40 226 : nLayers = 0;
41 226 : bIssuedCTError = FALSE;
42 226 : poGTMFile = NULL;
43 226 : fpOutput = NULL;
44 226 : fpTmpTrackpoints = NULL;
45 226 : pszTmpTrackpoints = NULL;
46 226 : fpTmpTracks = NULL;
47 226 : pszTmpTracks = NULL;
48 :
49 226 : minlat = 0;
50 226 : maxlat = 0;
51 226 : minlon = 0;
52 226 : maxlon = 0;
53 :
54 226 : numWaypoints = 0;
55 226 : numTracks = 0;
56 226 : numTrackpoints = 0;
57 :
58 226 : }
59 :
60 : /************************************************************************/
61 : /* AppendTemporaryFiles() */
62 : /************************************************************************/
63 226 : void OGRGTMDataSource::AppendTemporaryFiles()
64 : {
65 226 : if( fpOutput == NULL )
66 220 : return;
67 :
68 6 : if (numTrackpoints != 0 || numTracks != 0)
69 : {
70 2 : void* pBuffer = CPLMalloc(2048);
71 : size_t bytes;
72 :
73 : // Append Trackpoints to the output file
74 2 : fpTmpTrackpoints = VSIFOpenL( pszTmpTrackpoints, "r" );
75 2 : if (fpTmpTrackpoints != NULL)
76 : {
77 6 : while ( !VSIFEofL(fpTmpTrackpoints) )
78 : {
79 2 : bytes = VSIFReadL(pBuffer, 1, 2048, fpTmpTrackpoints);
80 2 : VSIFWriteL(pBuffer, bytes, 1, fpOutput);
81 : }
82 2 : VSIFCloseL( fpTmpTrackpoints );
83 2 : fpTmpTrackpoints = NULL;
84 : }
85 :
86 : // Append Tracks to the output file
87 2 : fpTmpTracks = VSIFOpenL( pszTmpTracks, "r" );
88 2 : if (fpTmpTracks != NULL)
89 : {
90 6 : while ( !VSIFEofL(fpTmpTracks) )
91 : {
92 2 : bytes = VSIFReadL(pBuffer, 1, 2048, fpTmpTracks);
93 2 : VSIFWriteL(pBuffer, bytes, 1, fpOutput);
94 : }
95 2 : VSIFCloseL( fpTmpTracks );
96 2 : fpTmpTracks = NULL;
97 : }
98 2 : CPLFree(pBuffer);
99 : }
100 : }
101 :
102 : /************************************************************************/
103 : /* WriteWaypointStyles() */
104 : /************************************************************************/
105 226 : void OGRGTMDataSource::WriteWaypointStyles()
106 : {
107 226 : if( fpOutput != NULL )
108 : {
109 : // We have waypoints, thus we need to write the default
110 : // waypoint style as defined by the specification
111 6 : if ( numWaypoints != 0)
112 : {
113 6 : void* pBuffer = CPLMalloc(35);
114 6 : void* pBufferAux = pBuffer;
115 30 : for (int i = 0; i < 4; ++i)
116 : {
117 : // height
118 24 : appendInt(pBufferAux, -11);
119 24 : pBufferAux = ((char*)pBufferAux) + 4;
120 : // facename size
121 24 : appendUShort(pBufferAux, 5);
122 24 : pBufferAux = ((char*)pBufferAux) + 2;
123 : // facename
124 24 : strncpy((char*)pBufferAux, "Arial", 5);
125 24 : pBufferAux = ((char*)pBufferAux) + 5;
126 : // dspl
127 24 : appendUChar(pBufferAux, (unsigned char) i);
128 24 : pBufferAux = ((char*)pBufferAux) + 1;
129 : // color
130 24 : appendInt(pBufferAux, 0);
131 24 : pBufferAux = ((char*)pBufferAux) + 4;
132 : // weight
133 24 : appendInt(pBufferAux, 400);
134 24 : pBufferAux = ((char*)pBufferAux) + 4;
135 : // scale1
136 24 : appendInt(pBufferAux, 0);
137 24 : pBufferAux = ((char*)pBufferAux) + 4;
138 : // border
139 24 : appendUChar(pBufferAux, (i != 3) ? 0 : 139);
140 24 : pBufferAux = ((char*)pBufferAux) + 1;
141 : // background
142 24 : appendUShort(pBufferAux, (i != 3) ? 0 : 0xFF);
143 24 : pBufferAux = ((char*)pBufferAux) + 2;
144 : // backcolor
145 24 : appendInt(pBufferAux, (i != 3) ? 0 : 0xFFFF);
146 24 : pBufferAux = ((char*)pBufferAux) + 4;
147 : // italic, underline, strikeout
148 24 : appendInt(pBufferAux, 0);
149 24 : pBufferAux = ((char*)pBufferAux) + 3;
150 : // alignment
151 24 : appendUChar(pBufferAux, (i != 3) ? 0 : 1);
152 24 : pBufferAux = pBuffer;
153 24 : VSIFWriteL(pBuffer, 35, 1, fpOutput);
154 : }
155 6 : CPLFree(pBuffer);
156 : }
157 : }
158 226 : }
159 :
160 :
161 : /************************************************************************/
162 : /* ~OGRGTMDataSource() */
163 : /************************************************************************/
164 :
165 226 : OGRGTMDataSource::~OGRGTMDataSource()
166 : {
167 226 : if (fpTmpTrackpoints != NULL)
168 6 : VSIFCloseL( fpTmpTrackpoints );
169 :
170 226 : if (fpTmpTracks != NULL)
171 6 : VSIFCloseL( fpTmpTracks );
172 :
173 226 : WriteWaypointStyles();
174 226 : AppendTemporaryFiles();
175 :
176 226 : if( fpOutput != NULL )
177 : {
178 : /* Adjust header counters */
179 6 : VSIFSeekL(fpOutput, NWPTS_OFFSET, SEEK_SET);
180 6 : writeInt(fpOutput, numWaypoints);
181 6 : writeInt(fpOutput, numTrackpoints);
182 :
183 6 : VSIFSeekL(fpOutput, NTK_OFFSET, SEEK_SET);
184 6 : writeInt(fpOutput, numTracks);
185 :
186 : /* Adjust header bounds */
187 6 : VSIFSeekL(fpOutput, BOUNDS_OFFSET, SEEK_SET);
188 6 : writeFloat(fpOutput, maxlon);
189 6 : writeFloat(fpOutput, minlon);
190 6 : writeFloat(fpOutput, maxlat);
191 6 : writeFloat(fpOutput, minlat);
192 6 : VSIFCloseL( fpOutput );
193 : }
194 :
195 :
196 226 : if (papoLayers != NULL)
197 : {
198 38 : for( int i = 0; i < nLayers; i++ )
199 24 : delete papoLayers[i];
200 14 : CPLFree( papoLayers );
201 : }
202 :
203 226 : if (pszName != NULL)
204 14 : CPLFree( pszName );
205 :
206 226 : if (pszTmpTracks != NULL)
207 : {
208 6 : VSIUnlink( pszTmpTracks );
209 6 : CPLFree( pszTmpTracks );
210 : }
211 :
212 226 : if (pszTmpTrackpoints != NULL)
213 : {
214 6 : VSIUnlink( pszTmpTrackpoints );
215 6 : CPLFree( pszTmpTrackpoints );
216 : }
217 :
218 226 : if (poGTMFile != NULL)
219 8 : delete poGTMFile;
220 226 : }
221 :
222 :
223 :
224 : /************************************************************************/
225 : /* Open() */
226 : /************************************************************************/
227 :
228 220 : int OGRGTMDataSource::Open(const char* pszFilename, int bUpdate)
229 : {
230 220 : CPLAssert( pszFilename != NULL );
231 :
232 : /* Should not happen as the driver already returned if bUpdate == NULL */
233 220 : 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 220 : poGTMFile = new GTM();
244 :
245 220 : if ( !poGTMFile->Open( pszFilename ) )
246 : {
247 80 : delete poGTMFile;
248 80 : poGTMFile = NULL;
249 80 : return FALSE;
250 : }
251 :
252 : /* -------------------------------------------------------------------- */
253 : /* Validate it by start parsing */
254 : /* -------------------------------------------------------------------- */
255 140 : if( !poGTMFile->isValid() )
256 : {
257 132 : delete poGTMFile;
258 132 : poGTMFile = NULL;
259 132 : return FALSE;
260 : }
261 :
262 8 : 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 8 : 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 8 : char* pszBaseFileName = CPLStrdup( CPLGetBasename(pszFilename) );
275 : /* We are going to create two layers, one for storing waypoints and
276 : another for storing tracks */
277 8 : papoLayers = (OGRGTMLayer **) CPLMalloc(sizeof(void*) * 2);
278 :
279 :
280 : /* Create a spatial reference for WGS8*/
281 8 : OGRSpatialReference* poSRS = new OGRSpatialReference(NULL);
282 8 : poSRS->SetWellKnownGeogCS( "WGS84" );
283 :
284 :
285 : /* Waypoint layer */
286 8 : size_t layerNameSize = strlen(pszBaseFileName) + sizeof("_waypoints");
287 8 : char* pszLayerName = (char*) CPLMalloc(layerNameSize);
288 : /* The layer name will be "<basename>_waypoints" */
289 8 : strcpy (pszLayerName, pszBaseFileName);
290 8 : CPLStrlcat (pszLayerName, "_waypoints", layerNameSize);
291 :
292 : /* Store the layer of waypoints */
293 :
294 : GTMWaypointLayer* poWaypointLayer = new GTMWaypointLayer ( pszLayerName,
295 : poSRS,
296 : FALSE,
297 16 : this );
298 8 : papoLayers[nLayers++] = poWaypointLayer;
299 8 : CPLFree(pszLayerName);
300 :
301 : /* Track layer */
302 8 : layerNameSize = strlen(pszBaseFileName) + sizeof("_tracks");
303 8 : pszLayerName = (char*) CPLMalloc(layerNameSize);
304 : /* The layer name will be "<basename>_tracks" */
305 8 : strcpy (pszLayerName, pszBaseFileName);
306 8 : CPLStrlcat (pszLayerName, "_tracks", layerNameSize);
307 :
308 8 : CPLFree(pszBaseFileName);
309 : /* Store the layer of tracks */
310 : GTMTrackLayer* poTrackLayer = new GTMTrackLayer ( pszLayerName,
311 : poSRS,
312 : FALSE,
313 16 : this );
314 8 : papoLayers[nLayers++] = poTrackLayer;
315 8 : CPLFree(pszLayerName);
316 :
317 8 : poSRS->Release();
318 8 : return TRUE;
319 :
320 : }
321 :
322 :
323 : /************************************************************************/
324 : /* Create() */
325 : /************************************************************************/
326 :
327 6 : int OGRGTMDataSource::Create( const char* pszFilename, char** papszOptions )
328 : {
329 6 : CPLAssert( NULL != pszFilename );
330 :
331 6 : 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 6 : 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 6 : pszName = CPLStrdup( pszFilename );
356 :
357 6 : fpOutput = VSIFOpenL( pszFilename, "w" );
358 6 : 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 6 : const char* pszTmpName = CPLGenerateTempFilename(NULL);
368 6 : pszTmpTrackpoints = CPLStrdup( pszTmpName );
369 6 : fpTmpTrackpoints = VSIFOpenL(pszTmpName , "w" );
370 6 : 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 6 : pszTmpName = CPLGenerateTempFilename(NULL);
379 6 : pszTmpTracks = CPLStrdup( pszTmpName );
380 6 : fpTmpTracks = VSIFOpenL(pszTmpName , "w" );
381 6 : 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 6 : char* pszBaseFileName = CPLStrdup( CPLGetBasename(pszFilename) );
393 6 : int sizeBuffer = 175 + strlen(pszBaseFileName);
394 6 : void* pBuffer = CPLCalloc(1, sizeBuffer);
395 6 : void* pCurrentPos = pBuffer;
396 :
397 : // Write version number
398 6 : appendUShort(pCurrentPos, 211);
399 6 : pCurrentPos = ((char*)pCurrentPos) + 2;
400 : // Write code
401 6 : strcpy((char*)pCurrentPos, "TrackMaker");
402 : // gradnum
403 6 : pCurrentPos = (char*) pBuffer + 14;
404 6 : appendUChar(pCurrentPos, 8);
405 : // bcolor
406 6 : pCurrentPos = (char*) pBuffer + 23;
407 6 : appendInt(pCurrentPos, 0xffffff);
408 : // nwptstyles -- We just create the defaults, so four
409 6 : pCurrentPos = (char*) pBuffer + 27;
410 6 : appendInt(pCurrentPos, 4);
411 : // gradfont, labelfont
412 6 : pCurrentPos = (char*) pBuffer + 99;
413 18 : for (int i = 0; i < 2; i++)
414 : {
415 12 : appendUShort(pCurrentPos, 5);
416 12 : pCurrentPos = ((char*)pCurrentPos) + 2;
417 12 : strcpy((char*)pCurrentPos, "Arial");
418 12 : pCurrentPos = ((char*)pCurrentPos) + 5;
419 : }
420 6 : appendUShort(pCurrentPos, (unsigned short) strlen(pszBaseFileName));
421 6 : pCurrentPos = ((char*)pCurrentPos) + 2;
422 6 : strcpy((char*)pCurrentPos, pszBaseFileName);
423 :
424 : // write ndatum. We are implementing just WGS84, so write the
425 : // correspondig value for WGS84
426 6 : pCurrentPos = ((char*) pBuffer) + 151 + strlen(pszBaseFileName);
427 6 : appendInt(pCurrentPos, 217);
428 :
429 6 : VSIFWriteL(pBuffer, sizeBuffer, 1, fpOutput);
430 :
431 6 : CPLFree(pszBaseFileName);
432 6 : CPLFree(pBuffer);
433 6 : return TRUE;
434 : }
435 :
436 :
437 : /************************************************************************/
438 : /* GetLayer() */
439 : /************************************************************************/
440 20 : OGRLayer* OGRGTMDataSource::GetLayer( int iLayer )
441 : {
442 20 : if( iLayer < 0 || iLayer >= nLayers )
443 0 : return NULL;
444 : else
445 20 : return papoLayers[iLayer];
446 : }
447 :
448 :
449 : /************************************************************************/
450 : /* CreateLayer() */
451 : /************************************************************************/
452 :
453 8 : OGRLayer * OGRGTMDataSource::CreateLayer( const char * pszLayerName,
454 : OGRSpatialReference *poSRS,
455 : OGRwkbGeometryType eType,
456 : char ** papszOptions )
457 :
458 : {
459 8 : if (eType == wkbPoint || eType == wkbPoint25D)
460 : {
461 : // Waypoints
462 6 : nLayers++;
463 6 : papoLayers = (OGRGTMLayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRGTMLayer*));
464 6 : papoLayers[nLayers-1] = new GTMWaypointLayer( pszName, poSRS, TRUE, this );
465 6 : return papoLayers[nLayers-1];
466 :
467 : }
468 2 : else if (eType == wkbLineString || eType == wkbLineString25D ||
469 : eType == wkbMultiLineString || eType == wkbMultiLineString25D)
470 : {
471 : // Tracks
472 2 : nLayers++;
473 2 : papoLayers = (OGRGTMLayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRGTMLayer*));
474 2 : papoLayers[nLayers-1] = new GTMTrackLayer( pszName, poSRS, TRUE, this );
475 2 : 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 4 : int OGRGTMDataSource::TestCapability( const char * pszCap )
499 :
500 : {
501 4 : if( EQUAL(pszCap,ODsCCreateLayer) )
502 4 : return TRUE;
503 : else
504 0 : return FALSE;
505 : }
506 :
507 : /************************************************************************/
508 : /* Methods for creating a new gtm file */
509 : /************************************************************************/
510 24 : void OGRGTMDataSource::checkBounds(float newLat,
511 : float newLon)
512 : {
513 30 : if (minlat == 0 && maxlat == 0 &&
514 : minlon == 0 && maxlon == 0)
515 : {
516 6 : minlat = newLat;
517 6 : maxlat = newLat;
518 6 : minlon = newLon;
519 6 : maxlon = newLon;
520 : }
521 : else
522 : {
523 18 : minlat = MIN(newLat, minlat);
524 18 : maxlat = MAX(newLat, maxlat);
525 18 : minlon = MIN(newLon, minlon);
526 18 : maxlon = MAX(newLon, maxlon);
527 : }
528 24 : }
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 18 : int OGRGTMDataSource::getNWpts()
547 : {
548 18 : if (poGTMFile == NULL)
549 6 : return 0;
550 :
551 12 : return poGTMFile->getNWpts();
552 : }
553 :
554 :
555 : /*----------------------------------------------------------------------*/
556 : /* hasNextWaypoint() */
557 : /*----------------------------------------------------------------------*/
558 14 : bool OGRGTMDataSource::hasNextWaypoint()
559 : {
560 14 : if (poGTMFile == NULL)
561 0 : return FALSE;
562 :
563 14 : return poGTMFile->hasNextWaypoint();
564 : }
565 :
566 :
567 : /*----------------------------------------------------------------------*/
568 : /* fetchNextWaypoint() */
569 : /*----------------------------------------------------------------------*/
570 14 : Waypoint* OGRGTMDataSource::fetchNextWaypoint()
571 : {
572 14 : if (poGTMFile == NULL)
573 0 : return NULL;
574 :
575 14 : 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 14 : int OGRGTMDataSource::getNTracks()
602 : {
603 14 : if (poGTMFile == NULL)
604 2 : return 0;
605 :
606 12 : return poGTMFile->getNTracks();
607 : }
608 :
609 :
610 : /*----------------------------------------------------------------------*/
611 : /* hasNextTrack() */
612 : /*----------------------------------------------------------------------*/
613 14 : bool OGRGTMDataSource::hasNextTrack()
614 : {
615 14 : if (poGTMFile == NULL)
616 0 : return FALSE;
617 :
618 14 : return poGTMFile->hasNextTrack();
619 : }
620 :
621 :
622 : /*----------------------------------------------------------------------*/
623 : /* fetchNextTrack() */
624 : /*----------------------------------------------------------------------*/
625 14 : Track* OGRGTMDataSource::fetchNextTrack()
626 : {
627 14 : if (poGTMFile == NULL)
628 0 : return NULL;
629 :
630 14 : 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 4029 : }
644 :
|