Coverage Report

Created: 2026-01-20 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/wpg.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2025 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 - 2023                               %
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/quantize.h"
50
#include "magick/utility.h"
51
#include "magick/static.h"
52

53
54
typedef struct
55
{
56
  unsigned char Red;
57
  unsigned char Blue;
58
  unsigned char Green;
59
} RGB_Record;
60
61
/* Default palette for WPG level 1 */
62
static const RGB_Record WPG1_Palette[256] =
63
  {
64
    {  0,  0,  0},          {  0,  0,168},
65
    {  0,168,  0},          {  0,168,168},
66
    {168,  0,  0},          {168,  0,168},
67
    {168, 84,  0},          {168,168,168},
68
    { 84, 84, 84},          { 84, 84,252},
69
    { 84,252, 84},          { 84,252,252},
70
    {252, 84, 84},          {252, 84,252},
71
    {252,252, 84},          {252,252,252},  /*16*/
72
    {  0,  0,  0},          { 20, 20, 20},
73
    { 32, 32, 32},          { 44, 44, 44},
74
    { 56, 56, 56},          { 68, 68, 68},
75
    { 80, 80, 80},          { 96, 96, 96},
76
    {112,112,112},          {128,128,128},
77
    {144,144,144},          {160,160,160},
78
    {180,180,180},          {200,200,200},
79
    {224,224,224},          {252,252,252},  /*32*/
80
    {  0,  0,252},          { 64,  0,252},
81
    {124,  0,252},          {188,  0,252},
82
    {252,  0,252},          {252,  0,188},
83
    {252,  0,124},          {252,  0, 64},
84
    {252,  0,  0},          {252, 64,  0},
85
    {252,124,  0},          {252,188,  0},
86
    {252,252,  0},          {188,252,  0},
87
    {124,252,  0},          { 64,252,  0},  /*48*/
88
    {  0,252,  0},          {  0,252, 64},
89
    {  0,252,124},          {  0,252,188},
90
    {  0,252,252},          {  0,188,252},
91
    {  0,124,252},          {  0, 64,252},
92
    {124,124,252},          {156,124,252},
93
    {188,124,252},          {220,124,252},
94
    {252,124,252},          {252,124,220},
95
    {252,124,188},          {252,124,156},  /*64*/
96
    {252,124,124},          {252,156,124},
97
    {252,188,124},          {252,220,124},
98
    {252,252,124},          {220,252,124},
99
    {188,252,124},          {156,252,124},
100
    {124,252,124},          {124,252,156},
101
    {124,252,188},          {124,252,220},
102
    {124,252,252},          {124,220,252},
103
    {124,188,252},          {124,156,252},  /*80*/
104
    {180,180,252},          {196,180,252},
105
    {216,180,252},          {232,180,252},
106
    {252,180,252},          {252,180,232},
107
    {252,180,216},          {252,180,196},
108
    {252,180,180},          {252,196,180},
109
    {252,216,180},          {252,232,180},
110
    {252,252,180},          {232,252,180},
111
    {216,252,180},          {196,252,180},  /*96*/
112
    {180,220,180},          {180,252,196},
113
    {180,252,216},          {180,252,232},
114
    {180,252,252},          {180,232,252},
115
    {180,216,252},          {180,196,252},
116
    {0,0,112},              {28,0,112},
117
    {56,0,112},             {84,0,112},
118
    {112,0,112},            {112,0,84},
119
    {112,0,56},             {112,0,28},     /*112*/
120
    {112,0,0},              {112,28,0},
121
    {112,56,0},             {112,84,0},
122
    {112,112,0},            {84,112,0},
123
    {56,112,0},             {28,112,0},
124
    {0,112,0},              {0,112,28},
125
    {0,112,56},             {0,112,84},
126
    {0,112,112},            {0,84,112},
127
    {0,56,112},             {0,28,112},     /*128*/
128
    {56,56,112},            {68,56,112},
129
    {84,56,112},            {96,56,112},
130
    {112,56,112},           {112,56,96},
131
    {112,56,84},            {112,56,68},
132
    {112,56,56},            {112,68,56},
133
    {112,84,56},            {112,96,56},
134
    {112,112,56},           {96,112,56},
135
    {84,112,56},            {68,112,56},    /*144*/
136
    {56,112,56},            {56,112,69},
137
    {56,112,84},            {56,112,96},
138
    {56,112,112},           {56,96,112},
139
    {56,84,112},            {56,68,112},
140
    {80,80,112},            {88,80,112},
141
    {96,80,112},            {104,80,112},
142
    {112,80,112},           {112,80,104},
143
    {112,80,96},            {112,80,88},    /*160*/
144
    {112,80,80},            {112,88,80},
145
    {112,96,80},            {112,104,80},
146
    {112,112,80},           {104,112,80},
147
    {96,112,80},            {88,112,80},
148
    {80,112,80},            {80,112,88},
149
    {80,112,96},            {80,112,104},
150
    {80,112,112},           {80,114,112},
151
    {80,96,112},            {80,88,112},    /*176*/
152
    {0,0,64},               {16,0,64},
153
    {32,0,64},              {48,0,64},
154
    {64,0,64},              {64,0,48},
155
    {64,0,32},              {64,0,16},
156
    {64,0,0},               {64,16,0},
157
    {64,32,0},              {64,48,0},
158
    {64,64,0},              {48,64,0},
159
    {32,64,0},              {16,64,0},      /*192*/
160
    {0,64,0},               {0,64,16},
161
    {0,64,32},              {0,64,48},
162
    {0,64,64},              {0,48,64},
163
    {0,32,64},              {0,16,64},
164
    {32,32,64},             {40,32,64},
165
    {48,32,64},             {56,32,64},
166
    {64,32,64},             {64,32,56},
167
    {64,32,48},             {64,32,40},     /*208*/
168
    {64,32,32},             {64,40,32},
169
    {64,48,32},             {64,56,32},
170
    {64,64,32},             {56,64,32},
171
    {48,64,32},             {40,64,32},
172
    {32,64,32},             {32,64,40},
173
    {32,64,48},             {32,64,56},
174
    {32,64,64},             {32,56,64},
175
    {32,48,64},             {32,40,64},     /*224*/
176
    {44,44,64},             {48,44,64},
177
    {52,44,64},             {60,44,64},
178
    {64,44,64},             {64,44,60},
179
    {64,44,52},             {64,44,48},
180
    {64,44,44},             {64,48,44},
181
    {64,52,44},             {64,60,44},
182
    {64,64,44},             {60,64,44},
183
    {52,64,44},             {48,64,44},     /*240*/
184
    {44,64,44},             {44,64,48},
185
    {44,64,52},             {44,64,60},
186
    {44,64,64},             {44,60,64},
187
    {44,55,64},             {44,48,64},
188
    {0,0,0},                {0,0,0},
189
    {0,0,0},                {0,0,0},
190
    {0,0,0},                {0,0,0},
191
    {0,0,0},                {0,0,0}         /*256*/
192
  };
193
194
195
static int ApproveFormatForWPG(const char *Format, ExceptionInfo *exception)
196
4.99M
{
197
4.99M
  const MagickInfo *
198
4.99M
    magick_info;
199
200
4.99M
  if (!strcmp(Format,"PFB")) return 0;
201
202
  /*if (!strcmp(Format,"8BIMTEXT")) return 0; This test is no longer needed, META module includes this case. */
203
4.99M
  magick_info = GetMagickInfo(Format,exception);
204
4.99M
  if (magick_info != (const MagickInfo *)NULL)
205
4.97M
    {
206
4.97M
      if (strcmp(magick_info->module, "META") == 0) return 0;
207
4.97M
    }
208
209
4.98M
  return 1;
210
4.99M
}
211
212
213
214
/*
215
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216
%                                                                             %
217
%                                                                             %
218
%                                                                             %
219
%   I s W P G                                                                 %
220
%                                                                             %
221
%                                                                             %
222
%                                                                             %
223
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224
%
225
%  IsWPG() returns True if the image format type, identified by the magick
226
%  string, is WPG.
227
%
228
%  The format of the IsWPG method is:
229
%
230
%      unsigned int IsWPG(const unsigned char *magick,const size_t length)
231
%
232
%  A description of each parameter follows:
233
%
234
%    o status:  Method IsWPG returns True if the image format type is WPG.
235
%
236
%    o magick: This string is generally the first few bytes of an image file
237
%      or blob.
238
%
239
%    o length: Specifies the length of the magick string.
240
%
241
%
242
*/
243
static unsigned int IsWPG(const unsigned char *magick,const size_t length)
244
0
{
245
0
  if (length < 4)
246
0
    return(False);
247
0
  if (memcmp(magick,"\377WPC",4) == 0)
248
0
    return(True);
249
0
  return(False);
250
0
}
251

252
static int Rd_WP_DWORD(Image *image, magick_uint32_t *d)
253
179M
{
254
179M
  unsigned char
255
179M
    b;
256
257
179M
  b = ReadBlobByte(image);
258
179M
  *d = b;
259
179M
  if (b < 0xFFU)
260
177M
    return 1;
261
1.38M
  b = ReadBlobByte(image);
262
1.38M
  *d = (unsigned long) b;
263
1.38M
  b = ReadBlobByte(image);
264
1.38M
  *d+=(unsigned long) b*256l;
265
1.38M
  if (*d < 0x8000)
266
1.22M
    return 3;
267
160k
  *d=(*d & 0x7FFF) << 16;
268
160k
  b = ReadBlobByte(image);
269
160k
  *d += (unsigned long) b;
270
160k
  b=ReadBlobByte(image);
271
160k
  *d += (unsigned long) b*256l;
272
160k
  return 5;
273
1.38M
}
274
275
276
static MagickPassFail InsertRow(unsigned char *p,unsigned long y, Image *image, int bpp)
277
1.08M
{
278
1.08M
  unsigned long
279
1.08M
    x;
280
281
1.08M
  register PixelPacket
282
1.08M
    *q;
283
284
1.08M
  MagickPassFail
285
1.08M
    RetVal = MagickFail;
286
287
1.08M
  IndexPacket
288
1.08M
    index;
289
290
1.08M
  IndexPacket *
291
1.08M
    indexes;
292
293
1.08M
  if (image->logging)
294
1.08M
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
295
1.08M
                          "Insert row %ld of %lu...", y, image->rows);
296
297
1.08M
  q = SetImagePixels(image,0,y,image->columns,1);
298
1.08M
  if (q == (PixelPacket *) NULL)
299
19.0k
    return MagickFail;
300
301
1.06M
  switch (bpp)
302
1.06M
    {
303
1.04M
    case 1:  /* Convert bitmap scanline. WP seems to ignore palette even if it is present. */
304
1.04M
      RetVal = ImportImagePixelArea(image,GrayQuantum,bpp,p,NULL,0);
305
1.04M
      break;
306
307
7.53k
    case 4:  /* Convert PseudoColor scanline. */
308
10.3k
    case 8:  /* Convert PseudoColor scanline. */
309
10.3k
      RetVal = ImportImagePixelArea(image,IndexQuantum,bpp,p,NULL,0);
310
10.3k
      break;
311
312
13.2k
    case 2:  /* Convert PseudoColor scanline. */
313
13.2k
      {
314
13.2k
        indexes=AccessMutableIndexes(image);
315
13.2k
        if ((image->storage_class != PseudoClass) ||
316
13.2k
            (indexes == (IndexPacket *) NULL))
317
0
          {
318
0
            if (image->logging)
319
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
320
0
                                    "Image has no colormap, skipping...");
321
0
            return MagickFail;
322
0
          }
323
13.2k
        x = 0;
324
165k
        while (x+3 < image->columns)
325
151k
          {
326
151k
            index = (IndexPacket)((*p >> 6) & 0x3);
327
151k
            VerifyColormapIndex(image,index);
328
151k
            indexes[x++]=index;
329
151k
            *q++=image->colormap[index];
330
151k
            index = (IndexPacket)((*p >> 4) & 0x3);
331
151k
            VerifyColormapIndex(image,index);
332
151k
            indexes[x++]=index;
333
151k
            *q++=image->colormap[index];
334
151k
            index = (IndexPacket)((*p >> 2) & 0x3);
335
151k
            VerifyColormapIndex(image,index);
336
151k
            indexes[x++]=index;
337
151k
            *q++ = image->colormap[index];
338
151k
            index = (IndexPacket)((*p) & 0x3);
339
151k
            VerifyColormapIndex(image,index);
340
151k
            indexes[x++]=index;
341
151k
            *q++ = image->colormap[index];
342
151k
            p++;
343
151k
          }
344
13.2k
        if (x < image->columns)
345
12.3k
          {
346
12.3k
            index = (IndexPacket) ((*p >> 6) & 0x3);
347
12.3k
            VerifyColormapIndex(image,index);
348
12.3k
            indexes[x++] = index;
349
12.3k
            *q++=image->colormap[index];
350
12.3k
            if (x < image->columns)
351
3.54k
              {
352
3.54k
                index = (IndexPacket) ((*p >> 4) & 0x3);
353
3.54k
                VerifyColormapIndex(image,index);
354
3.54k
                indexes[x++] = index;
355
3.54k
                *q++=image->colormap[index];
356
3.54k
                if (x < image->columns)
357
1.06k
                  {
358
1.06k
                    index = (IndexPacket)((*p >> 2) & 0x3);
359
1.06k
                    VerifyColormapIndex(image,index);
360
1.06k
                    indexes[x] = index;
361
1.06k
                    *q++=image->colormap[index];
362
1.06k
                  }
363
3.54k
              }
364
            /* p++; */
365
12.3k
          }
366
13.2k
        RetVal = MagickPass;
367
13.2k
        break;
368
13.2k
      }
