Coverage Report

Created: 2025-11-16 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/rle.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2025 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
5
%
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11
%                                                                             %
12
%                                                                             %
13
%                                                                             %
14
%                            RRRR   L      EEEEE                              %
15
%                            R   R  L      E                                  %
16
%                            RRRR   L      EEE                                %
17
%                            R R    L      E                                  %
18
%                            R  R   LLLLL  EEEEE                              %
19
%                                                                             %
20
%                                                                             %
21
%                         Read URT RLE Image Format.                          %
22
%                                                                             %
23
%                                                                             %
24
%                              Software Design                                %
25
%                                John Cristy                                  %
26
%                                 July 1992                                   %
27
%                                                                             %
28
%                                                                             %
29
%                                                                             %
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31
%
32
%
33
*/
34

35
/*
36
  Include declarations.
37
*/
38
#include "magick/studio.h"
39
#include "magick/attribute.h"
40
#include "magick/blob.h"
41
#include "magick/colormap.h"
42
#include "magick/log.h"
43
#include "magick/magick.h"
44
#include "magick/monitor.h"
45
#include "magick/pixel_cache.h"
46
#include "magick/utility.h"
47
48
typedef struct _RLE_Header
49
{
50
  magick_uint8_t   Magic[2];    /* Magic number */
51
  magick_uint16_t  Xpos;        /* Lower left x of image */
52
  magick_uint16_t  Ypos;        /* Lower left y of image */
53
  magick_uint16_t  XSize;       /* Image width */
54
  magick_uint16_t  YSize;       /* Image height */
55
  magick_uint8_t   Flags;       /* Misc flags */
56
  magick_uint8_t   Ncolors;     /* Number of colors */
57
  magick_uint8_t   Pixelbits;   /* Number of bits per channel */
58
  magick_uint8_t   Ncmap;       /* Number of color channels in palette */
59
  magick_uint8_t   Cmaplen;     /* Colormap length */
60
61
} RLE_HEADER;
62
63
/* If this flag is set, the image rectangle should first be cleared to
64
the background color (q.v.) before reading the scanline data. */
65
56.8k
#define ClearFirstFlag    0x01
66
67
/* If this flag is set, no background color is supplied, and the
68
ClearFirst flag should be ignored. */
69
160k
#define NoBackgroundFlag  0x02
70
71
/* This flag indicates the presence of an "alpha" channel. The alpha
72
channel is used by image compositing software to correctly blend
73
anti-aliased edges. It is stored as channel -1 (255). */
74
235k
#define AlphaFlag         0x04
75
76
/* If this flag is set, comments are present in the variable part of
77
the header, immediately following the color map. */
78
89.9k
#define CommentsFlag      0x08
79
80
/* RLE operators */
81
5.95M
#define SkipLinesOp  0x01
82
61.8k
#define SetColorOp  0x02
83
58.9k
#define SkipPixelsOp  0x03
84
30.9k
#define ByteDataOp  0x05
85
18.0k
#define RunDataOp  0x06
86
11.5M
#define EOFOp  0x07
87
88
static void LogRLEHeader(const RLE_HEADER* rle_header)
89
147k
{
90
147k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
91
147k
                        "RLE Header\n"
92
147k
                        "    Magic:     \\%03o\\%03o\n"
93
147k
                        "    Xpos:      %u\n"
94
147k
                        "    Ypos:      %u\n"
95
147k
                        "    XSize:     %u\n"
96
147k
                        "    YSize:     %u\n"
97
147k
                        "    Flags:     0x%02x (%u,%u,%u,%u,%u,%u,%u,%u)\n"
98
147k
                        "    Ncolors:   %u\n"
99
147k
                        "    Pixelbits: %u\n"
100
147k
                        "    Ncmap:     %u\n"
101
147k
                        "    Cmaplen:   %u",
102
147k
                        rle_header->Magic[0],
103
147k
                        rle_header->Magic[1],
104
147k
                        rle_header->Xpos,
105
147k
                        rle_header->Ypos,
106
147k
                        rle_header->XSize,
107
147k
                        rle_header->YSize,
108
147k
                        rle_header->Flags,
109
147k
                        (rle_header->Flags >> 7) & 0x01,
110
147k
                        (rle_header->Flags >> 6) & 0x01,
111
147k
                        (rle_header->Flags >> 5) & 0x01,
112
147k
                        (rle_header->Flags >> 4) & 0x01,
113
147k
                        (rle_header->Flags >> 3) & 0x01,
114
147k
                        (rle_header->Flags >> 2) & 0x01,
115
147k
                        (rle_header->Flags >> 1) & 0x01,
116
147k
                        (rle_header->Flags >> 0) & 0x01,
117
147k
                        rle_header->Ncolors,
118
147k
                        rle_header->Pixelbits,
119
147k
                        rle_header->Ncmap,
120
147k
                        rle_header->Cmaplen);
