1 : /******************************************************************************
2 : * $Id: gifabstractdataset.cpp 22685 2011-07-10 19:31:35Z rouault $
3 : *
4 : * Project: GIF Driver
5 : * Purpose: GIF Abstract Dataset
6 : * Author: Even Rouault <even dot rouault at mines dash paris dot org>
7 : *
8 : ****************************************************************************
9 : * Copyright (c) 2011, Even Rouault <even dot rouault at mines dash paris dot org>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gifabstractdataset.h"
31 :
32 : CPL_CVSID("$Id: gifabstractdataset.cpp 22685 2011-07-10 19:31:35Z rouault $");
33 :
34 : /************************************************************************/
35 : /* ==================================================================== */
36 : /* GIFAbstractDataset */
37 : /* ==================================================================== */
38 : /************************************************************************/
39 :
40 :
41 : /************************************************************************/
42 : /* GIFAbstractDataset() */
43 : /************************************************************************/
44 :
45 31 : GIFAbstractDataset::GIFAbstractDataset()
46 :
47 : {
48 31 : hGifFile = NULL;
49 31 : fp = NULL;
50 :
51 31 : pszProjection = NULL;
52 31 : bGeoTransformValid = FALSE;
53 31 : adfGeoTransform[0] = 0.0;
54 31 : adfGeoTransform[1] = 1.0;
55 31 : adfGeoTransform[2] = 0.0;
56 31 : adfGeoTransform[3] = 0.0;
57 31 : adfGeoTransform[4] = 0.0;
58 31 : adfGeoTransform[5] = 1.0;
59 :
60 31 : nGCPCount = 0;
61 31 : pasGCPList = NULL;
62 :
63 31 : bHasReadXMPMetadata = FALSE;
64 31 : }
65 :
66 : /************************************************************************/
67 : /* ~GIFAbstractDataset() */
68 : /************************************************************************/
69 :
70 31 : GIFAbstractDataset::~GIFAbstractDataset()
71 :
72 : {
73 31 : FlushCache();
74 :
75 31 : if ( pszProjection )
76 0 : CPLFree( pszProjection );
77 :
78 31 : if ( nGCPCount > 0 )
79 : {
80 0 : GDALDeinitGCPs( nGCPCount, pasGCPList );
81 0 : CPLFree( pasGCPList );
82 : }
83 :
84 31 : if( hGifFile )
85 30 : DGifCloseFile( hGifFile );
86 :
87 31 : if( fp != NULL )
88 30 : VSIFCloseL( fp );
89 31 : }
90 :
91 :
92 : /************************************************************************/
93 : /* GIFCollectXMPMetadata() */
94 : /************************************************************************/
95 :
96 : /* See ยง2.1.2 of http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf */
97 :
98 1 : static CPLString GIFCollectXMPMetadata(VSILFILE* fp)
99 :
100 : {
101 1 : CPLString osXMP;
102 :
103 : /* Save current position to avoid disturbing GIF stream decoding */
104 1 : vsi_l_offset nCurOffset = VSIFTellL(fp);
105 :
106 : char abyBuffer[2048+1];
107 :
108 1 : VSIFSeekL( fp, 0, SEEK_SET );
109 :
110 : /* Loop over file */
111 :
112 1 : int iStartSearchOffset = 1024;
113 0 : while(TRUE)
114 : {
115 1 : int nRead = VSIFReadL( abyBuffer + 1024, 1, 1024, fp );
116 1 : if (nRead <= 0)
117 0 : break;
118 1 : abyBuffer[1024 + nRead] = 0;
119 :
120 : int i;
121 1 : int iFoundOffset = -1;
122 782 : for(i=iStartSearchOffset;i<1024+nRead - 14;i++)
123 : {
124 782 : if (memcmp(abyBuffer + i, "\x21\xff\x0bXMP DataXMP", 14) == 0)
125 : {
126 1 : iFoundOffset = i + 14;
127 1 : break;
128 : }
129 : }
130 :
131 1 : iStartSearchOffset = 0;
132 :
133 1 : if (iFoundOffset >= 0)
134 : {
135 1 : int nSize = 1024 + nRead - iFoundOffset;
136 1 : char* pszXMP = (char*)VSIMalloc(nSize + 1);
137 1 : if (pszXMP == NULL)
138 0 : break;
139 :
140 1 : pszXMP[nSize] = 0;
141 1 : memcpy(pszXMP, abyBuffer + iFoundOffset, nSize);
142 :
143 : /* Read from file until we find a NUL character */
144 1 : int nLen = (int)strlen(pszXMP);
145 6 : while(nLen == nSize)
146 : {
147 4 : char* pszNewXMP = (char*)VSIRealloc(pszXMP, nSize + 1024 + 1);
148 4 : if (pszNewXMP == NULL)
149 0 : break;
150 4 : pszXMP = pszNewXMP;
151 :
152 4 : nRead = VSIFReadL( pszXMP + nSize, 1, 1024, fp );
153 4 : if (nRead <= 0)
154 0 : break;
155 :
156 4 : pszXMP[nSize + nRead] = 0;
157 4 : nLen += (int)strlen(pszXMP + nSize);
158 4 : nSize += nRead;
159 : }
160 :
161 4 : if (nLen > 256 && pszXMP[nLen - 1] == '\x01' &&
162 2 : pszXMP[nLen - 2] == '\x02' && pszXMP[nLen - 255] == '\xff' &&
163 1 : pszXMP[nLen - 256] == '\x01')
164 : {
165 1 : pszXMP[nLen - 256] = 0;
166 :
167 1 : osXMP = pszXMP;
168 : }
169 :
170 1 : VSIFree(pszXMP);
171 :
172 1 : break;
173 : }
174 :
175 0 : if (nRead != 1024)
176 0 : break;
177 :
178 0 : memcpy(abyBuffer, abyBuffer + 1024, 1024);
179 : }
180 :
181 1 : VSIFSeekL( fp, nCurOffset, SEEK_SET );
182 :
183 0 : return osXMP;
184 : }
185 :
186 : /************************************************************************/
187 : /* CollectXMPMetadata() */
188 : /************************************************************************/
189 :
190 1 : void GIFAbstractDataset::CollectXMPMetadata()
191 :
192 : {
193 1 : if (fp == NULL || bHasReadXMPMetadata)
194 0 : return;
195 :
196 1 : CPLString osXMP = GIFCollectXMPMetadata(fp);
197 1 : if (osXMP.size())
198 : {
199 : /* Avoid setting the PAM dirty bit just for that */
200 1 : int nOldPamFlags = nPamFlags;
201 :
202 : char *apszMDList[2];
203 1 : apszMDList[0] = (char*) osXMP.c_str();
204 1 : apszMDList[1] = NULL;
205 1 : SetMetadata(apszMDList, "xml:XMP");
206 :
207 1 : nPamFlags = nOldPamFlags;
208 : }
209 :
210 1 : bHasReadXMPMetadata = TRUE;
211 : }
212 :
213 : /************************************************************************/
214 : /* GetMetadata() */
215 : /************************************************************************/
216 :
217 36 : char **GIFAbstractDataset::GetMetadata( const char * pszDomain )
218 : {
219 36 : if (fp == NULL)
220 0 : return NULL;
221 36 : if (eAccess == GA_ReadOnly && !bHasReadXMPMetadata &&
222 : (pszDomain != NULL && EQUAL(pszDomain, "xml:XMP")))
223 1 : CollectXMPMetadata();
224 36 : return GDALPamDataset::GetMetadata(pszDomain);
225 : }
226 :
227 : /************************************************************************/
228 : /* GetMetadataItem() */
229 : /************************************************************************/
230 :
231 21 : const char *GIFAbstractDataset::GetMetadataItem( const char * pszName,
232 : const char * pszDomain )
233 : {
234 21 : if (fp == NULL)
235 0 : return NULL;
236 21 : if (eAccess == GA_ReadOnly && !bHasReadXMPMetadata &&
237 : (pszDomain != NULL && EQUAL(pszDomain, "xml:XMP")))
238 0 : CollectXMPMetadata();
239 21 : return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
240 : }
241 :
242 : /************************************************************************/
243 : /* GetProjectionRef() */
244 : /************************************************************************/
245 :
246 18 : const char *GIFAbstractDataset::GetProjectionRef()
247 :
248 : {
249 18 : if ( pszProjection && bGeoTransformValid )
250 0 : return pszProjection;
251 : else
252 18 : return GDALPamDataset::GetProjectionRef();
253 : }
254 :
255 : /************************************************************************/
256 : /* GetGeoTransform() */
257 : /************************************************************************/
258 :
259 33 : CPLErr GIFAbstractDataset::GetGeoTransform( double * padfTransform )
260 :
261 : {
262 33 : if( bGeoTransformValid )
263 : {
264 0 : memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
265 0 : return CE_None;
266 : }
267 : else
268 33 : return GDALPamDataset::GetGeoTransform( padfTransform );
269 : }
270 :
271 : /************************************************************************/
272 : /* GetGCPCount() */
273 : /************************************************************************/
274 :
275 7 : int GIFAbstractDataset::GetGCPCount()
276 :
277 : {
278 7 : if (nGCPCount > 0)
279 0 : return nGCPCount;
280 : else
281 7 : return GDALPamDataset::GetGCPCount();
282 : }
283 :
284 : /************************************************************************/
285 : /* GetGCPProjection() */
286 : /************************************************************************/
287 :
288 0 : const char *GIFAbstractDataset::GetGCPProjection()
289 :
290 : {
291 0 : if ( pszProjection && nGCPCount > 0 )
292 0 : return pszProjection;
293 : else
294 0 : return GDALPamDataset::GetGCPProjection();
295 : }
296 :
297 : /************************************************************************/
298 : /* GetGCPs() */
299 : /************************************************************************/
300 :
301 0 : const GDAL_GCP *GIFAbstractDataset::GetGCPs()
302 :
303 : {
304 0 : if (nGCPCount > 0)
305 0 : return pasGCPList;
306 : else
307 0 : return GDALPamDataset::GetGCPs();
308 : }
309 :
310 : /************************************************************************/
311 : /* Identify() */
312 : /************************************************************************/
313 :
314 23429 : int GIFAbstractDataset::Identify( GDALOpenInfo * poOpenInfo )
315 :
316 : {
317 23429 : if( poOpenInfo->nHeaderBytes < 8 )
318 21610 : return FALSE;
319 :
320 1819 : if( strncmp((const char *) poOpenInfo->pabyHeader, "GIF87a",5) != 0
321 : && strncmp((const char *) poOpenInfo->pabyHeader, "GIF89a",5) != 0 )
322 1788 : return FALSE;
323 :
324 31 : return TRUE;
325 : }
326 :
327 : /************************************************************************/
328 : /* DetectGeoreferencing() */
329 : /************************************************************************/
330 :
331 30 : void GIFAbstractDataset::DetectGeoreferencing( GDALOpenInfo * poOpenInfo )
332 : {
333 : bGeoTransformValid =
334 : GDALReadWorldFile( poOpenInfo->pszFilename, NULL,
335 30 : adfGeoTransform );
336 30 : if ( !bGeoTransformValid )
337 : {
338 : bGeoTransformValid =
339 : GDALReadWorldFile( poOpenInfo->pszFilename, ".wld",
340 30 : adfGeoTransform );
341 :
342 30 : if ( !bGeoTransformValid )
343 : {
344 : int bOziFileOK =
345 : GDALReadOziMapFile( poOpenInfo->pszFilename,
346 : adfGeoTransform,
347 : &pszProjection,
348 30 : &nGCPCount, &pasGCPList );
349 :
350 30 : if ( bOziFileOK && nGCPCount == 0 )
351 0 : bGeoTransformValid = TRUE;
352 : }
353 : }
354 30 : }
|