369
370
3.37k
    case 24:     /*  Convert DirectColor scanline.  */
371
3.37k
      RetVal = ImportImagePixelArea(image,RGBQuantum,8,p,NULL,0);
372
3.37k
      break;
373
374
3
    default:
375
3
      if (image->logging)
376
3
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
377
3
                              "Unsupported bits per pixel %u",bpp);
378
379
3
      return MagickFail;  /* emit some error here */
380
1.06M
    }
381
382
383
1.06M
  if (RetVal==MagickFail)
384
0
    {
385
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"ImportImagePixelArea failed for row: %lu, bpp: %d", y, bpp);
386
0
      return MagickFail;
387
0
    }
388
389
1.06M
  if (!SyncImagePixels(image))
390
0
    {
391
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"SyncImagePixels failed for row: %ld, bpp: %d", y, bpp);
392
0
      return MagickFail;
393
0
    }
394
395
1.06M
  return RetVal;
396
1.06M
}
397
398
399
/* Helper for WPG1 raster reader. */
400
#define InsertByte(b)                                                   \
401
322k
  {                                                                     \
402
322k
    BImgBuff[x]=b;                                                      \
403
322k
    x++;                                                                \
404
322k
    if ((long) x>=ldblk)                                                \
405
322k
      {                                                                 \
406
19.6k
        if (InsertRow(BImgBuff,y,image,bpp)==MagickFail)                \
407
19.6k
          {                                                             \
408
3.52k
            RetVal=-6;                                                  \
409
3.52k
            goto unpack_wpg_raser_error;                                \
410
3.52k
          }                                                             \
411
19.6k
        x=0;                                                            \
412
16.1k
        y++;                                                            \
413
16.1k
        if (y>=image->rows) break;                                      \
414
16.1k
      }                                                                 \
415
322k
}
416
417
418
/** Call this function to ensure that all data matrix is filled with something. This function
419
 * is used only to error recovery. */
420
static MagickPassFail ZeroFillMissingData(unsigned char *BImgBuff,
421
                                          unsigned long x,
422
                                          unsigned long y,
423
                                          Image *image,
424
                                          int bpp,
425
                                          long ldblk)
426
347
{
427
347
  MagickPassFail
428
347
    status = MagickPass;
429
430
1.62k
  while (y<image->rows && image->exception.severity!=UndefinedException)
431
1.28k
    {
432
1.28k
      if ((long) x<ldblk)
433
14
        {
434
14
          memset(BImgBuff+x, 0, (size_t)ldblk-(size_t)x);
435
14
          if (x == 0)
436
6
            x = ldblk;      /* Do not memset any more */
437
8
          else
438
8
            x = 0;          /* Next pass will need to clear whole row */
439
14
        }
440
1.28k
      if (InsertRow(BImgBuff,y,image,bpp) == MagickFail)
441
10
        {
442
10
          status = MagickFail;
443
10
          break;
444
10
        }
445
1.27k
      y++;
446
1.27k
    }
447
347
  return status;
448
347
}
449
450
451
/* WPG1 raster reader.
452
 * @return      0 - OK; -2 - allocation failure; -3 unaligned column; -4 - image row overflowl
453
                -5 - blob read error; -6 - row insert problem  */
454
static int UnpackWPGRaster(Image *image,int bpp)
455
4.93k
{
456
4.93k
  unsigned long
457
4.93k
    x = 0,
458
4.93k
    y = 0;
459
460
4.93k
  int
461
4.93k
    i;
462
463
4.93k
  int RetVal
464
4.93k
    = 0;
465
466
4.93k
  unsigned char
467
4.93k
    bbuf,
468
4.93k
    *BImgBuff,
469
4.93k
    RunCount;
470
471
4.93k
  long
472
4.93k
    ldblk;
473
474
4.93k
  ldblk = (long)((bpp*image->columns+7)/8);
475
4.93k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
476
4.93k
                        "Raster allocation size: %ld byte%s",
477
4.93k
                        ldblk, (ldblk > 1 ? "s" : ""));
478
4.93k
  BImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) ldblk);
479
4.93k
  if (BImgBuff==NULL)
480
433
    return(-2);
481
4.50k
  (void) memset(BImgBuff,0,(size_t) ldblk);
482
483
12.0k
  while (y<image->rows)
484
11.6k
    {
485
11.6k
      i = ReadBlobByte(image);
486
11.6k
      if (i==EOF)
487
118
        {
488
118
          ZeroFillMissingData(BImgBuff,x,y,image,bpp,ldblk);
489
118
          MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff);
490
118
          return(-5);
491
118
        }
492
11.5k
      bbuf = i;
493
494
11.5k
      RunCount=bbuf & 0x7F;
495
11.5k
      if (bbuf & 0x80)
496
2.90k
        {
497
2.90k
          if (RunCount)  /* repeat next byte runcount * */
498
2.18k
            {
499
2.18k
              bbuf=ReadBlobByte(image);
500
159k
              for (i=0;i<(int) RunCount;i++) InsertByte(bbuf);
501
1.74k
            }
502
712
          else {  /* read next byte as RunCount; repeat 0xFF runcount* */
503
712
            RunCount=ReadBlobByte(image);
504
77.8k
            for (i=0;i<(int) RunCount;i++) InsertByte(0xFF);
505
702
          }
506
2.90k
        }
507
8.61k
      else {
508
8.61k
        if (RunCount)   /* next runcount byte are readd directly */
509
6.82k
          {
510
91.0k
            for (i=0;i < (int) RunCount;i++)
511
87.3k
              {
512
87.3k
                bbuf=ReadBlobByte(image);
513
87.3k
                InsertByte(bbuf);
514
84.1k
              }
515
6.82k
          }
516
1.78k
        else {  /* repeat previous line runcount* */
517
1.78k
          i = ReadBlobByte(image);
518
1.78k
          if (i==EOF)
519
222
            {
520
222
              ZeroFillMissingData(BImgBuff,x,y,image,bpp,ldblk);
521
222
              MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff);
522
222
              return -7;
523
222
            }
524
1.56k
          RunCount = i;
525
1.56k
          if (x!=0) {    /* attempt to duplicate row from x position: */
526
            /* I do not know what to do here */
527
69
            if (InsertRow(BImgBuff,y,image,bpp) == MagickPass)   /* May be line flush can fix a situation. */
528
7
              {
529
7
                x=0;
530
7
                y++;
531
7
                ZeroFillMissingData(BImgBuff,x,y,image,bpp,ldblk);
532
7
              }
533
69
            MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff);
534
69
            return(-3);
535
69
          }
536
6.53k
          for (i=0; i<(int)RunCount; i++)
537
5.19k
            {           /* Here I need to duplicate previous row RUNCOUNT* */
538
                        /* when x=0; y points to a new empty line. For y=0 zero line will be populated. */
539
5.19k
              if (y>=image->rows)
540
9
                {
541
9
                  MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff);
542
9
                  return(-4);
543
9
                }
544
5.19k
              if (InsertRow(BImgBuff,y,image,bpp)==MagickFail)
545
144
                {
546
144
                  MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff);
547
144
                  return(-6);
548
144
                }
549
5.04k
              y++;
550
5.04k
            }
551
1.49k
        }
552
8.61k
      }
553
11.5k
    }
554
3.94k
 unpack_wpg_raser_error:;
555
3.94k
  MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff);
556
3.94k
  return(RetVal);
557
4.50k
}
558
559
560
/* Helper for WPG2 reader. */
561
#define InsertByte6(b)                                          \
562
27.9M
  {                                                             \
563
27.9M
    if (XorMe)                                                  \
564
27.9M
      BImgBuff[x] = b ^ UpImgBuff[x];                           \
565
27.9M
    else                                                        \
566
27.9M
      BImgBuff[x] = b;                                          \
567
27.9M
    x++;                                                        \
568
27.9M
    if ((long) x >= ldblk)                                      \
569
27.9M
      {                                                         \
570
33.2k
        if (InsertRow(BImgBuff,(long) y,image,bpp)==MagickFail) \
571
33.2k
          { RetVal=-6;                                          \
572
14.6k
            goto unpack_wpg2_error;                             \
573
14.6k
          }                                                     \
574
33.2k
        x=0;                                                    \
575
18.6k
        y++;                                                    \
576
18.6k
        XorMe = 0;                                              \
577
18.6k
        tmpImgBuff = BImgBuff;                                  \
578
18.6k
        BImgBuff = UpImgBuff;                                   \
579
18.6k
        UpImgBuff = tmpImgBuff;                                 \
580
18.6k
      }                                                         \
581
27.9M
  }
582
583
#define FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff)                 \
584
26.3k
  do                                                                   \
585
26.3k
    {                                                                  \
586
26.3k
      MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff);       \
587
26.3k
      MagickFreeResourceLimitedMemory(unsigned char *,UpImgBuff);      \
588
26.3k
    } while (0);
589
590
/* WPG2 raster reader. */
591
static int UnpackWPG2Raster(Image *image, int bpp)
592
26.3k
{
593
26.3k
  unsigned int
594
26.3k
    SampleSize=1;
595
596
26.3k
  unsigned char
597
26.3k
    bbuf,
598
26.3k
    *BImgBuff = (unsigned char *) NULL,   /* Buffer for a current line. */
599
26.3k
    *UpImgBuff = (unsigned char *) NULL,  /* Buffer for previous line. */
600
26.3k
    *tmpImgBuff = (unsigned char *) NULL,
601
26.3k
    RunCount,
602
26.3k
    SampleBuffer[8];
603
604
26.3k
  unsigned long
605
26.3k
    x = 0,
606
26.3k
    y = 0;
607
608
26.3k
  unsigned int
609
26.3k
    i;
610
611
26.3k
  long
612
26.3k
    ldblk;
613
614
26.3k
  int XorMe = 0;
615
26.3k
  int c;
616
26.3k
  int RetVal = 0;
617
618
26.3k
  ldblk=(long) ((bpp*image->columns+7)/8);
619
26.3k
  BImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) ldblk);
620
26.3k
  if (BImgBuff==NULL)
621
0
    return(-2);
622
26.3k
  UpImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) ldblk);
623
26.3k
  if (UpImgBuff==NULL)
624
0
    {
625
0
      FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
626
0
      return(-2);
627
0
    }
628
26.3k
  (void) memset(UpImgBuff,0,ldblk);
629
26.3k
  (void) memset(SampleBuffer,0,sizeof(SampleBuffer));
630
631
335k
  while ( y< image->rows)
