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