summaryrefslogtreecommitdiff
path: root/DevIL/src-IL/src/il_dcx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'DevIL/src-IL/src/il_dcx.cpp')
-rw-r--r--DevIL/src-IL/src/il_dcx.cpp485
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