rnd-20000718-1-src
[rocksndiamonds.git] / src / pcx.c
index f2dac1d9cfdb266bc669d54bab7a6a3770b4988b..b26e44274c4c99d8f7dbfa18857cf5bedd20af6b 100644 (file)
--- a/src/pcx.c
+++ b/src/pcx.c
 *  pcx.c                                                   *
 ***********************************************************/
 
+#include "pcx.h"
 #include "image.h"
 #include "misc.h"
 
+#define PCX_DEBUG              FALSE
+
 #define PCX_MAGIC              0x0a    /* first byte in a PCX image file    */
 #define PCX_LAST_VERSION       5       /* last acceptable version number    */
 #define PCX_ENCODING           1       /* PCX encoding method               */
@@ -44,8 +47,79 @@ struct PCX_Header
   unsigned char filler[58];    /* fill to struct size of 128          */
 };
 
-static byte *PCX_ReadBitmap(Image *, byte *, byte *);
-static byte *PCX_ReadColormap(Image *, byte *, byte *);
+/* global PCX error value */
+int errno_pcx = PCX_Success;
+
+static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last)
+{
+  /* Run Length Encoding: If the two high bits are set,
+   * then the low 6 bits contain a repeat count, and the byte to
+   * repeat is the next byte in the file.  If the two high bits are
+   * not set, then this is the byte to write.
+   */
+
+  unsigned int bytes_per_pixel = (image->depth + 7) / 8;
+  register byte *bitmap_ptr, *bitmap_last;
+  register byte value, count;
+
+  bitmap_ptr = image->data;
+  bitmap_last = bitmap_ptr + (image->width * image->height * bytes_per_pixel);
+
+  while (bitmap_ptr < bitmap_last && buffer_ptr < buffer_last)
+  {
+    value = *buffer_ptr++;
+
+    if ((value & 0xc0) == 0xc0)                /* this is a repeat count byte */
+    {
+      count = value & 0x3f;            /* extract repeat count from byte */
+      value = *buffer_ptr++;           /* next byte is value to repeat */
+
+      for (; count && bitmap_ptr < bitmap_last; count--)
+       *bitmap_ptr++ = value;
+
+      if (count)                       /* repeat count spans end of bitmap */
+       return NULL;
+    }
+    else
+      *bitmap_ptr++ = value;
+
+    image->rgb.color_used[value] = TRUE;
+  }
+
+  /* check if end of buffer was reached before end of bitmap */
+  if (bitmap_ptr < bitmap_last)
+    return NULL;
+
+  /* return current buffer position for next decoding function */
+  return buffer_ptr;
+}
+
+static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last)
+{
+  int i, magic;
+
+  /* read colormap magic byte */
+  magic = *buffer_ptr++;
+
+  /* check magic colormap header byte */
+  if (magic != PCX_256COLORS_MAGIC)
+    return NULL;
+
+  /* check if enough bytes left for a complete colormap */
+  if (buffer_ptr + PCX_COLORMAP_SIZE > buffer_last)
+    return NULL;
+
+  /* read 256 colors from PCX colormap */
+  for (i=0; i<PCX_MAXCOLORS; i++)
+  {
+    image->rgb.red[i]   = *buffer_ptr++ << 8;
+    image->rgb.green[i] = *buffer_ptr++ << 8;
+    image->rgb.blue[i]  = *buffer_ptr++ << 8;
+  }
+
+  /* return current buffer position for next decoding function */
+  return buffer_ptr;
+}
 
 Image *Read_PCX_to_Image(char *filename)
 {
@@ -58,21 +132,30 @@ Image *Read_PCX_to_Image(char *filename)
   int width, height, depth;
   int i;
 
+  errno_pcx = PCX_Success;
+
   if (!(file = fopen(filename, "r")))
+  {
+    errno_pcx = PCX_OpenFailed;
     return NULL;
+  }
 
   if (fseek(file, 0, SEEK_END) == -1)
   {
     fclose(file);
+    errno_pcx = PCX_ReadFailed;
     return NULL;
   }
 
   file_length = ftell(file);
   rewind(file);
 
-  if (file_length < PCX_HEADER_SIZE + PCX_COLORMAP_SIZE)
+  if (file_length < PCX_HEADER_SIZE)
   {
+    /* PCX file is too short to contain a valid PCX header */
     fclose(file);
+
+    errno_pcx = PCX_FileInvalid;
     return NULL;
   }
 
@@ -81,6 +164,7 @@ Image *Read_PCX_to_Image(char *filename)
   if (fread(file_buffer, 1, file_length, file) != file_length)
   {
     fclose(file);
+    errno_pcx = PCX_ReadFailed;
     return NULL;
   }
 
@@ -107,20 +191,25 @@ Image *Read_PCX_to_Image(char *filename)
       width < 0 || height < 0)
   {
     free(file_buffer);
+
+    errno_pcx = PCX_FileInvalid;
     return NULL;
   }
 