632
328k
    {
633
328k
      bbuf=ReadBlobByte(image);
634
635
328k
      switch (bbuf)
636
328k
        {
637
811
        case 0x7D:
638
811
          if ((c = ReadBlobByte(image)) == EOF) /* DSZ */
639
4
            {
640
4
              FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
641
4
              return(-4);
642
4
            }
643
807
          SampleSize=c;
644
807
          if (SampleSize>8)
645
24
            {
646
24
              FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
647
24
              return(-2);
648
24
            }
649
783
          if (SampleSize<1)
650
3
            {
651
3
              FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
652
3
              return(-2);
653
3
            }
654
780
          break;
655
1.18k
        case 0x7E:
656
1.18k
          if (y==0)                         /* XOR */
657
1.11k
            (void)fprintf(stderr,"\nWPG token XOR on the first line is not supported, please report!");
658
1.18k
          XorMe=!XorMe; /* or XorMe=1 ?? */
659
1.18k
          break;
660
12.2k
        case 0x7F:
661
12.2k
          if ((c = ReadBlobByte(image)) == EOF) /* BLK */
662
6
            {
663
6
              FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
664
6
              return(-4);
665
6
            }
666
12.2k
          RunCount=c;
667
2.88M
          for (i=0; i < SampleSize*(RunCount+1); i++)
668
2.87M
            {
669
2.87M
              InsertByte6(0);
670
2.87M
            }
671
11.6k
          break;
672
88.8k
        case 0xFD:
673
88.8k
          if ((c = ReadBlobByte(image)) == EOF) /* EXT */
674
3.00k
            {
675
3.00k
              FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
676
3.00k
              return(-4);
677
3.00k
            }
678
85.8k
          RunCount=c;
679
21.4M
          for (i=0; i<= RunCount;i++)
680
42.9M
            for (bbuf=0; bbuf < SampleSize; bbuf++)
681
21.6M
              InsertByte6(SampleBuffer[bbuf]);
682
84.0k
          break;
683
4.17k
        case 0xFE:
684
4.17k
          if ((c = ReadBlobByte(image)) == EOF)  /* RST */
685
5
            {
686
5
              FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
687
5
              return(-4);
688
5
            }
689
4.16k
          RunCount = c;
690
4.16k
          if (x!=0)
691
37
            {
692
37
              (void) fprintf(stderr,
693
37
                             "\nUnsupported WPG2 unaligned token RST x=%lu, please report!\n"
694
37
                             ,x);
695
37
              FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
696
37
              return(-3);
697
37
            }
698
4.13k
          {
699
            /* duplicate the previous row RunCount x */
700
1.03M
            for (i=0;i<=RunCount;i++)
701
1.02M
              {
702
1.02M
                if (InsertRow(UpImgBuff,(long)((image->rows>y) ? y : image->rows-1),image,bpp) == MagickFail)
703
58
                  {
704
58
                    FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
705
58
                    return(-4);
706
58
                  }
707
1.02M
                y++;
708
1.02M
              }
709
4.13k
          }
710
4.07k
          break;
711
19.4k
        case 0xFF:
712
19.4k
          if ((c = ReadBlobByte(image)) == EOF)  /* WHT */
713
580
            {
714
580
              FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
715
580
              return(-4);
716
580
            }
717
18.9k
          RunCount=c;
718
1.24M
          for (i=0; i < SampleSize*(RunCount+1); i++)
719
1.23M
            {
720
1.23M
              InsertByte6(0xFF);
721
1.22M
            }
722
13.3k
          break;
723
201k
        default:
724
201k
          RunCount=bbuf & 0x7F;
725
726
201k
          if (bbuf & 0x80)                /* REP */
727
8.94k
            {
728
20.1k
              for (i=0; i < SampleSize; i++)
729
11.1k
                SampleBuffer[i]=ReadBlobByte(image);
730
572k
              for (i=0;i<=RunCount;i++)
731
1.26M
                for (bbuf=0;bbuf<SampleSize;bbuf++)
732
701k
                  InsertByte6(SampleBuffer[bbuf]);
733
8.19k
            }
734
192k
          else {                        /* NRP */
735
1.59M
            for (i=0; i< SampleSize*(RunCount+1);i++)
736
1.40M
              {
737
1.40M
                bbuf=ReadBlobByte(image);
738
1.40M
                InsertByte6(bbuf);
739
1.40M
              }
740
192k
          }
741
195k
          if (EOFBlob(image))
742
1.37k
            {
743
1.37k
              FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
744
1.37k
              return(-4);
745
1.37k
            }
746
328k
        }
747
328k
    }
748
21.2k
 unpack_wpg2_error:;
749
21.2k
  FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
750
21.2k
  return(RetVal);
751
26.3k
}
752
753
754
typedef float tCTM[3][3];
755
756
static unsigned LoadWPG2Flags(Image *image, char Precision, float *Angle, tCTM *CTM)
757
56.2k
{
758
56.2k
  const unsigned char
759
56.2k
    TPR=1,
760
56.2k
    TRN=2,
761
56.2k
    SKW=4,
762
56.2k
    SCL=8,
763
56.2k
    ROT=0x10,
764
56.2k
    OID=0x20,
765
56.2k
    LCK=0x80;
766
767
56.2k
  long
768
56.2k
    x;
769
770
56.2k
  unsigned
771
56.2k
    DenX;
772
773
56.2k
  unsigned
774
56.2k
    Flags;
775
776
56.2k
  (void) memset(*CTM,0,sizeof(*CTM));     /*CTM.erase();CTM.resize(3,3);*/
777
56.2k
  (*CTM)[0][0]=1;
778
56.2k
  (*CTM)[1][1]=1;
779
56.2k
  (*CTM)[2][2]=1;
780
781
56.2k
  Flags=ReadBlobLSBShort(image);
782
56.2k
  if (Flags & LCK) /*x=*/
783
4.08k
    (void)ReadBlobLSBLong(image);  /*Edit lock*/
784
56.2k
  if (Flags & OID)
785
9.73k
    {
786
9.73k
      if (Precision==0)
787
4.98k
        {
788
4.98k
          x = ReadBlobLSBShort(image);
789
4.98k
          if (x >= 0x8000)
790
1.46k
            {
791
1.46k
              Precision = 1;   /* Double precision Switched on. */
792
1.46k
              (void) ReadBlobLSBShort(image);
793
              /* ObjectId = ((xW & 0x7FFF)<<16) | DenX; */
794
1.46k
            }
795
4.98k
        }      /*ObjectID*/
796
4.75k
      else
797
4.75k
        {/*x=*/ (void) ReadBlobLSBLong(image);}  /*ObjectID native (Double precision)*/
798
9.73k
    }
799
56.2k
  if (Flags & ROT)
800
25.9k
    {
801
25.9k
      x=ReadBlobLSBLong(image);       /*Rot Angle*/
802
25.9k
      if (Angle)
803
0
        *Angle=(float) (x/65536.0);
804
25.9k
    }
805
56.2k
  if (Flags & (ROT|SCL))
806
30.5k
    {
807
30.5k
      x=ReadBlobLSBLong(image);       /*Sx*cos()*/
808
30.5k
      (*CTM)[0][0] = (float)x/0x10000;
809
30.5k
      x=ReadBlobLSBLong(image);       /*Sy*cos()*/
810
30.5k
      (*CTM)[1][1] = (float)x/0x10000;
811
30.5k
    }
812
56.2k
  if (Flags & (ROT|SKW))
813
30.5k
    {
814
30.5k
      x=ReadBlobLSBLong(image);       /*Kx*sin()*/
815
30.5k
      (*CTM)[1][0] = (float)x/0x10000;
816
30.5k
      x=ReadBlobLSBLong(image);       /*Ky*sin()*/
817
30.5k
      (*CTM)[0][1] = (float)x/0x10000;
818
30.5k
    }
819
56.2k
  if (Flags & TRN)
820
24.0k
    {
821
24.0k
      DenX=ReadBlobLSBShort(image); x=ReadBlobLSBLong(image);  /*Tx*/
822
24.0k
      (*CTM)[0][2] = (double)x + (float)DenX/0x10000;
823
24.0k
      DenX=ReadBlobLSBShort(image); x=ReadBlobLSBLong(image);  /*Ty*/
824
24.0k
      (*CTM)[1][2] = (double)x + (float)DenX/0x10000;
825
24.0k
    }
826
56.2k
  if (Flags & TPR)
827
26.5k
    {
828
26.5k
      x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image);  /*Px*/
829
26.5k
      (*CTM)[2][0] = x + (float)DenX/0x10000;;
830
26.5k
      x=ReadBlobLSBShort(image);  DenX=ReadBlobLSBShort(image); /*Py*/
831
26.5k
      (*CTM)[2][1] = x + (float)DenX/0x10000;
832
26.5k
    }
833
56.2k
  return (Flags);
834
56.2k
}
835
836
837
static Image *ExtractPostscript(Image *image,const ImageInfo *image_info,
838
                                ExtendedSignedIntegralType PS_Offset,
839
                                size_t PS_Size,ExceptionInfo *exception)
840
6.42M
{
841
6.42M
  ImageInfo
842
6.42M
    *clone_info;
843
844
6.42M
  Image
845
6.42M
    *image2;
846
847
6.42M
  unsigned char
848
6.42M
    header_magick[2*MaxTextExtent];
849
850
6.42M
  void
851
6.42M
    *ps_data,
852
6.42M
    *ps_data_alloc = (unsigned char *) NULL;
853
854
6.42M
  char
855
6.42M
    format[MaxTextExtent];
856
857
6.42M
  size_t
858
6.42M
    header_magick_size;
859
860
6.42M
  magick_off_t
861
6.42M
    filesize;
862
863
6.42M
  if (image->logging)
864
6.42M
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
865
6.42M
                          "ExtractPostscript(): PS_Offset=%" MAGICK_OFF_F "d, PS_Size=%" MAGICK_SIZE_T_F "u",
866
6.42M
                          (magick_off_t) PS_Offset, (MAGICK_SIZE_T) PS_Size);
867
868
  /*
869
    Validate that claimed subordinate image data is contained in file size
870
  */
871
6.42M
  filesize = GetBlobSize(image);
872
6.42M
  if ((PS_Offset > filesize) || ((size_t) (filesize - PS_Offset) < PS_Size))
873
1.48k
    {
874
1.48k
      if (image->logging)
875
1.48k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
876
1.48k
                              "ExtractPostscript(): Failed to seek to PS_Offset=%" MAGICK_OFF_F "d",
877
1.48k
                              (magick_off_t) PS_Offset);
878
1.48k
      ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename);
879
1.48k
      return image;
880
1.48k
    }
881
882
  /*
883
    Get subordinate file header magick and use it to identify file format
884
  */
885
6.42M
  if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
886
0
    {
887
0
      if (image->logging)
888
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
889
0
                              "ExtractPostscript(): Failed to seek to PS_Offset=%" MAGICK_OFF_F "d",
890
0
                              (magick_off_t) PS_Offset);
891
0
      ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename);
892
0
      return image;
893
0
    }
894
6.42M
  header_magick_size = ReadBlob(image, Min(sizeof(header_magick),PS_Size), header_magick);
895
6.42M
  format[0]='\0';
896
  /*
897
    MagickExport MagickPassFail
898
    GetMagickFileFormat(const unsigned char *header, const size_t header_length,
899
    char *format, const size_t format_length,
900
    ExceptionInfo *exception)
901
  */
902
6.42M
  if (GetMagickFileFormat(header_magick,header_magick_size,format,
903
6.42M
                          sizeof(format),exception) == MagickFail)
904
1.43M
    {
905
1.43M
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
906
1.43M
                            "Failed to identify embedded file type!");
907
1.43M
      ThrowException(exception,CorruptImageError,UnableToReadImageHeader,image->filename);
908
1.43M
      return image;
909
1.43M
    }
910
911
  /*
912
    Verify if this is an allowed subordinate image format
913
  */
914
4.99M
  if (!ApproveFormatForWPG(format,exception))
915
8.73k
    {
916
8.73k
      (void) LogMagickEvent(CoderEvent, GetMagickModule(),
917
8.73k
                            "Format \"%s\" cannot be embedded inside WPG.", format);
918
8.73k
      ThrowException(exception,CorruptImageError,UnableToReadImageHeader,image->filename);
919
8.73k
      return image;
920
8.73k
    }
921
922
  /*
923
    Restore seek offset after reading header
924
  */
925
4.98M
  if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
926
0
    {
927
0
      if (image->logging)
928
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
929
0
                              "ExtractPostscript(): Failed to seek to PS_Offset=%" MAGICK_OFF_F "d",
930
0
                              (magick_off_t) PS_Offset);
931
0
      ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename);
932
0
      return image;
933
0
    }
934
  /*
935
    Allocate buffer if zero-copy read is not possible.
936
  */
937
4.98M
  if (GetBlobStreamData(image) == (unsigned char *) NULL)
938
0
    {
939
0
      ps_data_alloc=MagickAllocateResourceLimitedMemory(unsigned char *, PS_Size);
940
0
      if (ps_data_alloc == (unsigned char *) NULL)
941
0
        {
942
0
          if (image->logging)
943
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
944
0
                                  "ExtractPostscript(): Failed to allocate "
945
0
                                  "%" MAGICK_SIZE_T_F "u bytes of memory",
946
0
                                  (MAGICK_SIZE_T) PS_Size);
947
0
          ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,image->filename);
948
0
          return image;
949
0
        }
950
0
    }
951
  /*
952
    Use a zero-copy read when possible to access data
953
  */
954
4.98M
  ps_data=ps_data_alloc;
955
4.98M
  if (ReadBlobZC(image,PS_Size,&ps_data) != PS_Size)
956
22
    {
957
22
      MagickFreeResourceLimitedMemory(unsigned char *,ps_data_alloc);
958
22
      if (image->logging)
959
22
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
960
22
                              "ExtractPostscript(): Failed to read %" MAGICK_SIZE_T_F "u bytes of data at"
961
22
                              " offset=%" MAGICK_OFF_F "d",
962
22
                              (MAGICK_SIZE_T) PS_Size, (magick_off_t) PS_Offset);
963
22
      ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename);
964
22
      return image; /* return (Image *) NULL; */
965
22
    }
966
4.98M
  if (ps_data_alloc != ps_data)
967
4.98M
    {
968
4.98M
      if (image->logging)
969
4.98M
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
970
4.98M
                              "ExtractPostscript(): Zero copy read.");
971
4.98M
    }
972
#if 0
973
  /*
974
    Write in-memory blob to file for test purposes.
975
  */
976
  {
977
    char file_name[MaxTextExtent];
978
    FILE *file;
979
980
    FormatString(file_name,"wpg-blob.%s",format);
981
    if ((file=fopen(file_name,"w")) != (FILE *) NULL)
982
      {
983
        if (image->logging)
984
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
985
                                "Writing %s...", file_name);
986
        (void) fwrite(ps_data, 1, PS_Size, file);
987
        (void) fclose(file);
988
      }
