Coverage Report

Created: 2025-12-03 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/pdb.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2021 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
%
5
% This program is covered by multiple licenses, which are described in
6
% Copyright.txt. You should have received a copy of Copyright.txt with this
7
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
8
%
9
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10
%                                                                             %
11
%                                                                             %
12
%                                                                             %
13
%                            PPPP   DDDD   BBBB                               %
14
%                            P   P  D   D  B   B                              %
15
%                            PPPP   D   D  BBBB                               %
16
%                            P      D   D  B   B                              %
17
%                            P      DDDD   BBBB                               %
18
%                                                                             %
19
%                                                                             %
20
%              Read/Write Palm Database ImageViewer Image Format.             %
21
%                                                                             %
22
%                                                                             %
23
%                              Software Design                                %
24
%                                John Cristy                                  %
25
%                                 July 1992                                   %
26
%                                                                             %
27
%                                                                             %
28
%                                                                             %
29
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30
%
31
%
32
*/
33
/*
34
  Some information on this format may be found at
35
  http://fileformats.archiveteam.org/wiki/Palm_Database_ImageViewer
36
37
  Round-trip tests do not pass so this format is not included in the
38
  test suite.
39
*/
40

41
/*
42
  Include declarations.
43
*/
44
#include "magick/studio.h"
45
#include "magick/analyze.h"
46
#include "magick/attribute.h"
47
#include "magick/blob.h"
48
#include "magick/colormap.h"
49
#include "magick/constitute.h"
50
#include "magick/log.h"
51
#include "magick/magick.h"
52
#include "magick/monitor.h"
53
#include "magick/pixel_cache.h"
54
#include "magick/utility.h"
55

56
/*
57
  Typedef declarations.
58
*/
59
typedef struct _PDBInfo
60
{
61
  char
62
    name[32];
63
64
  short int
65
    attributes,
66
    version;
67
68
  unsigned long
69
    create_time,
70
    modify_time,
71
    archive_time,
72
    modify_number,
73
    application_info,
74
    sort_info;
75
76
  char
77
    type[4],  /* database type identifier "vIMG" */
78
    id[4];    /* database creator identifier "View" */
79
80
  unsigned long
81
    seed,
82
    next_record;
83
84
  short int
85
    number_records;
86
} PDBInfo;
87
88
typedef struct _PDBImage
89
{
90
  char
91
    name[32],
92
    version,
93
    type;
94
95
  unsigned long
96
    reserved_1,
97
    note;
98
99
  unsigned short int
100
    x_last,
101
    y_last;
102
103
  unsigned long
104
    reserved_2;
105
106
  unsigned short int
107
    x_anchor,
108
    y_anchor,
109
    width,
110
    height;
111
} PDBImage;
112
/*
113
  Forward declarations.
114
*/
115
static unsigned int
116
  WritePDBImage(const ImageInfo *,Image *);
117
118
static void LogPDPInfo(const PDBInfo *info)
119
19.5k
{
120
19.5k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
121
19.5k
                        "PDP Info:\n"
122
19.5k
                        "    name            : %.32s\n"
123
19.5k
                        "    attributes      : %d\n"
124
19.5k
                        "    version         : %d\n"
125
19.5k
                        "    create_time     : %lu\n"
126
19.5k
                        "    modify_time     : %lu\n"
127
19.5k
                        "    archive_time    : %lu\n"
128
19.5k
                        "    modify_number   : %lu\n"
129
19.5k
                        "    application_info: %lu\n"
130
19.5k
                        "    sort_info       : %lu\n"
131
19.5k
                        "    type            : %.4s\n"
132
19.5k
                        "    id              : %.4s\n"
133
19.5k
                        "    seed            : %lu\n"
134
19.5k
                        "    next_record     : %lu\n"
135
19.5k
                        "    number_records  : %u",
136
19.5k
                        info->name,
137
19.5k
                        info->attributes,
138
19.5k
                        info->version,
139
19.5k
                        info->create_time,
140
19.5k
                        info->modify_time,
141
19.5k
                        info->archive_time,
142
19.5k
                        info->modify_number,
143
19.5k
                        info->application_info,
144
19.5k
                        info->sort_info,
145
19.5k
                        info->type,
146
19.5k
                        info->id,
147
19.5k
                        info->seed,
148
19.5k
                        info->next_record,
149
19.5k
                        info->number_records);
150
19.5k
}
151
152
static void LogPDPImage(const PDBImage *image)
153
4.06k
{
154
4.06k
  static const char *type_string;
155
4.06k
  switch(image->type)
156
4.06k
    {
157
2.49k
    case 0: type_string = "2 bit gray"; break;
158
121
    case 2: type_string = "4 bit gray"; break;
159
1.44k
    default: type_string = "monochrome"; break;
160
4.06k
    }
161
162
4.06k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
163
4.06k
                        "PDP Image:\n"
164
4.06k
                        "    name:       %.32s\n"
165
4.06k
                        "    version:    %d\n"
166
4.06k
                        "    type:       %d (%s)\n"
167
4.06k
                        "    reserved_1: %lu\n"
168
4.06k
                        "    note:       %lu\n"
169
4.06k
                        "    x_last:     %u\n"
170
4.06k
                        "    y_last:     %u\n"
171
4.06k
                        "    reserved_2: %lu\n"
172
4.06k
                        "    x_anchor:   %u\n"
173
4.06k
                        "    y_anchor:   %u\n"
174
4.06k
                        "    width:      %u\n"
175
4.06k
                        "    height:     %u",
176
4.06k
                        image->name,
177
4.06k
                        image->version,
178
4.06k
                        image->type, type_string,
179
4.06k
                        image->reserved_1,
180
4.06k
                        image->note,
181
4.06k
                        image->x_last,
182
4.06k
                        image->y_last,
183
4.06k
                        image->reserved_2,
184
4.06k
                        image->x_anchor,
185
4.06k
                        image->y_anchor,
186
4.06k
                        image->width,
187
4.06k
                        image->height
188
4.06k
                        );
