Coverage Report

Created: 2026-11-12 07:35

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
476
{
92
476
  typedef struct _WindowFrame
93
476
  {
94
476
    short
95
476
      left,
96
476
      right,
97
476
      bottom,
98
476
      top;
99
476
  } WindowFrame;
100
101
476
  typedef struct _RLAInfo
102
476
  {
103
476
    WindowFrame
104
476
      window,
105
476
      active_window;
106
107
476
    short
108
476
      frame,
109
476
      storage_type,
110
476
      number_channels,
111
476
      number_matte_channels,
112
476
      number_auxiliary_channels,
113
476
      revision;
114
115
476
    char
116
476
      gamma[16+1],
117
476
      red_primary[24+1],
118
476
      green_primary[24+1],
119
476
      blue_primary[24+1],
120
476
      white_point[24+1];
121
122
476
    int
123
476
      job_number;
124
125
476
    char
126
476
      name[128+1],
127
476
      description[128+1],
128
476
      program[64+1],
129
476
      machine[32+1],
130
476
      user[32+1],
131
476
      date[20+1],
132
476
      aspect[24+1],
133
476
      aspect_ratio[8+1],
134
476
      chan[32+1];
135
136
476
    short
137
476
      field;
138
139
476
    char
140
476
      time[12],
141
476
      filter[32];
142
143
476
    short
144
476
      bits_per_channel,
145
476
      matte_type,
146
476
      matte_bits,
147
476
      auxiliary_type,
148
476
      auxiliary_bits;
149
150
476
    char
151
476
      auxiliary[32+1],
152
476
      space[36+1];
153
154
476
    int
155
476
      next;
156
476
  } RLAInfo;
157
158
476
  Image
159
476
    *image;
160
161
476
  int
162
476
    channel,
163
476
    length,
164
476
    runlength;
165
166
476
  MagickBooleanType
167
476
    status;
168
169
476
  MagickOffsetType
170
476
    offset,
171
476
    *scanlines;
172
173
476
  ssize_t
174
476
    i,
175
476
    x;
176
177
476
  Quantum
178
476
    *q;
179
180
476
  ssize_t
181
476
    count,
182
476
    y;
183
184
476
  RLAInfo
185
476
    rla_info;
186
187
476
  unsigned char
188
476
    byte;
189
190
  /*
191
    Open image file.
192
  */
193
476
  assert(image_info != (const ImageInfo *) NULL);
194
476
  assert(image_info->signature == MagickCoreSignature);
195
476
  assert(exception != (ExceptionInfo *) NULL);
196
476
  assert(exception->signature == MagickCoreSignature);
197
476
  if (IsEventLogging() != MagickFalse)
198
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
199
0
      image_info->filename);
200
476
  image=AcquireImage(image_info,exception);
201
476
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
202
476
  if (status == MagickFalse)
203
0
    {
204
0
      image=DestroyImageList(image);
205
0
      return((Image *) NULL);
206
0
    }
207
476
  (void) memset(&rla_info,0,sizeof(rla_info));
208
476
  rla_info.window.left=(short) ReadBlobMSBShort(image);
209
476
  rla_info.window.right=(short) ReadBlobMSBShort(image);
210
476
  rla_info.window.bottom=(short) ReadBlobMSBShort(image);
211
476
  rla_info.window.top=(short) ReadBlobMSBShort(image);
212
476
  rla_info.active_window.left=(short) ReadBlobMSBShort(image);
213
476
  rla_info.active_window.right=(short) ReadBlobMSBShort(image);
214
476
  rla_info.active_window.bottom=(short) ReadBlobMSBShort(image);
215
476
  rla_info.active_window.top=(short) ReadBlobMSBShort(image);
216
476
  rla_info.frame=(short) ReadBlobMSBShort(image);
217
476
  rla_info.storage_type=(short) ReadBlobMSBShort(image);
218
476
  rla_info.number_channels=(short) ReadBlobMSBShort(image);
219
476
  if (rla_info.number_channels < 0)
