Coverage Report

Created: 2026-02-14 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/rla.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            RRRR   L       AAA                               %
7
%                            R   R  L      A   A                              %
8
%                            RRRR   L      AAAAA                              %
9
%                            R R    L      A   A                              %
10
%                            R  R   LLLLL  A   A                              %
11
%                                                                             %
12
%                                                                             %
13
%                      Read Alias/Wavefront Image Format                      %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                                 July 1992                                   %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
21
%  dedicated to making software imaging solutions freely available.           %
22
%                                                                             %
23
%  You may not use this file except in compliance with the License.  You may  %
24
%  obtain a copy of the License at                                            %
25
%                                                                             %
26
%    https://imagemagick.org/license/                                         %
27
%                                                                             %
28
%  Unless required by applicable law or agreed to in writing, software        %
29
%  distributed under the License is distributed on an "AS IS" BASIS,          %
30
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31
%  See the License for the specific language governing permissions and        %
32
%  limitations under the License.                                             %
33
%                                                                             %
34
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
%
36
%
37
*/
38

39
/*
40
  Include declarations.
41
*/
42
#include "MagickCore/studio.h"
43
#include "MagickCore/property.h"
44
#include "MagickCore/blob.h"
45
#include "MagickCore/blob-private.h"
46
#include "MagickCore/cache.h"
47
#include "MagickCore/exception.h"
48
#include "MagickCore/exception-private.h"
49
#include "MagickCore/image.h"
50
#include "MagickCore/image-private.h"
51
#include "MagickCore/list.h"
52
#include "MagickCore/magick.h"
53
#include "MagickCore/memory_.h"
54
#include "MagickCore/monitor.h"
55
#include "MagickCore/monitor-private.h"
56
#include "MagickCore/pixel-accessor.h"
57
#include "MagickCore/quantum-private.h"
58
#include "MagickCore/static.h"
59
#include "MagickCore/string_.h"
60
#include "MagickCore/module.h"
61

62
/*
63
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64
%                                                                             %
65
%                                                                             %
66
%                                                                             %
67
%   R e a d R L A I m a g e                                                   %
68
%                                                                             %
69
%                                                                             %
70
%                                                                             %
71
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72
%
73
%  ReadRLAImage() reads a run-length encoded Wavefront RLA image file
74
%  and returns it.  It allocates the memory necessary for the new Image
75
%  structure and returns a pointer to the new image.
76
%
77
%  Note:  This module was contributed by Lester Vecsey (master@internexus.net).
78
%
79
%  The format of the ReadRLAImage method is:
80
%
81
%      Image *ReadRLAImage(const ImageInfo *image_info,ExceptionInfo *exception)
82
%
83
%  A description of each parameter follows:
84
%
85
%    o image_info: the image info.
86
%
87
%    o exception: return any errors or warnings in this structure.
88
%
89
*/
90
static Image *ReadRLAImage(const ImageInfo *image_info,ExceptionInfo *exception)
91
645
{
92
645
  typedef struct _WindowFrame
93
645
  {
94
645
    short
95
645
      left,
96
645
      right,
97
645
      bottom,
98
645
      top;
99
645
  } WindowFrame;
100
101
645
  typedef struct _RLAInfo
102
645
  {
103
645
    WindowFrame
104
645
      window,
105
645
      active_window;
106
107
645
    short
108
645
      frame,
109
645
      storage_type,
110
645
      number_channels,
111
645
      number_matte_channels,
112
645
      number_auxiliary_channels,
113
645
      revision;
114
115
645
    char
116
645
      gamma[16+1],
117
645
      red_primary[24+1],
118
645
      green_primary[24+1],
119
645
      blue_primary[24+1],
120
645
      white_point[24+1];
121
122
645
    int
123
645
      job_number;
124
125
645
    char
126
645
      name[128+1],
127
645
      description[128+1],
128
645
      program[64+1],
129
645
      machine[32+1],
130
645
      user[32+1],
131
645
      date[20+1],
132
645
      aspect[24+1],
133
645
      aspect_ratio[8+1],
134
645
      chan[32+1];
135
136
645
    short
137
645
      field;
138
139
645
    char
140
645
      time[12],
141
645
      filter[32];
142
143
645
    short
144
645
      bits_per_channel,
145
645
      matte_type,
146
645
      matte_bits,
147
645
      auxiliary_type,
148
645
      auxiliary_bits;
149
150
645
    char
151
645
      auxiliary[32+1],
152
645
      space[36+1];
153
154
645
    int
155
645
      next;
156
645
  } RLAInfo;
157
158
645
  Image
159
645
    *image;
160
161
645
  int
162
645
    channel,
163
645
    length,
164
645
    runlength;
165
166
645
  MagickBooleanType
167
645
    status;
168
169
645
  MagickOffsetType
170
645
    offset,
171
645
    *scanlines;
172
173
645
  ssize_t
174
645
    i,
175
645
    x;
176
177
645
  Quantum
178
645
    *q;
179
180
645
  ssize_t
181
645
    count,
182
645
    y;
183
184
645
  RLAInfo
185
645
    rla_info;
186
187
645
  unsigned char
188
645
    byte;
189
190
  /*
191
    Open image file.
192
  */
193
645
  assert(image_info != (const ImageInfo *) NULL);
194
645
  assert(image_info->signature == MagickCoreSignature);
195
645
  assert(exception != (ExceptionInfo *) NULL);
196
645
  assert(exception->signature == MagickCoreSignature);
197
645
  if (IsEventLogging() != MagickFalse)
198
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
199
0
      image_info->filename);