989
    SeekBlob(image,PS_Offset,SEEK_SET);
990
  }
991
#endif
992
  /*
993
    Read nested image from blob, forcing read as Postscript format
994
  */
995
4.98M
  if ((clone_info=CloneImageInfo(image_info)) == NULL)
996
0
    {
997
0
      MagickFreeResourceLimitedMemory(unsigned char *,ps_data_alloc);
998
0
      return(image);
999
0
    }
1000
4.98M
  clone_info->blob=(_BlobInfoPtr_) NULL;
1001
  /* clone_info->length=0; */
1002
4.98M
  (void) strlcpy(clone_info->magick, format, sizeof(clone_info->magick));
1003
4.98M
  (void) strlcpy(clone_info->filename, "", sizeof(clone_info->filename));
1004
4.98M
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1005
4.98M
                        "Reading embedded \"%s\" content from blob...", clone_info->magick);
1006
4.98M
  image2 = BlobToImage(clone_info, ps_data, PS_Size, &image->exception );
1007
4.98M
  MagickFreeResourceLimitedMemory(unsigned char *,ps_data_alloc);
1008
4.98M
  if (!image2)
1009
4.97M
    {
1010
4.97M
      goto FINISH_UNL;
1011
4.97M
    }
1012
12.9k
  if (exception->severity >= ErrorException) /* When exception is raised, destroy image2 read. */
1013
2.82k
    {
1014
2.82k
      if (image->logging)
1015
2.82k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Exception raised during embedded image reading.");
1016
2.82k
      CloseBlob(image2);
1017
2.82k
      DestroyImageList(image2);
1018
2.82k
      goto FINISH_UNL;
1019
2.82k
    }
1020
10.1k
  if (!GetPixelCachePresent(image2))
1021
250
    {
1022
250
      if (image->logging)
1023
250
        (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Pixel cache is missing for embedded image.");
1024
250
      CloseBlob(image2);
1025
250
      DestroyImageList(image2);
1026
250
      goto FINISH_UNL;
1027
250
    }
1028
1029
  /*
1030
    Replace current image with new image while copying base image
1031
    attributes.
1032
  */
1033
9.91k
  {
1034
9.91k
    Image *p;
1035
9.91k
    p = image2;
1036
9.91k
    do
1037
9.91k
      {
1038
9.91k
        (void) strlcpy(p->filename,image->filename,MaxTextExtent);
1039
9.91k
        (void) strlcpy(p->magick_filename,image->magick_filename,MaxTextExtent);
1040
9.91k
        (void) strlcpy(p->magick,image->magick,MaxTextExtent);
1041
        /*image2->depth=image->depth;*/   /* !!!! The image2 depth should not be modified here. Image2 is completely different. */
1042
9.91k
        DestroyBlob(p);
1043
1044
9.91k
        if (p->rows==0 || p->columns==0)
1045
0
          {
1046
0
            DeleteImageFromList(&p);
1047
0
            if (p==NULL)
1048
0
              {
1049
0
                image2 = NULL;
1050
0
                goto FINISH_UNL;      /* Nothing to add, skip. */
1051
0
              }
1052
0
          }
1053
9.91k
        else
1054
9.91k
          {
1055
9.91k
            p->blob = ReferenceBlob(image->blob);
1056
9.91k
            p = p->next;
1057
9.91k
          }
1058
9.91k
      } while (p!=NULL);
1059
9.91k
  }
1060
1061
9.91k
  if ((image->rows==0 || image->columns==0) && (image->previous!=NULL || image->next!=NULL))
1062
344
    {
1063
344
      DeleteImageFromList(&image);
1064
344
    }
1065
1066
9.91k
  AppendImageToList(&image,image2);     /* This should append list 'image2' to the list 'image', image2 accepts NULL. */
1067
9.91k
  while (image->next != NULL)
1068
0
    image = image->next;                /* Rewind the cursor to the end. */
1069
1070
4.98M
 FINISH_UNL:
1071
4.98M
  DestroyImageInfo(clone_info);
1072
4.98M
  return(image);
1073
9.91k
}
1074
1075
static int EnsureNextImage(const ImageInfo *image_info, Image **pp_image)
1076
409
{
1077
409
  if (pp_image==NULL)
1078
0
    return -1;
1079
409
  if (*pp_image==NULL)
1080
0
    return -2;
1081
409
  if (image_info==NULL)
1082
0
    return -3;
1083
409
  AllocateNextImage(image_info,*pp_image);
1084
409
  if ((*pp_image)->next == (Image *) NULL)
1085
0
    return -4;
1086
409
  *pp_image = SyncNextImageInList(*pp_image);
1087
409
  (*pp_image)->columns = (*pp_image)->rows = 0;
1088
409
  (*pp_image)->colors = 0;
1089
409
  return 0;
1090
409
}
1091
1092
1093
#define LogHeaderWPG(_WPG_HEADER)                                    \
1094
0
  (void)LogMagickEvent(CoderEvent,GetMagickModule(),                 \
1095
0
                       "WPG Header Id=%Xh:\n"                        \
1096
0
                       "    DataOffset=%u\n"                         \
1097
0
                       "    ProductType=%u\n"                        \
1098
0
                       "    FileType=%u\n"                           \
1099
0
                       "    Version=%u.%u\n"                         \
1100
0
                       "    EncryptKey=%u\n"                         \
1101
0
                       "    Reserved=%u",                            \
1102
0
                       (unsigned int) _WPG_HEADER.FileId,            \
1103
0
                       (unsigned int) _WPG_HEADER.DataOffset,        \
1104
0
                       (unsigned int) _WPG_HEADER.ProductType,       \
1105
0
                       (unsigned int) _WPG_HEADER.FileType,          \
1106
0
                       (unsigned int) _WPG_HEADER.MajorVersion,      \
1107
0
                       (unsigned int) _WPG_HEADER.MinorVersion,      \
1108
0
                       (unsigned int) _WPG_HEADER.EncryptKey,        \
1109
0
                       (unsigned int) _WPG_HEADER.Reserved)
1110
1111
#define LogWPGBitmapType1(_WPG_BITMAP_TYPE1)                         \
1112
0
  (void)LogMagickEvent(CoderEvent,GetMagickModule(),                 \
1113
0
                       "WPG Bitmap1 Header:\n"                       \
1114
0
                       "    Width=%u\n"                              \
1115
0
                       "    Height=%u\n"                             \
1116
0
                       "    Depth=%u\n"                              \
1117
0
                       "    HorzRes=%u\n"                            \
1118
0
                       "    VertRes=%u",                             \
1119
0
                       (unsigned int) _WPG_BITMAP_TYPE1.Width,       \
1120
0
                       (unsigned int) _WPG_BITMAP_TYPE1.Height,      \
1121
0
                       (unsigned int) _WPG_BITMAP_TYPE1.Depth,       \
1122
0
                       (unsigned int) _WPG_BITMAP_TYPE1.HorzRes,     \
1123
0
                       (unsigned int) _WPG_BITMAP_TYPE1.VertRes)
1124
1125
#define LogWPGBitmapType2(_WPG_BITMAP_TYPE2)                           \
1126
0
  (void)LogMagickEvent(CoderEvent,GetMagickModule(),                   \
1127
0
                       "WPG Bitmap2 Header:\n"                         \
1128
0
                       "    RotAngle=%u\n"                             \
1129
0
                       "    LowLeftX=%u\n"                             \
1130
0
                       "    LowLeftY=%u\n"                             \
1131
0
                       "    UpRightX=%u\n"                             \
1132
0
                       "    UpRightY=%u\n"                             \
1133
0
                       "    Width=%u\n"                                \
1134
0
                       "    Height=%u\n"                               \
1135
0
                       "    Depth=%u\n"                                \
1136
0
                       "    HorzRes=%u\n"                              \
1137
0
                       "    VertRes=%u",                               \
1138
0
                       (unsigned int) _WPG_BITMAP_TYPE2.RotAngle,      \
1139
0
                       (unsigned int) _WPG_BITMAP_TYPE2.LowLeftX,      \
1140
0
                       (unsigned int) _WPG_BITMAP_TYPE2.LowLeftY,      \
1141
0
                       (unsigned int) _WPG_BITMAP_TYPE2.UpRightX,      \
1142
0
                       (unsigned int) _WPG_BITMAP_TYPE2.UpRightY,      \
1143
0
                       (unsigned int) _WPG_BITMAP_TYPE2.Width,         \
1144
0
                       (unsigned int) _WPG_BITMAP_TYPE2.Height,        \
1145
0
                       (unsigned int) _WPG_BITMAP_TYPE2.Depth,         \
1146
0
                       (unsigned int) _WPG_BITMAP_TYPE2.HorzRes,       \
1147
0
                       (unsigned int) _WPG_BITMAP_TYPE2.VertRes)
1148
1149
1150
typedef struct
1151
{
1152
  magick_uint16_t StartIndex;
1153
  magick_uint16_t NumOfEntries;
1154
} WPGColorMapRec;
1155
1156
1157
static void LoadPaletteRec(Image *image, WPGColorMapRec *pWPG_Palette, const int logging)
1158
30.1k
{
1159
30.1k
  pWPG_Palette->StartIndex=ReadBlobLSBShort(image);
1160
30.1k
  pWPG_Palette->NumOfEntries=ReadBlobLSBShort(image);
1161
30.1k
  if (logging)
1162
0
    (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1163
0
                         "WPG Color palette:\n"
1164
0
                         "    StartIndex=%u\n"
1165
0
                         "    NumOfEntries=%u\n",
1166
0
                         (unsigned) pWPG_Palette->StartIndex,
1167
0
                         (unsigned) pWPG_Palette->NumOfEntries);
1168
1169
30.1k
}
1170
1171
1172
/*
1173
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1174
%                                                                             %
1175
%                                                                             %
1176
%                                                                             %
1177
%   R e a d W P G I m a g e                                                   %
1178
%                                                                             %
1179
%                                                                             %
1180
%                                                                             %
1181
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1182
%
1183
%  Method ReadWPGImage reads an WPG X image file and returns it.  It
1184
%  allocates the memory necessary for the new Image structure and returns a
1185
%  pointer to the new image.
1186
%
1187
%  The format of the ReadWPGImage method is:
1188
%
1189
%    Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1190
%
1191
%  A description of each parameter follows:
1192
%
1193
%    o image:  Method ReadWPGImage returns a pointer to the image after
1194
%      reading. A null image is returned if there is a memory shortage or if
1195
%      the image cannot be read.
1196
%
1197
%    o image_info: Specifies a pointer to a ImageInfo structure.
1198
%
1199
%    o exception: return any errors or warnings in this structure.
1200
%
1201
*/
1202
static Image *ReadWPGImage(const ImageInfo *image_info,
1203
                           ExceptionInfo *exception)