121
147k
}
122

123
/*
124
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125
%                                                                             %
126
%                                                                             %
127
%                                                                             %
128
%   I s R L E                                                                 %
129
%                                                                             %
130
%                                                                             %
131
%                                                                             %
132
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133
%
134
%  Method IsRLE returns True if the image format type, identified by the
135
%  magick string, is RLE.
136
%
137
%  The format of the ReadRLEImage method is:
138
%
139
%      unsigned int IsRLE(const unsigned char *magick,const size_t length)
140
%
141
%  A description of each parameter follows:
142
%
143
%    o status:  Method IsRLE returns True if the image format type is RLE.
144
%
145
%    o magick: This string is generally the first few bytes of an image file
146
%      or blob.
147
%
148
%    o length: Specifies the length of the magick string.
149
%
150
%
151
*/
152
static unsigned int IsRLE(const unsigned char *magick,const size_t length)
153
0
{
154
0
  if (length < 2)
155
0
    return(False);
156
0
  if (memcmp(magick,"\122\314",2) == 0)
157
0
    return(True);
158
0
  return(False);
159
0
}
160

161
/*
162
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163
%                                                                             %
164
%                                                                             %
165
%                                                                             %
166
%   R e a d R L E I m a g e                                                   %
167
%                                                                             %
168
%                                                                             %
169
%                                                                             %
170
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171
%
172
%  Method ReadRLEImage reads a run-length encoded Utah Raster Toolkit
173
%  image file and returns it.  It allocates the memory necessary for the new
174
%  Image structure and returns a pointer to the new image.
175
%
176
%  The format of the ReadRLEImage method is:
177
%
178
%      Image *ReadRLEImage(const ImageInfo *image_info,ExceptionInfo *exception)
179
%
180
%  A description of each parameter follows:
181
%
182
%    o image:  Method ReadRLEImage returns a pointer to the image after
183
%      reading.  A null image is returned if there is a memory shortage or
184
%      if the image cannot be read.
185
%
186
%    o image_info: Specifies a pointer to a ImageInfo structure.
187
%
188
%    o exception: return any errors or warnings in this structure.
189
%
190
%
191
*/
192
139k
#define ThrowRLEReaderException(code_,reason_,image_) \
193
143k
do { \
194
143k
  MagickFreeResourceLimitedMemory(colormap); \
195
143k
  MagickFreeResourceLimitedMemory(rle_pixels); \
196
143k
  ThrowReaderException(code_,reason_,image_); \
197
0
} while (0);
198
static Image *ReadRLEImage(const ImageInfo *image_info,ExceptionInfo *exception)
199
153k
{
200
153k
  RLE_HEADER
201
153k
    rle_header;
202
203
153k
  Image
204
153k
    *image;
205
206
153k
  int
207
153k
    b,
208
153k
    opcode,
209
153k
    operand,
210
153k
    pixel,
211
153k
    status;
212
213
153k
  size_t
214
153k
    colormap_entries;
215
216
153k
  unsigned int
217
153k
    index;
218
219
153k
  unsigned long
220
153k
    y;
221
222
153k
  register IndexPacket
223
153k
    *indexes;
224
225
153k
  register unsigned long
226
153k
    x;
227
228
153k
  register PixelPacket
229
153k
    *q;
230
231
153k
  register unsigned int
232
153k
    i;
233
234
153k
  register unsigned char
235
153k
    *p;
236
237
153k
  size_t
238
153k
    count,
239
153k
    map_length,
240
153k
    number_pixels,
241
153k
    offset,
242
153k
    rle_bytes;
243
244
153k
  unsigned char
245
153k
    background_color[256],
246
153k
    *colormap = (unsigned char *) NULL,
247
153k
    plane,
248
153k
    *rle_pixels = (unsigned char *) NULL;
249
250
153k
  unsigned int
251
153k
    number_colormaps,
252
153k
    number_planes;
253
254
153k
  magick_off_t
255
153k
    file_size;
256
257
  /*
258
    Open image file.
259
  */
260
153k
  assert(image_info != (const ImageInfo *) NULL);
261
153k
  assert(image_info->signature == MagickSignature);
262
153k
  assert(exception != (ExceptionInfo *) NULL);
263
153k
  assert(exception->signature == MagickSignature);
264
153k
  (void) memset(&rle_header,0,sizeof(rle_header));
265
153k
  image=AllocateImage(image_info);
266
153k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
267
153k
  if (status == False)
268
153k
    ThrowRLEReaderException(FileOpenError,UnableToOpenFile,image);
269
  /*
270
    Determine if this is a RLE file.
271
  */
272
153k
  count=ReadBlob(image,2,(char *) &rle_header.Magic);
273
153k
  if ((count != 2) || (memcmp(&rle_header.Magic,"\122\314",2) != 0))
274
153k
    ThrowRLEReaderException(CorruptImageError,ImproperImageHeader,image);
275
153k
  file_size=GetBlobSize(image);
276
  /*
277
    Read image header.
278
  */
279
153k
  rle_header.Xpos=ReadBlobLSBShort(image);
280
153k
  rle_header.Ypos=ReadBlobLSBShort(image);
281
153k
  rle_header.XSize=ReadBlobLSBShort(image);
282
153k
  rle_header.YSize=ReadBlobLSBShort(image);
283
153k
  rle_header.Flags=ReadBlobByte(image);
284
153k
  b=ReadBlobByte(image);
285
153k
  if (EOF == b)
286
150k
    ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
287
150k
  if (b < 0)
288
150k
    ThrowRLEReaderException(CorruptImageError,ImproperImageHeader,image);
289
150k
  rle_header.Ncolors=(magick_uint8_t) b;
290
150k
  b=ReadBlobByte(image);
291
150k
  if (EOF == b)
292
150k
    ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
293
150k
  if (b < 0)
294
150k
    ThrowRLEReaderException(CorruptImageError,ImproperImageHeader,image);
295
150k
  rle_header.Pixelbits=(magick_uint8_t) b;
296
150k
  b=ReadBlobByte(image);
297
150k
  if (EOF == b)
298
147k
    ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
299
147k
  if (b < 0)
300
147k
    ThrowRLEReaderException(CorruptImageError,ImproperImageHeader,image);
301
147k
  rle_header.Ncmap=(magick_uint8_t) b;
302
147k
  b=ReadBlobByte(image);
303
147k
  if (EOF == b)
304
147k
    ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
305
147k
  if (b < 0)
306
147k
    ThrowRLEReaderException(CorruptImageError,ImproperImageHeader,image);
307
147k
  rle_header.Cmaplen=(magick_uint8_t) b;
308
147k
  if (EOFBlob(image))
309
147k
    ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
310
311
147k
  LogRLEHeader(&rle_header);
312
313
147k
  if ((rle_header.Ncolors == 0) ||
314
139k
      (rle_header.Ncolors == 2) ||
315
130k
      ((rle_header.Flags & AlphaFlag) &&
316
39.8k
       ((rle_header.Ncolors > 254) || (rle_header.Ncolors < 3))) ||
317
128k
      (rle_header.Pixelbits != 8))
318
121k
    ThrowRLEReaderException(CoderError,DataEncodingSchemeIsNotSupported,image);
319
320
  /* X/Y size may not be zero and may not exceed 32768 */
321
121k
  if ((rle_header.XSize == 0) || (rle_header.XSize >= 32768) ||
322
113k
      (rle_header.YSize == 0) || (rle_header.YSize >= 32768))
323
112k
    ThrowRLEReaderException(CorruptImageError,ImproperImageHeader,image);
324
325
112k
  if (rle_header.Cmaplen > 8)
326
104k
    ThrowRLEReaderException(CorruptImageError,ImproperImageHeader,image);
327
328
104k
  image->columns=rle_header.XSize;
329
104k
  image->rows=rle_header.YSize;
330
104k
  image->matte=rle_header.Flags & AlphaFlag;
331
104k
  number_planes=rle_header.Ncolors;
332
104k
  number_colormaps=rle_header.Ncmap;
333
104k
  map_length=(size_t) 1 << rle_header.Cmaplen;
334
335
104k
  (void) memset(background_color,0,sizeof(background_color));
336
104k
  if (rle_header.Flags & NoBackgroundFlag)
337
16.9k
    {
338
      /*
339
        No background color-- initialize to black.
340
      */
341
133k
      for (i=0; i < number_planes; i++)
342
116k
        background_color[i]=0;
343
16.9k
      (void) ReadBlobByte(image);
344
16.9k
    }
345
87.9k
  else
346
87.9k
    {
347
      /*
348
        Initialize background color.
349
      */
350
87.9k
      p=background_color;
351
626k
      for (i=0; i < number_planes; i++)
352
538k
        *p++=ReadBlobByte(image);
353
87.9k
    }
354
104k
  if ((number_planes & 0x01) == 0)
355
10.7k
    (void) ReadBlobByte(image);
356
357
104k
  if (EOFBlob(image))
358
103k
    ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
359
360
103k
  if (image->matte)
361
31.8k
    number_planes++;
362
363
  /*
364
    Rationalize pixels with file size
365
  */
366
103k
  if ((file_size == 0) ||
367
103k
      ((((double) image->columns*image->rows*number_planes*
368
103k
         rle_header.Pixelbits/8)/file_size) > 254.0))
369
12.9k
    ThrowRLEReaderException(CorruptImageError,InsufficientImageDataInFile,
370
103k
                            image);
371
372
90.9k
  if ((double) number_colormaps*map_length > file_size)
373
453
    ThrowRLEReaderException(CorruptImageError,InsufficientImageDataInFile,
374
90.9k
                            image);
375
376
  /*
377
    Cap the number of planes at 4 since we don't support more than that.
378
  */
379
90.4k
  if (number_planes > 4)
380
24.0k
    number_planes=4;
381
382
90.4k
  colormap_entries=0;
383
90.4k
  if (number_colormaps != 0)
384
67.1k
    {
385
      /*
386
        Read image colormaps.  Color map values are stored as 16 bit
387
        quantities, left justified in the word.
388
      */
389
67.1k
      colormap=MagickAllocateResourceLimitedArray(unsigned char *,number_colormaps,
390
67.1k
                                   map_length);
391
67.1k
      if (colormap == (unsigned char *) NULL)
392
0
        ThrowRLEReaderException(ResourceLimitError,MemoryAllocationFailed,
393
67.1k
                                image);
394
67.1k
      p=colormap; /* unsigned char * */
395
557k
      for (i=0; i < number_colormaps; i++)
396
4.73M
        for (x=0; x < map_length; x++)
397
4.24M
          {
398
4.24M
            if (EOFBlob(image))
399
529
              ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,
400
4.24M
                                      image);
401
4.24M
            *p++=(ReadBlobLSBShort(image) >> 8);
402
4.24M
          }
403
66.5k
      colormap_entries=MagickArraySize(number_colormaps,map_length);
404
66.5k
    }