189
4.06k
}
190

191
/*
192
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
193
%                                                                             %
194
%                                                                             %
195
%                                                                             %
196
%   D e c o d e I m a g e                                                     %
197
%                                                                             %
198
%                                                                             %
199
%                                                                             %
200
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
201
%
202
%  Method DecodeImage unpacks the packed image pixels into runlength-encoded
203
%  pixel packets.
204
%
205
%  The format of the DecodeImage method is:
206
%
207
%      unsigned int DecodeImage(Image *image,unsigned char *pixels,
208
%        const size_t length)
209
%
210
%  A description of each parameter follows:
211
%
212
%    o status:  Method DecodeImage returns True if all the pixels are
213
%      uncompressed without error, otherwise False.
214
%
215
%    o image: The address of a structure of type Image.
216
%
217
%    o pixels:  The address of a byte (8 bits) array of pixel data created by
218
%      the decoding process.
219
%
220
%
221
*/
222
static MagickPassFail DecodeImage(Image *image,unsigned char *pixels,
223
  const size_t length)
224
381
{
225
381
  int
226
381
    c,
227
381
    count,
228
381
    pixel;
229
230
381
  register long
231
381
    i;
232
233
381
  register unsigned char
234
381
    *p;
235
236
381
  MagickPassFail
237
381
    status = MagickPass;
238
239
381
  p=pixels;
240
623k
  while (p < (pixels+length))
241
623k
  {
242
623k
    if ((pixel=ReadBlobByte(image)) == EOF)
243
28
      {
244
28
        status = MagickFail;
245
28
        goto decode_image_quit;
246
28
      }
247
623k
    if (pixel <= 0x80)
248
175k
      {
249
175k
        count=pixel+1;
250
10.9M
        for (i=0; i < count; i++)
251
10.8M
          {
252
10.8M
            if ((c = ReadBlobByte(image)) == EOF)
253
25
              {
254
25
                status = MagickFail;
255
25
                goto decode_image_quit;
256
25
              }
257
10.8M
            *p++ = (unsigned char) c;
258
10.8M
          }
259
175k
        continue;
260
175k
      }
261
447k
    count=pixel+1-0x80;
262
447k
    if ((pixel=ReadBlobByte(image)) == EOF)
263
4
      {
264
4
        status = MagickFail;
265
4
        goto decode_image_quit;
266
4
      }
267
268
33.7M
    for (i=0; i < count; i++)
269
33.2M
      *p++=(unsigned char) pixel;
270
447k
  }
271
381
 decode_image_quit:;
272
273
381
  return(status);
274
381
}
275

276
/*
277
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
278
%                                                                             %
279
%                                                                             %
280
%                                                                             %
281
%   I s P D B                                                                 %
282
%                                                                             %
283
%                                                                             %
284
%                                                                             %
285
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286
%
287
%  Method IsPDB returns True if the image format type, identified by the
288
%  magick string, is PDB.
289
%
290
%  The format of the ReadPDBImage method is:
291
%
292
%      unsigned int IsPDB(const unsigned char *magick,const size_t length)
293
%
294
%  A description of each parameter follows:
295
%
296
%    o status:  Method IsPDB returns True if the image format type is PDB.
297
%
298
%    o magick: This string is generally the first few bytes of an image file
299
%      or blob.
300
%
301
%    o length: Specifies the length of the magick string.
302
%
303
%
304
*/
305
static unsigned int IsPDB(const unsigned char *magick,const size_t length)
306
0
{
307
0
  if (length < 68)
308
0
    return(False);
309
0
  if (memcmp(magick+60,"vIMGView",8) == 0)
310
0
    return(True);
311
0
  return(False);
312
0
}
313