220
471
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
221
471
  rla_info.number_matte_channels=(short) ReadBlobMSBShort(image);
222
471
  if (rla_info.number_matte_channels < 0)
223
464
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
224
464
  if ((rla_info.number_channels > 3) || (rla_info.number_matte_channels > 3))
225
431
    ThrowReaderException(CoderError,"Unsupported number of channels");
226
431
  if (rla_info.number_channels == 0)
227
378
    rla_info.number_channels=3;
228
431
  rla_info.number_channels+=rla_info.number_matte_channels;
229
431
  rla_info.number_auxiliary_channels=(short) ReadBlobMSBShort(image);
230
431
  rla_info.revision=(short) ReadBlobMSBShort(image);
231
431
  (void) ReadBlob(image,16,(unsigned char *) rla_info.gamma);
232
431
  (void) ReadBlob(image,24,(unsigned char *) rla_info.red_primary);
233
431
  (void) ReadBlob(image,24,(unsigned char *) rla_info.green_primary);
234
431
  (void) ReadBlob(image,24,(unsigned char *) rla_info.blue_primary);
235
431
  (void) ReadBlob(image,24,(unsigned char *) rla_info.white_point);
236
431
  rla_info.job_number=ReadBlobMSBSignedLong(image);
237
431
  (void) ReadBlob(image,128,(unsigned char *) rla_info.name);
238
431
  (void) ReadBlob(image,128,(unsigned char *) rla_info.description);
239
431
  rla_info.description[127]='\0';
240
431
  (void) ReadBlob(image,64,(unsigned char *) rla_info.program);
241
431
  (void) ReadBlob(image,32,(unsigned char *) rla_info.machine);
242
431
  (void) ReadBlob(image,32,(unsigned char *) rla_info.user);
243
431
  (void) ReadBlob(image,20,(unsigned char *) rla_info.date);
244
431
  (void) ReadBlob(image,24,(unsigned char *) rla_info.aspect);
245
431
  (void) ReadBlob(image,8,(unsigned char *) rla_info.aspect_ratio);
246
431
  (void) ReadBlob(image,32,(unsigned char *) rla_info.chan);
247
431
  rla_info.field=(short) ReadBlobMSBShort(image);
248
431
  (void) ReadBlob(image,12,(unsigned char *) rla_info.time);
249
431
  (void) ReadBlob(image,32,(unsigned char *) rla_info.filter);
250
431
  rla_info.bits_per_channel=(short) ReadBlobMSBShort(image);
251
431
  rla_info.matte_type=(short) ReadBlobMSBShort(image);
252
431
  rla_info.matte_bits=(short) ReadBlobMSBShort(image);
253
431
  rla_info.auxiliary_type=(short) ReadBlobMSBShort(image);
254
431
  rla_info.auxiliary_bits=(short) ReadBlobMSBShort(image);
255
431
  (void) ReadBlob(image,32,(unsigned char *) rla_info.auxiliary);
256
431
  count=ReadBlob(image,36,(unsigned char *) rla_info.space);
257
431
  if ((size_t) count != 36)
258
349
    ThrowReaderException(CorruptImageError,"UnableToReadImageData");
259
349
  rla_info.next=ReadBlobMSBSignedLong(image);
260
  /*
261
    Initialize image structure.
262
  */
263
349
  image->alpha_trait=rla_info.number_matte_channels != 0 ? BlendPixelTrait : 
264
349
    UndefinedPixelTrait;
265
349
  if ((rla_info.active_window.right < rla_info.active_window.left) ||
266
347
      (rla_info.active_window.top < rla_info.active_window.bottom))
267
346
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
268
346
  image->columns=(size_t) (rla_info.active_window.right-
269
346
    rla_info.active_window.left+1);
270
346
  image->rows=(size_t) (rla_info.active_window.top-
271
346
    rla_info.active_window.bottom+1);
272
346
  if (image_info->ping != MagickFalse)
273
0
    {
274
0
      (void) CloseBlob(image);
275
0
      return(GetFirstImageInList(image));
276
0
    }