405
89.9k
  if (rle_header.Flags & CommentsFlag)
406
20.9k
    {
407
20.9k
      char
408
20.9k
        *comment;
409
410
20.9k
      unsigned int
411
20.9k
        length;
412
413
      /*
414
        Read image comment.
415
416
        The comment block contains any number of null-terminated
417
        text strings. These strings will conventionally be of the
418
        form "name=value", allowing for easy retrieval of specific
419
        information. However, there is no restriction that a given
420
        name appear only once, and a comment may contain an
421
        arbitrary string.
422
      */
423
20.9k
      length=ReadBlobLSBShort(image);
424
20.9k
      comment=MagickAllocateResourceLimitedMemory(char *,(size_t) length+1);
425
20.9k
      if (comment == (char *) NULL)
426
0
        {
427
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
428
0
                                "Failed to allocate %u bytes for comment",
429
0
                                length+1);
430
0
          ThrowRLEReaderException(ResourceLimitError,MemoryAllocationFailed,
431
0
                                  image);
432
0
        }
433
20.9k
      if (ReadBlob(image,length,comment) != length)
434
3.61k
        {
435
3.61k
          MagickFreeResourceLimitedMemory(comment);
436
3.61k
          ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
437
0
        }
438
17.3k
      comment[length]='\0';
