]> granicus.if.org Git - imagemagick/blob - coders/cals.c
Added missing calls to xmlFreeDoc to fix memory leak reported in #1766.
[imagemagick] / coders / cals.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                         CCCC   AAA   L      SSSSS                           %
7 %                        C      A   A  L      SS                              %
8 %                        C      AAAAA  L       SSS                            %
9 %                        C      A   A  L         SS                           %
10 %                         CCCC  A   A  LLLLL  SSSSS                           %
11 %                                                                             %
12 %                                                                             %
13 %                 Read/Write CALS Raster Group 1 Image Format                 %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2019 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 %    https://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 % The CALS raster format is a standard developed by the Computer Aided
37 % Acquisition and Logistics Support (CALS) office of the United States
38 % Department of Defense to standardize graphics data interchange for
39 % electronic publishing, especially in the areas of technical graphics,
40 % CAD/CAM, and image processing applications.
41 %
42 */
43 \f
44 /*
45   Include declarations.
46 */
47 #include "MagickCore/studio.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/colorspace.h"
52 #include "MagickCore/constitute.h"
53 #include "MagickCore/exception.h"
54 #include "MagickCore/exception-private.h"
55 #include "MagickCore/geometry.h"
56 #include "MagickCore/image.h"
57 #include "MagickCore/image-private.h"
58 #include "MagickCore/list.h"
59 #include "MagickCore/magick.h"
60 #include "MagickCore/memory_.h"
61 #include "MagickCore/monitor.h"
62 #include "MagickCore/monitor-private.h"
63 #include "MagickCore/option.h"
64 #include "MagickCore/quantum-private.h"
65 #include "MagickCore/resource_.h"
66 #include "MagickCore/static.h"
67 #include "MagickCore/string_.h"
68 #include "MagickCore/module.h"
69 \f
70 #if defined(MAGICKCORE_TIFF_DELEGATE)
71 /*
72  Forward declarations.
73 */
74 static MagickBooleanType
75   WriteCALSImage(const ImageInfo *,Image *,ExceptionInfo *);
76 #endif
77 \f
78 /*
79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80 %                                                                             %
81 %                                                                             %
82 %                                                                             %
83 %   I s C A L S                                                               %
84 %                                                                             %
85 %                                                                             %
86 %                                                                             %
87 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88 %
89 %  IsCALS() returns MagickTrue if the image format type, identified by the
90 %  magick string, is CALS Raster Group 1.
91 %
92 %  The format of the IsCALS method is:
93 %
94 %      MagickBooleanType IsCALS(const unsigned char *magick,const size_t length)
95 %
96 %  A description of each parameter follows:
97 %
98 %    o magick: compare image format pattern against these bytes.
99 %
100 %    o length: Specifies the length of the magick string.
101 %
102 */
103 static MagickBooleanType IsCALS(const unsigned char *magick,const size_t length)
104 {
105   if (length < 128)
106     return(MagickFalse);
107   if (LocaleNCompare((const char *) magick,"version: MIL-STD-1840",21) == 0)
108     return(MagickTrue);
109   if (LocaleNCompare((const char *) magick,"srcdocid:",9) == 0)
110     return(MagickTrue);
111   if (LocaleNCompare((const char *) magick,"rorient:",8) == 0)
112     return(MagickTrue);
113   return(MagickFalse);
114 }
115 \f
116 /*
117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118 %                                                                             %
119 %                                                                             %
120 %                                                                             %
121 %   R e a d C A L S I m a g e                                                 %
122 %                                                                             %
123 %                                                                             %
124 %                                                                             %
125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 %
127 %  ReadCALSImage() reads an CALS Raster Group 1 image format image file and
128 %  returns it.  It allocates the memory necessary for the new Image structure
129 %  and returns a pointer to the new image.
130 %
131 %  The format of the ReadCALSImage method is:
132 %
133 %      Image *ReadCALSImage(const ImageInfo *image_info,
134 %        ExceptionInfo *exception)
135 %
136 %  A description of each parameter follows:
137 %
138 %    o image_info: the image info.
139 %
140 %    o exception: return any errors or warnings in this structure.
141 %
142 */
143 static Image *ReadCALSImage(const ImageInfo *image_info,
144   ExceptionInfo *exception)
145 {
146   char
147     filename[MagickPathExtent],
148     header[MagickPathExtent],
149     message[MagickPathExtent];
150
151   FILE
152     *file;
153
154   Image
155     *image;
156
157   ImageInfo
158     *read_info;
159
160   int
161     c,
162     unique_file;
163
164   MagickBooleanType
165     status;
166
167   register ssize_t
168     i;
169
170   unsigned long
171     density,
172     direction,
173     height,
174     orientation,
175     pel_path,
176     type,
177     width;
178
179   /*
180     Open image file.
181   */
182   assert(image_info != (const ImageInfo *) NULL);
183   assert(image_info->signature == MagickCoreSignature);
184   if (image_info->debug != MagickFalse)
185     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
186       image_info->filename);
187   assert(exception != (ExceptionInfo *) NULL);
188   assert(exception->signature == MagickCoreSignature);
189   image=AcquireImage(image_info,exception);
190   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
191   if (status == MagickFalse)
192     {
193       image=DestroyImageList(image);
194       return((Image *) NULL);
195     }
196   /*
197     Read CALS header.
198   */
199   (void) memset(header,0,sizeof(header));
200   density=0;
201   direction=0;
202   orientation=1;
203   pel_path=0;
204   type=1;
205   width=0;
206   height=0;
207   for (i=0; i < 16; i++)
208   {
209     if (ReadBlob(image,128,(unsigned char *) header) != 128)
210       break;
211     switch (*header)
212     {
213       case 'R':
214       case 'r':
215       {
216         if (LocaleNCompare(header,"rdensty:",8) == 0)
217           {
218             (void) sscanf(header+8,"%lu",&density);
219             break;
220           }
221         if (LocaleNCompare(header,"rpelcnt:",8) == 0)
222           {
223             (void) sscanf(header+8,"%lu,%lu",&width,&height);
224             break;
225           }
226         if (LocaleNCompare(header,"rorient:",8) == 0)
227           {
228             (void) sscanf(header+8,"%lu,%lu",&pel_path,&direction);
229             if (pel_path == 90)
230               orientation=5;
231             else
232               if (pel_path == 180)
233                 orientation=3;
234               else
235                 if (pel_path == 270)
236                   orientation=7;
237             if (direction == 90)
238               orientation++;
239             break;
240           }
241         if (LocaleNCompare(header,"rtype:",6) == 0)
242           {
243             (void) sscanf(header+6,"%lu",&type);
244             break;
245           }
246         break;
247       }
248     }
249   }
250   /*
251     Read CALS pixels.
252   */
253   file=(FILE *) NULL;
254   unique_file=AcquireUniqueFileResource(filename);
255   if (unique_file != -1)
256     file=fdopen(unique_file,"wb");
257   if ((unique_file == -1) || (file == (FILE *) NULL))
258     ThrowImageException(FileOpenError,"UnableToCreateTemporaryFile");
259   while ((c=ReadBlobByte(image)) != EOF)
260     if (fputc(c,file) != c)
261       break;
262   (void) fclose(file);
263   (void) CloseBlob(image);
264   image=DestroyImage(image);
265   read_info=CloneImageInfo(image_info);
266   SetImageInfoBlob(read_info,(void *) NULL,0);
267   (void) FormatLocaleString(read_info->filename,MagickPathExtent,"group4:%s",
268     filename);
269   (void) FormatLocaleString(message,MagickPathExtent,"%lux%lu",width,height);
270   (void) CloneString(&read_info->size,message);
271   (void) FormatLocaleString(message,MagickPathExtent,"%lu",density);
272   (void) CloneString(&read_info->density,message);
273   read_info->orientation=(OrientationType) orientation;
274   image=ReadImage(read_info,exception);
275   if (image != (Image *) NULL)
276     {
277       (void) CopyMagickString(image->filename,image_info->filename,
278         MagickPathExtent);
279       (void) CopyMagickString(image->magick_filename,image_info->filename,
280         MagickPathExtent);
281       (void) CopyMagickString(image->magick,"CALS",MagickPathExtent);
282     }
283   read_info=DestroyImageInfo(read_info);
284   (void) RelinquishUniqueFileResource(filename);
285   return(image);
286 }
287 \f
288 /*
289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
290 %                                                                             %
291 %                                                                             %
292 %                                                                             %
293 %   R e g i s t e r C A L S I m a g e                                         %
294 %                                                                             %
295 %                                                                             %
296 %                                                                             %
297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
298 %
299 %  RegisterCALSImage() adds attributes for the CALS Raster Group 1 image file
300 %  image format to the list of supported formats.  The attributes include the
301 %  image format tag, a method to read and/or write the format, whether the
302 %  format supports the saving of more than one frame to the same file or blob,
303 %  whether the format supports native in-memory I/O, and a brief description
304 %  of the format.
305 %
306 %  The format of the RegisterCALSImage method is:
307 %
308 %      size_t RegisterCALSImage(void)
309 %
310 */
311 ModuleExport size_t RegisterCALSImage(void)
312 {
313 #define CALSDescription  "Continuous Acquisition and Life-cycle Support Type 1"
314 #define CALSNote  "Specified in MIL-R-28002 and MIL-PRF-28002"
315
316   MagickInfo
317     *entry;
318
319   entry=AcquireMagickInfo("CALS","CAL",CALSDescription);
320   entry->decoder=(DecodeImageHandler *) ReadCALSImage;
321 #if defined(MAGICKCORE_TIFF_DELEGATE)
322   entry->encoder=(EncodeImageHandler *) WriteCALSImage;
323 #endif
324   entry->flags^=CoderAdjoinFlag;
325   entry->magick=(IsImageFormatHandler *) IsCALS;
326   entry->note=ConstantString(CALSNote);
327   (void) RegisterMagickInfo(entry);
328   entry=AcquireMagickInfo("CALS","CALS",CALSDescription);
329   entry->decoder=(DecodeImageHandler *) ReadCALSImage;
330 #if defined(MAGICKCORE_TIFF_DELEGATE)
331   entry->encoder=(EncodeImageHandler *) WriteCALSImage;
332 #endif
333   entry->flags^=CoderAdjoinFlag;
334   entry->magick=(IsImageFormatHandler *) IsCALS;
335   entry->note=ConstantString(CALSNote);
336   (void) RegisterMagickInfo(entry);
337   return(MagickImageCoderSignature);
338 }
339 \f
340 /*
341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342 %                                                                             %
343 %                                                                             %
344 %                                                                             %
345 %   U n r e g i s t e r C A L S I m a g e                                     %
346 %                                                                             %
347 %                                                                             %
348 %                                                                             %
349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350 %
351 %  UnregisterCALSImage() removes format registrations made by the
352 %  CALS module from the list of supported formats.
353 %
354 %  The format of the UnregisterCALSImage method is:
355 %
356 %      UnregisterCALSImage(void)
357 %
358 */
359 ModuleExport void UnregisterCALSImage(void)
360 {
361   (void) UnregisterMagickInfo("CAL");
362   (void) UnregisterMagickInfo("CALS");
363 }
364 \f
365 #if defined(MAGICKCORE_TIFF_DELEGATE)
366 /*
367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
368 %                                                                             %
369 %                                                                             %
370 %                                                                             %
371 %   W r i t e C A L S I m a g e                                               %
372 %                                                                             %
373 %                                                                             %
374 %                                                                             %
375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376 %
377 %  WriteCALSImage() writes an image to a file in CALS Raster Group 1 image
378 %  format.
379 %
380 %  The format of the WriteCALSImage method is:
381 %
382 %      MagickBooleanType WriteCALSImage(const ImageInfo *image_info,
383 %        Image *image,ExceptionInfo *exception)
384 %
385 %  A description of each parameter follows.
386 %
387 %    o image_info: the image info.
388 %
389 %    o image:  The image.
390 %
391 %    o exception: return any errors or warnings in this structure.
392 %
393 */
394
395 static ssize_t WriteCALSRecord(Image *image,const char *data)
396 {
397   char
398     pad[128];
399
400   register const char
401     *p;
402
403   register ssize_t
404     i;
405
406   ssize_t
407     count;
408
409   i=0;
410   count=0;
411   if (data != (const char *) NULL)
412     {
413       p=data;
414       for (i=0; (i < 128) && (p[i] != '\0'); i++);
415       count=WriteBlob(image,(size_t) i,(const unsigned char *) data);
416     }
417   if (i < 128)
418     {
419       i=128-i;
420       (void) memset(pad,' ',(size_t) i);
421       count=WriteBlob(image,(size_t) i,(const unsigned char *) pad);
422     }
423   return(count);
424 }
425
426 static MagickBooleanType WriteCALSImage(const ImageInfo *image_info,
427   Image *image,ExceptionInfo *exception)
428 {
429   char
430     header[129];
431
432   Image
433     *group4_image;
434
435   ImageInfo
436     *write_info;
437
438   MagickBooleanType
439     status;
440
441   register ssize_t
442     i;
443
444   size_t
445     density,
446     length,
447     orient_x,
448     orient_y;
449
450   ssize_t
451     count;
452
453   unsigned char
454     *group4;
455
456   /*
457     Open output image file.
458   */
459   assert(image_info != (const ImageInfo *) NULL);
460   assert(image_info->signature == MagickCoreSignature);
461   assert(image != (Image *) NULL);
462   assert(image->signature == MagickCoreSignature);
463   if (image->debug != MagickFalse)
464     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
465   assert(exception != (ExceptionInfo *) NULL);
466   assert(exception->signature == MagickCoreSignature);
467   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
468   if (status == MagickFalse)
469     return(status);
470   /*
471     Create standard CALS header.
472   */
473   count=WriteCALSRecord(image,"srcdocid: NONE");
474   (void) count;
475   count=WriteCALSRecord(image,"dstdocid: NONE");
476   count=WriteCALSRecord(image,"txtfilid: NONE");
477   count=WriteCALSRecord(image,"figid: NONE");
478   count=WriteCALSRecord(image,"srcgph: NONE");
479   count=WriteCALSRecord(image,"doccls: NONE");
480   count=WriteCALSRecord(image,"rtype: 1");
481   orient_x=0;
482   orient_y=0;
483   switch (image->orientation)
484   {
485     case TopRightOrientation:
486     {
487       orient_x=180;
488       orient_y=270;
489       break;
490     }
491     case BottomRightOrientation:
492     {
493       orient_x=180;
494       orient_y=90;
495       break;
496     }
497     case BottomLeftOrientation:
498     {
499       orient_y=90;
500       break;
501     }
502     case LeftTopOrientation:
503     {
504       orient_x=270;
505       break;
506     }
507     case RightTopOrientation:
508     {
509       orient_x=270;
510       orient_y=180;
511       break;
512     }
513     case RightBottomOrientation:
514     {
515       orient_x=90;
516       orient_y=180;
517       break;
518     }
519     case LeftBottomOrientation:
520     {
521       orient_x=90;
522       break;
523     }
524     default:
525     {
526       orient_y=270;
527       break;
528     }
529   }
530   (void) FormatLocaleString(header,sizeof(header),"rorient: %03ld,%03ld",
531     (long) orient_x,(long) orient_y);
532   count=WriteCALSRecord(image,header);
533   (void) FormatLocaleString(header,sizeof(header),"rpelcnt: %06lu,%06lu",
534     (unsigned long) image->columns,(unsigned long) image->rows);
535   count=WriteCALSRecord(image,header);  
536   density=200;
537   if (image_info->density != (char *) NULL)
538     {
539       GeometryInfo
540         geometry_info;
541
542       (void) ParseGeometry(image_info->density,&geometry_info);
543       density=(size_t) floor(geometry_info.rho+0.5);
544     }
545   (void) FormatLocaleString(header,sizeof(header),"rdensty: %04lu",
546     (unsigned long) density);
547   count=WriteCALSRecord(image,header);
548   count=WriteCALSRecord(image,"notes: NONE");
549   (void) memset(header,' ',128);
550   for (i=0; i < 5; i++)
551     (void) WriteBlob(image,128,(unsigned char *) header);
552   /*
553     Write CALS pixels.
554   */
555   write_info=CloneImageInfo(image_info);
556   (void) CopyMagickString(write_info->filename,"GROUP4:",MagickPathExtent);
557   (void) CopyMagickString(write_info->magick,"GROUP4",MagickPathExtent);
558   group4_image=CloneImage(image,0,0,MagickTrue,exception);
559   if (group4_image == (Image *) NULL)
560     {
561       write_info=DestroyImageInfo(write_info);
562       (void) CloseBlob(image);
563       return(MagickFalse);
564     }
565   group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
566     exception);
567   group4_image=DestroyImage(group4_image);
568   if (group4 == (unsigned char *) NULL)
569     {
570       write_info=DestroyImageInfo(write_info);
571       (void) CloseBlob(image);
572       return(MagickFalse);
573     }
574   write_info=DestroyImageInfo(write_info);
575   if (WriteBlob(image,length,group4) != (ssize_t) length)
576     status=MagickFalse;
577   group4=(unsigned char *) RelinquishMagickMemory(group4);
578   (void) CloseBlob(image);
579   return(status);
580 }
581 #endif