PageRenderTime 41ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/branches/WXSJ/????/??/???/Devil/src-IL/src/il_xpm.c

http://mmo-resourse.googlecode.com/
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
  1. //-----------------------------------------------------------------------------
  2. //
  3. // ImageLib Sources
  4. // Copyright (C) 2000-2002 by Denton Woods
  5. // Last modified: 05/27/2002 <--Y2K Compliant! =]
  6. //
  7. // Filename: src-IL/src/il_xpm.c
  8. //
  9. // Description: Reads from an .xpm file.
  10. //
  11. //-----------------------------------------------------------------------------
  12. #include "il_internal.h"
  13. #ifndef IL_NO_XPM
  14. #include <ctype.h>
  15. //If this is defined, only xpm files with 1 char/pixel
  16. //can be loaded. They load somewhat faster then, though
  17. //(not much).
  18. //#define XPM_DONT_USE_HASHTABLE
  19. ILboolean iLoadXpmInternal(ILvoid);
  20. // Reads an .xpm file
  21. ILboolean ilLoadXpm(const ILstring FileName)
  22. {
  23. ILHANDLE XpmFile;
  24. ILboolean bXpm = IL_FALSE;
  25. XpmFile = iopenr(FileName);
  26. if (XpmFile == NULL) {
  27. ilSetError(IL_COULD_NOT_OPEN_FILE);
  28. return bXpm;
  29. }
  30. iSetInputFile(XpmFile);
  31. bXpm = ilLoadXpmF(XpmFile);
  32. icloser(XpmFile);
  33. return bXpm;
  34. }
  35. //! Reads an already-opened .xpm file
  36. ILboolean ilLoadXpmF(ILHANDLE File)
  37. {
  38. ILuint FirstPos;
  39. ILboolean bRet;
  40. iSetInputFile(File);
  41. FirstPos = itell();
  42. bRet = iLoadXpmInternal();
  43. iseek(FirstPos, IL_SEEK_SET);
  44. return bRet;
  45. }
  46. //! Reads from a memory "lump" that contains an .xpm
  47. ILboolean ilLoadXpmL(ILvoid *Lump, ILuint Size)
  48. {
  49. iSetInputLump(Lump, Size);
  50. return iLoadXpmInternal();
  51. }
  52. typedef ILubyte XpmPixel[4];
  53. #define XPM_MAX_CHAR_PER_PIXEL 2
  54. #ifndef XPM_DONT_USE_HASHTABLE
  55. //The following hash table code was inspired by the xpm
  56. //loading code of xv, one of the best image viewers of X11
  57. //For xpm files with more than one character/pixel, it is
  58. //impractical to use a simple lookup table for the
  59. //character-to-color mapping (because the table requires
  60. //2^(chars/pixel) entries, this is quite big).
  61. //Because of that, a hash table is used for the mapping.
  62. //The hash table has 257 entries, and collisions are
  63. //resolved by chaining.
  64. //257 is the smallest prime > 256
  65. #define XPM_HASH_LEN 257
  66. typedef struct XPMHASHENTRY
  67. {
  68. ILubyte ColourName[XPM_MAX_CHAR_PER_PIXEL];
  69. XpmPixel ColourValue;
  70. struct XPMHASHENTRY *Next;
  71. } XPMHASHENTRY;
  72. static ILuint XpmHash(const ILubyte* name, int len)
  73. {
  74. ILint i, sum;
  75. for (sum = i = 0; i < len; ++i)
  76. sum += name[i];
  77. return sum % XPM_HASH_LEN;
  78. }
  79. XPMHASHENTRY** XpmCreateHashTable()
  80. {
  81. XPMHASHENTRY** Table =
  82. (XPMHASHENTRY**)ialloc(XPM_HASH_LEN*sizeof(XPMHASHENTRY*));
  83. if (Table != NULL)
  84. memset(Table, 0, XPM_HASH_LEN*sizeof(XPMHASHENTRY*));
  85. return Table;
  86. }
  87. void XpmDestroyHashTable(XPMHASHENTRY **Table)
  88. {
  89. ILint i;
  90. XPMHASHENTRY* Entry;
  91. for (i = 0; i < XPM_HASH_LEN; ++i) {
  92. while (Table[i] != NULL) {
  93. Entry = Table[i]->Next;
  94. ifree(Table[i]);
  95. Table[i] = Entry;
  96. }
  97. }
  98. ifree(Table);
  99. }
  100. void XpmInsertEntry(XPMHASHENTRY **Table, const ILubyte* Name, int Len, XpmPixel Colour)
  101. {
  102. XPMHASHENTRY* NewEntry;
  103. ILuint Index;
  104. Index = XpmHash(Name, Len);
  105. NewEntry = (XPMHASHENTRY*)ialloc(sizeof(XPMHASHENTRY));
  106. if (NewEntry != NULL) {
  107. NewEntry->Next = Table[Index];
  108. memcpy(NewEntry->ColourName, Name, Len);
  109. memcpy(NewEntry->ColourValue, Colour, sizeof(Colour));
  110. Table[Index] = NewEntry;
  111. }
  112. }
  113. void XpmGetEntry(XPMHASHENTRY **Table, const ILubyte* Name, int Len, XpmPixel Colour)
  114. {
  115. XPMHASHENTRY* Entry;
  116. ILuint Index;
  117. Index = XpmHash(Name, Len);
  118. Entry = Table[Index];
  119. while (Entry != NULL && strncmp((char*)(Entry->ColourName), (char*)Name, Len) != 0)
  120. Entry = Entry->Next;
  121. if (Entry != NULL)
  122. memcpy(Colour, Entry->ColourValue, sizeof(Colour));
  123. }
  124. #endif //XPM_DONT_USE_HASHTABLE
  125. ILint XpmGetsInternal(ILubyte *Buffer, ILint MaxLen)
  126. {
  127. ILint i = 0, Current;
  128. if (ieof())
  129. return IL_EOF;
  130. while ((Current = igetc()) != IL_EOF && i < MaxLen - 1) {
  131. if (Current == IL_EOF)
  132. return 0;
  133. if (Current == '\n') //unix line ending
  134. break;
  135. if (Current == '\r') { //dos/mac line ending
  136. Current = igetc();
  137. if (Current == '\n') //dos line ending
  138. break;
  139. if (Current == IL_EOF)
  140. break;
  141. Buffer[i++] = Current;
  142. continue;
  143. }
  144. Buffer[i++] = Current;
  145. }
  146. Buffer[i++] = 0;
  147. return i;
  148. }
  149. ILint XpmGets(ILubyte *Buffer, ILint MaxLen)
  150. {
  151. ILint Size, i, j;
  152. ILboolean NotComment = IL_FALSE, InsideComment = IL_FALSE;
  153. do {
  154. Size = XpmGetsInternal(Buffer, MaxLen);
  155. if (Size == IL_EOF)
  156. return IL_EOF;
  157. //stip leading whitespace (sometimes there's whitespace
  158. //before a comment or before the pixel data)
  159. for(i = 0; i < Size && isspace(Buffer[i]); ++i) ;
  160. Size = Size - i;
  161. for(j = 0; j < Size; ++j)
  162. Buffer[j] = Buffer[j + i];
  163. if (Size == 0)
  164. continue;
  165. if (Buffer[0] == '/' && Buffer[1] == '*') {
  166. for (i = 2; i < Size; i++) {
  167. if (Buffer[i] == '*' && Buffer[i+1] == '/') {
  168. break;
  169. }
  170. }
  171. if (i >= Size)
  172. InsideComment = IL_TRUE;
  173. }
  174. else if (InsideComment) {
  175. for (i = 0; i < Size; i++) {
  176. if (Buffer[i] == '*' && Buffer[i+1] == '/') {
  177. break;
  178. }
  179. }
  180. if (i < Size)
  181. InsideComment = IL_FALSE;
  182. }
  183. else {
  184. NotComment = IL_TRUE;
  185. }
  186. } while (!NotComment);
  187. return Size;
  188. }
  189. ILint XpmGetInt(ILubyte *Buffer, ILint Size, ILint *Position)
  190. {
  191. char Buff[1024];
  192. ILint i, j;
  193. ILboolean IsInNum = IL_FALSE;
  194. for (i = *Position, j = 0; i < Size; i++) {
  195. if (isdigit(Buffer[i])) {
  196. IsInNum = IL_TRUE;
  197. Buff[j++] = Buffer[i];
  198. }
  199. else {
  200. if (IsInNum) {
  201. Buff[j] = 0;
  202. *Position = i;
  203. return atoi(Buff);
  204. }
  205. }
  206. }
  207. return -1;
  208. }
  209. ILboolean XpmPredefCol(char *Buff, XpmPixel *Colour)
  210. {
  211. ILint len;
  212. ILint val = 128;
  213. if (!stricmp(Buff, "none")) {
  214. (*Colour)[0] = 0;
  215. (*Colour)[1] = 0;
  216. (*Colour)[2] = 0;
  217. (*Colour)[3] = 0;
  218. return IL_TRUE;
  219. }
  220. (*Colour)[3] = 255;
  221. if (!stricmp(Buff, "black")) {
  222. (*Colour)[0] = 0;
  223. (*Colour)[1] = 0;
  224. (*Colour)[2] = 0;
  225. return IL_TRUE;
  226. }
  227. if (!stricmp(Buff, "white")) {
  228. (*Colour)[0] = 255;
  229. (*Colour)[1] = 255;
  230. (*Colour)[2] = 255;
  231. return IL_TRUE;
  232. }
  233. if (!stricmp(Buff, "red")) {
  234. (*Colour)[0] = 255;
  235. (*Colour)[1] = 0;
  236. (*Colour)[2] = 0;
  237. return IL_TRUE;
  238. }
  239. if (!stricmp(Buff, "green")) {
  240. (*Colour)[0] = 0;
  241. (*Colour)[1] = 255;
  242. (*Colour)[2] = 0;
  243. return IL_TRUE;
  244. }
  245. if (!stricmp(Buff, "blue")) {
  246. (*Colour)[0] = 0;
  247. (*Colour)[1] = 0;
  248. (*Colour)[2] = 255;
  249. return IL_TRUE;
  250. }
  251. if (!stricmp(Buff, "yellow")) {
  252. (*Colour)[0] = 255;
  253. (*Colour)[1] = 255;
  254. (*Colour)[2] = 0;
  255. return IL_TRUE;
  256. }
  257. if (!stricmp(Buff, "cyan")) {
  258. (*Colour)[0] = 0;
  259. (*Colour)[1] = 255;
  260. (*Colour)[2] = 255;
  261. return IL_TRUE;
  262. }
  263. if (!stricmp(Buff, "gray")) {
  264. (*Colour)[0] = 128;
  265. (*Colour)[1] = 128;
  266. (*Colour)[2] = 128;
  267. return IL_TRUE;
  268. }
  269. //check for grayXXX codes (added 20040218)
  270. len = strlen(Buff);
  271. if (len >= 4) {
  272. if (Buff[0] == 'g' || Buff[0] == 'G'
  273. || Buff[1] == 'r' || Buff[1] == 'R'
  274. || Buff[2] == 'a' || Buff[2] == 'A'
  275. || Buff[3] == 'y' || Buff[3] == 'Y') {
  276. if (isdigit(Buff[4])) { // isdigit returns false on '\0'
  277. val = Buff[4] - '0';
  278. if (isdigit(Buff[5])) {
  279. val = val*10 + Buff[5] - '0';
  280. if (isdigit(Buff[6]))
  281. val = val*10 + Buff[6] - '0';
  282. }
  283. val = (255*val)/100;
  284. }
  285. (*Colour)[0] = val;
  286. (*Colour)[1] = val;
  287. (*Colour)[2] = val;
  288. return IL_TRUE;
  289. }
  290. }
  291. // Unknown colour string, so use black
  292. // (changed 20040218)
  293. (*Colour)[0] = 0;
  294. (*Colour)[1] = 0;
  295. (*Colour)[2] = 0;
  296. return IL_FALSE;
  297. }
  298. #ifndef XPM_DONT_USE_HASHTABLE
  299. ILboolean XpmGetColour(ILubyte *Buffer, ILint Size, int Len, XPMHASHENTRY **Table)
  300. #else
  301. ILboolean XpmGetColour(ILubyte *Buffer, ILint Size, int Len, XpmPixel* Colours)
  302. #endif
  303. {
  304. ILint i = 0, j, strLen = 0;
  305. ILubyte ColBuff[3];
  306. char Buff[1024];
  307. XpmPixel Colour;
  308. ILubyte Name[XPM_MAX_CHAR_PER_PIXEL];
  309. for ( ; i < Size; i++) {
  310. if (Buffer[i] == '\"')
  311. break;
  312. }
  313. i++; // Skip the quotes.
  314. if (i >= Size)
  315. return IL_FALSE;
  316. // Get the characters.
  317. for (j = 0; j < Len; ++j) {
  318. Name[j] = Buffer[i++];
  319. }
  320. // Skip to the colour definition.
  321. for ( ; i < Size; i++) {
  322. if (Buffer[i] == 'c')
  323. break;
  324. }
  325. i++; // Skip the 'c'.
  326. if (i >= Size || Buffer[i] != ' ') { // no 'c' found...assume black
  327. #ifndef XPM_DONT_USE_HASHTABLE
  328. memset(Colour, 0, sizeof(Colour));
  329. Colour[3] = 255;
  330. XpmInsertEntry(Table, Name, Len, Colour);
  331. #else
  332. memset(Colours[Name[0]], 0, sizeof(Colour));
  333. Colours[Name[0]][3] = 255;
  334. #endif
  335. return IL_TRUE;
  336. }
  337. for ( ; i < Size; i++) {
  338. if (Buffer[i] != ' ')
  339. break;
  340. }
  341. if (i >= Size)
  342. return IL_FALSE;
  343. if (Buffer[i] == '#') {
  344. // colour string may 4 digits/color or 1 digit/color
  345. // (added 20040218) TODO: is isxdigit() ANSI???
  346. ++i;
  347. while (i + strLen < Size && isxdigit(Buffer[i + strLen]))
  348. ++strLen;
  349. for (j = 0; j < 3; j++) {
  350. if (strLen >= 10) { // 4 digits
  351. ColBuff[0] = Buffer[i + j*4];
  352. ColBuff[1] = Buffer[i + j*4 + 1];
  353. }
  354. else if (strLen >= 8) { // 3 digits
  355. ColBuff[0] = Buffer[i + j*3];
  356. ColBuff[1] = Buffer[i + j*3 + 1];
  357. }
  358. else if (strLen >= 6) { // 2 digits
  359. ColBuff[0] = Buffer[i + j*2];
  360. ColBuff[1] = Buffer[i + j*2 + 1];
  361. }
  362. else if(j < strLen) { // 1 digit, strLen >= 1
  363. ColBuff[0] = Buffer[i + j];
  364. ColBuff[1] = 0;
  365. }
  366. ColBuff[2] = 0; // add terminating '\0' char
  367. Colour[j] = (ILubyte)strtol((char*)ColBuff, NULL, 16);
  368. }
  369. Colour[3] = 255; // Full alpha.
  370. }
  371. else {
  372. for (j = 0; i < Size; i++) {
  373. if (!isalnum(Buffer[i]))
  374. break;
  375. Buff[j++] = Buffer[i];
  376. }
  377. Buff[j] = 0;
  378. if (i >= Size)
  379. return IL_FALSE;
  380. if (!XpmPredefCol(Buff, &Colour))
  381. return IL_FALSE;
  382. }
  383. #ifndef XPM_DONT_USE_HASHTABLE
  384. XpmInsertEntry(Table, Name, Len, Colour);
  385. #else
  386. memcpy(Colours[Name[0]], Colour, sizeof(Colour));
  387. #endif
  388. return IL_TRUE;
  389. }
  390. ILboolean iLoadXpmInternal()
  391. {
  392. #define BUFFER_SIZE 2000
  393. ILubyte Buffer[BUFFER_SIZE], *Data;
  394. ILint Size, Pos, Width, Height, NumColours, i, x, y;
  395. ILint CharsPerPixel;
  396. #ifndef XPM_DONT_USE_HASHTABLE
  397. XPMHASHENTRY **HashTable;
  398. #else
  399. XpmPixel *Colours;
  400. ILint Offset;
  401. #endif
  402. Size = XpmGetsInternal(Buffer, BUFFER_SIZE);
  403. if (strncmp("/* XPM */", (char*)Buffer, strlen("/* XPM */"))) {
  404. ilSetError(IL_INVALID_FILE_HEADER);
  405. return IL_FALSE;
  406. }
  407. Size = XpmGets(Buffer, BUFFER_SIZE);
  408. // @TODO: Actually check the variable name here.
  409. Size = XpmGets(Buffer, BUFFER_SIZE);
  410. Pos = 0;
  411. Width = XpmGetInt(Buffer, Size, &Pos);
  412. Height = XpmGetInt(Buffer, Size, &Pos);
  413. NumColours = XpmGetInt(Buffer, Size, &Pos);
  414. CharsPerPixel = XpmGetInt(Buffer, Size, &Pos);
  415. #ifdef XPM_DONT_USE_HASHTABLE
  416. if (CharsPerPixel != 1) {
  417. ilSetError(IL_FORMAT_NOT_SUPPORTED);
  418. return IL_FALSE;
  419. }
  420. #endif
  421. if (CharsPerPixel > XPM_MAX_CHAR_PER_PIXEL
  422. || Width*CharsPerPixel > BUFFER_SIZE) {
  423. ilSetError(IL_FORMAT_NOT_SUPPORTED);
  424. return IL_FALSE;
  425. }
  426. #ifndef XPM_DONT_USE_HASHTABLE
  427. HashTable = XpmCreateHashTable();
  428. if (HashTable == NULL)
  429. return IL_FALSE;
  430. #else
  431. Colours = ialloc(256 * sizeof(XpmPixel));
  432. if (Colours == NULL)
  433. return IL_FALSE;
  434. #endif
  435. for (i = 0; i < NumColours; i++) {
  436. Size = XpmGets(Buffer, BUFFER_SIZE);
  437. #ifndef XPM_DONT_USE_HASHTABLE
  438. if (!XpmGetColour(Buffer, Size, CharsPerPixel, HashTable)) {
  439. XpmDestroyHashTable(HashTable);
  440. #else
  441. if (!XpmGetColour(Buffer, Size, CharsPerPixel, Colours)) {
  442. ifree(Colours);
  443. #endif
  444. return IL_FALSE;
  445. }
  446. }
  447. if (!ilTexImage(Width, Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
  448. #ifndef XPM_DONT_USE_HASHTABLE
  449. XpmDestroyHashTable(HashTable);
  450. #else
  451. ifree(Colours);
  452. #endif
  453. return IL_FALSE;
  454. }
  455. Data = iCurImage->Data;
  456. for (y = 0; y < Height; y++) {
  457. Size = XpmGets(Buffer, BUFFER_SIZE);
  458. for (x = 0; x < Width; x++) {
  459. #ifndef XPM_DONT_USE_HASHTABLE
  460. XpmGetEntry(HashTable, &Buffer[1 + x*CharsPerPixel], CharsPerPixel, &Data[(x << 2)]);
  461. #else
  462. Offset = (x << 2);
  463. Data[Offset + 0] = Colours[Buffer[x + 1]][0];
  464. Data[Offset + 1] = Colours[Buffer[x + 1]][1];
  465. Data[Offset + 2] = Colours[Buffer[x + 1]][2];
  466. Data[Offset + 3] = Colours[Buffer[x + 1]][3];
  467. #endif
  468. }
  469. Data += iCurImage->Bps;
  470. }
  471. //added 20040218
  472. iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
  473. #ifndef XPM_DONT_USE_HASHTABLE
  474. XpmDestroyHashTable(HashTable);
  475. #else
  476. ifree(Colours);
  477. #endif
  478. return IL_TRUE;
  479. #undef BUFFER_SIZE
  480. }
  481. #endif//IL_NO_XPM