+#if PCX_DEBUG
   if (options.verbose)
   {
     printf("%s is a %dx%d PC Paintbrush image with %d bitplanes\n",
-          filename, pcx.xmax, pcx.ymax,
+          filename, width, height,
           pcx.color_planes);
     printf("depth: %d\n", pcx.bits_per_pixel);
+    printf("color_planes: %d\n", pcx.color_planes);
     printf("bytes_per_line: %d\n", pcx.bytes_per_line);
     printf("palette type: %s\n",
           (pcx.palette_type == 1 ? "color" :
            pcx.palette_type == 2 ? "grayscale" : "undefined"));
   }
+#endif
 
   /* allocate new image structure */
   image = newImage(width, height, depth);
@@ -133,6 +222,16 @@ Image *Read_PCX_to_Image(char *filename)
   {
     free(file_buffer);
     freeImage(image);
+
+    errno_pcx = PCX_FileInvalid;
+    return NULL;
+  }
+
+  if (file_length < PCX_HEADER_SIZE + PCX_COLORMAP_SIZE)
+  {
+    /* PCX file is too short to contain a valid 256 colors colormap */
+    fclose(file);
+    errno_pcx = PCX_ColorFailed;
     return NULL;
   }
 
@@ -141,6 +240,7 @@ Image *Read_PCX_to_Image(char *filename)
   {
     free(file_buffer);
     freeImage(image);
+    errno_pcx = PCX_ColorFailed;
     return NULL;
   }
 
@@ -152,79 +252,10 @@ Image *Read_PCX_to_Image(char *filename)
     if (image->rgb.color_used[i])
       image->rgb.used++;
 
+#if PCX_DEBUG
   if (options.verbose)
     printf("Read_PCX_to_Image: %d colors found\n", image->rgb.used);
+#endif
 
   return image;
 }
-
-static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last)
-{
-  /* Run Length Encoding: If the two high bits are set,
-   * then the low 6 bits contain a repeat count, and the byte to
-   * repeat is the next byte in the file.  If the two high bits are
-   * not set, then this is the byte to write.
-   */
-
-  unsigned int bytes_per_pixel = (image->depth + 7) / 8;
-  register byte *bitmap_ptr, *bitmap_last;
-  register byte value, count;
-
-  bitmap_ptr = image->data;
-  bitmap_last = bitmap_ptr + (image->width * image->height * bytes_per_pixel);
-
-  while (bitmap_ptr < bitmap_last && buffer_ptr < buffer_last)
-  {
-    value = *buffer_ptr++;
-
-    if ((value & 0xc0) == 0xc0)                /* this is a repeat count byte */
-    {
-      count = value & 0x3f;            /* extract repeat count from byte */
-      value = *buffer_ptr++;           /* next byte is value to repeat */
-
-      for (; count && bitmap_ptr < bitmap_last; count--)
-       *bitmap_ptr++ = value;
-
-      if (count)                       /* repeat count spans end of bitmap */
-       return NULL;
-    }
-    else
-      *bitmap_ptr++ = value;
-
-    image->rgb.color_used[value] = TRUE;
-  }
-
-  /* check if end of buffer was reached before end of bitmap */
-  if (bitmap_ptr < bitmap_last)
-    return NULL;
-
-  /* return current buffer position for next decoding function */
-  return buffer_ptr;
-}
-
-static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last)
-{
-  int i, magic;
-
-  /* read colormap magic byte */
-  magic = *buffer_ptr++;
-
-  /* check magic colormap header byte */
-  if (magic != PCX_256COLORS_MAGIC)
-    return NULL;
-
-  /* check if enough bytes left for a complete colormap */
-  if (buffer_ptr + PCX_COLORMAP_SIZE > buffer_last)
-    return NULL;
-
-  /* read 256 colors from PCX colormap */
-  for (i=0; i<PCX_MAXCOLORS; i++)
-  {
-    image->rgb.red[i]   = *buffer_ptr++ << 8;
-    image->rgb.green[i] = *buffer_ptr++ << 8;
-    image->rgb.blue[i]  = *buffer_ptr++ << 8;
-  }
-
-  /* return current buffer position for next decoding function */
-  return buffer_ptr;
-}