Coverage Report

Created: 2026-07-25 07:06

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