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