314
/*
315
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
316
%                                                                             %
317
%                                                                             %
318
%                                                                             %
319
%   R e a d P D B I m a g e                                                   %
320
%                                                                             %
321
%                                                                             %
322
%                                                                             %
323
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324
%
325
%  Method ReadPDBImage reads an Pilot image file and returns it.  It
326
%  allocates the memory necessary for the new Image structure and returns a
327
%  pointer to the new image.
328
%
329
%  The format of the ReadPDBImage method is:
330
%
331
%      Image *ReadPDBImage(const ImageInfo *image_info,ExceptionInfo *exception)
332
%
333
%  A description of each parameter follows:
334
%
335
%    o image:  Method ReadPDBImage returns a pointer to the image after
336
%      reading. A null image is returned if there is a memory shortage or if
337
%      the image cannot be read.
338
%
339
%    o image_info: Specifies a pointer to a ImageInfo structure.
340
%
341
%    o exception: return any errors or warnings in this structure.
342
%
343
%
344
*/
345
14.4k
#define ThrowPDBReaderException(code_,reason_,image_) \
346
14.4k
{ \
347
14.4k
  MagickFreeResourceLimitedMemory(pixels);                   \
348
14.4k
  ThrowReaderException(code_,reason_,image_); \
349
0
}
350
351
static Image *ReadPDBImage(const ImageInfo *image_info,ExceptionInfo *exception)
352
19.5k
{
353
19.5k
  int
354
19.5k
    record_type;
355
356
19.5k
  char
357
19.5k
    tag[3];
358
359
19.5k
  Image
360
19.5k
    *image;
361
362
19.5k
  IndexPacket
363
19.5k
    index;
364
365
19.5k
  long
366
19.5k
    offset;
367
368
19.5k
  PDBImage
369
19.5k
    pdb_image;
370
371
19.5k
  PDBInfo
372
19.5k
    pdb_info;
373
374
19.5k
  register IndexPacket
375
19.5k
    *indexes;
376
377
19.5k
  unsigned long
378
19.5k
    y;
379
380
19.5k
  register unsigned long
381
19.5k
    x;
382
383
19.5k
  register PixelPacket
384
19.5k
    *q;
385
386
19.5k
  register unsigned char
387
19.5k
    *p;
388
389
19.5k
  size_t
390
19.5k
    count;
391
392
19.5k
  unsigned char
393
19.5k
    *pixels = (unsigned char *) NULL;
394
395
19.5k
  unsigned int
396
19.5k
    bits_per_pixel,
397
19.5k
    status;
398
399
19.5k
  size_t
400
19.5k
    packets;
401
402
  /*
403
    Open image file.
404
  */
405
19.5k
  assert(image_info != (const ImageInfo *) NULL);
406
19.5k
  assert(image_info->signature == MagickSignature);
407
19.5k
  assert(exception != (ExceptionInfo *) NULL);
408
19.5k
  assert(exception->signature == MagickSignature);
409
19.5k
  image=AllocateImage(image_info);
410
19.5k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
411
19.5k
  if (status == False)
412
19.5k
    ThrowPDBReaderException(FileOpenError,UnableToOpenFile,image);
413
  /*
414
    Determine if this is a PDB image file.
415
  */
416
19.5k
  count=ReadBlob(image,32,pdb_info.name);
417
19.5k
  if (count != 32)
418
19.5k
    ThrowPDBReaderException(CorruptImageError,ImproperImageHeader,image);
419
19.5k
  pdb_info.name[sizeof(pdb_info.name)-1]='\0';
420
19.5k
  pdb_info.attributes=ReadBlobMSBShort(image);
421
19.5k
  pdb_info.version=ReadBlobMSBShort(image);
422
19.5k
  pdb_info.create_time=ReadBlobMSBLong(image);
423
19.5k
  pdb_info.modify_time=ReadBlobMSBLong(image);
424
19.5k
  pdb_info.archive_time=ReadBlobMSBLong(image);
425
19.5k
  pdb_info.modify_number=ReadBlobMSBLong(image);
426
19.5k
  pdb_info.application_info=ReadBlobMSBLong(image);
427
19.5k
  pdb_info.sort_info=ReadBlobMSBLong(image);
428
19.5k
  if ((ReadBlob(image,4,pdb_info.type) != 4) ||
429
19.5k
      (ReadBlob(image,4,pdb_info.id) != 4))
430
19.5k
    ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
431
19.5k
  pdb_info.seed=ReadBlobMSBLong(image);
432
19.5k
  pdb_info.next_record=ReadBlobMSBLong(image);
433
19.5k
  pdb_info.number_records=ReadBlobMSBShort(image);
434
19.5k
  if (image->logging)
435
19.5k
    LogPDPInfo(&pdb_info);
436
19.5k
  if ((memcmp(pdb_info.type,"vIMG",4) != 0) ||
437
19.5k
      (memcmp(pdb_info.id,"View",4) != 0))
438
19.5k
    ThrowPDBReaderException(CorruptImageError,ImproperImageHeader,image);
439
19.5k
  if (pdb_info.next_record != 0)
440
17.5k
    ThrowPDBReaderException(CoderError,MultipleRecordListNotSupported,image);
441
  /*
442
    Read record header.
443
  */
444
17.5k
  offset=(long) ReadBlobMSBLong(image);
445
17.5k
  if (ReadBlob(image,3,tag) != 3)
446
12.9k
    ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
447
12.9k
  record_type=ReadBlobByte(image);
448
12.9k
  if (((record_type != 0x00) && (record_type != 0x01)) ||
449
12.8k
      (memcmp(tag,"\x40\x6f\x80",3) != 0))
450
7.03k
    ThrowPDBReaderException(CorruptImageError,CorruptImage,image);
451
7.03k
  if ((offset-TellBlob(image)) == 6)
452
7
    {
453
7
      (void) ReadBlobByte(image);
454
7
      (void) ReadBlobByte(image);
455
7
    }
456
7.03k
  if (pdb_info.number_records > 1)
457
4.03k
    {
458
4.03k
      offset=(long) ReadBlobMSBLong(image);
459
4.03k
      (void) ReadBlob(image,3,tag);
460
4.03k
      record_type=ReadBlobByte(image);
461
4.03k
      if (((record_type != 0x00) && (record_type != 0x01)) ||
462
3.45k
          (memcmp(tag,"\x40\x6f\x80",3) != 0))
463
2.97k
        ThrowPDBReaderException(CorruptImageError,CorruptImage,image);
464
1.06k
      if ((offset-TellBlob(image)) == 6)
465
29
        {
466
29
          (void) ReadBlobByte(image);
467
29
          (void) ReadBlobByte(image);
468
29
        }
469
1.06k
    }
470
  /*
471
    Read image header.
472
  */
473
4.06k
  (void) ReadBlob(image,32,pdb_image.name);
474
4.06k
  pdb_image.version=ReadBlobByte(image);
475
4.06k
  pdb_image.type=ReadBlobByte(image);
476
4.06k
  pdb_image.reserved_1=ReadBlobMSBLong(image);
477
4.06k
  pdb_image.note=ReadBlobMSBLong(image);
478
4.06k
  pdb_image.x_last=ReadBlobMSBShort(image);
479
4.06k
  pdb_image.y_last=ReadBlobMSBShort(image);
480
4.06k
  pdb_image.reserved_2=ReadBlobMSBLong(image);
481
4.06k
  pdb_image.x_anchor=ReadBlobMSBShort(image);
482
4.06k
  pdb_image.y_anchor=ReadBlobMSBShort(image);
483
4.06k
  pdb_image.width=ReadBlobMSBShort(image);
484
4.06k
  pdb_image.height=ReadBlobMSBShort(image);
485
4.06k
  if (image->logging)
486
4.06k
    LogPDPImage(&pdb_image);
487
  /*
488
    Initialize image structure.
489
  */
490
4.06k
  image->columns=pdb_image.width;
491
4.06k
  image->rows=pdb_image.height;
492
4.06k
  image->depth=8;
493
4.06k
  image->storage_class=PseudoClass;
494
4.06k
  bits_per_pixel=pdb_image.type == 0 ? 2 : pdb_image.type == 2 ? 4 : 1;
495
4.06k
  if (!AllocateImageColormap(image,1 << bits_per_pixel))
496
4.06k
    ThrowPDBReaderException(ResourceLimitError,MemoryAllocationFailed,image);
497
4.06k
  if (image_info->ping)
498
0
    {
499
0
      CloseBlob(image);
500
0
      StopTimer(&image->timer);
501
0
      return(image);
502
0
    }
503
504
4.06k
  if (CheckImagePixelLimits(image, exception) != MagickPass)
505
3.41k
    ThrowPDBReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
506
507
650
  packets=MagickArraySize(MagickArraySize(bits_per_pixel,image->columns)/8,
508
650
                          image->rows);
509
650
  pixels=MagickAllocateResourceLimitedMemory(unsigned char *,packets + (packets != 0 ? 256 : 0));
510
650
  if (pixels == (unsigned char *) NULL)
511
649
    ThrowPDBReaderException(ResourceLimitWarning,MemoryAllocationFailed,image);
512
649
  (void) memset(pixels,0,packets+256);
513
649
  switch (pdb_image.version)
514
649
  {
515
267
    case 0:
516
267
    {
517
267
      image->compression=NoCompression;
518
267
      if (ReadBlob(image,packets,(char *) pixels) != packets)
519
100
        {
520
100
          MagickFreeResourceLimitedMemory(pixels);
521
100
          ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
522
0
        }
523
167
      break;
524
267
    }
525
381
    case 1:
526
381
    {
527
381
      image->compression=RLECompression;
528
381
      if (DecodeImage(image,pixels,packets) == MagickFail)
529
324
        ThrowPDBReaderException(CorruptImageError,UnexpectedEndOfFile,image);
530
324
      break;
531
381
    }
532
1
    default:
533
1
      {
534
1
        ThrowPDBReaderException(CorruptImageError,UnrecognizedImageCompression,image);
535
0
      }
536
649
  }
537
491
  p=pixels;
538
491
  switch (bits_per_pixel)
539
491
  {
540
111
    case 1:
541
111
    {
542
111
      int
543
111
        bit;
544
545
      /*
546
        Read 1-bit PDB image.
547
      */
548
41.4k
      for (y=0; y < image->rows; y++)
549
41.3k
      {
550
41.3k
        q=SetImagePixels(image,0,y,image->columns,1);
551
41.3k
        if (q == (PixelPacket *) NULL)
552
0
          break;
553
41.3k
        indexes=AccessMutableIndexes(image);
554
41.3k
        bit=0;
555
19.2M
        for (x=0; x < image->columns; x++)
556
19.1M
        {
557
19.1M
          index=(*p & (0x80U >> bit) ? 0x00U : 0x01U);
558
19.1M
          indexes[x]=index;
559
19.1M
          *q++=image->colormap[index];
560
19.1M
          bit++;
561
19.1M
          if (bit == 8)
562
2.37M
            {
563
2.37M
              p++;
564
2.37M
              bit=0;
565
2.37M
            }
566
19.1M
        }
567
41.3k
        if (!SyncImagePixels(image))
568
0
          break;
569
41.3k
        if (QuantumTick(y,image->rows))
570
7.44k
          if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText,
571
7.44k
                                      image->filename,
572
7.44k
                                      image->columns,image->rows))
573
0
            break;
574
41.3k
      }
575
111
      break;
576
0
    }
