Coverage Report

Created: 2025-10-12 07:48

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