1 : /******************************************************************************
2 : * $Id: gifabstractdataset.cpp 25287 2012-12-05 21:17:14Z 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 25287 2012-12-05 21:17:14Z rouault $");
33 :
34 : /************************************************************************/
35 : /* ==================================================================== */
36 : /* GIFAbstractDataset */
37 : /* ==================================================================== */
38 : /************************************************************************/
39 :
40 :
41 : /************************************************************************/
42 : /* GIFAbstractDataset() */
43 : /************************************************************************/
44 :
45 33 : GIFAbstractDataset::GIFAbstractDataset()
46 :
47 : {
48 33 : hGifFile = NULL;
49 33 : fp = NULL;
50 :
51 33 : pszProjection = NULL;
52 33 : bGeoTransformValid = FALSE;
53 33 : adfGeoTransform[0] = 0.0;
54 33 : adfGeoTransform[1] = 1.0;
55 33 : adfGeoTransform[2] = 0.0;
56 33 : adfGeoTransform[3] = 0.0;
57 33 : adfGeoTransform[4] = 0.0;
58 33 : adfGeoTransform[5] = 1.0;
59 :
60 33 : nGCPCount = 0;
61 33 : pasGCPList = NULL;
62 :
63 33 : bHasReadXMPMetadata = FALSE;
64 33 : }
65 :
66 : /************************************************************************/
67 : /* ~GIFAbstractDataset() */
68 : /************************************************************************/
69 :
70 33 : GIFAbstractDataset::~GIFAbstractDataset()
71 :
72 : {
73 33 : FlushCache();
74 :
75 33 : if ( pszProjection )
76 0 : CPLFree( pszProjection );
77 :
78 33 : if ( nGCPCount > 0 )
79 : {
80 0 : GDALDeinitGCPs( nGCPCount, pasGCPList );
81 0 : CPLFree( pasGCPList );
82 : }
83 :
84 33 : if( hGifFile )
85 32 : DGifCloseFile( hGifFile );
86 :
87 33 : if( fp != NULL )
88 32 : VSIFCloseL( fp );
89 33 : }
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 3 : static CPLString GIFCollectXMPMetadata(VSILFILE* fp)
99 :
100 : {
101 3 : CPLString osXMP;
102 :
103 : /* Save current position to avoid disturbing GIF stream decoding */
104 3 : vsi_l_offset nCurOffset = VSIFTellL(fp);
105 :
106 : char abyBuffer[2048+1];
107 :
108 3 : VSIFSeekL( fp, 0, SEEK_SET );
109 :
110 : /* Loop over file */
111 :
112 3 : int iStartSearchOffset = 1024;
113 7 : while(TRUE)
114 : {
115 10 : int nRead = VSIFReadL( abyBuffer + 1024, 1, 1024, fp );
116 10 : if (nRead <= 0)
117 0 : break;
118 10 : abyBuffer[1024 + nRead] = 0;
119 :
120 : int i;
121 10 : int iFoundOffset = -1;
122 15089 : for(i=iStartSearchOffset;i<1024+nRead - 14;i++)
123 : {
124 15080 : if (memcmp(abyBuffer + i, "\x21\xff\x0bXMP DataXMP", 14) == 0)
125 : {
126 1 : iFoundOffset = i + 14;
127 1 : break;
128 : }
129 : }
130 :
131 10 : iStartSearchOffset = 0;
132 :
133 10 : 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 9 : if (nRead != 1024)
176 2 : break;
177 :
178 7 : memcpy(abyBuffer, abyBuffer + 1024, 1024);
179 : }
180 :
181 3 : VSIFSeekL( fp, nCurOffset, SEEK_SET );
182 :
183 0 : return osXMP;
184 : }
185 :
186 : /************************************************************************/
187 : /* CollectXMPMetadata() */
188 : /************************************************************************/
189 :
190 3 : void GIFAbstractDataset::CollectXMPMetadata()
191 :
192 : {
193 3 : if (fp == NULL || bHasReadXMPMetadata)
194 0 : return;
195 :
196 3 : CPLString osXMP = GIFCollectXMPMetadata(fp);
197 3 : 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 3 : bHasReadXMPMetadata = TRUE;
211 : }
212 :
213 : /************************************************************************/
214 : /* GetMetadata() */
215 : /************************************************************************/
216 :
217 38 : char **GIFAbstractDataset::GetMetadata( const char * pszDomain )
218 : {
219 38 : if (fp == NULL)
220 0 : return NULL;
221 38 : if (eAccess == GA_ReadOnly && !bHasReadXMPMetadata &&
222 : (pszDomain != NULL && EQUAL(pszDomain, "xml:XMP")))
223 3 : CollectXMPMetadata();
224 38 : return GDALPamDataset::GetMetadata(pszDomain);
225 : }
226 :
227 : /************************************************************************/
228 : /* GetProjectionRef() */
229 : /************************************************************************/
230 :
231 21 : const char *GIFAbstractDataset::GetProjectionRef()
232 :
233 : {
234 21 : if ( pszProjection && bGeoTransformValid )
235 0 : return pszProjection;
236 : else
237 21 : return GDALPamDataset::GetProjectionRef();
238 : }
239 :
240 : /************************************************************************/
241 : /* GetGeoTransform() */
242 : /************************************************************************/
243 :
244 35 : CPLErr GIFAbstractDataset::GetGeoTransform( double * padfTransform )
245 :
246 : {
247 35 : if( bGeoTransformValid )
248 : {
249 0 : memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
250 0 : return CE_None;
251 : }
252 : else
253 35 : return GDALPamDataset::GetGeoTransform( padfTransform );
254 : }
255 :
256 : /************************************************************************/
257 : /* GetGCPCount() */
258 : /************************************************************************/
259 :
260 8 : int GIFAbstractDataset::GetGCPCount()
261 :
262 : {
263 8 : if (nGCPCount > 0)
264 0 : return nGCPCount;
265 : else
266 8 : return GDALPamDataset::GetGCPCount();
267 : }
268 :
269 : /************************************************************************/
270 : /* GetGCPProjection() */
271 : /************************************************************************/
272 :
273 0 : const char *GIFAbstractDataset::GetGCPProjection()
274 :
275 : {
276 0 : if ( pszProjection && nGCPCount > 0 )
277 0 : return pszProjection;
278 : else
279 0 : return GDALPamDataset::GetGCPProjection();
280 : }
281 :
282 : /************************************************************************/
283 : /* GetGCPs() */
284 : /************************************************************************/
285 :
286 0 : const GDAL_GCP *GIFAbstractDataset::GetGCPs()
287 :
288 : {
289 0 : if (nGCPCount > 0)
290 0 : return pasGCPList;
291 : else
292 0 : return GDALPamDataset::GetGCPs();
293 : }
294 :
295 : /************************************************************************/
296 : /* Identify() */
297 : /************************************************************************/
298 :
299 25368 : int GIFAbstractDataset::Identify( GDALOpenInfo * poOpenInfo )
300 :
301 : {
302 25368 : if( poOpenInfo->nHeaderBytes < 8 )
303 23430 : return FALSE;
304 :
305 1938 : if( strncmp((const char *) poOpenInfo->pabyHeader, "GIF87a",5) != 0
306 : && strncmp((const char *) poOpenInfo->pabyHeader, "GIF89a",5) != 0 )
307 1904 : return FALSE;
308 :
309 34 : return TRUE;
310 : }
311 :
312 : /************************************************************************/
313 : /* DetectGeoreferencing() */
314 : /************************************************************************/
315 :
316 32 : void GIFAbstractDataset::DetectGeoreferencing( GDALOpenInfo * poOpenInfo )
317 : {
318 : bGeoTransformValid =
319 : GDALReadWorldFile( poOpenInfo->pszFilename, NULL,
320 32 : adfGeoTransform );
321 32 : if ( !bGeoTransformValid )
322 : {
323 : bGeoTransformValid =
324 : GDALReadWorldFile( poOpenInfo->pszFilename, ".wld",
325 32 : adfGeoTransform );
326 : }
327 32 : }
|