277
346
  status=SetImageExtent(image,image->columns,image->rows,exception);
278
346
  if (status == MagickFalse)
279
39
    return(DestroyImageList(image));
280
307
  scanlines=(MagickOffsetType *) AcquireQuantumMemory(image->rows,
281
307
    sizeof(*scanlines));
282
307
  if (scanlines == (MagickOffsetType *) NULL)
283
307
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
284
307
  if (*rla_info.description != '\0')
285
184
    (void) SetImageProperty(image,"comment",rla_info.description,exception);
286
  /*
287
    Read offsets to each scanline data.
288
  */
289
70.2k
  for (i=0; i < (ssize_t) image->rows; i++)
290
69.8k
    scanlines[i]=(MagickOffsetType) ReadBlobMSBSignedLong(image);
291
307
  if (EOFBlob(image) != MagickFalse)
292
57
    {
293
57
      scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
294
57
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
295
0
    }
296
  /*
297
    Read image data.
298
  */
299
6.61k
  for (y=0; y < (ssize_t) image->rows; y++)
300
6.55k
  {
301
6.55k
    offset=SeekBlob(image,scanlines[(ssize_t) image->rows-y-1],SEEK_SET);
302
6.55k
    if (offset < 0)
303
47
      {
304
47
        scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
305
47
        ThrowReaderException(CorruptImageError,"ImproperImageHeader");
306
0
      }
307
6.50k
    x=0;
308
30.6k
    for (channel=0; channel < (int) rla_info.number_channels; channel++)
309
24.1k
    {
310
24.1k
      length=ReadBlobMSBSignedShort(image);
311
1.38M
      while (length > 0)
312
1.36M
      {
313
1.36M
        byte=(unsigned char) ReadBlobByte(image);
314
1.36M
        runlength=byte;
315
1.36M
        if (byte > 127)
316
557k
          runlength=byte-256;
317
1.36M
        length--;
318
1.36M
        if (length == 0)
319
4.47k
          break;
320
1.35M
        if (runlength < 0)
321
556k
          {
322
2.63M
            while (runlength < 0)
323
2.08M
            {
324
2.08M
              q=GetAuthenticPixels(image,x % (ssize_t) image->columns,y,1,1,
325
2.08M
                exception);
326
2.08M
              if (q == (Quantum *) NULL)
327
0
                break;
328
2.08M
              byte=(unsigned char) ReadBlobByte(image);
329
2.08M
              length--;
330
2.08M
              switch (channel)
331
2.08M
              {
332
839k
                case 0:
333
839k
                {
334
839k
                  SetPixelRed(image,ScaleCharToQuantum(byte),q);
335
839k
                  break;
336
0
                }
337
373k
                case 1:
338
373k
                {
339
373k
                  SetPixelGreen(image,ScaleCharToQuantum(byte),q);
340
373k
                  break;
341
0
                }
342
663k
                case 2:
343
663k
                {
344
663k
                  SetPixelBlue(image,ScaleCharToQuantum(byte),q);
345
663k
                  break;
346
0
                }
347
146k
                case 3:
348
204k
                default:
349
204k
                {
350
204k
                  SetPixelAlpha(image,ScaleCharToQuantum(byte),q);
351
204k
                  break;
352
146k
                }
353
2.08M
              }
354
2.08M
              if (SyncAuthenticPixels(image,exception) == MagickFalse)
355
0
                break;
356
2.08M
              x++;
357
2.08M
              runlength++;
358
2.08M
            }
359
556k
            continue;
360
556k
          }
361
802k
        byte=(unsigned char) ReadBlobByte(image);
362
802k
        length--;
363
802k
        runlength++;
364
802k
        do
365
11.1M
        {
366
11.1M
          q=GetAuthenticPixels(image,x % (ssize_t) image->columns,y,1,1,
367
11.1M
            exception);
368
11.1M
          if (q == (Quantum *) NULL)
369
0
            break;
370
11.1M
          switch (channel)
371
11.1M
          {
372
3.07M
            case 0:
373
3.07M
            {
374
3.07M
              SetPixelRed(image,ScaleCharToQuantum(byte),q);
375
3.07M
              break;
376
0
            }
377
2.88M
            case 1:
378
2.88M
            {
379
2.88M
              SetPixelGreen(image,ScaleCharToQuantum(byte),q);
380
2.88M
              break;
381
0
            }
382
4.52M
            case 2:
383
4.52M
            {
384
4.52M
              SetPixelBlue(image,ScaleCharToQuantum(byte),q);
385
4.52M
              break;
386
0
            }
387
571k
            case 3:
388
679k
            default:
389
679k
            {
390
679k
              SetPixelAlpha(image,ScaleCharToQuantum(byte),q);
391
679k
              break;
392
571k
            }
393
11.1M
          }
394
11.1M
          if (SyncAuthenticPixels(image,exception) == MagickFalse)
395
0
            break;
396
11.1M
          x++;
397
11.1M
          runlength--;
398
11.1M
        }
399
11.1M
        while (runlength > 0);
400
802k
      }
401
24.1k
    }
402
6.50k
    if ((x/(ssize_t) rla_info.number_channels) > (ssize_t) image->columns)
403
70
      {
404
70
        scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
405
70
        ThrowReaderException(CorruptImageError,"CorruptImage");
406
0
      }
407
6.43k
    if (EOFBlob(image) != MagickFalse)
408
69
      break;
409
6.36k
    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
410
6.36k
      image->rows);
