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   if(Precision==0)
713     {(void) ReadBlobLSBShort(image);}  /*ObjectID*/
714   else
715     {(void) ReadBlobLSBLong(image);}  /*ObjectID (Double precision)*/
716   }
717  if(Flags & ROT)
718   {
719   x=ReadBlobLSBLong(image);  /*Rot Angle*/
720   if(Angle) *Angle=x/65536.0;
721   }
722  if(Flags & (ROT|SCL))
723   {
724   x=ReadBlobLSBLong(image);  /*Sx*cos()*/
725   (*CTM)[0][0] = (float)x/0x10000;
726   x=ReadBlobLSBLong(image);  /*Sy*cos()*/
727   (*CTM)[1][1] = (float)x/0x10000;
728   }
729  if(Flags & (ROT|SKW))
730   {
731   x=ReadBlobLSBLong(image);       /*Kx*sin()*/
732   (*CTM)[1][0] = (float)x/0x10000;
733   x=ReadBlobLSBLong(image);       /*Ky*sin()*/
734   (*CTM)[0][1] = (float)x/0x10000;
735   }
736  if(Flags & TRN)
737   {
738   x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image);  /*Tx*/
739         if(x>=0) (*CTM)[0][2] = (float)x+(float)DenX/0x10000;
740             else (*CTM)[0][2] = (float)x-(float)DenX/0x10000;
741   x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image);  /*Ty*/
742   (*CTM)[1][2]=(float)x + ((x>=0)?1:-1)*(float)DenX/0x10000;
743         if(x>=0) (*CTM)[1][2] = (float)x+(float)DenX/0x10000;
744             else (*CTM)[1][2] = (float)x-(float)DenX/0x10000;
745   }
746  if(Flags & TPR)
747   {
748   x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image);  /*Px*/
749   (*CTM)[2][0] = x + (float)DenX/0x10000;;
750   x=ReadBlobLSBShort(image);  DenX=ReadBlobLSBShort(image); /*Py*/
751   (*CTM)[2][1] = x + (float)DenX/0x10000;
752   }
753  return(Flags);
754 }
755 
756 
ExtractPostscript(Image * image,const ImageInfo * image_info,MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo * exception)757 static Image *ExtractPostscript(Image *image,const ImageInfo *image_info,
758   MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo *exception)
759 {
760   char
761     postscript_file[MagickPathExtent];
762 
763   const MagicInfo
764     *magic_info;
765 
766   FILE
767     *ps_file;
768 
769   int
770     c;
771 
772   ImageInfo
773     *clone_info;
774 
775   Image
776     *image2;
777 
778   MagickBooleanType
779     status;
780 
781   unsigned char
782     magick[2*MagickPathExtent];
783 
784   ssize_t
785     count;
786 
787   if ((clone_info=CloneImageInfo(image_info)) == NULL)
788     return(image);
789   clone_info->blob=(void *) NULL;
790   clone_info->length=0;
791   status=MagickFalse;
792 
793   /* Obtain temporary file */
794   (void) AcquireUniqueFilename(postscript_file);
795   ps_file=fopen_utf8(postscript_file,"wb");
796   if (ps_file == (FILE *) NULL)
797     goto FINISH;
798 
799   /* Copy postscript to temporary file */
800   if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
801     {
802       (void) fclose(ps_file);
803       ThrowException(exception,CorruptImageError,"ImproperImageHeader",
804         image->filename);
805       goto FINISH_UNL;
806     }
807   count=ReadBlob(image, 2*MagickPathExtent, magick);
808   if (count < 1)
809     {
810       (void) fclose(ps_file);
811       ThrowException(exception,CorruptImageError,"ImproperImageHeader",
812         image->filename);
813       goto FINISH_UNL;
814     }
815 
816   if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
817     {
818       (void) fclose(ps_file);
819       ThrowException(exception,CorruptImageError,"ImproperImageHeader",
820         image->filename);
821       goto FINISH_UNL;
822     }
823   while (PS_Size-- > 0)
824   {
825     c=ReadBlobByte(image);
826     if (c == EOF)
827       {
828         (void) fclose(ps_file);
829         ThrowException(exception,CorruptImageError,"ImproperImageHeader",
830           image->filename);
831         goto FINISH_UNL;
832       }
833     (void) fputc(c,ps_file);
834   }
835   (void) fclose(ps_file);
836 
837     /* Detect file format - Check magic.mgk configuration file. */
838   magic_info=GetMagicInfo(magick,count,exception);
839   if(magic_info == (const MagicInfo *) NULL) goto FINISH_UNL;
840   /*     printf("Detected:%s  \n",magic_info->name); */
841   if(exception->severity != UndefinedException) goto FINISH_UNL;
842   (void) CopyMagickString(clone_info->magick,GetMagicName(magic_info),
843     MagickPathExtent);
844   if (LocaleCompare(clone_info->magick,"PFB") != 0)
845     {
846       ThrowException(exception,CorruptImageError,"ImproperImageHeader",
847         image->filename);
848       goto FINISH_UNL;
849     }
850 
851     /* Read nested image */
852   /*FormatString(clone_info->filename,"%s:%s",magic_info->name,postscript_file);*/
853   FormatLocaleString(clone_info->filename,MagickPathExtent,"%.1024s:%.1024s",
854     clone_info->magick,postscript_file);
855   image2=ReadImage(clone_info,exception);
856 
857   if (!image2)
858     goto FINISH_UNL;
859   if(exception->severity>=ErrorException)
860   {
861     CloseBlob(image2);
862     DestroyImageList(image2);
863     goto FINISH_UNL;
864   }
865 
866   {
867     Image
868       *p;
869 
870     /*
871       Replace current image with new image while copying base image attributes.
872     */
873     p=image2;
874     do
875     {
876       (void) CopyMagickString(p->filename,image->filename,MagickPathExtent);
877       (void) CopyMagickString(p->magick_filename,image->magick_filename,
878         MagickPathExtent);
879       (void) CopyMagickString(p->magick,image->magick,MagickPathExtent);
880       if ((p->rows == 0) || (p->columns == 0))
881         {
882           DeleteImageFromList(&p);
883           if (p == (Image *) NULL)
884             {
885               image2=(Image *) NULL;
886               goto FINISH_UNL;
887             }
888         }
889       else
890         {
891           DestroyBlob(p);
892           p->blob=ReferenceBlob(image->blob);
893           p=p->next;
894         }
895     } while (p != (Image *) NULL);
896   }
897 
898   if ((image->rows == 0 || image->columns == 0) &&
899       (image->previous != NULL || image->next != NULL))
900   {
901     DeleteImageFromList(&image);
902   }
903 
904   AppendImageToList(&image,image2);
905   while (image->next != NULL)
906     image=image->next;
907   status=MagickTrue;
908 
909  FINISH_UNL:
910   (void) RelinquishUniqueFileResource(postscript_file);
911  FINISH:
912   DestroyImageInfo(clone_info);
913   if (status == MagickFalse)
914     return(DestroyImageList(image));
915   return(image);
916 }
917 
918 /*
919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
920 %                                                                             %
921 %                                                                             %
922 %                                                                             %
923 %   R e a d W P G I m a g e                                                   %
924 %                                                                             %
925 %                                                                             %
926 %                                                                             %
927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
928 %
929 %  Method ReadWPGImage reads an WPG X image file and returns it.  It
930 %  allocates the memory necessary for the new Image structure and returns a
931 %  pointer to the new image.
932 %
933 %  The format of the ReadWPGImage method is:
934 %
935 %    Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception)
936 %
937 %  A description of each parameter follows:
938 %
939 %    o image:  Method ReadWPGImage returns a pointer to the image after
940 %      reading. A null image is returned if there is a memory shortage or if
941 %      the image cannot be read.
942 %
943 %    o image_info: Specifies a pointer to a ImageInfo structure.
944 %
945 %    o exception: return any errors or warnings in this structure.
946 %
947 */
ReadWPGImage(const ImageInfo * image_info,ExceptionInfo * exception)948 static Image *ReadWPGImage(const ImageInfo *image_info,
949   ExceptionInfo *exception)
950 {
951   typedef struct
952   {
953     size_t FileId;
954     MagickOffsetType DataOffset;
955     unsigned int ProductType;
956     unsigned int FileType;
957     unsigned char MajorVersion;
958     unsigned char MinorVersion;
959     unsigned int EncryptKey;
960     unsigned int Reserved;
961   } WPGHeader;
962 
963   typedef struct
964   {
965     unsigned char RecType;
966     size_t RecordLength;
967   } WPGRecord;
968 
969   typedef struct
970   {
971     unsigned char Class;
972     unsigned char RecType;
973     size_t Extension;
974     size_t RecordLength;
975   } WPG2Record;
976 
977   typedef struct
978   {
979     unsigned  HorizontalUnits;
980     unsigned  VerticalUnits;
981     unsigned char PosSizePrecision;
982   } WPG2Start;
983 
984   typedef struct
985   {
986     unsigned int Width;
987     unsigned int Height;
988     unsigned int Depth;
989     unsigned int HorzRes;
990     unsigned int VertRes;
991   } WPGBitmapType1;
992 
993   typedef struct
994   {
995     unsigned int Width;
996     unsigned int Height;
997     unsigned char Depth;
998     unsigned char Compression;
999   } WPG2BitmapType1;
1000 
1001   typedef struct
1002   {
1003     unsigned int RotAngle;
1004     unsigned int LowLeftX;
1005     unsigned int LowLeftY;
1006     unsigned int UpRightX;
1007     unsigned int UpRightY;
1008     unsigned int Width;
1009     unsigned int Height;
1010     unsigned int Depth;
1011     unsigned int HorzRes;
1012     unsigned int VertRes;
1013   } WPGBitmapType2;
1014 
1015   typedef struct
1016   {
1017     unsigned int StartIndex;
1018     unsigned int NumOfEntries;
1019   } WPGColorMapRec;
1020 
1021   /*
1022   typedef struct {
1023     size_t PS_unknown1;
1024     unsigned int PS_unknown2;
1025     unsigned int PS_unknown3;
1026   } WPGPSl1Record;
1027   */
1028 
1029   Image
1030     *image;
1031 
1032   unsigned int
1033     status;
1034 
1035   WPGHeader
1036     Header;
1037 
1038   WPGRecord
1039     Rec;
1040 
1041   WPG2Record
1042     Rec2;
1043 
1044   WPG2Start StartWPG;
1045 
1046   WPGBitmapType1
1047     BitmapHeader1;
1048 
1049   WPG2BitmapType1
1050     Bitmap2Header1;
1051 
1052   WPGBitmapType2
1053     BitmapHeader2;
1054 
1055   WPGColorMapRec
1056     WPG_Palette;
1057 
1058   int
1059     i,
1060     bpp,
1061     WPG2Flags;
1062 
1063   ssize_t
1064     ldblk;
1065 
1066   size_t
1067     one;
1068 
1069   unsigned char
1070     *BImgBuff;
1071 
1072   tCTM CTM;         /*current transform matrix*/
1073 
1074   /*
1075     Open image file.
1076   */
1077   assert(image_info != (const ImageInfo *) NULL);
1078   assert(image_info->signature == MagickCoreSignature);
1079   assert(exception != (ExceptionInfo *) NULL);
1080   assert(exception->signature == MagickCoreSignature);
1081   one=1;
1082   image=AcquireImage(image_info,exception);
1083   image->depth=8;
1084   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1085   if (status == MagickFalse)
1086     {
1087       image=DestroyImageList(image);
1088       return((Image *) NULL);
1089     }
1090   /*
1091     Read WPG image.
1092   */
1093   Header.FileId=ReadBlobLSBLong(image);
1094   Header.DataOffset=(MagickOffsetType) ReadBlobLSBLong(image);
1095   Header.ProductType=ReadBlobLSBShort(image);
1096   Header.FileType=ReadBlobLSBShort(image);
1097   Header.MajorVersion=ReadBlobByte(image);
1098   Header.MinorVersion=ReadBlobByte(image);
1099   Header.EncryptKey=ReadBlobLSBShort(image);
1100   Header.Reserved=ReadBlobLSBShort(image);
1101 
1102   if (Header.FileId!=0x435057FF || (Header.ProductType>>8)!=0x16)
1103     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1104   if (Header.EncryptKey!=0)
1105     ThrowReaderException(CoderError,"EncryptedWPGImageFileNotSupported");
1106 
1107   image->columns = 1;
1108   image->rows = 1;
1109   image->colors = 0;
1110   image->storage_class=DirectClass;
1111   (void) ResetImagePixels(image,exception);
1112   bpp=0;
1113   BitmapHeader2.RotAngle=0;
1114   Rec2.RecordLength=0;
1115 
1116   switch(Header.FileType)
1117     {
1118     case 1:     /* WPG level 1 */
1119       while(!EOFBlob(image)) /* object parser loop */
1120         {
1121           if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
1122             break;
1123           if(EOFBlob(image))
1124             break;
1125 
1126           Rec.RecType=(i=ReadBlobByte(image));
1127           if(i==EOF)
1128             break;
1129           Rd_WP_DWORD(image,&Rec.RecordLength);
1130           if (Rec.RecordLength > GetBlobSize(image))
1131             ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1132           if(EOFBlob(image))
1133             break;
1134 
1135           Header.DataOffset=TellBlob(image)+Rec.RecordLength;
1136 
1137           switch(Rec.RecType)
1138             {
1139             case 0x0B: /* bitmap type 1 */
1140               BitmapHeader1.Width=ReadBlobLSBShort(image);
1141               BitmapHeader1.Height=ReadBlobLSBShort(image);
1142               if ((BitmapHeader1.Width == 0) || (BitmapHeader1.Height == 0))
1143                 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1144               BitmapHeader1.Depth=ReadBlobLSBShort(image);
1145               BitmapHeader1.HorzRes=ReadBlobLSBShort(image);
1146               BitmapHeader1.VertRes=ReadBlobLSBShort(image);
1147 
1148               if(BitmapHeader1.HorzRes && BitmapHeader1.VertRes)
1149                 {
1150                   image->units=PixelsPerCentimeterResolution;
1151                   image->resolution.x=BitmapHeader1.HorzRes/470.0;
1152                   image->resolution.y=BitmapHeader1.VertRes/470.0;
1153                 }
1154               image->columns=BitmapHeader1.Width;
1155               image->rows=BitmapHeader1.Height;
1156               bpp=BitmapHeader1.Depth;
1157 
1158               goto UnpackRaster;
1159 
1160             case 0x0E:  /*Color palette */
1161               WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1162               WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1163               if ((WPG_Palette.NumOfEntries-WPG_Palette.StartIndex) >
1164                   (Rec2.RecordLength-2-2)/3)
1165                 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1166               if (WPG_Palette.StartIndex > WPG_Palette.NumOfEntries)
1167                 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1168               image->colors=WPG_Palette.NumOfEntries;
1169               if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
1170                 goto NoMemory;
1171               for (i=WPG_Palette.StartIndex;
1172                    i < (int)WPG_Palette.NumOfEntries; i++)
1173                 {
1174                   image->colormap[i].red=ScaleCharToQuantum((unsigned char)
1175                     ReadBlobByte(image));
1176                   image->colormap[i].green=ScaleCharToQuantum((unsigned char)
1177                     ReadBlobByte(image));
1178                   image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
1179                     ReadBlobByte(image));
1180                 }
1181               break;
1182 
1183             case 0x11:  /* Start PS l1 */
1184               if (Rec.RecordLength > 8)
1185                 {
1186                   image=ExtractPostscript(image,image_info,
1187                     TellBlob(image)+8,   /* skip PS header in the wpg */
1188                     (ssize_t) Rec.RecordLength-8,exception);
1189                   if (image == NULL)
1190                     ThrowReaderException(CorruptImageError,
1191                       "ImproperImageHeader");
1192                 }
1193               break;
1194 
1195             case 0x14:  /* bitmap type 2 */
1196               BitmapHeader2.RotAngle=ReadBlobLSBShort(image);
1197               BitmapHeader2.LowLeftX=ReadBlobLSBShort(image);
1198               BitmapHeader2.LowLeftY=ReadBlobLSBShort(image);
1199               BitmapHeader2.UpRightX=ReadBlobLSBShort(image);
1200               BitmapHeader2.UpRightY=ReadBlobLSBShort(image);
1201               BitmapHeader2.Width=ReadBlobLSBShort(image);
1202               BitmapHeader2.Height=ReadBlobLSBShort(image);
1203               if ((BitmapHeader2.Width == 0) || (BitmapHeader2.Height == 0))
1204                 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1205               BitmapHeader2.Depth=ReadBlobLSBShort(image);
1206               BitmapHeader2.HorzRes=ReadBlobLSBShort(image);
1207               BitmapHeader2.VertRes=ReadBlobLSBShort(image);
1208 
1209               image->units=PixelsPerCentimeterResolution;
1210               image->page.width=(unsigned int)
1211                 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightX)/470.0);
1212               image->page.height=(unsigned int)
1213                 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightY)/470.0);
1214               image->page.x=(int) (BitmapHeader2.LowLeftX/470.0);
1215               image->page.y=(int) (BitmapHeader2.LowLeftX/470.0);
1216               if(BitmapHeader2.HorzRes && BitmapHeader2.VertRes)
1217                 {
1218                   image->resolution.x=BitmapHeader2.HorzRes/470.0;
1219                   image->resolution.y=BitmapHeader2.VertRes/470.0;
1220                 }
1221               image->columns=BitmapHeader2.Width;
1222               image->rows=BitmapHeader2.Height;
1223               bpp=BitmapHeader2.Depth;
1224 
1225             UnpackRaster:
1226               status=SetImageExtent(image,image->columns,image->rows,exception);
1227               if (status == MagickFalse)
1228                 break;
1229               (void) ResetImagePixels(image,exception);
1230               if ((image->storage_class != PseudoClass) && (bpp < 24))
1231                 {
1232                   image->colors=one << bpp;
1233                   if (image->colors > GetBlobSize(image))
1234                     ThrowReaderException(CorruptImageError,
1235                       "InsufficientImageDataInFile");
1236                   if (!AcquireImageColormap(image,image->colors,exception))
1237                     {
1238                     NoMemory:
1239                       ThrowReaderException(ResourceLimitError,
1240                         "MemoryAllocationFailed");
1241                     }
1242                   /* printf("Load default colormap \n"); */
1243                   for (i=0; (i < (int) image->colors) && (i < 256); i++)
1244                     {
1245                       image->colormap[i].red=ScaleCharToQuantum(WPG1_Palette[i].Red);
1246                       image->colormap[i].green=ScaleCharToQuantum(WPG1_Palette[i].Green);
1247                       image->colormap[i].blue=ScaleCharToQuantum(WPG1_Palette[i].Blue);
1248                       image->colormap[i].alpha=OpaqueAlpha;
1249                     }
1250                 }
1251               else
1252                 {
1253                   if (bpp < 24)
1254                   if ( (image->colors < (one << bpp)) && (bpp != 24) )
1255                     {
1256                       PixelInfo
1257                         *colormap;
1258 
1259                       size_t
1260                         colors;
1261 
1262                       colormap=image->colormap;
1263                       colors=image->colors;
1264                       image->colormap=(PixelInfo *) NULL;
1265                       if (AcquireImageColormap(image,one << bpp,exception) == MagickFalse)
1266                         {
1267                           colormap=(PixelInfo *)
1268                             RelinquishMagickMemory(colormap);
1269                           goto NoMemory;
1270                         }
1271                       (void) memcpy(image->colormap,colormap,MagickMin(
1272                         image->colors,colors)*sizeof(*image->colormap));
1273                       colormap=(PixelInfo *)
1274                         RelinquishMagickMemory(colormap);
1275                     }
1276                 }
1277 
1278               if ((bpp == 1) && (image->colors > 1))
1279                 {
1280                   if(image->colormap[0].red==0 &&
1281                      image->colormap[0].green==0 &&
1282                      image->colormap[0].blue==0 &&
1283                      image->colormap[1].red==0 &&
1284                      image->colormap[1].green==0 &&
1285                      image->colormap[1].blue==0)
1286                     {  /* fix crippled monochrome palette */
1287                       image->colormap[1].red =
1288                         image->colormap[1].green =
1289                         image->colormap[1].blue = QuantumRange;
1290                       image->colormap[1].alpha=OpaqueAlpha;
1291                     }
1292                 }
1293               if(!image_info->ping)
1294                 if(UnpackWPGRaster(image,bpp,exception) < 0)
1295                   /* The raster cannot be unpacked */
1296                   {
1297                   DecompressionFailed:
1298                     ThrowReaderException(CoderError,"UnableToDecompressImage");
1299                   }
1300 
1301               if(Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping)
1302                 {
1303                   /* flop command */
1304                   if(BitmapHeader2.RotAngle & 0x8000)
1305                     {
1306                       Image
1307                         *flop_image;
1308 
1309                       flop_image = FlopImage(image, exception);
1310                       if (flop_image != (Image *) NULL) {
1311                         DuplicateBlob(flop_image,image);
1312                         ReplaceImageInList(&image,flop_image);
1313                       }
1314                     }
1315                   /* flip command */
1316                   if(BitmapHeader2.RotAngle & 0x2000)
1317                     {
1318                       Image
1319                         *flip_image;
1320 
1321                       flip_image = FlipImage(image, exception);
1322                       if (flip_image != (Image *) NULL) {
1323                         DuplicateBlob(flip_image,image);
1324                         ReplaceImageInList(&image,flip_image);
1325                       }
1326                     }
1327                   /* rotate command */
1328                   if(BitmapHeader2.RotAngle & 0x0FFF)
1329                     {
1330                       Image
1331                         *rotate_image;
1332 
1333                       rotate_image=RotateImage(image,(BitmapHeader2.RotAngle &
1334                         0x0FFF), exception);
1335                       if (rotate_image != (Image *) NULL) {
1336                         DuplicateBlob(rotate_image,image);
1337                         ReplaceImageInList(&image,rotate_image);
1338                       }
1339                     }
1340                 }
1341 
1342               /* Allocate next image structure. */
1343               if ((image_info->ping != MagickFalse) &&
1344                   (image_info->number_scenes != 0))
1345                 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1346                   goto Finish;
1347               AcquireNextImage(image_info,image,exception);
1348               image->depth=8;
1349               if (image->next == (Image *) NULL)
1350                 goto Finish;
1351               image=SyncNextImageInList(image);
1352               image->columns=image->rows=0;
1353               image->colors=0;
1354               break;
1355 
1356             case 0x1B:  /* Postscript l2 */
1357               if (Rec.RecordLength>0x3C)
1358                 {
1359                   image=ExtractPostscript(image,image_info,
1360                     TellBlob(image)+0x3C,   /* skip PS l2 header in the wpg */
1361                     (ssize_t) Rec.RecordLength-0x3C,exception);
1362                   if (image == NULL)
1363                     ThrowReaderException(CorruptImageError,
1364                       "ImproperImageHeader");
1365                 }
1366               break;
1367             }
1368         }
1369       break;
1370 
1371     case 2:  /* WPG level 2 */
1372       (void) memset(CTM,0,sizeof(CTM));
1373       StartWPG.PosSizePrecision = 0;
1374       while(!EOFBlob(image)) /* object parser loop */
1375         {
1376           if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
1377             break;
1378           if (EOFBlob(image))
1379             break;
1380 
1381           Rec2.Class=(i=ReadBlobByte(image));
1382           if(i==EOF)
1383             break;
1384           Rec2.RecType=(i=ReadBlobByte(image));
1385           if(i==EOF)
1386             break;
1387           Rd_WP_DWORD(image,&Rec2.Extension);
1388           Rd_WP_DWORD(image,&Rec2.RecordLength);
1389           if(EOFBlob(image))
1390             break;
1391 
1392           Header.DataOffset=TellBlob(image)+Rec2.RecordLength;
1393 
1394           switch(Rec2.RecType)
1395             {
1396       case 1:
1397               StartWPG.HorizontalUnits=ReadBlobLSBShort(image);
1398               StartWPG.VerticalUnits=ReadBlobLSBShort(image);
1399               StartWPG.PosSizePrecision=ReadBlobByte(image);
1400               break;
1401             case 0x0C:    /* Color palette */
1402               WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1403               WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1404               if ((WPG_Palette.NumOfEntries-WPG_Palette.StartIndex) >
1405                   (Rec2.RecordLength-2-2) / 3)
1406                 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1407               if (WPG_Palette.StartIndex >= WPG_Palette.NumOfEntries)
1408                 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1409               image->colors=WPG_Palette.NumOfEntries;
1410               if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
1411                 ThrowReaderException(ResourceLimitError,
1412                   "MemoryAllocationFailed");
1413               for (i=WPG_Palette.StartIndex;
1414                    i < (int)WPG_Palette.NumOfEntries; i++)
1415                 {
1416                   image->colormap[i].red=ScaleCharToQuantum((char)
1417                     ReadBlobByte(image));
1418                   image->colormap[i].green=ScaleCharToQuantum((char)
1419                     ReadBlobByte(image));
1420                   image->colormap[i].blue=ScaleCharToQuantum((char)
1421                     ReadBlobByte(image));
1422                   image->colormap[i].alpha=OpaqueAlpha;
1423                   (void) ReadBlobByte(image);   /*Opacity??*/
1424                 }
1425               break;
1426             case 0x0E:
1427               Bitmap2Header1.Width=ReadBlobLSBShort(image);
1428               Bitmap2Header1.Height=ReadBlobLSBShort(image);
1429               if ((Bitmap2Header1.Width == 0) || (Bitmap2Header1.Height == 0))
1430                 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1431               Bitmap2Header1.Depth=ReadBlobByte(image);
1432               Bitmap2Header1.Compression=ReadBlobByte(image);
1433 
1434               if(Bitmap2Header1.Compression > 1)
1435                 continue; /*Unknown compression method */
1436               switch(Bitmap2Header1.Depth)
1437                 {
1438                 case 1:
1439                   bpp=1;
1440                   break;
1441                 case 2:
1442                   bpp=2;
1443                   break;
1444                 case 3:
1445                   bpp=4;
1446                   break;
1447                 case 4:
1448                   bpp=8;
1449                   break;
1450                 case 8:
1451                   bpp=24;
1452                   break;
1453                 default:
1454                   continue;  /*Ignore raster with unknown depth*/
1455                 }
1456               image->columns=Bitmap2Header1.Width;
1457               image->rows=Bitmap2Header1.Height;
1458               if (image_info->ping != MagickFalse)
1459                 return(image);
1460               status=SetImageExtent(image,image->columns,image->rows,exception);
1461               if (status != MagickFalse)
1462                 status=ResetImagePixels(image,exception);
1463               if (status == MagickFalse)
1464                 break;
1465               if ((image->colors == 0) && (bpp != 24))
1466                 {
1467                   image->colors=one << bpp;
1468                   if (!AcquireImageColormap(image,image->colors,exception))
1469                     goto NoMemory;
1470                 }
1471               else
1472                 {
1473                   if(bpp < 24)
1474                     if( image->colors<(one << bpp) && bpp!=24 )
1475                       image->colormap=(PixelInfo *) ResizeQuantumMemory(
1476                        image->colormap,(size_t) (one << bpp),
1477                        sizeof(*image->colormap));
1478                 }
1479 
1480 
1481               switch(Bitmap2Header1.Compression)
1482                 {
1483                 case 0:    /*Uncompressed raster*/
1484                   {
1485                     ldblk=(ssize_t) ((bpp*image->columns+7)/8);
1486                     BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t)
1487                       ldblk+1,sizeof(*BImgBuff));
1488                     if (BImgBuff == (unsigned char *) NULL)
1489                       goto NoMemory;
1490                     for (i=0; i< (ssize_t) image->rows; i++)
1491                     {
1492                       ssize_t
1493                         count;
1494 
1495                       count=ReadBlob(image,(size_t) ldblk,BImgBuff);
1496                       if (count != ldblk)
1497                         break;
1498                       if (InsertRow(image,BImgBuff,i,bpp,exception) == MagickFalse)
1499                         break;
1500                     }
1501                     BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
1502                     if (i < (ssize_t) image->rows)
1503                       goto DecompressionFailed;
1504                     break;
1505                   }
1506                 case 1:    /*RLE for WPG2 */
1507                   {
1508                     if( UnpackWPG2Raster(image,bpp,exception) < 0)
1509                       goto DecompressionFailed;
1510                     break;
1511                   }
1512                 }
1513 
1514               if(CTM[0][0]<0 && !image_info->ping)
1515                 {    /*?? RotAngle=360-RotAngle;*/
1516                   Image
1517                     *flop_image;
1518 
1519                   flop_image = FlopImage(image, exception);
1520                   if (flop_image != (Image *) NULL) {
1521                     DuplicateBlob(flop_image,image);
1522                     ReplaceImageInList(&image,flop_image);
1523                   }
1524                   /* Try to change CTM according to Flip - I am not sure, must be checked.
1525                      Tx(0,0)=-1;      Tx(1,0)=0;   Tx(2,0)=0;
1526                      Tx(0,1)= 0;      Tx(1,1)=1;   Tx(2,1)=0;
1527                      Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
1528                      Tx(1,2)=0;   Tx(2,2)=1; */
1529                 }
1530               if(CTM[1][1]<0 && !image_info->ping)
1531                 {    /*?? RotAngle=360-RotAngle;*/
1532                   Image
1533                     *flip_image;
1534 
1535                    flip_image = FlipImage(image, exception);
1536                    if (flip_image != (Image *) NULL) {
1537                      DuplicateBlob(flip_image,image);
1538                      ReplaceImageInList(&image,flip_image);
1539                     }
1540                   /* Try to change CTM according to Flip - I am not sure, must be checked.
1541                      float_matrix Tx(3,3);
1542                      Tx(0,0)= 1;   Tx(1,0)= 0;   Tx(2,0)=0;
1543                      Tx(0,1)= 0;   Tx(1,1)=-1;   Tx(2,1)=0;
1544                      Tx(0,2)= 0;   Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
1545                      Tx(2,2)=1; */
1546               }
1547 
1548 
1549               /* Allocate next image structure. */
1550               if ((image_info->ping != MagickFalse) &&
1551                   (image_info->number_scenes != 0))
1552                 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1553                   goto Finish;
1554               AcquireNextImage(image_info,image,exception);
1555               image->depth=8;
1556               if (image->next == (Image *) NULL)
1557                 goto Finish;
1558               image=SyncNextImageInList(image);
1559               image->columns=image->rows=0;
1560               image->colors=0;
1561               break;
1562 
1563             case 0x12:  /* Postscript WPG2*/
1564         i=ReadBlobLSBShort(image);
1565               if (Rec2.RecordLength > (unsigned int) i)
1566                 {
1567                   image=ExtractPostscript(image,image_info,
1568                     TellBlob(image)+i,    /*skip PS header in the wpg2*/
1569                     (ssize_t) (Rec2.RecordLength-i-2),exception);
1570                   if (image == NULL)
1571                     ThrowReaderException(CorruptImageError,
1572                       "ImproperImageHeader");
1573                 }
1574               break;
1575 
1576       case 0x1B:          /*bitmap rectangle*/
1577               WPG2Flags = LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM);
1578               (void) WPG2Flags;
1579               break;
1580             }
1581         }
1582 
1583       break;
1584 
1585     default:
1586       {
1587          ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
1588       }
1589    }
1590 
1591  Finish:
1592   (void) CloseBlob(image);
1593 
1594   {
1595     Image
1596       *p;
1597 
1598     ssize_t
1599       scene=0;
1600 
1601     /*
1602       Rewind list, removing any empty images while rewinding.
1603     */
1604     p=image;
1605     image=NULL;
1606     while (p != (Image *) NULL)
1607       {
1608         Image *tmp=p;
1609         if ((p->rows == 0) || (p->columns == 0)) {
1610           p=p->previous;
1611           DeleteImageFromList(&tmp);
1612         } else {
1613           image=p;
1614           p=p->previous;
1615         }
1616       }
1617     /*
1618       Fix scene numbers.
1619     */
1620     for (p=image; p != (Image *) NULL; p=p->next)
1621       p->scene=(size_t) scene++;
1622   }
1623   if (image == (Image *) NULL)
1624     ThrowReaderException(CorruptImageError,
1625       "ImageFileDoesNotContainAnyImageData");
1626   return(image);
1627 }
1628 
1629 /*
1630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631 %                                                                             %
1632 %                                                                             %
1633 %                                                                             %
1634 %   R e g i s t e r W P G I m a g e                                           %
1635 %                                                                             %
1636 %                                                                             %
1637 %                                                                             %
1638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639 %
1640 %  Method RegisterWPGImage adds attributes for the WPG image format to
1641 %  the list of supported formats.  The attributes include the image format
1642 %  tag, a method to read and/or write the format, whether the format
1643 %  supports the saving of more than one frame to the same file or blob,
1644 %  whether the format supports native in-memory I/O, and a brief
1645 %  description of the format.
1646 %
1647 %  The format of the RegisterWPGImage method is:
1648 %
1649 %      size_t RegisterWPGImage(void)
1650 %
1651 */
RegisterWPGImage(void)1652 ModuleExport size_t RegisterWPGImage(void)
1653 {
1654   MagickInfo
1655     *entry;
1656 
1657   entry=AcquireMagickInfo("WPG","WPG","Word Perfect Graphics");
1658   entry->decoder=(DecodeImageHandler *) ReadWPGImage;
1659   entry->magick=(IsImageFormatHandler *) IsWPG;
1660   entry->flags|=CoderDecoderSeekableStreamFlag;
1661   (void) RegisterMagickInfo(entry);
1662   return(MagickImageCoderSignature);
1663 }
1664 
1665 /*
1666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1667 %                                                                             %
1668 %                                                                             %
1669 %                                                                             %
1670 %   U n r e g i s t e r W P G I m a g e                                       %
1671 %                                                                             %
1672 %                                                                             %
1673 %                                                                             %
1674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675 %
1676 %  Method UnregisterWPGImage removes format registrations made by the
1677 %  WPG module from the list of supported formats.
1678 %
1679 %  The format of the UnregisterWPGImage method is:
1680 %
1681 %      UnregisterWPGImage(void)
1682 %
1683 */
UnregisterWPGImage(void)1684 ModuleExport void UnregisterWPGImage(void)
1685 {
1686   (void) UnregisterMagickInfo("WPG");
1687 }
1688