439
      /*
440
        Delimit multiple comments with '\n' so they fit in one string.
441
      */
442
17.3k
      if (length)
443
1.52M
        for (i=0; i < length-1; i++)
444
1.52M
          {
445
1.52M
            if (comment[i]=='\0')
446
349k
              comment[i]='\n';
447
1.52M
          }
448
17.3k
      (void) SetImageAttribute(image,"comment",comment);
449
17.3k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
450
17.3k
                            "Comment: '%s'", comment);
451
17.3k
      MagickFreeResourceLimitedMemory(comment);
452
17.3k
      if ((length & 0x01) == 0)
453
11.6k
        (void) ReadBlobByte(image);
454
17.3k
    }
455
456
86.3k
  if (EOFBlob(image))
457
84.3k
    ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
458
459
84.3k
  if (image_info->ping)
460
0
    {
461
0
      MagickFreeResourceLimitedMemory(colormap);
462
0
      CloseBlob(image);
463
0
      StopTimer(&image->timer);
464
0
      return(image);
465
0
    }
466
467
84.3k
  if (CheckImagePixelLimits(image, exception) != MagickPass)
468
56.8k
    ThrowRLEReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
469
470
  /*
471
    Allocate RLE pixels.
472
  */
473
56.8k
  number_pixels=MagickArraySize(image->columns,image->rows);