577
310
    case 2:
578
310
    {
579
      /*
580
        Read 2-bit PDB image.
581
      */
582
310
      unsigned int
583
310
        shift;
584
585
190k
      for (y=0; y < image->rows; y++)
586
190k
      {
587
190k
        q=SetImagePixels(image,0,y,image->columns,1);
588
190k
        if (q == (PixelPacket *) NULL)
589
0
          break;
590
190k
        indexes=AccessMutableIndexes(image);
591
190k
        shift = 8;
592
158M
        for (x=0; x < image->columns; x++)
593
157M
          {
594
157M
            shift -= 2;
595
157M
            index=(IndexPacket) (3-((*p >> shift) & 0x03));
596
157M
            VerifyColormapIndex(image,index);
597
157M
            indexes[x]=index;
598
157M
            *q++=image->colormap[index];
599
157M
            if (shift == 0)
600
39.3M
              {
601
39.3M
                shift = 8;
602
39.3M
                p++;
603
39.3M
              }
604
157M
          }
605
190k
        if (!SyncImagePixels(image))
606
0
          break;
607
190k
        if (QuantumTick(y,image->rows))
608
16.4k
          if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText,
609
16.4k
                                      image->filename,
610
16.4k
                                      image->columns,image->rows))
611
0
            break;