200
645
  image=AcquireImage(image_info,exception);
201
645
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
202
645
  if (status == MagickFalse)
203
0
    {
204
0
      image=DestroyImageList(image);
205
0
      return((Image *) NULL);
206
0
    }
207
645
  (void) memset(&rla_info,0,sizeof(rla_info));
208
645
  rla_info.window.left=(short) ReadBlobMSBShort(image);
209
645
  rla_info.window.right=(short) ReadBlobMSBShort(image);
210
645
  rla_info.window.bottom=(short) ReadBlobMSBShort(image);
211
645
  rla_info.window.top=(short) ReadBlobMSBShort(image);
212
645
  rla_info.active_window.left=(short) ReadBlobMSBShort(image);
213
645
  rla_info.active_window.right=(short) ReadBlobMSBShort(image);
214
645
  rla_info.active_window.bottom=(short) ReadBlobMSBShort(image);
215
645
  rla_info.active_window.top=(short) ReadBlobMSBShort(image);
216
645
  rla_info.frame=(short) ReadBlobMSBShort(image);
217
645
  rla_info.storage_type=(short) ReadBlobMSBShort(image);
218
645
  rla_info.number_channels=(short) ReadBlobMSBShort(image);
219
645
  if (rla_info.number_channels < 0)
220
640
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
221
640
  rla_info.number_matte_channels=(short) ReadBlobMSBShort(image);
222
640
  if (rla_info.number_matte_channels < 0)
223
637
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
224
637
  if ((rla_info.number_channels > 3) || (rla_info.number_matte_channels > 3))
225
597
    ThrowReaderException(CoderError,"Unsupported number of channels");
226
597
  if (rla_info.number_channels == 0)
227
544
    rla_info.number_channels=3;
228
597
  rla_info.number_channels+=rla_info.number_matte_channels;
229
597
  rla_info.number_auxiliary_channels=(short) ReadBlobMSBShort(image);
230
597
  rla_info.revision=(short) ReadBlobMSBShort(image);
231
597
  (void) ReadBlob(image,16,(unsigned char *) rla_info.gamma);
232
597
  (void) ReadBlob(image,24,(unsigned char *) rla_info.red_primary);
233
597
  (void) ReadBlob(image,24,(unsigned char *) rla_info.green_primary);
234
597
  (void) ReadBlob(image,24,(unsigned char *) rla_info.blue_primary);
235
597
  (void) ReadBlob(image,24,(unsigned char *) rla_info.white_point);
236
597
  rla_info.job_number=ReadBlobMSBSignedLong(image);
237
597
  (void) ReadBlob(image,128,(unsigned char *) rla_info.name);
238
597
  (void) ReadBlob(image,128,(unsigned char *) rla_info.description);
239
597
  rla_info.description[127]='\0';
240
597
  (void) ReadBlob(image,64,(unsigned char *) rla_info.program);
241
597
  (void) ReadBlob(image,32,(unsigned char *) rla_info.machine);
242
597
  (void) ReadBlob(image,32,(unsigned char *) rla_info.user);
243
597
  (void) ReadBlob(image,20,(unsigned char *) rla_info.date);
244
597
  (void) ReadBlob(image,24,(unsigned char *) rla_info.aspect);
245
597
  (void) ReadBlob(image,8,(unsigned char *) rla_info.aspect_ratio);
246
597
  (void) ReadBlob(image,32,(unsigned char *) rla_info.chan);
247
597
  rla_info.field=(short) ReadBlobMSBShort(image);
248
597
  (void) ReadBlob(image,12,(unsigned char *) rla_info.time);
249
597
  (void) ReadBlob(image,32,(unsigned char *) rla_info.filter);
250
597
  rla_info.bits_per_channel=(short) ReadBlobMSBShort(image);
