- Main Page
- Data Structures
- Files

- File List

# E:/DevIL/src-IL/src/il_xpm.c

    00001 //-----------------------------------------------------------------------------
    00002 //
    00003 // ImageLib Sources
    00004 // Copyright (C) 2000-2009 by Denton Woods
    00005 // Last modified: 01/04/2009
    00006 //
    00007 // Filename: src-IL/src/il_xpm.c
    00008 //
    00009 // Description: Reads from an .xpm file.
    00010 //
    00011 //-----------------------------------------------------------------------------
    00012
    00013
    00014 #include "il_internal.h"
    00015 #ifndef IL_NO_XPM
    00016 #include <ctype.h>
    00017
    00018
    00019 //If this is defined, only xpm files with 1 char/pixel
    00020 //can be loaded. They load somewhat faster then, though
    00021 //(not much).
    00022 //#define XPM_DONT_USE_HASHTABLE
    00023
    00024 ILboolean iIsValidXpm(void);
    00025 ILboolean iLoadXpmInternal(void);
    00026 ILint XpmGetsInternal(ILubyte *Buffer, ILint MaxLen);
    00027
    00029 ILboolean ilIsValidXpm(ILconst_string FileName)
    00030 {
    00031         ILHANDLE        XpmFile;
    00032         ILboolean       bXpm = IL_FALSE;
    00033
    00034         if (!iCheckExtension(FileName, IL_TEXT("xpm"))) {
    00035                 ilSetError(IL_INVALID_EXTENSION);
    00036                 return bXpm;
    00037         }
    00038
    00039         XpmFile = iopenr(FileName);
    00040         if (XpmFile == NULL) {
    00041                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00042                 return bXpm;
    00043         }
    00044
    00045         bXpm = ilIsValidXpmF(XpmFile);
    00046         icloser(XpmFile);
    00047
    00048         return bXpm;
    00049 }
    00050
    00051
    00053 ILboolean ilIsValidXpmF(ILHANDLE File)
    00054 {
    00055         ILuint          FirstPos;
    00056         ILboolean       bRet;
    00057
    00058         iSetInputFile(File);
    00059         FirstPos = itell();
    00060         bRet = iIsValidXpm();
    00061         iseek(FirstPos, IL_SEEK_SET);
    00062
    00063         return bRet;
    00064 }
    00065
    00066
    00068 ILboolean ilIsValidXpmL(const void *Lump, ILuint Size)
    00069 {
    00070         iSetInputLump(Lump, Size);
    00071         return iIsValidXpm();
    00072 }
    00073
    00074
    00075 // Internal function to get the header and check it.
    00076 ILboolean iIsValidXpm(void)
    00077 {
    00078         ILubyte Buffer[10];
    00079         ILuint  Pos = itell();
    00080
    00081         XpmGetsInternal(Buffer, 10);
    00082         iseek(Pos, IL_SEEK_SET);  // Restore position
    00083
    00084         if (strncmp("/* XPM */", (char*)Buffer, strlen("/* XPM */")))
    00085                 return IL_FALSE;
    00086         return IL_TRUE;
    00087 }
    00088
    00089
    00090 // Reads an .xpm file
    00091 ILboolean ilLoadXpm(ILconst_string FileName)
    00092 {
    00093         ILHANDLE        XpmFile;
    00094         ILboolean       bXpm = IL_FALSE;
    00095
    00096         XpmFile = iopenr(FileName);
    00097         if (XpmFile == NULL) {
    00098                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00099                 return bXpm;
    00100         }
    00101
    00102         iSetInputFile(XpmFile);
    00103         bXpm = ilLoadXpmF(XpmFile);
    00104         icloser(XpmFile);
    00105
    00106         return bXpm;
    00107 }
    00108
    00109
    00111 ILboolean ilLoadXpmF(ILHANDLE File)
    00112 {
    00113         ILuint          FirstPos;
    00114         ILboolean       bRet;
    00115
    00116         iSetInputFile(File);
    00117         FirstPos = itell();
    00118         bRet = iLoadXpmInternal();
    00119         iseek(FirstPos, IL_SEEK_SET);
    00120
    00121         return bRet;
    00122 }
    00123
    00124
    00126 ILboolean ilLoadXpmL(const void *Lump, ILuint Size)
    00127  {
    00128         iSetInputLump(Lump, Size);
    00129         return iLoadXpmInternal();
    00130 }
    00131
    00132
    00133 typedef ILubyte XpmPixel[4];
    00134
    00135 #define XPM_MAX_CHAR_PER_PIXEL 2
    00136
    00137
    00138 #ifndef XPM_DONT_USE_HASHTABLE
    00139
    00140 //The following hash table code was inspired by the xpm
    00141 //loading code of xv, one of the best image viewers of X11
    00142
    00143 //For xpm files with more than one character/pixel, it is
    00144 //impractical to use a simple lookup table for the
    00145 //character-to-color mapping (because the table requires
    00146 //2^(chars/pixel) entries, this is quite big).
    00147 //Because of that, a hash table is used for the mapping.
    00148 //The hash table has 257 entries, and collisions are
    00149 //resolved by chaining.
    00150
    00151 //257 is the smallest prime > 256
    00152 #define XPM_HASH_LEN 257
    00153
    00154 typedef struct XPMHASHENTRY
    00155 {
    00156         ILubyte ColourName[XPM_MAX_CHAR_PER_PIXEL];
    00157         XpmPixel ColourValue;
    00158         struct XPMHASHENTRY *Next;
    00159 } XPMHASHENTRY;
    00160
    00161
    00162 static ILuint XpmHash(const ILubyte* name, int len)
    00163 {
    00164         ILint i, sum;
    00165         for (sum = i = 0; i < len; ++i)
    00166                 sum += name[i];
    00167         return sum % XPM_HASH_LEN;
    00168 }
    00169
    00170
    00171 XPMHASHENTRY** XpmCreateHashTable()
    00172 {
    00173         XPMHASHENTRY** Table =
    00174                 (XPMHASHENTRY**)ialloc(XPM_HASH_LEN*sizeof(XPMHASHENTRY*));
    00175         if (Table != NULL)
    00176                 memset(Table, 0, XPM_HASH_LEN*sizeof(XPMHASHENTRY*));
    00177         return Table;
    00178 }
    00179
    00180
    00181 void XpmDestroyHashTable(XPMHASHENTRY **Table)
    00182 {
    00183         ILint i;
    00184         XPMHASHENTRY* Entry;
    00185
    00186         for (i = 0; i < XPM_HASH_LEN; ++i) {
    00187                 while (Table[i] != NULL) {
    00188                         Entry = Table[i]->Next;
    00189                         ifree(Table[i]);
    00190                         Table[i] = Entry;
    00191                 }
    00192         }
    00193
    00194         ifree(Table);
    00195 }
    00196
    00197
    00198 void XpmInsertEntry(XPMHASHENTRY **Table, const ILubyte* Name, int Len, XpmPixel Colour)
    00199 {
    00200         XPMHASHENTRY* NewEntry;
    00201         ILuint Index;
    00202         Index = XpmHash(Name, Len);
    00203
    00204         NewEntry = (XPMHASHENTRY*)ialloc(sizeof(XPMHASHENTRY));
    00205         if (NewEntry != NULL) {
    00206                 NewEntry->Next = Table[Index];
    00207                 memcpy(NewEntry->ColourName, Name, Len);
    00208                 memcpy(NewEntry->ColourValue, Colour, sizeof(Colour));
    00209                 Table[Index] = NewEntry;
    00210         }
    00211 }
    00212
    00213
    00214 void XpmGetEntry(XPMHASHENTRY **Table, const ILubyte* Name, int Len, XpmPixel Colour)
    00215 {
    00216         XPMHASHENTRY* Entry;
    00217         ILuint Index;
    00218
    00219         Index = XpmHash(Name, Len);
    00220         Entry = Table[Index];
    00221         while (Entry != NULL && strncmp((char*)(Entry->ColourName), (char*)Name, Len) != 0)
    00222                 Entry = Entry->Next;
    00223
    00224         if (Entry != NULL)
    00225                 memcpy(Colour, Entry->ColourValue, sizeof(Colour));
    00226 }
    00227
    00228 #endif //XPM_DONT_USE_HASHTABLE
    00229
    00230
    00231 ILint XpmGetsInternal(ILubyte *Buffer, ILint MaxLen)
    00232 {
    00233         ILint   i = 0, Current;
    00234
    00235         if (ieof())
    00236                 return IL_EOF;
    00237
    00238         while ((Current = igetc()) != IL_EOF && i < MaxLen - 1) {
    00239                 if (Current == IL_EOF)
    00240                         return 0;
    00241                 if (Current == '\n') //unix line ending
    00242                         break;
    00243
    00244                 if (Current == '\r') { //dos/mac line ending
    00245                         Current = igetc();
    00246                         if (Current == '\n') //dos line ending
    00247                                 break;
    00248
    00249                         if (Current == IL_EOF)
    00250                                 break;
    00251
    00252                         Buffer[i++] = (ILubyte)Current;
    00253                         continue;
    00254                 }
    00255                 Buffer[i++] = (ILubyte)Current;
    00256         }
    00257
    00258         Buffer[i++] = 0;
    00259
    00260         return i;
    00261 }
    00262
    00263
    00264 ILint XpmGets(ILubyte *Buffer, ILint MaxLen)
    00265 {
    00266         ILint           Size, i, j;
    00267         ILboolean       NotComment = IL_FALSE, InsideComment = IL_FALSE;
    00268
    00269         do {
    00270                 Size = XpmGetsInternal(Buffer, MaxLen);
    00271                 if (Size == IL_EOF)
    00272                         return IL_EOF;
    00273
    00274                 //skip leading whitespace (sometimes there's whitespace
    00275                 //before a comment or before the pixel data)
    00276
    00277                 for(i = 0; i < Size && isspace(Buffer[i]); ++i) ;
    00278                 Size = Size - i;
    00279                 for(j = 0; j < Size; ++j)
    00280                         Buffer[j] = Buffer[j + i];
    00281
    00282                 if (Size == 0)
    00283                         continue;
    00284
    00285                 if (Buffer[0] == '/' && Buffer[1] == '*') {
    00286                         for (i = 2; i < Size; i++) {
    00287                                 if (Buffer[i] == '*' && Buffer[i+1] == '/') {
    00288                                         break;
    00289                                 }
    00290                         }
    00291                         if (i >= Size)
    00292                                 InsideComment = IL_TRUE;
    00293                 }
    00294                 else if (InsideComment) {
    00295                         for (i = 0; i < Size; i++) {
    00296                                 if (Buffer[i] == '*' && Buffer[i+1] == '/') {
    00297                                         break;
    00298                                 }
    00299                         }
    00300                         if (i < Size)
    00301                                 InsideComment = IL_FALSE;
    00302                 }
    00303                 else {
    00304                         NotComment = IL_TRUE;
    00305                 }
    00306         } while (!NotComment);
    00307
    00308         return Size;
    00309 }
    00310
    00311
    00312 ILint XpmGetInt(ILubyte *Buffer, ILint Size, ILint *Position)
    00313 {
    00314         char            Buff[1024];
    00315         ILint           i, j;
    00316         ILboolean       IsInNum = IL_FALSE;
    00317
    00318         for (i = *Position, j = 0; i < Size; i++) {
    00319                 if (isdigit(Buffer[i])) {
    00320                         IsInNum = IL_TRUE;
    00321                         Buff[j++] = Buffer[i];
    00322                 }
    00323                 else {
    00324                         if (IsInNum) {
    00325                                 Buff[j] = 0;
    00326                                 *Position = i;
    00327                                 return atoi(Buff);
    00328                         }
    00329                 }
    00330         }
    00331
    00332         return -1;
    00333 }
    00334
    00335
    00336 ILboolean XpmPredefCol(char *Buff, XpmPixel *Colour)
    00337 {
    00338         ILint len;
    00339         ILint val = 128;
    00340
    00341         if (!stricmp(Buff, "none")) {
    00342                 (*Colour)[0] = 0;
    00343                 (*Colour)[1] = 0;
    00344                 (*Colour)[2] = 0;
    00345                 (*Colour)[3] = 0;
    00346                 return IL_TRUE;
    00347         }
    00348
    00349         (*Colour)[3] = 255;
    00350
    00351         if (!stricmp(Buff, "black")) {
    00352                 (*Colour)[0] = 0;
    00353                 (*Colour)[1] = 0;
    00354                 (*Colour)[2] = 0;
    00355                 return IL_TRUE;
    00356         }
    00357         if (!stricmp(Buff, "white")) {
    00358                 (*Colour)[0] = 255;
    00359                 (*Colour)[1] = 255;
    00360                 (*Colour)[2] = 255;
    00361                 return IL_TRUE;
    00362         }
    00363         if (!stricmp(Buff, "red")) {
    00364                 (*Colour)[0] = 255;
    00365                 (*Colour)[1] = 0;
    00366                 (*Colour)[2] = 0;
    00367                 return IL_TRUE;
    00368         }
    00369         if (!stricmp(Buff, "green")) {
    00370                 (*Colour)[0] = 0;
    00371                 (*Colour)[1] = 255;
    00372                 (*Colour)[2] = 0;
    00373                 return IL_TRUE;
    00374         }
    00375         if (!stricmp(Buff, "blue")) {
    00376                 (*Colour)[0] = 0;
    00377                 (*Colour)[1] = 0;
    00378                 (*Colour)[2] = 255;
    00379                 return IL_TRUE;
    00380         }
    00381         if (!stricmp(Buff, "yellow")) {
    00382                 (*Colour)[0] = 255;
    00383                 (*Colour)[1] = 255;
    00384                 (*Colour)[2] = 0;
    00385                 return IL_TRUE;
    00386         }
    00387         if (!stricmp(Buff, "cyan")) {
    00388                 (*Colour)[0] = 0;
    00389                 (*Colour)[1] = 255;
    00390                 (*Colour)[2] = 255;
    00391                 return IL_TRUE;
    00392         }
    00393         if (!stricmp(Buff, "gray")) {
    00394                 (*Colour)[0] = 128;
    00395                 (*Colour)[1] = 128;
    00396                 (*Colour)[2] = 128;
    00397                 return IL_TRUE;
    00398         }
    00399
    00400         //check for grayXXX codes (added 20040218)
    00401         len = ilCharStrLen(Buff);
    00402         if (len >= 4) {
    00403                 if (Buff[0] == 'g' || Buff[0] == 'G'
    00404                         || Buff[1] == 'r' || Buff[1] == 'R'
    00405                         || Buff[2] == 'a' || Buff[2] == 'A'
    00406                         || Buff[3] == 'y' || Buff[3] == 'Y') {
    00407                         if (isdigit(Buff[4])) { // isdigit returns false on '\0'
    00408                                 val = Buff[4] - '0';
    00409                                 if (isdigit(Buff[5])) {
    00410                                         val = val*10 + Buff[5] - '0';
    00411                                         if (isdigit(Buff[6]))
    00412                                                 val = val*10 + Buff[6] - '0';
    00413                                 }
    00414                                 val = (255*val)/100;
    00415                         }
    00416                         (*Colour)[0] = (ILubyte)val;
    00417                         (*Colour)[1] = (ILubyte)val;
    00418                         (*Colour)[2] = (ILubyte)val;
    00419                         return IL_TRUE;
    00420                 }
    00421         }
    00422
    00423
    00424         // Unknown colour string, so use black
    00425         // (changed 20040218)
    00426         (*Colour)[0] = 0;
    00427         (*Colour)[1] = 0;
    00428         (*Colour)[2] = 0;
    00429
    00430         return IL_FALSE;
    00431 }
    00432
    00433
    00434 #ifndef XPM_DONT_USE_HASHTABLE
    00435 ILboolean XpmGetColour(ILubyte *Buffer, ILint Size, int Len, XPMHASHENTRY **Table)
    00436 #else
    00437 ILboolean XpmGetColour(ILubyte *Buffer, ILint Size, int Len, XpmPixel* Colours)
    00438 #endif
    00439 {
    00440         ILint           i = 0, j, strLen = 0;
    00441         ILubyte         ColBuff[3];
    00442         char            Buff[1024];
    00443
    00444         XpmPixel        Colour;
    00445         ILubyte         Name[XPM_MAX_CHAR_PER_PIXEL];
    00446
    00447         for ( ; i < Size; i++) {
    00448                 if (Buffer[i] == '\"')
    00449                         break;
    00450         }
    00451         i++;  // Skip the quotes.
    00452
    00453         if (i >= Size)
    00454                 return IL_FALSE;
    00455
    00456         // Get the characters.
    00457         for (j = 0; j < Len; ++j) {
    00458                 Name[j] = Buffer[i++];
    00459         }
    00460
    00461         // Skip to the colour definition.
    00462         for ( ; i < Size; i++) {
    00463                 if (Buffer[i] == 'c')
    00464                         break;
    00465         }
    00466         i++;  // Skip the 'c'.
    00467
    00468         if (i >= Size || Buffer[i] != ' ') { // no 'c' found...assume black
    00469 #ifndef XPM_DONT_USE_HASHTABLE
    00470                 memset(Colour, 0, sizeof(Colour));
    00471                 Colour[3] = 255;
    00472                 XpmInsertEntry(Table, Name, Len, Colour);
    00473 #else
    00474                 memset(Colours[Name[0]], 0, sizeof(Colour));
    00475                 Colours[Name[0]][3] = 255;
    00476 #endif
    00477                 return IL_TRUE;
    00478         }
    00479
    00480         for ( ; i < Size; i++) {
    00481                 if (Buffer[i] != ' ')
    00482                         break;
    00483         }
    00484
    00485         if (i >= Size)
    00486                 return IL_FALSE;
    00487
    00488         if (Buffer[i] == '#') {
    00489                 // colour string may 4 digits/color or 1 digit/color
    00490                 // (added 20040218) TODO: is isxdigit() ANSI???
    00491                 ++i;
    00492                 while (i + strLen < Size && isxdigit(Buffer[i + strLen]))
    00493                         ++strLen;
    00494
    00495                 for (j = 0; j < 3; j++) {
    00496                         if (strLen >= 10) { // 4 digits
    00497                                 ColBuff[0] = Buffer[i + j*4];
    00498                                 ColBuff[1] = Buffer[i + j*4 + 1];
    00499                         }
    00500                         else if (strLen >= 8) { // 3 digits
    00501                                 ColBuff[0] = Buffer[i + j*3];
    00502                                 ColBuff[1] = Buffer[i + j*3 + 1];
    00503                         }
    00504                         else if (strLen >= 6) { // 2 digits
    00505                                 ColBuff[0] = Buffer[i + j*2];
    00506                                 ColBuff[1] = Buffer[i + j*2 + 1];
    00507                         }
    00508                         else if(j < strLen) { // 1 digit, strLen >= 1
    00509                                 ColBuff[0] = Buffer[i + j];
    00510                                 ColBuff[1] = 0;
    00511                         }
    00512
    00513                         ColBuff[2] = 0; // add terminating '\0' char
    00514                         Colour[j] = (ILubyte)strtol((char*)ColBuff, NULL, 16);
    00515                 }
    00516                 Colour[3] = 255;  // Full alpha.
    00517         }
    00518         else {
    00519                 for (j = 0; i < Size; i++) {
    00520                         if (!isalnum(Buffer[i]))
    00521                                 break;
    00522                         Buff[j++] = Buffer[i];
    00523                 }
    00524                 Buff[j] = 0;
    00525
    00526                 if (i >= Size)
    00527                         return IL_FALSE;
    00528
    00529                 if (!XpmPredefCol(Buff, &Colour))
    00530
    00531                         return IL_FALSE;
    00532         }
    00533
    00534
    00535 #ifndef XPM_DONT_USE_HASHTABLE
    00536         XpmInsertEntry(Table, Name, Len, Colour);
    00537 #else
    00538         memcpy(Colours[Name[0]], Colour, sizeof(Colour));
    00539 #endif
    00540         return IL_TRUE;
    00541 }
    00542
    00543
    00544 ILboolean iLoadXpmInternal()
    00545 {
    00546 #define BUFFER_SIZE 2000
    00547         ILubyte                 Buffer[BUFFER_SIZE], *Data;
    00548         ILint                   Size, Pos, Width, Height, NumColours, i, x, y;
    00549
    00550         ILint                   CharsPerPixel;
    00551
    00552 #ifndef XPM_DONT_USE_HASHTABLE
    00553         XPMHASHENTRY    **HashTable;
    00554 #else
    00555         XpmPixel        *Colours;
    00556         ILint           Offset;
    00557 #endif
    00558
    00559         Size = XpmGetsInternal(Buffer, BUFFER_SIZE);
    00560         if (strncmp("/* XPM */", (char*)Buffer, strlen("/* XPM */"))) {
    00561                 ilSetError(IL_INVALID_FILE_HEADER);
    00562                 return IL_FALSE;
    00563         }
    00564
    00565         Size = XpmGets(Buffer, BUFFER_SIZE);
    00566         // @TODO:  Actually check the variable name here.
    00567
    00568         Size = XpmGets(Buffer, BUFFER_SIZE);
    00569         Pos = 0;
    00570         Width = XpmGetInt(Buffer, Size, &Pos);
    00571         Height = XpmGetInt(Buffer, Size, &Pos);
    00572         NumColours = XpmGetInt(Buffer, Size, &Pos);
    00573
    00574         CharsPerPixel = XpmGetInt(Buffer, Size, &Pos);
    00575
    00576 #ifdef XPM_DONT_USE_HASHTABLE
    00577         if (CharsPerPixel != 1) {
    00578                 ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00579                 return IL_FALSE;
    00580         }
    00581 #endif
    00582
    00583         if (CharsPerPixel > XPM_MAX_CHAR_PER_PIXEL
    00584                 || Width*CharsPerPixel > BUFFER_SIZE) {
    00585                 ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00586                 return IL_FALSE;
    00587         }
    00588
    00589 #ifndef XPM_DONT_USE_HASHTABLE
    00590         HashTable = XpmCreateHashTable();
    00591         if (HashTable == NULL)
    00592                 return IL_FALSE;
    00593 #else
    00594         Colours = ialloc(256 * sizeof(XpmPixel));
    00595         if (Colours == NULL)
    00596                 return IL_FALSE;
    00597 #endif
    00598
    00599         for (i = 0; i < NumColours; i++) {
    00600                 Size = XpmGets(Buffer, BUFFER_SIZE);
    00601 #ifndef XPM_DONT_USE_HASHTABLE
    00602                 if (!XpmGetColour(Buffer, Size, CharsPerPixel, HashTable)) {
    00603                         XpmDestroyHashTable(HashTable);
    00604 #else
    00605                 if (!XpmGetColour(Buffer, Size, CharsPerPixel, Colours)) {
    00606                         ifree(Colours);
    00607 #endif
    00608                         return IL_FALSE;
    00609                 }
    00610         }
    00611
    00612         if (!ilTexImage(Width, Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
    00613 #ifndef XPM_DONT_USE_HASHTABLE
    00614                 XpmDestroyHashTable(HashTable);
    00615 #else
    00616                 ifree(Colours);
    00617 #endif
    00618                 return IL_FALSE;
    00619         }
    00620
    00621         Data = iCurImage->Data;
    00622
    00623         for (y = 0; y < Height; y++) {
    00624                 Size = XpmGets(Buffer, BUFFER_SIZE);
    00625                 for (x = 0; x < Width; x++) {
    00626 #ifndef XPM_DONT_USE_HASHTABLE
    00627                         XpmGetEntry(HashTable, &Buffer[1 + x*CharsPerPixel], CharsPerPixel, &Data[(x << 2)]);
    00628 #else
    00629                         Offset = (x << 2);
    00630                         Data[Offset + 0] = Colours[Buffer[x + 1]][0];
    00631                         Data[Offset + 1] = Colours[Buffer[x + 1]][1];
    00632                         Data[Offset + 2] = Colours[Buffer[x + 1]][2];
    00633                         Data[Offset + 3] = Colours[Buffer[x + 1]][3];
    00634 #endif
    00635                 }
    00636
    00637                 Data += iCurImage->Bps;
    00638         }
    00639
    00640         //added 20040218
    00641         iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
    00642
    00643
    00644 #ifndef XPM_DONT_USE_HASHTABLE
    00645         XpmDestroyHashTable(HashTable);
    00646 #else
    00647         ifree(Colours);
    00648 #endif
    00649         return IL_TRUE;
    00650
    00651 #undef BUFFER_SIZE
    00652 }
    00653
    00654 #endif//IL_NO_XPM
    00655