1204
173k
{
1205
173k
  typedef struct
1206
173k
  {
1207
173k
    unsigned long FileId;
1208
173k
    ExtendedSignedIntegralType DataOffset;  /* magick_uint32_t */
1209
173k
    unsigned char ProductType;
1210
173k
    unsigned char FileType;
1211
173k
    unsigned char MajorVersion;
1212
173k
    unsigned char MinorVersion;
1213
173k
    unsigned int EncryptKey;
1214
173k
    unsigned int Reserved;
1215
173k
  } WPGHeader;
1216
1217
173k
  typedef struct
1218
173k
  {
1219
173k
    unsigned char RecType;
1220
173k
    magick_uint32_t RecordLength;
1221
173k
  } WPGRecord;
1222
1223
173k
  typedef struct
1224
173k
  {
1225
173k
    unsigned char Class;
1226
173k
    unsigned char RecType;
1227
173k
    magick_uint32_t Extension;
1228
173k
    magick_uint32_t RecordLength;
1229
173k
  } WPG2Record;
1230
1231
173k
  typedef struct
1232
173k
  {
1233
173k
    unsigned    HorizontalUnits;
1234
173k
    unsigned    VerticalUnits;
1235
173k
    unsigned char PosSizePrecision;
1236
173k
  } WPG2Start;
1237
1238
173k
  typedef struct
1239
173k
  {
1240
173k
    unsigned int Width;
1241
173k
    unsigned int Height;
1242
173k
    unsigned int Depth;
1243
173k
    unsigned int HorzRes;
1244
173k
    unsigned int VertRes;
1245
173k
  } WPGBitmapType1;
1246
1247
173k
  typedef struct
1248
173k
  {
1249
173k
    unsigned int Width;
1250
173k
    unsigned int Height;
1251
173k
    unsigned char Depth;
1252
173k
    unsigned char Compression;
1253
173k
  } WPG2BitmapType1;
1254
1255
173k
  typedef struct
1256
173k
  {
1257
173k
    unsigned int RotAngle;
1258
173k
    unsigned int LowLeftX;
1259
173k
    unsigned int LowLeftY;
1260
173k
    unsigned int UpRightX;
1261
173k
    unsigned int UpRightY;
1262
173k
    unsigned int Width;
1263
173k
    unsigned int Height;
1264
173k
    unsigned int Depth;
1265
173k
    unsigned int HorzRes;
1266
173k
    unsigned int VertRes;
1267
173k
  } WPGBitmapType2;
1268
1269
  /*
1270
    typedef struct {
1271
    unsigned long PS_unknown1;
1272
    unsigned int PS_unknown2;
1273
    unsigned int PS_unknown3;
1274
    } WPGPSl1Record;
1275
  */
1276
1277
173k
  Image
1278
173k
    *image,
1279
173k
    *rotated_image;
1280
1281
173k
  unsigned int
1282
173k
    status;
1283
1284
173k
  WPGHeader
1285
173k
    Header;
1286
1287
173k
  WPGRecord
1288
173k
    Rec;
1289
1290
173k
  WPG2Record
1291
173k
    Rec2;
1292
1293
173k
  WPG2Start StartWPG;
1294
1295
173k
  WPGBitmapType1
1296
173k
    BitmapHeader1;
1297
1298
173k
  WPG2BitmapType1
1299
173k
    Bitmap2Header1;
1300
1301
173k
  WPGBitmapType2
1302
173k
    BitmapHeader2;
1303
1304
173k
  WPGColorMapRec
1305
173k
    WPG_Palette;
1306
1307
173k
  int
1308
173k
    i,
1309
173k
    bpp;
1310
1311
173k
  int logging;
1312
1313
173k
  long
1314
173k
    ldblk;
1315
1316
173k
  unsigned char
1317
173k
    *BImgBuff;
1318
1319
173k
  BlobInfo
1320
173k
    *TmpBlob;
1321
1322
173k
  magick_off_t
1323
173k
    FilePos,
1324
173k
    filesize;
1325
1326
173k
  unsigned char *
1327
173k
    pPalette = NULL;
1328
1329
173k
  magick_uint16_t
1330
173k
    PaletteItems = 0;
1331
1332
173k
  magick_uint32_t
1333
173k
    PaletteAllocBytes = 0;
1334
1335
173k
  tCTM
1336
173k
    CTM;         /*current transform matrix*/
1337
1338
  /*
1339
    Open image file.
1340
  */
1341
173k
  assert(image_info != (const ImageInfo *) NULL);
1342
173k
  assert(image_info->signature == MagickSignature);
1343
173k
  assert(exception != (ExceptionInfo *) NULL);
1344
173k
  assert(exception->signature == MagickSignature);
1345
1346
173k
  logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter");
1347
1348
173k
  image=AllocateImage(image_info);
1349
173k
  image->rows=0;
1350
173k
  image->columns=0;
1351
173k
  image->depth=8;
1352
173k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1353
173k
  if (status == False)
1354
173k
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
1355
1356
  /*
1357
    Read WPG image.
1358
  */
1359
173k
  Header.FileId=ReadBlobLSBLong(image);
1360
173k
  Header.DataOffset=(ExtendedSignedIntegralType) ReadBlobLSBLong(image);
1361
173k
  Header.ProductType=ReadBlobByte(image);
1362
173k
  Header.FileType=ReadBlobByte(image);
1363
173k
  Header.MajorVersion=ReadBlobByte(image);
1364
173k
  Header.MinorVersion=ReadBlobByte(image);
1365
173k
  Header.EncryptKey=ReadBlobLSBShort(image);
1366
173k
  Header.Reserved=ReadBlobLSBShort(image);
1367
173k
  if (logging) LogHeaderWPG(Header);
1368
1369
173k
  if (Header.FileId!=0x435057FF || Header.FileType!=0x16)
1370
158k
    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
1371
158k
  if (Header.EncryptKey!=0)
1372
131k
    ThrowReaderException(CoderError,EncryptedWPGImageFileNotSupported,image);
1373
1374
131k
  image->colors = 0;
1375
131k
  image->storage_class = DirectClass;
1376
131k
  bpp=0;
1377
1378
131k
  if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1379
0
                                    "File type: %d", Header.FileType);
1380
1381
  /* Determine file size. */
1382
131k
  filesize = GetBlobSize(image);              /* zero is returned if the size cannot be determined. */
1383
131k
  if (filesize>0 && BlobIsSeekable(image))
1384
131k
    {
1385
131k
      if (filesize > (magick_off_t)0xFFFFFFFF)
1386
0
        filesize = (magick_off_t)0xFFFFFFFF;  /* More than 4GiB are not supported in WPG! */
1387
131k
    }
1388
0
  else
1389
0
    {
1390
0
      filesize = (magick_off_t)0xFFFFFFFF;
1391
0
      if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1392
0
                                        "Blob is not seekable, WPG reader could fail.");
1393
0
      ThrowReaderException(CorruptImageError,AnErrorHasOccurredReadingFromFile,image);
1394
0
    }
1395
1396
131k
  switch (Header.MajorVersion)
1397
131k
    {
1398
58.8k
    case 1:     /* WPG level 1 */
1399
58.8k
      BitmapHeader2.RotAngle = 0;
1400
58.8k
      FilePos = Header.DataOffset;
1401
143M
      while (!EOFBlob(image)) /* object parser loop */
1402
143M
        {
1403
143M
          if (SeekBlob(image,FilePos,SEEK_SET) != FilePos)
1404
0
            break;
1405
1406
143M
          Rec.RecType = 0;
1407
143M
          i=ReadBlobByte(image); /* unsigned char RecType,  EOF =-1 !!! */
1408
143M
          if (i==EOF)
1409
4.48k
            break;
1410
143M
          Rec.RecType = (unsigned char) i;
1411
143M
          FilePos += 1;
1412
1413
143M
          FilePos += Rd_WP_DWORD(image,&Rec.RecordLength);
1414
143M
          if ((magick_off_t)Rec.RecordLength > filesize)
1415
11.1k
            {
1416
11.1k
              MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1417
11.1k
              ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
1418
0
            }
1419
143M
          if (EOFBlob(image))
1420
0
            break;
1421
1422
143M
          FilePos += (magick_off_t)Rec.RecordLength;
1423
143M
          if (FilePos>filesize || FilePos<Header.DataOffset)
1424
28.4k
            {
1425
28.4k
              if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1426
0
                                                "Invalid record length: %X", (unsigned)Rec.RecType);
1427
28.4k
              break;
1428
28.4k
            }
1429
143M
          Header.DataOffset = FilePos;
1430
1431
143M
          if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1432
0
                                            "Parsing object: %X", Rec.RecType);
1433
          /* printf("\nParsing object: %u:%X", (unsigned)FilePos, Rec.RecType); */
1434
1435
143M
          switch (Rec.RecType)
1436
143M
            {
1437
1.23k
            case 0x0B: /* bitmap type 1 */
1438
1.23k
              BitmapHeader1.Width=ReadBlobLSBShort(image);
1439
1.23k
              BitmapHeader1.Height=ReadBlobLSBShort(image);
1440
1.23k
              if ((BitmapHeader1.Width == 0) || (BitmapHeader1.Height == 0))
1441
762
                {
1442
762
                  MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1443
762
                  ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
1444
0
                }
1445
470
              BitmapHeader1.Depth=ReadBlobLSBShort(image);
1446
470
              BitmapHeader1.HorzRes=ReadBlobLSBShort(image);
1447
470
              BitmapHeader1.VertRes=ReadBlobLSBShort(image);
1448
470
              if (logging) LogWPGBitmapType1(BitmapHeader1);
1449
1450
470
              if (image->rows!=0 && image->columns!=0)
1451
11
                {                       /* Allocate next image structure. */
1452
11
                  if (EnsureNextImage(image_info, &image) < 0)
1453
0
                    goto Finish;
1454
11
                }
1455
1456
470
              if (BitmapHeader1.HorzRes && BitmapHeader1.VertRes)
1457
344
                {
1458
344
                  image->units=PixelsPerCentimeterResolution;
1459
344
                  image->x_resolution=BitmapHeader1.HorzRes/470.0;
1460
344
                  image->y_resolution=BitmapHeader1.VertRes/470.0;
1461
344
                }
1462
470
              image->columns=BitmapHeader1.Width;
1463
470
              image->rows=BitmapHeader1.Height;
1464
470
              bpp=BitmapHeader1.Depth;
1465
470
              if (image->logging)
1466
470
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1467
470
                                      "Image dimensions %lux%lu, bpp=%u", image->columns, image->rows, bpp);
1468
              /* Whole palette is useless for bilevel image. */
1469
470
              if (bpp==1)
1470
28
                {
1471
28
                  image->storage_class = PseudoClass;
1472
28
                  image->colors = 2;
1473
28
                  if (!AllocateImageColormap(image,2)) goto NoMemory;
1474
28
                  image->colormap[0].red = image->colormap[0].green = image->colormap[0].blue = 0;
1475
28
                  image->colormap[1].red = image->colormap[1].green = image->colormap[1].blue = MaxRGB;
1476
28
                  image->colormap[0].opacity = image->colormap[1].opacity = OpaqueOpacity;
1477
28
                  goto UnpackRaster1bpp;  /* bypass cached palette for 1bpp. */
1478
28
                }
1479
442
              goto UnpackRaster;
1480
1481
28.5k
            case 0x0E:  /*Color palette */
1482
28.5k
              LoadPaletteRec(image,&WPG_Palette,logging);
1483
28.5k
              PaletteItems = WPG_Palette.NumOfEntries;
1484
28.5k
              if ((magick_uint32_t)PaletteItems + WPG_Palette.StartIndex > 256)
1485
756
                {
1486
756
                  MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1487
756
                  ThrowReaderException(CorruptImageError,ColormapExceedsColorsLimit,image);
1488
0
                }
1489
27.8k
              if (pPalette==NULL)
1490
2.64k
                {
1491
2.64k
                  PaletteAllocBytes = 3*256;
1492
2.64k
                  pPalette = MagickAllocateResourceLimitedMemory(unsigned char *,(size_t)PaletteAllocBytes);
1493
2.64k
                  if (pPalette==NULL)
1494
2.64k
                    ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1495
679k
                  for (i=0; i<=255; i++)
1496
676k
                    {
1497
676k
                      pPalette[3*i] = WPG1_Palette[i].Red;
1498
676k
                      pPalette[3*i+1] = WPG1_Palette[i].Green;
1499
676k
                      pPalette[3*i+2] = WPG1_Palette[i].Blue;
1500
676k
                    }
1501
2.64k
                }
1502
27.8k
              if (ReadBlob(image,(size_t) PaletteItems*3,pPalette+((size_t)3*WPG_Palette.StartIndex)) != (size_t) PaletteItems*3)
1503
27
                {
1504
27
                  MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1505
27
                  ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1506
0
                }
1507
27.8k
              break;
1508
1509
4.84M
            case 0x11:  /* Start PS l1 */
1510
4.84M
              if (Rec.RecordLength > 8)
1511
4.42M
                image=ExtractPostscript(image,image_info,
1512
4.42M
                                        TellBlob(image)+8,   /* skip PS header in the wpg */
1513
4.42M
                                        (size_t) (Rec.RecordLength-8),exception);
1514
4.84M
              break;
1515
1516
11.2k
            case 0x14:  /* bitmap type 2 */
1517
11.2k
              BitmapHeader2.RotAngle=ReadBlobLSBShort(image);
1518
11.2k
              BitmapHeader2.LowLeftX=ReadBlobLSBShort(image);
1519
11.2k
              BitmapHeader2.LowLeftY=ReadBlobLSBShort(image);
1520
11.2k
              BitmapHeader2.UpRightX=ReadBlobLSBShort(image);
1521
11.2k
              BitmapHeader2.UpRightY=ReadBlobLSBShort(image);
1522
11.2k
              BitmapHeader2.Width=ReadBlobLSBShort(image);
1523
11.2k
              BitmapHeader2.Height=ReadBlobLSBShort(image);
1524
11.2k
              if ((BitmapHeader2.Width == 0) || (BitmapHeader2.Height == 0))
1525
754
                {
1526
754
                  MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1527
754
                  ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
1528
0
                }
1529
10.4k
              BitmapHeader2.Depth=ReadBlobLSBShort(image);
1530
10.4k
              BitmapHeader2.HorzRes=ReadBlobLSBShort(image);
1531
10.4k
              BitmapHeader2.VertRes=ReadBlobLSBShort(image);
1532
10.4k
              if (logging) LogWPGBitmapType2(BitmapHeader2);
1533
1534
10.4k
              if (image->rows!=0 && image->columns!=0)
1535
10
                {       /* Allocate next image structure. */
1536
10
                  if (EnsureNextImage(image_info, &image) < 0)
1537
0
                    goto Finish;
1538
10
                }
1539
1540
10.4k
              image->units=PixelsPerCentimeterResolution;
1541
10.4k
              image->page.width=(unsigned int)
1542
10.4k
                ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightX)/470.0);
1543
10.4k
              image->page.height=(unsigned int)
1544
10.4k
                ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightY)/470.0);
1545
10.4k
              image->page.x=(int) (BitmapHeader2.LowLeftX/470.0);
