Coverage Report

Created: 2026-03-31 06:56

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
717
{
92
717
  typedef struct _WindowFrame
93
717
  {
94
717
    short
95
717
      left,
96
717
      right,
97
717
      bottom,
98
717
      top;
99
717
  } WindowFrame;
100
101
717
  typedef struct _RLAInfo
102
717
  {
103
717
    WindowFrame
104
717
      window,
105
717
      active_window;
106
107
717
    short
108
717
      frame,
109
717
      storage_type,
110
717
      number_channels,
111
717
      number_matte_channels,
112
717
      number_auxiliary_channels,
113
717
      revision;
114
115
717
    char
116
717
      gamma[16+1],
117
717
      red_primary[24+1],
118
717
      green_primary[24+1],
119
717
      blue_primary[24+1],
120
717
      white_point[24+1];
121
122
717
    int
123
717
      job_number;
124
125
717
    char
126
717
      name[128+1],
127
717
      description[128+1],
128
717
      program[64+1],
129
717
      machine[32+1],
130
717
      user[32+1],
131
717
      date[20+1],
132
717
      aspect[24+1],
133
717
      aspect_ratio[8+1],
134
717
      chan[32+1];
135
136
717
    short
137
717
      field;
138
139
717
    char
140
717
      time[12],
141
717
      filter[32];
142
143
717
    short
144
717
      bits_per_channel,
145
717
      matte_type,
146
717
      matte_bits,
147
717
      auxiliary_type,
148
717
      auxiliary_bits;
149
150
717
    char
151
717
      auxiliary[32+1],
152
717
      space[36+1];
153
154
717
    int
155
717
      next;
156
717
  } RLAInfo;
157
158
717
  Image
159
717
    *image;
160
161
717
  int
162
717
    channel,
163
717
    length,
164
717
    runlength;
165
166
717
  MagickBooleanType
167
717
    status;
168
169
717
  MagickOffsetType
170
717
    offset,
171
717
    *scanlines;
172
173
717
  ssize_t
174
717
    i,
175
717
    x;
176
177
717
  Quantum
178
717
    *q;
179
180
717
  ssize_t
181
717
    count,
182
717
    y;
183
184
717
  RLAInfo
185
717
    rla_info;
186
187
717
  unsigned char
188
717
    byte;
189
190
  /*
191
    Open image file.
192
  */
193
717
  assert(image_info != (const ImageInfo *) NULL);
194
717
  assert(image_info->signature == MagickCoreSignature);
195
717
  assert(exception != (ExceptionInfo *) NULL);
196
717
  assert(exception->signature == MagickCoreSignature);
197
717
  if (IsEventLogging() != MagickFalse)
198
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
199
0
      image_info->filename);
200
717
  image=AcquireImage(image_info,exception);
201
717
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
202
717
  if (status == MagickFalse)
203
0
    {
204
0
      image=DestroyImageList(image);
205
0
      return((Image *) NULL);
206
0
    }
207
717
  (void) memset(&rla_info,0,sizeof(rla_info));
208
717
  rla_info.window.left=(short) ReadBlobMSBShort(image);
209
717
  rla_info.window.right=(short) ReadBlobMSBShort(image);
210
717
  rla_info.window.bottom=(short) ReadBlobMSBShort(image);
211
717
  rla_info.window.top=(short) ReadBlobMSBShort(image);
212
717
  rla_info.active_window.left=(short) ReadBlobMSBShort(image);
213
717
  rla_info.active_window.right=(short) ReadBlobMSBShort(image);
214
717
  rla_info.active_window.bottom=(short) ReadBlobMSBShort(image);
215
717
  rla_info.active_window.top=(short) ReadBlobMSBShort(image);
216
717
  rla_info.frame=(short) ReadBlobMSBShort(image);
217
717
  rla_info.storage_type=(short) ReadBlobMSBShort(image);
218
717
  rla_info.number_channels=(short) ReadBlobMSBShort(image);
219
717
  if (rla_info.number_channels < 0)
220
710
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
221
710
  rla_info.number_matte_channels=(short) ReadBlobMSBShort(image);
222
710
  if (rla_info.number_matte_channels < 0)
223
705
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
224
705
  if ((rla_info.number_channels > 3) || (rla_info.number_matte_channels > 3))
225
666
    ThrowReaderException(CoderError,"Unsupported number of channels");
226
666
  if (rla_info.number_channels == 0)
227
609
    rla_info.number_channels=3;
228
666
  rla_info.number_channels+=rla_info.number_matte_channels;