612
190k
      }
613
310
      break;
614
0
    }
615
70
    case 4:
616
70
    {
617
      /*
618
        Read 4-bit PDB image.
619
      */
620
70
      unsigned int
621
70
        shift;
622
623
35.2k
      for (y=0; y < image->rows; y++)
624
35.2k
      {
625
35.2k
        q=SetImagePixels(image,0,y,image->columns,1);
626
35.2k
        if (q == (PixelPacket *) NULL)
627
0
          break;
628
35.2k
        indexes=AccessMutableIndexes(image);
629
35.2k
        shift = 8;
630
4.33M
        for (x=0; x < image->columns; x++)
631
4.29M
        {
632
4.29M
          shift -= 4;
633
4.29M
          index=(IndexPacket) (15-((*p >> shift) & 0x0f));
634
4.29M
          VerifyColormapIndex(image,index);
635
4.29M
          indexes[x]=index;
636
4.29M
          *q++=image->colormap[index];
637
4.29M
          if (shift == 0)
638
2.14M
            {
639
2.14M
              shift = 8;
640
2.14M
              p++;
641
2.14M
            }
642
4.29M
        }
643
35.2k
        if (!SyncImagePixels(image))
644
0
          break;
645
35.2k
        if (QuantumTick(y,image->rows))
646
5.74k
          if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText,
647
5.74k
                                      image->filename,
648
5.74k
                                      image->columns,image->rows))
649
0
            break;
650
35.2k
      }
651
70
      break;
652
0
    }
653
0
    default:
654
0
      {
655
0
        ThrowPDBReaderException(CorruptImageError,ImproperImageHeader,image);
656
0
      }
657
491
  }
658
491
  MagickFreeResourceLimitedMemory(pixels);
659
491
  if (EOFBlob(image))
660
0
    ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
661
491
      image->filename);
662
491
  if ((offset-TellBlob(image)) == 0)
663
127
    {
664
127
      char
665
127
        *comment;
666
667
127
      int
668
127
        c;
669
670
127
      size_t
671
127
        length;
672
673
      /*
674
        Read comment.
675
      */
676
127
      c=ReadBlobByte(image);
677
127
      length=MaxTextExtent;
678
127
      comment=MagickAllocateResourceLimitedMemory(char *,length+1);
679
127
      if (comment != (char *) NULL)
680
127
        {
681
127
          register char
682
127
            *p=comment;
683
684
127
          p[0]='\0';
685
16.3M
          for ( ; c != EOF; p++)
686
16.3M
            {
687
16.3M
              if ((size_t) (p-comment) >= length)
688
7.26k
                {
689
7.26k
                  char
690
7.26k
                    *new_comment;
691
692
7.26k
                  length+=MaxTextExtent;
693
7.26k
                  new_comment=MagickReallocateResourceLimitedMemory(char *,comment,length+1);
694
7.26k
                  if (new_comment == (char *) NULL)
695
0
                    {
696
0
                      MagickFreeResourceLimitedMemory(comment);
697
0
                      break;
698
0
                    }
699
7.26k
                  comment=new_comment;
700
7.26k
                  p=comment+strlen(comment);
701
7.26k
                }
702
16.3M
              *p=c;
703
16.3M
              *(p+1)='\0';
704
16.3M
              c=ReadBlobByte(image);
705
16.3M
            }
706
127
        }
707
127
      if (comment == (char *) NULL)
708
127
        ThrowPDBReaderException(ResourceLimitError,MemoryAllocationFailed,image);
709
127
      (void) SetImageAttribute(image,"comment",comment);
710
127
      MagickFreeResourceLimitedMemory(comment);
711
127
    }
712
491
  CloseBlob(image);
713
491
  StopTimer(&image->timer);
714
491
  return(image);
715
491
}
716

