]> git.sur5r.net Git - cc65/blobdiff - src/sp65/pcx.c
Changed most "backticks" (grave accents) into apostrophes.
[cc65] / src / sp65 / pcx.c
index 3a9ccb3b0c8f8bb579e9ede50a2dce43559c27d1..d721671b3944bed07982399bbf6388e8679997d2 100644 (file)
@@ -42,6 +42,7 @@
 #include "xmalloc.h"
 
 /* sp65 */
+#include "attr.h"
 #include "error.h"
 #include "fileio.h"
 #include "pcx.h"
@@ -105,6 +106,14 @@ static PCXHeader* NewPCXHeader (void)
 
 
 
+static void FreePCXHeader (PCXHeader* H)
+/* Free a PCX header structure */
+{
+    xfree (H);
+}
+
+
+
 static PCXHeader* ReadPCXHeader (FILE* F, const char* Name)
 /* Read a structured PCX header from the given file and return it */
 {
@@ -137,29 +146,29 @@ static PCXHeader* ReadPCXHeader (FILE* F, const char* Name)
 
     /* Check the header data */
     if (P->Id != PCX_MAGIC_ID || P->FileVersion == 1 || P->FileVersion > 5) {
-        Error ("`%s' is not a PCX file", Name);
+        Error ("'%s' is not a PCX file", Name);
     }
     if (P->Compressed > 1) {
-        Error ("Unsupported compression (%d) in PCX file `%s'",
+        Error ("Unsupported compression (%d) in PCX file '%s'",
                P->Compressed, Name);
     }
     /* We support:
-     *   - one plane with either 1 or 8 bits per pixel
-     *   - three planes with 8 bits per pixel
-     *   - four planes with 8 bits per pixel (does this exist?)
-     */
+    **   - one plane with either 1 or 8 bits per pixel
+    **   - three planes with 8 bits per pixel
+    **   - four planes with 8 bits per pixel (does this exist?)
+    */
     if (!((P->BPP == 1 && P->Planes == 1) ||
           (P->BPP == 8 && (P->Planes == 1 || P->Planes == 3 || P->Planes == 4)))) {
         /* We could support others, but currently we don't */
-        Error ("Unsupported PCX format: %u planes, %u bpp in PCX file `%s'",
+        Error ("Unsupported PCX format: %u planes, %u bpp in PCX file '%s'",
                P->Planes, P->BPP, Name);
     }
     if (P->PalInfo != 1 && P->PalInfo != 2) {
-        Error ("Unsupported palette info (%u) in PCX file `%s'",
+        Error ("Unsupported palette info (%u) in PCX file '%s'",
                P->PalInfo, Name);
     }
     if (!ValidBitmapSize (P->Width, P->Height)) {
-        Error ("PCX file `%s' has an unsupported size (w=%u, h=%d)",
+        Error ("PCX file '%s' has an unsupported size (w=%u, h=%d)",
                Name, P->Width, P->Height);
     }
 
@@ -235,21 +244,24 @@ static void ReadPlane (FILE* F, PCXHeader* P, unsigned char* L)
 
 
 
-Bitmap* ReadPCXFile (const char* Name)
+Bitmap* ReadPCXFile (const Collection* A)
 /* Read a bitmap from a PCX file */
 {
     PCXHeader* P;
     Bitmap* B;
     unsigned char* L;
     Pixel* Px;
+    unsigned MaxIdx = 0;
     unsigned X, Y;
 
 
+    /* Get the file name */
+    const char* Name = NeedAttrVal (A, "name", "read pcx file");
 
     /* Open the file */
     FILE* F = fopen (Name, "rb");
     if (F == 0) {
-        Error ("Cannot open PCX file `%s': %s", Name, strerror (errno));
+        Error ("Cannot open PCX file '%s': %s", Name, strerror (errno));
     }
 
     /* Read the PCX header */
@@ -263,16 +275,8 @@ Bitmap* ReadPCXFile (const char* Name)
     /* Create the bitmap */
     B = NewBitmap (P->Width, P->Height);
 
-    /* Determine the type of the bitmap */
-    switch (P->Planes) {
-        case 1: B->Type = (P->PalInfo? bmIndexed : bmMonochrome);       break;
-        case 3: B->Type = bmRGB;                                        break;
-        case 4: B->Type = bmRGBA;                                       break;
-        default:Internal ("Unexpected number of planes");
-    }
-
-    /* Remember the PCX header in the tag */
-    B->Tag = P;
+    /* Copy the name */
+    SB_CopyStr (&B->Name, Name);
 
     /* Allocate memory for the scan line */
     L = xmalloc (P->Width);
@@ -313,11 +317,82 @@ Bitmap* ReadPCXFile (const char* Name)
 
                 /* Create pixels */
                 for (X = 0; X < P->Width; ++X, ++Px) {
+                    if (L[X] > MaxIdx) {
+                        MaxIdx = L[X];
+                    }
                     Px->Index = L[X];
                 }
             }
         }
+
+        /* One plane means we have a palette which is either part of the header
+        ** or follows.
+        */
+        if (P->PalInfo == 0) {
+
+            /* Create the monochrome palette */
+            B->Pal = NewMonochromePalette ();
+
+        } else {
+
+            unsigned      Count;
+            unsigned      I;
+            unsigned char Palette[256][3];
+            unsigned long EndPos;
+
+            /* Determine the current file position */
+            unsigned long CurPos = FileGetPos (F);
+
+            /* Seek to the end of the file */
+            (void) fseek (F, 0, SEEK_END);
+
+            /* Get this position */
+            EndPos = FileGetPos (F);
+
+            /* There's a palette if the old location is 769 bytes from the end */
+            if (EndPos - CurPos == sizeof (Palette) + 1) {
+
+                /* Seek back */
+                FileSetPos (F, CurPos);
+
+                /* Check for palette marker */
+                if (Read8 (F) != 0x0C) {
+                    Error ("Invalid palette marker in PCX file '%s'", Name);
+                }
+
+            } else if (EndPos == CurPos) {
+
+                /* The palette is in the header */
+                FileSetPos (F, 16);
+
+                /* Check the maximum index for safety */
+                if (MaxIdx > 15) {
+                    Error ("PCX file '%s' contains more than 16 indexed colors "
+                           "but no extra palette", Name);
+                }
+
+            } else {
+                Error ("Error in PCX file '%s': %lu bytes at end of pixel data",
+                       Name, EndPos - CurPos);
+            }
+
+            /* Read the palette. We will just read what we need. */
+            Count = MaxIdx + 1;
+            ReadData (F, Palette, Count * sizeof (Palette[0]));
+
+            /* Create the palette from the data */
+            B->Pal = NewPalette (Count);
+            for (I = 0; I < Count; ++I) {
+                B->Pal->Entries[I].R = Palette[I][0];
+                B->Pal->Entries[I].G = Palette[I][1];
+                B->Pal->Entries[I].B = Palette[I][2];
+                B->Pal->Entries[I].A = 0;
+            }
+
+        }
+
     } else {
+
         /* 3 or 4 planes are RGB or RGBA (don't know if this exists) */
         for (Y = 0, Px = B->Data; Y < P->Height; ++Y) {
 
@@ -353,73 +428,15 @@ Bitmap* ReadPCXFile (const char* Name)
         }
     }
 
-    /* One plane means we have a palette which is either part of the header
-     * or follows.
-     */
-    if (B->Type == bmMonochrome) {
-
-        /* Create the monochrome palette */
-        B->Pal = NewMonochromePalette ();
-
-    } else if (B->Type == bmIndexed) {
-
-        unsigned      Count;
-        unsigned      I;
-        unsigned char Palette[256][3];
-        unsigned long EndPos;
-
-        /* Determine the current file position */
-        unsigned long CurPos = FileGetPos (F);
-
-        /* Seek to the end of the file */
-        (void) fseek (F, 0, SEEK_END);
-
-        /* Get this position */
-        EndPos = FileGetPos (F);
-
-        /* There's a palette if the old location is 769 bytes from the end */
-        if (EndPos - CurPos == sizeof (Palette) + 1) {
-
-            /* Seek back */
-            FileSetPos (F, CurPos);
-
-            /* Check for palette marker */
-            if (Read8 (F) != 0x0C) {
-                Error ("Invalid palette marker in PCX file `%s'", Name);
-            }
-
-            /* Read the palette */
-            ReadData (F, Palette, sizeof (Palette));
-            Count = 256;
-
-        } else if (EndPos == CurPos) {
-
-            /* The palette is in the header */
-            FileSetPos (F, 16);
-            ReadData (F, Palette, 48);
-            Count = 16;
-
-        } else {
-            Error ("Error in PCX file `%s': %lu bytes at end of pixel data",
-                   Name, EndPos - CurPos);
-        }
-
-        /* Create the palette from the data */
-        B->Pal = NewPalette (Count);
-        for (I = 0; I < Count; ++I) {
-            B->Pal->Entries[I].R = Palette[I][0];
-            B->Pal->Entries[I].G = Palette[I][1];
-            B->Pal->Entries[I].B = Palette[I][2];
-            B->Pal->Entries[I].A = 0;
-        }
-    }
-
     /* Close the file */
     fclose (F);
 
+    /* Free memory for the scan line */
+    xfree (L);
+
+    /* Free the PCX header */
+    FreePCXHeader (P);
+
     /* Return the bitmap */
     return B;
 }
-
-
-