1546
10.4k
              image->page.y=(int) (BitmapHeader2.LowLeftX/470.0);
1547
10.4k
              if (BitmapHeader2.HorzRes && BitmapHeader2.VertRes)
1548
6.74k
                {
1549
6.74k
                  image->x_resolution=BitmapHeader2.HorzRes/470.0;
1550
6.74k
                  image->y_resolution=BitmapHeader2.VertRes/470.0;
1551
6.74k
                }
1552
10.4k
              image->columns=BitmapHeader2.Width;
1553
10.4k
              image->rows=BitmapHeader2.Height;
1554
10.4k
              bpp=BitmapHeader2.Depth;
1555
10.4k
              if (image->logging)
1556
10.4k
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1557
10.4k
                                      "Image dimensions %lux%lu, bpp=%u",
1558
10.4k
                                      image->columns, image->rows, bpp);
1559
1560
10.9k
            UnpackRaster:
1561
10.9k
              if (bpp>24)
1562
4.45k
                {
1563
4.45k
                  MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1564
4.45k
                  ThrowReaderException(CoderError,ColorTypeNotSupported,image);
1565
0
                }
1566
1567
6.45k
              if (pPalette!=NULL && PaletteItems>0)
1568
48
                {
1569
48
                  if (bpp>=16 || PaletteItems<(1<<bpp))
1570
19
                    image->colors = PaletteItems; /*WPG_Palette.NumOfEntries;*/
1571
29
                  else
1572
29
                    image->colors = 1 << bpp;
1573
48
                  if (!AllocateImageColormap(image,image->colors))
1574
0
                    goto NoMemory;
1575
48
                  image->storage_class = PseudoClass;
1576
464
                  for (i=0; i<(int)image->colors; i++)
1577
416
                    {
1578
416
                      image->colormap[i].red = ScaleCharToQuantum(pPalette[3*i]);
1579
416
                      image->colormap[i].green=ScaleCharToQuantum(pPalette[3*i+1]);
1580
416
                      image->colormap[i].blue=ScaleCharToQuantum(pPalette[3*i+2]);
1581
416
                      image->colormap[i].opacity = OpaqueOpacity;
1582
416
                    }
1583
48
                }
1584
1585
6.48k
            UnpackRaster1bpp:
1586
6.48k
              image->depth = bpp;
1587
1588
6.48k
              if ((image->storage_class != PseudoClass) && (bpp != 24) && bpp!=1)
1589
2.51k
                {
1590
2.51k
                  image->colors=1 << bpp;
1591
2.51k
                  if (!AllocateImageColormap(image,image->colors))
1592
1.54k
                    {
1593
1.54k
                    NoMemory:
1594
1.54k
                      MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1595
1.54k
                      ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1596
0
                    }
1597
968
                  image->storage_class = PseudoClass;
1598
                  /* printf("Load default colormap \n"); */
1599
20.1k
                  for (i=0; (i < (int) image->colors) && (i < 256); i++)
1600
19.1k
                    {
1601
19.1k
                      image->colormap[i].red=ScaleCharToQuantum(WPG1_Palette[i].Red);
1602
19.1k
                      image->colormap[i].green=ScaleCharToQuantum(WPG1_Palette[i].Green);
1603
19.1k
                      image->colormap[i].blue=ScaleCharToQuantum(WPG1_Palette[i].Blue);
1604
19.1k
                      image->colormap[i].opacity = OpaqueOpacity;
1605
19.1k
                    }
1606
968
                }
1607
3.97k
              else
1608
3.97k
                {
1609
3.97k
                  if (bpp < 24)
1610
3.93k
                    if ((image->colors != (1UL<<bpp)) && (bpp != 24))
1611
3.87k
                      if (!ReallocateImageColormap(image,1U<<bpp))
1612
5
                        goto NoMemory;
1613
3.97k
                }
1614
1615
4.93k
              if (bpp == 1)
1616
3.90k
                {
1617
3.90k
                  if (image->colors<=0)
1618
0
                    {
1619
0
                      image->colormap[0].red =
1620
0
                        image->colormap[0].green =
1621
0
                        image->colormap[0].blue = 0;
1622
0
                      image->colormap[0].opacity = OpaqueOpacity;
1623
0
                    }
1624
3.90k
                  if (image->colors<=1 ||        /* Realloc has been enforced and value [1] remains uninitialised, or .. */
1625
3.90k
                      (image->colormap[0].red==0 && image->colormap[0].green==0 && image->colormap[0].blue==0 &&
1626
3.89k
                       image->colormap[1].red==0 && image->colormap[1].green==0 && image->colormap[1].blue==0))
1627
3.85k
                    {  /* fix crippled monochrome palette */
1628
3.85k
                      image->colormap[1].red =
1629
3.85k
                        image->colormap[1].green =
1630
3.85k
                        image->colormap[1].blue = MaxRGB;
1631
3.85k
                      image->colormap[1].opacity = OpaqueOpacity;
1632
3.85k
                    }
1633
3.90k
                }
1634
1635
4.93k
              if (!image_info->ping)
1636
4.93k
                if (UnpackWPGRaster(image,bpp) < 0)
1637
4.52k
                  {     /* The raster cannot be unpacked */
1638
25.3k
                  DecompressionFailed:
1639
25.3k
                    MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1640
25.3k
                    ThrowReaderException(CoderError,UnableToDecompressImage,image)
1641
25.3k
                      }
1642
1643
411
              if (Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping)
1644
387
                {
1645
                  /* flop command */
1646
387
                  if (BitmapHeader2.RotAngle & 0x8000)
1647
124
                    {
1648
124
                      rotated_image = FlopImage(image, exception);
1649
124
                      if (rotated_image != (Image *)NULL)
1650
124
                        {
1651
124
                          TmpBlob = rotated_image->blob;
1652
124
                          rotated_image->blob = image->blob;
1653
124
                          image->blob = TmpBlob;
1654
124
                          ReplaceImageInList(&image,rotated_image);
1655
124
                        }
1656
124
                    }
1657
                  /* flip command */
1658
387
                  if (BitmapHeader2.RotAngle & 0x2000)
1659
126
                    {
1660
126
                      rotated_image = FlipImage(image, exception);
1661
126
                      if (rotated_image != (Image *) NULL)
1662
126
                        {
1663
126
                          TmpBlob = rotated_image->blob;
1664
126
                          rotated_image->blob = image->blob;
1665
126
                          image->blob = TmpBlob;
1666
126
                          ReplaceImageInList(&image,rotated_image);
1667
126
                        }
1668
126
                    }
1669
1670
                  /* rotate command */
1671
387
                  if (BitmapHeader2.RotAngle & 0x0FFF)
1672
382
                    {
1673
382
                      rotated_image = RotateImage(image,
1674
382
                                                  (BitmapHeader2.RotAngle & 0x0FFF),
1675
382
                                                  exception);
1676
382
                      if (rotated_image != (Image *) NULL)
1677
371
                        {
1678
371
                          TmpBlob = rotated_image->blob;
1679
371
                          rotated_image->blob = image->blob;
1680
371
                          image->blob = TmpBlob;
1681
371
                          ReplaceImageInList(&image,rotated_image);
1682
371
                        }
1683
382
                    }
1684
387
                }
1685
1686
411
              StopTimer(&image->timer);
1687
1688
411
              if (image_info->subrange != 0)
1689
411
                if (image->scene >= (image_info->subimage+image_info->subrange-1))
1690
411
                  goto Finish;
1691
1692
0
              break;
1693
1694
1.21M
            case 0x1B:  /* Postscript l2 */
1695
1.21M
              if (Rec.RecordLength>0x3C)
1696
968k
                image=ExtractPostscript(image,image_info,
1697
968k
                                        TellBlob(image)+0x3C,   /* skip PS l2 header in the wpg */
1698
968k
                                        (size_t) (Rec.RecordLength-0x3C),exception);
1699
1.21M
              break;
1700
143M
            }
1701
143M
        }
1702
34.4k
      break;
1703
1704
69.4k
    case 2:  /* WPG level 2 */
1705
69.4k
      (void) memset(CTM,0,sizeof(CTM));
1706
69.4k
      StartWPG.PosSizePrecision = 0;
1707
17.7M
      while (!EOFBlob(image)) /* object parser loop */
1708
17.7M
        {
1709
17.7M
          if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
1710
0
            break;
1711
17.7M
          if (EOFBlob(image))
1712
0
            break;
1713
1714
17.7M
          Rec2.Class=(i=ReadBlobByte(image));
1715
17.7M
          if (i==EOF)
1716
23.7k
            break;
1717
17.7M
          Rec2.RecType=(i=ReadBlobByte(image));
1718
17.7M
          if (i==EOF)
1719
1.41k
            break;
1720
17.7M
          Rd_WP_DWORD(image,&Rec2.Extension);
1721
17.7M
          Rd_WP_DWORD(image,&Rec2.RecordLength);
1722
17.7M
          if (EOFBlob(image))
1723
9.05k
            break;
1724
1725
17.7M
          Header.DataOffset=TellBlob(image)+Rec2.RecordLength;
1726
1727
17.7M
          if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1728
0
                                            "Parsing object: %X", Rec2.RecType);
1729
1730
17.7M
          switch (Rec2.RecType)
1731
17.7M
            {
1732
542k
            case 1:
1733
542k
              StartWPG.HorizontalUnits=ReadBlobLSBShort(image);
1734
542k
              StartWPG.VerticalUnits=ReadBlobLSBShort(image);
1735
542k
              StartWPG.PosSizePrecision=ReadBlobByte(image);
1736
542k
              break;
1737
1738
1.54k
            case 0x0C:    /* Color palette */
1739
1.54k
              LoadPaletteRec(image,&WPG_Palette,logging);
1740
1741
              /* Sanity check for amount of palette entries. */
1742
1.54k
              if (WPG_Palette.NumOfEntries == 0)
1743
432
                {
1744
432
                  MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1745
432
                  ThrowReaderException(CorruptImageError,UnrecognizedNumberOfColors,image);
1746
0
                }
1747
1.11k
              if ((unsigned) (WPG_Palette.NumOfEntries-1) > MaxMap)
1748
0
                {
1749
0
                  MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1750
0
                  ThrowReaderException(CorruptImageError,ColormapExceedsColorsLimit,image);
1751
0
                }
1752
1753
1.11k
              if ((WPG_Palette.StartIndex > WPG_Palette.NumOfEntries) ||
1754
639
                  ((((magick_int32_t)WPG_Palette.NumOfEntries-(magick_int32_t)WPG_Palette.StartIndex) >
1755
639
                    (((magick_int32_t)Rec2.RecordLength-2-2) / 4))))
1756
785
                {
1757
785
                  MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1758
785
                  ThrowReaderException(CorruptImageError,InvalidColormapIndex,image);
1759
0
                }
1760
1761
              /* Assure that buffer is allocated and the current size */
1762
326
              if (PaletteAllocBytes != Max(4*(WPG_Palette.StartIndex+WPG_Palette.NumOfEntries),4*256))
1763
159
                {
1764
159
                  unsigned char *new_pPalette;
1765
159
                  PaletteAllocBytes = Max(4*(WPG_Palette.StartIndex+WPG_Palette.NumOfEntries),4*256);
1766
159
                  new_pPalette=MagickReallocateResourceLimitedMemory(unsigned char *,pPalette,PaletteAllocBytes);
1767
159
                  if (new_pPalette == (unsigned char *) NULL)
1768
0
                    MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1769
159
                  pPalette=new_pPalette;
1770
159
                }
1771
326
              if (pPalette==NULL)
1772
326
                ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1773
1774
326
              PaletteItems = WPG_Palette.NumOfEntries;
1775
83.7k
              for (i=0; i<=255; i++)
1776
83.4k
                {
1777
83.4k
                  pPalette[4*i] = WPG1_Palette[i].Red;
1778
83.4k
                  pPalette[4*i+1] = WPG1_Palette[i].Green;
1779
83.4k
                  pPalette[4*i+2] = WPG1_Palette[i].Blue;
1780
83.4k
                  pPalette[4*i+3] = OpaqueOpacity;
1781
83.4k
                }
1782
326
              if (ReadBlob(image,(size_t) PaletteItems*4,pPalette+((size_t)4*WPG_Palette.StartIndex)) != (size_t) PaletteItems*4)
1783
105
                {
1784
105
                  MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1785
105
                  ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1786
0
                }
1787
221
              break;
1788
1789
61.6k
            case 0x0E:
1790
61.6k
              Bitmap2Header1.Width=ReadBlobLSBShort(image);
1791
61.6k
              Bitmap2Header1.Height=ReadBlobLSBShort(image);
1792
61.6k
              Bitmap2Header1.Depth=ReadBlobByte(image);
1793
61.6k
              Bitmap2Header1.Compression=ReadBlobByte(image);
1794
1795
61.6k
              if ((Bitmap2Header1.Width == 0) || (Bitmap2Header1.Height == 0))
1796
2.70k
                {
1797
2.70k
                  MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1798
2.70k
                  ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
1799
0
                }
1800
1801
58.9k
              if (image->rows!=0 && image->columns!=0)
1802
388
                {       /* Allocate next image structure. */
1803
388
                  if (EnsureNextImage(image_info, &image) < 0)
1804
0
                    goto Finish;
1805
388
                }
1806
1807
58.9k
              if (Bitmap2Header1.Compression > 1)
1808
15.9k
                continue; /*Unknown compression method */
1809
43.0k
              switch (Bitmap2Header1.Depth)
1810
43.0k
                {
1811
13.5k
                case 1: bpp=1;
1812
13.5k
                  break;
1813
721
                case 2: bpp=2;
1814
721
                  break;
1815
1.52k
                case 3: bpp=4;
1816
1.52k
                  break;
1817
10.6k
                case 4: bpp=8;
1818
10.6k
                  break;
1819
1.91k
                case 8: bpp=24;
1820
1.91k
                  break;
1821
14.6k
                default:
1822
14.6k
                  continue; /*Ignore raster with unknown depth*/
1823
43.0k
                }
1824
28.3k
              image->columns=Bitmap2Header1.Width;
1825
28.3k
              image->rows=Bitmap2Header1.Height;
1826
28.3k
              if (image->logging)
1827
28.3k
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1828
28.3k
                                      "Image dimensions %lux%lu, bpp=%u",
1829
28.3k
                                      image->columns, image->rows, bpp);