717
/*
718
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
719
%                                                                             %
720
%                                                                             %
721
%                                                                             %
722
%   R e g i s t e r P D B I m a g e                                           %
723
%                                                                             %
724
%                                                                             %
725
%                                                                             %
726
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
727
%
728
%  Method RegisterPDBImage adds attributes for the PDB image format to
729
%  the list of supported formats.  The attributes include the image format
730
%  tag, a method to read and/or write the format, whether the format
731
%  supports the saving of more than one frame to the same file or blob,
732
%  whether the format supports native in-memory I/O, and a brief
733
%  description of the format.
734
%
735
%  The format of the RegisterPDBImage method is:
736
%
737
%      RegisterPDBImage(void)
738
%
739
*/
740
ModuleExport void RegisterPDBImage(void)
741
4
{
742
4
  MagickInfo
743
4
    *entry;
744
745
4
  entry=SetMagickInfo("PDB");
746
4
  entry->decoder=(DecoderHandler) ReadPDBImage;
747
4
  entry->encoder=(EncoderHandler) WritePDBImage;
748
4
  entry->magick=(MagickHandler) IsPDB;
749
4
  entry->description="Palm Database ImageViewer Format";
750
4
  entry->module="PDB";
751
4
  entry->coder_class=UnstableCoderClass;
752
4
  (void) RegisterMagickInfo(entry);
753
4
}
754

755
/*
756
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
757
%                                                                             %
758
%                                                                             %
759
%                                                                             %
760
%   U n r e g i s t e r P D B I m a g e                                       %
761
%                                                                             %
762
%                                                                             %
763
%                                                                             %
764
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
765
%
766
%  Method UnregisterPDBImage removes format registrations made by the
767
%  PDB module from the list of supported formats.
768
%
769
%  The format of the UnregisterPDBImage method is:
770
%
771
%      UnregisterPDBImage(void)
772
%
773
*/
774
ModuleExport void UnregisterPDBImage(void)
775
0
{
776
0
  (void) UnregisterMagickInfo("PDB");
777
0
}
778

779
/*
780
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
781
%                                                                             %
782
%                                                                             %
783
%                                                                             %
784
%   W r i t e P D B I m a g e                                                 %
785
%                                                                             %
786
%                                                                             %
787
%                                                                             %
788
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789
%
790
%  Method WritePDBImage writes an image
791
%
792
%  The format of the WritePDBImage method is:
793
%
794
%      unsigned int WritePDBImage(const ImageInfo *image_info,Image *image)
795
%
796
%  A description of each parameter follows.
797
%
798
%    o status: Method WritePDBImage return True if the image is written.
799
%      False is returned is there is a memory shortage or if the image file
800
%      fails to write.
801
%
802
%    o image_info: Specifies a pointer to a ImageInfo structure.
803
%
804
%    o image:  A pointer to an Image structure.
805
%
806
%
807
*/
808
809
static unsigned char *EncodeRLE(unsigned char *destination,
810
  unsigned char *source,unsigned int literal,unsigned int repeat)
811
11.1M
{
812
11.1M
  if (literal != 0)
813
10.5M
    *destination++=literal-1;
814
11.1M
  (void) memcpy(destination,source,literal);
815
11.1M
  destination+=literal;
816
11.1M
  if (repeat != 0)
817
309k
    {
818
309k
      *destination++=0x80 | (repeat-1);
819
309k
      *destination++=source[literal];
820
309k
    }
821
11.1M
  return(destination);
822
11.1M
}
823
824
0
#define ThrowPDBWriterException(code_,reason_,image_) \
825
0
{ \
826
0
  MagickFreeResourceLimitedMemory(buffer);                     \
827
0
  MagickFreeResourceLimitedMemory(p);                          \
828
0
  MagickFreeResourceLimitedMemory(scanline);                   \
829
0
  ThrowWriterException(code_,reason_,image_); \
830
0
}
831
832
static unsigned int WritePDBImage(const ImageInfo *image_info,Image *image)
833
489
{
834
489
  int
835
489
    bits;
836
837
489
  unsigned long
838
489
    y;
839
840
489
  PDBImage
841
489
    pdb_image;
842
843
489
  PDBInfo
844
489
    pdb_info;
845
846
489
  register long
847
489
    x;
848
849
489
  unsigned char
850
489
    *buffer = (unsigned char *) NULL,
851
489
    *p = (unsigned char *) NULL,
852
489
    *q,
853
489
    *scanline = (unsigned char *) NULL;
854
855
489
  unsigned int
856
489
    bits_per_pixel,
857
489
    packet_size,
858
489
    status;
859
860
489
  size_t
861
489
    packets;
862
863
489
  unsigned long
864
489
    literal,
865
489
    repeat;
866
867
489
  const ImageAttribute
868
489
    *comment;
869
870
489
  if (image->logging)
871
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
872
0
                          "Dimensions: %lux%lu",
873
0
                          image->columns,image->rows);
874
875
  /*
876
    Open output image file.
877
  */
878
489
  assert(image_info != (const ImageInfo *) NULL);
879
489
  assert(image_info->signature == MagickSignature);
880
489
  assert(image != (Image *) NULL);
881
489
  assert(image->signature == MagickSignature);
882
489
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
883
489
  if (status == False)
884
489
    ThrowPDBWriterException(FileOpenError,UnableToOpenFile,image);
885
489
  (void) TransformColorspace(image,RGBColorspace);
886
489
  (void) SetImageType(image,GrayscaleType);
887
489
  bits_per_pixel=image->depth;
888
489
  if (GetImageType(image,&image->exception) == BilevelType)
889
111
    bits_per_pixel=1;
890
489
  if ((bits_per_pixel != 1) && (bits_per_pixel != 2))
891
378
    bits_per_pixel=4;
