diff options
Diffstat (limited to 'DevIL/src-IL/src/il_dcx.cpp')
-rw-r--r-- | DevIL/src-IL/src/il_dcx.cpp | 485 |
1 files changed, 485 insertions, 0 deletions
diff --git a/DevIL/src-IL/src/il_dcx.cpp b/DevIL/src-IL/src/il_dcx.cpp new file mode 100644 index 00000000..ec07e3ff --- /dev/null +++ b/DevIL/src-IL/src/il_dcx.cpp @@ -0,0 +1,485 @@ +//----------------------------------------------------------------------------- +// +// ImageLib Sources +// Copyright (C) 2000-2009 by Denton Woods +// Last modified: 03/07/2009 +// +// Filename: src-IL/src/il_dcx.c +// +// Description: Reads from a .dcx file. +// +//----------------------------------------------------------------------------- + + +#include "il_internal.h" +#ifndef IL_NO_DCX +#include "il_dcx.h" + + +//! Checks if the file specified in FileName is a valid .dcx file. +ILboolean ilIsValidDcx(ILconst_string FileName) +{ + ILHANDLE DcxFile; + ILboolean bDcx = IL_FALSE; + + if (!iCheckExtension(FileName, IL_TEXT("dcx"))) { + ilSetError(IL_INVALID_EXTENSION); + return bDcx; + } + + DcxFile = iopenr(FileName); + if (DcxFile == NULL) { + ilSetError(IL_COULD_NOT_OPEN_FILE); + return bDcx; + } + + bDcx = ilIsValidDcxF(DcxFile); + icloser(DcxFile); + + return bDcx; +} + + +//! Checks if the ILHANDLE contains a valid .dcx file at the current position. +ILboolean ilIsValidDcxF(ILHANDLE File) +{ + ILuint FirstPos; + ILboolean bRet; + + iSetInputFile(File); + FirstPos = itell(); + bRet = iIsValidDcx(); + iseek(FirstPos, IL_SEEK_SET); + + return bRet; +} + + +//! Checks if Lump is a valid .dcx lump. +ILboolean ilIsValidDcxL(const void *Lump, ILuint Size) +{ + iSetInputLump(Lump, Size); + return iIsValidDcx(); +} + + +// Internal function obtain the .dcx header from the current file. +ILboolean iGetDcxHead(DCXHEAD *Head) +{ + Head->Xmin = GetLittleUShort(); + Head->Ymin = GetLittleUShort(); + Head->Xmax = GetLittleUShort(); + Head->Ymax = GetLittleUShort(); + Head->HDpi = GetLittleUShort(); + Head->VDpi = GetLittleUShort(); + Head->Bps = GetLittleUShort(); + Head->PaletteInfo = GetLittleUShort(); + Head->HScreenSize = GetLittleUShort(); + Head->VScreenSize = GetLittleUShort(); + + return IL_TRUE; +} + + +// Internal function to get the header and check it. +ILboolean iIsValidDcx() +{ + ILuint Signature; + + if (iread(&Signature, 1, 4) != 4) + return IL_FALSE; + iseek(-4, IL_SEEK_CUR); + + return (Signature == 987654321); +} + + +// Internal function used to check if the HEADER is a valid .dcx header. +// Should we also do a check on Header->Bpp? +ILboolean iCheckDcx(DCXHEAD *Header) +{ + ILuint Test, i; + + // There are other versions, but I am not supporting them as of yet. + // Got rid of the Reserved check, because I've seen some .dcx files with invalid values in it. + if (Header->Manufacturer != 10 || Header->Version != 5 || Header->Encoding != 1/* || Header->Reserved != 0*/) + return IL_FALSE; + + // See if the padding size is correct + Test = Header->Xmax - Header->Xmin + 1; + /*if (Header->Bpp >= 8) { + if (Test & 1) { + if (Header->Bps != Test + 1) + return IL_FALSE; + } + else { + if (Header->Bps != Test) // No padding + return IL_FALSE; + } + }*/ + + for (i = 0; i < 54; i++) { + if (Header->Filler[i] != 0) + return IL_FALSE; + } + + return IL_TRUE; +} + + +//! Reads a .dcx file +ILboolean ilLoadDcx(ILconst_string FileName) +{ + ILHANDLE DcxFile; + ILboolean bDcx = IL_FALSE; + + DcxFile = iopenr(FileName); + if (DcxFile == NULL) { + ilSetError(IL_COULD_NOT_OPEN_FILE); + return bDcx; + } + + bDcx = ilLoadDcxF(DcxFile); + icloser(DcxFile); + + return bDcx; +} + + +//! Reads an already-opened .dcx file +ILboolean ilLoadDcxF(ILHANDLE File) +{ + ILuint FirstPos; + ILboolean bRet; + + iSetInputFile(File); + FirstPos = itell(); + bRet = iLoadDcxInternal(); + iseek(FirstPos, IL_SEEK_SET); + + return bRet; +} + + +//! Reads from a memory "lump" that contains a .dcx +ILboolean ilLoadDcxL(const void *Lump, ILuint Size) { + iSetInputLump(Lump, Size); + return iLoadDcxInternal(); +} + + +// Internal function used to load the .dcx. +ILboolean iLoadDcxInternal() +{ + DCXHEAD Header; + ILuint Signature, i, Entries[1024], Num = 0; + ILimage *Image, *Base; + + if (iCurImage == NULL) { + ilSetError(IL_ILLEGAL_OPERATION); + return IL_FALSE; + } + + if (!iIsValidDcx()) + return IL_FALSE; + iread(&Signature, 1, 4); + + do { + if (iread(&Entries[Num], 1, 4) != 4) + return IL_FALSE; + Num++; + } while (Entries[Num-1] != 0); + + for (i = 0; i < Num; i++) { + iseek(Entries[i], IL_SEEK_SET); + iGetDcxHead(&Header); + /*if (!iCheckDcx(&Header)) { + ilSetError(IL_INVALID_FILE_HEADER); + return IL_FALSE; + }*/ + + Image = iUncompressDcx(&Header); + if (Image == NULL) + return IL_FALSE; + + if (i == 0) { + ilTexImage(Image->Width, Image->Height, 1, Image->Bpp, Image->Format, Image->Type, Image->Data); + Base = iCurImage; + Base->Origin = IL_ORIGIN_UPPER_LEFT; + ilCloseImage(Image); + } + else { + iCurImage->Next = Image; + iCurImage = iCurImage->Next; + } + } + + return ilFixImage(); +} + + +// Internal function to uncompress the .dcx (all .dcx files are rle compressed) +ILimage *iUncompressDcx(DCXHEAD *Header) +{ + ILubyte ByteHead, Colour, *ScanLine = NULL /* Only one plane */; + ILuint c, i, x, y;//, Read = 0; + ILimage *Image = NULL; + + if (Header->Bpp < 8) { + /*ilSetError(IL_FORMAT_NOT_SUPPORTED); + return IL_FALSE;*/ + return iUncompressDcxSmall(Header); + } + + Image = ilNewImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 1); + if (Image == NULL) + return NULL; + /*if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 0, IL_UNSIGNED_BYTE, NULL)) { + return IL_FALSE; + }*/ + Image->Origin = IL_ORIGIN_UPPER_LEFT; + + ScanLine = (ILubyte*)ialloc(Header->Bps); + if (ScanLine == NULL) + goto dcx_error; + + switch (Image->Bpp) + { + case 1: + Image->Format = IL_COLOUR_INDEX; + Image->Pal.PalType = IL_PAL_RGB24; + Image->Pal.PalSize = 256 * 3; // Need to find out for sure... + Image->Pal.Palette = (ILubyte*)ialloc(Image->Pal.PalSize); + if (Image->Pal.Palette == NULL) + goto dcx_error; + break; + //case 2: // No 16-bit images in the dcx format! + case 3: + Image->Format = IL_RGB; + Image->Pal.Palette = NULL; + Image->Pal.PalSize = 0; + Image->Pal.PalType = IL_PAL_NONE; + break; + case 4: + Image->Format = IL_RGBA; + Image->Pal.Palette = NULL; + Image->Pal.PalSize = 0; + Image->Pal.PalType = IL_PAL_NONE; + break; + + default: + ilSetError(IL_ILLEGAL_FILE_VALUE); + goto dcx_error; + } + + + /*StartPos = itell(); + Compressed = (ILubyte*)ialloc(Image->SizeOfData * 4 / 3); + iread(Compressed, 1, Image->SizeOfData * 4 / 3); + + for (y = 0; y < Image->Height; y++) { + for (c = 0; c < Image->Bpp; c++) { + x = 0; + while (x < Header->Bps) { + ByteHead = Compressed[Read++]; + if ((ByteHead & 0xC0) == 0xC0) { + ByteHead &= 0x3F; + Colour = Compressed[Read++]; + for (i = 0; i < ByteHead; i++) { + ScanLine[x++] = Colour; + } + } + else { + ScanLine[x++] = ByteHead; + } + } + + for (x = 0; x < Image->Width; x++) { // 'Cleverly' ignores the pad bytes ;) + Image->Data[y * Image->Bps + x * Image->Bpp + c] = ScanLine[x]; + } + } + } + + ifree(Compressed); + iseek(StartPos + Read, IL_SEEK_SET);*/ + + //changed 2003-09-01 + if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST) + iPreCache(iCurImage->SizeOfData); + + //TODO: because the .pcx-code was broken this + //code is probably broken, too + for (y = 0; y < Image->Height; y++) { + for (c = 0; c < Image->Bpp; c++) { + x = 0; + while (x < Header->Bps) { + if (iread(&ByteHead, 1, 1) != 1) { + iUnCache(); + goto dcx_error; + } + if ((ByteHead & 0xC0) == 0xC0) { + ByteHead &= 0x3F; + if (iread(&Colour, 1, 1) != 1) { + iUnCache(); + goto dcx_error; + } + for (i = 0; i < ByteHead; i++) { + ScanLine[x++] = Colour; + } + } + else { + ScanLine[x++] = ByteHead; + } + } + + for (x = 0; x < Image->Width; x++) { // 'Cleverly' ignores the pad bytes ;) + Image->Data[y * Image->Bps + x * Image->Bpp + c] = ScanLine[x]; + } + } + } + + iUnCache(); + + + ifree(ScanLine); + + // Read in the palette + if (Image->Bpp == 1) { + ByteHead = igetc(); // the value 12, because it signals there's a palette for some reason... + // We should do a check to make certain it's 12... + if (ByteHead != 12) + iseek(-1, IL_SEEK_CUR); + if (iread(Image->Pal.Palette, 1, Image->Pal.PalSize) != Image->Pal.PalSize) { + ilCloseImage(Image); + return NULL; + } + } + + return Image; + +dcx_error: + ifree(ScanLine); + ilCloseImage(Image); + return NULL; +} + + +ILimage *iUncompressDcxSmall(DCXHEAD *Header) +{ + ILuint i = 0, j, k, c, d, x, y, Bps; + ILubyte HeadByte, Colour, Data = 0, *ScanLine = NULL; + ILimage *Image; + + Image = ilNewImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 1); + if (Image == NULL) + return NULL; + + /*if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, 1, 0, IL_UNSIGNED_BYTE, NULL)) { + return IL_FALSE; + }*/ + Image->Origin = IL_ORIGIN_UPPER_LEFT; + + switch (Header->NumPlanes) + { + case 1: + Image->Format = IL_LUMINANCE; + break; + case 4: + Image->Format = IL_COLOUR_INDEX; + break; + default: + ilSetError(IL_ILLEGAL_FILE_VALUE); + ilCloseImage(Image); + return NULL; + } + + if (Header->NumPlanes == 1) { + for (j = 0; j < Image->Height; j++) { + i = 0; + while (i < Image->Width) { + if (iread(&HeadByte, 1, 1) != 1) + goto file_read_error; + if (HeadByte >= 192) { + HeadByte -= 192; + if (iread(&Data, 1, 1) != 1) + goto file_read_error; + + for (c = 0; c < HeadByte; c++) { + k = 128; + for (d = 0; d < 8 && i < Image->Width; d++) { + Image->Data[j * Image->Width + i++] = (!!(Data & k) == 1 ? 255 : 0); + k >>= 1; + } + } + } + else { + k = 128; + for (c = 0; c < 8 && i < Image->Width; c++) { + Image->Data[j * Image->Width + i++] = (!!(HeadByte & k) == 1 ? 255 : 0); + k >>= 1; + } + } + } + if (Data != 0) + igetc(); // Skip pad byte if last byte not a 0 + } + } + else { // 4-bit images + Bps = Header->Bps * Header->NumPlanes * 2; + Image->Pal.Palette = (ILubyte*)ialloc(16 * 3); // Size of palette always (48 bytes). + Image->Pal.PalSize = 16 * 3; + Image->Pal.PalType = IL_PAL_RGB24; + ScanLine = (ILubyte*)ialloc(Bps); + if (Image->Pal.Palette == NULL || ScanLine == NULL) { + ifree(ScanLine); + ilCloseImage(Image); + return NULL; + } + + memcpy(Image->Pal.Palette, Header->ColMap, 16 * 3); + imemclear(Image->Data, Image->SizeOfData); // Since we do a += later. + + for (y = 0; y < Image->Height; y++) { + for (c = 0; c < Header->NumPlanes; c++) { + x = 0; + while (x < Bps) { + if (iread(&HeadByte, 1, 1) != 1) + goto file_read_error; + if ((HeadByte & 0xC0) == 0xC0) { + HeadByte &= 0x3F; + if (iread(&Colour, 1, 1) != 1) + goto file_read_error; + for (i = 0; i < HeadByte; i++) { + k = 128; + for (j = 0; j < 8; j++) { + ScanLine[x++] = !!(Colour & k); + k >>= 1; + } + } + } + else { + k = 128; + for (j = 0; j < 8; j++) { + ScanLine[x++] = !!(HeadByte & k); + k >>= 1; + } + } + } + + for (x = 0; x < Image->Width; x++) { // 'Cleverly' ignores the pad bytes. ;) + Image->Data[y * Image->Width + x] += ScanLine[x] << c; + } + } + } + ifree(ScanLine); + } + + return Image; + +file_read_error: + ifree(ScanLine); + ilCloseImage(Image); + return NULL; +} + +#endif//IL_NO_DCX |