474
56.8k
  rle_bytes=MagickArraySize(number_pixels,number_planes);
475
56.8k
  if ((number_pixels == 0) || (rle_bytes == 0))
476
56.8k
    ThrowRLEReaderException(ResourceLimitError,MemoryAllocationFailed,image);
477
56.8k
  rle_pixels=MagickAllocateResourceLimitedArray(unsigned char *,number_pixels,
478
56.8k
                                 number_planes);
479
56.8k
  if (rle_pixels == (unsigned char *) NULL)
480
56.8k
    ThrowRLEReaderException(ResourceLimitError,MemoryAllocationFailed,image);
481
56.8k
  (void) memset(rle_pixels,0,rle_bytes);
482
56.8k
  if ((rle_header.Flags & ClearFirstFlag) &&
483
56.0k
      !(rle_header.Flags & NoBackgroundFlag))
484
55.9k
    {
485
55.9k
      int
486
55.9k
        j;
487
488
      /*
489
        Set background color.
490
      */
491
55.9k
      p=rle_pixels;
492
4.10M
      for (i=0; i < number_pixels; i++)
493
4.04M
        {
494
4.04M
          if (!image->matte)
495
8.85M
            for (j=0; j < (int) number_planes; j++)
496
4.82M
              *p++=background_color[j];
497
18.9k
          else
498
18.9k
            {
499
75.9k
              for (j=0; j < ((int) number_planes-1); j++)
500
56.9k
                *p++=background_color[j];
501
18.9k
              *p++=0;  /* initialize matte channel */
502
18.9k
            }
503
4.04M
        }
504
55.9k
    }
505
  /*
506
    Read runlength-encoded image.
507
  */
508
56.8k
  plane=0;
509
56.8k
  x=0;
510
56.8k
  y=0;
511
56.8k
  opcode=ReadBlobByte(image);
512
56.8k
  if (opcode == EOF)
513
51.5k
    ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
514
51.5k
  do