1830
1831
28.3k
              if (pPalette!=NULL && PaletteItems>0)
1832
7
                {
1833
7
                  if (bpp>=16 || PaletteItems<(1<<bpp))
1834
3
                    image->colors = PaletteItems; /*WPG_Palette.NumOfEntries;*/
1835
4
                  else
1836
4
                    image->colors = 1 << bpp;
1837
7
                  if (!AllocateImageColormap(image,image->colors))
1838
0
                    goto NoMemory;
1839
7
                  image->storage_class = PseudoClass;
1840
34
                  for (i=0; i<(int)image->colors; i++)
1841
27
                    {
1842
27
                      image->colormap[i].red = ScaleCharToQuantum(pPalette[4*i]);
1843
27
                      image->colormap[i].green = ScaleCharToQuantum(pPalette[4*i+1]);
1844
27
                      image->colormap[i].blue = ScaleCharToQuantum(pPalette[4*i+2]);
1845
27
                      image->colormap[i].opacity = ScaleCharToQuantum(pPalette[4*i+3]);
1846
27
                    }
1847
7
                }
1848
1849
28.3k
              if ((image->colors == 0) && (bpp != 24))
1850
26.4k
                {
1851
26.4k
                  image->colors=1 << bpp;
1852
26.4k
                  if (!AllocateImageColormap(image,image->colors))
1853
0
                    goto NoMemory;
1854
26.4k
                  image->storage_class = PseudoClass;
1855
26.4k
                }
1856
1.92k
              else
1857
1.92k
                {
1858
1.92k
                  if (bpp < 24)
1859
6
                    if (image->colors!=(1UL<<bpp) && bpp!=24)
1860
2
                      if (!ReallocateImageColormap(image,1U<<bpp))
1861
0
                        goto NoMemory;
1862
1.92k
                }
1863
1864
28.3k
              switch (Bitmap2Header1.Compression)
1865
28.3k
                {
1866
2.04k
                case 0:    /*Uncompressed raster*/
1867
2.04k
                  {
1868
2.04k
                    ldblk=(long) ((bpp*image->columns+7)/8);
1869
2.04k
                    BImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) ldblk);
1870
2.04k
                    if (BImgBuff == (unsigned char *) NULL)
1871
0
                      goto NoMemory;
1872
1873
3.09k
                    for (i=0; i< (long) image->rows; i++)
1874
2.14k
                      {
1875
2.14k
                        if (ReadBlob(image,ldblk,(char *) BImgBuff) != (size_t) ldblk)
1876
498
                          {
1877
498
                            MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff);
1878
498
                            ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename);
1879
498
                            goto DecompressionFailed;
1880
498
                          }
1881
1.64k
                        if (InsertRow(BImgBuff,i,image,bpp) == MagickFail)
1882
597
                          {
1883
597
                            MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff);
1884
597
                            goto DecompressionFailed;
1885
597
                          }
1886
1.64k
                      }
1887
1888
953
                    MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff);
1889
953
                    break;
1890
2.04k
                  }
1891
26.3k
                case 1:    /*RLE for WPG2 */
1892
26.3k
                  {
1893
26.3k
                    if ( UnpackWPG2Raster(image,bpp) < 0)
1894
19.7k
                      goto DecompressionFailed;
1895
6.61k
                    break;
1896
26.3k
                  }
1897
28.3k
                }
1898
1899
1900
7.56k
              if (CTM[0][0]<0 && !image_info->ping)
1901
0
                {               /*?? RotAngle=360-RotAngle;*/
1902
0
                  rotated_image = FlopImage(image, exception);
1903
0
                  if (rotated_image != (Image *) NULL)
1904
0
                    {
1905
0
                      TmpBlob = rotated_image->blob;
1906
0
                      rotated_image->blob = image->blob;
1907
0
                      image->blob = TmpBlob;
1908
0
                      ReplaceImageInList(&image,rotated_image);
1909
0
                    }
1910
                  /* Try to change CTM according to Flip - I am not sure, must be checked.
1911
                     Tx(0,0)=-1;      Tx(1,0)=0;   Tx(2,0)=0;
1912
                     Tx(0,1)= 0;      Tx(1,1)=1;   Tx(2,1)=0;
1913
                     Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
1914
                     Tx(1,2)=0;   Tx(2,2)=1; */
1915
0
                }
1916
7.56k
              if (CTM[1][1]<0 && !image_info->ping)
1917
0
                {               /*?? RotAngle=360-RotAngle;*/
1918
0
                  rotated_image = FlipImage(image, exception);
1919
0
                  if (rotated_image != (Image *) NULL)
1920
0
                    {
1921
0
                      TmpBlob = rotated_image->blob;
1922
0
                      rotated_image->blob = image->blob;
1923
0
                      image->blob = TmpBlob;
1924
0
                      ReplaceImageInList(&image,rotated_image);
1925
0
                    }
1926
                  /* Try to change CTM according to Flip - I am not sure, must be checked.
1927
                     float_matrix Tx(3,3);
1928
                     Tx(0,0)= 1;   Tx(1,0)= 0;   Tx(2,0)=0;
1929
                     Tx(0,1)= 0;   Tx(1,1)=-1;   Tx(2,1)=0;
1930
                     Tx(0,2)= 0;   Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
1931
                     Tx(2,2)=1; */
1932
0
                }
1933
1934
7.56k
              StopTimer(&image->timer);
1935
1936
7.56k
              if (image_info->subrange != 0)
1937
7.56k
                if (image->scene >= (image_info->subimage+image_info->subrange-1))
1938
7.56k
                  goto Finish;
1939
1940
0
              break;
1941
1942
1.38M
            case 0x12:  /* Postscript WPG2*/
1943
1.38M
              i=ReadBlobLSBShort(image);
1944
1.38M
              if (Rec2.RecordLength > ((unsigned long) i+2))
1945
1.03M
                image=ExtractPostscript(image,image_info,
1946
1.03M
                                        TellBlob(image)+i,  /*skip PS header in the wpg2*/
1947
1.03M
                                        (size_t)Rec2.RecordLength-i-2,exception);
1948
1.38M
              break;
1949
1950
56.2k
            case 0x1B:  /*bitmap rectangle*/
1951
56.2k
              (void) LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM); /* WPG2Flags */
1952
56.2k
              break;
1953
17.7M
            }
1954
17.7M
        }
1955
1956
37.0k
      break;
1957
1958
37.0k
    default:
1959
3.46k
      {
1960
3.46k
        MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1961
3.46k
        ThrowReaderException(CoderError,DataEncodingSchemeIsNotSupported,image);
1962
0
      }
1963
131k
    }
1964
1965
79.4k
 Finish:
1966
79.4k
  CloseBlob(image);
1967
79.4k
  MagickFreeResourceLimitedMemory(unsigned char *,pPalette);
1968
1969
79.4k
  {
1970
79.4k
    Image
1971
79.4k
      *p;
1972
1973
79.4k
    long
1974
79.4k
      scene=0;
1975
1976
    /*
1977
      Rewind list, removing any empty images while rewinding.
1978
    */
1979
79.4k
    p=image;    /* reverted GetFirstImageInList(image); */
1980
79.4k
    image=NULL;
1981
167k
    while (p != (Image *) NULL)
1982
88.1k
      {
1983
88.1k
        Image *tmp=p;
1984
88.1k
        if ((p->rows == 0) || (p->columns == 0))
1985
71.5k
          {
1986
71.5k
            p=p->previous;
1987
71.5k
            DeleteImageFromList(&tmp);
1988
71.5k
          }
1989
16.6k
        else
1990
16.6k
          {
1991
16.6k
            image=p;
1992
16.6k
            p=p->previous;
1993
16.6k
          }
1994
88.1k
      }
1995
1996
    /*
1997
      Fix scene numbers
1998
    */
1999
96.1k
    for (p=image; p != (Image *) NULL; p=p->next)
2000
16.6k
      p->scene=scene++;
2001
79.4k
  }
2002
2003
79.4k
  if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),"return");
2004
79.4k
  if (image==NULL)
2005
69.7k
    ThrowReaderException(CorruptImageError,ImageFileDoesNotContainAnyImageData,image);
2006
9.68k
  return(image);
2007
79.4k
}
2008
2009

