Various Datatypes.
[AROS-Contrib.git] / workbench / classes / datatypes / icns / icns_class.c
blob3af1844955bd8206c1db9657c181475899cf63a7
1 /*
2 * icns.datatype
3 * (c) Fredrik Wikstrom
4 */
6 #include "icns_class.h"
7 #include <string.h>
9 uint32 ClassDispatch (Class *cl, Object *o, Msg msg);
11 Class *initDTClass (struct ClassBase *libBase) {
12 Class *cl = NULL;
13 SuperClassBase = IExec->OpenLibrary("datatypes/picture.datatype", 52);
14 if (SuperClassBase) {
15 cl = IIntuition->MakeClass(libBase->libNode.lib_Node.ln_Name, PICTUREDTCLASS, NULL, 0, 0);
16 if (cl) {
17 cl->cl_Dispatcher.h_Entry = (HOOKFUNC)ClassDispatch;
18 cl->cl_UserData = (uint32)libBase;
19 IIntuition->AddClass(cl);
20 } else {
21 IExec->CloseLibrary(SuperClassBase);
24 return cl;
27 BOOL freeDTClass (struct ClassBase *libBase, Class *cl) {
28 BOOL res = TRUE;
29 if (cl) {
30 res = IIntuition->FreeClass(cl);
31 if (res) {
32 IExec->CloseLibrary(SuperClassBase);
35 return res;
38 static int32 ConvertICNS (Class *cl, Object *o, BPTR file, struct BitMapHeader *bmh,
39 uint32 index, uint32 *total);
40 static int32 GetICNS (Class *cl, Object *o, struct TagItem *tags);
42 uint32 ClassDispatch (Class *cl, Object *o, Msg msg) {
43 struct ClassBase *libBase = (struct ClassBase *)cl->cl_UserData;
44 uint32 ret;
46 switch (msg->MethodID) {
48 case OM_NEW:
49 ret = IIntuition->IDoSuperMethodA(cl, o, msg);
50 if (ret) {
51 int32 error;
52 error = GetICNS(cl, (Object *)ret, ((struct opSet *)msg)->ops_AttrList);
53 if (error != OK) {
54 IIntuition->ICoerceMethod(cl, (Object *)ret, OM_DISPOSE);
55 ret = (uint32)NULL;
56 IDOS->SetIoErr(error);
59 break;
61 default:
62 ret = IIntuition->IDoSuperMethodA(cl, o, msg);
63 break;
67 return ret;
70 static int32 ReadC1A1 (Class *cl, Object *o, BPTR file, struct BitMapHeader *bmh,
71 struct IconInfo *info);
72 static int32 ReadCLUT4_8 (Class *cl, Object *o, BPTR file, struct BitMapHeader *bmh,
73 struct IconInfo *info);
74 static int32 ReadARGB32 (Class *cl, Object *o, BPTR file, struct BitMapHeader *bmh,
75 struct IconInfo *info);
77 static int32 ConvertICNS (Class *cl, Object *o, BPTR file, struct BitMapHeader *bmh,
78 uint32 index, uint32 *total)
80 struct ClassBase *libBase = (struct ClassBase *)cl->cl_UserData;
81 int32 status, error = OK;
82 struct ResourceHeader rsh;
83 struct ElementHeader elem;
84 struct IconInfo info;
85 int32 (*ReadFunc) (Class *cl, Object *o, BPTR file, struct BitMapHeader *bmh,
86 struct IconInfo *info);
88 status = IDOS->Read(file, &rsh, sizeof(struct ResourceHeader));
89 if (status != sizeof(struct ResourceHeader)) {
90 return ReadError(status);
93 if (rsh.ResourceType != RST_ICNS) {
94 return ERROR_OBJECT_WRONG_TYPE;
97 if (total) {
98 if (error = ParseElements(cl, file, &elem, &info, 0, 0, total)) return error;
99 if (index >= *total) return DTERROR_NOT_AVAILABLE;
102 if (error = ParseElements(cl, file, &elem, &info, 0, index, NULL)) return error;
104 bmh->bmh_Width = info.Width;
105 bmh->bmh_Height = info.Height;
106 bmh->bmh_Depth = info.BitDepth;
108 info.DataSize = elem.ElementSize - sizeof(elem);
109 info.Data = IExec->AllocVec(info.DataSize, MEMF_SHARED);
110 if (!info.Data) {
111 error = ERROR_NO_FREE_STORE;
112 goto out;
115 status = IDOS->Read(file, info.Data, info.DataSize);
116 if (status != info.DataSize) {
117 error = ReadError(status);
118 goto out;
121 ReadFunc = NULL;
122 switch (bmh->bmh_Depth) {
123 case 1:
124 ReadFunc = ReadC1A1;
125 break;
126 case 4:
127 bmh->bmh_Depth = 8;
128 case 8:
129 ReadFunc = ReadCLUT4_8;
130 break;
131 case 32:
132 bmh->bmh_Masking = mskHasAlpha;
133 ReadFunc = ReadARGB32;
134 break;
136 if (!ReadFunc) {
137 error = DTERROR_UNKNOWN_COMPRESSION;
138 goto out;
141 error = ReadFunc(cl, o, file, bmh, &info);
143 out:
144 IExec->FreeVec(info.Data);
146 return error;
149 static int32 ReadC1A1 (Class *cl, Object *o, BPTR file, struct BitMapHeader *bmh,
150 struct IconInfo *info)
152 struct ClassBase *libBase = (struct ClassBase *)cl->cl_UserData;
153 struct BitMap *bm;
154 uint8 *mask, *src, *dst;
155 int32 error = OK;
156 uint32 bpr, mod;
157 int y;
158 struct ColorRegister *cmap = NULL;
159 uint32 *cregs = NULL;
161 bpr = (bmh->bmh_Width + 7) >> 3;
162 if (info->DataSize != ((bpr*bmh->bmh_Height) << 1)) {
163 return DTERROR_INVALID_DATA;
166 bm = IGraphics->AllocBitMap(bmh->bmh_Width, bmh->bmh_Height, 1, 0, NULL);
167 mask = IGraphics->AllocRaster(bmh->bmh_Width, bmh->bmh_Height);
168 if (!bm && !mask) {
169 IGraphics->FreeBitMap(bm);
170 if (mask) IGraphics->FreeRaster(mask, bmh->bmh_Width, bmh->bmh_Height);
171 return ERROR_NO_FREE_STORE;
174 src = info->Data;
175 dst = (uint8 *)bm->Planes[0];
176 mod = bm->BytesPerRow;
177 for (y = 0; y < bmh->bmh_Width; y++) {
178 IExec->CopyMem(src, dst, bpr);
179 src += bpr;
180 dst += mod;
182 dst = mask;
183 for (y = 0; y < bmh->bmh_Width; y++) {
184 IExec->CopyMem(src, dst, bpr);
185 src += bpr;
186 dst += bpr;
189 IDataTypes->SetDTAttrs(o, NULL, NULL,
190 DTA_NominalHoriz, bmh->bmh_Width,
191 DTA_NominalVert, bmh->bmh_Height,
192 PDTA_BitMap, bm,
193 PDTA_MaskPlane, mask,
194 TAG_END);
195 bmh->bmh_Masking = mskHasMask;
197 SetCMAP(cl, o, 2);
199 return error;
202 static int32 ReadCLUT4_8 (Class *cl, Object *o, BPTR file, struct BitMapHeader *bmh,
203 struct IconInfo *info)
205 struct ClassBase *libBase = (struct ClassBase *)cl->cl_UserData;
206 uint8 *data;
207 uint32 pixel_count;
208 int32 level = 0, error = OK;
209 uint32 mask_type;
210 struct ElementHeader elem;
212 pixel_count = bmh->bmh_Width * bmh->bmh_Height;
213 if (info->DataSize != ((pixel_count * info->BitDepth) >> 3)) {
214 return DTERROR_INVALID_DATA;
217 IDataTypes->SetDTAttrs(o, NULL, NULL,
218 DTA_NominalHoriz, bmh->bmh_Width,
219 DTA_NominalVert, bmh->bmh_Height,
220 PDTA_SourceMode, PMODE_V43,
221 DTA_ErrorLevel, &level,
222 DTA_ErrorNumber, &error,
223 TAG_END);
224 if (level) return error;
226 if (info->BitDepth == 4) {
227 uint8 *src, *dst;
228 int x, y;
229 data = IExec->AllocVec(pixel_count, 0);
230 if (!data) return ERROR_NO_FREE_STORE;
231 src = info->Data;
232 dst = data;
233 for (y = 0; y < bmh->bmh_Height; y++) {
234 for (x = 0; x < bmh->bmh_Width; x += 2) {
235 *dst++ = *src >> 4;
236 *dst++ = *src & 0xF;
237 src++;
240 } else {
241 data = info->Data;
244 IIntuition->IDoSuperMethod(cl, o,
245 PDTM_WRITEPIXELARRAY, data, PBPAFMT_LUT8,
246 bmh->bmh_Width, 0, 0, bmh->bmh_Width, bmh->bmh_Height);
248 if (info->BitDepth == 4) {
249 IExec->FreeVec(data);
252 SetCMAP(cl, o, 1 << info->BitDepth);
254 IExec->FreeVec(info->Data);
255 info->Data = NULL;
256 mask_type = GetMaskType(info->Type);
257 error = mask_type ? ParseElements(cl, file, &elem, info, mask_type, 0, NULL) :
258 DTERROR_NOT_AVAILABLE;
259 if (error == OK) {
260 uint8 *mask;
261 uint32 plane_size;
262 int32 status;
264 plane_size = (bmh->bmh_Width * bmh->bmh_Height) >> 3;
265 if (!IDOS->ChangeFilePosition(file, plane_size, OFFSET_CURRENT)) {
266 return IDOS->IoErr();
269 mask = IGraphics->AllocRaster(bmh->bmh_Width, bmh->bmh_Height);
270 if (!mask) return ERROR_NO_FREE_STORE;
272 status = IDOS->Read(file, mask, plane_size);
273 if (status != plane_size) {
274 IGraphics->FreeRaster(mask, bmh->bmh_Width, bmh->bmh_Height);
275 return ReadError(status);
278 IDataTypes->SetDTAttrs(o, NULL, NULL,
279 PDTA_MaskPlane, mask,
280 TAG_END);
281 bmh->bmh_Masking = mskHasMask;
283 if (error == DTERROR_NOT_AVAILABLE) error = OK;
285 return OK;
288 static int32 ReadARGB32 (Class *cl, Object *o, BPTR file, struct BitMapHeader *bmh,
289 struct IconInfo *info)
291 struct ClassBase *libBase = (struct ClassBase *)cl->cl_UserData;
292 uint32 bpr;
293 uint8 *buf;
294 int32 status, level = 0, error = OK;
295 uint32 pixel_count;
296 uint32 decoded_size;
297 uint8 *mask = NULL;
299 bpr = bmh->bmh_Width << 2;
300 pixel_count = bmh->bmh_Width * bmh->bmh_Height;
301 decoded_size = pixel_count << 2;
302 buf = IExec->AllocVec(decoded_size, MEMF_SHARED);
303 if (!buf) {
304 return ERROR_NO_FREE_STORE;
307 IDataTypes->SetDTAttrs(o, NULL, NULL,
308 DTA_NominalHoriz, bmh->bmh_Width,
309 DTA_NominalVert, bmh->bmh_Height,
310 PDTA_SourceMode, PMODE_V43,
311 DTA_ErrorLevel, &level,
312 DTA_ErrorNumber, &error,
313 TAG_END);
314 if (level)
315 goto out;
316 else
317 error = OK;
319 if (bmh->bmh_Width >= 256 && bmh->bmh_Height >= 256) {
320 error = icns_jp2_decode(info, buf);
321 } else {
322 struct ElementHeader elem;
323 uint32 mask_type;
324 error = rle24_decode(info->Data, info->DataSize, buf, decoded_size, pixel_count);
325 if (error) goto out;
327 IExec->FreeVec(info->Data);
328 info->Data = NULL;
329 mask = IExec->AllocVec(pixel_count, MEMF_SHARED);
330 if (!mask) {
331 error = ERROR_NO_FREE_STORE;
332 goto out;
335 mask_type = GetMaskType(info->Type);
336 error = mask_type ? ParseElements(cl, file, &elem, info, mask_type, 0, NULL) :
337 DTERROR_NOT_AVAILABLE;
338 if (error == OK) {
339 uint8 *in, *out;
340 uint32 pixels_left;
341 status = IDOS->Read(file, mask, pixel_count);
342 if (status != pixel_count) {
343 error = ReadError(status);
344 goto out;
346 in = mask;
347 out = buf;
348 pixels_left = pixel_count;
349 while (pixels_left--) {
350 *out = *in++;
351 out += 4;
354 if (error == DTERROR_NOT_AVAILABLE) error = OK;
356 if (error) goto out;
358 IIntuition->IDoSuperMethod(cl, o,
359 PDTM_WRITEPIXELARRAY, buf, PBPAFMT_ARGB,
360 bpr, 0, 0, bmh->bmh_Width, bmh->bmh_Height);
362 out:
363 IExec->FreeVec(mask);
364 IExec->FreeVec(buf);
365 return error;
368 static int32 GetICNS (Class *cl, Object *o, struct TagItem *tags) {
369 struct ClassBase *libBase = (struct ClassBase *)cl->cl_UserData;
370 struct BitMapHeader *bmh = NULL;
371 char *filename;
372 int32 srctype;
373 int32 error = ERROR_REQUIRED_ARG_MISSING;
374 BPTR file = (BPTR)NULL;
375 uint32 whichpic, *numpics;
377 filename = (char *)IUtility->GetTagData(DTA_Name, (uint32)"Untitled", tags);
378 whichpic = IUtility->GetTagData(PDTA_WhichPicture, 0, tags);
379 numpics = (uint32 *)IUtility->GetTagData(PDTA_GetNumPictures, (uint32)NULL, tags);
381 IDataTypes->GetDTAttrs(o,
382 PDTA_BitMapHeader, &bmh,
383 DTA_Handle, &file,
384 DTA_SourceType, &srctype,
385 TAG_END);
387 /* Do we have everything we need? */
388 if (bmh && file && srctype == DTST_FILE) {
389 error = ConvertICNS(cl, o, file, bmh, whichpic, numpics);
390 if (error == OK) {
391 IDataTypes->SetDTAttrs(o, NULL, NULL,
392 DTA_ObjName, IDOS->FilePart(filename),
393 TAG_END);
395 } else
396 if (srctype != DTST_FILE) error = ERROR_NOT_IMPLEMENTED;
398 return error;