515
11.6M
    {
516
11.6M
      switch (opcode & 0x3f)
517
11.6M
        {
518
5.95M
        case SkipLinesOp:
519
5.95M
          {
520
5.95M
            operand=ReadBlobByte(image);
521
5.95M
            if (operand == EOF)
522
5.95M
              ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
523
5.95M
            if (opcode & 0x40)
524
5.86M
              {
525
5.86M
                operand=ReadBlobLSBShort(image);
526
5.86M
                if (EOFBlob(image))
527
5.86M
                  ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
528
5.86M
              }
529
5.95M
            x=0;
530
5.95M
            y+=operand;
531
5.95M
            break;
532
5.95M
          }
533
61.8k
        case SetColorOp:
534
61.8k
          {
535
61.8k
            operand=ReadBlobByte(image);
536
61.8k
            if (operand == EOF)
537
61.2k
              ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
538
61.2k
            plane=(unsigned char) operand;
539
61.2k
            if (plane == 255)
540
12.2k
              plane=(unsigned char) (number_planes-1);
541
61.2k
            x=0;
542
61.2k
            break;
543
61.8k
          }
544
58.9k
        case SkipPixelsOp:
545
58.9k
          {
546
58.9k
            operand=ReadBlobByte(image);
547
58.9k
            if (operand == EOF)
548
56.9k
              ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
549
56.9k
            if (opcode & 0x40)
550
29.0k
              {
551
29.0k
                operand=ReadBlobLSBShort(image);
552
29.0k
                if (EOFBlob(image))
553
28.7k
                  ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
554
28.7k
              }
555
56.6k
            x+=operand;
556
56.6k
            break;
557
56.9k
          }
558
30.9k
        case ByteDataOp:
559
30.9k
          {
560
30.9k
            operand=ReadBlobByte(image);
561
30.9k
            if (operand == EOF)
562
28.9k
              ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
563
28.9k
            if (opcode & 0x40)
564
7.14k
              {
565
7.14k
                operand=ReadBlobLSBShort(image);
566
7.14k
                if (EOFBlob(image))
567
6.06k
                  ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
568
6.06k
              }
569
27.8k
            offset=(((size_t) image->rows-y-1)*image->columns*number_planes)+x*(size_t) number_planes+plane;
570
27.8k
            operand++;
571
27.8k
            if ((SIZE_MAX - (size_t) rle_pixels) < offset)
572
24.0k
              ThrowRLEReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image);
573
24.0k
            p=rle_pixels+offset;
574
158k
            for (i=0; i < (unsigned int) operand; i++)
575
138k
              {
576
138k
                pixel=ReadBlobByte(image);
577
138k
                if (pixel == EOF)
578
137k
                  ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
579
137k
                if ((p >= rle_pixels) && (p < rle_pixels+rle_bytes))
580
134k
                  *p=(unsigned char) pixel;
581
3.76k
                else
582
134k
                  ThrowRLEReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image);
583
134k
                p+=number_planes;
584
134k
              }
585
19.2k
            if (operand & 0x01)
586
16.0k
              (void) ReadBlobByte(image);
587
19.2k
            x+=operand;
588
19.2k
            break;
589
24.0k
          }
590
18.0k
        case RunDataOp:
591
18.0k
          {
592
18.0k
            operand=ReadBlobByte(image);
593
18.0k
            if (operand == EOF)
594
17.1k
              ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
595
17.1k
            if (opcode & 0x40)
596
8.62k
              {
597
8.62k
                operand=ReadBlobLSBShort(image);
598
8.62k
                if (EOFBlob(image))
599
7.21k
                  ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
600
7.21k
              }
601
15.7k
            pixel=ReadBlobByte(image);
602
15.7k
            if (pixel == EOF)
603
13.9k
              ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
604
13.9k
            (void) ReadBlobByte(image);
605
13.9k
            operand++;
606
13.9k
            offset=(((size_t) image->rows-y-1)*image->columns*number_planes)+x*(size_t) number_planes+plane;
607
13.9k
            if ((SIZE_MAX - (size_t) rle_pixels) < offset)
608
12.6k
              ThrowRLEReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image);
609
12.6k
            p=rle_pixels+offset;
610
221k
            for (i=0; i < (unsigned int) operand; i++)
611
214k
              {
612
214k
                if ((p >= rle_pixels) && (p < rle_pixels+rle_bytes))
613
208k
                  *p=pixel;
614
6.13k
                else
615
208k
                  ThrowRLEReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image);
616
208k
                p+=number_planes;
617
208k
              }
618
6.51k
            x+=operand;
619
6.51k
            break;
620
12.6k
          }
621
5.50M
        default:
622
5.50M
          break;
623
11.6M
        }
624
11.6M
      opcode=ReadBlobByte(image);
625
11.6M
      if (opcode == EOF)
626
11.5M
        ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
627
11.5M
    } while (((opcode & 0x3f) != EOFOp) && (opcode != EOF));
628
9.96k
  if (number_colormaps != 0)
629
8.18k
    {
630
8.18k
      unsigned int
631
8.18k
        mask;
632
633
      /*
634
        Apply colormap affineation to image.
635
      */
636
8.18k
      mask=(unsigned int) (map_length-1);
637
8.18k
      p=rle_pixels;
638
8.18k
      if (number_colormaps == 1)
639
5.97M
        for (i=0; i < number_pixels; i++)
640
5.97M
          {
641
5.97M
            index=*p & mask;
642
5.97M
            VerifyColormapIndexWithColors(image,index,colormap_entries);
643
5.97M
            *p=colormap[index];
644
5.97M
            p++;
645
5.97M
          }
646
5.68k
      else
647
5.68k
        if ((number_planes >= 3) && (number_colormaps >= 3))
648
229k
          for (i=0; i < number_pixels; i++)
649
963k
            for (x=0; x < number_planes; x++)
650
735k
              {
651
735k
                index=x*(unsigned int) map_length+(*p & mask);
652
735k
                VerifyColormapIndexWithColors(image,index,colormap_entries);
653
735k
                *p=colormap[index];
654
735k
                p++;
655
735k
              }
656
8.18k
    }
