1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                            W   W  PPPP    GGGG                              %
6 %                            W   W  P   P  G                                  %
7 %                            W W W  PPPP   G GGG                              %
8 %                            WW WW  P      G   G                              %
9 %                            W   W  P       GGG                               %
10 %                                                                             %
11 %                                                                             %
12 %                       Read WordPerfect Image Format                         %
13 %                                                                             %
14 %                              Software Design                                %
15 %                              Jaroslav Fojtik                                %
16 %                                 June 2000                                   %
17 %                                                                             %
18 %                                                                             %
19 %  Copyright 1999-2021 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/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 
38 /*
39   Include declarations.
40 */
41 #include "MagickCore/studio.h"
42 #include "MagickCore/blob.h"
43 #include "MagickCore/blob-private.h"
44 #include "MagickCore/color-private.h"
45 #include "MagickCore/colormap.h"
46 #include "MagickCore/colormap-private.h"
47 #include "MagickCore/constitute.h"
48 #include "MagickCore/exception.h"
49 #include "MagickCore/exception-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/distort.h"
52 #include "MagickCore/image.h"
53 #include "MagickCore/image-private.h"
54 #include "MagickCore/list.h"
55 #include "MagickCore/magic.h"
56 #include "MagickCore/magick.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/resource_.h"
59 #include "MagickCore/pixel-accessor.h"
60 #include "MagickCore/quantum-private.h"
61 #include "MagickCore/static.h"
62 #include "MagickCore/string_.h"
63 #include "MagickCore/module.h"
64 #include "MagickCore/transform.h"
65 #include "MagickCore/utility.h"
66 #include "MagickCore/utility-private.h"
67 
68 typedef struct
69    {
70    unsigned char Red;
71    unsigned char Blue;
72    unsigned char Green;
73    } RGB_Record;
74 
75 /* Default palette for WPG level 1 */
76 static const RGB_Record WPG1_Palette[256]={
77 {  0,  0,  0},    {  0,  0,168},
78 {  0,168,  0},    {  0,168,168},
79 {168,  0,  0},    {168,  0,168},
80 {168, 84,  0},    {168,168,168},
81 { 84, 84, 84},    { 84, 84,252},
82 { 84,252, 84},    { 84,252,252},
83 {252, 84, 84},    {252, 84,252},
84 {252,252, 84},    {252,252,252},  /*16*/
85 {  0,  0,  0},    { 20, 20, 20},
86 { 32, 32, 32},    { 44, 44, 44},
87 { 56, 56, 56},    { 68, 68, 68},
88 { 80, 80, 80},    { 96, 96, 96},
89 {112,112,112},    {128,128,128},
90 {144,144,144},    {160,160,160},
91 {180,180,180},    {200,200,200},
92 {224,224,224},    {252,252,252},  /*32*/
93 {  0,  0,252},    { 64,  0,252},
94 {124,  0,252},    {188,  0,252},
95 {252,  0,252},    {252,  0,188},
96 {252,  0,124},    {252,  0, 64},
97 {252,  0,  0},    {252, 64,  0},
98 {252,124,  0},    {252,188,  0},
99 {252,252,  0},    {188,252,  0},
100 {124,252,  0},    { 64,252,  0},  /*48*/
101 {  0,252,  0},    {  0,252, 64},
102 {  0,252,124},    {  0,252,188},
103 {  0,252,252},    {  0,188,252},
104 {  0,124,252},    {  0, 64,252},
105 {124,124,252},    {156,124,252},
106 {188,124,252},    {220,124,252},
107 {252,124,252},    {252,124,220},
108 {252,124,188},    {252,124,156},  /*64*/
109 {252,124,124},    {252,156,124},
110 {252,188,124},    {252,220,124},
111 {252,252,124},    {220,252,124},
112 {188,252,124},    {156,252,124},
113 {124,252,124},    {124,252,156},
114 {124,252,188},    {124,252,220},
115 {124,252,252},    {124,220,252},
116 {124,188,252},    {124,156,252},  /*80*/
117 {180,180,252},    {196,180,252},
118 {216,180,252},    {232,180,252},
119 {252,180,252},    {252,180,232},
120 {252,180,216},    {252,180,196},
121 {252,180,180},    {252,196,180},
122 {252,216,180},    {252,232,180},
123 {252,252,180},    {232,252,180},
124 {216,252,180},    {196,252,180},  /*96*/
125 {180,220,180},    {180,252,196},
126 {180,252,216},    {180,252,232},
127 {180,252,252},    {180,232,252},
128 {180,216,252},    {180,196,252},
129 {0,0,112},    {28,0,112},
130 {56,0,112},    {84,0,112},
131 {112,0,112},    {112,0,84},
132 {112,0,56},    {112,0,28},  /*112*/
133 {112,0,0},    {112,28,0},
134 {112,56,0},    {112,84,0},
135 {112,112,0},    {84,112,0},
136 {56,112,0},    {28,112,0},
137 {0,112,0},    {0,112,28},
138 {0,112,56},    {0,112,84},
139 {0,112,112},    {0,84,112},
140 {0,56,112},    {0,28,112},   /*128*/
141 {56,56,112},    {68,56,112},
142 {84,56,112},    {96,56,112},
143 {112,56,112},    {112,56,96},
144 {112,56,84},    {112,56,68},
145 {112,56,56},    {112,68,56},
146 {112,84,56},    {112,96,56},
147 {112,112,56},    {96,112,56},
148 {84,112,56},    {68,112,56},  /*144*/
149 {56,112,56},    {56,112,69},
150 {56,112,84},    {56,112,96},
151 {56,112,112},    {56,96,112},
152 {56,84,112},    {56,68,112},
153 {80,80,112},    {88,80,112},
154 {96,80,112},    {104,80,112},
155 {112,80,112},    {112,80,104},
156 {112,80,96},    {112,80,88},  /*160*/
157 {112,80,80},    {112,88,80},
158 {112,96,80},    {112,104,80},
159 {112,112,80},    {104,112,80},
160 {96,112,80},    {88,112,80},
161 {80,112,80},    {80,112,88},
162 {80,112,96},    {80,112,104},
163 {80,112,112},    {80,114,112},
164 {80,96,112},    {80,88,112},  /*176*/
165 {0,0,64},    {16,0,64},
166 {32,0,64},    {48,0,64},
167 {64,0,64},    {64,0,48},
168 {64,0,32},    {64,0,16},
169 {64,0,0},    {64,16,0},
170 {64,32,0},    {64,48,0},
171 {64,64,0},    {48,64,0},
172 {32,64,0},    {16,64,0},  /*192*/
173 {0,64,0},    {0,64,16},
174 {0,64,32},    {0,64,48},
175 {0,64,64},    {0,48,64},
176 {0,32,64},    {0,16,64},
177 {32,32,64},    {40,32,64},
178 {48,32,64},    {56,32,64},
179 {64,32,64},    {64,32,56},
180 {64,32,48},    {64,32,40},  /*208*/
181 {64,32,32},    {64,40,32},
182 {64,48,32},    {64,56,32},
183 {64,64,32},    {56,64,32},
184 {48,64,32},    {40,64,32},
185 {32,64,32},    {32,64,40},
186 {32,64,48},    {32,64,56},
187 {32,64,64},    {32,56,64},
188 {32,48,64},    {32,40,64},  /*224*/
189 {44,44,64},    {48,44,64},
190 {52,44,64},    {60,44,64},
191 {64,44,64},    {64,44,60},
192 {64,44,52},    {64,44,48},
193 {64,44,44},    {64,48,44},
194 {64,52,44},    {64,60,44},
195 {64,64,44},    {60,64,44},
196 {52,64,44},    {48,64,44},  /*240*/
197 {44,64,44},    {44,64,48},
198 {44,64,52},    {44,64,60},
199 {44,64,64},    {44,60,64},
200 {44,55,64},    {44,48,64},
201 {0,0,0},    {0,0,0},
202 {0,0,0},    {0,0,0},
203 {0,0,0},    {0,0,0},
204 {0,0,0},    {0,0,0}    /*256*/
205 };
206 
207 /*
208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
209 %                                                                             %
210 %                                                                             %
211 %                                                                             %
212 %   I s W P G                                                                 %
213 %                                                                             %
214 %                                                                             %
215 %                                                                             %
216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 %
218 %  IsWPG() returns True if the image format type, identified by the magick
219 %  string, is WPG.
220 %
221 %  The format of the IsWPG method is:
222 %
223 %      unsigned int IsWPG(const unsigned char *magick,const size_t length)
224 %
225 %  A description of each parameter follows:
226 %
227 %    o status:  Method IsWPG returns True if the image format type is WPG.
228 %
229 %    o magick: compare image format pattern against these bytes.
230 %
231 %    o length: Specifies the length of the magick string.
232 %
233 */
IsWPG(const unsigned char * magick,const size_t length)234 static unsigned int IsWPG(const unsigned char *magick,const size_t length)
235 {
236   if (length < 4)
237     return(MagickFalse);
238   if (memcmp(magick,"\377WPC",4) == 0)
239     return(MagickTrue);
240   return(MagickFalse);
241 }
242 
243 
Rd_WP_DWORD(Image * image,size_t * d)244 static void Rd_WP_DWORD(Image *image,size_t *d)
245 {
246   unsigned char
247     b;
248 
249   b=ReadBlobByte(image);
250   *d=b;
251   if (b < 0xFFU)
252     return;
253   b=ReadBlobByte(image);
254   *d=(size_t) b;
255   b=ReadBlobByte(image);
256   *d+=(size_t) b*256l;
257   if (*d < 0x8000)
258     return;
259   *d=(*d & 0x7FFF) << 16;
260   b=ReadBlobByte(image);
261   *d+=(size_t) b;
262   b=ReadBlobByte(image);
263   *d+=(size_t) b*256l;
264   return;
265 }
266 
InsertRow(Image * image,unsigned char * p,ssize_t y,int bpp,ExceptionInfo * exception)267 static MagickBooleanType InsertRow(Image *image,unsigned char *p,ssize_t y,
268   int bpp,ExceptionInfo *exception)
269 {
270   int
271     bit;
272 
273   Quantum
274     index;
275 
276   Quantum
277     *q;
278 
279   ssize_t
280     x;
281 
282   q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
283   if (q == (Quantum *) NULL)
284     return(MagickFalse);
285   switch (bpp)
286     {
287     case 1:  /* Convert bitmap scanline. */
288       {
289         for (x=0; x < ((ssize_t) image->columns-7); x+=8)
290         {
291           for (bit=0; bit < 8; bit++)
292           {
293             index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
294             SetPixelIndex(image,index,q);
295             if (index < image->colors)
296               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
297             q+=GetPixelChannels(image);
298           }
299           p++;
300         }
301         if ((image->columns % 8) != 0)
302           {
303             for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
304             {
305               index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
306               SetPixelIndex(image,index,q);
307               if (index < image->colors)
308                 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
309               q+=GetPixelChannels(image);
310             }
311             p++;
312           }
313         break;
314       }
315     case 2:  /* Convert PseudoColor scanline. */
316       {
317         for (x=0; x < ((ssize_t) image->columns-3); x+=4)
318         {
319             index=ConstrainColormapIndex(image,(*p >> 6) & 0x3,exception);
320             SetPixelIndex(image,index,q);
321             if (index < image->colors)
322               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
323             q+=GetPixelChannels(image);
324             index=ConstrainColormapIndex(image,(*p >> 4) & 0x3,exception);
325             SetPixelIndex(image,index,q);
326             if (index < image->colors)
327               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
328             q+=GetPixelChannels(image);
329             index=ConstrainColormapIndex(image,(*p >> 2) & 0x3,exception);
330             SetPixelIndex(image,index,q);
331             if (index < image->colors)
332               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
333             q+=GetPixelChannels(image);
334             index=ConstrainColormapIndex(image,(*p) & 0x3,exception);
335             SetPixelIndex(image,index,q);
336             if (index < image->colors)
337               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
338             q+=GetPixelChannels(image);
339             p++;
340         }
341        if ((image->columns % 4) != 0)
342           {
343             index=ConstrainColormapIndex(image,(*p >> 6) & 0x3,exception);
344             SetPixelIndex(image,index,q);
345             if (index < image->colors)
346               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
347             q+=GetPixelChannels(image);
348             if ((image->columns % 4) > 1)
349               {
350                 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3,exception);
351                 SetPixelIndex(image,index,q);
352                 if (index < image->colors)
353                   SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
354                 q+=GetPixelChannels(image);
355                 if ((image->columns % 4) > 2)
356                   {
357                     index=ConstrainColormapIndex(image,(*p >> 2) & 0x3,
358                       exception);
359                     SetPixelIndex(image,index,q);
360                     if (index < image->colors)
361                       SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
362                         index,q);
363                     q+=GetPixelChannels(image);
364                   }
365               }
366             p++;
367           }
368         break;
369       }
370 
371     case 4:  /* Convert PseudoColor scanline. */
372       {
373         for (x=0; x < ((ssize_t) image->columns-1); x+=2)
374           {
375             index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f,exception);
376             SetPixelIndex(image,index,q);
377             if (index < image->colors)
378               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
379             q+=GetPixelChannels(image);
380             index=ConstrainColormapIndex(image,(*p) & 0x0f,exception);
381             SetPixelIndex(image,index,q);
382             if (index < image->colors)
383               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
384             p++;
385             q+=GetPixelChannels(image);
386           }
387         if ((image->columns % 2) != 0)
388           {
389             index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f,exception);
390             SetPixelIndex(image,index,q);
391             if (index < image->colors)
392               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
393             p++;
394             q+=GetPixelChannels(image);
395           }
396         break;
397       }
398     case 8: /* Convert PseudoColor scanline. */
399       {
400         for (x=0; x < (ssize_t) image->columns; x++)
401           {
402             index=ConstrainColormapIndex(image,*p,exception);
403             SetPixelIndex(image,index,q);
404             if (index < image->colors)
405               SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
406             p++;
407             q+=GetPixelChannels(image);
408           }
409       }
410       break;
411 
412     case 24:     /*  Convert DirectColor scanline.  */
413       for (x=0; x < (ssize_t) image->columns; x++)
414         {
415           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
416           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
417           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
418           q+=GetPixelChannels(image);
419         }
420       break;
421     }
422   if (!SyncAuthenticPixels(image,exception))
423     return(MagickFalse);
424   return(MagickTrue);
425 }
426 
427 
428 /* Helper for WPG1 raster reader. */
429 #define InsertByte(b) \
430 { \
431   BImgBuff[x]=b; \
432   x++; \
433   if((ssize_t) x>=ldblk) \
434   { \
435     if (InsertRow(image,BImgBuff,(ssize_t) y,bpp,exception) != MagickFalse) \
436       y++; \
437     x=0; \
438   } \
439 }
440 /* WPG1 raster reader. */
UnpackWPGRaster(Image * image,int bpp,ExceptionInfo * exception)441 static int UnpackWPGRaster(Image *image,int bpp,ExceptionInfo *exception)
442 {
443   int
444     x,
445     y,
446     i;
447 
448   unsigned char
449     bbuf,
450     *BImgBuff,
451     RunCount;
452 
453   ssize_t
454     ldblk;
455 
456   x=0;
457   y=0;
458 
459   ldblk=(ssize_t) ((bpp*image->columns+7)/8);
460   BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
461     8*sizeof(*BImgBuff));
462   if(BImgBuff==NULL) return(-2);
463   (void) memset(BImgBuff,0,(size_t) ldblk*8*sizeof(*BImgBuff));
464 
465   while(y<(ssize_t) image->rows)
466     {
467       int
468         c;
469 
470       c=ReadBlobByte(image);
471       if (c == EOF)
472         break;
473       bbuf=(unsigned char) c;
474       RunCount=bbuf & 0x7F;
475       if(bbuf & 0x80)
476         {
477           if(RunCount)  /* repeat next byte runcount * */
478             {
479               bbuf=ReadBlobByte(image);
480               for(i=0;i<(int) RunCount;i++) InsertByte(bbuf);
481             }
482           else {  /* read next byte as RunCount; repeat 0xFF runcount* */
483             c=ReadBlobByte(image);
484             if (c < 0)
485               break;
486             RunCount=(unsigned char) c;
487             for(i=0;i<(int) RunCount;i++) InsertByte(0xFF);
488           }
489         }
490       else {
491         if(RunCount)   /* next runcount byte are readed directly */
492           {
493             for(i=0;i < (int) RunCount;i++)
494               {
495                 c=ReadBlobByte(image);
496                 if (c < 0)
497                   break;
498                 InsertByte(c);
499               }
500           }
501         else {  /* repeat previous line runcount* */
502           c=ReadBlobByte(image);
503           if (c == EOF)
504             {
505               BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
506               return(-7);
507             }
508           RunCount=(unsigned char) c;
509           if(x) {    /* attempt to duplicate row from x position: */
510             /* I do not know what to do here */
511             BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
512             return(-3);
513           }
514           for(i=0;i < (int) RunCount;i++)
515             {
516               x=0;
517               y++;    /* Here I need to duplicate previous row RUNCOUNT* */
518               if(y<2) continue;
519               if(y>(ssize_t) image->rows)
520                 {
521                   BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
522                   return(-4);
523                 }
524               if (InsertRow(image,BImgBuff,y-1,bpp,exception) == MagickFalse)
525                 {
526                   BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
527                   return(-5);
528                 }
529             }
530         }
531       }
532       if (EOFBlob(image) != MagickFalse)
533         break;
534     }
535   BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
536   return(y <(ssize_t) image->rows ? -5 : 0);
537 }
538 
539 
540 /* Helper for WPG2 reader. */
541 #define InsertByte6(b) \
542 { \
543 DisableMSCWarning(4310) \
544   if(XorMe)\
545     BImgBuff[x] = (unsigned char)~b;\
546   else\
547     BImgBuff[x] = b;\
548 RestoreMSCWarning \
549   x++; \
550   if((ssize_t) x >= ldblk) \
551   { \
552     if (InsertRow(image,BImgBuff,(ssize_t) y,bpp,exception) != MagickFalse) \
553       y++; \
554     x=0; \
555    } \
556 }
557 /* WPG2 raster reader. */
UnpackWPG2Raster(Image * image,int bpp,ExceptionInfo * exception)558 static int UnpackWPG2Raster(Image *image,int bpp,ExceptionInfo *exception)
559 {
560   int
561     RunCount,
562     XorMe = 0;
563 
564   ssize_t
565     i;
566 
567   size_t
568     x,
569     y;
570 
571   ssize_t
572     ldblk;
573 
574   unsigned int
575     SampleSize=1;
576 
577   unsigned char
578     bbuf,
579     *BImgBuff,
580     SampleBuffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
581 
582   x=0;
583   y=0;
584   ldblk=(ssize_t) ((bpp*image->columns+7)/8);
585   BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
586     sizeof(*BImgBuff));
587   if(BImgBuff==NULL)
588     return(-2);
589   (void) memset(BImgBuff,0,ldblk*sizeof(*BImgBuff));
590 
591   while( y< image->rows)
592     {
593       bbuf=ReadBlobByte(image);
594 
595       switch(bbuf)
596         {
597         case 0x7D:
598           SampleSize=ReadBlobByte(image);  /* DSZ */
599           if(SampleSize>8)
600             {
601               BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
602               return(-2);
603             }
604           if(SampleSize<1)
605             {
606               BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
607               return(-2);
608             }
609           break;
610         case 0x7E:
611           if (y == 0)
612             (void) FormatLocaleFile(stderr,
613               "\nUnsupported WPG token XOR, please report!");
614           XorMe=!XorMe;
615           break;
616         case 0x7F:
617           RunCount=ReadBlobByte(image);   /* BLK */
618           if (RunCount < 0)
619             break;
620           for(i=0; i < ((ssize_t) SampleSize*(RunCount+1)); i++)
621             {
622               InsertByte6(0);
623             }
624           break;
625         case 0xFD:
626           RunCount=ReadBlobByte(image);   /* EXT */
627           if (RunCount < 0)
628             break;
629           for(i=0; i<= RunCount;i++)
630             for(bbuf=0; bbuf < SampleSize; bbuf++)
631               InsertByte6(SampleBuffer[bbuf]);
632           break;
633         case 0xFE:
634           RunCount=ReadBlobByte(image);  /* RST */
635           if (RunCount < 0)
636             break;
637           if(x!=0)
638             {
639               (void) FormatLocaleFile(stderr,
640                 "\nUnsupported WPG2 unaligned token RST x=%.20g, please report!\n"
641                 ,(double) x);
642               BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
643               return(-3);
644             }
645           {
646             /* duplicate the previous row RunCount x */
647             for(i=0;i<=RunCount;i++)
648               {
649                 if (InsertRow(image,BImgBuff,(ssize_t) (image->rows > y ? y : image->rows-1),bpp,exception) == MagickFalse)
650                   {
651                     BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
652                     return(-3);
653                   }
654                 y++;
655               }
656           }
657           break;
658         case 0xFF:
659           RunCount=ReadBlobByte(image);   /* WHT */
660           if (RunCount < 0)
661             break;
662           for(i=0; i < ((ssize_t) SampleSize*(RunCount+1)); i++)
663             {
664               InsertByte6(0xFF);
665             }
666           break;
667         default:
668           RunCount=bbuf & 0x7F;
669 
670           if(bbuf & 0x80)     /* REP */
671             {
672               for(i=0; i < SampleSize; i++)
673                 SampleBuffer[i]=ReadBlobByte(image);
674               for(i=0;i<=RunCount;i++)
675                 for(bbuf=0;bbuf<SampleSize;bbuf++)
676                   InsertByte6(SampleBuffer[bbuf]);
677             }
678           else {      /* NRP */
679             for(i=0; i < (ssize_t) (SampleSize*(RunCount+1)); i++)
680               {
681                 bbuf=ReadBlobByte(image);
682                 InsertByte6(bbuf);
683               }
684           }
685         }
686       if (EOFBlob(image) != MagickFalse)
687         break;
688     }
689   BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
690   return(0);
691 }
692 
693 
694 typedef float tCTM[3][3];
695 
LoadWPG2Flags(Image * image,char Precision,float * Angle,tCTM * CTM)696 static unsigned LoadWPG2Flags(Image *image,char Precision,float *Angle,tCTM *CTM)
697 {
698 const unsigned char TPR=1,TRN=2,SKW=4,SCL=8,ROT=0x10,OID=0x20,LCK=0x80;
699 ssize_t x;
700 unsigned DenX;
701 unsigned Flags;
702 
703  (void) memset(*CTM,0,sizeof(*CTM));     /*CTM.erase();CTM.resize(3,3);*/
704  (*CTM)[0][0]=1;
705  (*CTM)[1][1]=1;
706  (*CTM)[2][2]=1;
707 
708  Flags=ReadBlobLSBShort(image);
709  if(Flags & LCK) (void) ReadBlobLSBLong(image);  /*Edit lock*/
710  if(Flags & OID)
711   {
712     /* Read object ID. */
713     if (Precision == 0)
714       {
715         x=ReadBlobLSBShort(image);
716         if (x >= 0x8000)
717           {
718             Precision=1;
719             (void) ReadBlobLSBShort(image);
720           }
721       }
722     else
723       (void) ReadBlobLSBLong(image);
724   }
725  if(Flags & ROT)
726   {
727   x=ReadBlobLSBLong(image);  /*Rot Angle*/
728   if(Angle) *Angle=x/65536.0;
729   }
730  if(Flags & (ROT|SCL))
731   {
732   x=ReadBlobLSBLong(image);  /*Sx*cos()*/
733   (*CTM)[0][0] = (float)x/0x10000;
734   x=ReadBlobLSBLong(image);  /*Sy*cos()*/
735   (*CTM)[1][1] = (float)x/0x10000;
736   }
737  if(Flags & (ROT|SKW))
738   {
739   x=ReadBlobLSBLong(image);       /*Kx*sin()*/
740   (*CTM)[1][0] = (float)x/0x10000;
741   x=ReadBlobLSBLong(image);       /*Ky*sin()*/
742   (*CTM)[0][1] = (float)x/0x10000;
743   }
744  if(Flags & TRN)
745   {
746   x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image);  /*Tx*/
747         if(x>=0) (*CTM)[0][2] = (float)x+(float)DenX/0x10000;
748             else (*CTM)[0][2] = (float)x-(float)DenX/0x10000;
749   x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image);  /*Ty*/
750   (*CTM)[1][2]=(float)x + ((x>=0)?1:-1)*(float)DenX/0x10000;
751         if(x>=0) (*CTM)[1][2] = (float)x+(float)DenX/0x10000;
752             else (*CTM)[1][2] = (float)x-(float)DenX/0x10000;
753   }
754  if(Flags & TPR)
755   {
756   x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image);  /*Px*/
757   (*CTM)[2][0] = x + (float)DenX/0x10000;;
758   x=ReadBlobLSBShort(image);  DenX=ReadBlobLSBShort(image); /*Py*/
759   (*CTM)[2][1] = x + (float)DenX/0x10000;
760   }
761  return(Flags);
762 }
763 
764 
ExtractPostscript(Image * image,const ImageInfo * image_info,MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo * exception)765 static Image *ExtractPostscript(Image *image,const ImageInfo *image_info,
766   MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo *exception)
767 {
768   char
769     postscript_file[MagickPathExtent];
770 
771   const MagicInfo
772     *magic_info;
773 
774   FILE
775     *ps_file;
776 
777   int
778     c;
779 
780   ImageInfo
781     *clone_info;
782 
783   Image
784     *image2;
785 
786   MagickBooleanType
787     status;
788 
789   unsigned char
790     magick[2*MagickPathExtent];
791 
792   ssize_t
793     count;
794 
795   if ((clone_info=CloneImageInfo(image_info)) == NULL)
796     return(image);
797   clone_info->blob=(void *) NULL;
798   clone_info->length=0;
799   status=MagickFalse;
800 
801   /* Obtain temporary file */
802   (void) AcquireUniqueFilename(postscript_file);
803   ps_file=fopen_utf8(postscript_file,"wb");
804   if (ps_file == (FILE *) NULL)
805     goto FINISH;
806 
807   /* Copy postscript to temporary file */
808   if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
809     {
810       (void) fclose(ps_file);
811       ThrowException(exception,CorruptImageError,"ImproperImageHeader",
812         image->filename);
813       goto FINISH_UNL;
814     }
815   count=ReadBlob(image, 2*MagickPathExtent, magick);
816   if (count < 1)
817     {
818       (void) fclose(ps_file);
819       ThrowException(exception,CorruptImageError,"ImproperImageHeader",
820         image->filename);
821       goto FINISH_UNL;
822     }
823 
824   if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
825     {
826       (void) fclose(ps_file);
827       ThrowException(exception,CorruptImageError,"ImproperImageHeader",
828         image->filename);
829       goto FINISH_UNL;
830     }
831   while (PS_Size-- > 0)
832   {
833     c=ReadBlobByte(image);
834     if (c == EOF)
835       {
836         (void) fclose(ps_file);
837         ThrowException(exception,CorruptImageError,"ImproperImageHeader",
838           image->filename);
839         goto FINISH_UNL;
840       }
841     (void) fputc(c,ps_file);
842   }
843   (void) fclose(ps_file);
844 
845     /* Detect file format - Check magic.mgk configuration file. */
846   magic_info=GetMagicInfo(magick,count,exception);
847   if(magic_info == (const MagicInfo *) NULL) goto FINISH_UNL;
848   /*     printf("Detected:%s  \n",magic_info->name); */
849   if(exception->severity != UndefinedException) goto FINISH_UNL;
850   (void) CopyMagickString(clone_info->magick,GetMagicName(magic_info),
851     MagickPathExtent);
852   if (LocaleCompare(clone_info->magick,"PFB") != 0)
853     {
854       ThrowException(exception,CorruptImageError,"ImproperImageHeader",
855         image->filename);
856       goto FINISH_UNL;
857     }
858 
859     /* Read nested image */
860   /*FormatString(clone_info->filename,"%s:%s",magic_info->name,postscript_file);*/
861   FormatLocaleString(clone_info->filename,MagickPathExtent,"%.1024s:%.1024s",
862     clone_info->magick,postscript_file);
863   image2=ReadImage(clone_info,exception);
864 
865   if (!image2)
866     goto FINISH_UNL;
867   if(exception->severity>=ErrorException)
868   {
869     CloseBlob(image2);
870     DestroyImageList(image2);
871     goto FINISH_UNL;
872   }
873 
874   {
875     Image
876       *p;
877 
878     /*
879       Replace current image with new image while copying base image attributes.
880     */
881     p=image2;
882     do
883     {
884       (void) CopyMagickString(p->filename,image->filename,MagickPathExtent);
885       (void) CopyMagickString(p->magick_filename,image->magick_filename,
886         MagickPathExtent);
887       (void) CopyMagickString(p->magick,image->magick,MagickPathExtent);
888       if ((p->rows == 0) || (p->columns == 0))
889         {
890           DeleteImageFromList(&p);
891           if (p == (Image *) NULL)
892             {
893               image2=(Image *) NULL;
894               goto FINISH_UNL;
895             }
896         }
897       else
898         {
899           DestroyBlob(p);
900           p->blob=ReferenceBlob(image->blob);
901           p=p->next;
902         }
903     } while (p != (Image *) NULL);
904   }
905 
906   if ((image->rows == 0 || image->columns == 0) &&
907       (image->previous != NULL || image->next != NULL))
908   {
909     DeleteImageFromList(&image);
910   }
911 
912   AppendImageToList(&image,image2);
913   while (image->next != NULL)
914     image=image->next;
915   status=MagickTrue;
916 
917  FINISH_UNL:
918   (void) RelinquishUniqueFileResource(postscript_file);
919  FINISH:
920   DestroyImageInfo(clone_info);
921   if (status == MagickFalse)
922     return(DestroyImageList(image));
923   return(image);
924 }
925 
926 /*
927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
928 %                                                                             %
929 %                                                                             %
930 %                                                                             %
931 %   R e a d W P G I m a g e                                                   %
932 %                                                                             %
933 %                                                                             %
934 %                                                                             %
935 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
936 %
937 %  Method ReadWPGImage reads an WPG X image file and returns it.  It
938 %  allocates the memory necessary for the new Image structure and returns a
939 %  pointer to the new image.
940 %
941 %  The format of the ReadWPGImage method is:
942 %
943 %    Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception)
944 %
945 %  A description of each parameter follows:
946 %
947 %    o image:  Method ReadWPGImage returns a pointer to the image after
948 %      reading. A null image is returned if there is a memory shortage or if
949 %      the image cannot be read.
950 %
951 %    o image_info: Specifies a pointer to a ImageInfo structure.
952 %
953 %    o exception: return any errors or warnings in this structure.
954 %
955 */
ReadWPGImage(const ImageInfo * image_info,ExceptionInfo * exception)956 static Image *ReadWPGImage(const ImageInfo *image_info,
957   ExceptionInfo *exception)
958 {
959   typedef struct
960   {
961     size_t FileId;
962     MagickOffsetType DataOffset;
963     unsigned int ProductType;
964     unsigned int FileType;
965     unsigned char MajorVersion;
966     unsigned char MinorVersion;
967     unsigned int EncryptKey;
968     unsigned int Reserved;
969   } WPGHeader;
970 
971   typedef struct
972   {
973     unsigned char RecType;
974     size_t RecordLength;
975   } WPGRecord;
976 
977   typedef struct
978   {
979     unsigned char Class;
980     unsigned char RecType;
981     size_t Extension;
982     size_t RecordLength;
983   } WPG2Record;
984 
985   typedef struct
986   {
987     unsigned  HorizontalUnits;
988     unsigned  VerticalUnits;
989     unsigned char PosSizePrecision;
990   } WPG2Start;
991 
992   typedef struct
993   {
994     unsigned int Width;
995     unsigned int Height;
996     unsigned int Depth;
997     unsigned int HorzRes;
998     unsigned int VertRes;
999   } WPGBitmapType1;
1000 
1001   typedef struct
1002   {
1003     unsigned int Width;
1004     unsigned int Height;
1005     unsigned char Depth;
1006     unsigned char Compression;
1007   } WPG2BitmapType1;
1008 
1009   typedef struct
1010   {
1011     unsigned int RotAngle;
1012     unsigned int LowLeftX;
1013     unsigned int LowLeftY;
1014     unsigned int UpRightX;
1015     unsigned int UpRightY;
1016     unsigned int Width;
1017     unsigned int Height;
1018     unsigned int Depth;
1019     unsigned int HorzRes;
1020     unsigned int VertRes;
1021   } WPGBitmapType2;
1022 
1023   typedef struct
1024   {
1025     unsigned int StartIndex;
1026     unsigned int NumOfEntries;
1027   } WPGColorMapRec;
1028 
1029   /*
1030   typedef struct {
1031     size_t PS_unknown1;
1032     unsigned int PS_unknown2;
1033     unsigned int PS_unknown3;
1034   } WPGPSl1Record;
1035   */
1036 
1037   Image
1038     *image;
1039 
1040   unsigned int
1041     status;
1042 
1043   WPGHeader
1044     Header;
1045 
1046   WPGRecord
1047     Rec;
1048 
1049   WPG2Record
1050     Rec2;
1051 
1052   WPG2Start StartWPG;
1053 
1054   WPGBitmapType1
1055     BitmapHeader1;
1056 
1057   WPG2BitmapType1
1058     Bitmap2Header1;
1059 
1060   WPGBitmapType2
1061     BitmapHeader2;
1062 
1063   WPGColorMapRec
1064     WPG_Palette;
1065 
1066   int
1067     i,
1068     bpp,
1069     WPG2Flags;
1070 
1071   ssize_t
1072     ldblk;
1073 
1074   size_t
1075     one;
1076 
1077   unsigned char
1078     *BImgBuff;
1079 
1080   tCTM CTM;         /*current transform matrix*/
1081 
1082   /*
1083     Open image file.
1084   */
1085   assert(image_info != (const ImageInfo *) NULL);
1086   assert(image_info->signature == MagickCoreSignature);
1087   assert(exception != (ExceptionInfo *) NULL);
1088   assert(exception->signature == MagickCoreSignature);
1089   one=1;
1090   image=AcquireImage(image_info,exception);
1091   image->depth=8;
1092   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1093   if (status == MagickFalse)
1094     {
1095       image=DestroyImageList(image);
1096       return((Image *) NULL);
1097     }
1098   /*
1099     Read WPG image.
1100   */
1101   Header.FileId=ReadBlobLSBLong(image);
1102   Header.DataOffset=(MagickOffsetType) ReadBlobLSBLong(image);
1103   Header.ProductType=ReadBlobLSBShort(image);
1104   Header.FileType=ReadBlobLSBShort(image);
1105   Header.MajorVersion=ReadBlobByte(image);
1106   Header.MinorVersion=ReadBlobByte(image);
1107   Header.EncryptKey=ReadBlobLSBShort(image);
1108   Header.Reserved=ReadBlobLSBShort(image);
1109 
1110   if (Header.FileId!=0x435057FF || (Header.ProductType>>8)!=0x16)
1111     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1112   if (Header.EncryptKey!=0)
1113     ThrowReaderException(CoderError,"EncryptedWPGImageFileNotSupported");
1114 
1115   image->columns = 1;
1116   image->rows = 1;
1117   image->colors = 0;
1118   image->storage_class=DirectClass;
1119   (void) ResetImagePixels(image,exception);
1120   bpp=0;
1121   BitmapHeader2.RotAngle=0;
1122   Rec2.RecordLength=0;
1123 
1124   switch(Header.FileType)
1125     {
1126     case 1:     /* WPG level 1 */
1127       while(!EOFBlob(image)) /* object parser loop */
1128         {
1129           if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
1130             break;
1131           if(EOFBlob(image))
1132             break;
1133 
1134           Rec.RecType=(i=ReadBlobByte(image));
1135           if(i==EOF)
1136             break;
1137           Rd_WP_DWORD(image,&Rec.RecordLength);
1138           if (Rec.RecordLength > GetBlobSize(image))
1139             ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1140           if(EOFBlob(image))
1141             break;
1142 
1143           Header.DataOffset=TellBlob(image)+Rec.RecordLength;
1144 
1145           switch(Rec.RecType)
1146             {
1147             case 0x0B: /* bitmap type 1 */
1148               BitmapHeader1.Width=ReadBlobLSBShort(image);
1149               BitmapHeader1.Height=ReadBlobLSBShort(image);
1150               if ((BitmapHeader1.Width == 0) || (BitmapHeader1.Height == 0))
1151                 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1152               BitmapHeader1.Depth=ReadBlobLSBShort(image);
1153               BitmapHeader1.HorzRes=ReadBlobLSBShort(image);
1154               BitmapHeader1.VertRes=ReadBlobLSBShort(image);
1155 
1156               if(BitmapHeader1.HorzRes && BitmapHeader1.VertRes)
1157                 {
1158                   image->units=PixelsPerCentimeterResolution;
1159                   image->resolution.x=BitmapHeader1.HorzRes/470.0;
1160                   image->resolution.y=BitmapHeader1.VertRes/470.0;
1161                 }
1162               image->columns=BitmapHeader1.Width;
1163               image->rows=BitmapHeader1.Height;
1164               bpp=BitmapHeader1.Depth;
1165 
1166               goto UnpackRaster;
1167 
1168             case 0x0E:  /*Color palette */
1169               WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1170               WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1171               if ((WPG_Palette.NumOfEntries-WPG_Palette.StartIndex) >
1172                   (Rec2.RecordLength-2-2)/3)
1173                 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1174               if (WPG_Palette.StartIndex > WPG_Palette.NumOfEntries)
1175                 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1176               image->colors=WPG_Palette.NumOfEntries;
1177               if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
1178                 goto NoMemory;
1179               for (i=WPG_Palette.StartIndex;
1180                    i < (int)WPG_Palette.NumOfEntries; i++)
1181                 {
1182                   image->colormap[i].red=ScaleCharToQuantum((unsigned char)
1183                     ReadBlobByte(image));
1184                   image->colormap[i].green=ScaleCharToQuantum((unsigned char)
1185                     ReadBlobByte(image));
1186                   image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
1187                     ReadBlobByte(image));
1188                 }
1189               break;
1190 
1191             case 0x11:  /* Start PS l1 */
1192               if (Rec.RecordLength > 8)
1193                 {
1194                   image=ExtractPostscript(image,image_info,
1195                     TellBlob(image)+8,   /* skip PS header in the wpg */
1196                     (ssize_t) Rec.RecordLength-8,exception);
1197                   if (image == NULL)
1198                     ThrowReaderException(CorruptImageError,
1199                       "ImproperImageHeader");
1200                 }
1201               break;
1202 
1203             case 0x14:  /* bitmap type 2 */
1204               BitmapHeader2.RotAngle=ReadBlobLSBShort(image);
1205               BitmapHeader2.LowLeftX=ReadBlobLSBShort(image);
1206               BitmapHeader2.LowLeftY=ReadBlobLSBShort(image);
1207               BitmapHeader2.UpRightX=ReadBlobLSBShort(image);
1208               BitmapHeader2.UpRightY=ReadBlobLSBShort(image);
1209               BitmapHeader2.Width=ReadBlobLSBShort(image);
1210               BitmapHeader2.Height=ReadBlobLSBShort(image);
1211               if ((BitmapHeader2.Width == 0) || (BitmapHeader2.Height == 0))
1212                 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1213               BitmapHeader2.Depth=ReadBlobLSBShort(image);
1214               BitmapHeader2.HorzRes=ReadBlobLSBShort(image);
1215               BitmapHeader2.VertRes=ReadBlobLSBShort(image);
1216 
1217               image->units=PixelsPerCentimeterResolution;
1218               image->page.width=(unsigned int)
1219                 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightX)/470.0);
1220               image->page.height=(unsigned int)
1221                 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightY)/470.0);
1222               image->page.x=(int) (BitmapHeader2.LowLeftX/470.0);
1223               image->page.y=(int) (BitmapHeader2.LowLeftX/470.0);
1224               if(BitmapHeader2.HorzRes && BitmapHeader2.VertRes)
1225                 {
1226                   image->resolution.x=BitmapHeader2.HorzRes/470.0;
1227                   image->resolution.y=BitmapHeader2.VertRes/470.0;
1228                 }
1229               image->columns=BitmapHeader2.Width;
1230               image->rows=BitmapHeader2.Height;
1231               bpp=BitmapHeader2.Depth;
1232 
1233             UnpackRaster:
1234               status=SetImageExtent(image,image->columns,image->rows,exception);
1235               if (status == MagickFalse)
1236                 break;
1237               (void) ResetImagePixels(image,exception);
1238               if ((image->storage_class != PseudoClass) && (bpp < 24))
1239                 {
1240                   image->colors=one << bpp;
1241                   if (image->colors > GetBlobSize(image))
1242                     ThrowReaderException(CorruptImageError,
1243                       "InsufficientImageDataInFile");
1244                   if (!AcquireImageColormap(image,image->colors,exception))
1245                     {
1246                     NoMemory:
1247                       ThrowReaderException(ResourceLimitError,
1248                         "MemoryAllocationFailed");
1249                     }
1250                   /* printf("Load default colormap \n"); */
1251                   for (i=0; (i < (int) image->colors) && (i < 256); i++)
1252                     {
1253                       image->colormap[i].red=ScaleCharToQuantum(WPG1_Palette[i].Red);
1254                       image->colormap[i].green=ScaleCharToQuantum(WPG1_Palette[i].Green);
1255                       image->colormap[i].blue=ScaleCharToQuantum(WPG1_Palette[i].Blue);
1256                       image->colormap[i].alpha=OpaqueAlpha;
1257                     }
1258                 }
1259               else
1260                 {
1261                   if (bpp < 24)
1262                   if ( (image->colors < (one << bpp)) && (bpp != 24) )
1263                     {
1264                       PixelInfo
1265                         *colormap;
1266 
1267                       size_t
1268                         colors;
1269 
1270                       colormap=image->colormap;
1271                       colors=image->colors;
1272                       image->colormap=(PixelInfo *) NULL;
1273                       if (AcquireImageColormap(image,one << bpp,exception) == MagickFalse)
1274                         {
1275                           colormap=(PixelInfo *)
1276                             RelinquishMagickMemory(colormap);
1277                           goto NoMemory;
1278                         }
1279                       (void) memcpy(image->colormap,colormap,MagickMin(
1280                         image->colors,colors)*sizeof(*image->colormap));
1281                       colormap=(PixelInfo *)
1282                         RelinquishMagickMemory(colormap);
1283                     }
1284                 }
1285 
1286               if ((bpp == 1) && (image->colors > 1))
1287                 {
1288                   if(image->colormap[0].red==0 &&
1289                      image->colormap[0].green==0 &&
1290                      image->colormap[0].blue==0 &&
1291                      image->colormap[1].red==0 &&
1292                      image->colormap[1].green==0 &&
1293                      image->colormap[1].blue==0)
1294                     {  /* fix crippled monochrome palette */
1295                       image->colormap[1].red =
1296                         image->colormap[1].green =
1297                         image->colormap[1].blue = QuantumRange;
1298                       image->colormap[1].alpha=OpaqueAlpha;
1299                     }
1300                 }
1301               if(!image_info->ping)
1302                 if(UnpackWPGRaster(image,bpp,exception) < 0)
1303                   /* The raster cannot be unpacked */
1304                   {
1305                   DecompressionFailed:
1306                     ThrowReaderException(CoderError,"UnableToDecompressImage");
1307                   }
1308 
1309               if(Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping)
1310                 {
1311                   /* flop command */
1312                   if(BitmapHeader2.RotAngle & 0x8000)
1313                     {
1314                       Image
1315                         *flop_image;
1316 
1317                       flop_image = FlopImage(image, exception);
1318                       if (flop_image != (Image *) NULL) {
1319                         DuplicateBlob(flop_image,image);
1320                         ReplaceImageInList(&image,flop_image);
1321                       }
1322                     }
1323                   /* flip command */
1324                   if(BitmapHeader2.RotAngle & 0x2000)
1325                     {
1326                       Image
1327                         *flip_image;
1328 
1329                       flip_image = FlipImage(image, exception);
1330                       if (flip_image != (Image *) NULL) {
1331                         DuplicateBlob(flip_image,image);
1332                         ReplaceImageInList(&image,flip_image);
1333                       }
1334                     }
1335                   /* rotate command */
1336                   if(BitmapHeader2.RotAngle & 0x0FFF)
1337                     {
1338                       Image
1339                         *rotate_image;
1340 
1341                       rotate_image=RotateImage(image,(BitmapHeader2.RotAngle &
1342                         0x0FFF), exception);
1343                       if (rotate_image != (Image *) NULL) {
1344                         DuplicateBlob(rotate_image,image);
1345                         ReplaceImageInList(&image,rotate_image);
1346                       }
1347                     }
1348                 }
1349 
1350               /* Allocate next image structure. */
1351               if ((image_info->ping != MagickFalse) &&
1352                   (image_info->number_scenes != 0))
1353                 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1354                   goto Finish;
1355               AcquireNextImage(image_info,image,exception);
1356               image->depth=8;
1357               if (image->next == (Image *) NULL)
1358                 goto Finish;
1359               image=SyncNextImageInList(image);
1360               image->columns=image->rows=0;
1361               image->colors=0;
1362               break;
1363 
1364             case 0x1B:  /* Postscript l2 */
1365               if (Rec.RecordLength>0x3C)
1366                 {
1367                   image=ExtractPostscript(image,image_info,
1368                     TellBlob(image)+0x3C,   /* skip PS l2 header in the wpg */
1369                     (ssize_t) Rec.RecordLength-0x3C,exception);
1370                   if (image == NULL)
1371                     ThrowReaderException(CorruptImageError,
1372                       "ImproperImageHeader");
1373                 }
1374               break;
1375             }
1376         }
1377       break;
1378 
1379     case 2:  /* WPG level 2 */
1380       (void) memset(CTM,0,sizeof(CTM));
1381       StartWPG.PosSizePrecision = 0;
1382       while(!EOFBlob(image)) /* object parser loop */
1383         {
1384           if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
1385             break;
1386           if (EOFBlob(image))
1387             break;
1388 
1389           Rec2.Class=(i=ReadBlobByte(image));
1390           if(i==EOF)
1391             break;
1392           Rec2.RecType=(i=ReadBlobByte(image));
1393           if(i==EOF)
1394             break;
1395           Rd_WP_DWORD(image,&Rec2.Extension);
1396           Rd_WP_DWORD(image,&Rec2.RecordLength);
1397           if(EOFBlob(image))
1398             break;
1399 
1400           Header.DataOffset=TellBlob(image)+Rec2.RecordLength;
1401 
1402           switch(Rec2.RecType)
1403             {
1404       case 1:
1405               StartWPG.HorizontalUnits=ReadBlobLSBShort(image);
1406               StartWPG.VerticalUnits=ReadBlobLSBShort(image);
1407               StartWPG.PosSizePrecision=ReadBlobByte(image);
1408               break;
1409             case 0x0C:    /* Color palette */
1410               WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1411               WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1412               if ((WPG_Palette.NumOfEntries-WPG_Palette.StartIndex) >
1413                   (Rec2.RecordLength-2-2) / 3)
1414                 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1415               if (WPG_Palette.StartIndex >= WPG_Palette.NumOfEntries)
1416                 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1417               image->colors=WPG_Palette.NumOfEntries;
1418               if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
1419                 ThrowReaderException(ResourceLimitError,
1420                   "MemoryAllocationFailed");
1421               for (i=WPG_Palette.StartIndex;
1422                    i < (int)WPG_Palette.NumOfEntries; i++)
1423                 {
1424                   image->colormap[i].red=ScaleCharToQuantum((char)
1425                     ReadBlobByte(image));
1426                   image->colormap[i].green=ScaleCharToQuantum((char)
1427                     ReadBlobByte(image));
1428                   image->colormap[i].blue=ScaleCharToQuantum((char)
1429                     ReadBlobByte(image));
1430                   image->colormap[i].alpha=OpaqueAlpha;
1431                   (void) ReadBlobByte(image);   /*Opacity??*/
1432                 }
1433               break;
1434             case 0x0E:
1435               Bitmap2Header1.Width=ReadBlobLSBShort(image);
1436               Bitmap2Header1.Height=ReadBlobLSBShort(image);
1437               if ((Bitmap2Header1.Width == 0) || (Bitmap2Header1.Height == 0))
1438                 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1439               Bitmap2Header1.Depth=ReadBlobByte(image);
1440               Bitmap2Header1.Compression=ReadBlobByte(image);
1441 
1442               if(Bitmap2Header1.Compression > 1)
1443                 continue; /*Unknown compression method */
1444               switch(Bitmap2Header1.Depth)
1445                 {
1446                 case 1:
1447                   bpp=1;
1448                   break;
1449                 case 2:
1450                   bpp=2;
1451                   break;
1452                 case 3:
1453                   bpp=4;
1454                   break;
1455                 case 4:
1456                   bpp=8;
1457                   break;
1458                 case 8:
1459                   bpp=24;
1460                   break;
1461                 default:
1462                   continue;  /*Ignore raster with unknown depth*/
1463                 }
1464               image->columns=Bitmap2Header1.Width;
1465               image->rows=Bitmap2Header1.Height;
1466               if (image_info->ping != MagickFalse)
1467                 return(image);
1468               status=SetImageExtent(image,image->columns,image->rows,exception);
1469               if (status != MagickFalse)
1470                 status=ResetImagePixels(image,exception);
1471               if (status == MagickFalse)
1472                 break;
1473               if ((image->colors == 0) && (bpp != 24))
1474                 {
1475                   image->colors=one << bpp;
1476                   if (!AcquireImageColormap(image,image->colors,exception))
1477                     goto NoMemory;
1478                 }
1479               else
1480                 {
1481                   if(bpp < 24)
1482                     if( image->colors<(one << bpp) && bpp!=24 )
1483                       image->colormap=(PixelInfo *) ResizeQuantumMemory(
1484                        image->colormap,(size_t) (one << bpp),
1485                        sizeof(*image->colormap));
1486                 }
1487 
1488 
1489               switch(Bitmap2Header1.Compression)
1490                 {
1491                 case 0:    /*Uncompressed raster*/
1492                   {
1493                     ldblk=(ssize_t) ((bpp*image->columns+7)/8);
1494                     BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t)
1495                       ldblk+1,sizeof(*BImgBuff));
1496                     if (BImgBuff == (unsigned char *) NULL)
1497                       goto NoMemory;
1498                     for (i=0; i< (ssize_t) image->rows; i++)
1499                     {
1500                       ssize_t
1501                         count;
1502 
1503                       count=ReadBlob(image,(size_t) ldblk,BImgBuff);
1504                       if (count != ldblk)
1505                         break;
1506                       if (InsertRow(image,BImgBuff,i,bpp,exception) == MagickFalse)
1507                         break;
1508                     }
1509                     BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
1510                     if (i < (ssize_t) image->rows)
1511                       goto DecompressionFailed;
1512                     break;
1513                   }
1514                 case 1:    /*RLE for WPG2 */
1515                   {
1516                     if( UnpackWPG2Raster(image,bpp,exception) < 0)
1517                       goto DecompressionFailed;
1518                     break;
1519                   }
1520                 }
1521 
1522               if(CTM[0][0]<0 && !image_info->ping)
1523                 {    /*?? RotAngle=360-RotAngle;*/
1524                   Image
1525                     *flop_image;
1526 
1527                   flop_image = FlopImage(image, exception);
1528                   if (flop_image != (Image *) NULL) {
1529                     DuplicateBlob(flop_image,image);
1530                     ReplaceImageInList(&image,flop_image);
1531                   }
1532                   /* Try to change CTM according to Flip - I am not sure, must be checked.
1533                      Tx(0,0)=-1;      Tx(1,0)=0;   Tx(2,0)=0;
1534                      Tx(0,1)= 0;      Tx(1,1)=1;   Tx(2,1)=0;
1535                      Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
1536                      Tx(1,2)=0;   Tx(2,2)=1; */
1537                 }
1538               if(CTM[1][1]<0 && !image_info->ping)
1539                 {    /*?? RotAngle=360-RotAngle;*/
1540                   Image
1541                     *flip_image;
1542 
1543                    flip_image = FlipImage(image, exception);
1544                    if (flip_image != (Image *) NULL) {
1545                      DuplicateBlob(flip_image,image);
1546                      ReplaceImageInList(&image,flip_image);
1547                     }
1548                   /* Try to change CTM according to Flip - I am not sure, must be checked.
1549                      float_matrix Tx(3,3);
1550                      Tx(0,0)= 1;   Tx(1,0)= 0;   Tx(2,0)=0;
1551                      Tx(0,1)= 0;   Tx(1,1)=-1;   Tx(2,1)=0;
1552                      Tx(0,2)= 0;   Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
1553                      Tx(2,2)=1; */
1554               }
1555 
1556 
1557               /* Allocate next image structure. */
1558               if ((image_info->ping != MagickFalse) &&
1559                   (image_info->number_scenes != 0))
1560                 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1561                   goto Finish;
1562               AcquireNextImage(image_info,image,exception);
1563               image->depth=8;
1564               if (image->next == (Image *) NULL)
1565                 goto Finish;
1566               image=SyncNextImageInList(image);
1567               image->columns=image->rows=0;
1568               image->colors=0;
1569               break;
1570 
1571             case 0x12:  /* Postscript WPG2*/
1572         i=ReadBlobLSBShort(image);
1573               if (Rec2.RecordLength > (unsigned int) i)
1574                 {
1575                   image=ExtractPostscript(image,image_info,
1576                     TellBlob(image)+i,    /*skip PS header in the wpg2*/
1577                     (ssize_t) (Rec2.RecordLength-i-2),exception);
1578                   if (image == NULL)
1579                     ThrowReaderException(CorruptImageError,
1580                       "ImproperImageHeader");
1581                 }
1582               break;
1583 
1584       case 0x1B:          /*bitmap rectangle*/
1585               WPG2Flags = LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM);
1586               (void) WPG2Flags;
1587               break;
1588             }
1589         }
1590 
1591       break;
1592 
1593     default:
1594       {
1595          ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
1596       }
1597    }
1598 
1599  Finish:
1600   (void) CloseBlob(image);
1601 
1602   {
1603     Image
1604       *p;
1605 
1606     ssize_t
1607       scene=0;
1608 
1609     /*
1610       Rewind list, removing any empty images while rewinding.
1611     */
1612     p=image;
1613     image=NULL;
1614     while (p != (Image *) NULL)
1615       {
1616         Image *tmp=p;
1617         if ((p->rows == 0) || (p->columns == 0)) {
1618           p=p->previous;
1619           DeleteImageFromList(&tmp);
1620         } else {
1621           image=p;
1622           p=p->previous;
1623         }
1624       }
1625     /*
1626       Fix scene numbers.
1627     */
1628     for (p=image; p != (Image *) NULL; p=p->next)
1629       p->scene=(size_t) scene++;
1630   }
1631   if (image == (Image *) NULL)
1632     ThrowReaderException(CorruptImageError,
1633       "ImageFileDoesNotContainAnyImageData");
1634   return(image);
1635 }
1636 
1637 /*
1638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639 %                                                                             %
1640 %                                                                             %
1641 %                                                                             %
1642 %   R e g i s t e r W P G I m a g e                                           %
1643 %                                                                             %
1644 %                                                                             %
1645 %                                                                             %
1646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1647 %
1648 %  Method RegisterWPGImage adds attributes for the WPG image format to
1649 %  the list of supported formats.  The attributes include the image format
1650 %  tag, a method to read and/or write the format, whether the format
1651 %  supports the saving of more than one frame to the same file or blob,
1652 %  whether the format supports native in-memory I/O, and a brief
1653 %  description of the format.
1654 %
1655 %  The format of the RegisterWPGImage method is:
1656 %
1657 %      size_t RegisterWPGImage(void)
1658 %
1659 */
RegisterWPGImage(void)1660 ModuleExport size_t RegisterWPGImage(void)
1661 {
1662   MagickInfo
1663     *entry;
1664 
1665   entry=AcquireMagickInfo("WPG","WPG","Word Perfect Graphics");
1666   entry->decoder=(DecodeImageHandler *) ReadWPGImage;
1667   entry->magick=(IsImageFormatHandler *) IsWPG;
1668   entry->flags|=CoderDecoderSeekableStreamFlag;
1669   (void) RegisterMagickInfo(entry);
1670   return(MagickImageCoderSignature);
1671 }
1672 
1673 /*
1674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675 %                                                                             %
1676 %                                                                             %
1677 %                                                                             %
1678 %   U n r e g i s t e r W P G I m a g e                                       %
1679 %                                                                             %
1680 %                                                                             %
1681 %                                                                             %
1682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1683 %
1684 %  Method UnregisterWPGImage removes format registrations made by the
1685 %  WPG module from the list of supported formats.
1686 %
1687 %  The format of the UnregisterWPGImage method is:
1688 %
1689 %      UnregisterWPGImage(void)
1690 %
1691 */
UnregisterWPGImage(void)1692 ModuleExport void UnregisterWPGImage(void)
1693 {
1694   (void) UnregisterMagickInfo("WPG");
1695 }
1696