2010
/* RLE helper structure. */
2011
typedef struct
2012
{
2013
  unsigned char count;
2014
  unsigned char pos;
2015
  unsigned char buf[254];
2016
} WPG_RLE_packer;
2017
2018
/* FILE *DebugRLE = NULL; */
2019
2020
static void WPG_RLE_Flush(WPG_RLE_packer *WPG_RLE, Image *image, unsigned char n)
2021
309k
{
2022
309k
  if (n>WPG_RLE->pos)
2023
29.3k
    n=WPG_RLE->pos;
2024
309k
  if (n>0x7F)
2025
0
    n=0x7F;
2026
309k
  if (n>0)
2027
93.1k
    {
2028
      /* if (DebugRLE) fprintf(DebugRLE," size=%X",n); */
2029
93.1k
      WriteBlobByte(image,n);
2030
93.1k
      WriteBlob(image, n, WPG_RLE->buf);
2031
93.1k
      WPG_RLE->pos -= n;
2032
93.1k
      if (WPG_RLE->pos>0)
2033
78.4k
        memcpy(WPG_RLE->buf, WPG_RLE->buf+n, n);
2034
14.7k
      else
2035
14.7k
        WPG_RLE->count = 0;
2036
93.1k
    }
2037
309k
}
2038
2039
2040
static void WPG_RLE_AddCharacter(WPG_RLE_packer *WPG_RLE, unsigned char b, Image *image)
2041
13.3M
{
2042
13.3M
  WPG_RLE->buf[WPG_RLE->pos++] = b;
2043
2044
  /*  if (DebugRLE)
2045
      {
2046
      fprintf(DebugRLE,"\n%u",b);
2047
      if (WPG_RLE->pos>=0x7E)
2048
      fprintf(DebugRLE," *%u %X", WPG_RLE->pos, WPG_RLE->pos);
2049
      } */
2050
2051
13.3M
  if (WPG_RLE->pos>1)
2052
13.3M
    {
2053
13.3M
      if (WPG_RLE->count==0x7E || WPG_RLE->buf[WPG_RLE->pos-2]!=b)
2054
568k
        {
2055
568k
          if (WPG_RLE->count>=1)
2056
199k
            {
2057
199k
              WPG_RLE->count++; /* True number of repeated BYTEs. */
2058
199k
              WPG_RLE_Flush(WPG_RLE, image, WPG_RLE->pos-1-WPG_RLE->count);
2059
199k
              WriteBlobByte(image, WPG_RLE->count|0x80);
2060
199k
              WriteBlobByte(image, WPG_RLE->buf[0]);
2061
              /* if (DebugRLE) fprintf(DebugRLE," count=%X, val=%X",WPG_RLE->count,WPG_RLE->buf[0]); */
2062
199k
              WPG_RLE->pos = 1;
2063
199k
              WPG_RLE->buf[0] = b;
2064
199k
            }
2065
568k
          WPG_RLE->count = 0;
2066
568k
        }
2067
12.7M
      else
2068
12.7M
        WPG_RLE->count++;
2069
13.3M
    }
2070
2071
13.3M
  if (WPG_RLE->pos-WPG_RLE->count>0x7E) /* We have uncompressible block with size 0x7F. */
2072
104
    {
2073
104
      WPG_RLE_Flush(WPG_RLE, image, 0x7F);
2074
104
      return;
2075
104
    }
2076
13.3M
  if (WPG_RLE->pos>0x7E && WPG_RLE->count>=1)
2077
80.1k
    {
2078
80.1k
      WPG_RLE_Flush(WPG_RLE, image, WPG_RLE->pos-1-WPG_RLE->count);
2079
80.1k
      return;
2080
80.1k
    }
2081
13.3M
}
2082
2083
2084
static void WPG_RLE_FinalFlush(WPG_RLE_packer *WPG_RLE, Image *image)
2085
57.3k
{
2086
57.3k
  if (WPG_RLE->count>1)
2087
42.6k
    {
2088
42.6k
      WPG_RLE_AddCharacter(WPG_RLE, WPG_RLE->buf[WPG_RLE->pos-1]^0xFF, image); /* Add a fake BYTE. */
2089
42.6k
      WPG_RLE->pos = 0; /* Take a last fake BYTE away. */
2090
42.6k
    }
2091
14.6k
  else
2092
14.6k
    {
2093
14.6k
      WPG_RLE_Flush(WPG_RLE,image,0x7F);
2094
14.6k
      WPG_RLE_Flush(WPG_RLE,image,0x7F);
2095
14.6k
      WPG_RLE->count = 0;
2096
14.6k
    }
2097
57.3k
}
2098
2099
2100
static void WPG_RLE_AddBlock(WPG_RLE_packer *WPG_RLE, Image *image, const unsigned char *blk, magick_uint16_t size)
2101
57.3k
{
2102
13.4M
  while (size-- > 0)
2103
13.3M
    {
2104
13.3M
      WPG_RLE_AddCharacter(WPG_RLE, *blk, image);
2105
13.3M
      blk++;
2106
13.3M
    }
2107
57.3k
}
2108
2109
2110
static void WPG_RLE_Init(WPG_RLE_packer *WPG_RLE)
2111
889
{
2112
889
  WPG_RLE->pos = WPG_RLE->count = 0;
2113
889
}
2114
2115
2116
/*
2117
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2118
%                                                                             %
2119
%                                                                             %
2120
%                                                                             %
2121
%   W r i t e W P G I m a g e                                           %
2122
%                                                                             %
2123
%                                                                             %
2124
%                                                                             %
2125
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2126
%
2127
%  Function WriteWPGImage writes an WPG image to a file.
2128
%
2129
%  The format of the WriteWPGImage method is:
2130
%
2131
%      unsigned int WriteWPGImage(const ImageInfo *image_info,Image *image)
2132
%
2133
%  A description of each parameter follows.
2134
%
2135
%    o status: Function WriteWPGImage return True if the image is written.
2136
%      False is returned is there is a memory shortage or if the image file
2137
%      fails to write.
2138
%
2139
%    o image_info: Specifies a pointer to a ImageInfo structure.
2140
%
2141
%    o image:  A pointer to an Image structure.
2142
*/
2143
static MagickPassFail WriteWPGImage(const ImageInfo *image_info, Image *image)
2144
889
{
2145
889
  long
2146
889
    y;
2147
2148
889
  unsigned int
2149
889
    status;
2150
2151
889
  int
2152
889
    logging;
2153
2154
889
  unsigned char
2155
889
    StoredPlanes;
2156
2157
889
  unsigned
2158
889
    ldblk;
2159
2160
889
  magick_off_t
2161
889
    NumericOffs,
2162
889
    CurrOffs;
2163
2164
889
  QuantizeInfo
2165
889
    quantize_info;
2166
2167
889
  WPG_RLE_packer
2168
889
    PackRLE;
2169
2170
889
  unsigned char
2171
889
    *pixels;
2172
2173
  /*
2174
    Open output image file.
2175
  */
2176
889
  assert(image_info != (const ImageInfo *) NULL);
2177
889
  assert(image_info->signature == MagickSignature);
2178
889
  assert(image != (Image *) NULL);
2179
889
  assert(image->signature == MagickSignature);
2180
889
  logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter WPG");
2181
889
  status = OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
2182
889
  if (status == MagickFail)
2183
889
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
2184
889
  WPG_RLE_Init(&PackRLE);
2185
2186
889
  (void)TransformColorspace(image,RGBColorspace);
2187
2188
889
  if ((image->storage_class == DirectClass) ||
2189
136
      ((image->storage_class == PseudoClass) && (image->colors<=0 || image->colors>256)))
2190
755
    {
2191
755
      GetQuantizeInfo(&quantize_info);
2192
755
      quantize_info.dither = image_info->dither;
2193
755
      quantize_info.number_colors = 256;
2194
755
      status = QuantizeImage(&quantize_info,image);
2195
755
      if (status==MagickFail || image->colors==0)
2196
0
        goto ImageFailure;
2197
755
    }
2198
889
  if (image->colors <= 2)
2199
456
    {
2200
456
      StoredPlanes=1;
2201
456
      ldblk = (image->columns+7)/8;
2202
456
    } else if (image->colors <= 16)
2203
127
    {
2204
127
      StoredPlanes=4;
2205
127
      ldblk = (image->columns+1)/2;
2206
127
    } else
2207
306
    {
2208
306
      StoredPlanes = 8;
2209
306
      ldblk = image->columns;
2210
306
    }
2211
2212
889
  pixels = MagickAllocateResourceLimitedMemory(unsigned char *,(size_t)(ldblk));
2213
889
  if (pixels == (unsigned char *) NULL)
2214
889
    ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
2215
2216
  /* Write WPG header. */
2217
889
  WriteBlobLSBLong(image,0x435057FF);           /* DWORD FileId */
2218
889
  WriteBlobLSBLong(image,16);                   /* DWORD DataOffset; */
2219
889
  WriteBlobByte(image,1);                       /* BYTE Product Type */
2220
889
  WriteBlobByte(image,0x16);                    /* BYTE FileType; */
2221
889
  WriteBlobByte(image,1);                       /* BYTE MajorVersion; */
2222
889
  WriteBlobByte(image,0);                       /* BYTE MinorVersion; */
2223
889
  WriteBlobLSBShort(image,0);                   /* WORD EncryptKey; */
2224
889
  WriteBlobLSBShort(image,0);                   /* WORD Reserved; */
2225
2226
  /* Start WPG l1 */
2227
889
  WriteBlobByte(image,0xF);
2228
889
  WriteBlobByte(image,0x6);
2229
889
  WriteBlobByte(image,1);                       /* BYTE Version number */
2230
889
  WriteBlobByte(image,0);                       /* BYTE Flags (bit 0 PostScript, maybe bitmap, bit 1 PostScript, no bitmap */
2231
889
  WriteBlobLSBShort(image,image->columns);      /* WORD Width of image (arbitrary units) */
2232
889
  WriteBlobLSBShort(image,image->rows);         /* WORD Height of image (arbitrary units) */
2233
2234
  /* Palette */
2235
889
  if (StoredPlanes>1)
2236
433
    {
2237
433
      magick_uint16_t i;
2238
433
      WriteBlobByte(image,0xE);
2239
433
      i = 4+3*(1<<StoredPlanes);
2240
433
      if (i<0xFF)
2241
127
        WriteBlobByte(image,i);
2242
306
      else
2243
306
        {
2244
306
          WriteBlobByte(image,0xFF);
2245
306
          WriteBlobLSBShort(image,i);
2246
306
        }
2247
433
      WriteBlobLSBShort(image,0);                         /* Start index */
2248
433
      WriteBlobLSBShort(image,1<<StoredPlanes);           /* Num entries */
2249
2250
80.8k
      for (i=0; i<(1<<StoredPlanes); i++)
2251
80.3k
        {
2252
80.3k
          if (i>=image->colors || image->colormap==NULL)
2253
28.4k
            {
2254
28.4k
              WriteBlobByte(image,i);
2255
28.4k
              WriteBlobByte(image,i);
2256
28.4k
              WriteBlobByte(image,i);
2257
28.4k
            }
2258
51.8k
          else
2259
51.8k
            {
2260
51.8k
              WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
2261
51.8k
              WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].green));
2262
51.8k
              WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
2263
51.8k
            }
2264
80.3k
        }
2265
433
    }
2266
2267
  /* Bitmap 1 header */
2268
889
  WriteBlobByte(image,0xB);
2269
889
  WriteBlobByte(image,0xFF);
2270
889
  NumericOffs = TellBlob(image);
2271
889
  WriteBlobLSBShort(image,0x8000);
2272
889
  WriteBlobLSBShort(image,0);
2273
2274
889
  WriteBlobLSBShort(image,image->columns);      /* WORD Width */
2275
889
  WriteBlobLSBShort(image,image->rows);         /* WORD Height */
2276
889
  WriteBlobLSBShort(image,StoredPlanes);        /* WORD Depth; */
2277
889
  WriteBlobLSBShort(image,75);                  /* WORD HorzRes; */
2278
889
  WriteBlobLSBShort(image,75);                  /* WORD VertRes; */
2279
2280
  /*
2281
    Store image data.
2282
  */
2283
58.2k
  for (y=0; y<(long)image->rows; y++)
2284
57.3k
    {
2285
      /* if (y==1310 && DebugRLE==NULL) DebugRLE=fopen("o:\\temp\\14\\debug.txt","wb"); */
2286
      /* if (y>1310 && DebugRLE) {fclose(DebugRLE);DebugRLE=NULL;} */
2287
2288
57.3k
      if (AcquireImagePixels(image,0,y,image->columns,1,&image->exception) == (const PixelPacket *)NULL)
2289
0
        {
2290
0
          status = MagickFail;
2291
0
          break;
2292
0
        }
2293
57.3k
      if (ExportImagePixelArea(image, (StoredPlanes==1)?GrayQuantum:IndexQuantum, StoredPlanes,pixels,0,0) != MagickPass)
2294
0
        {
2295
0
          status = MagickFail;
2296
0
          break;
2297
0
        }
2298
57.3k
      WPG_RLE_AddBlock(&PackRLE,image,pixels,ldblk);
2299
57.3k
      WPG_RLE_FinalFlush(&PackRLE,image);
2300
57.3k
    }
2301
2302
889
  CurrOffs = TellBlob(image);
2303
889
  SeekBlob(image,NumericOffs,SEEK_SET);
2304
889
  NumericOffs = CurrOffs - NumericOffs - 4;
2305
889
  WriteBlobLSBShort(image, 0x8000|(NumericOffs>>16));
2306
889
  WriteBlobLSBShort(image, NumericOffs&0xFFFF);
2307
889
  SeekBlob(image,CurrOffs,SEEK_SET);
2308
2309
  /* End of WPG data */
2310
889
  WriteBlobByte(image,0x10);
2311
889
  WriteBlobByte(image,0);
2312
2313
889
  MagickFreeResourceLimitedMemory(unsigned char *,pixels);
2314
889
 ImageFailure:
2315
889
  status &= CloseBlob(image);
2316
2317
2318
889
  if (logging)
2319
0
    (void)LogMagickEvent(CoderEvent,GetMagickModule(),"return WPG");
2320
2321
889
  return(status);
2322
889
}
2323
2324

2325
/*
2326
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2327
%                                                                             %
2328
%                                                                             %
2329
%                                                                             %
2330
%   R e g i s t e r W P G I m a g e                                           %
2331
%                                                                             %
2332
%                                                                             %
2333
%                                                                             %
2334
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2335
%
2336
%  Method RegisterWPGImage adds attributes for the WPG image format to
2337
%  the list of supported formats.  The attributes include the image format
2338
%  tag, a method to read and/or write the format, whether the format
2339
%  supports the saving of more than one frame to the same file or blob,
2340
%  whether the format supports native in-memory I/O, and a brief
2341
%  description of the format.
2342
%
2343
%  The format of the RegisterWPGImage method is:
2344
%
2345
%      RegisterWPGImage(void)
2346
%
2347
*/
2348
ModuleExport void RegisterWPGImage(void)
2349
4
{
2350
4
  MagickInfo
2351
4
    *entry;
2352
2353
4
  entry=SetMagickInfo("WPG");
2354
4
  entry->decoder=(DecoderHandler) ReadWPGImage;
2355
4
  entry->encoder = (EncoderHandler)WriteWPGImage;
2356
4
  entry->magick=(MagickHandler) IsWPG;
2357
4
  entry->description="Word Perfect Graphics";
2358
4
  entry->module="WPG";
2359
4
  entry->seekable_stream=True;
2360
4
  entry->adjoin=MagickFalse;
2361
4
  entry->coder_class=UnstableCoderClass;
2362
4
  (void) RegisterMagickInfo(entry);
2363
4
}
2364

2365
/*
2366
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367
%                                                                             %
2368
%                                                                             %
2369
%                                                                             %
2370
%   U n r e g i s t e r W P G I m a g e                                       %
2371
%                                                                             %
2372
%                                                                             %
2373
%                                                                             %
2374
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2375
%
2376
%  Method UnregisterWPGImage removes format registrations made by the
2377
%  WPG module from the list of supported formats.
2378
%
2379
%  The format of the UnregisterWPGImage method is:
2380
%
2381
%      UnregisterWPGImage(void)
2382
%
2383
*/
2384
ModuleExport void UnregisterWPGImage(void)
2385
0
{
2386
0
  (void) UnregisterMagickInfo("WPG");
2387
0
}