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