/branches/WXSJ/????/??/???/Devil/src-IL/src/il_xpm.c
C | 583 lines | 442 code | 102 blank | 39 comment | 137 complexity | e7b21307b89331c95697de21d6174b2f MD5 | raw file
Possible License(s): Zlib, LGPL-2.1, LGPL-2.0
- //-----------------------------------------------------------------------------
- //
- // ImageLib Sources
- // Copyright (C) 2000-2002 by Denton Woods
- // Last modified: 05/27/2002 <--Y2K Compliant! =]
- //
- // Filename: src-IL/src/il_xpm.c
- //
- // Description: Reads from an .xpm file.
- //
- //-----------------------------------------------------------------------------
-
-
- #include "il_internal.h"
- #ifndef IL_NO_XPM
- #include <ctype.h>
-
- //If this is defined, only xpm files with 1 char/pixel
- //can be loaded. They load somewhat faster then, though
- //(not much).
- //#define XPM_DONT_USE_HASHTABLE
-
- ILboolean iLoadXpmInternal(ILvoid);
-
-
- // Reads an .xpm file
- ILboolean ilLoadXpm(const ILstring FileName)
- {
- ILHANDLE XpmFile;
- ILboolean bXpm = IL_FALSE;
-
- XpmFile = iopenr(FileName);
- if (XpmFile == NULL) {
- ilSetError(IL_COULD_NOT_OPEN_FILE);
- return bXpm;
- }
-
- iSetInputFile(XpmFile);
-
- bXpm = ilLoadXpmF(XpmFile);
-
- icloser(XpmFile);
-
- return bXpm;
- }
-
-
- //! Reads an already-opened .xpm file
- ILboolean ilLoadXpmF(ILHANDLE File)
- {
- ILuint FirstPos;
- ILboolean bRet;
-
- iSetInputFile(File);
- FirstPos = itell();
- bRet = iLoadXpmInternal();
- iseek(FirstPos, IL_SEEK_SET);
-
- return bRet;
- }
-
-
- //! Reads from a memory "lump" that contains an .xpm
- ILboolean ilLoadXpmL(ILvoid *Lump, ILuint Size)
- {
- iSetInputLump(Lump, Size);
- return iLoadXpmInternal();
- }
-
- typedef ILubyte XpmPixel[4];
- #define XPM_MAX_CHAR_PER_PIXEL 2
-
-
- #ifndef XPM_DONT_USE_HASHTABLE
-
- //The following hash table code was inspired by the xpm
- //loading code of xv, one of the best image viewers of X11
-
- //For xpm files with more than one character/pixel, it is
- //impractical to use a simple lookup table for the
- //character-to-color mapping (because the table requires
- //2^(chars/pixel) entries, this is quite big).
- //Because of that, a hash table is used for the mapping.
- //The hash table has 257 entries, and collisions are
- //resolved by chaining.
-
- //257 is the smallest prime > 256
- #define XPM_HASH_LEN 257
-
- typedef struct XPMHASHENTRY
- {
- ILubyte ColourName[XPM_MAX_CHAR_PER_PIXEL];
- XpmPixel ColourValue;
- struct XPMHASHENTRY *Next;
- } XPMHASHENTRY;
-
-
- static ILuint XpmHash(const ILubyte* name, int len)
- {
- ILint i, sum;
- for (sum = i = 0; i < len; ++i)
- sum += name[i];
- return sum % XPM_HASH_LEN;
- }
-
-
- XPMHASHENTRY** XpmCreateHashTable()
- {
- XPMHASHENTRY** Table =
- (XPMHASHENTRY**)ialloc(XPM_HASH_LEN*sizeof(XPMHASHENTRY*));
- if (Table != NULL)
- memset(Table, 0, XPM_HASH_LEN*sizeof(XPMHASHENTRY*));
- return Table;
- }
-
-
- void XpmDestroyHashTable(XPMHASHENTRY **Table)
- {
- ILint i;
- XPMHASHENTRY* Entry;
-
- for (i = 0; i < XPM_HASH_LEN; ++i) {
- while (Table[i] != NULL) {
- Entry = Table[i]->Next;
- ifree(Table[i]);
- Table[i] = Entry;
- }
- }
-
- ifree(Table);
- }
-
-
- void XpmInsertEntry(XPMHASHENTRY **Table, const ILubyte* Name, int Len, XpmPixel Colour)
- {
- XPMHASHENTRY* NewEntry;
- ILuint Index;
- Index = XpmHash(Name, Len);
-
- NewEntry = (XPMHASHENTRY*)ialloc(sizeof(XPMHASHENTRY));
- if (NewEntry != NULL) {
- NewEntry->Next = Table[Index];
- memcpy(NewEntry->ColourName, Name, Len);
- memcpy(NewEntry->ColourValue, Colour, sizeof(Colour));
- Table[Index] = NewEntry;
- }
- }
-
-
- void XpmGetEntry(XPMHASHENTRY **Table, const ILubyte* Name, int Len, XpmPixel Colour)
- {
- XPMHASHENTRY* Entry;
- ILuint Index;
-
- Index = XpmHash(Name, Len);
- Entry = Table[Index];
- while (Entry != NULL && strncmp((char*)(Entry->ColourName), (char*)Name, Len) != 0)
- Entry = Entry->Next;
-
- if (Entry != NULL)
- memcpy(Colour, Entry->ColourValue, sizeof(Colour));
- }
-
- #endif //XPM_DONT_USE_HASHTABLE
-
-
- ILint XpmGetsInternal(ILubyte *Buffer, ILint MaxLen)
- {
- ILint i = 0, Current;
-
- if (ieof())
- return IL_EOF;
-
- while ((Current = igetc()) != IL_EOF && i < MaxLen - 1) {
- if (Current == IL_EOF)
- return 0;
- if (Current == '\n') //unix line ending
- break;
- if (Current == '\r') { //dos/mac line ending
- Current = igetc();
- if (Current == '\n') //dos line ending
- break;
-
- if (Current == IL_EOF)
- break;
-
- Buffer[i++] = Current;
- continue;
- }
-
- Buffer[i++] = Current;
- }
-
- Buffer[i++] = 0;
-
- return i;
- }
-
-
- ILint XpmGets(ILubyte *Buffer, ILint MaxLen)
- {
- ILint Size, i, j;
- ILboolean NotComment = IL_FALSE, InsideComment = IL_FALSE;
-
- do {
- Size = XpmGetsInternal(Buffer, MaxLen);
- if (Size == IL_EOF)
- return IL_EOF;
-
- //stip leading whitespace (sometimes there's whitespace
- //before a comment or before the pixel data)
- for(i = 0; i < Size && isspace(Buffer[i]); ++i) ;
- Size = Size - i;
- for(j = 0; j < Size; ++j)
- Buffer[j] = Buffer[j + i];
-
-
- if (Size == 0)
- continue;
-
- if (Buffer[0] == '/' && Buffer[1] == '*') {
- for (i = 2; i < Size; i++) {
- if (Buffer[i] == '*' && Buffer[i+1] == '/') {
- break;
- }
- }
- if (i >= Size)
- InsideComment = IL_TRUE;
- }
- else if (InsideComment) {
- for (i = 0; i < Size; i++) {
- if (Buffer[i] == '*' && Buffer[i+1] == '/') {
- break;
- }
- }
- if (i < Size)
- InsideComment = IL_FALSE;
- }
- else {
- NotComment = IL_TRUE;
- }
- } while (!NotComment);
-
- return Size;
- }
-
-
- ILint XpmGetInt(ILubyte *Buffer, ILint Size, ILint *Position)
- {
- char Buff[1024];
- ILint i, j;
- ILboolean IsInNum = IL_FALSE;
-
- for (i = *Position, j = 0; i < Size; i++) {
- if (isdigit(Buffer[i])) {
- IsInNum = IL_TRUE;
- Buff[j++] = Buffer[i];
- }
- else {
- if (IsInNum) {
- Buff[j] = 0;
- *Position = i;
- return atoi(Buff);
- }
- }
- }
-
- return -1;
- }
-
-
- ILboolean XpmPredefCol(char *Buff, XpmPixel *Colour)
- {
- ILint len;
- ILint val = 128;
-
- if (!stricmp(Buff, "none")) {
- (*Colour)[0] = 0;
- (*Colour)[1] = 0;
- (*Colour)[2] = 0;
- (*Colour)[3] = 0;
- return IL_TRUE;
- }
-
- (*Colour)[3] = 255;
-
- if (!stricmp(Buff, "black")) {
- (*Colour)[0] = 0;
- (*Colour)[1] = 0;
- (*Colour)[2] = 0;
- return IL_TRUE;
- }
- if (!stricmp(Buff, "white")) {
- (*Colour)[0] = 255;
- (*Colour)[1] = 255;
- (*Colour)[2] = 255;
- return IL_TRUE;
- }
- if (!stricmp(Buff, "red")) {
- (*Colour)[0] = 255;
- (*Colour)[1] = 0;
- (*Colour)[2] = 0;
- return IL_TRUE;
- }
- if (!stricmp(Buff, "green")) {
- (*Colour)[0] = 0;
- (*Colour)[1] = 255;
- (*Colour)[2] = 0;
- return IL_TRUE;
- }
- if (!stricmp(Buff, "blue")) {
- (*Colour)[0] = 0;
- (*Colour)[1] = 0;
- (*Colour)[2] = 255;
- return IL_TRUE;
- }
- if (!stricmp(Buff, "yellow")) {
- (*Colour)[0] = 255;
- (*Colour)[1] = 255;
- (*Colour)[2] = 0;
- return IL_TRUE;
- }
- if (!stricmp(Buff, "cyan")) {
- (*Colour)[0] = 0;
- (*Colour)[1] = 255;
- (*Colour)[2] = 255;
- return IL_TRUE;
- }
- if (!stricmp(Buff, "gray")) {
- (*Colour)[0] = 128;
- (*Colour)[1] = 128;
- (*Colour)[2] = 128;
- return IL_TRUE;
- }
-
- //check for grayXXX codes (added 20040218)
- len = strlen(Buff);
- if (len >= 4) {
- if (Buff[0] == 'g' || Buff[0] == 'G'
- || Buff[1] == 'r' || Buff[1] == 'R'
- || Buff[2] == 'a' || Buff[2] == 'A'
- || Buff[3] == 'y' || Buff[3] == 'Y') {
- if (isdigit(Buff[4])) { // isdigit returns false on '\0'
- val = Buff[4] - '0';
- if (isdigit(Buff[5])) {
- val = val*10 + Buff[5] - '0';
- if (isdigit(Buff[6]))
- val = val*10 + Buff[6] - '0';
- }
- val = (255*val)/100;
- }
- (*Colour)[0] = val;
- (*Colour)[1] = val;
- (*Colour)[2] = val;
- return IL_TRUE;
- }
- }
-
-
- // Unknown colour string, so use black
- // (changed 20040218)
- (*Colour)[0] = 0;
- (*Colour)[1] = 0;
- (*Colour)[2] = 0;
-
- return IL_FALSE;
- }
-
-
- #ifndef XPM_DONT_USE_HASHTABLE
- ILboolean XpmGetColour(ILubyte *Buffer, ILint Size, int Len, XPMHASHENTRY **Table)
- #else
- ILboolean XpmGetColour(ILubyte *Buffer, ILint Size, int Len, XpmPixel* Colours)
- #endif
- {
- ILint i = 0, j, strLen = 0;
- ILubyte ColBuff[3];
- char Buff[1024];
- XpmPixel Colour;
- ILubyte Name[XPM_MAX_CHAR_PER_PIXEL];
-
- for ( ; i < Size; i++) {
- if (Buffer[i] == '\"')
- break;
- }
- i++; // Skip the quotes.
-
- if (i >= Size)
- return IL_FALSE;
-
- // Get the characters.
- for (j = 0; j < Len; ++j) {
- Name[j] = Buffer[i++];
- }
-
- // Skip to the colour definition.
- for ( ; i < Size; i++) {
- if (Buffer[i] == 'c')
- break;
- }
- i++; // Skip the 'c'.
-
- if (i >= Size || Buffer[i] != ' ') { // no 'c' found...assume black
- #ifndef XPM_DONT_USE_HASHTABLE
- memset(Colour, 0, sizeof(Colour));
- Colour[3] = 255;
- XpmInsertEntry(Table, Name, Len, Colour);
- #else
- memset(Colours[Name[0]], 0, sizeof(Colour));
- Colours[Name[0]][3] = 255;
- #endif
- return IL_TRUE;
- }
-
- for ( ; i < Size; i++) {
- if (Buffer[i] != ' ')
- break;
- }
-
- if (i >= Size)
- return IL_FALSE;
-
- if (Buffer[i] == '#') {
- // colour string may 4 digits/color or 1 digit/color
- // (added 20040218) TODO: is isxdigit() ANSI???
- ++i;
- while (i + strLen < Size && isxdigit(Buffer[i + strLen]))
- ++strLen;
-
- for (j = 0; j < 3; j++) {
- if (strLen >= 10) { // 4 digits
- ColBuff[0] = Buffer[i + j*4];
- ColBuff[1] = Buffer[i + j*4 + 1];
- }
- else if (strLen >= 8) { // 3 digits
- ColBuff[0] = Buffer[i + j*3];
- ColBuff[1] = Buffer[i + j*3 + 1];
- }
- else if (strLen >= 6) { // 2 digits
- ColBuff[0] = Buffer[i + j*2];
- ColBuff[1] = Buffer[i + j*2 + 1];
- }
- else if(j < strLen) { // 1 digit, strLen >= 1
- ColBuff[0] = Buffer[i + j];
- ColBuff[1] = 0;
- }
-
- ColBuff[2] = 0; // add terminating '\0' char
- Colour[j] = (ILubyte)strtol((char*)ColBuff, NULL, 16);
- }
- Colour[3] = 255; // Full alpha.
- }
- else {
- for (j = 0; i < Size; i++) {
- if (!isalnum(Buffer[i]))
- break;
- Buff[j++] = Buffer[i];
- }
- Buff[j] = 0;
-
- if (i >= Size)
- return IL_FALSE;
-
- if (!XpmPredefCol(Buff, &Colour))
- return IL_FALSE;
- }
-
- #ifndef XPM_DONT_USE_HASHTABLE
- XpmInsertEntry(Table, Name, Len, Colour);
- #else
- memcpy(Colours[Name[0]], Colour, sizeof(Colour));
- #endif
-
- return IL_TRUE;
- }
-
-
- ILboolean iLoadXpmInternal()
- {
- #define BUFFER_SIZE 2000
- ILubyte Buffer[BUFFER_SIZE], *Data;
- ILint Size, Pos, Width, Height, NumColours, i, x, y;
- ILint CharsPerPixel;
- #ifndef XPM_DONT_USE_HASHTABLE
- XPMHASHENTRY **HashTable;
- #else
- XpmPixel *Colours;
- ILint Offset;
- #endif
-
- Size = XpmGetsInternal(Buffer, BUFFER_SIZE);
- if (strncmp("/* XPM */", (char*)Buffer, strlen("/* XPM */"))) {
- ilSetError(IL_INVALID_FILE_HEADER);
- return IL_FALSE;
- }
-
- Size = XpmGets(Buffer, BUFFER_SIZE);
- // @TODO: Actually check the variable name here.
-
- Size = XpmGets(Buffer, BUFFER_SIZE);
- Pos = 0;
- Width = XpmGetInt(Buffer, Size, &Pos);
- Height = XpmGetInt(Buffer, Size, &Pos);
- NumColours = XpmGetInt(Buffer, Size, &Pos);
- CharsPerPixel = XpmGetInt(Buffer, Size, &Pos);
-
- #ifdef XPM_DONT_USE_HASHTABLE
- if (CharsPerPixel != 1) {
- ilSetError(IL_FORMAT_NOT_SUPPORTED);
- return IL_FALSE;
- }
- #endif
-
- if (CharsPerPixel > XPM_MAX_CHAR_PER_PIXEL
- || Width*CharsPerPixel > BUFFER_SIZE) {
- ilSetError(IL_FORMAT_NOT_SUPPORTED);
- return IL_FALSE;
- }
-
- #ifndef XPM_DONT_USE_HASHTABLE
- HashTable = XpmCreateHashTable();
- if (HashTable == NULL)
- return IL_FALSE;
- #else
- Colours = ialloc(256 * sizeof(XpmPixel));
- if (Colours == NULL)
- return IL_FALSE;
- #endif
-
- for (i = 0; i < NumColours; i++) {
- Size = XpmGets(Buffer, BUFFER_SIZE);
- #ifndef XPM_DONT_USE_HASHTABLE
- if (!XpmGetColour(Buffer, Size, CharsPerPixel, HashTable)) {
- XpmDestroyHashTable(HashTable);
- #else
- if (!XpmGetColour(Buffer, Size, CharsPerPixel, Colours)) {
- ifree(Colours);
- #endif
- return IL_FALSE;
- }
- }
-
- if (!ilTexImage(Width, Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
- #ifndef XPM_DONT_USE_HASHTABLE
- XpmDestroyHashTable(HashTable);
- #else
- ifree(Colours);
- #endif
- return IL_FALSE;
- }
-
- Data = iCurImage->Data;
- for (y = 0; y < Height; y++) {
- Size = XpmGets(Buffer, BUFFER_SIZE);
- for (x = 0; x < Width; x++) {
- #ifndef XPM_DONT_USE_HASHTABLE
- XpmGetEntry(HashTable, &Buffer[1 + x*CharsPerPixel], CharsPerPixel, &Data[(x << 2)]);
- #else
- Offset = (x << 2);
- Data[Offset + 0] = Colours[Buffer[x + 1]][0];
- Data[Offset + 1] = Colours[Buffer[x + 1]][1];
- Data[Offset + 2] = Colours[Buffer[x + 1]][2];
- Data[Offset + 3] = Colours[Buffer[x + 1]][3];
- #endif
- }
- Data += iCurImage->Bps;
- }
-
- //added 20040218
- iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
-
- #ifndef XPM_DONT_USE_HASHTABLE
- XpmDestroyHashTable(HashTable);
- #else
- ifree(Colours);
- #endif
-
- return IL_TRUE;
- #undef BUFFER_SIZE
- }
-
- #endif//IL_NO_XPM
-