251
597
  rla_info.matte_type=(short) ReadBlobMSBShort(image);
252
597
  rla_info.matte_bits=(short) ReadBlobMSBShort(image);
253
597
  rla_info.auxiliary_type=(short) ReadBlobMSBShort(image);
254
597
  rla_info.auxiliary_bits=(short) ReadBlobMSBShort(image);
255
597
  (void) ReadBlob(image,32,(unsigned char *) rla_info.auxiliary);
256
597
  count=ReadBlob(image,36,(unsigned char *) rla_info.space);
257
597
  if ((size_t) count != 36)
258
438
    ThrowReaderException(CorruptImageError,"UnableToReadImageData");
259
438
  rla_info.next=ReadBlobMSBSignedLong(image);
260
  /*
261
    Initialize image structure.
262
  */
263
438
  image->alpha_trait=rla_info.number_matte_channels != 0 ? BlendPixelTrait : 
264
438
    UndefinedPixelTrait;
265
438
  image->columns=(size_t) (rla_info.active_window.right-
266
438
    rla_info.active_window.left+1);
267
438
  image->rows=(size_t) (rla_info.active_window.top-
268
438
    rla_info.active_window.bottom+1);
269
438
  if (image_info->ping != MagickFalse)
270
0
    {
271
0
      (void) CloseBlob(image);
272
0
      return(GetFirstImageInList(image));
273
0
    }
274
438
  status=SetImageExtent(image,image->columns,image->rows,exception);
275
438
  if (status == MagickFalse)
276
86
    return(DestroyImageList(image));
277
352
  scanlines=(MagickOffsetType *) AcquireQuantumMemory(image->rows,
278
352
    sizeof(*scanlines));
279
352
  if (scanlines == (MagickOffsetType *) NULL)
280
352
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
281
352
  if (*rla_info.description != '\0')
282
226
    (void) SetImageProperty(image,"comment",rla_info.description,exception);
283
  /*
284
    Read offsets to each scanline data.
285
  */
286
50.6k
  for (i=0; i < (ssize_t) image->rows; i++)
287
50.2k
    scanlines[i]=(MagickOffsetType) ReadBlobMSBSignedLong(image);
288
352
  if (EOFBlob(image) != MagickFalse)
289
66
    {
290
66
      scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
291
66
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
292
0
    }
293
  /*
294
    Read image data.
295
  */
296
5.53k
  for (y=0; y < (ssize_t) image->rows; y++)
297
5.47k
  {
298
5.47k
    offset=SeekBlob(image,scanlines[(ssize_t) image->rows-y-1],SEEK_SET);
299
5.47k
    if (offset < 0)
300
46
      {
301
46
        scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
302
46
        ThrowReaderException(CorruptImageError,"ImproperImageHeader");
303
0
      }
304
5.42k
    x=0;
305
27.1k
    for (channel=0; channel < (int) rla_info.number_channels; channel++)
306
21.6k
    {
307
21.6k
      length=ReadBlobMSBSignedShort(image);
308
1.59M
      while (length > 0)
309
1.58M
      {
310
1.58M
        byte=(unsigned char) ReadBlobByte(image);
311
1.58M
        runlength=byte;
312
1.58M
        if (byte > 127)
313
890k
          runlength=byte-256;
314
1.58M
        length--;
315
1.58M
        if (length == 0)
316
3.26k
          break;
317
1.57M
        if (runlength < 0)
318
889k
          {
319
2.93M
            while (runlength < 0)
320
2.04M
            {
321
2.04M
              q=GetAuthenticPixels(image,x % (ssize_t) image->columns,y,1,1,
322
2.04M
                exception);
323
2.04M
              if (q == (Quantum *) NULL)
324
0
                break;
325
2.04M
              byte=(unsigned char) ReadBlobByte(image);
326
2.04M
              length--;
327
2.04M
              switch (channel)
328
2.04M
              {
329
719k
                case 0:
330
719k
                {
331
719k
                  SetPixelRed(image,ScaleCharToQuantum(byte),q);
332
719k
                  break;
333
0
                }
334
525k
                case 1:
335
525k
                {
336
525k
                  SetPixelGreen(image,ScaleCharToQuantum(byte),q);
337
525k
                  break;
338
0
                }
339
564k
                case 2:
340
564k
                {
341
564k
                  SetPixelBlue(image,ScaleCharToQuantum(byte),q);
342
564k
                  break;
343
0
                }
344
184k
                case 3:
345
234k
                default:
346
234k
                {
347
234k
                  SetPixelAlpha(image,ScaleCharToQuantum(byte),q);
348
234k
                  break;
349
184k
                }
350
2.04M
              }
351
2.04M
              if (SyncAuthenticPixels(image,exception) == MagickFalse)
352
0
                break;
353
2.04M
              x++;
354
2.04M
              runlength++;
355
2.04M
            }
356
889k
            continue;
357
889k
          }
358
688k
        byte=(unsigned char) ReadBlobByte(image);
359
688k
        length--;
360
688k
        runlength++;
361
688k
        do
362
8.62M
        {
363
8.62M
          q=GetAuthenticPixels(image,x % (ssize_t) image->columns,y,1,1,
364
8.62M
            exception);
365
8.62M
          if (q == (Quantum *) NULL)
366
0
            break;
367
8.62M
          switch (channel)
368
8.62M
          {
369
2.24M
            case 0:
370
2.24M
            {
371
2.24M
              SetPixelRed(image,ScaleCharToQuantum(byte),q);
372
2.24M
              break;
373
0
            }
374
3.14M
            case 1:
375
3.14M
            {
376
3.14M
              SetPixelGreen(image,ScaleCharToQuantum(byte),q);
377
3.14M
              break;
378
0
            }
379
2.48M
            case 2:
380
2.48M
            {
381
2.48M
              SetPixelBlue(image,ScaleCharToQuantum(byte),q);
382
2.48M
              break;
383
0
            }
384
644k
            case 3:
385
753k
            default:
386
753k
            {
387
753k
              SetPixelAlpha(image,ScaleCharToQuantum(byte),q);
388
753k
              break;
389
644k
            }
390
8.62M
          }
391
8.62M
          if (SyncAuthenticPixels(image,exception) == MagickFalse)
392
0
            break;
393
8.62M
          x++;
394
8.62M
          runlength--;
395
8.62M
        }
396
8.62M
        while (runlength > 0);
397
688k
      }
398
21.6k
    }
399
5.42k
    if ((x/(ssize_t) rla_info.number_channels) > (ssize_t) image->columns)
400
104
      {
401
104
        scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
402
104
        ThrowReaderException(CorruptImageError,"CorruptImage");
403
0
      }
404
5.32k
    if (EOFBlob(image) != MagickFalse)
405
73
      break;
406
5.24k
    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
407
5.24k
      image->rows);