892
489
  (void) memset(&pdb_info,0,sizeof(pdb_info));
893
489
  (void) strlcpy(pdb_info.name,image_info->filename,sizeof(pdb_info.name));
894
489
  pdb_info.attributes=0;
895
489
  pdb_info.version=0;
896
489
  pdb_info.create_time=time(NULL);
897
489
  pdb_info.modify_time=pdb_info.create_time;
898
489
  pdb_info.archive_time=0;
899
489
  pdb_info.modify_number=0;
900
489
  pdb_info.application_info=0;
901
489
  pdb_info.sort_info=0;
902
489
  (void) memcpy(pdb_info.type,"vIMG",4);
903
489
  (void) memcpy(pdb_info.id,"View",4);
904
489
  pdb_info.seed=0;
905
489
  pdb_info.next_record=0;
906
489
  comment=GetImageAttribute(image,"comment");
907
489
  pdb_info.number_records=1;
908
489
  if ((comment != (ImageAttribute *) NULL) && (comment->value != (char *) NULL))
909
125
    pdb_info.number_records++;
910
489
  if (image->logging)
911
0
    LogPDPInfo(&pdb_info);
912
489
  (void) WriteBlob(image,32,pdb_info.name);
913
489
  (void) WriteBlobMSBShort(image,pdb_info.attributes);
914
489
  (void) WriteBlobMSBShort(image,pdb_info.version);
915
489
  (void) WriteBlobMSBLong(image,pdb_info.create_time);
916
489
  (void) WriteBlobMSBLong(image,pdb_info.modify_time);
917
489
  (void) WriteBlobMSBLong(image,pdb_info.archive_time);
918
489
  (void) WriteBlobMSBLong(image,pdb_info.modify_number);
919
489
  (void) WriteBlobMSBLong(image,pdb_info.application_info);
920
489
  (void) WriteBlobMSBLong(image,pdb_info.sort_info);
921
489
  (void) WriteBlob(image,4,pdb_info.type);
922
489
  (void) WriteBlob(image,4,pdb_info.id);
923
489
  (void) WriteBlobMSBLong(image,pdb_info.seed);
924
489
  (void) WriteBlobMSBLong(image,pdb_info.next_record);
925
489
  (void) WriteBlobMSBShort(image,pdb_info.number_records);
926
489
  (void) memset(&pdb_image,0,sizeof(pdb_image));
927
489
  (void) strlcpy(pdb_image.name,pdb_info.name,sizeof(pdb_image.name));
928
489
  pdb_image.version=1;  /* RLE Compressed */
929
489
  switch(bits_per_pixel)
930
489
  {
931
111
    case 1: pdb_image.type=0xffU; break;  /* monochrome */
932
0
    case 2: pdb_image.type=0x00U; break;  /* 2 bit gray */
933
378
    default: pdb_image.type=0x02U;        /* 4 bit gray */
934
489
  }
935
489
  pdb_image.reserved_1=0;
936
489
  pdb_image.note=0;
937
489
  pdb_image.x_last=0;
938
489
  pdb_image.y_last=0;
939
489
  pdb_image.reserved_2=0;
940
489
  pdb_image.x_anchor=(short) 0xffff;
941
489
  pdb_image.y_anchor=(short) 0xffff;
942
489
  pdb_image.width=(short) image->columns;
943
489
  if (image->columns % 16)
944
467
    pdb_image.width=(short) (16*(image->columns/16+1));
945
489
  pdb_image.height=(short) image->rows;
946
489
  if (image->logging)
947
0
    LogPDPImage(&pdb_image);
948
489
  if ((pdb_image.width < image->columns) ||
949
489
      (pdb_image.height != image->rows))
950
489
    ThrowPDBWriterException(CoderError,ImageColumnOrRowSizeIsNotSupported, image);
951
489
  packets=MagickArraySize(MagickArraySize(MagickArraySize(bits_per_pixel,
952
489
                                                          pdb_image.width)/8,
953
489
                                          pdb_image.height),2);
954
489
  p=MagickAllocateResourceLimitedMemory(unsigned char *,packets);
955
489
  if (p == (unsigned char *) NULL)
956
489
    ThrowPDBWriterException(ResourceLimitWarning,MemoryAllocationFailed,image);
957
489
  buffer=MagickAllocateResourceLimitedMemory(unsigned char *,512);
958
489
  if (buffer == (unsigned char *) NULL)
959
489
    ThrowPDBWriterException(ResourceLimitWarning,MemoryAllocationFailed,image);
960
489
  (void) memset(buffer,0,512);
961
489
  packet_size=bits_per_pixel > 8 ? 2: 1;
962
489
  scanline=MagickAllocateResourceLimitedArray(unsigned char *,image->columns,packet_size);
963
489
  if (scanline == (unsigned char *) NULL)
964
489
    ThrowPDBWriterException(ResourceLimitWarning,MemoryAllocationFailed,image);
965
489
  (void) TransformColorspace(image,RGBColorspace);
966
  /*
967
    Convert to GRAY raster scanline.
968
  */
969
489
  bits=8/(long) bits_per_pixel-1;  /* start at most significant bits */
970
489
  literal=0;
971
489
  repeat=0;
972
489
  q=p;
973
489
  buffer[0]=0x00;
974
267k
  for (y=0; y < image->rows; y++)
