]> granicus.if.org Git - imagemagick/blob - coders/raw.c
Fix improper cast that could cause an overflow as demonstrated in #347.
[imagemagick] / coders / raw.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            RRRR    AAA   W   W                              %
7 %                            R   R  A   A  W   W                              %
8 %                            RRRR   AAAAA  W W W                              %
9 %                            R R    A   A  WW WW                              %
10 %                            R  R   A   A  W   W                              %
11 %                                                                             %
12 %                                                                             %
13 %                       Read/Write RAW Image Format                           %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 \f
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/blob-private.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/colorspace.h"
47 #include "MagickCore/constitute.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/monitor.h"
56 #include "MagickCore/monitor-private.h"
57 #include "MagickCore/pixel-accessor.h"
58 #include "MagickCore/quantum-private.h"
59 #include "MagickCore/quantum-private.h"
60 #include "MagickCore/static.h"
61 #include "MagickCore/statistic.h"
62 #include "MagickCore/string_.h"
63 #include "MagickCore/module.h"
64 \f
65 /*
66   Forward declarations.
67 */
68 static MagickBooleanType
69   WriteRAWImage(const ImageInfo *,Image *,ExceptionInfo *);
70 \f
71 /*
72 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73 %                                                                             %
74 %                                                                             %
75 %                                                                             %
76 %   R e a d R A W I m a g e                                                   %
77 %                                                                             %
78 %                                                                             %
79 %                                                                             %
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 %
82 %  ReadRAWImage() reads an image of raw samples and returns it.  It allocates
83 %  the memory necessary for the new Image structure and returns a pointer to
84 %  the new image.
85 %
86 %  The format of the ReadRAWImage method is:
87 %
88 %      Image *ReadRAWImage(const ImageInfo *image_info,ExceptionInfo *exception)
89 %
90 %  A description of each parameter follows:
91 %
92 %    o image_info: the image info.
93 %
94 %    o exception: return any errors or warnings in this structure.
95 %
96 */
97 static Image *ReadRAWImage(const ImageInfo *image_info,ExceptionInfo *exception)
98 {
99   const unsigned char
100     *pixels;
101
102   Image
103     *canvas_image,
104     *image;
105
106   MagickBooleanType
107     status;
108
109   MagickOffsetType
110     scene;
111
112   QuantumInfo
113     *quantum_info;
114
115   QuantumType
116     quantum_type;
117
118   size_t
119     length;
120
121   ssize_t
122     count,
123     y;
124
125   /*
126     Open image file.
127   */
128   assert(image_info != (const ImageInfo *) NULL);
129   assert(image_info->signature == MagickCoreSignature);
130   if (image_info->debug != MagickFalse)
131     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
132       image_info->filename);
133   assert(exception != (ExceptionInfo *) NULL);
134   assert(exception->signature == MagickCoreSignature);
135   image=AcquireImage(image_info,exception);
136   if ((image->columns == 0) || (image->rows == 0))
137     ThrowReaderException(OptionError,"MustSpecifyImageSize");
138   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
139   if (status == MagickFalse)
140     {
141       image=DestroyImageList(image);
142       return((Image *) NULL);
143     }
144   if (DiscardBlobBytes(image,image->offset) == MagickFalse)
145     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
146       image->filename);
147   /*
148     Create virtual canvas to support cropping (i.e. image.gray[100x100+10+20]).
149   */
150   canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse,
151     exception);
152   (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod,
153     exception);
154   quantum_type=GrayQuantum;
155   quantum_info=AcquireQuantumInfo(image_info,canvas_image);
156   if (quantum_info == (QuantumInfo *) NULL)
157     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
158   pixels=(const unsigned char *) NULL;
159   if (image_info->number_scenes != 0)
160     while (image->scene < image_info->scene)
161     {
162       /*
163         Skip to next image.
164       */
165       image->scene++;
166       length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
167       for (y=0; y < (ssize_t) image->rows; y++)
168       {
169         pixels=(const unsigned char *) ReadBlobStream(image,length,
170           GetQuantumPixels(quantum_info),&count);
171         if (count != (ssize_t) length)
172           break;
173       }
174     }
175   scene=0;
176   count=0;
177   length=0;
178   do
179   {
180     /*
181       Read pixels to virtual canvas image then push to image.
182     */
183     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
184       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
185         break;
186     status=SetImageExtent(image,image->columns,image->rows,exception);
187     if (status == MagickFalse)
188       return(DestroyImageList(image));
189     if (scene == 0)
190       {
191         length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
192         pixels=(const unsigned char *) ReadBlobStream(image,length,
193           GetQuantumPixels(quantum_info),&count);
194       }
195     for (y=0; y < (ssize_t) image->extract_info.height; y++)
196     {
197       register const Quantum
198         *magick_restrict p;
199
200       register Quantum
201         *magick_restrict q;
202
203       register ssize_t
204         x;
205
206       if (count != (ssize_t) length)
207         {
208           ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
209             image->filename);
210           break;
211         }
212       q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,exception);
213       if (q == (Quantum *) NULL)
214         break;
215       length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,quantum_info,
216         quantum_type,pixels,exception);
217       if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
218         break;
219       if (((y-image->extract_info.y) >= 0) && 
220           ((y-image->extract_info.y) < (ssize_t) image->rows))
221         {
222           p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
223             image->columns,1,exception);
224           q=QueueAuthenticPixels(image,0,y-image->extract_info.y,image->columns,
225             1,exception);
226           if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
227             break;
228           for (x=0; x < (ssize_t) image->columns; x++)
229           {
230             SetPixelRed(image,GetPixelRed(canvas_image,p),q);
231             SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
232             SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
233             p+=GetPixelChannels(canvas_image);
234             q+=GetPixelChannels(image);
235           }
236           if (SyncAuthenticPixels(image,exception) == MagickFalse)
237             break;
238         }
239       if (image->previous == (Image *) NULL)
240         {
241           status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
242             image->rows);
243           if (status == MagickFalse)
244             break;
245         }
246       pixels=(const unsigned char *) ReadBlobStream(image,length,
247         GetQuantumPixels(quantum_info),&count);
248     }
249     SetQuantumImageType(image,quantum_type);
250     /*
251       Proceed to next image.
252     */
253     if (image_info->number_scenes != 0)
254       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
255         break;
256     if (count == (ssize_t) length)
257       {
258         /*
259           Allocate next image structure.
260         */
261         AcquireNextImage(image_info,image,exception);
262         if (GetNextImageInList(image) == (Image *) NULL)
263           {
264             image=DestroyImageList(image);
265             return((Image *) NULL);
266           }
267         image=SyncNextImageInList(image);
268         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
269           GetBlobSize(image));
270         if (status == MagickFalse)
271           break;
272       }
273     scene++;
274   } while (count == (ssize_t) length);
275   quantum_info=DestroyQuantumInfo(quantum_info);
276   canvas_image=DestroyImage(canvas_image);
277   (void) CloseBlob(image);
278   return(GetFirstImageInList(image));
279 }
280 \f
281 /*
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283 %                                                                             %
284 %                                                                             %
285 %                                                                             %
286 %   R e g i s t e r R A W I m a g e                                           %
287 %                                                                             %
288 %                                                                             %
289 %                                                                             %
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291 %
292 %  RegisterRAWImage() adds attributes for the RAW image format to the list of
293 %  supported formats.  The attributes include the image format tag, a method to
294 %  read and/or write the format, whether the format supports the saving of
295 %  more than one frame to the same file or blob, whether the format supports
296 %  native in-memory I/O, and a brief description of the format.
297 %
298 %  The format of the RegisterRAWImage method is:
299 %
300 %      size_t RegisterRAWImage(void)
301 %
302 */
303 ModuleExport size_t RegisterRAWImage(void)
304 {
305   MagickInfo
306     *entry;
307
308   entry=AcquireMagickInfo("RAW","R","Raw red samples");
309   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
310   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
311   entry->flags|=CoderRawSupportFlag;
312   entry->flags|=CoderEndianSupportFlag;
313   entry->format_type=ImplicitFormatType;
314   (void) RegisterMagickInfo(entry);
315   entry=AcquireMagickInfo("RAW","C","Raw cyan samples");
316   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
317   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
318   entry->flags|=CoderRawSupportFlag;
319   entry->flags|=CoderEndianSupportFlag;
320   entry->format_type=ImplicitFormatType;
321   (void) RegisterMagickInfo(entry);
322   entry=AcquireMagickInfo("RAW","G","Raw green samples");
323   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
324   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
325   entry->flags|=CoderRawSupportFlag;
326   entry->flags|=CoderEndianSupportFlag;
327   entry->format_type=ImplicitFormatType;
328   (void) RegisterMagickInfo(entry);
329   entry=AcquireMagickInfo("RAW","M","Raw magenta samples");
330   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
331   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
332   entry->flags|=CoderRawSupportFlag;
333   entry->flags|=CoderEndianSupportFlag;
334   entry->format_type=ImplicitFormatType;
335   (void) RegisterMagickInfo(entry);
336   entry=AcquireMagickInfo("RAW","B","Raw blue samples");
337   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
338   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
339   entry->flags|=CoderRawSupportFlag;
340   entry->flags|=CoderEndianSupportFlag;
341   entry->format_type=ImplicitFormatType;
342   (void) RegisterMagickInfo(entry);
343   entry=AcquireMagickInfo("RAW","Y","Raw yellow samples");
344   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
345   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
346   entry->flags|=CoderRawSupportFlag;
347   entry->flags|=CoderEndianSupportFlag;
348   entry->format_type=ImplicitFormatType;
349   (void) RegisterMagickInfo(entry);
350   entry=AcquireMagickInfo("RAW","A","Raw alpha samples");
351   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
352   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
353   entry->flags|=CoderRawSupportFlag;
354   entry->flags|=CoderEndianSupportFlag;
355   entry->format_type=ImplicitFormatType;
356   (void) RegisterMagickInfo(entry);
357   entry=AcquireMagickInfo("RAW","O","Raw opacity samples");
358   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
359   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
360   entry->flags|=CoderRawSupportFlag;
361   entry->flags|=CoderEndianSupportFlag;
362   entry->format_type=ImplicitFormatType;
363   (void) RegisterMagickInfo(entry);
364   entry=AcquireMagickInfo("RAW","K","Raw black samples");
365   entry->decoder=(DecodeImageHandler *) ReadRAWImage;
366   entry->encoder=(EncodeImageHandler *) WriteRAWImage;
367   entry->flags|=CoderRawSupportFlag;
368   entry->flags|=CoderEndianSupportFlag;
369   entry->format_type=ImplicitFormatType;
370   (void) RegisterMagickInfo(entry);
371   return(MagickImageCoderSignature);
372 }
373 \f
374 /*
375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376 %                                                                             %
377 %                                                                             %
378 %                                                                             %
379 %   U n r e g i s t e r R A W I m a g e                                       %
380 %                                                                             %
381 %                                                                             %
382 %                                                                             %
383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384 %
385 %  UnregisterRAWImage() removes format registrations made by the RAW module
386 %  from the list of supported formats.
387 %
388 %  The format of the UnregisterRAWImage method is:
389 %
390 %      UnregisterRAWImage(void)
391 %
392 */
393 ModuleExport void UnregisterRAWImage(void)
394 {
395   (void) UnregisterMagickInfo("R");
396   (void) UnregisterMagickInfo("C");
397   (void) UnregisterMagickInfo("G");
398   (void) UnregisterMagickInfo("M");
399   (void) UnregisterMagickInfo("B");
400   (void) UnregisterMagickInfo("Y");
401   (void) UnregisterMagickInfo("A");
402   (void) UnregisterMagickInfo("O");
403   (void) UnregisterMagickInfo("K");
404 }
405 \f
406 /*
407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
408 %                                                                             %
409 %                                                                             %
410 %                                                                             %
411 %   W r i t e R A W I m a g e                                                 %
412 %                                                                             %
413 %                                                                             %
414 %                                                                             %
415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
416 %
417 %  WriteRAWImage() writes an image to a file as raw intensity values.
418 %
419 %  The format of the WriteRAWImage method is:
420 %
421 %      MagickBooleanType WriteRAWImage(const ImageInfo *image_info,
422 %        Image *image,ExceptionInfo *exception)
423 %
424 %  A description of each parameter follows.
425 %
426 %    o image_info: the image info.
427 %
428 %    o image:  The image.
429 %
430 %    o exception: return any errors or warnings in this structure.
431 %
432 */
433 static MagickBooleanType WriteRAWImage(const ImageInfo *image_info,Image *image,
434   ExceptionInfo *exception)
435 {
436   MagickOffsetType
437     scene;
438
439   QuantumInfo
440     *quantum_info;
441
442   QuantumType
443     quantum_type;
444
445   MagickBooleanType
446     status;
447
448   register const Quantum
449     *p;
450
451   size_t
452     length;
453
454   ssize_t
455     count,
456     y;
457
458   unsigned char
459     *pixels;
460
461   /*
462     Open output image file.
463   */
464   assert(image_info != (const ImageInfo *) NULL);
465   assert(image_info->signature == MagickCoreSignature);
466   assert(image != (Image *) NULL);
467   assert(image->signature == MagickCoreSignature);
468   if (image->debug != MagickFalse)
469     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
470   assert(exception != (ExceptionInfo *) NULL);
471   assert(exception->signature == MagickCoreSignature);
472   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
473   if (status == MagickFalse)
474     return(status);
475   switch (*image->magick)
476   {
477     case 'A':
478     case 'a':
479     {
480       quantum_type=AlphaQuantum;
481       break;
482     }
483     case 'B':
484     case 'b':
485     {
486       quantum_type=BlueQuantum;
487       break;
488     }
489     case 'C':
490     case 'c':
491     {
492       quantum_type=CyanQuantum;
493       if (image->colorspace == CMYKColorspace)
494         break;
495       ThrowWriterException(ImageError,"ColorSeparatedImageRequired");
496     }
497     case 'g':
498     case 'G':
499     {
500       quantum_type=GreenQuantum;
501       break;
502     }
503     case 'I':
504     case 'i':
505     {
506       quantum_type=IndexQuantum;
507       break;
508     }
509     case 'K':
510     case 'k':
511     {
512       quantum_type=BlackQuantum;
513       if (image->colorspace == CMYKColorspace)
514         break;
515       ThrowWriterException(ImageError,"ColorSeparatedImageRequired");
516     }
517     case 'M':
518     case 'm':
519     {
520       quantum_type=MagentaQuantum;
521       if (image->colorspace == CMYKColorspace)
522         break;
523       ThrowWriterException(ImageError,"ColorSeparatedImageRequired");
524     }
525     case 'o':
526     case 'O':
527     {
528       quantum_type=OpacityQuantum;
529       break;
530     }
531     case 'R':
532     case 'r':
533     {
534       quantum_type=RedQuantum;
535       break;
536     }
537     case 'Y':
538     case 'y':
539     {
540       quantum_type=YellowQuantum;
541       if (image->colorspace == CMYKColorspace)
542         break;
543       ThrowWriterException(ImageError,"ColorSeparatedImageRequired");
544     }
545     default:
546     {
547       quantum_type=GrayQuantum;
548       break;
549     }
550   }
551   scene=0;
552   do
553   {
554     /*
555       Convert image to RAW raster pixels.
556     */
557     quantum_info=AcquireQuantumInfo(image_info,image);
558     if (quantum_info == (QuantumInfo *) NULL)
559       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
560     pixels=(unsigned char *) GetQuantumPixels(quantum_info);
561     for (y=0; y < (ssize_t) image->rows; y++)
562     {
563       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
564       if (p == (const Quantum *) NULL)
565         break;
566       length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
567         quantum_type,pixels,exception);
568       count=WriteBlob(image,length,pixels);
569       if (count != (ssize_t) length)
570         break;
571       if (image->previous == (Image *) NULL)
572         {
573           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
574             image->rows);
575           if (status == MagickFalse)
576             break;
577         }
578     }
579     quantum_info=DestroyQuantumInfo(quantum_info);
580     if (GetNextImageInList(image) == (Image *) NULL)
581       break;
582     image=SyncNextImageInList(image);
583     status=SetImageProgress(image,SaveImagesTag,scene++,
584       GetImageListLength(image));
585     if (status == MagickFalse)
586       break;
587   } while (image_info->adjoin != MagickFalse);
588   (void) CloseBlob(image);
589   return(MagickTrue);
590 }