Added support for zip files.
[cake.git] / rom / oop / rootclass.c
blob042ec1939a2ed94fadaec7bf383c18d961bd4170
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: OOP rootclass
6 Lang: english
7 */
9 #include <proto/exec.h>
10 #include <proto/oop.h>
11 #include <proto/utility.h>
12 #include <exec/memory.h>
13 #include <oop/oop.h>
14 #include <string.h>
16 #include "intern.h"
17 #include "private.h"
19 #undef SDEBUG
20 #undef DEBUG
21 #define SDEBUG 0
22 #define DEBUG 0
23 #include <aros/debug.h>
25 #define MD(x) ((struct metadata *)x)
27 /***************************
28 ** RootClass' metaclass **
29 ***************************/
30 /* The root class' meta class is not really needed, but
31 it makes code of other metaclasses more consistent
34 #define OOPBase ((struct IntOOPBase *)(cl->OOPBasePtr))
35 #define IS_META_ATTR(attr, idx) ( (idx = attr - MetaAttrBase) < num_Meta_Attrs )
36 /**********************
37 ** BaseMeta::New() **
38 **********************/
39 static OOP_Object *basemeta_new(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
41 struct metadata *data;
43 struct OOP_InterfaceDescr *ifdescr = NULL;
44 STRPTR superid = NULL, clid = "-- private class -- ";
45 struct metadata *superptr = NULL;
46 struct TagItem *tag, *tstate;
47 ULONG instsize = (ULONG)-1L;
49 ULONG idx;
51 EnterFunc(bug("BaseMeta::New(cl=%s, msg = %p)\n",
52 cl->ClassNode.ln_Name, msg));
54 /* Analyze the taglist before object is allocated,
55 ** so we can easily exit cleanly if some info is missing
58 tstate = msg->attrList;
60 while ((tag = NextTagItem((const struct TagItem **)&tstate)))
62 if (IS_META_ATTR(tag->ti_Tag, idx))
64 D(bug("Got meta attr %lx with TagIdx %ld\n",
65 tag->ti_Tag, idx ));
67 switch (idx)
70 case aoMeta_SuperID:
71 /* ID of superclass */
72 superid = (STRPTR)tag->ti_Data;
73 D(bug("Got superID: %s\n", superid));
74 break;
76 case aoMeta_InterfaceDescr:
77 D(bug("Got ifdescr\n"));
78 /* What interfaces does the class support ? */
79 ifdescr = (struct OOP_InterfaceDescr *)tag->ti_Data;
80 break;
82 case aoMeta_ID:
83 /* The new class' ID */
84 clid = (STRPTR)tag->ti_Data;
85 D(bug("Got classID: %s\n", clid));
86 break;
88 case aoMeta_SuperPtr:
89 D(bug("Got superPtr\n"));
90 /* If the super class is private, than we must have
91 a pointer to it.
93 superptr = (struct metadata *)tag->ti_Data;
94 break;
96 case aoMeta_InstSize:
97 /* Instance data size for the new class */
98 instsize = (ULONG)tag->ti_Data;
99 break;
107 /* The user must supply instance size */
108 if (instsize == (ULONG)-1)
109 ReturnPtr ("Meta::New, no instsize", OOP_Object *, NULL);
111 /* The new class must have interfaces */
112 if (!ifdescr)
113 ReturnPtr ("Meta::New, no ifdescr", OOP_Object *, NULL);
115 /* The new class must have a superclass */
116 if (!superptr)
118 if (superid)
120 superptr = (struct metadata *)FindName((struct List *)&(GetOBase(OOPBase)->ob_ClassList), superid);
121 if (!superptr)
122 ReturnPtr ("Meta::New, no superptr/id", OOP_Object *, NULL);
126 /* We are sure we have enough args, and can let rootclass alloc the instance data */
127 o = (OOP_Object *)OOP_DoSuperMethod((OOP_Class *)cl, o, (OOP_Msg)msg);
128 if (o)
131 ULONG dispose_mid = OOP_GetMethodID(IID_Root, moRoot_Dispose);
133 D(bug("Instance allocated\n"));
135 data = OOP_INST_DATA(cl, o);
137 D(bug("o=%p,data=%p\n", o, data));
138 D(bug("instoffset: %ld\n", cl->InstOffset));
140 /* Clear instdata, so we in Dispose() can see what's been allocated */
141 memset(data, 0, sizeof (struct metadata));
143 D(bug("superptr=%p\n", superptr));
145 data->public.OOPBasePtr = (struct IntOOPBase *)OOPBase;
148 /* Let subclass create an initialize dispatch tables for the new class object*/
149 if (meta_allocdisptabs(o, (OOP_Class *)superptr, ifdescr))
151 data->disptabs_inited = TRUE;
153 /* Copy the class' ID */
154 D(bug("Allocating class ID\n"));
155 data->public.ClassNode.ln_Name = AllocVec(strlen (clid) + 1, MEMF_ANY);
156 if (data->public.ClassNode.ln_Name)
158 D(bug("class ID allocated\n"));
160 /* Initialize class fields */
161 D(bug("Setting instoffset\n"));
162 /* Instoffset */
163 if (superptr)
164 data->public.InstOffset = superptr->public.InstOffset + superptr->instsize;
165 else
166 data->public.InstOffset = 0UL;
167 D(bug("Setting other stuff\n"));
169 data->subclasscount = 0UL;
170 data->objectcount = 0UL;
171 data->superclass = (OOP_Class *)superptr;
172 data->instsize = instsize;
174 D(bug("Copying class ID\n"));
175 /* Copy class ID */
176 strcpy(data->public.ClassNode.ln_Name, clid);
179 ReturnPtr ("Meta::New", OOP_Object *, o);
183 OOP_CoerceMethod((OOP_Class *)cl, o, (OOP_Msg)&dispose_mid);
186 ReturnPtr ("Meta::New", OOP_Object *, NULL);
190 /**************************
191 ** BaseMeta::Dispose() **
192 **************************/
193 static VOID basemeta_dispose(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
195 struct metadata *data = OOP_INST_DATA(cl, o);
196 IPTR iterval = 0UL;
197 STRPTR interface_id = NULL;
198 ULONG num_methods = 0UL;
200 if (data->public.ClassNode.ln_Name)
201 FreeVec(data->public.ClassNode.ln_Name);
203 /* Release interfaces from global interface table */
204 while (meta_iterateifs(o, &iterval, &interface_id, &num_methods))
206 /* Only release the interfaces that were new for the class */
207 if (!meta_getifinfo((OOP_Object *)MD(o)->superclass, interface_id, &num_methods))
208 release_idbucket(interface_id, GetOBase(OOPBase));
212 if (data->disptabs_inited)
213 meta_freedisptabs(o);
215 OOP_DoSuperMethod(cl, o, msg);
217 return;
221 /****************************
222 ** BaseMeta::getifinfo() **
223 ****************************/
224 static struct IFMethod *basemeta_getifinfo(OOP_Class *cl, OOP_Object *o, struct P_meta_getifinfo *msg)
226 struct IFMethod *mtab = NULL;
227 EnterFunc(bug("BaseMeta::hasinterface(cl=%p, o=%p, iid=%s\n",
228 cl, o, msg->interface_id));
230 /* The object passed might be one of two classes: Root class or basemetaclass */
231 if (0 == strcmp(msg->interface_id, IID_Root))
233 /* Both classes support the root interface */
234 D(bug("Root interface\n"));
235 *(msg->num_methods_ptr) = num_Root_Methods;
236 if ( ((OOP_Class *)o) == BASEMETAPTR)
238 mtab = OOPBase->ob_BaseMetaObject.inst.rootif;
240 else
242 mtab = OOPBase->ob_RootClassObject.inst.rootif;
246 else if (0 == strcmp(msg->interface_id, IID_Meta))
248 D(bug("Meta interface. BASEMETAPTR: %p\n", BASEMETAPTR));
249 if ( ((OOP_Class *)o) == BASEMETAPTR )
252 /* Only BaseMeta has Meta interface */
253 mtab = OOPBase->ob_BaseMetaObject.inst.metaif;
254 *(msg->num_methods_ptr) = NUMTOTAL_M_Meta;
258 ReturnPtr ("BaseMeta::hasinterface", struct IFMethod *, mtab);
262 /*****************************
263 ** BaseMeta::iterateifs() **
264 *****************************/
265 static struct IFMethod *basemeta_iterateifs(
266 OOP_Class *cl, OOP_Object *o, struct P_meta_iterateifs *msg)
268 struct IFMethod *current_if = NULL;
270 EnterFunc(bug("BaseMeta::iterateifs(o=%p)\n", o));
272 /* As in has_interface() the object here can only be the basemetaclass, or rootclass */
273 if (((OOP_Class *)o) == ROOTCLASSPTR)
275 /* Rootclass have only one interface */
276 if ( *(msg->iterval_ptr) )
278 current_if = NULL;
280 else
282 current_if = OOPBase->ob_RootClassObject.inst.rootif;
283 *(msg->num_methods_ptr) = num_Root_Methods;
284 *(msg->interface_id_ptr) = IID_Root;
285 *(msg->iterval_ptr) = 1UL; /* We're through iterating */
288 else if (((OOP_Class *)o) == BASEMETAPTR)
290 struct basemeta_inst *inst = (struct basemeta_inst *)o;
291 switch (*(msg->iterval_ptr))
293 case 0:
294 current_if = inst->rootif;
295 *(msg->num_methods_ptr) = num_Root_Methods;
296 *(msg->interface_id_ptr) = IID_Root;
297 break;
299 case 1:
300 current_if = inst->metaif;
301 *(msg->num_methods_ptr) = NUMTOTAL_M_Meta;
302 *(msg->interface_id_ptr) = IID_Meta;
303 break;
305 default:
306 current_if = NULL;
307 break;
310 (*(msg->iterval_ptr)) ++;
313 else
315 /* Should never get here, unless someone has created an instance
316 of the BaseMeta class (which is meaningless)
318 current_if = NULL;
320 #if DEBUG
321 if (current_if)
323 D(bug("Current IF: %s, num_methods %ld\n",
324 *(msg->interface_id_ptr), *(msg->num_methods_ptr)));
326 #endif
327 ReturnPtr ("BaseMeta::iterate_ifs", struct IFMethod *, current_if);
331 #undef OOPBase
333 /*******************************
334 ** BaseMeta DoSuperMethod() **
335 *******************************/
336 /* cl->USerData passed to DoSuperMethodA might be
337 a subclass of rootclass, which does not have
338 the OOPBase in cl->UserData, so instead we use the
339 meta's UserData (IFMeta or HIDDMeta class
342 #define OOPBase ((struct IntOOPBase *)cl->OOPBasePtr)
344 static IPTR basemeta_dosupermethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
346 ULONG method_offset = *msg & METHOD_MASK;
347 struct IFMethod *ifm;
349 EnterFunc(bug("basemeta_dosupermethod(cl=%p, o=%p, msg=%p)\n",
350 cl, o, msg));
352 if (MD(cl)->superclass == ROOTCLASSPTR)
354 ifm = &(OOPBase->ob_RootClassObject.inst.rootif[*msg]);
356 else /* superclass is the BaseMeta class */
358 switch (*msg >> NUM_METHOD_BITS)
361 case 0:
362 ifm = &(OOPBase->ob_BaseMetaObject.inst.rootif[method_offset]);
363 break;
365 case 1:
366 ifm = &(OOPBase->ob_BaseMetaObject.inst.metaif[method_offset]);
367 break;
370 default:
371 D(bug("Error: basemeta_dosupermethod got method call to unknown interface %d\n",
372 *msg >> NUM_METHOD_BITS));
373 ifm = NULL;
374 break;
377 ReturnPtr ("basemeta_dosupermethod", IPTR, ifm->MethodFunc(ifm->mClass, o, msg));
380 #undef OOPBase
382 #define OOPBase ((struct IntOOPBase *)(cl->OOPBasePtr))
383 /*******************************
384 ** BaseMeta CoerceMethod() **
385 *******************************/
386 static IPTR basemeta_coercemethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
388 ULONG method_offset = *msg & METHOD_MASK;
389 struct IFMethod *ifm;
391 EnterFunc(bug("basemeta_coercemethod(cl=%p, o=%p, msg=%p)\n",
392 cl, o, msg));
395 switch (*msg >> NUM_METHOD_BITS)
398 case 0:
399 ifm = &(OOPBase->ob_BaseMetaObject.inst.rootif[method_offset]);
400 break;
402 case 1:
403 ifm = &(OOPBase->ob_BaseMetaObject.inst.metaif[method_offset]);
404 break;
407 default:
408 D(bug("Error: basemeta_coercemethod got method call to unknown interface %d\n",
409 *msg >> NUM_METHOD_BITS));
410 ifm = NULL;
411 break;
413 ReturnPtr ("basemeta_coercemethod", IPTR, ifm->MethodFunc(ifm->mClass, o, msg));
416 /************************
417 ** BaseMeta DoMethod **
418 ************************/
420 static IPTR basemeta_domethod(OOP_Object *o, OOP_Msg msg)
422 return basemeta_coercemethod(OOP_OCLASS(o), o, msg);
424 #undef OOPBase
426 /**********************
427 ** init_basemeta() **
428 **********************/
430 BOOL init_basemeta(struct IntOOPBase *OOPBase)
432 struct basemetaobject *bmo;
433 BOOL success;
434 ULONG mbase = NULL;
436 EnterFunc(bug("init_basemeta()\n"));
438 bmo = &(OOPBase->ob_BaseMetaObject);
439 bmo->oclass = BASEMETAPTR;
441 bmo->inst.data.public.ClassNode.ln_Name = "private base metaclass";
442 bmo->inst.data.public.OOPBasePtr = (struct Library *)OOPBase;
443 bmo->inst.data.public.InstOffset = 0UL;
444 bmo->inst.data.public.UserData = OOPBase;
445 bmo->inst.data.public.cl_DoSuperMethod = basemeta_dosupermethod;
446 bmo->inst.data.public.cl_CoerceMethod = basemeta_coercemethod;
447 bmo->inst.data.public.cl_DoMethod = basemeta_domethod;
449 bmo->inst.data.superclass = ROOTCLASSPTR;
450 bmo->inst.data.subclasscount = 0UL;
451 bmo->inst.data.objectcount = 0UL;
452 bmo->inst.data.instsize = sizeof (struct metadata);
453 bmo->inst.data.numinterfaces = NUM_BASEMETA_IFS;
455 /* Initialize interface table */
456 bmo->inst.iftable[0] = bmo->inst.rootif;
457 bmo->inst.iftable[1] = bmo->inst.metaif;
459 /* initialize interfaces */
460 bmo->inst.rootif[moRoot_New].MethodFunc = (IPTR (*)())basemeta_new;
461 bmo->inst.rootif[moRoot_Dispose].MethodFunc = (IPTR (*)())basemeta_dispose;
463 bmo->inst.rootif[moRoot_New].mClass = BASEMETAPTR;
464 bmo->inst.rootif[moRoot_Dispose].mClass = BASEMETAPTR;
466 /* Initialize meta interface */
467 bmo->inst.metaif[MO_meta_allocdisptabs].MethodFunc = (IPTR (*)())NULL;
468 bmo->inst.metaif[MO_meta_freedisptabs].MethodFunc = (IPTR (*)())NULL;
469 bmo->inst.metaif[MO_meta_getifinfo].MethodFunc = (IPTR (*)())basemeta_getifinfo;
470 bmo->inst.metaif[MO_meta_iterateifs].MethodFunc = (IPTR (*)())basemeta_iterateifs;
472 bmo->inst.metaif[MO_meta_allocdisptabs].mClass = BASEMETAPTR;
473 bmo->inst.metaif[MO_meta_freedisptabs].mClass = BASEMETAPTR;
474 bmo->inst.metaif[MO_meta_getifinfo].mClass = BASEMETAPTR;
475 bmo->inst.metaif[MO_meta_iterateifs].mClass = BASEMETAPTR;
477 /* Meta interface ID gets initialized to 1 */
478 success = init_mi_methodbase(IID_Meta, &mbase, OOPBase);
480 ReturnBool ("init_basemeta", success);
484 /* Root class is the base class of all classes.
485 (Well, one can create new baseclasses, but all classes must
486 implement the root interface).
489 /************************
490 ** Rootclass methods **
491 ************************/
493 /************
494 ** New() **
495 ************/
496 #define OOPBase ((struct IntOOPBase*)(root_cl->OOPBasePtr))
499 OOP_Object *root_new(OOP_Class *root_cl, OOP_Class *cl, struct pRoot_New *param)
501 struct _OOP_Object *o;
502 struct RootData *data;
504 EnterFunc(bug("Root::New(cl=%s, param = %p)\n",
505 cl->ClassNode.ln_Name, param));
507 /* Allocate memory for the object */
508 D(bug("Object size: %ld\n", MD(cl)->public.InstOffset + MD(cl)->instsize + sizeof (struct _OOP_Object)));
509 o = AllocVec(MD(cl)->public.InstOffset + MD(cl)->instsize + sizeof (struct _OOP_Object), MEMF_ANY|MEMF_CLEAR);
510 if (o)
512 D(bug("Mem allocated: %p\n", o));
513 o->o_Class = (OOP_Class *)cl;
515 data = (struct RootData *)OOP_BASEOBJECT(o);
517 /* Class has one more object */
518 MD(cl)->objectcount ++;
520 ReturnPtr ("Root::New", OOP_Object *, OOP_BASEOBJECT(o) );
523 ReturnPtr ("Root::New", OOP_Object *, NULL);
526 /****************
527 ** Dispose() **
528 ****************/
529 static VOID root_dispose(OOP_Class *root_cl, OOP_Object *o, OOP_Msg msg)
531 EnterFunc(bug("Root::Dispose(o=%p, oclass=%s)\n", o, _OOP_OBJECT(o)->o_Class->ClassNode.ln_Name));
533 MD(OOP_OCLASS(o))->objectcount --;
534 D(bug("Object mem: %p, size: %ld\n", _OOP_OBJECT(o), ((ULONG *)_OOP_OBJECT(o))[-1] ));
536 /* Free object's memory */
537 FreeVec(_OOP_OBJECT(o));
539 ReturnVoid("Root::Dispose");
542 static VOID root_get(OOP_Class *root_cl, OOP_Object *p, struct pRoot_Get *msg)
544 *msg->storage = 0UL;
545 D(bug("!!! Get() METHOD REACHED ROOTCLASS !!!\n"));
546 return;
549 #undef OOPBase
551 /**********************
552 ** init_rootclass() **
553 **********************/
554 BOOL init_rootclass(struct IntOOPBase *OOPBase)
557 struct rootclassobject *rco;
558 OOP_Class *rootclass;
560 BOOL success;
561 ULONG mbase = 0UL;
563 EnterFunc(bug("init_rootclass()\n"));
565 rco = &(OOPBase->ob_RootClassObject);
566 rootclass = &(rco->inst.data.public);
568 /* Its class is the metaobject */
569 rco->oclass = &(OOPBase->ob_BaseMetaObject.inst.data.public);
571 rco->inst.data.public.ClassNode.ln_Name = CLID_Root;
572 rco->inst.data.public.OOPBasePtr = (struct Library *)OOPBase;
573 rco->inst.data.public.InstOffset = NULL;
574 rco->inst.data.public.UserData = (APTR)OOPBase;
576 rco->inst.data.public.cl_DoMethod = NULL;
577 rco->inst.data.public.cl_CoerceMethod = NULL;
578 rco->inst.data.public.cl_DoSuperMethod = basemeta_dosupermethod;
579 rco->inst.data.public.cl_CoerceMethod = basemeta_coercemethod;
580 rco->inst.data.public.cl_DoMethod = basemeta_domethod;
582 D(bug("Root stuff: dosupermethod %p, coeremethod %p, domethod %p\n",
583 basemeta_dosupermethod, basemeta_coercemethod, basemeta_domethod));
585 rco->inst.data.superclass = NULL;
586 rco->inst.data.subclasscount = 0UL;
587 rco->inst.data.objectcount = 0UL;
588 rco->inst.data.instsize = 0UL;
589 rco->inst.data.numinterfaces = 1UL;
591 /* Initialize methodtable */
593 rco->inst.rootif[moRoot_New].MethodFunc = (IPTR (*)())root_new;
594 rco->inst.rootif[moRoot_New].mClass = rootclass;
596 rco->inst.rootif[moRoot_Dispose].MethodFunc = (IPTR (*)())root_dispose;
597 rco->inst.rootif[moRoot_Dispose].mClass = rootclass;
599 rco->inst.rootif[moRoot_Get].MethodFunc = (IPTR (*)())root_get;
600 rco->inst.rootif[moRoot_Get].mClass = rootclass;
602 /* Important: IID_Root interface ID MUST be the first one
603 initialized, so that it gets the value 0UL. This is
604 because it's used as rootclass both for IFMeta and HIDDMeta classes
607 success = init_mi_methodbase(IID_Root, &mbase, OOPBase);
608 if (success)
610 /* Make it public */
611 OOP_AddClass(rootclass);
614 ReturnBool ("init_rootclass", success);
617 /* Below is rootclass DoMethod and CoerceMethod. They are hardly useful,
618 cause you would never create an object of rootclass
622 #define ROOT_CALLMETHOD(cl, o, m) \
624 register struct IFMethod *ifm; \
625 ifm = &(RI(cl)->rootif[msg->MethodID]); \
626 return ifm->MethodFunc(ifm->mClass, o, msg); \
629 #define RI(cl) ((struct rootinst *)cl)
631 static IPTR root_domethod(OOP_Object *o, OOP_Msg msg)
633 register Class *cl;
634 cl = OCLASS(o);
636 ROOT_CALLMETHOD(cl, o, msg);
639 static IPTR root_coercemethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
641 ROOT_CALLMETHOD(cl, o, msg);