408
5.24k
    if (status == MagickFalse)
409
0
      break;
410
5.24k
  }
411
136
  scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
412
136
  if (EOFBlob(image) != MagickFalse)
413
73
    ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
414
136
      image->filename);
415
136
  if (CloseBlob(image) == MagickFalse)
416
0
    status=MagickFalse;
417
136
  if (status == MagickFalse)
418
0
    return(DestroyImageList(image));
419
136
  return(GetFirstImageInList(image));
420
136
}
421

422
/*
423
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
424
%                                                                             %
425
%                                                                             %
426
%                                                                             %
427
%   R e g i s t e r R L A I m a g e                                           %
428
%                                                                             %
429
%                                                                             %
430
%                                                                             %
431
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
432
%
433
%  RegisterRLAImage() adds attributes for the RLA image format to
434
%  the list of supported formats.  The attributes include the image format
435
%  tag, a method to read and/or write the format, whether the format
436
%  supports the saving of more than one frame to the same file or blob,
437
%  whether the format supports native in-memory I/O, and a brief
438
%  description of the format.
439
%
440
%  The format of the RegisterRLAImage method is:
441
%
442
%      size_t RegisterRLAImage(void)
443
%
444
*/
445
ModuleExport size_t RegisterRLAImage(void)
446
9
{
447
9
  MagickInfo
448
9
    *entry;
449
450
9
  entry=AcquireMagickInfo("RLA","RLA","Alias/Wavefront image");
451
9
  entry->decoder=(DecodeImageHandler *) ReadRLAImage;
452
9
  entry->flags^=CoderAdjoinFlag;
453
9
  entry->flags|=CoderDecoderSeekableStreamFlag;
454
9
  (void) RegisterMagickInfo(entry);
455
9
  return(MagickImageCoderSignature);
456
9
}
457

458
/*
459
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
460
%                                                                             %
461
%                                                                             %
462
%                                                                             %
463
%   U n r e g i s t e r R L A I m a g e                                       %
464
%                                                                             %
465
%                                                                             %
466
%                                                                             %
467
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
468
%
469
%  UnregisterRLAImage() removes format registrations made by the
470
%  RLA module from the list of supported formats.
471
%
472
%  The format of the UnregisterRLAImage method is:
473
%
474
%      UnregisterRLAImage(void)
475
%
476
*/
477
ModuleExport void UnregisterRLAImage(void)
478
0
{
479
0
  (void) UnregisterMagickInfo("RLA");
480
0
}