void DumpObjSegments (FILE* F, unsigned long Offset) /* Dump the segments in the object file */ { ObjHeader H; Collection StrPool = AUTO_COLLECTION_INITIALIZER; unsigned Count; unsigned I; /* Seek to the header position and read the header */ FileSetPos (F, Offset); ReadObjHeader (F, &H); /* Seek to the start of the string pool and read it */ FileSetPos (F, Offset + H.StrPoolOffs); ReadStrPool (F, &StrPool); /* Seek to the start of the segments */ FileSetPos (F, Offset + H.SegOffs); /* Output a header */ printf (" Segments:\n"); /* Read the number of segments and print it */ Count = ReadVar (F); printf (" Count:%27u\n", Count); /* Read and print all segments */ for (I = 0; I < Count; ++I) { /* Read the data for one segments */ unsigned long DataSize = Read32 (F); unsigned long NextSeg = ftell (F) + DataSize; const char* Name = GetString (&StrPool, ReadVar (F)); unsigned Len = strlen (Name); unsigned Flags = ReadVar (F); unsigned long Size = ReadVar (F); unsigned long Align = ReadVar (F); unsigned char AddrSize = Read8 (F); unsigned long FragCount = ReadVar (F); /* Print the header */ printf (" Index:%27u\n", I); /* Print the data */ printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name); printf (" Flags:%25u\n", Flags); printf (" Size:%26lu\n", Size); printf (" Alignment:%21lu\n", Align); printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize, AddrSizeToStr (AddrSize)); printf (" Fragment count:%16lu\n", FragCount); /* Seek to the end of the segment data (start of next) */ FileSetPos (F, NextSeg); } /* Destroy the string pool */ DestroyStrPool (&StrPool); }
void DumpObjSegSize (FILE* F, unsigned long Offset) /* Dump the sizes of the segment in the object file */ { ObjHeader H; Collection StrPool = AUTO_COLLECTION_INITIALIZER; unsigned Count; /* Seek to the header position and read the header */ FileSetPos (F, Offset); ReadObjHeader (F, &H); /* Seek to the start of the string pool and read it */ FileSetPos (F, Offset + H.StrPoolOffs); ReadStrPool (F, &StrPool); /* Seek to the start of the segments */ FileSetPos (F, Offset + H.SegOffs); /* Output a header */ printf (" Segment sizes:\n"); /* Read the number of segments */ Count = ReadVar (F); /* Read and print the sizes of all segments */ while (Count--) { unsigned long Size; /* Read the data for one segment */ unsigned long DataSize = Read32 (F); unsigned long NextSeg = ftell (F) + DataSize; const char* Name = GetString (&StrPool, ReadVar (F)); unsigned Len = strlen (Name); /* Skip segment flags, read size */ (void) ReadVar (F); Size = ReadVar (F); /* Skip alignment, type and fragment count */ (void) ReadVar (F); (void) Read8 (F); (void) ReadVar (F); /* Print the size for this segment */ printf (" %s:%*s%6lu\n", Name, (int)(24-Len), "", Size); /* Seek to the end of the segment data (start of next) */ FileSetPos (F, NextSeg); } /* Destroy the string pool */ DestroyStrPool (&StrPool); }
void DumpObjImports (FILE* F, unsigned long Offset) /* Dump the imports in the object file */ { ObjHeader H; Collection StrPool = AUTO_COLLECTION_INITIALIZER; unsigned Count; unsigned I; /* Seek to the header position and read the header */ FileSetPos (F, Offset); ReadObjHeader (F, &H); /* Seek to the start of the string pool and read it */ FileSetPos (F, Offset + H.StrPoolOffs); ReadStrPool (F, &StrPool); /* Seek to the start of the imports */ FileSetPos (F, Offset + H.ImportOffs); /* Output a header */ printf (" Imports:\n"); /* Read the number of imports and print it */ Count = ReadVar (F); printf (" Count:%27u\n", Count); /* Read and print all imports */ for (I = 0; I < Count; ++I) { /* Read the data for one import */ unsigned char AddrSize = Read8 (F); const char* Name = GetString (&StrPool, ReadVar (F)); unsigned Len = strlen (Name); /* Skip both line info lists */ SkipLineInfoList (F); SkipLineInfoList (F); /* Print the header */ printf (" Index:%27u\n", I); /* Print the data */ printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize, AddrSizeToStr (AddrSize)); printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name); } /* Destroy the string pool */ DestroyStrPool (&StrPool); }
void DumpObjFiles (FILE* F, unsigned long Offset) /* Dump the source files */ { ObjHeader H; Collection StrPool = AUTO_COLLECTION_INITIALIZER; unsigned Count; unsigned I; /* Seek to the header position and read the header */ FileSetPos (F, Offset); ReadObjHeader (F, &H); /* Seek to the start of the string pool and read it */ FileSetPos (F, Offset + H.StrPoolOffs); ReadStrPool (F, &StrPool); /* Seek to the start of the source files */ FileSetPos (F, Offset + H.FileOffs); /* Output a header */ printf (" Files:\n"); /* Read the number of files and print it */ Count = ReadVar (F); printf (" Count:%27u\n", Count); /* Read and print all files */ for (I = 0; I < Count; ++I) { /* Read the data for one file */ const char* Name = GetString (&StrPool, ReadVar (F)); unsigned long MTime = Read32 (F); unsigned long Size = ReadVar (F); unsigned Len = strlen (Name); /* Print the header */ printf (" Index:%27u\n", I); /* Print the data */ printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name); printf (" Size:%26lu\n", Size); printf (" Modification time:%13lu (%s)\n", MTime, TimeToStr (MTime)); } /* Destroy the string pool */ DestroyStrPool (&StrPool); }
void DumpObjHeader (FILE* F, unsigned long Offset) /* Dump the header of the given object file */ { ObjHeader H; /* Seek to the header position */ FileSetPos (F, Offset); /* Read the header */ ReadObjHeader (F, &H); /* Now dump the information */ /* Output a header */ printf (" Header:\n"); /* Magic */ printf (" Magic:%17s0x%08lX\n", "", H.Magic); /* Version */ printf (" Version:%25u\n", H.Version); /* Flags */ printf (" Flags:%21s0x%04X (", "", H.Flags); if (H.Flags & OBJ_FLAGS_DBGINFO) { printf ("OBJ_FLAGS_DBGINFO"); } printf (")\n"); /* Options */ DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize); /* Files */ DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize); /* Segments */ DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize); /* Imports */ DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize); /* Exports */ DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize); /* Debug symbols */ DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize); /* Line infos */ DumpObjHeaderSection ("Line infos", H.LineInfoOffs, H.LineInfoSize); /* String pool */ DumpObjHeaderSection ("String pool", H.StrPoolOffs, H.StrPoolSize); /* Assertions */ DumpObjHeaderSection ("Assertions", H.AssertOffs, H.AssertSize); /* Scopes */ DumpObjHeaderSection ("Scopes", H.ScopeOffs, H.ScopeSize); }
void ObjReadScopes (FILE* F, unsigned long Pos, ObjData* O) /* Read the scope table from a file at the given offset */ { unsigned I; /* Seek to the correct position */ FileSetPos (F, Pos); /* Read the data */ O->ScopeCount = ReadVar (F); O->Scopes = xmalloc (O->ScopeCount * sizeof (O->Scopes[0])); for (I = 0; I < O->ScopeCount; ++I) { O->Scopes[I] = 0; /* ReadScope (F, O); ### not implemented */ } }
void ObjReadAssertions (FILE* F, unsigned long Pos, ObjData* O) /* Read the assertions from a file at the given offset */ { unsigned I; /* Seek to the correct position */ FileSetPos (F, Pos); /* Read the data */ O->AssertionCount = ReadVar (F); O->Assertions = xmalloc (O->AssertionCount * sizeof (O->Assertions[0])); for (I = 0; I < O->AssertionCount; ++I) { O->Assertions[I] = ReadAssertion (F, O); } }
void ObjReadStrPool (FILE* F, unsigned long Pos, ObjData* O) /* Read the string pool from a file at the given position */ { unsigned I; /* Seek to the correct position */ FileSetPos (F, Pos); /* Read the data */ O->StringCount = ReadVar (F); O->Strings = xmalloc (O->StringCount * sizeof (O->Strings[0])); for (I = 0; I < O->StringCount; ++I) { O->Strings[I] = ReadStr (F); } }
void ObjReadLineInfos (FILE* F, unsigned long Pos, ObjData* O) /* Read the line infos from a file at the given position */ { unsigned I; /* Seek to the correct position */ FileSetPos (F, Pos); /* Read the data */ O->LineInfoCount = ReadVar (F); O->LineInfos = xmalloc (O->LineInfoCount * sizeof (O->LineInfos[0])); for (I = 0; I < O->LineInfoCount; ++I) { O->LineInfos[I] = ReadLineInfo (F, O); } }
void ObjReadDbgSyms (FILE* F, unsigned long Pos, ObjData* O) /* Read the debug symbols from a file at the given position */ { unsigned I; /* Seek to the correct position */ FileSetPos (F, Pos); /* Read the data */ O->DbgSymCount = ReadVar (F); O->DbgSyms = xmalloc (O->DbgSymCount * sizeof (O->DbgSyms[0])); for (I = 0; I < O->DbgSymCount; ++I) { O->DbgSyms [I] = ReadDbgSym (F, O); } }
void DumpObjScopes (FILE* F, unsigned long Offset) /* Dump the scopes from an object file */ { ObjHeader H; Collection StrPool = AUTO_COLLECTION_INITIALIZER; unsigned Count; unsigned I; /* Seek to the header position and read the header */ FileSetPos (F, Offset); ReadObjHeader (F, &H); /* Seek to the start of the string pool and read it */ FileSetPos (F, Offset + H.StrPoolOffs); ReadStrPool (F, &StrPool); /* Seek to the start of scopes */ FileSetPos (F, Offset + H.ScopeOffs); /* Output a header */ printf (" Scopes:\n"); /* Check if the object file was compiled with debug info */ if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) { /* Print that there no scopes and bail out */ printf (" Count:%27u\n", 0); return; } /* Read the number of scopes and print it */ Count = ReadVar (F); printf (" Count:%27u\n", Count); /* Read and print all scopes */ for (I = 0; I < Count; ++I) { const char* Name; unsigned Len; /* Read the data */ unsigned ParentId = ReadVar (F); unsigned LexicalLevel = ReadVar (F); unsigned Flags = ReadVar (F); const char* ScopeType = GetScopeType (ReadVar (F)); /* Print the header */ printf (" Index:%27u\n", I); /* Print the data */ printf (" Parent id:%21u\n", ParentId); printf (" Lexical level:%17u\n", LexicalLevel); printf (" Flags:%21s0x%02X\n", "", Flags); printf (" Type:%26s\n", ScopeType); /* Resolve and print the name */ Name = GetString (&StrPool, ReadVar (F)); Len = strlen (Name); printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name); /* Size */ if (SCOPE_HAS_SIZE (Flags)) { unsigned long Size = ReadVar (F); printf (" Size:%20s0x%04lX (%lu)\n", "", Size, Size); } /* Label */ if (SCOPE_HAS_LABEL (Flags)) { unsigned LabelId = ReadVar (F); printf (" Label id:%22u\n", LabelId); } /* Skip the spans */ SkipSpanList (F); } /* Destroy the string pool */ DestroyStrPool (&StrPool); }
void DumpObjLineInfo (FILE* F, unsigned long Offset) /* Dump the line info from an object file */ { ObjHeader H; Collection StrPool = AUTO_COLLECTION_INITIALIZER; unsigned Count; unsigned I; /* Seek to the header position and read the header */ FileSetPos (F, Offset); ReadObjHeader (F, &H); /* Seek to the start of the string pool and read it */ FileSetPos (F, Offset + H.StrPoolOffs); ReadStrPool (F, &StrPool); /* Seek to the start of line infos */ FileSetPos (F, Offset + H.LineInfoOffs); /* Output a header */ printf (" Line info:\n"); /* Check if the object file was compiled with debug info */ if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) { /* Print that there no line infos and bail out */ printf (" Count:%27u\n", 0); return; } /* Read the number of line infos and print it */ Count = ReadVar (F); printf (" Count:%27u\n", Count); /* Read and print all line infos */ for (I = 0; I < Count; ++I) { FilePos Pos; unsigned Type; /* File position of line info */ ReadFilePos (F, &Pos); /* Type of line info */ Type = ReadVar (F); /* Skip the spans */ SkipSpanList (F); /* Print the header */ printf (" Index:%27u\n", I); /* Print the data */ printf (" Type:%26u\n", LI_GET_TYPE (Type)); printf (" Count:%25u\n", LI_GET_COUNT (Type)); printf (" Line:%26u\n", Pos.Line); printf (" Col:%27u\n", Pos.Col); printf (" Name:%26u\n", Pos.Name); } /* Destroy the string pool */ DestroyStrPool (&StrPool); }
void DumpObjDbgSyms (FILE* F, unsigned long Offset) /* Dump the debug symbols from an object file */ { ObjHeader H; Collection StrPool = AUTO_COLLECTION_INITIALIZER; unsigned Count; unsigned I; /* Seek to the header position and read the header */ FileSetPos (F, Offset); ReadObjHeader (F, &H); /* Seek to the start of the string pool and read it */ FileSetPos (F, Offset + H.StrPoolOffs); ReadStrPool (F, &StrPool); /* Seek to the start of the debug syms */ FileSetPos (F, Offset + H.DbgSymOffs); /* Output a header */ printf (" Debug symbols:\n"); /* Check if the object file was compiled with debug info */ if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) { /* Print that there no debug symbols and bail out */ printf (" Count:%27u\n", 0); return; } /* Read the number of exports and print it */ Count = ReadVar (F); printf (" Count:%27u\n", Count); /* Read and print all debug symbols */ for (I = 0; I < Count; ++I) { unsigned long Value = 0; unsigned long Size = 0; unsigned ImportId = 0; unsigned ExportId = 0; /* Read the data for one symbol */ unsigned Type = ReadVar (F); unsigned char AddrSize = Read8 (F); unsigned long Owner = ReadVar (F); const char* Name = GetString (&StrPool, ReadVar (F)); unsigned Len = strlen (Name); if (SYM_IS_CONST (Type)) { Value = Read32 (F); } else { SkipExpr (F); } if (SYM_HAS_SIZE (Type)) { Size = ReadVar (F); } if (SYM_IS_IMPORT (Type)) { ImportId = ReadVar (F); } if (SYM_IS_EXPORT (Type)) { ExportId = ReadVar (F); } /* Skip both line info lists */ SkipLineInfoList (F); SkipLineInfoList (F); /* Print the header */ printf (" Index:%27u\n", I); /* Print the data */ printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, 0)); printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize, AddrSizeToStr (AddrSize)); printf (" Owner:%25lu\n", Owner); printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name); if (SYM_IS_CONST (Type)) { printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value); } if (SYM_HAS_SIZE (Type)) { printf (" Size:%20s0x%04lX (%lu)\n", "", Size, Size); } if (SYM_IS_IMPORT (Type)) { printf (" Import:%24u\n", ImportId); } if (SYM_IS_EXPORT (Type)) { printf (" Export:%24u\n", ExportId); } } /* Destroy the string pool */ DestroyStrPool (&StrPool); }
void DumpObjExports (FILE* F, unsigned long Offset) /* Dump the exports in the object file */ { ObjHeader H; Collection StrPool = AUTO_COLLECTION_INITIALIZER; unsigned Count; unsigned I; /* Seek to the header position and read the header */ FileSetPos (F, Offset); ReadObjHeader (F, &H); /* Seek to the start of the string pool and read it */ FileSetPos (F, Offset + H.StrPoolOffs); ReadStrPool (F, &StrPool); /* Seek to the start of the exports */ FileSetPos (F, Offset + H.ExportOffs); /* Output a header */ printf (" Exports:\n"); /* Read the number of exports and print it */ Count = ReadVar (F); printf (" Count:%27u\n", Count); /* Read and print all exports */ for (I = 0; I < Count; ++I) { unsigned long Value = 0; unsigned long Size = 0; unsigned char ConDes[CD_TYPE_COUNT]; const char* Name; unsigned Len; /* Read the data for one export */ unsigned Type = ReadVar (F); unsigned char AddrSize = Read8 (F); ReadData (F, ConDes, SYM_GET_CONDES_COUNT (Type)); Name = GetString (&StrPool, ReadVar (F)); Len = strlen (Name); if (SYM_IS_CONST (Type)) { Value = Read32 (F); } else { SkipExpr (F); } if (SYM_HAS_SIZE (Type)) { Size = ReadVar (F); } /* Skip both line infos lists */ SkipLineInfoList (F); SkipLineInfoList (F); /* Print the header */ printf (" Index:%27u\n", I); /* Print the data */ printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes)); printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize, AddrSizeToStr (AddrSize)); printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name); if (SYM_IS_CONST (Type)) { printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value); } if (SYM_HAS_SIZE (Type)) { printf (" Size:%16s0x%04lX (%lu)\n", "", Size, Size); } } /* Destroy the string pool */ DestroyStrPool (&StrPool); }
void DumpObjOptions (FILE* F, unsigned long Offset) /* Dump the file options */ { ObjHeader H; Collection StrPool = AUTO_COLLECTION_INITIALIZER; unsigned Count; unsigned I; /* Seek to the header position and read the header */ FileSetPos (F, Offset); ReadObjHeader (F, &H); /* Seek to the start of the string pool and read it */ FileSetPos (F, Offset + H.StrPoolOffs); ReadStrPool (F, &StrPool); /* Seek to the start of the options */ FileSetPos (F, Offset + H.OptionOffs); /* Output a header */ printf (" Options:\n"); /* Read the number of options and print it */ Count = ReadVar (F); printf (" Count:%27u\n", Count); /* Read and print all options */ for (I = 0; I < Count; ++I) { const char* ArgStr; unsigned ArgLen; /* Read the type of the option and the value */ unsigned char Type = Read8 (F); unsigned long Val = ReadVar (F); /* Get the type of the argument */ unsigned char ArgType = Type & OPT_ARGMASK; /* Determine which option follows */ const char* TypeDesc; switch (Type) { case OPT_COMMENT: TypeDesc = "OPT_COMMENT"; break; case OPT_AUTHOR: TypeDesc = "OPT_AUTHOR"; break; case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR"; break; case OPT_COMPILER: TypeDesc = "OPT_COMPILER"; break; case OPT_OS: TypeDesc = "OPT_OS"; break; case OPT_DATETIME: TypeDesc = "OPT_DATETIME"; break; default: TypeDesc = "OPT_UNKNOWN"; break; } /* Print the header */ printf (" Index:%27u\n", I); /* Print the data */ printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc); switch (ArgType) { case OPT_ARGSTR: ArgStr = GetString (&StrPool, Val); ArgLen = strlen (ArgStr); printf (" Data:%*s\"%s\"\n", (int)(24-ArgLen), "", ArgStr); break; case OPT_ARGNUM: printf (" Data:%26lu", Val); if (Type == OPT_DATETIME) { /* Print the time as a string */ printf (" (%s)", TimeToStr (Val)); } printf ("\n"); break; default: /* Unknown argument type. This means that we cannot determine * the option length, so we cannot proceed. */ Error ("Unknown option type: 0x%02X", Type); break; } } /* Destroy the string pool */ DestroyStrPool (&StrPool); }
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)); } /* Read the PCX header */ P = ReadPCXHeader (F, Name); /* Dump the header if requested */ if (Verbosity > 0) { DumpPCXHeader (P, Name); } /* Create the bitmap */ B = NewBitmap (P->Width, P->Height); /* Copy the name */ SB_CopyStr (&B->Name, Name); /* Allocate memory for the scan line */ L = xmalloc (P->Width); /* Read the pixel data */ Px = B->Data; if (P->Planes == 1) { /* This is either monochrome or indexed */ if (P->BPP == 1) { /* Monochrome */ for (Y = 0, Px = B->Data; Y < P->Height; ++Y) { unsigned I; unsigned char Mask; /* Read the plane */ ReadPlane (F, P, L); /* Create pixels */ for (X = 0, I = 0, Mask = 0x01; X < P->Width; ++Px) { Px->Index = (L[I] & Mask) != 0; if (Mask == 0x80) { Mask = 0x01; ++I; } else { Mask <<= 1; } } } } else { /* One plane with 8bpp is indexed */ for (Y = 0, Px = B->Data; Y < P->Height; ++Y) { /* Read the plane */ ReadPlane (F, P, L); /* 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) { /* Read the R plane and move the data */ ReadPlane (F, P, L); for (X = 0; X < P->Width; ++X, ++Px) { Px->C.R = L[X]; } /* Read the G plane and move the data */ ReadPlane (F, P, L); for (X = 0; X < P->Width; ++X, ++Px) { Px->C.G = L[X]; } /* Read the B plane and move the data */ ReadPlane (F, P, L); for (X = 0; X < P->Width; ++X, ++Px) { Px->C.B = L[X]; } /* Either read the A plane or clear it */ if (P->Planes == 4) { ReadPlane (F, P, L); for (X = 0; X < P->Width; ++X, ++Px) { Px->C.A = L[X]; } } else { for (X = 0; X < P->Width; ++X, ++Px) { Px->C.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; }