comparison libgfx.c @ 443:f7c9d1619c74

Beginnings of IFF ILBM reader. Not functional, only chunk parsing, BMHD header chunk parsing and CMAP handling implemented.
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 04 Nov 2012 06:41:51 +0200
parents a67600e186d0
children 7d588807f91d
comparison
equal deleted inserted replaced
442:a67600e186d0 443:f7c9d1619c74
918 fclose(fp); 918 fclose(fp);
919 return res; 919 return res;
920 } 920 }
921 921
922 922
923 #define IFF_ID_FORM 0x464F524D // "FORM"
924 #define IFF_ID_ILBM 0x494C424D // "ILBM"
925 #define IFF_ID_BMHD 0x424D4844 // "BMHD"
926 #define IFF_ID_CMAP 0x434D4150 // "CMAP"
927 #define IFF_ID_BODY 0x424F4459 // "BODY"
928
929 #define IFF_MASK_NONE 0
930 #define IFF_MASK_HAS_MASK 1
931 #define IFF_MASK_TRANSP 2
932 #define IFF_MASK_LASSO 3
933
934 #define IFF_COMP_NONE 0
935 #define IFF_COMP_BYTERUN1 1
936
937
938 typedef struct
939 {
940 Uint32 id;
941 Uint32 size;
942 int count;
943 } DMIFFChunk;
944
945
946 typedef struct
947 {
948 Uint16 w, h;
949 Sint16 x, y;
950 Uint8 nplanes;
951 Uint8 masking;
952 Uint8 compression;
953 Uint8 pad1;
954 Uint16 transp;
955 Uint8 xasp, yasp;
956 Sint16 pagew, pageh;
957 } DMIFFBMHD;
958
959
960 static BOOL dmReadIFFChunk(FILE *fp, DMIFFChunk *chunk)
961 {
962 if (!dm_fread_be32(fp, &chunk->id) ||
963 !dm_fread_be32(fp, &chunk->size))
964 {
965 dmError("ILBM: Could not read IFF chunk header.\n");
966 return FALSE;
967 }
968 else
969 return TRUE;
970 }
971
972 static char * dmGetIFFChunkID(DMIFFChunk *chunk, char *buf)
973 {
974 buf[0] = (chunk->id >> 24) & 0xff;
975 buf[1] = (chunk->id >> 16) & 0xff;
976 buf[2] = (chunk->id >> 8) & 0xff;
977 buf[3] = (chunk->id) & 0xff;
978 buf[4] = 0;
979 return buf;
980 }
981
982 static BOOL dmCheckIFFChunk(DMIFFChunk *dest, DMIFFChunk *chunk, BOOL multi, Uint32 minSize)
983 {
984 if (dest->count > 0 && !multi)
985 {
986 char buf[6];
987 dmError("ILBM: Multiple instances of chunk %s found.\n",
988 dmGetIFFChunkID(chunk, buf));
989 return FALSE;
990 }
991
992 dest->count++;
993
994 if (chunk->size < minSize)
995 return FALSE;
996
997 return TRUE;
998 }
999
1000
1001 int dmReadILBMImageFILE(FILE *fp, DMImage **pimg)
1002 {
1003 Uint32 idILBM;
1004 DMIFFChunk chunk, chBMHD, chCMAP, chBODY;
1005 DMIFFBMHD bmhd;
1006 int ncolors, i;
1007 DMColor *pal = NULL;
1008 DMImage *img = NULL;
1009 BOOL paletted = FALSE, parsed = FALSE;
1010 int res = DMERR_OK;
1011
1012 memset(&chBMHD, 0, sizeof(DMIFFChunk));
1013 memset(&chCMAP, 0, sizeof(DMIFFChunk));
1014 memset(&chBODY, 0, sizeof(DMIFFChunk));
1015 memset(&bmhd, 0, sizeof(bmhd));
1016
1017 // Read IFF FORM header
1018 if (!dmReadIFFChunk(fp, &chunk) ||
1019 chunk.id != IFF_ID_FORM ||
1020 chunk.size < 32)
1021 {
1022 dmError("ILBM: Not a IFF file.\n");
1023 return DMERR_FREAD;
1024 }
1025
1026 // Check IFF ILBM signature
1027 if (!dm_fread_be32(fp, &idILBM) ||
1028 idILBM != IFF_ID_ILBM)
1029 {
1030 dmError("ILBM: Not a ILBM file.\n");
1031 return DMERR_INVALID_DATA;
1032 }
1033
1034 while (!parsed && !feof(fp))
1035 {
1036 if (!dmReadIFFChunk(fp, &chunk))
1037 {
1038 dmError("ILBM: Error reading IFF ILBM data.\n");
1039 return DMERR_FREAD;
1040 }
1041
1042 switch (chunk.id)
1043 {
1044 case IFF_ID_BMHD:
1045 if (!dmCheckIFFChunk(&chBMHD, &chunk, FALSE, sizeof(bmhd)))
1046 return DMERR_FREAD;
1047
1048 if (!dm_fread_be16(fp, &bmhd.w) ||
1049 !dm_fread_be16(fp, &bmhd.h) ||
1050 !dm_fread_be16(fp, (Uint16 *) &bmhd.x) ||
1051 !dm_fread_be16(fp, (Uint16 *) &bmhd.y) ||
1052 !dm_fread_byte(fp, &bmhd.nplanes) ||
1053 !dm_fread_byte(fp, &bmhd.masking) ||
1054 !dm_fread_byte(fp, &bmhd.compression) ||
1055 !dm_fread_byte(fp, &bmhd.pad1) ||
1056 !dm_fread_be16(fp, &bmhd.transp) ||
1057 !dm_fread_byte(fp, &bmhd.xasp) ||
1058 !dm_fread_byte(fp, &bmhd.yasp) ||
1059 !dm_fread_be16(fp, (Uint16 *) &bmhd.pagew) ||
1060 !dm_fread_be16(fp, (Uint16 *) &bmhd.pageh))
1061 {
1062 dmError("ILBM: Error reading BMHD chunk.\n");
1063 return DMERR_FREAD;
1064 }
1065 dmMsg(2, "ILBM: BMHD %d x %d @ %d, %d : nplanes=%d, comp=%d, mask=%d\n",
1066 bmhd.w, bmhd.h, bmhd.x, bmhd.y, bmhd.nplanes, bmhd.compression, bmhd.masking);
1067 break;
1068
1069
1070 case IFF_ID_CMAP:
1071 // Check for multiple occurences of CMAP
1072 if (!dmCheckIFFChunk(&chCMAP, &chunk, FALSE, 3))
1073 return DMERR_FREAD;
1074
1075 // Check for sanity
1076 if (chunk.size % 3 != 0)
1077 dmError("ILBM: CMAP chunk size not divisible by 3, possibly broken file.\n");
1078
1079 ncolors = chunk.size / 3;
1080 dmMsg(2, "ILBM: CMAP %d entries (%d bytes)\n",
1081 ncolors, chunk.size, 1 << bmhd.nplanes);
1082
1083 if (bmhd.nplanes > 0 && ncolors != 1 << bmhd.nplanes)
1084 dmMsg(2, "ILBM: Expected %d entries in CMAP.\n", 1 << bmhd.nplanes);
1085
1086 if (ncolors == 0)
1087 break;
1088
1089 // Allocate palette
1090 if ((pal = dmMalloc(sizeof(DMColor) * ncolors)) == NULL)
1091 {
1092 dmError("ILBM: Could not allocate memory for palette.\n");
1093 return DMERR_MALLOC;
1094 }
1095
1096 // Read palette
1097 for (i = 0; i < ncolors; i++)
1098 {
1099 Uint8 colR, colG, colB;
1100 if (!dm_fread_byte(fp, &colR) ||
1101 !dm_fread_byte(fp, &colG) ||
1102 !dm_fread_byte(fp, &colB))
1103 {
1104 dmError("ILBM: Error reading CMAP entry #%d, broken file.\n", i);
1105 return DMERR_FREAD;
1106 }
1107
1108 pal[i].r = colR;
1109 pal[i].g = colG;
1110 pal[i].b = colB;
1111 }
1112
1113 if (chBMHD.count && chBODY.count)
1114 parsed = TRUE;
1115 break;
1116
1117 case IFF_ID_BODY:
1118 if (!dmCheckIFFChunk(&chBODY, &chunk, FALSE, 1))
1119 return DMERR_FREAD;
1120
1121 if (!chBMHD.count)
1122 {
1123 dmError("ILBM: BODY chunk before BMHD?\n");
1124 return DMERR_INVALID_DATA;
1125 }
1126
1127 dmMsg(2, "ILBM: BODY chunk size %d bytes\n", chunk.size);
1128 if (fseeko(fp, chunk.size, SEEK_CUR) != 0)
1129 {
1130 dmError("ILBM: Error skipping in file.");
1131 return DMERR_FREAD;
1132 }
1133
1134 if (chCMAP.count)
1135 parsed = TRUE;
1136 break;
1137
1138 default:
1139 {
1140 char buf[6];
1141 dmMsg(3, "Unknown chunk ID '%s', size %d\n",
1142 dmGetIFFChunkID(&chunk, buf), chunk.size);
1143
1144 if (fseeko(fp, chunk.size, SEEK_CUR) != 0)
1145 {
1146 dmError("ILBM: Error skipping in file.");
1147 return DMERR_FREAD;
1148 }
1149 }
1150 break;
1151 }
1152
1153 if (chunk.size & 1)
1154 fgetc(fp);
1155 }
1156
1157 return res;
1158 }
1159
1160
1161 int dmReadILBMImage(const char *filename, DMImage **pimg)
1162 {
1163 FILE *fp;
1164 int res;
1165
1166 if ((fp = fopen(filename, "rb")) == NULL)
1167 {
1168 dmError("ILBM: Could not open file '%s' for reading.\n", filename);
1169 return DMERR_FOPEN;
1170 }
1171
1172 res = dmReadILBMImageFILE(fp, pimg);
1173
1174 fclose(fp);
1175 return res;
1176 }
1177
1178
1179
1180
923 static int fmtProbePNG(const Uint8 *buf, const size_t len) 1181 static int fmtProbePNG(const Uint8 *buf, const size_t len)
924 { 1182 {
925 if (len > 64 && buf[0] == 0x89 && 1183 if (len > 64 && buf[0] == 0x89 &&
926 buf[1] == 'P' && buf[2] == 'N' && buf[3] == 'G' && 1184 buf[1] == 'P' && buf[2] == 'N' && buf[3] == 'G' &&
927 buf[4] == 0x0d && buf[5] == 0x0a) 1185 buf[4] == 0x0d && buf[5] == 0x0a)
1186 {
1187 if (buf[12] == 'I' && buf[13] == 'H' &&
1188 buf[14] == 'D' && buf[15] == 'R')
1189 return DM_PROBE_SCORE_MAX;
1190 else
1191 return DM_PROBE_SCORE_GOOD;
1192 }
1193
1194 return DM_PROBE_SCORE_FALSE;
1195 }
1196
1197
1198 static int fmtProbePCX(const Uint8 *buf, const size_t len)
1199 {
1200 if (len > 128 + 32 &&
1201 buf[0] == 10 &&
1202 (buf[1] == 5 || buf[1] == 2 || buf[1] == 3) &&
1203 buf[2] == 1 &&
1204 (buf[3] == 8 || buf[3] == 4 || buf[3] == 3 || buf[3] == 1) &&
1205 buf[65] >= 1 && buf[65] <= 4)
928 return DM_PROBE_SCORE_GOOD; 1206 return DM_PROBE_SCORE_GOOD;
929 1207
930 return DM_PROBE_SCORE_FALSE; 1208 return DM_PROBE_SCORE_FALSE;
931 } 1209 }
932 1210
933 1211
934 static int fmtProbePCX(const Uint8 *buf, const size_t len) 1212 static int fmtProbeILBM(const Uint8 *buf, const size_t len)
935 { 1213 {
936 if (len > 128 + 64 && 1214 if (len > 32 &&
937 buf[0] == 10 && 1215 buf[ 0] == 'F' && buf[ 1] == 'O' &&
938 buf[1] == 5 && 1216 buf[ 2] == 'R' && buf[ 3] == 'M' &&
939 buf[2] == 1 && 1217 buf[ 8] == 'I' && buf[ 9] == 'L' &&
940 buf[3] == 8) 1218 buf[10] == 'B' && buf[11] == 'M')
941 return DM_PROBE_SCORE_GOOD; 1219 {
1220 if (buf[12] == 'B' && buf[13] == 'M' &&
1221 buf[14] == 'H' && buf[15] == 'D')
1222 return DM_PROBE_SCORE_MAX;
1223 else
1224 return DM_PROBE_SCORE_GOOD;
1225 }
942 1226
943 return DM_PROBE_SCORE_FALSE; 1227 return DM_PROBE_SCORE_FALSE;
944 } 1228 }
945 1229
946 1230
967 fmtProbePCX, 1251 fmtProbePCX,
968 dmReadPCXImage, dmReadPCXImageFILE, 1252 dmReadPCXImage, dmReadPCXImageFILE,
969 dmWritePCXImage, dmWritePCXImageFILE, 1253 dmWritePCXImage, dmWritePCXImageFILE,
970 }, 1254 },
971 { 1255 {
1256 "ILBM", "IFF ILBM",
1257 fmtProbeILBM,
1258 dmReadILBMImage, dmReadILBMImageFILE,
1259 NULL, NULL,
1260 },
1261 {
972 "ARAW", "IFFMaster Amiga RAW", 1262 "ARAW", "IFFMaster Amiga RAW",
973 NULL, 1263 NULL,
974 NULL, NULL, 1264 NULL, NULL,
975 dmWriteIFFMasterRAWImage, dmWriteIFFMasterRAWImageFILE, 1265 dmWriteIFFMasterRAWImage, dmWriteIFFMasterRAWImageFILE,
976 } 1266 }