]> granicus.if.org Git - imagemagick/blob - coders/jnx.c
Fix improper cast that could cause an overflow as demonstrated in #347.
[imagemagick] / coders / jnx.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                              JJJ  N   N  X   X                              %
7 %                               J   NN  N   X X                               %
8 %                               J   N N N    X                                %
9 %                            J  J   N  NN   X X                               %
10 %                             JJ    N   N  X   X                              %
11 %                                                                             %
12 %                                                                             %
13 %                       Read/Write Garmin Image Format                        %
14 %                                                                             %
15 %                                   Cristy                                    %
16 %                                 July 2012                                   %
17 %                                                                             %
18 %                                                                             %
19 %  Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization      %
20 %  dedicated to making software imaging solutions freely available.           %
21 %                                                                             %
22 %  You may not use this file except in compliance with the License.  You may  %
23 %  obtain a copy of the License at                                            %
24 %                                                                             %
25 %    http://www.imagemagick.org/script/license.php                            %
26 %                                                                             %
27 %  Unless required by applicable law or agreed to in writing, software        %
28 %  distributed under the License is distributed on an "AS IS" BASIS,          %
29 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
30 %  See the License for the specific language governing permissions and        %
31 %  limitations under the License.                                             %
32 %                                                                             %
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34 %
35 %
36 */
37 \f
38 /*
39   Include declarations.
40 */
41 \f
42 /*
43   Include declarations.
44 */
45 #include "MagickCore/studio.h"
46 #include "MagickCore/blob.h"
47 #include "MagickCore/blob-private.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/colorspace.h"
50 #include "MagickCore/colorspace-private.h"
51 #include "MagickCore/draw.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/image.h"
55 #include "MagickCore/image-private.h"
56 #include "MagickCore/list.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/module.h"
60 #include "MagickCore/monitor.h"
61 #include "MagickCore/monitor-private.h"
62 #include "MagickCore/property.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/quantum-private.h"
65 #include "MagickCore/static.h"
66 #include "MagickCore/string_.h"
67 \f
68 typedef struct _JNXInfo
69 {
70   int
71     version,
72     serial;
73
74   PointInfo
75     northeast,
76     southwest;
77
78   int
79     levels,
80     expire,
81     id,
82     crc,
83     signature;
84
85   unsigned int
86     offset;
87
88   int
89     order;
90 } JNXInfo;
91
92 typedef struct _JNXLevelInfo
93 {
94   int
95     count,
96     offset;
97
98   unsigned int
99     scale;
100
101   unsigned short
102     copyright[MagickPathExtent];
103 } JNXLevelInfo;
104 \f
105 /*
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107 %                                                                             %
108 %                                                                             %
109 %                                                                             %
110 %   R e a d J N X I m a g e                                                   %
111 %                                                                             %
112 %                                                                             %
113 %                                                                             %
114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115 %
116 %  ReadJNXImage() reads an image in the Garmin tile storage format and returns
117 %  it.  It allocates the memory necessary for the new Image structure and
118 %  returns a pointer to the new image.
119 %
120 %  The format of the ReadJNXImage method is:
121 %
122 %      Image *ReadJNXImage(const ImageInfo *image_info,ExceptionInfo *exception)
123 %
124 %  A description of each parameter follows:
125 %
126 %    o image_info: the image info.
127 %
128 %    o exception: return any errors or warnings in this structure.
129 %
130 */
131 static Image *ReadJNXImage(const ImageInfo *image_info,ExceptionInfo *exception)
132 {
133 #define JNXMaxLevels  20
134
135   Image
136     *image,
137     *images;
138
139   JNXInfo
140     jnx_info;
141
142   JNXLevelInfo
143     jnx_level_info[JNXMaxLevels];
144
145   MagickBooleanType
146     status;
147
148   register ssize_t
149     i;
150
151   /*
152     Open image file.
153   */
154   assert(image_info != (const ImageInfo *) NULL);
155   assert(image_info->signature == MagickCoreSignature);
156   if (image_info->debug != MagickFalse)
157     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
158       image_info->filename);
159   assert(exception != (ExceptionInfo *) NULL);
160   assert(exception->signature == MagickCoreSignature);
161   image=AcquireImage(image_info,exception);
162   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
163   if (status == MagickFalse)
164     {
165       image=DestroyImageList(image);
166       return((Image *) NULL);
167     }
168   /*
169     Read JNX header.
170   */
171   (void) ResetMagickMemory(&jnx_info,0,sizeof(jnx_info));
172   jnx_info.version=ReadBlobLSBSignedLong(image);
173   if ((jnx_info.version != 3) && (jnx_info.version != 4))
174     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
175   jnx_info.serial=ReadBlobLSBSignedLong(image);
176   jnx_info.northeast.x=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff;
177   jnx_info.northeast.y=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff;
178   jnx_info.southwest.x=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff;
179   jnx_info.southwest.y=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff;
180   jnx_info.levels=ReadBlobLSBSignedLong(image);
181   if (jnx_info.levels > JNXMaxLevels)
182     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
183   jnx_info.expire=ReadBlobLSBSignedLong(image);
184   jnx_info.id=ReadBlobLSBSignedLong(image);
185   jnx_info.crc=ReadBlobLSBSignedLong(image);
186   jnx_info.signature=ReadBlobLSBSignedLong(image);
187   jnx_info.offset=ReadBlobLSBLong(image);
188   if (jnx_info.version > 3)
189     jnx_info.order=ReadBlobLSBSignedLong(image);
190   else
191     if (jnx_info.version == 3)
192       jnx_info.order=30;
193   /*
194     Read JNX levels.
195   */
196   (void) ResetMagickMemory(&jnx_level_info,0,sizeof(jnx_level_info));
197   for (i=0; i < (ssize_t) jnx_info.levels; i++)
198   {
199     jnx_level_info[i].count=ReadBlobLSBSignedLong(image);
200     if (jnx_level_info[i].count > 50000)
201       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
202     jnx_level_info[i].offset=ReadBlobLSBSignedLong(image);
203     jnx_level_info[i].scale=ReadBlobLSBLong(image);
204     if (jnx_info.version > 3)
205       {
206         register ssize_t
207           j;
208
209         unsigned short
210           c;
211
212         (void) ReadBlobLSBLong(image);
213         j=0;
214         while ((c=ReadBlobLSBShort(image)) != 0)
215           if (j < (MagickPathExtent-1))
216             jnx_level_info[i].copyright[j++]=c;
217         jnx_level_info[i].copyright[j]=0;
218       }
219   }
220   /*
221     Read JNX tiles.
222   */
223   images=NewImageList();
224   for (i=0; i < (ssize_t) jnx_info.levels; i++)
225   {
226     MagickOffsetType
227       offset;
228
229     register ssize_t
230       j;
231
232     offset=SeekBlob(image,(MagickOffsetType) jnx_level_info[i].offset,SEEK_SET);
233     if (offset != (MagickOffsetType) jnx_level_info[i].offset)
234       continue;
235     for (j=0; j < (ssize_t) jnx_level_info[i].count; j++)
236     {
237       Image
238         *tile_image;
239
240       ImageInfo
241         *read_info;
242
243       int
244         tile_offset;
245
246       MagickOffsetType
247         restore_offset;
248
249       PointInfo
250         northeast,
251         southwest;
252
253       ssize_t
254         count;
255
256       unsigned char
257         *blob;
258
259       unsigned int
260         tile_length;
261
262       northeast.x=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff;
263       northeast.y=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff;
264       southwest.x=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff;
265       southwest.y=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff;
266       (void) ReadBlobLSBShort(image); /* width */
267       (void) ReadBlobLSBShort(image); /* height */
268       tile_length=ReadBlobLSBLong(image);
269       tile_offset=ReadBlobLSBSignedLong(image);
270       if (tile_offset == -1)
271         continue;
272       restore_offset=TellBlob(image);
273       if (restore_offset < 0)
274         continue;
275       offset=SeekBlob(image,(MagickOffsetType) tile_offset,SEEK_SET);
276       if (offset != (MagickOffsetType) tile_offset)
277         continue;
278       /*
279         Read a tile.
280       */
281       blob=(unsigned char *) AcquireQuantumMemory((size_t) tile_length+2,
282         sizeof(*blob));
283       if (blob == (unsigned char *) NULL)
284         {
285           if (images != (Image *) NULL)
286             images=DestroyImageList(images);
287           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
288         }
289       blob[0]=0xFF;
290       blob[1]=0xD8;
291       count=ReadBlob(image,tile_length,blob+2);
292       if (count != (ssize_t) tile_length)
293         {
294           if (images != (Image *) NULL)
295             images=DestroyImageList(images);
296           blob=(unsigned char *) RelinquishMagickMemory(blob);
297           ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
298         }
299       read_info=CloneImageInfo(image_info);
300       (void) CopyMagickString(read_info->magick,"JPEG",MagickPathExtent);
301       tile_image=BlobToImage(read_info,blob,tile_length+2,exception);
302       read_info=DestroyImageInfo(read_info);
303       blob=(unsigned char *) RelinquishMagickMemory(blob);
304       offset=SeekBlob(image,restore_offset,SEEK_SET);
305       if (tile_image == (Image *) NULL)
306         continue;
307       (void) CopyMagickString(tile_image->magick,image->magick,MagickPathExtent);
308       (void) FormatImageProperty(tile_image,"jnx:northeast","%.20g,%.20g",
309         northeast.x,northeast.y);
310       (void) FormatImageProperty(tile_image,"jnx:southwest","%.20g,%.20g",
311         southwest.x,southwest.y);
312       AppendImageToList(&images,tile_image);
313     }
314     if (image->progress_monitor != (MagickProgressMonitor) NULL)
315       {
316         MagickBooleanType
317           proceed;
318
319         proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType) i,
320           (MagickSizeType) jnx_info.levels);
321         if (proceed == MagickFalse)
322           status=MagickFalse;
323       }
324   }
325   (void) CloseBlob(image);
326   image=DestroyImage(image);
327   if (images == (Image *) NULL)
328     return((Image *) NULL);
329   return(GetFirstImageInList(images));
330 }
331 \f
332 /*
333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334 %                                                                             %
335 %                                                                             %
336 %                                                                             %
337 %   R e g i s t e r J N X I m a g e                                           %
338 %                                                                             %
339 %                                                                             %
340 %                                                                             %
341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342 %
343 %  RegisterJNXImage() adds attributes for the JNX image format to the list
344 %  of supported formats.  The attributes include the image format tag, a
345 %  method to read and/or write the format, whether the format supports the
346 %  saving of more than one frame to the same file or blob, whether the format
347 %  supports native in-memory I/O, and a brief description of the format.
348 %
349 %  The format of the RegisterJNXImage method is:
350 %
351 %      size_t RegisterJNXImage(void)
352 %
353 */
354 ModuleExport size_t RegisterJNXImage(void)
355 {
356   MagickInfo
357     *entry;
358
359   entry=AcquireMagickInfo("JNX","JNX","Garmin tile format");
360   entry->decoder=(DecodeImageHandler *) ReadJNXImage;
361   entry->flags|=CoderSeekableStreamFlag;
362   (void) RegisterMagickInfo(entry);
363   return(MagickImageCoderSignature);
364 }
365 \f
366 /*
367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
368 %                                                                             %
369 %                                                                             %
370 %                                                                             %
371 %   U n r e g i s t e r J N X I m a g e                                       %
372 %                                                                             %
373 %                                                                             %
374 %                                                                             %
375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376 %
377 %  UnregisterJNXImage() removes format registrations made by the
378 %  JNX module from the list of supported formats.
379 %
380 %  The format of the UnregisterJNXImage method is:
381 %
382 %      UnregisterJNXImage(void)
383 %
384 */
385 ModuleExport void UnregisterJNXImage(void)
386 {
387   (void) UnregisterMagickInfo("JNX");
388 }