657
  /*
658
    Initialize image structure.
659
  */
660
9.96k
  if (number_planes >= 3)
661
905
    {
662
      /*
663
        Convert raster image to DirectClass pixel packets.
664
      */
665
905
      p=rle_pixels;
666
37.2k
      for (y=0; y < image->rows; y++)
667
36.3k
        {
668
36.3k
          q=SetImagePixels(image,0,y,image->columns,1);
669
36.3k
          if (q == (PixelPacket *) NULL)
670
0
            break;
671
358k
          for (x=0; x < image->columns; x++)
672
322k
            {
673
322k
              q->red=ScaleCharToQuantum(*p++);
674
322k
              q->green=ScaleCharToQuantum(*p++);
675
322k
              q->blue=ScaleCharToQuantum(*p++);
676
322k
              if (image->matte)
677
85.3k
                q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(*p++));
678
322k
              q++;
679
322k
            }
680
36.3k
          if (!SyncImagePixels(image))
681
0
            break;
682
36.3k
          if (image->previous == (Image *) NULL)
683
36.3k
            if (QuantumTick(y,image->rows))
684
9.90k
              if (!MagickMonitorFormatted(y,image->rows,exception,
685
9.90k
                                          LoadImageText,image->filename,
686
9.90k
            image->columns,image->rows))
687
0
                break;
688
36.3k
        }
689
905
    }
690
9.05k
  else
691
9.05k
    {
692
      /*
693
        Create colormap.
694
      */
695
9.05k
      if (number_colormaps == 0)
696
1.66k
        map_length=256;
697
9.05k
      if (((unsigned long) map_length != map_length) ||
698
9.05k
          (!AllocateImageColormap(image,(unsigned long) map_length)))
699
0
        ThrowRLEReaderException(ResourceLimitError,MemoryAllocationFailed,
700
9.05k
                                image);
701
9.05k
      p=colormap;
702
9.05k
      if (number_colormaps == 1)
703
13.7k
        for (i=0; i < image->colors; i++)
704
11.2k
          {
705
            /*
706
              Pseudocolor.
707
            */
708
11.2k
            image->colormap[i].red=ScaleCharToQuantum(i);
709
11.2k
            image->colormap[i].green=ScaleCharToQuantum(i);
710
11.2k
            image->colormap[i].blue=ScaleCharToQuantum(i);
711
11.2k
          }
712
6.64k
      else
713
6.64k
        if (number_colormaps > 1)
714
36.6k
          for (i=0; i < image->colors; i++)
715
31.7k
            {
716
31.7k
              image->colormap[i].red=ScaleCharToQuantum(*p);
717
31.7k
              image->colormap[i].green=ScaleCharToQuantum(*(p+map_length));
718
31.7k
              if (number_colormaps > 2)
719
1.75k
                image->colormap[i].blue=ScaleCharToQuantum(*(p+map_length*2));
720
29.9k
              else
721
29.9k
                image->colormap[i].blue=0U;
722
31.7k
              p++;
723
31.7k
            }
724
9.05k
      p=rle_pixels;
725
9.05k
      if (!image->matte)
726
9.05k
        {
727
          /*
728
            Convert raster image to PseudoClass pixel packets.
729
          */
730
121k
          for (y=0; y < image->rows; y++)
731
112k
            {
732
112k
              q=SetImagePixels(image,0,y,image->columns,1);
733
112k
              if (q == (PixelPacket *) NULL)
734
0
                break;
735
112k
              indexes=AccessMutableIndexes(image);
736
25.7M
              for (x=0; x < image->columns; x++)
737
25.6M
                indexes[x]=(*p++);
738
112k
              if (!SyncImagePixels(image))
739
0
                break;
740
112k
              if (image->previous == (Image *) NULL)
741
112k
                if (QuantumTick(y,image->rows))
742
27.2k
                  if (!MagickMonitorFormatted(y,image->rows,exception,
743
27.2k
                                              LoadImageText,image->filename,
744
27.2k
                image->columns,image->rows))
745
0
                    break;
746
112k
            }
747
9.05k
          (void) SyncImage(image);
748
9.05k
        }
749
0
      else
750
0
        {
751
          /*
752
            Image has a matte channel-- promote to DirectClass.
753
          */
754
0
          for (y=0; y < image->rows; y++)
755
0
            {
756
0
              q=SetImagePixels(image,0,y,image->columns,1);
757
0
              if (q == (PixelPacket *) NULL)
758
0
                break;
759
0
              for (x=0; x < image->columns; x++)
760
0
                {
761
0
                  index=*p++;
762
0
                  VerifyColormapIndex(image,index);
763
0
                  q->red=image->colormap[index].red;
764
0
                  index=*p++;
765
0
                  VerifyColormapIndex(image,index);
766
0
                  q->green=image->colormap[index].green;
767
0
                  index=*p++;
768
0
                  VerifyColormapIndex(image,index);
769
0
                  q->blue=image->colormap[index].blue;
770
0
                  q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(*p++));
771
0
                  q++;
772
0
                }
773
0
              if (!SyncImagePixels(image))
774
0
                break;
775
0
              if (image->previous == (Image *) NULL)
776
0
                if (QuantumTick(y,image->rows))
777
0
                  if (!MagickMonitorFormatted(y,image->rows,exception,
778
0
                                              LoadImageText,
779
0
                                              image->filename,
780
0
                image->columns,image->rows))
781
0
                    break;
782
0
            }
783
0
          MagickFreeMemory(image->colormap);
784
0
          image->colormap=(PixelPacket *) NULL;
785
0
          image->storage_class=DirectClass;
786
0
          image->colors=0;
787
0
        }