229
666
  rla_info.number_auxiliary_channels=(short) ReadBlobMSBShort(image);
230
666
  rla_info.revision=(short) ReadBlobMSBShort(image);
231
666
  (void) ReadBlob(image,16,(unsigned char *) rla_info.gamma);
232
666
  (void) ReadBlob(image,24,(unsigned char *) rla_info.red_primary);
233
666
  (void) ReadBlob(image,24,(unsigned char *) rla_info.green_primary);
234
666
  (void) ReadBlob(image,24,(unsigned char *) rla_info.blue_primary);
235
666
  (void) ReadBlob(image,24,(unsigned char *) rla_info.white_point);
236
666
  rla_info.job_number=ReadBlobMSBSignedLong(image);
237
666
  (void) ReadBlob(image,128,(unsigned char *) rla_info.name);
238
666
  (void) ReadBlob(image,128,(unsigned char *) rla_info.description);
239
666
  rla_info.description[127]='\0';
240
666
  (void) ReadBlob(image,64,(unsigned char *) rla_info.program);
241
666
  (void) ReadBlob(image,32,(unsigned char *) rla_info.machine);
242
666
  (void) ReadBlob(image,32,(unsigned char *) rla_info.user);
243
666
  (void) ReadBlob(image,20,(unsigned char *) rla_info.date);
244
666
  (void) ReadBlob(image,24,(unsigned char *) rla_info.aspect);
245
666
  (void) ReadBlob(image,8,(unsigned char *) rla_info.aspect_ratio);
246
666
  (void) ReadBlob(image,32,(unsigned char *) rla_info.chan);
247
666
  rla_info.field=(short) ReadBlobMSBShort(image);
248
666
  (void) ReadBlob(image,12,(unsigned char *) rla_info.time);
249
666
  (void) ReadBlob(image,32,(unsigned char *) rla_info.filter);
250
666
  rla_info.bits_per_channel=(short) ReadBlobMSBShort(image);
251
666
  rla_info.matte_type=(short) ReadBlobMSBShort(image);
252
666
  rla_info.matte_bits=(short) ReadBlobMSBShort(image);
253
666
  rla_info.auxiliary_type=(short) ReadBlobMSBShort(image);
254
666
  rla_info.auxiliary_bits=(short) ReadBlobMSBShort(image);
255
666
  (void) ReadBlob(image,32,(unsigned char *) rla_info.auxiliary);
256
666
  count=ReadBlob(image,36,(unsigned char *) rla_info.space);
257
666
  if ((size_t) count != 36)
258
471
    ThrowReaderException(CorruptImageError,"UnableToReadImageData");
259
471
  rla_info.next=ReadBlobMSBSignedLong(image);
260
  /*
261
    Initialize image structure.
262
  */
263
471
  image->alpha_trait=rla_info.number_matte_channels != 0 ? BlendPixelTrait : 
264
471
    UndefinedPixelTrait;
265
471
  image->columns=(size_t) (rla_info.active_window.right-
266
471
    rla_info.active_window.left+1);
267
471
  image->rows=(size_t) (rla_info.active_window.top-
268
471
    rla_info.active_window.bottom+1);
269
471
  if (image_info->ping != MagickFalse)
270
0
    {
271
0
      (void) CloseBlob(image);
272
0
      return(GetFirstImageInList(image));
273
0
    }
274
471
  status=SetImageExtent(image,image->columns,image->rows,exception);
275
471
  if (status == MagickFalse)
276
93
    return(DestroyImageList(image));
277
378
  scanlines=(MagickOffsetType *) AcquireQuantumMemory(image->rows,
278
378
    sizeof(*scanlines));
279
378
  if (scanlines == (MagickOffsetType *) NULL)
280
378
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
281
378
  if (*rla_info.description != '\0')
282
228
    (void) SetImageProperty(image,"comment",rla_info.description,exception);
283
  /*
284
    Read offsets to each scanline data.
285
  */
286
54.7k
  for (i=0; i < (ssize_t) image->rows; i++)
287
54.3k
    scanlines[i]=(MagickOffsetType) ReadBlobMSBSignedLong(image);
288
378
  if (EOFBlob(image) != MagickFalse)
289
69
    {
290
69
      scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
291
69
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
292
0
    }
293
  /*
294
    Read image data.
295
  */
296
5.50k
  for (y=0; y < (ssize_t) image->rows; y++)