975
266k
  {
976
266k
    if (!AcquireImagePixels(image,0,y,image->columns,1,&image->exception))
977
0
      break;
978
266k
    (void) memset(scanline,0, (size_t) image->columns*packet_size); /* FIXME: remove */
979
266k
    (void) ExportImagePixelArea(image,GrayQuantum,bits_per_pixel,scanline,0,0);
980
183M
    for (x=0; x < pdb_image.width; x++)
981
183M
    {
982
183M
      if (x < (long) image->columns)
983
181M
        buffer[literal+repeat]|=(0xff-scanline[x*packet_size]) >>
984
181M
          (8-bits_per_pixel) << bits*bits_per_pixel;
985
183M
      bits--;
986
183M
      if (bits < 0)
987
84.4M
        {
988
84.4M
          if (((literal+repeat) > 0) &&
989
84.1M
              (buffer[literal+repeat] == buffer[literal+repeat-1]))
990
72.4M
            {
991
72.4M
              if (repeat == 0)
992
1.58M
                {
993
1.58M
                  literal--;
994
1.58M
                  repeat++;
995
1.58M
                }
996
72.4M
              repeat++;
997
72.4M
              if (0x7f < repeat)
998
308k
                {
999
308k
                  q=EncodeRLE(q,buffer,literal,repeat);
1000
308k
                  literal=0;
1001
308k
                  repeat=0;
1002
308k
                }
1003
72.4M
            }
1004
11.9M
          else
1005
11.9M
            {
1006
11.9M
              if (repeat >= 2)
1007
1.27M
                literal+=repeat;
1008
10.7M
              else
1009
10.7M
                {
1010
10.7M
                  q=EncodeRLE(q,buffer,literal,repeat);
1011
10.7M
                  buffer[0]=buffer[literal+repeat];
1012
10.7M
                  literal=0;
1013
10.7M
                }
1014
11.9M
              literal++;
1015
11.9M
              repeat=0;
1016
11.9M
              if (0x7f < literal)
1017
107k
                {
1018
107k
                  q=EncodeRLE(q,buffer,(literal < 0x80 ? literal : 0x80),0);
1019
107k
                  (void) memmove(buffer,buffer+literal+repeat,0x80);
1020
107k
                  literal-=0x80;
1021
107k
                }
1022
11.9M
            }
1023
84.4M
        bits=8/(long) bits_per_pixel-1;
1024
84.4M
        buffer[literal+repeat]=0x00;
1025
84.4M
      }
1026
183M
    }
1027
266k
    if (QuantumTick(y,image->rows))
1028
29.6k
      if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1029
29.6k
                                  SaveImageText,image->filename,
1030
29.6k
                                  image->columns,image->rows))
1031
0
        break;
1032
266k
  }
1033
489
  q=EncodeRLE(q,buffer,literal,repeat);
1034
489
  MagickFreeResourceLimitedMemory(scanline);
1035
489
  MagickFreeResourceLimitedMemory(buffer);
1036
  /*
1037
    Write the Image record header.
1038
  */
1039
489
  (void) WriteBlobMSBLong(image,(magick_uint32_t)
1040
489
    (TellBlob(image)+(size_t)8*pdb_info.number_records));
1041
489
  (void) WriteBlobByte(image,0x40);
1042
489
  (void) WriteBlobByte(image,0x6f);
1043
489
  (void) WriteBlobByte(image,0x80);
1044
489
  (void) WriteBlobByte(image,0);
1045
489
  if (pdb_info.number_records > 1)
1046
125
    {
1047
      /*
1048
        Write the comment record header.
1049
      */
1050
125
      (void) WriteBlobMSBLong(image,TellBlob(image)+8+58+q-p);
1051
125
      (void) WriteBlobByte(image,0x40);
1052
125
      (void) WriteBlobByte(image,0x6f);
1053
125
      (void) WriteBlobByte(image,0x80);
1054
125
      (void) WriteBlobByte(image,1);
1055
125
    }
1056
  /*
1057
    Write the Image data.
1058
  */
1059
489
  (void) WriteBlob(image,32,pdb_image.name);
1060
489
  (void) WriteBlobByte(image,pdb_image.version);
1061
489
  (void) WriteBlobByte(image,pdb_image.type);
1062
489
  (void) WriteBlobMSBLong(image,pdb_image.reserved_1);
1063
489
  (void) WriteBlobMSBLong(image,pdb_image.note);
1064
489
  (void) WriteBlobMSBShort(image,pdb_image.x_last);
1065
489
  (void) WriteBlobMSBShort(image,pdb_image.y_last);
1066
489
  (void) WriteBlobMSBLong(image,pdb_image.reserved_2);
1067
489
  (void) WriteBlobMSBShort(image,pdb_image.x_anchor);
1068
489
  (void) WriteBlobMSBShort(image,pdb_image.y_anchor);
1069
489
  (void) WriteBlobMSBShort(image,pdb_image.width);
1070
489
  (void) WriteBlobMSBShort(image,pdb_image.height);
1071
489
  (void) WriteBlob(image,q-p,p);
1072
489
  MagickFreeResourceLimitedMemory(p);
1073
489
  if ((comment != (ImageAttribute *) NULL) && (comment->value != (char *) NULL))
1074
125
    (void) WriteBlobString(image,comment->value);
1075
489
  status &= CloseBlob(image);
1076
489
  return(status);
1077
489
}