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