297
5.43k
  {
298
5.43k
    offset=SeekBlob(image,scanlines[(ssize_t) image->rows-y-1],SEEK_SET);
299
5.43k
    if (offset < 0)
300
46
      {
301
46
        scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
302
46
        ThrowReaderException(CorruptImageError,"ImproperImageHeader");
303
0
      }
304
5.38k
    x=0;
305
27.0k
    for (channel=0; channel < (int) rla_info.number_channels; channel++)
306
21.6k
    {
307
21.6k
      length=ReadBlobMSBSignedShort(image);
308
1.65M
      while (length > 0)
309
1.63M
      {
310
1.63M
        byte=(unsigned char) ReadBlobByte(image);
311
1.63M
        runlength=byte;
312
1.63M
        if (byte > 127)
313
951k
          runlength=byte-256;
314
1.63M
        length--;
315
1.63M
        if (length == 0)
316
3.18k
          break;
317
1.62M
        if (runlength < 0)
318
950k
          {
319
3.04M
            while (runlength < 0)
320
2.09M
            {
321
2.09M
              q=GetAuthenticPixels(image,x % (ssize_t) image->columns,y,1,1,
322
2.09M
                exception);
323
2.09M
              if (q == (Quantum *) NULL)
324
0
                break;
325
2.09M
              byte=(unsigned char) ReadBlobByte(image);
326
2.09M
              length--;
327
2.09M
              switch (channel)
328
2.09M
              {
329
798k
                case 0:
330
798k
                {
331
798k
                  SetPixelRed(image,ScaleCharToQuantum(byte),q);
332
798k
                  break;
333
0
                }
334
488k
                case 1:
335
488k
                {
336
488k
                  SetPixelGreen(image,ScaleCharToQuantum(byte),q);
337
488k
                  break;
338
0
                }
339
573k
                case 2:
340
573k
                {
341
573k
                  SetPixelBlue(image,ScaleCharToQuantum(byte),q);
342
573k
                  break;
343
0
                }
344
186k
                case 3:
345
230k
                default:
346
230k
                {
347
230k
                  SetPixelAlpha(image,ScaleCharToQuantum(byte),q);
348
230k
                  break;
349
186k
                }
350
2.09M
              }
351
2.09M
              if (SyncAuthenticPixels(image,exception) == MagickFalse)
352
0
                break;
353
2.09M
              x++;
354
2.09M
              runlength++;
355
2.09M
            }
356
950k
            continue;
357
950k
          }
358
679k
        byte=(unsigned char) ReadBlobByte(image);
359
679k
        length--;
360
679k
        runlength++;
361
679k
        do
362
8.82M
        {
363
8.82M
          q=GetAuthenticPixels(image,x % (ssize_t) image->columns,y,1,1,
364
8.82M
            exception);
365
8.82M
          if (q == (Quantum *) NULL)
366
0
            break;
367
8.82M
          switch (channel)
368
8.82M
          {
369
2.56M
            case 0:
370
2.56M
            {
371
2.56M
              SetPixelRed(image,ScaleCharToQuantum(byte),q);
372
2.56M
              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.43M
            case 2:
380
2.43M
            {
381
2.43M
              SetPixelBlue(image,ScaleCharToQuantum(byte),q);
382
2.43M
              break;
383
0
            }
384
564k
            case 3:
385
673k
            default:
386
673k
            {
387
673k
              SetPixelAlpha(image,ScaleCharToQuantum(byte),q);
388
673k
              break;
389
564k
            }
390
8.82M
          }
391
8.82M
          if (SyncAuthenticPixels(image,exception) == MagickFalse)
392
0
            break;
393
8.82M
          x++;
394
8.82M
          runlength--;
395
8.82M
        }
396
8.82M
        while (runlength > 0);
397
679k
      }
398
21.6k
    }
399
5.38k
    if ((x/(ssize_t) rla_info.number_channels) > (ssize_t) image->columns)
400
119
      {
401
119
        scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
402
119
        ThrowReaderException(CorruptImageError,"CorruptImage");
403
0
      }
404
5.26k
    if (EOFBlob(image) != MagickFalse)
405
77
      break;
406
5.19k
    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
407
5.19k
      image->rows);
408
5.19k
    if (status == MagickFalse)
409
0
      break;
410
5.19k
  }
411
144
  scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
412
144
  if (EOFBlob(image) != MagickFalse)
413
77
    ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
414
144
      image->filename);
415
144
  if (CloseBlob(image) == MagickFalse)
416
0
    status=MagickFalse;
417
144
  if (status == MagickFalse)
418
0
    return(DestroyImageList(image));
419
144
  return(GetFirstImageInList(image));
420
144
}
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
}