411
6.36k
    if (status == MagickFalse)
412
0
      break;
413
6.36k
  }
414
133
  scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
415
133
  if (EOFBlob(image) != MagickFalse)
416
69
    ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
417
133
      image->filename);
418
133
  if (CloseBlob(image) == MagickFalse)
419
0
    status=MagickFalse;
420
133
  if (GetBlobError(image) != MagickFalse)
421
0
    status=MagickFalse;
422
133
  if (status == MagickFalse)
423
0
    return(DestroyImageList(image));
424
133
  return(GetFirstImageInList(image));
425
133
}
426

427
/*
428
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429
%                                                                             %
430
%                                                                             %
431
%                                                                             %
432
%   R e g i s t e r R L A I m a g e                                           %
433
%                                                                             %
434
%                                                                             %
435
%                                                                             %
436
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
437
%
438
%  RegisterRLAImage() adds attributes for the RLA image format to
439
%  the list of supported formats.  The attributes include the image format
440
%  tag, a method to read and/or write the format, whether the format
441
%  supports the saving of more than one frame to the same file or blob,
442
%  whether the format supports native in-memory I/O, and a brief
443
%  description of the format.
444
%
445
%  The format of the RegisterRLAImage method is:
446
%
447
%      size_t RegisterRLAImage(void)
448
%
449
*/
450
ModuleExport size_t RegisterRLAImage(void)
451
8
{
452
8
  MagickInfo
453
8
    *entry;
454
455
8
  entry=AcquireMagickInfo("RLA","RLA","Alias/Wavefront image");
456
8
  entry->decoder=(DecodeImageHandler *) ReadRLAImage;
457
8
  entry->flags^=CoderAdjoinFlag;
458
8
  entry->flags|=CoderDecoderSeekableStreamFlag;
459
8
  (void) RegisterMagickInfo(entry);
460
8
  return(MagickImageCoderSignature);
461
8
}
462

463
/*
464
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
465
%                                                                             %
466
%                                                                             %
467
%                                                                             %
468
%   U n r e g i s t e r R L A I m a g e                                       %
469
%                                                                             %
470
%                                                                             %
471
%                                                                             %
472
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473
%
474
%  UnregisterRLAImage() removes format registrations made by the
475
%  RLA module from the list of supported formats.
476
%
477
%  The format of the UnregisterRLAImage method is:
478
%
479
%      UnregisterRLAImage(void)
480
%
481
*/
482
ModuleExport void UnregisterRLAImage(void)
483
0
{
484
0
  (void) UnregisterMagickInfo("RLA");
485
0
}