788
9.05k
    }
789
9.96k
  MagickFreeResourceLimitedMemory(colormap);
790
9.96k
  MagickFreeResourceLimitedMemory(rle_pixels);
791
9.96k
  if (EOFBlob(image))
792
0
    {
793
0
      ThrowRLEReaderException(CorruptImageError,UnexpectedEndOfFile,image);
794
0
    }
795
9.96k
  CloseBlob(image);
796
9.96k
  StopTimer(&image->timer);
797
9.96k
  return(image);
798
9.96k
}
799

800
/*
801
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
802
%                                                                             %
803
%                                                                             %
804
%                                                                             %
805
%   R e g i s t e r R L E I m a g e                                           %
806
%                                                                             %
807
%                                                                             %
808
%                                                                             %
809
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
810
%
811
%  Method RegisterRLEImage adds attributes for the RLE image format to
812
%  the list of supported formats.  The attributes include the image format
813
%  tag, a method to read and/or write the format, whether the format
814
%  supports the saving of more than one frame to the same file or blob,
815
%  whether the format supports native in-memory I/O, and a brief
816
%  description of the format.
817
%
818
%  The format of the RegisterRLEImage method is:
819
%
820
%      RegisterRLEImage(void)
821
%
822
*/
823
ModuleExport void RegisterRLEImage(void)
824
5
{
825
5
  MagickInfo
826
5
    *entry;
827
828
5
  entry=SetMagickInfo("RLE");
829
5
  entry->decoder=(DecoderHandler) ReadRLEImage;
830
5
  entry->magick=(MagickHandler) IsRLE;
831
5
  entry->adjoin=False;
832
5
  entry->description="Utah Run length encoded image";
833
5
  entry->module="RLE";
834
5
  entry->coder_class=UnstableCoderClass;
835
5
  (void) RegisterMagickInfo(entry);
836
5
}
837

838
/*
839
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
840
%                                                                             %
841
%                                                                             %
842
%                                                                             %
843
%   U n r e g i s t e r R L E I m a g e                                       %
844
%                                                                             %
845
%                                                                             %
846
%                                                                             %
847
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
848
%
849
%  Method UnregisterRLEImage removes format registrations made by the
850
%  RLE module from the list of supported formats.
851
%
852
%  The format of the UnregisterRLEImage method is:
853
%
854
%      UnregisterRLEImage(void)
855
%
856
*/
857
ModuleExport void UnregisterRLEImage(void)
858
0
{
859
0
  (void) UnregisterMagickInfo("RLE");
860
0
}