1 /*****************************************************************************
2  *
3  * Copyright (c) 2008-2010, CoreCodec, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in the
12  *       documentation and/or other materials provided with the distribution.
13  *     * Neither the name of CoreCodec, Inc. nor the
14  *       names of its contributors may be used to endorse or promote products
15  *       derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY CoreCodec, Inc. ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL CoreCodec, Inc. BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  ****************************************************************************/
29 
30 #include "node.h"
31 #include "node_internal.h"
32 
33 #define NODE_MAGIC    0xF0DE0A6C
34 #define DYNDATA_SHIFT 8
35 
36 static const uint16_t ParamSize[MAX_PARAMTYPE] =
37 {
38 	0,					//TYPE_NONE
39 	sizeof(bool_t),		//TYPE_BOOLEAN
40 	sizeof(int),		//TYPE_INT
41 	sizeof(cc_fraction),//TYPE_FRACTION
42 	MAXDATA,			//TYPE_STRING
43 	sizeof(cc_rect),	//TYPE_RECT
44 	sizeof(cc_point),	//TYPE_POINT
45 	sizeof(rgbval_t),	//TYPE_RGB
46 	sizeof(fourcc_t),	//TYPE_FOURCC
47 	sizeof(filepos_t),	//TYPE_FILEPOS
48 	sizeof(node*),		//TYPE_NODE
49 	sizeof(metanotify),	//TYPE_META
50 	sizeof(pin),		//TYPE_PACKET
51 	sizeof(tick_t),		//TYPE_TICK
52 	sizeof(nodenotify), //TYPE_NODENOTIFY
53 	sizeof(void*),		//TYPE_PTR
54 	MAXDATA,			//TYPE_BINARY
55 	sizeof(notify),		//TYPE_NOTIFY
56 	sizeof(int8_t),		//TYPE_INT8
57 	sizeof(int16_t),	//TYPE_INT16
58 	sizeof(int32_t),	//TYPE_INT32
59 	sizeof(int64_t),	//TYPE_INT64
60 	sizeof(nodefunc),	//TYPE_FUNC
61     sizeof(node*),      //TYPE_NODE_REF
62     sizeof(bool_t),     //TYPE_BOOL_BIT
63     sizeof(pin),        //TYPE_PIN
64     0,                  //TYPE_EVENT
65     MAXDATA,            //TYPE_EXPR
66     sizeof(cc_point16), //TYPE_POINT16
67     sizeof(int16_t)*4,  //TYPE_RECT16
68     sizeof(array),      //TYPE_ARRAY
69 	MAXDATA,			//TYPE_EXPRSTRING
70 	MAXDATA,			//TYPE_EXPRPARAM
71 	sizeof(datetime_t), //TYPE_DATETIME
72 	sizeof(int_fast32_t), //TYPE_DBNO
73     sizeof(cc_guid),    //TYPE_GUID
74     sizeof(int),        //TYPE_FIX16
75     sizeof(int),        //TYPE_LUA_REF
76 	sizeof(notifyex),   //TYPE_NOTIFYEX
77 	sizeof(dataenum),   //TYPE_ENUM
78     sizeof(multi_enum_set), //TYPE_ENUM_MULTI_SET
79     sizeof(size_t),     //TYPE_SIZE
80 };
81 
82 static const tchar_t* ParamName[MAX_PARAMTYPE] =
83 {
84 	T("none"),			//TYPE_NONE
85 	T("boolean"),		//TYPE_BOOLEAN
86 	T("integer"),		//TYPE_INT
87 	T("fraction"),      //TYPE_FRACTION
88 	T("string"),		//TYPE_STRING
89 	T("rectangle"),	    //TYPE_RECT
90 	T("point"),	        //TYPE_POINT
91 	T("rgb"),       	//TYPE_RGB
92 	T("fourcc"),	    //TYPE_FOURCC
93 	T("filepos"),	    //TYPE_FILEPOS
94 	T("node"),  		//TYPE_NODE
95 	NULL,	            //TYPE_META
96 	T("packet"),		//TYPE_PACKET
97 	T("tick"),		    //TYPE_TICK
98 	NULL,               //TYPE_NODENOTIFY
99 	T("pointer"),		//TYPE_PTR
100 	NULL,		        //TYPE_BINARY
101 	NULL,		        //TYPE_NOTIFY
102 	T("integer_8"),		//TYPE_INT8
103 	T("integer_16"),    //TYPE_INT16
104 	T("integer_32"),	//TYPE_INT32
105 	T("integer_64"),	//TYPE_INT64
106 	NULL,	            //TYPE_FUNC
107     T("node_ref"),      //TYPE_NODE_REF
108     NULL,               //TYPE_BOOL_BIT
109     T("pin"),           //TYPE_PIN
110     T("event"),         //TYPE_EVENT
111     NULL,               //TYPE_EXPR
112     T("point_16"),      //TYPE_POINT16
113     T("rect_16"),       //TYPE_RECT16
114     NULL,               //TYPE_ARRAY
115 	NULL,			    //TYPE_EXPRSTRING
116 	NULL,			    //TYPE_EXPRPARAM
117 	T("datetime"),      //TYPE_DATETIME
118     T("db_no"),         //TYPE_DBNO
119     T("guid"),          //TYPE_GUID
120     T("fix_16"),        //TYPE_FIX16
121     NULL,               //TYPE_LUA_REF
122 	NULL,               //TYPE_NOTIFYEX
123 	NULL,               //TYPE_ENUM
124 	NULL,               //TYPE_ENUM_MULTI_SET
125 	T("size"),          //TYPE_SIZE
126 };
127 
128 static const tchar_t* ParamFormat[(TUNIT_MASK>>TUNIT_SHIFT)+1] =
129 {
130     NULL,
131     T("kbyte"),         //TUNIT_KBYTE
132     T("second"),        //TUNIT_SECOND
133     T("mhz"),           //TUNIT_MHZ
134     T("xcoord"),        //TUNIT_XCOORD
135     T("ycoord"),        //TUNIT_YCOORD
136     T("byterate"),      //TUNIT_BYTERATE
137     T("folder"),        //TUNIT_FOLDER
138     T("number"),        //TUNIT_NUMBER
139     T("fix16"),         //TUNIT_FIX16
140     T("ip"),            //TUNIT_IP
141     T("coord"),         //TUNIT_COORD
142     T("password"),      //TUNIT_PASSWORD
143 
144     T("upper"),         //TUNIT_UPPER
145     T("hotkey"),        //TUNIT_HOTKEY
146     T("checklist"),     //TUNIT_CHECKLIST
147     T("percent"),       //TUNIT_PERCENT
148     T("hex"),           //TUNIT_HEX
149     T("task"),          //TUNIT_TASK
150 };
151 
Node_ValidatePtr(anynode * Node)152 static INLINE void Node_ValidatePtr(anynode* Node)
153 {
154 #ifdef CONFIG_DEBUGCHECKS
155     assert(((node*)Node)->Magic==NODE_MAGIC);
156 #endif
157 }
158 
NodeClass_IsPartOf(const nodeclass * p,fourcc_t PartOfClass)159 NOINLINE bool_t NodeClass_IsPartOf(const nodeclass* p, fourcc_t PartOfClass)
160 {
161 	for (;p;p=p->ParentClass)
162 		if (NodeClass_ClassId(p) == PartOfClass)
163 			return 1;
164 	return 0;
165 }
166 
NodeGetClass(const node * p)167 static INLINE nodeclass* NodeGetClass(const node* p)
168 {
169     return ((nodeclass*)p->VMT)-1;
170 }
171 
CheckLoadModule(nodecontext * p,nodemodule * Module)172 static INLINE bool_t CheckLoadModule(nodecontext* p,nodemodule* Module)
173 {
174 	if (&p->Base!=Module && p->LoadModule && !Module->Module)
175         return p->LoadModule(p,Module);
176     return 0;
177 }
178 
CmpClass(const void * UNUSED_PARAM (p),const nodeclass * const * a,const nodeclass * const * b)179 static NOINLINE int CmpClass(const void* UNUSED_PARAM(p), const nodeclass* const* a, const nodeclass* const* b)
180 {
181 	fourcc_t AClass = NodeClass_ClassId(*a);
182 	fourcc_t BClass = NodeClass_ClassId(*b);
183 	if (AClass > BClass) return 1;
184 	if (AClass < BClass) return -1;
185 	if ((*a)->Module != (*b)->Module)
186 		return ((*a)->Module > (*b)->Module) ? 1:-1;
187 	return 0;
188 }
189 
CmpClassNoModule(const void * UNUSED_PARAM (p),const nodeclass * const * a,const nodeclass * const * b)190 static NOINLINE int CmpClassNoModule(const void* UNUSED_PARAM(p), const nodeclass* const* a, const nodeclass* const* b)
191 {
192 	fourcc_t AClass = NodeClass_ClassId(*a);
193 	fourcc_t BClass = NodeClass_ClassId(*b);
194 	if (AClass > BClass) return 1;
195 	if (AClass < BClass) return -1;
196 	return 0;
197 }
198 
CmpClassPri(const void * UNUSED_PARAM (p),const nodeclass * const * a,const nodeclass * const * b)199 static NOINLINE int CmpClassPri(const void* UNUSED_PARAM(p), const nodeclass* const* a, const nodeclass* const* b)
200 {
201 	int APriority = (*a)->Priority;
202 	int BPriority = (*b)->Priority;
203 	if (APriority > BPriority) return -1;
204 	if (APriority < BPriority) return 1;
205 	return CmpClass(NULL,a,b);
206 }
207 
208 typedef struct nodeclassrated {
209     const nodeclass *Class;
210     int Rating;
211 } nodeclassrated;
212 
CmpRatedClassPri(const void * UNUSED_PARAM (p),const nodeclassrated * a,const nodeclassrated * b)213 static NOINLINE int CmpRatedClassPri(const void* UNUSED_PARAM(p), const nodeclassrated* a, const nodeclassrated* b)
214 {
215 	if (a->Rating > b->Rating) return -1;
216 	if (a->Rating < b->Rating) return 1;
217     return CmpClassPri(NULL,&a->Class,&b->Class);
218 }
219 
CmpNode(const void * p,const node * const * a,const node * const * b)220 static NOINLINE int CmpNode(const void* p, const node* const* a, const node* const* b)
221 {
222     const nodeclass* ca = NodeGetClass(*a);
223     const nodeclass* cb = NodeGetClass(*b);
224     return CmpClass(p,&ca,&cb);
225 }
226 
CmpNodeClass(void * UNUSED_PARAM (p),const node * const * a,const fourcc_t * b)227 static NOINLINE int CmpNodeClass(void* UNUSED_PARAM(p), const node* const* a, const fourcc_t* b)
228 {
229 	fourcc_t AClass = NodeClass_ClassId(NodeGetClass(*a));
230 	if (AClass > *b) return 1;
231 	if (AClass < *b) return -1;
232 	return 0;
233 }
234 
NodeContext_FindClass(anynode * Any,fourcc_t ClassId)235 NOINLINE const nodeclass* NodeContext_FindClass(anynode* Any,fourcc_t ClassId)
236 {
237 	size_t Pos;
238 	bool_t Found;
239 	nodeclass_with_vmt Item;
240 	const nodeclass* Ptr;
241     nodecontext* p = Node_Context(Any);
242 
243     if (ClassId == 0)
244         return NULL;
245 
246     Ptr = (const nodeclass*)p->NodeCache;
247     if (Ptr && NodeClass_ClassId(Ptr) == ClassId)
248         return Ptr;
249 
250 	LockEnter(p->NodeLock);
251 	Item.VMT.ClassId = ClassId;
252 	Ptr = &Item.Class;
253 	Pos = ArrayFind(&p->NodeClass,nodeclass*,&Ptr,(arraycmp)CmpClassNoModule, NULL, &Found);
254 	if (Found)
255 	{
256 		if (ARRAYBEGIN(p->NodeClass,const nodeclass*)[Pos]->State<CLASS_REGISTERED)
257 		{
258 			// try searching for a valid
259 			size_t Count = ARRAYCOUNT(p->NodeClass,const nodeclass*);
260 
261 			// find first with same id
262 			for (;Pos>0 && NodeClass_ClassId(ARRAYBEGIN(p->NodeClass,const nodeclass*)[Pos-1]) == ClassId;--Pos) {}
263 
264 			Ptr = NULL;
265 			for (;Pos<Count && NodeClass_ClassId(ARRAYBEGIN(p->NodeClass,const nodeclass*)[Pos]) == ClassId;++Pos)
266 				if (ARRAYBEGIN(p->NodeClass,const nodeclass*)[Pos]->State>=CLASS_REGISTERED)
267 				{
268 					Ptr = ARRAYBEGIN(p->NodeClass,const nodeclass*)[Pos];
269 					break;
270 				}
271 
272 		}
273 		else
274 			Ptr = ARRAYBEGIN(p->NodeClass,const nodeclass*)[Pos];
275 
276         p->NodeCache = Ptr;
277 	}
278 	else
279 	{
280 		Ptr = NULL;
281 		//DebugMessage(T("Class %c%c%c%c (%d) not found"),(ClassId>>0)&0xFF,(ClassId>>8)&0xFF,(ClassId>>16)&0xFF,(ClassId>>24)&0xFF,ClassId);
282 	}
283 
284 	LockLeave(p->NodeLock);
285 	return Ptr;
286 }
287 
FindModuleClass(nodecontext * p,fourcc_t ClassId,nodemodule * Module)288 static NOINLINE const nodeclass* FindModuleClass(nodecontext* p,fourcc_t ClassId,nodemodule* Module)
289 {
290     const nodeclass** i;
291 	for (i=ARRAYBEGIN(p->NodeClass,const nodeclass*);i!=ARRAYEND(p->NodeClass,const nodeclass*);++i)
292 		if (NodeClass_ClassId(*i) == ClassId && (*i)->Module == Module && (*i)->State>=CLASS_REGISTERED)
293 			return *i;
294     return NULL;
295 }
296 
NodeContext_FindClassEx(anynode * AnyNode,fourcc_t ClassId,nodemodule * Module)297 NOINLINE const nodeclass* NodeContext_FindClassEx(anynode* AnyNode,fourcc_t ClassId,nodemodule* Module)
298 {
299     const nodeclass* Class = NULL;
300 	if (ClassId)
301 	{
302         nodecontext* p = Node_Context(AnyNode);
303 		LockEnter(p->NodeLock);
304 
305 		Class = FindModuleClass(p,ClassId,Module);
306 		if (!Class)
307 			Class = NodeContext_FindClass(p,ClassId);
308 
309 		LockLeave(p->NodeLock);
310 	}
311     return Class;
312 }
313 
314 #if defined(CONFIG_DEBUG_LEAKS)
315 extern void DebugMessage(const tchar_t*,...);
316 
317 typedef struct class_ref_t
318 {
319     const nodeclass* Class;
320     size_t Count;
321 
322 } class_ref_t;
323 
CmpClassRef(void * UNUSED_PARAM (p),const class_ref_t * a,const class_ref_t * b)324 static int CmpClassRef(void* UNUSED_PARAM(p), const class_ref_t *a, const class_ref_t *b)
325 {
326     return (a->Class->FourCC - b->Class->FourCC);
327 }
328 
AddClassRef(const nodeclass * Class)329 static void AddClassRef(const nodeclass* Class)
330 {
331     bool_t Found;
332     intptr_t Pos=-1;
333     array *Refs = &Class->Module->ClassRefs;
334     class_ref_t Item;
335 
336     if (!Class->Module->LockRefs)
337         Class->Module->LockRefs = LockCreate();
338 
339     LockEnter(Class->Module->LockRefs);
340 
341     Item.Class = Class;
342     Item.Count = 1;
343     Pos = ArrayFind(Refs,class_ref_t,&Item,(arraycmp)CmpClassRef,NULL,&Found);
344     if (Found)
345     {
346         ARRAYBEGIN(*Refs,class_ref_t)[Pos].Count++;
347     }
348     else if (ArrayAdd(Refs,class_ref_t,&Item,(arraycmp)CmpClassRef,NULL,0)==-1)
349     {
350         DebugMessage(T("AddClassRef %p class %r/%p could not be added !"),Refs,Class->FourCC,Class);
351     }
352 
353     LockLeave(Class->Module->LockRefs);
354 }
355 
DelClassRef(const nodeclass * Class)356 static void DelClassRef(const nodeclass* Class)
357 {
358     bool_t Found;
359     intptr_t Pos;
360     array *Refs = &Class->Module->ClassRefs;
361     class_ref_t Item;
362 
363     if (!Class->Module->LockRefs)
364         Class->Module->LockRefs = LockCreate();
365 
366     LockEnter(Class->Module->LockRefs);
367 
368     Item.Class = Class;
369     Pos = ArrayFind(Refs,class_ref_t,&Item,(arraycmp)CmpClassRef,NULL,&Found);
370     if (Found)
371     {
372         if (--ARRAYBEGIN(*Refs,class_ref_t)[Pos].Count==0)
373         {
374             //DebugMessage(T("class %r No more used !"),Class->FourCC);
375             ArrayRemove(Refs,class_ref_t,&Item,(arraycmp)CmpClassRef,NULL);
376         }
377     }
378     else
379 	{
380         class_ref_t *r;
381         DebugMessage(T("DelClassRef %p class %r/%p Not found !"),Refs,Class->FourCC,Class);
382         for (r=ARRAYBEGIN(*Refs,class_ref_t);r!=ARRAYEND(*Refs,class_ref_t);++r)
383         {
384             DebugMessage(T("%r/%p=%d"),r->Class->FourCC,r->Class,r->Count);
385         }
386         Pos = ArrayFind(Refs,class_ref_t,&Item,(arraycmp)CmpClassRef,NULL,&Found);
387 	}
388     LockLeave(Class->Module->LockRefs);
389 }
390 #else
391 #define AddClassRef(c)
392 #define DelClassRef(c)
393 #endif
394 
395 static void UnInitClass(nodecontext* p,nodeclass* Class, bool_t IncludingModule);
396 
UnRegisterModule(nodecontext * p,nodemodule * Module,bool_t IncludingModule)397 static void UnRegisterModule(nodecontext* p, nodemodule* Module, bool_t IncludingModule)
398 {
399 	nodeclass** i;
400     node** j;
401 
402     // release singleton objects
403     for (j=ARRAYBEGIN(p->NodeSingleton,node*);j!=ARRAYEND(p->NodeSingleton,node*);++j)
404     {
405         if (NodeGetClass(*j)->Module == Module)
406         {
407             node* Node = *j;
408             ArrayDelete(&p->NodeSingleton,(uint8_t*)j-ARRAYBEGIN(p->NodeSingleton,uint8_t),sizeof(node*));
409             Node_Release(Node);
410             j = ARRAYBEGIN(p->NodeSingleton,node*)-1;
411         }
412     }
413 
414     // node memory leak in this module? (root module checked in NodeContext_Done)
415     assert(Module==&p->Base || Module->Base.RefCount==1);
416 
417 	for (i=ARRAYBEGIN(p->NodeClass,nodeclass*);i!=ARRAYEND(p->NodeClass,nodeclass*);++i)
418 		if ((*i)->Meta && (*i)->Module == Module)
419         {
420             if ((*i)->State>=CLASS_INITED)
421                 UnInitClass(p,(*i),IncludingModule);
422 	        (*i)->Meta = NULL;
423         }
424 }
425 
NodeContext_Cleanup(nodecontext * p,bool_t Force)426 NOINLINE bool_t NodeContext_Cleanup(nodecontext* p,bool_t Force)
427 {
428     // at the moment we only release modules without any object (not even singleton objects)
429     // because cleanup and singleton object releasing could have multithreading issues...
430 
431 	bool_t Found=0;
432     if (p->FreeModule)
433     {
434         nodemodule* i;
435     	LockEnter(p->NodeLock);
436 	    for (i=p->Base.Next;i;i=i->Next)
437 		    if (i->Module && (Force || (!i->Config && i->Base.RefCount==1)))
438 		    {
439                 if (!Force)
440                     NodeSingletonEvent(p,NODE_SINGLETON_SHUTDOWN,i);
441                 UnRegisterModule(p,i,0);
442                 p->FreeModule(p,i);
443 			    Found = 1;
444 		    }
445     	LockLeave(p->NodeLock);
446     }
447 	return Found;
448 }
449 
UnlockModules(const nodeclass * Class)450 static NOINLINE void UnlockModules(const nodeclass* Class)
451 {
452 	for (;Class;Class=Class->ParentClass)
453     {
454         DelClassRef(Class);
455 		--Class->Module->Base.RefCount;
456         assert(Class->Module->Base.RefCount>=1);
457     }
458 }
459 
UnlockModulesWithLock(nodecontext * p,const nodeclass * Class)460 static void UnlockModulesWithLock(nodecontext* p,const nodeclass* Class)
461 {
462     LockEnter(p->NodeLock);
463     UnlockModules(Class);
464     LockLeave(p->NodeLock);
465 }
466 
DataFree(nodecontext * p,node * Node,nodedata ** i,bool_t DeletingNode)467 static NOINLINE bool_t DataFree(nodecontext* p, node* Node, nodedata** i, bool_t DeletingNode)
468 {
469     datatype Type;
470     nodedata* Data = *i;
471     nodenotify *n,*m;
472 
473     Type = Data->Code & TYPE_MASK;
474     if (Type == TYPE_NODENOTIFY)
475     {
476         n=(nodenotify*)NodeData_Data(Data);
477         if (n)
478         {
479             if (n->Func) // the notification list is being used
480             {
481                 if (DeletingNode)
482                     n->Referer = &n->Referer; // mark the node to be removed after the notification
483                 else
484                     n->Referer = n; // mark all data to be freed after the notification
485                 return 0;
486             }
487             else
488             {
489                 n=n->Next;
490                 while (n)
491                 {
492                     m=n;
493                     n=n->Next;
494                     MemHeap_Free(p->NodeHeap,m,sizeof(nodenotify));
495                 }
496             }
497         }
498     }
499     else
500     if (Type == TYPE_EXPR && p->ExprRelease)
501         p->ExprRelease((nodeexpr*)NodeData_Data(Data));
502 #if defined(CONFIG_CORELUA)
503     else
504     if (Type == TYPE_LUA_REF && p->LuaRelease)
505         p->LuaRelease(p->LuaCookie,(int*)NodeData_Data(Data));
506 #endif
507     else
508     if (Type == TYPE_NODE_REF && *(node**)NodeData_Data(Data))
509         Node_Release(*(node**)NodeData_Data(Data));
510     else
511     if (Type == TYPE_NOTIFYEX)
512     {
513         notifyex *n=(notifyex*)NodeData_Data(Data);
514         if (n->Free)
515             n->Free(n->FreeCookie,n->This);
516     }
517 
518     *i = Data->Next;
519     MemHeap_Free(p->NodeHeap,Data,sizeof(nodedata)+Node_DataSize(Node,Data->Code>>8,Type,NodeData_Data(Data),META_PARAM_UNSET)); // META_PARAM_UNSET is neutral for the type
520     return 1;
521 }
522 
Node_GetDataStart(node * Node,dataid Id,datatype Type)523 NOINLINE nodedata** Node_GetDataStart(node* Node, dataid Id, datatype Type)
524 {
525     uint_fast32_t Code = (Id<<DYNDATA_SHIFT)|Type;
526     nodedata** i;
527     nodecontext* p = Node_Context(Node);
528 
529     LockEnter(p->NodeLock);
530 
531     for (i=&Node->Data;*i;i=&(*i)->Next)
532         if ((*i)->Code == Code)
533         {
534             LockLeave(p->NodeLock);
535             return i;
536         }
537 
538     LockLeave(p->NodeLock);
539     return NULL;
540 }
541 
Node_RemoveData(node * Node,dataid Id,datatype Type)542 NOINLINE void Node_RemoveData(node* Node, dataid Id, datatype Type)
543 {
544     uint_fast32_t Code = (Id<<DYNDATA_SHIFT)|Type;
545     nodedata** i;
546 	nodecontext* p = Node_Context(Node);
547 
548 	LockEnter(p->NodeLock);
549 
550     for (i=&Node->Data;*i;i=&(*i)->Next)
551         if ((*i)->Code == Code)
552         {
553             DataFree(p,Node,i,0);
554             break;
555         }
556 
557 	LockLeave(p->NodeLock);
558 }
559 
Node_AddData(node * Node,dataid Id,datatype Type,const void * Data)560 NOINLINE void* Node_AddData(node* Node, dataid Id, datatype Type, const void* Data)
561 {
562     if (Node)
563     {
564         size_t Size = Node_DataSize(Node,Id,Type&TYPE_MASK,Data,META_PARAM_UNSET); // META_PARAM_UNSET is neutral for the type
565         if (Size>0)
566         {
567             nodedata* Ptr;
568     	    nodecontext* p = Node_Context(Node);
569     	    LockEnter(p->NodeLock);
570 
571             Ptr = (nodedata*)MemHeap_Alloc(p->NodeHeap,sizeof(nodedata)+Size,0);
572             if (!Ptr)
573             {
574         	    LockLeave(p->NodeLock);
575                 return NULL;
576             }
577 
578             // Data list order is important. Evaluating TYPE_EXPRSTRING needs to be done in the order it was added
579             // This function reverses the order, but we also use Node_Copy with templates so the final order it correct (hackish...)
580 
581             memcpy(NodeData_Data(Ptr),Data,Size);
582             Ptr->Code = (Id<<DYNDATA_SHIFT)|Type;
583             Ptr->Next = Node->Data;
584             Node->Data = Ptr;
585 
586             if (Type == TYPE_NODE_REF && *(node**)NodeData_Data(Ptr))
587                 Node_AddRef(*(node**)NodeData_Data(Ptr));
588 
589 #if defined(CONFIG_CORELUA)
590             if (Type == TYPE_LUA_REF)
591                 p->LuaAddRef(p->LuaCookie,(int*)NodeData_Data(Ptr));
592 #endif
593 
594     	    LockLeave(p->NodeLock);
595 
596             return NodeData_Data(Ptr);
597         }
598     }
599     return NULL;
600 }
601 
SetData(node * p,dataid Id,datatype Type,const void * Data)602 static void* SetData(node* p, dataid Id, datatype Type, const void* Data)
603 {
604     size_t i,Size = Node_DataSize(p,Id,Type&TYPE_MASK,Data,META_PARAM_UNSET); // META_PARAM_UNSET is neutral for the type
605 
606     for (i=0;i<Size;++i)
607         if (((uint8_t*)Data)[i])
608             break;
609 
610     if (NodeTypeSize(Type)==MAXDATA) // variable size
611     {
612         Node_RemoveData(p,Id,Type);
613 
614         // do not write anything if the value is 0
615         if (i<Size)
616             return Node_AddData(p,Id,Type,Data);
617         else
618             return NULL; // TODO: remove the pre-existing data with Node_RemoveData() ?
619     }
620     else
621     {
622         // do not write anything if the value is 0
623         if (i<Size)
624         {
625             void *v = Node_GetData(p,Id,Type);
626             if (!v)
627                 return Node_AddData(p,Id,Type,Data);
628             else
629             {
630                 assert(Size==NodeTypeSize(Type));
631                 memcpy(v,Data,Size);
632             }
633             return v;
634         }
635         else
636             Node_RemoveData(p,Id,Type);
637         return NULL;
638     }
639 }
640 
Node_ReadData(node * p,dataid Id,datatype Type,void * Data,size_t Size)641 err_t Node_ReadData(node* p, dataid Id, datatype Type, void* Data, size_t Size)
642 {
643     const uint8_t* Ptr = Node_GetData(p,Id,Type);
644     if (Ptr)
645     {
646 		if (Type == TYPE_STRING)
647 			tcscpy_s((tchar_t*)Data,Size/sizeof(tchar_t),(const tchar_t*)Ptr);
648         else
649         {
650             size_t DataSize = Node_DataSize(p,Id,Type,Ptr,META_PARAM_GET);
651             if (DataSize > Size)
652                 return ERR_INVALID_PARAM;
653             memcpy(Data,Ptr,DataSize);
654         }
655     }
656     else if ((Type & TYPE_MASK) == TYPE_STRING)
657         *((tchar_t*)Data) = 0;
658     else
659         memset(Data,0,Size);
660 
661     return ERR_NONE;
662 }
663 
Node_GetDataStr(const node * p,dataid Id)664 const tchar_t* Node_GetDataStr(const node* p, dataid Id)
665 {
666     const tchar_t* s = Node_GetData(p,Id,TYPE_STRING);
667     return s?s:T("");
668 }
669 
Node_GetDataDatetime(const node * p,dataid Id)670 datetime_t Node_GetDataDatetime(const node* p, dataid Id)
671 {
672     datetime_t *d = Node_GetData(p,Id,TYPE_DATETIME);
673     return d?*d:INVALID_DATETIME_T;
674 }
675 
676 
Node_GetData(const node * p,dataid Id,datatype Type)677 void* Node_GetData(const node* p, dataid Id, datatype Type)
678 {
679     uint_fast32_t Code = (Id<<DYNDATA_SHIFT)|Type;
680     nodedata* i;
681     for (i=p->Data;i;i=i->Next)
682         if (i->Code == Code)
683             return NodeData_Data(i);
684     return NULL;
685 }
686 
CallDelete(nodecontext * p,node * Node,const nodeclass * Class)687 static NOINLINE bool_t CallDelete(nodecontext* p,node* Node,const nodeclass* Class)
688 {
689     bool_t Result = 1;
690     nodedata **ListItem;
691 
692 	for (;Class;Class=Class->ParentClass)
693 		if (Class->Meta)
694 		{
695 			const nodemeta* m;
696 			for (m=Class->Meta;m->Meta != META_CLASS_PARENT_ID;++m)
697             {
698 				if (m->Meta == META_CLASS_DELETE)
699 					((void(*)(node*))m->Data)(Node);
700                 else
701                 if (m->Meta == META_PARAM_DATA_RELEASE)
702 					((nodeupdatefunc)m->Data)(Node,0);
703                 else
704                 if (m->Meta == (META_MODE_DATA | TYPE_ARRAY) && (intptr_t)m->Data>=0)
705                 {
706                     array* Ptr = (array*)((uint8_t*)Node+m->Data);
707 #if defined(CONFIG_CORECDOC)
708                     if (m[2].Meta == META_PARAM_DATA_FLAGS)
709                     {
710                         ++m;
711                         ++m;
712                     }
713                     if (m[2].Meta == META_PARAM_DATA_RELEASE)
714                     {
715                         ++m;
716                         ++m;
717         				((nodeupdatefunc)m->Data)(Node,0);
718                     }
719 #else
720                     if (m[1].Meta == META_PARAM_DATA_FLAGS)
721                         ++m;
722                     if (m[1].Meta == META_PARAM_DATA_RELEASE)
723                     {
724                         ++m;
725         				((nodeupdatefunc)m->Data)(Node,0);
726                     }
727 #endif
728                     ArrayClear(Ptr);
729                 }
730                 else
731                 if (m->Meta == (META_MODE_DATA | TYPE_NODE_REF) && (intptr_t)m->Data>=0)
732                 {
733                     node** Ptr = (node**)((uint8_t*)Node+m->Data);
734                     node* v = *Ptr;
735                     if (v)
736                     {
737 #if defined(CONFIG_CORECDOC)
738                         if (m[2].Meta == META_PARAM_DATA_FLAGS)
739                         {
740                             ++m;
741                             ++m;
742                         }
743                         if (m[2].Meta == META_PARAM_DATA_RELEASE)
744                         {
745                             ++m;
746                             ++m;
747         				    ((nodeupdatefunc)m->Data)(Node,0);
748                         }
749 #else
750                         if (m[1].Meta == META_PARAM_DATA_FLAGS)
751                             ++m;
752                         if (m[1].Meta == META_PARAM_DATA_RELEASE)
753                         {
754                             ++m;
755         				    ((nodeupdatefunc)m->Data)(Node,0);
756                         }
757 #endif
758                         *Ptr = NULL;
759                         Node_Release(v);
760                     }
761                 }
762             }
763 		}
764 
765     // no need to NodeLock around DataFree(), because object in deleting
766     // (other threads should not touch this object anymore)
767     ListItem = &Node->Data;
768     while (*ListItem)
769         if (!DataFree(p,Node,ListItem,1))
770         {
771             ListItem = &(*ListItem)->Next; // will be deleted on Node_NotifyInternal exit
772             Result = 0;
773         }
774 
775     Node->VMT = NULL;
776     return Result;
777 }
778 
LockModules(nodecontext * p,const nodeclass * Class)779 static NOINLINE const nodeclass* LockModules(nodecontext* p, const nodeclass* Class)
780 {
781     fourcc_t ClassId = NodeClass_ClassId(Class);
782 	nodemodule* Module = Class->Module;
783 
784 	if (!Class->ParentClass)
785 	{
786 		if (Class->ParentId)
787 			return NULL;
788 	}
789 	else
790 	{
791         int8_t State = Class->State;
792 
793 		if (!LockModules(p,Class->ParentClass))
794 			return NULL;
795 
796         if (State<CLASS_INITED)
797             Class = FindModuleClass(p,ClassId,Module); // maybe have been reallocated
798 	}
799 
800     AddClassRef(Class);
801 	++Module->Base.RefCount;
802 
803     if (CheckLoadModule(p,Module))
804     {
805         NodeSingletonEvent(p,NODE_SINGLETON_STARTUP,Module);
806         Class = FindModuleClass(p,ClassId,Module); // maybe have been reallocated
807     }
808 
809 	if (Class->State<CLASS_INITED)
810 	{
811 		UnlockModules(Class);
812 		return NULL;
813 	}
814 
815 	return Class;
816 }
817 
LockModulesWithLock(nodecontext * p,const nodeclass * Class)818 static const nodeclass* LockModulesWithLock(nodecontext* p, const nodeclass* Class)
819 {
820     LockEnter(p->NodeLock);
821     Class = LockModules(p,Class);
822     LockLeave(p->NodeLock);
823     return Class;
824 }
825 
MetaConst(const nodemeta * i,void * Data)826 static void MetaConst(const nodemeta* i,void* Data)
827 {
828 	size_t Size = ParamSize[i->Meta & TYPE_MASK];
829 	if (Size == sizeof(uintptr_t))
830 		*(uintptr_t*)((uint8_t*)Data+i->Id) = i->Data;
831 	else
832     {
833         memset((uint8_t*)Data+i->Id,0,Size);
834 		memcpy((uint8_t*)Data+i->Id,&i->Data,min(sizeof(uintptr_t),Size));
835     }
836 }
837 
CallCreate(nodecontext * p,node * Node,const nodeclass * Class)838 static err_t CallCreate(nodecontext* p,node* Node,const nodeclass* Class)
839 {
840 	if (Class)
841 	{
842 		const nodemeta* i;
843 
844 		if (Class->ParentId && !Class->ParentClass)
845 			return ERR_NOT_SUPPORTED;
846 
847 		if (CallCreate(p,Node,Class->ParentClass)!=ERR_NONE)
848 			return ERR_NOT_SUPPORTED;
849 
850 		assert(Class->Meta && Class->State>=CLASS_INITED);
851 
852 		for (i=Class->Meta;i->Meta != META_CLASS_PARENT_ID;++i)
853 		{
854 			if ((i->Meta & META_MODE_MASK)==META_MODE_CONST)
855 				MetaConst(i,Node);
856 			else
857             if (i->Meta == (META_MODE_DATA | TYPE_ARRAY) && (intptr_t)i->Data>=0)
858             {
859                 array* Ptr = (array*)((uint8_t*)Node+i->Data);
860                 ArrayInitEx(Ptr,p->NodeHeap);
861             }
862             else
863 			if (i->Meta == META_CLASS_CREATE && ((err_t(*)(node*))i->Data)(Node) != ERR_NONE)
864 			{
865 				CallDelete(p,Node,Class->ParentClass);
866 				return ERR_NOT_SUPPORTED;
867 			}
868 		}
869 	}
870 	return ERR_NONE;
871 }
872 
NodeSize(const nodeclass * Class)873 static NOINLINE size_t NodeSize(const nodeclass* Class)
874 {
875 	const nodeclass *j;
876 	const nodemeta* m;
877     size_t Size = 0;
878 
879     if (NodeClass_ClassId(Class) == NODEMODULE_CLASS)
880         return sizeof(nodemodule); // for NodeContext_Done when all classes are already released
881 
882 	for (j=Class;j && !Size;j=j->ParentClass)
883 		for (m=j->Meta;m && m->Meta != META_CLASS_PARENT_ID;++m)
884 			if (m->Meta == META_CLASS_SIZE)
885 			{
886 				Size = (size_t)m->Data;
887 				break;
888 			}
889 
890     return Size;
891 }
892 
Node_Destructor(node * Node)893 void Node_Destructor(node* Node)
894 {
895     if (Node && Node->VMT)
896     {
897     	const nodeclass* Class = NodeGetClass(Node);
898         nodecontext* p = Node_Context(Node);
899 
900         Node_Notify(Node,NODE_DELETING);
901 
902 	    CallDelete(p,Node,Class);
903 
904 #ifdef CONFIG_DEBUGCHECKS
905         Node->Magic = 0;
906 #endif
907 
908         UnlockModulesWithLock(p,Class);
909     }
910 }
911 
AddSingleton(nodecontext * p,node * Node)912 static bool_t AddSingleton(nodecontext* p, node* Node)
913 {
914     bool_t Result;
915     LockEnter(p->NodeLock);
916     Result = ArrayAdd(&p->NodeSingleton,node*,&Node,(arraycmp)CmpNode,NULL,64)>=0;
917     LockLeave(p->NodeLock);
918     return Result;
919 }
920 
Node_Constructor(anynode * AnyNode,node * Node,size_t Size,fourcc_t ClassId)921 err_t Node_Constructor(anynode* AnyNode, node* Node, size_t Size, fourcc_t ClassId)
922 {
923     err_t Err;
924     const nodeclass* Class;
925     nodecontext* p = Node_Context(AnyNode);
926 
927     memset(Node,0,Size);
928     Node->RefCount = 1;
929 
930     Class = NodeContext_FindClass(p,ClassId);
931     if (Class && (Class = LockModulesWithLock(p,Class)) != NULL)
932     {
933 #ifdef CONFIG_DEBUGCHECKS
934         Node->FourCC = ClassId;
935         Node->Magic = NODE_MAGIC;
936 #endif
937         Node->VMT = Class+1;
938 
939 	    Err = CallCreate(p,Node,Class);
940         if (Err == ERR_NONE)
941         {
942             if (Class->Flags & CFLAG_SINGLETON)
943             {
944                 assert(Class->Flags & CFLAG_OWN_MEMORY);
945 
946                 if (!AddSingleton(p,Node))
947                 {
948                     Node_Destructor(Node);
949 			        return ERR_OUT_OF_MEMORY;
950                 }
951 
952                 Node_AddRef(Node);
953             }
954         }
955         else
956         {
957             Node->VMT = NULL;
958 		    UnlockModulesWithLock(p,Class);
959         }
960     }
961     else
962         Err = ERR_NOT_SUPPORTED;
963 
964     return Err;
965 }
966 
967 static node* NodeCreateFromClass(nodecontext* p, const nodeclass* Class, bool_t Singleton);
968 
ReleaseMetaLookup(nodecontext * p,nodeclass * Class)969 static NOINLINE void ReleaseMetaLookup(nodecontext* p, nodeclass* Class)
970 {
971     if (Class->ParentClass)
972     {
973         if (Class->MetaGet==Class->ParentClass->MetaGet)
974             Class->MetaGet=NULL;
975         if (Class->MetaSet==Class->ParentClass->MetaSet)
976             Class->MetaSet=NULL;
977         if (Class->MetaUnSet==Class->ParentClass->MetaUnSet)
978             Class->MetaUnSet=NULL;
979     }
980 
981     if (Class->MetaGet)
982     {
983         MemHeap_Free(p->NodeConstHeap,Class->MetaGet,sizeof(nodemetalookuphead)+(Class->MetaGet->Upper+1)*sizeof(nodemetalookup));
984         Class->MetaGet = NULL;
985     }
986 
987     if (Class->MetaSet)
988     {
989         MemHeap_Free(p->NodeConstHeap,Class->MetaSet,sizeof(nodemetalookuphead)+(Class->MetaSet->Upper+1)*sizeof(nodemetalookup));
990         Class->MetaSet = NULL;
991     }
992 
993     if (Class->MetaUnSet)
994     {
995         MemHeap_Free(p->NodeConstHeap,Class->MetaUnSet,sizeof(nodemetalookuphead)+(Class->MetaUnSet->Upper+1)*sizeof(nodemetalookup));
996         Class->MetaUnSet = NULL;
997     }
998 }
999 
UnInitClass(nodecontext * p,nodeclass * Class,bool_t IncludingModule)1000 static void UnInitClass(nodecontext* p,nodeclass* Class, bool_t IncludingModule)
1001 {
1002     nodeclass** i;
1003 	const nodemeta* m;
1004 
1005     if (!IncludingModule && NodeClass_IsPartOf(Class,NODEMODULE_CLASS))
1006         return;
1007 
1008     // uninit all child classes
1009    	for (i=ARRAYBEGIN(p->NodeClass,nodeclass*);i!=ARRAYEND(p->NodeClass,nodeclass*);++i)
1010     	if ((*i)->State>=CLASS_INITED && (*i)->ParentClass == Class)
1011 			UnInitClass(p,*i,IncludingModule);
1012 
1013 	for (m=Class->Meta;m->Meta != META_CLASS_PARENT_ID;++m)
1014 		if (m->Meta == META_CLASS_VMT_DELETE)
1015 			((void(*)(fourcc_t,const void*))m->Data)(NodeClass_ClassId(Class),Class+1);
1016 
1017     if (Class->State>CLASS_REGISTERED)
1018         Class->State=CLASS_REGISTERED;
1019 
1020     ReleaseMetaLookup(p,Class);
1021 }
1022 
NodeClassResize(nodecontext * p,nodeclass * Old,size_t VMTSize)1023 static nodeclass* NodeClassResize(nodecontext* p,nodeclass* Old,size_t VMTSize)
1024 {
1025     nodeclass* New = MemHeap_ReAlloc(p->NodeHeap,Old,sizeof(nodeclass)+Old->VMTSize,sizeof(nodeclass)+VMTSize);
1026 	if (New)
1027     {
1028         nodeclass** i;
1029 
1030         New->VMTSize = VMTSize;
1031 
1032 	    for (i=ARRAYBEGIN(p->NodeClass,nodeclass*);i!=ARRAYEND(p->NodeClass,nodeclass*);++i)
1033         {
1034             if (*i == Old)
1035                 *i = New;
1036             if ((*i)->ParentClass == Old)
1037                 (*i)->ParentClass = New;
1038         }
1039     }
1040     return New;
1041 }
1042 
FilterLookupGet(const nodemeta * m)1043 static bool_t FilterLookupGet(const nodemeta* m)
1044 {
1045     return m->Meta==META_PARAM_GET || (m->Meta & META_MODE_MASK)==META_MODE_DATA;
1046 }
1047 
FilterLookupSet(const nodemeta * m)1048 static bool_t FilterLookupSet(const nodemeta* m)
1049 {
1050     return m->Meta==META_PARAM_SET || m->Meta==META_PARAM_EVENT ||
1051 #if defined(CONFIG_CORECDOC)
1052         ((m->Meta & META_MODE_MASK)==META_MODE_DATA && (m[2].Meta != META_PARAM_DATA_FLAGS || !((int)m[2].Data & DFLAG_RDONLY)));
1053 #else
1054         ((m->Meta & META_MODE_MASK)==META_MODE_DATA && (m[1].Meta != META_PARAM_DATA_FLAGS || !((int)m[1].Data & DFLAG_RDONLY)));
1055 #endif
1056 }
1057 
FilterLookupUnSet(const nodemeta * m)1058 static bool_t FilterLookupUnSet(const nodemeta* m)
1059 {
1060     return m->Meta==META_PARAM_UNSET || m->Meta==META_PARAM_EVENT ||
1061 #if defined(CONFIG_CORECDOC)
1062         ((m->Meta & META_MODE_MASK)==META_MODE_DATA && (m[2].Meta != META_PARAM_DATA_FLAGS || !((int)m[2].Data & DFLAG_RDONLY)));
1063 #else
1064         ((m->Meta & META_MODE_MASK)==META_MODE_DATA && (m[1].Meta != META_PARAM_DATA_FLAGS || !((int)m[1].Data & DFLAG_RDONLY)));
1065 #endif
1066 }
1067 
BitLookup(const nodeclass * Class,dataid Id)1068 static const nodemeta* BitLookup(const nodeclass* Class,dataid Id)
1069 {
1070     const nodemeta* m;
1071 	for (;Class;Class=Class->ParentClass)
1072         if (Class->Meta)
1073             for (m=Class->Meta;m->Meta != META_CLASS_PARENT_ID;++m)
1074                 if (m->Id == Id && m->Meta == META_PARAM_BIT)
1075                     return m;
1076     return NULL;
1077 }
1078 
CmpLookup(const nodemetalookup * p,const nodemetalookup * a,const nodemetalookup * b)1079 static NOINLINE int CmpLookup(const nodemetalookup* p, const nodemetalookup* a, const nodemetalookup* b)
1080 {
1081     // sort by Id
1082 	if (a->Id > b->Id) return 1;
1083 	if (a->Id < b->Id) return -1;
1084     // make sure META_PARAM_BIT is after META_MODE_DATA
1085     if (a->Meta && b->Meta && a->Meta->Meta == META_PARAM_BIT) return 1;
1086     if (b->Meta && b->Meta && b->Meta->Meta == META_PARAM_BIT) return -1;
1087     // make sure META_PARAM_EVENT's are added in the order as they are found
1088     if (a==p) return 1;
1089     if (b==p) return -1;
1090 	return 0;
1091 }
1092 
AddLookup(nodeclass * Class,const nodemeta * m,array * List)1093 static NOINLINE void AddLookup(nodeclass* Class, const nodemeta* m, array* List)
1094 {
1095     bool_t Found;
1096     nodemetalookup Lookup;
1097     Lookup.Id = m->Id;
1098     Lookup.Meta = NULL;
1099     ArrayFind(List,nodemetalookup,&Lookup,(arraycmp)CmpLookup,NULL,&Found);
1100     if (!Found || m->Meta == META_PARAM_EVENT)
1101     {
1102         if ((m->Meta & META_MODE_MASK)==META_MODE_DATA && (m->Meta & TYPE_MASK)==TYPE_BOOL_BIT)
1103         {
1104             Lookup.Meta = BitLookup(Class,m->Id);
1105             assert(Lookup.Meta);
1106             if (!Lookup.Meta)
1107                 return;
1108             ArrayAdd(List,nodemetalookup,&Lookup,(arraycmp)CmpLookup,NULL,0);
1109         }
1110         Lookup.Meta = m;
1111         ArrayAdd(List,nodemetalookup,&Lookup,(arraycmp)CmpLookup,&Lookup,0);
1112     }
1113 }
1114 
BuildLookup(nodecontext * p,array * List)1115 static NOINLINE nodemetalookuphead* BuildLookup(nodecontext* p,array* List)
1116 {
1117     nodemetalookuphead* v;
1118     nodemetalookuphead Head;
1119     Head.Upper = ARRAYCOUNT(*List,nodemetalookup)-1;
1120     v = MemHeap_Alloc(p->NodeConstHeap,sizeof(Head)+ARRAYCOUNT(*List,uint8_t),0);
1121     if (v)
1122     {
1123         MemHeap_Write(p->NodeConstHeap,v,&Head,0,sizeof(Head));
1124         MemHeap_Write(p->NodeConstHeap,v,ARRAYBEGIN(*List,nodemetalookup),sizeof(Head),ARRAYCOUNT(*List,uint8_t));
1125     }
1126     ArrayClear(List);
1127     return v;
1128 }
1129 
BuildMetaLookup(nodecontext * p,nodeclass * Class)1130 static void BuildMetaLookup(nodecontext* p,nodeclass* Class)
1131 {
1132     const nodeclass* c;
1133     array List;
1134     bool_t NeedGet=0;
1135     bool_t NeedSet=0;
1136     bool_t NeedUnSet=0;
1137 
1138     const nodemeta* m;
1139 	for (m=Class->Meta;m->Meta != META_CLASS_PARENT_ID;++m)
1140     {
1141         if (FilterLookupGet(m))
1142             NeedGet = 1;
1143         if (FilterLookupSet(m))
1144             NeedSet = 1;
1145         if (FilterLookupUnSet(m))
1146             NeedUnSet = 1;
1147     }
1148 
1149 	if (NeedGet)
1150     {
1151         ArrayInit(&List);
1152 	    for (c=Class;c;c=c->ParentClass)
1153             if (c->Meta)
1154                 for (m=c->Meta;m->Meta != META_CLASS_PARENT_ID;++m)
1155 				    if (FilterLookupGet(m))
1156                         AddLookup(Class,m,&List);
1157 
1158         if (!ARRAYEMPTY(List))
1159             Class->MetaGet = BuildLookup(p,&List);
1160     }
1161     else
1162     if (Class->ParentClass)
1163         Class->MetaGet = Class->ParentClass->MetaGet;
1164 
1165 	if (NeedSet)
1166     {
1167         ArrayInit(&List);
1168 	    for (c=Class;c;c=c->ParentClass)
1169             if (c->Meta)
1170                 for (m=c->Meta;m->Meta != META_CLASS_PARENT_ID;++m)
1171 				    if (FilterLookupSet(m))
1172                         AddLookup(Class,m,&List);
1173 
1174         if (!ARRAYEMPTY(List))
1175             Class->MetaSet = BuildLookup(p,&List);
1176     }
1177     else
1178     if (Class->ParentClass)
1179         Class->MetaSet = Class->ParentClass->MetaSet;
1180 
1181 	if (NeedUnSet)
1182     {
1183         ArrayInit(&List);
1184 	    for (c=Class;c;c=c->ParentClass)
1185             if (c->Meta)
1186                 for (m=c->Meta;m->Meta != META_CLASS_PARENT_ID;++m)
1187 				    if (FilterLookupUnSet(m))
1188                         AddLookup(Class,m,&List);
1189 
1190         if (!ARRAYEMPTY(List))
1191             Class->MetaUnSet = BuildLookup(p,&List);
1192     }
1193     else
1194     if (Class->ParentClass)
1195         Class->MetaUnSet = Class->ParentClass->MetaUnSet;
1196 }
1197 
InitClass(nodecontext * p,nodeclass * Class)1198 static void InitClass(nodecontext* p,nodeclass* Class)
1199 {
1200     const nodeclass* Parent = Class->ParentClass;
1201     if (Class->State==CLASS_REGISTERED && Class->Meta && (!Class->ParentId || (Parent && Parent->State>=CLASS_INITED)))
1202     {
1203         uintptr_t Data;
1204         const nodemeta* i;
1205 
1206         if (Parent)
1207         {
1208             fourcc_t ClassId;
1209 
1210             if (Class->VMTSize == DEFAULT_VMT && Parent->VMTSize > DEFAULT_VMT)
1211             {
1212                 Class = NodeClassResize(p,Class,Parent->VMTSize);
1213                 if (!Class)
1214                     return;
1215             }
1216 
1217             assert(Parent->VMTSize >= DEFAULT_VMT);
1218             assert(Class->VMTSize >= Parent->VMTSize);
1219             assert(NodeClass_Context(Parent) == NodeClass_Context(Class));
1220 
1221             ClassId = NodeClass_ClassId(Class);
1222             memcpy(Class+1,Parent+1,min(Class->VMTSize,Parent->VMTSize));
1223             NodeClass_ClassId(Class) = ClassId;
1224         }
1225 
1226         BuildMetaLookup(p,Class);
1227 
1228         assert(Class->VMTSize >= DEFAULT_VMT);
1229         Class->State = CLASS_INITED;
1230 
1231 	    for (i=Class->Meta;i->Meta != META_CLASS_PARENT_ID;++i)
1232 	    {
1233 		    if ((i->Meta & META_MODE_MASK)==META_MODE_VMT)
1234 			{
1235 #if defined(CONFIG_CORECDOC)
1236 				if ((i->Meta & ~META_MODE_MASK)==TYPE_FUNC) // otherwise it might be some doc items
1237 #endif
1238 					MetaConst(i,Class+1);
1239 			}
1240 		    else
1241 		    switch (i->Meta)
1242 		    {
1243 		    case META_CLASS_VMT_CREATE:
1244 			    if (((int(*)(fourcc_t,void*))i->Data)(NodeClass_ClassId(Class),Class+1) != ERR_NONE)
1245                 {
1246                     ReleaseMetaLookup(p,Class);
1247                     p->NodeCache = NULL;
1248 				    Class->State = CLASS_FAILED;
1249                 }
1250 			    break;
1251 
1252             case META_CLASS_META:
1253                 if (((bool_t(*)(nodecontext*,void*,datameta,uintptr_t*))i->Data)(p,Class+1,META_CLASS_FLAGS,&Data))
1254     			    Class->Flags = (uint8_t)Data;
1255                 if (((bool_t(*)(nodecontext*,void*,datameta,uintptr_t*))i->Data)(p,Class+1,META_CLASS_PRIORITY,&Data))
1256 			        Class->Priority = (int16_t)(Data-PRI_DEFAULT);
1257                 break;
1258 
1259 		    case META_CLASS_FLAGS:
1260 			    Class->Flags = (uint8_t)i->Data;
1261 			    break;
1262 
1263 		    case META_CLASS_PRIORITY:
1264 			    Class->Priority = (int16_t)(i->Data-PRI_DEFAULT);
1265 			    break;
1266 		    }
1267 	    }
1268 
1269 	    if (Class->State>=CLASS_INITED && (Class->Flags & (CFLAG_SINGLETON|CFLAG_OWN_MEMORY))==CFLAG_SINGLETON && !NodeCreateFromClass(p,Class,1))
1270 	    {
1271             p->NodeCache = NULL;
1272             Class->State = CLASS_FAILED;
1273             UnInitClass(p,Class,0); // just to call META_CLASS_VMT_DELETE
1274 	    }
1275 
1276 	    if (Class->State>=CLASS_INITED)
1277         {
1278             nodeclass** i;
1279     	    for (i=ARRAYBEGIN(p->NodeClass,nodeclass*);i!=ARRAYEND(p->NodeClass,nodeclass*);++i)
1280 	    	    if ((*i)->ParentClass == Class)
1281 		    	    InitClass(p,*i);
1282         }
1283     }
1284 }
1285 
NodeContext_UpdateParents(nodecontext * p)1286 void NodeContext_UpdateParents(nodecontext* p)
1287 {
1288 	nodeclass** i;
1289 	for (i=ARRAYBEGIN(p->NodeClass,nodeclass*);i!=ARRAYEND(p->NodeClass,nodeclass*);++i)
1290     {
1291 		(*i)->ParentClass = NodeContext_FindClass(p,(*i)->ParentId);
1292         InitClass(p,*i);
1293     }
1294 }
1295 
NodeCreateFromClass(nodecontext * p,const nodeclass * Class,bool_t Singleton)1296 static node* NodeCreateFromClass(nodecontext* p, const nodeclass* Class, bool_t Singleton)
1297 {
1298 	node* Node;
1299 	size_t Size;
1300 
1301 	if (!Class || (Class->Flags & CFLAG_ABSTRACT))
1302 		return NULL;
1303 
1304 	if ((Class->Flags & CFLAG_SINGLETON) && (Node = NodeSingleton(p,NodeClass_ClassId(Class)))!=NULL)
1305 	{
1306         if (!Singleton)
1307             Node_AddRef(Node);
1308 		return Node;
1309 	}
1310 
1311 	Class = LockModulesWithLock(p,Class);
1312     if (!Class)
1313 		return NULL;
1314 
1315 	Size = NodeSize(Class);
1316 	if (!Size)
1317 	{
1318         UnlockModulesWithLock(p,Class);
1319 		return NULL;
1320 	}
1321 
1322     Node = (node*)MemHeap_Alloc(p->NodeHeap,Size,0);
1323     if (Node)
1324     {
1325 		memset(Node,0,Size);
1326 #ifdef CONFIG_DEBUGCHECKS
1327         Node->FourCC = NodeClass_ClassId(Class);
1328         Node->Magic = NODE_MAGIC;
1329 #endif
1330         Node->RefCount = 1;
1331         Node->VMT = Class+1;
1332 
1333         if (Singleton && !AddSingleton(p,Node))
1334         {
1335 	        UnlockModulesWithLock(p,Class);
1336 	        return NULL;
1337         }
1338 
1339 		if (CallCreate(p,Node,Class) != ERR_NONE)
1340 		{
1341         	LockEnter(p->NodeLock);
1342             if (Singleton)
1343                 ArrayRemove(&p->NodeSingleton,node*,&Node,NULL,NULL); // can't use CmpNode, because Node->VMT is NULL
1344 			UnlockModules(Class);
1345         	LockLeave(p->NodeLock);
1346 
1347             MemHeap_Free(p->NodeHeap,Node,Size);
1348 			Node = NULL;
1349 		}
1350 	}
1351 
1352 	return Node;
1353 }
1354 
NodeContext_CreateClass(nodecontext * p,fourcc_t ClassId,size_t VMTSize,nodemodule * Module)1355 nodeclass* NodeContext_CreateClass(nodecontext* p, fourcc_t ClassId, size_t VMTSize, nodemodule* Module)
1356 {
1357 	nodeclass* Class = NULL;
1358 	nodeclass** i;
1359     size_t Size = sizeof(nodeclass)+VMTSize;
1360 
1361     assert(VMTSize>=DEFAULT_VMT);
1362 
1363     p->NodeCache = NULL;
1364 
1365 	for (i=ARRAYBEGIN(p->NodeClass,nodeclass*);i!=ARRAYEND(p->NodeClass,nodeclass*);++i)
1366 		if (NodeClass_ClassId(*i) == ClassId && (*i)->Module == Module)
1367 		{
1368 			Class = *i;
1369 			break;
1370 		}
1371 
1372 	if (!Class)
1373 	{
1374    	    nodeclass** i;
1375 
1376 		Class = (nodeclass*) MemHeap_Alloc(p->NodeHeap,Size,0);
1377 		if (!Class)
1378 			return NULL;
1379 
1380 		memset(Class,0,Size);
1381 #ifdef CONFIG_DEBUGCHECKS
1382         Class->FourCC = ClassId;
1383 #endif
1384 		Class->VMTSize = VMTSize;
1385 		NodeClass_Context(Class) = p;
1386 		NodeClass_ClassId(Class) = ClassId;
1387 		Class->Module = Module;
1388 
1389 	    if (ArrayAdd(&p->NodeClass,nodeclass*,&Class,(arraycmp)CmpClass,NULL,128)<0)
1390         {
1391 			MemHeap_Free(p->NodeHeap,Class,Size);
1392 			return NULL;
1393         }
1394 
1395 	    // update child classes
1396 		for (i=ARRAYBEGIN(p->NodeClass,nodeclass*);i!=ARRAYEND(p->NodeClass,nodeclass*);++i)
1397 		    if ((*i)->ParentId == NodeClass_ClassId(Class) && (!(*i)->ParentClass || (*i)->ParentClass->State<CLASS_REGISTERED || (*i)->Module == Class->Module))
1398 				(*i)->ParentClass = Class;
1399 	}
1400 	else
1401 	{
1402 		if (Class->Meta)
1403 			return NULL; // already registered
1404 
1405 		if (Class->VMTSize != VMTSize)
1406         {
1407             Class = NodeClassResize(p,Class,VMTSize);
1408             if (!Class)
1409                 return NULL;
1410         }
1411 	}
1412 
1413     if (Class->State<CLASS_REGISTERED)
1414 	    Class->State=CLASS_REGISTERED;
1415 	Class->Priority = 0;
1416 	Class->Flags = 0;
1417 
1418 	return Class;
1419 }
1420 
NodeRegisterClassEx(nodemodule * Module,const nodemeta * Meta)1421 void NodeRegisterClassEx(nodemodule* Module,const nodemeta* Meta)
1422 {
1423 	nodeclass* Class;
1424 	nodecontext* p = Node_Context(Module);
1425 	LockEnter(p->NodeLock);
1426 
1427 	while (Meta->Meta == META_CLASS_CLASS_ID)
1428 	{
1429         const nodeclass* ParentClass;
1430         fourcc_t ParentId;
1431 		fourcc_t ClassId = (fourcc_t)(Meta++)->Data;
1432 		size_t VMTSize = DEFAULT_VMT;
1433         const nodemeta* i = Meta;
1434 
1435         if (!ClassId)
1436             ClassId = ++p->DynamicClass;
1437 
1438         for (;Meta->Meta != META_CLASS_PARENT_ID;++Meta)
1439             if (Meta->Meta == META_CLASS_VMT_SIZE)
1440 			    VMTSize = (size_t)(Meta->Data);
1441 
1442         ParentId = (fourcc_t)Meta->Data;
1443         ParentClass = NodeContext_FindClassEx(p,ParentId,Module);
1444 
1445         if (VMTSize == DEFAULT_VMT && ParentClass)
1446             VMTSize = ParentClass->VMTSize;
1447 
1448 		Class = NodeContext_CreateClass(p,ClassId,VMTSize,Module);
1449 		if (Class)
1450 		{
1451 			Class->Meta = i;
1452 			Class->ParentId = ParentId;
1453 			Class->ParentClass = ParentClass;
1454             InitClass(p,Class);
1455 		}
1456 
1457 		if (!(Meta++)->Id) // more classes?
1458 			break;
1459 	}
1460 
1461 	LockLeave(p->NodeLock);
1462 }
1463 
EraseNode(nodecontext * p,node * Node,const nodeclass * Class)1464 static void EraseNode(nodecontext* p,node* Node,const nodeclass* Class)
1465 {
1466     size_t Size = NodeSize(Class);
1467 
1468 #ifdef CONFIG_DEBUGCHECKS
1469     Node->Magic = 0;
1470 #endif
1471 
1472     UnlockModulesWithLock(p,Class);
1473 
1474     if (!(Class->Flags & CFLAG_OWN_MEMORY))
1475         MemHeap_Free(p->NodeHeap,Node,Size);
1476 }
1477 
Node_AddRef(thisnode p)1478 void Node_AddRef(thisnode p)
1479 {
1480     assert(p); // we may switch to virtual reference functions later
1481     Node_ValidatePtr(p);
1482     ++((node*)p)->RefCount;
1483 }
1484 
Node_Release(thisnode p)1485 void Node_Release(thisnode p)
1486 {
1487     nodecontext* Context;
1488     assert(p); // we may switch to virtual reference functions later
1489     Node_ValidatePtr(p);
1490 
1491     Context = Node_Context(p);
1492     if (--((node*)p)->RefCount == 0)
1493     {
1494     	const nodeclass* Class = NodeGetClass(p);
1495         Node_Notify((node*)p,NODE_DELETING);
1496 
1497         assert(((node*)p)->RefCount == 0); // the RefCount may increase during Node_Notify but it shouldn't
1498         if (CallDelete(Context,p,Class))
1499             EraseNode(Context,p,Class);
1500     }
1501 }
1502 
NodeDelete(node * p)1503 void NodeDelete(node* p)
1504 {
1505     if (p)
1506         Node_Release(p);
1507 }
1508 
NodeClassModule(anynode * Any,fourcc_t ClassId)1509 nodemodule* NodeClassModule(anynode* Any,fourcc_t ClassId)
1510 {
1511     nodecontext* p = Node_Context(Any);
1512     nodemodule* Module = NULL;
1513 	const nodeclass* Class = NULL;
1514 	if (ClassId)
1515 	{
1516 		LockEnter(p->NodeLock);
1517 		Class = NodeContext_FindClass(p,ClassId);
1518 		LockLeave(p->NodeLock);
1519 	}
1520 	if (Class)
1521 		Module = Class->Module;
1522 	else
1523 		Module = &p->Base;
1524     return Module;
1525 }
1526 
NodeModule(node * Node)1527 nodemodule* NodeModule(node* Node)
1528 {
1529     return NodeGetClass(Node)->Module;
1530 }
1531 
Node_IsPartOf(const void * Node,fourcc_t PartOfClass)1532 NOINLINE bool_t Node_IsPartOf(const void* Node, fourcc_t PartOfClass)
1533 {
1534     Node_ValidatePtr(Node);
1535     return NodeClass_IsPartOf(NodeGetClass(Node),PartOfClass);
1536 }
1537 
NodeClassSetPriority(node * Node,int Priority)1538 NOINLINE void NodeClassSetPriority(node* Node,int Priority)
1539 {
1540     NodeGetClass(Node)->Priority = (int16_t)(Priority - PRI_DEFAULT);
1541 }
1542 
NodeClassFlags(node * Node)1543 NOINLINE int NodeClassFlags(node* Node)
1544 {
1545 	return NodeGetClass(Node)->Flags;
1546 }
1547 
NodeCreate(anynode * Any,fourcc_t ClassId)1548 node* NodeCreate(anynode* Any, fourcc_t ClassId)
1549 {
1550 	nodecontext* p = Node_Context(Any);
1551 	return NodeCreateFromClass(p,NodeContext_FindClass(p,ClassId),0);
1552 }
1553 
NodeSingleton(anynode * Any,fourcc_t Class)1554 node* NodeSingleton(anynode* Any, fourcc_t Class)
1555 {
1556 	node* Node = NULL;
1557 	if (Any)
1558 	{
1559 		nodecontext* p = Node_Context(Any);
1560 		size_t Pos;
1561         bool_t Found;
1562 
1563 		LockEnter(p->NodeLock);
1564 
1565         Pos = ArrayFind(&p->NodeSingleton,node*,&Class,(arraycmp)CmpNodeClass,NULL,&Found);
1566     	if (Found)
1567             Node = ARRAYBEGIN(p->NodeSingleton,node*)[Pos];
1568 
1569 		LockLeave(p->NodeLock);
1570 	}
1571 	return Node;
1572 }
1573 
NodeIsClass(anynode * p,fourcc_t ClassId,fourcc_t PartOfClass)1574 bool_t NodeIsClass(anynode* p,fourcc_t ClassId, fourcc_t PartOfClass)
1575 {
1576 	return NodeClass_IsPartOf(NodeContext_FindClass(p,ClassId),PartOfClass);
1577 }
1578 
NodeEnumClass(anynode * Any,array * ListId,fourcc_t ClassId)1579 fourcc_t NodeEnumClass(anynode* Any,array* ListId, fourcc_t ClassId)
1580 {
1581 	return NodeEnumClassFilterRated(Any,ListId,ClassId,NULL,NULL);
1582 }
1583 
1584 typedef struct filterstr
1585 {
1586     int Id;
1587     const tchar_t* Str;
1588 } filterstr;
1589 
FilterStr(filterstr * i,const nodeclass * Class)1590 static int FilterStr(filterstr* i, const nodeclass* Class)
1591 {
1592     //TODO: suppport rating
1593     return StrListIndex(i->Str,NodeClass_Str(NULL,Class,i->Id))>=0?1:0;
1594 }
1595 
NodeEnumClassStr(anynode * Any,array * ListId,fourcc_t ClassId,int Id,const tchar_t * Str)1596 fourcc_t NodeEnumClassStr(anynode* Any,array* ListId, fourcc_t ClassId, int Id, const tchar_t* Str)
1597 {
1598     filterstr i;
1599     if (!Str || !Str[0])
1600     {
1601         if (ListId)
1602             ArrayInit(ListId);
1603         return 0;
1604     }
1605     i.Id = Id;
1606     i.Str = Str;
1607 	return NodeEnumClassFilterRated(Any,ListId,ClassId,(nodeenumclassfilterrated)FilterStr,&i);
1608 }
1609 
NodeEnumSingletonsEx(anynode * Any,array * List,nodemodule * Module)1610 static NOINLINE void NodeEnumSingletonsEx(anynode* Any,array* List, nodemodule* Module)
1611 {
1612     nodecontext* p = Node_Context(Any);
1613     node** i;
1614 	ArrayInit(List);
1615 
1616 	LockEnter(p->NodeLock);
1617 	for (i=ARRAYBEGIN(p->NodeSingleton,node*);i!=ARRAYEND(p->NodeSingleton,node*);++i)
1618 		if (*i && (!Module || NodeGetClass(*i)->Module == Module))
1619 			ArrayAppend(List,i,sizeof(*i),64);
1620 	LockLeave(p->NodeLock);
1621 }
1622 
NodeEnumSingletons(anynode * Any,array * List)1623 void NodeEnumSingletons(anynode* Any,array* List)
1624 {
1625     NodeEnumSingletonsEx(Any,List,NULL);
1626 }
1627 
NodeParamMeta(const nodeclass * Class,uint_fast32_t Meta,dataid Id,const node * Node)1628 static uintptr_t NOINLINE NodeParamMeta(const nodeclass* Class, uint_fast32_t Meta, dataid Id, const node* Node)
1629 {
1630     uintptr_t Data;
1631 	const nodemeta* m;
1632 
1633     for (;Class;Class=Class->ParentClass)
1634     {
1635 		if (Class->Meta) // should be registered, just fail safe
1636 			for (m=Class->Meta;m->Meta != META_CLASS_PARENT_ID;++m)
1637                 if (m->Id == Id)
1638                 {
1639 				    if (m->Meta == Meta)
1640 					    return m->Data;
1641                     if (m->Meta == META_PARAM_META && ((bool_t(*)(const node*,dataid,datameta,uintptr_t*))m->Data)(Node,Id,Meta,&Data))
1642                         return Data;
1643                 }
1644 
1645         if (Meta == META_PARAM_STRING)
1646         {
1647             const nodeclass* MainClass = Class;
1648             nodecontext* Context = NodeClass_Context(Class);
1649 
1650             // only check for META_PARAM_META...
1651 	        while ((Class=Class->ParentClass)!=NULL)
1652             {
1653 		        if (Class->Meta) // should be registered, just fail safe
1654 			        for (m=Class->Meta;m->Meta != META_CLASS_PARENT_ID;++m)
1655                         if (m->Id == Id && m->Meta == META_PARAM_META && ((bool_t(*)(const node*,dataid,datameta,uintptr_t*))m->Data)(Node,Id,Meta,&Data))
1656                             return Data;
1657             }
1658 
1659             Class = MainClass;
1660             if (Context->ExternalStr)
1661             {
1662                 do {
1663                     Data = (uintptr_t)Context->ExternalStr(Context,NodeClass_ClassId(Class),(int)Id);
1664                     if (Data!=0 && *((const tchar_t*)Data))
1665                         return Data;
1666                 } while ((Class=Class->ParentClass)!=NULL);
1667                 return (uintptr_t)T("");
1668             }
1669         }
1670     }
1671 	return 0;
1672 }
1673 
NodeClass_Meta(const nodeclass * Class,dataid Id,datameta Meta)1674 NOINLINE uintptr_t NodeClass_Meta(const nodeclass* Class,dataid Id,datameta Meta)
1675 {
1676     return NodeParamMeta(Class,Meta,Id,NULL);
1677 }
1678 
NodeClass_Priority(const nodeclass * Class)1679 NOINLINE int NodeClass_Priority(const nodeclass* Class)
1680 {
1681     return Class?Class->Priority:PRI_MINIMUM;
1682 }
1683 
NodeClass_Parent(const nodeclass * Class)1684 NOINLINE fourcc_t NodeClass_Parent(const nodeclass* Class)
1685 {
1686     return Class?Class->ParentId:0;
1687 }
1688 
NodeClass_Str(anynode * AnyNode,const nodeclass * Class,int No)1689 NOINLINE const tchar_t* NodeClass_Str(anynode* AnyNode, const nodeclass* Class,int No)
1690 {
1691 	const tchar_t* s = (const tchar_t*)NodeParamMeta(Class,META_PARAM_STRING,No,AnyNode);
1692     return s?s:T("");
1693 }
1694 
NodeParamStr(const node * p,int No)1695 const tchar_t* NodeParamStr(const node* p,int No)
1696 {
1697     return NodeClass_Str(p,NodeGetClass(p),No);
1698 }
1699 
NodeStr2(anynode * AnyNode,fourcc_t ClassId,int No)1700 const tchar_t* NodeStr2(anynode* AnyNode,fourcc_t ClassId,int No)
1701 {
1702 	nodecontext* Context = Node_Context(AnyNode);
1703     const nodeclass* Class = NodeContext_FindClass(Context,ClassId);
1704     if (Class)
1705 	    return NodeClass_Str(AnyNode,Class,No);
1706     if (Context->ExternalStr)
1707         return Context->ExternalStr(Context,ClassId,No);
1708     return T("");
1709 }
1710 
1711 //TODO: check if this can be merged with NodeStr2
NodeStrEx(anynode * AnyNode,fourcc_t ClassId,int No)1712 const tchar_t* NodeStrEx(anynode* AnyNode,fourcc_t ClassId,int No)
1713 {
1714 	nodecontext* Context = Node_Context(AnyNode);
1715     if (Context->ExternalStr)
1716         return Context->ExternalStr(Context,ClassId,No);
1717     return T("");
1718 }
1719 
NodeEnumClassFilterRated(anynode * AnyContext,array * ListId,fourcc_t ClassId,nodeenumclassfilterrated Func,void * Param)1720 fourcc_t NodeEnumClassFilterRated(anynode* AnyContext, array* ListId, fourcc_t ClassId, nodeenumclassfilterrated Func, void* Param)
1721 {
1722     nodecontext* p;
1723 	const nodeclass* v;
1724 	const nodeclass **i;
1725 	array List;
1726 
1727 	fourcc_t BestId = 0;
1728 	int BestPri = 0;
1729     int BestRate = 0;
1730 
1731     assert(AnyContext != NULL);
1732     p = Node_Context(AnyContext);
1733 
1734 	ArrayInit(&List);
1735 
1736 	LockEnter(p->NodeLock);
1737 	for (i=ARRAYBEGIN(p->NodeClass,const nodeclass*);i!=ARRAYEND(p->NodeClass,const nodeclass*);++i)
1738     {
1739 		if ((*i)->State>=CLASS_REGISTERED && !((*i)->Flags & CFLAG_ABSTRACT)) // skip abstract
1740         {
1741 			for (v=*i;v;v=v->ParentClass)
1742 				if (NodeClass_ClassId(v) == ClassId)
1743 				{
1744                     int Rating = Func ? Func(Param,*i):1;
1745                     if (Rating > 0)
1746                     {
1747 					    if (!ListId)
1748 					    {
1749 						    if (BestRate < Rating || (BestRate == Rating && BestPri < (*i)->Priority))
1750 						    {
1751 							    BestId = NodeClass_ClassId(*i);
1752 							    BestPri = (*i)->Priority;
1753                                 BestRate = Rating;
1754 						    }
1755 					    }
1756 					    else
1757                         {
1758                             nodeclassrated Item;
1759                             Item.Class = *i;
1760                             Item.Rating = Rating;
1761     					    ArrayAppend(&List,&Item,sizeof(Item),64);
1762                         }
1763                     }
1764 					break;
1765 				}
1766         }
1767     }
1768 
1769 	if (ListId)
1770 	{
1771 		fourcc_t* a;
1772 		nodeclassrated* b;
1773 		size_t Count = ARRAYCOUNT(List,nodeclassrated);
1774 		ArraySort(&List,nodeclassrated,(arraycmp)CmpRatedClassPri, NULL, 0);
1775 
1776 		ArrayInit(ListId);
1777 		if (ArrayAppend(ListId,NULL,Count*sizeof(fourcc_t),64))
1778 		{
1779 			for (a=ARRAYBEGIN(*ListId,fourcc_t),b=ARRAYBEGIN(List,nodeclassrated);b!=ARRAYEND(List,nodeclassrated);++b,++a)
1780                 *a = NodeClass_ClassId(b->Class);
1781 		}
1782 		ArrayClear(&List);
1783 	}
1784 
1785 	LockLeave(p->NodeLock);
1786 	return BestId;
1787 }
1788 
Node_NotifyInternal(node * Node,dataid Id,nodedata ** i,nodecontext * Context)1789 static INLINE void Node_NotifyInternal(node* Node,dataid Id,nodedata** i,nodecontext* Context)
1790 {
1791 	const nodeclass* Class = NodeGetClass(Node);
1792     nodenotify* Top = NodeData_Data(*i);
1793     nodeevt Pin;
1794     nodenotify *n,*m;
1795     bool_t PostDeleteNode = 0, PosDeleteList = 0;
1796 
1797     // Top->Referer = any: the item of the list being called / NULL: remove the item being called from the list / Top: delete all the notification / &Top->Referer: delete all the node
1798     // Top->Func = set if the notification is in use
1799 
1800     if (Top->Func!=NULL)
1801     {
1802         assert(Top->Func!=NULL);
1803         return; // already being notified, not supported
1804     }
1805     Top->Func = (notifyproc)Top; // mark the notification as in use
1806 
1807     Pin.Node = Node;
1808     Pin.Id = Id;
1809 
1810     n = Top->Next; // skip the dummy notify element
1811     assert(n!=NULL); // if there is a Top there should be at least one item in the list
1812     while (n)
1813     {
1814         Top->Referer = n; // tell the RemoveNotify that this item in the list is being used
1815         m=n;
1816         n->Func(n->Referer,&Pin);
1817         n=n->Next;
1818 
1819         if (Top->Referer==&Top->Referer)
1820         {
1821             PostDeleteNode = 1;
1822         }
1823         else
1824         if (Top->Referer==Top)
1825         {
1826             PosDeleteList = 1;
1827         }
1828         else
1829         if (Top->Referer==NULL) // the notification item has been (asked to be) removed
1830         {
1831             MemHeap_Free(Context->NodeHeap,m,sizeof(nodenotify));
1832             // i may have changed
1833             i = Node_GetDataStart(Node,Id,TYPE_NODENOTIFY);
1834         }
1835     }
1836     Top->Referer = NULL;
1837 
1838     if (PostDeleteNode)
1839     {
1840     	LockEnter(Context->NodeLock);
1841         DataFree(Context,Node,i,1);
1842         EraseNode(Context,Node,Class);
1843     	LockLeave(Context->NodeLock);
1844     }
1845     else
1846     if (Id==NODE_DELETING || Top->Next==NULL || PosDeleteList)
1847     {
1848     	LockEnter(Context->NodeLock);
1849         DataFree(Context,Node,i,0); // delete the notify data when it's not to be used anymore(NODE_DELETING) or empty
1850 	    LockLeave(Context->NodeLock);
1851     }
1852     Top->Func = NULL;
1853 }
1854 
Node_Notify(node * Node,dataid Id)1855 bool_t Node_Notify(node* Node,dataid Id)
1856 {
1857     nodedata** i = Node_GetDataStart(Node,Id,TYPE_NODENOTIFY);
1858     if (i && NodeData_Data(*i))
1859     {
1860         Node_NotifyInternal(Node,Id,i,Node_Context(Node));
1861         return 1;
1862     }
1863     return 0;
1864 }
1865 
1866 #if defined(CONFIG_MULTITHREAD)
Node_PostNotify(node * Node,dataid Id)1867 bool_t Node_PostNotify(node* Node,dataid Id)
1868 {
1869     nodedata** i = Node_GetDataStart(Node,Id,TYPE_NODENOTIFY);
1870     if (i && NodeData_Data(*i) && NodeData_Data(*i)->Next) // do not propagate empty events
1871     {
1872         nodecontext* Context = Node_Context(Node);
1873         register uintptr_t CurrentThreadId = ThreadId();
1874 
1875         if (Context->PostNotify && Context->ThreadId != CurrentThreadId) // TODO: what about the other ones in the same thread ?
1876         {
1877             if (Context->PostNotify(Context->PostNotifyParam,Node,Id))
1878                 return 0;
1879             // fallback to the same thread as we don't want to lose any event sending
1880         }
1881         Node_NotifyInternal(Node,Id,i,Context);
1882         return 1;
1883     }
1884     return 0;
1885 }
1886 #endif
1887 
Node_AddNotify(node * Node,dataid Id,notifyproc Func,void * Referer)1888 NOINLINE void Node_AddNotify(node* Node, dataid Id, notifyproc Func, void* Referer)
1889 {
1890     if (Node)
1891     {
1892         nodecontext* p = Node_Context(Node);
1893         nodenotify* n;
1894         nodenotify* Ptr;
1895     	LockEnter(p->NodeLock);
1896 
1897         Ptr = Node_GetData(Node,Id,TYPE_NODENOTIFY);
1898         if (!Ptr)
1899         {
1900             nodenotify Origin = {NULL,NULL,NULL};
1901             Ptr = Node_AddData(Node,Id,TYPE_NODENOTIFY,&Origin);
1902             if (!Ptr)
1903             {
1904                 // Something went wrong ! No more memory ?
1905         	    LockLeave(p->NodeLock);
1906                 return;
1907             }
1908         }
1909 
1910         n = MemHeap_Alloc(p->NodeHeap,sizeof(nodenotify),0);
1911         if (!n)
1912         {
1913         	LockLeave(p->NodeLock);
1914             return;
1915         }
1916 
1917         n->Func = Func;
1918         n->Referer = Referer;
1919         n->Next = Ptr->Next;
1920         Ptr->Next = n;
1921 
1922         LockLeave(p->NodeLock);
1923     }
1924 }
1925 
Node_AddNotify_Update(node * Node,dataid Id,notifyproc Func,void * Refered)1926 void Node_AddNotify_Update(node* Node, dataid Id, notifyproc Func, void* Refered)
1927 {
1928     Node_AddNotify(Node,Id,Func,Refered);
1929     if (Func)
1930     {
1931         nodeevt Pin;
1932         Pin.Node = Node;
1933         Pin.Id = Id;
1934         Func(Refered,&Pin);
1935     }
1936 }
1937 
Node_RemoveNotify(node * Node,dataid Id,notifyproc Func,void * Referer)1938 void Node_RemoveNotify(node* Node, dataid Id, notifyproc Func, void* Referer)
1939 {
1940     if (Node)
1941     {
1942         nodecontext* p = Node_Context(Node);
1943         nodenotify* n;
1944     	LockEnter(p->NodeLock);
1945 
1946         n = Node_GetData(Node,Id,TYPE_NODENOTIFY);
1947         if (n)
1948         {
1949             nodenotify** Ptr;
1950             nodenotify* Top = n;
1951             void *OldReferer = Top->Referer;
1952 
1953             n = Top->Next; // skip the first element which is just there to know if an item of the chain is being notified
1954             Ptr = &n;
1955             for (;(n=*Ptr)!=NULL;Ptr=&n->Next)
1956             {
1957                 if (n->Func==Func && n->Referer==Referer)
1958                 {
1959                     // remove the item from the list
1960                     if (*Ptr == Top->Next)
1961                         Top->Next = n->Next;
1962                     else
1963                         *Ptr = n->Next;
1964 
1965                     if (Top->Referer==n) // this notification item is being called
1966                         Top->Referer = NULL; // tell the notifier that it should remove this element after the call
1967                     else
1968                         MemHeap_Free(p->NodeHeap,n,sizeof(nodenotify));
1969                     break;
1970                 }
1971             }
1972 
1973             if (Top->Next==NULL && OldReferer==Top->Referer)
1974                 Node_RemoveData(Node,Id,TYPE_NODENOTIFY); // the notification list is empty and it's not being called
1975         }
1976     	LockLeave(p->NodeLock);
1977     }
1978 }
1979 
NodeTypeSize(datatype Type)1980 size_t NodeTypeSize(datatype Type)
1981 {
1982 	assert((Type & TYPE_MASK)<MAX_PARAMTYPE);
1983     return ParamSize[Type & TYPE_MASK];
1984 }
1985 
NodeContext_FindDataType(const tchar_t * Type,const tchar_t * Format)1986 dataflags NodeContext_FindDataType(const tchar_t* Type, const tchar_t* Format)
1987 {
1988     dataflags i;
1989     for (i=0;i<MAX_PARAMTYPE;++i)
1990         if (ParamName[i] && tcsisame_ascii(Type,ParamName[i]))
1991         {
1992             if (Format && Format[0])
1993             {
1994                 dataflags j;
1995                 for (j=1;(j<<TUNIT_SHIFT) & TUNIT_MASK;++j)
1996                     if (ParamFormat[j] && tcsisame_ascii(Format,ParamFormat[j]))
1997                     {
1998                         i |= j<<TUNIT_SHIFT;
1999                         break;
2000                     }
2001             }
2002             return i;
2003         }
2004     return 0;
2005 }
2006 
NodeContext_TypeName(datatype Type)2007 const tchar_t *NodeContext_TypeName(datatype Type)
2008 {
2009     Type &= TYPE_MASK;
2010     return ParamName[Type];
2011 }
2012 
NodeContext_UnitName(datatype Unit)2013 const tchar_t *NodeContext_UnitName(datatype Unit)
2014 {
2015     Unit &= TUNIT_MASK;
2016     return ParamFormat[Unit>>TUNIT_SHIFT];
2017 }
2018 
2019 static const tchar_t NullString[] = T("");
2020 
EqData(datatype Type,const void * a,const void * b,size_t Size)2021 static NOINLINE bool_t EqData(datatype Type, const void* a, const void* b, size_t Size)
2022 {
2023     size_t i;
2024 
2025     switch (Type)
2026     {
2027     case TYPE_EXPRSTRING:
2028     case TYPE_EXPRPARAM:
2029     case TYPE_STRING:
2030         if (!a) a = NullString;
2031         if (!b) b = NullString;
2032         return tcscmp(a,b)==0;
2033 
2034     case TYPE_ARRAY:
2035         return ArrayEq(a,b);
2036 
2037     case TYPE_FRACTION:
2038         if (a && b)
2039             return EqFrac((const cc_fraction*)a,(const cc_fraction*)b);
2040         break;
2041     }
2042 
2043     if (!a && !b)
2044         return 1;
2045 
2046     if (a && b)
2047         return memcmp(a,b,Size)==0;
2048 
2049     if (!a)
2050         a = b;
2051 
2052     for (i=0;i<Size;++i)
2053         if (((const uint8_t*)a)[i])
2054             return 0;
2055 
2056     return 1;
2057 }
2058 
Node_EqData(node * p,dataid Id,dataflags Type,const void * a,const void * b)2059 bool_t Node_EqData(node* p, dataid Id, dataflags Type, const void* a, const void* b)
2060 {
2061     if ((Type & TFLAG_MULTI_ENUM) && (Id & DATA_ENUM_MULTI))
2062     {
2063         // b is a dataenumex with all the set values
2064         uint8_t *v;
2065         int *IsSet;
2066         const dataenum *Values = (const dataenum *)b;
2067         for (v=ARRAYBEGIN(Values->Value,uint8_t),IsSet=ARRAYBEGIN(Values->Name,int);v!=ARRAYEND(Values->Value,uint8_t);v+=Values->ValueSize,++IsSet)
2068         {
2069             if (EqData(Type & TYPE_MASK,a,v,Values->ValueSize))
2070                 return (*IsSet!=0);
2071         }
2072         return 0;
2073     }
2074     return EqData(Type & TYPE_MASK,a,b,Node_MaxDataSize(p,Id,Type,META_PARAM_GET));
2075 }
2076 
Node_MaxDataSize(node * p,dataid Id,dataflags Flags,int QueryType)2077 NOINLINE size_t Node_MaxDataSize(node* p, dataid Id, dataflags Flags, int QueryType)
2078 {
2079 	size_t Size;
2080     assert(QueryType==META_PARAM_GET || QueryType==META_PARAM_SET || QueryType==META_PARAM_UNSET);
2081     Flags &= TYPE_MASK;
2082     //assert(Flags != 0);
2083     if (Flags == 0)
2084         return 0;
2085 
2086     if (Id < (DATA_ENUM_MULTI*2)) // a normal ID (instead of a class ID, sometimes)
2087     {
2088         if (Id & DATA_ENUM)
2089         {
2090             if (QueryType==META_PARAM_GET)
2091                 Flags = TYPE_ENUM;
2092             else
2093             if (QueryType==META_PARAM_SET)
2094                 Flags = TYPE_STRING;
2095         }
2096         if (Id & DATA_ENUM_MULTI)
2097         {
2098             if (QueryType==META_PARAM_GET)
2099                 Flags = TYPE_ENUM;
2100             else
2101             if (QueryType==META_PARAM_SET)
2102                 Flags = TYPE_ENUM_MULTI_SET;
2103         }
2104     }
2105 
2106 	assert(Flags < MAX_PARAMTYPE);
2107 	Size = ParamSize[Flags];
2108 	if (Size == MAXDATA && Flags != TYPE_STRING) // we don't care about how much space the non-dynamic string needs (except in MetaSet())
2109 	{
2110 		Size = (size_t)Node_Meta(p,Id,META_PARAM_SIZE);
2111 		if (!Size)
2112 			Size = MAXDATA;
2113 	}
2114 	return Size;
2115 }
2116 
Node_DataSize(node * p,dataid Id,datatype Type,const void * Data,int QueryType)2117 NOINLINE size_t Node_DataSize(node* p, dataid Id, datatype Type, const void* Data, int QueryType)
2118 {
2119     size_t Size;
2120 
2121     assert(QueryType==META_PARAM_GET || QueryType==META_PARAM_SET || QueryType==META_PARAM_UNSET);
2122     if (!Data)
2123         return 0;
2124 
2125     switch (Type)
2126     {
2127     case TYPE_EXPR:
2128         Size = Node_Context(p)->ExprSize((nodeexpr*)Data);
2129         break;
2130 
2131     case TYPE_EXPRSTRING:
2132     case TYPE_EXPRPARAM:
2133     case TYPE_STRING:
2134         Size = tcsbytes((const tchar_t*)Data);
2135         break;
2136 
2137     default:
2138         Size = Node_MaxDataSize(p,Id,Type,QueryType);
2139         break;
2140     }
2141     return Size;
2142 }
2143 
MetaEnumClass(const nodeclass * Class,array * List)2144 static NOINLINE void MetaEnumClass(const nodeclass* Class,array* List)
2145 {
2146     if (Class->ParentClass)
2147         MetaEnumClass(Class->ParentClass,List);
2148 
2149     if (Class->Meta)
2150     {
2151         const nodemeta* m;
2152         for (m=Class->Meta;m->Meta != META_CLASS_PARENT_ID;++m)
2153 		    if (m->Meta == META_PARAM_TYPE)
2154     	    {
2155                 dataid Id = m->Id;
2156                 ArrayAppend(List,&Id,sizeof(Id),256);
2157             }
2158     }
2159 }
2160 
MetaEnum(node * p,array * List)2161 static void MetaEnum(node* p,array* List)
2162 {
2163 	const nodeclass* Class;
2164     ArrayInit(List);
2165     Class = NodeGetClass(p);
2166 	if (Class)
2167         MetaEnumClass(Class,List);
2168 }
2169 
MetaMeta(node * p,dataid Id,datameta Meta)2170 static uintptr_t MetaMeta(node* p,dataid Id,datameta Meta)
2171 {
2172     return NodeParamMeta(NodeGetClass(p),Meta,Id,p);
2173 }
2174 
MetaGet(node * p,dataid Id,void * Data,size_t Size)2175 static err_t MetaGet(node* p,dataid Id,void* Data,size_t Size)
2176 {
2177 	const nodeclass* Class = NodeGetClass(p);
2178     nodemetalookuphead* Head = Class->MetaGet;
2179     if (Head)
2180     {
2181         nodemetalookup* Lookup = (nodemetalookup*)(Head+1);
2182 	    intptr_t Mid;
2183 	    intptr_t Lower = 0;
2184 	    intptr_t Upper = Head->Upper;
2185 
2186 	    while (Upper >= Lower)
2187 	    {
2188 		    Mid = (Upper + Lower) >> 1;
2189 
2190 		    if (Lookup[Mid].Id>Id)
2191 			    Upper = Mid-1;
2192 		    else if (Lookup[Mid].Id<Id)
2193 			    Lower = Mid+1;
2194 		    else
2195 		    {
2196                 const nodemeta* m = Lookup[Mid].Meta;
2197 				const uint8_t* Ptr;
2198 				datatype Type;
2199 
2200                 if (m->Meta == META_PARAM_GET)
2201 					return ((err_t(*)(node*,dataid,void*,size_t))m->Data)(p,Id,Data,Size);
2202 
2203                 if (m->Meta == META_PARAM_BIT)
2204                     m = Lookup[--Mid].Meta;
2205 
2206 			    assert((m->Meta & META_MODE_MASK)==META_MODE_DATA);
2207 
2208 				Type = (m->Meta & TYPE_MASK);
2209                 if ((intptr_t)m->Data<0)
2210                 {
2211                     Ptr = Node_GetData(p,Id,Type);
2212                     if (!Ptr)
2213                     {
2214 #if defined(CONFIG_CORECDOC)
2215                         if (m[2].Meta == META_PARAM_DATA_FLAGS && (m[2].Data & DFLAG_NODEFAULT))
2216 #else
2217                         if (m[1].Meta == META_PARAM_DATA_FLAGS && (m[1].Data & DFLAG_NODEFAULT))
2218 #endif
2219                             return ERR_INVALID_DATA;
2220 
2221                         memset(Data,0,Size);
2222                         return ERR_NONE;
2223                     }
2224                 }
2225                 else
2226                     Ptr = (const uint8_t*)p + (intptr_t)m->Data;
2227 
2228 				if (Type == TYPE_STRING)
2229 					tcscpy_s(Data,Size/sizeof(tchar_t),(const tchar_t*)Ptr);
2230 				else
2231                 if (Type == TYPE_BOOL_BIT)
2232                 {
2233                     uint32_t Bit;
2234                     assert(Lookup[Mid+1].Id == Id && Lookup[Mid+1].Meta->Meta==META_PARAM_BIT);
2235                     Bit = (uint32_t)Lookup[Mid+1].Meta->Data;
2236                     if (Size != sizeof(bool_t))
2237                         return ERR_INVALID_DATA;
2238                     *(bool_t*)Data = (*(const uint32_t*)Ptr & Bit) != 0;
2239                 }
2240                 else
2241 				{
2242 					size_t DataSize = Node_MaxDataSize(p,m->Id,Type,META_PARAM_GET);
2243 					assert(Size == DataSize);
2244 					if (DataSize != Size)
2245 						return ERR_INVALID_DATA;
2246 
2247                     if (DataSize==sizeof(int))
2248                         *(int*)Data = *(const int*)Ptr;
2249                     else
2250     					memcpy(Data,Ptr,DataSize);
2251 				}
2252 
2253 				return ERR_NONE;
2254 		    }
2255 	    }
2256     }
2257 	return ERR_INVALID_PARAM;
2258 }
2259 
MetaSet(node * p,dataid Id,const void * Data,size_t Size)2260 static err_t MetaSet(node* p,dataid Id,const void* Data,size_t Size)
2261 {
2262 	const nodeclass* Class = NodeGetClass(p);
2263     nodemetalookuphead* Head = Class->MetaSet;
2264     if (Head)
2265     {
2266         nodemetalookup* Lookup = (nodemetalookup*)(Head+1);
2267 	    intptr_t Mid;
2268 	    intptr_t Lower = 0;
2269 	    intptr_t Upper = Head->Upper;
2270 
2271 	    while (Upper >= Lower)
2272 	    {
2273 		    Mid = (Upper + Lower) >> 1;
2274 
2275 		    if (Lookup[Mid].Id>Id)
2276 			    Upper = Mid-1;
2277 		    else if (Lookup[Mid].Id<Id)
2278 			    Lower = Mid+1;
2279 		    else
2280 		    {
2281                 err_t Result;
2282                 int DFlags;
2283                 dataflags Type;
2284                 intptr_t MetaData;
2285                 const nodemeta* m = Lookup[Mid].Meta;
2286 
2287 			    if (m->Meta == META_PARAM_SET)
2288 				    return ((err_t(*)(node*,dataid,const void*,size_t))m->Data)(p,Id,Data,Size);
2289 
2290 			    if (m->Meta == META_PARAM_EVENT)
2291 			    {
2292                     while (Mid>0 && Lookup[Mid-1].Id==Id)
2293                         --Mid;
2294                     do
2295                     {
2296                         assert(Lookup[Mid].Meta->Meta==META_PARAM_EVENT);
2297 				        Result = ((nodeupdatefunc)Lookup[Mid].Meta->Data)(p,Id);
2298 				        if (Result != ERR_NONE)
2299 					        return Result;
2300                         ++Mid;
2301                     }
2302                     while (Mid<=(intptr_t)Head->Upper && Lookup[Mid].Id==Id);
2303 
2304                     return ERR_NONE;
2305                 }
2306 
2307                 if (m->Meta == META_PARAM_BIT)
2308                     m = Lookup[--Mid].Meta;
2309 
2310 			    assert((m->Meta & META_MODE_MASK)==META_MODE_DATA); // any variable needs either a SET method, be an event or have related DATA
2311 
2312                 MetaData = m->Data;
2313 				Type = m->Meta;
2314                 DFlags = 0;
2315 
2316 #if defined(CONFIG_CORECDOC)
2317                 if (m[2].Meta == META_PARAM_DATA_FLAGS)
2318 #else
2319                 if (m[1].Meta == META_PARAM_DATA_FLAGS)
2320 #endif
2321                 {
2322                     ++m;
2323 #if defined(CONFIG_CORECDOC)
2324                     ++m;
2325 #endif
2326                     DFlags = (int)m->Data;
2327                     if (DFlags & DFLAG_RDONLY)
2328                         continue;
2329 
2330                     // TODO: pointer should not use DFLAG_CMP because it maybe a recreated different object (unless referencing is used)
2331                     //assert(!(DFlags & DFLAG_CMP) || (Type & TYPE_MASK) != TYPE_NODE);
2332 
2333                     if ((DFlags & DFLAG_VERIFY_CLASS) && ((Type & TYPE_MASK) == TYPE_NODE || (Type & TYPE_MASK) == TYPE_NODE_REF) &&
2334                         Data && Size==sizeof(node*) && *(const node**)Data &&
2335                         !Node_IsPartOf(*(const node**)Data,(fourcc_t)Node_Meta(p,Id,META_PARAM_CLASS)))
2336                         return ERR_INVALID_DATA;
2337                 }
2338 
2339                 if (MetaData < 0)
2340                 {
2341                     // dynamic data
2342                     size_t RealSize = Node_DataSize(p,Id,(Type & TYPE_MASK),Data,META_PARAM_SET);
2343                     if ((Type & TYPE_MASK) != TYPE_STRING && RealSize > Size)
2344                         return ERR_INVALID_DATA;
2345 
2346                     if ((DFlags & DFLAG_CMP) && Node_EqData(p,Id,Type,Data,Node_GetData(p,Id,Type & TYPE_MASK)))
2347                         return ERR_NONE;
2348 
2349                     // we don't support release with dynamic, because object destructor or manually dynamic data manipulation would not trigger it
2350 #if defined(CONFIG_CORECDOC)
2351                     assert(m[2].Meta != META_PARAM_DATA_RELEASE);
2352 #else
2353                     assert(m[1].Meta != META_PARAM_DATA_RELEASE);
2354 #endif
2355 
2356                     Node_SetData(p,Id,Type & TYPE_MASK,Data);
2357                 }
2358                 else
2359                 {
2360                     uint32_t Bit;
2361 					uint8_t* Ptr = (uint8_t*)p + (intptr_t)MetaData;
2362 					size_t DataSize = Node_MaxDataSize(p,Id,Type,META_PARAM_SET);
2363 
2364 					assert((Type & TYPE_MASK) == TYPE_STRING || !Data || Size == DataSize);
2365 					if (Data && Size != DataSize && (Type & TYPE_MASK) != TYPE_STRING)
2366 						return ERR_INVALID_DATA;
2367 
2368                     if (DFlags & DFLAG_CMP)
2369                     {
2370                         if ((Type & TYPE_MASK) == TYPE_BOOL_BIT)
2371                         {
2372                             bool_t v;
2373                             uint32_t Bit;
2374                             assert(Lookup[Mid+1].Id == Id && Lookup[Mid+1].Meta->Meta==META_PARAM_BIT);
2375                             Bit = (uint32_t)Lookup[Mid+1].Meta->Data;
2376                             v = (*(uint32_t*)Ptr & Bit) != 0;
2377                             if (EqData(Type & TYPE_MASK,&v,Data,DataSize))
2378                                 return ERR_NONE;
2379                         }
2380                         else
2381                         {
2382                            if (EqData(Type & TYPE_MASK,Ptr,Data,DataSize))
2383                                 return ERR_NONE;
2384                         }
2385                     }
2386 
2387 #if defined(CONFIG_CORECDOC)
2388                     if (m[2].Meta == META_PARAM_DATA_RELEASE)
2389 #else
2390                     if (m[1].Meta == META_PARAM_DATA_RELEASE)
2391 #endif
2392                     {
2393                         ++m;
2394 #if defined(CONFIG_CORECDOC)
2395                         ++m;
2396 #endif
2397 						((nodeupdatefunc)m->Data)(p,Id);
2398                     }
2399 
2400 					switch (Type & TYPE_MASK)
2401 					{
2402 					case TYPE_STRING:
2403                         DataSize = (size_t)Node_Meta(p,Id,META_PARAM_SIZE);
2404                         assert(DataSize);
2405                         if (!Data)
2406                             Data = NullString;
2407                         tcscpy_s((tchar_t*)Ptr,DataSize/sizeof(tchar_t),(const tchar_t*)Data);
2408 						break;
2409 
2410                     case TYPE_BOOL_BIT:
2411                         assert(Lookup[Mid+1].Id == Id && Lookup[Mid+1].Meta->Meta==META_PARAM_BIT);
2412                         Bit = (uint32_t)Lookup[Mid+1].Meta->Data;
2413                         if (Data && *(const bool_t*)Data)
2414                             *(uint32_t*)Ptr |= Bit;
2415                         else
2416                             *(uint32_t*)Ptr &= ~Bit;
2417                         break;
2418 
2419                     case TYPE_NODE_REF:
2420                     {
2421                         node* v = Data?*(node**)Data:NULL;
2422                         node* v0 = *(node**)Ptr;
2423                         if (v0 != v)
2424                         {
2425                             if (v)
2426                                 Node_AddRef(v);
2427                             *(node**)Ptr = v;
2428                             if (v0)
2429                                 Node_Release(v0);
2430                         }
2431                         break;
2432                     }
2433                     case TYPE_ARRAY:
2434                         ArrayCopy((array*)Ptr,(const array*)Data);
2435                         break;
2436 
2437 					default:
2438 						if (Data)
2439 							memcpy(Ptr,Data,DataSize);
2440                         else
2441 							memset(Ptr,0,DataSize);
2442 						break;
2443 					}
2444                 }
2445 
2446                 Result = ERR_NONE;
2447 
2448 #if defined(CONFIG_CORECDOC)
2449 				if (m[2].Meta == META_PARAM_DATA_UPDATE)
2450 #else
2451 				if (m[1].Meta == META_PARAM_DATA_UPDATE)
2452 #endif
2453                 {
2454                     ++m;
2455 #if defined(CONFIG_CORECDOC)
2456                     ++m;
2457 #endif
2458 					Result = ((nodeupdatefunc)m->Data)(p,Id);
2459                 }
2460 
2461                 if (DFlags & DFLAG_NOTIFY)
2462                     Node_PostNotify(p,Id);
2463 
2464 				return Result;
2465             }
2466 	    }
2467     }
2468 	return ERR_INVALID_PARAM;
2469 }
2470 
MetaUnSet(node * p,dataid Id,const void * Data,size_t Size)2471 static err_t MetaUnSet(node* p,dataid Id,const void* Data,size_t Size)
2472 {
2473 	const nodeclass* Class = NodeGetClass(p);
2474     nodemetalookuphead* Head = Class->MetaUnSet;
2475     if (Head)
2476     {
2477         nodemetalookup* Lookup = (nodemetalookup*)(Head+1);
2478 	    intptr_t Mid;
2479 	    intptr_t Lower = 0;
2480 	    intptr_t Upper = Head->Upper;
2481 
2482 	    while (Upper >= Lower)
2483 	    {
2484 		    Mid = (Upper + Lower) >> 1;
2485 
2486 		    if (Lookup[Mid].Id>Id)
2487 			    Upper = Mid-1;
2488 		    else if (Lookup[Mid].Id<Id)
2489 			    Lower = Mid+1;
2490 		    else
2491 		    {
2492                 err_t Result;
2493                 int DFlags;
2494                 dataflags Type;
2495                 intptr_t MetaData;
2496                 const nodemeta* m = Lookup[Mid].Meta;
2497 
2498 			    if (m->Meta == META_PARAM_UNSET)
2499 				    return ((err_t(*)(node*,dataid,const void*,size_t))m->Data)(p,Id,Data,Size);
2500 
2501 			    if (m->Meta == META_PARAM_EVENT)
2502 			    {
2503                     while (Mid>0 && Lookup[Mid-1].Id==Id)
2504                         --Mid;
2505                     do
2506                     {
2507                         assert(Lookup[Mid].Meta->Meta==META_PARAM_EVENT);
2508 				        Result = ((nodeupdatefunc)Lookup[Mid].Meta->Data)(p,Id);
2509 				        if (Result != ERR_NONE)
2510 					        return Result;
2511                         ++Mid;
2512                     }
2513                     while (Mid<=(intptr_t)Head->Upper && Lookup[Mid].Id==Id);
2514 
2515                     return ERR_NONE;
2516                 }
2517 
2518                 if (m->Meta == META_PARAM_BIT)
2519                     m = Lookup[--Mid].Meta;
2520 
2521 			    assert((m->Meta & META_MODE_MASK)==META_MODE_DATA);
2522 
2523                 MetaData = m->Data;
2524 				Type = m->Meta;
2525                 DFlags = 0;
2526 
2527 #if defined(CONFIG_CORECDOC)
2528                 if (m[2].Meta == META_PARAM_DATA_FLAGS)
2529 #else
2530                 if (m[1].Meta == META_PARAM_DATA_FLAGS)
2531 #endif
2532                 {
2533                     ++m;
2534 #if defined(CONFIG_CORECDOC)
2535                     ++m;
2536 #endif
2537                     DFlags = (int)m->Data;
2538                     if (DFlags & DFLAG_RDONLY)
2539                         continue;
2540 
2541                     // TODO: pointer should not use DFLAG_CMP because it maybe a recreated different object (unless referencing is used)
2542                     //assert(!(DFlags & DFLAG_CMP) || (Type & TYPE_MASK) != TYPE_NODE);
2543 
2544                     if ((DFlags & DFLAG_VERIFY_CLASS) && ((Type & TYPE_MASK) == TYPE_NODE || (Type & TYPE_MASK) == TYPE_NODE_REF) &&
2545                         Data && Size==sizeof(node*) && *(const node**)Data &&
2546                         !Node_IsPartOf(*(const node**)Data,(fourcc_t)Node_Meta(p,Id,META_PARAM_CLASS)))
2547                         return ERR_INVALID_DATA;
2548                 }
2549 
2550                 if (MetaData < 0)
2551                 {
2552                     size_t RealSize = Node_DataSize(p,Id,Type,Data,META_PARAM_UNSET);
2553                     if ((Type & TYPE_MASK) != TYPE_STRING && RealSize > Size)
2554                         return ERR_INVALID_DATA;
2555 
2556                     if ((DFlags & DFLAG_CMP) && Node_EqData(p,Id,Type,Data,Node_GetData(p,Id,Type & TYPE_MASK)))
2557                         return ERR_NONE;
2558 
2559                     // we don't support release with dynamic, because object destructor or manually dynamic data manipulation would not trigger it
2560 #if defined(CONFIG_CORECDOC)
2561                     assert(m[2].Meta != META_PARAM_DATA_RELEASE);
2562 #else
2563                     assert(m[1].Meta != META_PARAM_DATA_RELEASE);
2564 #endif
2565 
2566                     Node_SetData(p,Id,Type & TYPE_MASK,Data);
2567                 }
2568                 else
2569                 {
2570                     uint32_t Bit;
2571 					uint8_t* Ptr = (uint8_t*)p + (intptr_t)MetaData;
2572 					size_t DataSize = Node_MaxDataSize(p,Id,Type,META_PARAM_UNSET);
2573 
2574 					assert((Type & TYPE_MASK) == TYPE_STRING || !Data || Size == DataSize);
2575 					if (Data && Size != DataSize && (Type & TYPE_MASK) != TYPE_STRING)
2576 						return ERR_INVALID_DATA;
2577 
2578                     if (DFlags & DFLAG_CMP)
2579                     {
2580                         if ((Type & TYPE_MASK) == TYPE_BOOL_BIT)
2581                         {
2582                             bool_t v;
2583                             uint32_t Bit;
2584                             assert(Lookup[Mid+1].Id == Id && Lookup[Mid+1].Meta->Meta==META_PARAM_BIT);
2585                             Bit = (uint32_t)Lookup[Mid+1].Meta->Data;
2586                             v = (*(uint32_t*)Ptr & Bit) != 0;
2587                             if (EqData(Type & TYPE_MASK,&v,Data,DataSize))
2588                                 return ERR_NONE;
2589                         }
2590                         else
2591                         {
2592                            if (EqData(Type & TYPE_MASK,Ptr,Data,DataSize))
2593                                 return ERR_NONE;
2594                         }
2595                     }
2596 
2597 #if defined(CONFIG_CORECDOC)
2598                     if (m[2].Meta == META_PARAM_DATA_RELEASE)
2599 #else
2600                     if (m[1].Meta == META_PARAM_DATA_RELEASE)
2601 #endif
2602                     {
2603                         ++m;
2604 #if defined(CONFIG_CORECDOC)
2605                         ++m;
2606 #endif
2607 						((nodeupdatefunc)m->Data)(p,Id);
2608                     }
2609 
2610 					switch (Type & TYPE_MASK)
2611 					{
2612 					case TYPE_STRING:
2613                         DataSize = (size_t)Node_Meta(p,Id,META_PARAM_SIZE);
2614                         assert(DataSize);
2615                         if (!Data)
2616                             Data = NullString;
2617                         tcscpy_s((tchar_t*)Ptr,DataSize/sizeof(tchar_t),(const tchar_t*)Data);
2618 						break;
2619 
2620                     case TYPE_BOOL_BIT:
2621                         assert(Lookup[Mid+1].Id == Id && Lookup[Mid+1].Meta->Meta==META_PARAM_BIT);
2622                         Bit = (uint32_t)Lookup[Mid+1].Meta->Data;
2623                         if (Data && *(const bool_t*)Data)
2624                             *(uint32_t*)Ptr |= Bit;
2625                         else
2626                             *(uint32_t*)Ptr &= ~Bit;
2627                         break;
2628 
2629                     case TYPE_NODE_REF:
2630                     {
2631                         node* v = Data?*(node**)Data:NULL;
2632                         node* v0 = *(node**)Ptr;
2633                         if (v0 != v)
2634                         {
2635                             if (v)
2636                                 Node_AddRef(v);
2637                             *(node**)Ptr = v;
2638                             if (v0)
2639                                 Node_Release(v0);
2640                         }
2641                         break;
2642                     }
2643                     case TYPE_ARRAY:
2644                         ArrayCopy((array*)Ptr,(const array*)Data);
2645                         break;
2646 
2647 					default:
2648 						if (Data)
2649 							memcpy(Ptr,Data,DataSize);
2650                         else
2651 							memset(Ptr,0,DataSize);
2652 						break;
2653 					}
2654                 }
2655 
2656                 Result = ERR_NONE;
2657 
2658 #if defined(CONFIG_CORECDOC)
2659 				if (m[2].Meta == META_PARAM_DATA_UPDATE)
2660 #else
2661 				if (m[1].Meta == META_PARAM_DATA_UPDATE)
2662 #endif
2663                 {
2664                     ++m;
2665 #if defined(CONFIG_CORECDOC)
2666                     ++m;
2667 #endif
2668 					Result = ((nodeupdatefunc)m->Data)(p,Id);
2669                 }
2670 
2671                 if (DFlags & DFLAG_NOTIFY)
2672                     Node_PostNotify(p,Id);
2673 
2674 				return Result;
2675             }
2676 	    }
2677     }
2678 	return ERR_INVALID_PARAM;
2679 }
2680 
MetaFindParam(node * p,const tchar_t * Token)2681 static dataid MetaFindParam(node* p,const tchar_t* Token)
2682 {
2683     if (Token)
2684     {
2685         const nodeclass* c;
2686         const nodemeta* m;
2687 
2688         for (c = NodeGetClass(p);c;c=c->ParentClass)
2689 	        if (c->Meta) // should be registered, just fail safe
2690 		        for (m=c->Meta;m->Meta != META_CLASS_PARENT_ID;++m)
2691 			        if (m->Meta == META_PARAM_NAME && tcsisame_ascii(Token,(const tchar_t*)m->Data))
2692                     {
2693                         return m->Id;
2694                     }
2695     }
2696     return 0;
2697 }
2698 
META_START(Node_Class,NODE_CLASS)2699 META_START(Node_Class,NODE_CLASS)
2700 META_CLASS(SIZE,sizeof(node))
2701 META_VMT(TYPE_FUNC,node_vmt,Enum,MetaEnum)
2702 META_VMT(TYPE_FUNC,node_vmt,Get,MetaGet)
2703 META_VMT(TYPE_FUNC,node_vmt,Set,MetaSet)
2704 META_VMT(TYPE_FUNC,node_vmt,UnSet,MetaUnSet)
2705 META_VMT(TYPE_FUNC,node_vmt,Meta,MetaMeta)
2706 META_VMT(TYPE_FUNC,node_vmt,FindParam,MetaFindParam)
2707 META_VMT(TYPE_FUNC,node_vmt,SetData,SetData)
2708 META_PARAM(TYPE,NODE_DELETING,TYPE_EVENT|TFLAG_NOTIFY|TFLAG_RDONLY)
2709 META_END_CONTINUE(0)
2710 
2711 META_START_CONTINUE(NODEMODULE_CLASS)
2712 META_CLASS(SIZE,sizeof(nodemodule))
2713 META_END_CONTINUE(NODE_CLASS)
2714 
2715 META_START_CONTINUE(NODECONTEXT_CLASS)
2716 META_CLASS(SIZE,sizeof(nodecontext))
2717 META_PARAM(NAME,NODECONTEXT_PROJECT_NAME,T("ProjName"))
2718 META_PARAM(TYPE,NODECONTEXT_PROJECT_NAME,TYPE_STRING|TFLAG_SETUP|TFLAG_RDONLY)
2719 META_DYNAMIC_RDONLY(TYPE_STRING,NODECONTEXT_PROJECT_NAME)
2720 
2721 META_PARAM(NAME,NODECONTEXT_PROJECT_VENDOR,T("ProjVendor"))
2722 META_PARAM(TYPE,NODECONTEXT_PROJECT_VENDOR,TYPE_STRING|TFLAG_SETUP|TFLAG_RDONLY)
2723 META_DYNAMIC_RDONLY(TYPE_STRING,NODECONTEXT_PROJECT_VENDOR)
2724 
2725 META_PARAM(NAME,NODECONTEXT_PROJECT_VERSION,T("ProjVersion"))
2726 META_PARAM(TYPE,NODECONTEXT_PROJECT_VERSION,TYPE_STRING|TFLAG_SETUP|TFLAG_RDONLY)
2727 META_DYNAMIC_RDONLY(TYPE_STRING,NODECONTEXT_PROJECT_VERSION)
2728 
2729 META_PARAM(NAME,NODECONTEXT_PROJECT_HELP,T("HelpFile"))
2730 META_PARAM(TYPE,NODECONTEXT_PROJECT_HELP,TYPE_STRING|TFLAG_SETUP|TFLAG_RDONLY)
2731 META_DYNAMIC_RDONLY(TYPE_STRING,NODECONTEXT_PROJECT_HELP)
2732 
2733 #if defined(TARGET_PALMOS)
2734 META_PARAM(NAME,NODECONTEXT_PROJECT_FOURCC,T("ProjFourCC"))
2735 META_PARAM(TYPE,NODECONTEXT_PROJECT_FOURCC,TYPE_FOURCC|TFLAG_SETUP|TFLAG_RDONLY)
2736 META_DATA(TYPE_FOURCC,NODECONTEXT_PROJECT_FOURCC,nodecontext,ProjFourCC)
2737 #endif
2738 
2739 META_PARAM(NAME,NODECONTEXT_PROJECT_BUILD,T("BuildVersion"))
2740 META_PARAM(TYPE,NODECONTEXT_PROJECT_BUILD,TYPE_INT|TFLAG_SETUP|TFLAG_RDONLY)
2741 META_DATA(TYPE_INT,NODECONTEXT_PROJECT_BUILD,nodecontext,Build)
2742 
2743 META_PARAM(NAME,NODECONTEXT_PROJECT_MIME,T("AppMime"))
2744 META_PARAM(TYPE,NODECONTEXT_PROJECT_MIME,TYPE_STRING|TFLAG_SETUP|TFLAG_RDONLY)
2745 META_DYNAMIC_RDONLY(TYPE_STRING,NODECONTEXT_PROJECT_MIME)
2746 
2747 META_PARAM(NAME,NODECONTEXT_PROJECT_PATH,T("ProjPath"))
2748 META_PARAM(TYPE,NODECONTEXT_PROJECT_PATH,TYPE_STRING|TFLAG_SETUP|TFLAG_RDONLY)
2749 META_DYNAMIC_RDONLY(TYPE_STRING,NODECONTEXT_PROJECT_PATH)
2750 
2751 META_PARAM(TYPE,NODECONTEXT_PROJECT_APPID,TYPE_INT16|TFLAG_SETUP|TFLAG_RDONLY)
2752 META_DATA(TYPE_INT16,NODECONTEXT_PROJECT_APPID,nodecontext,AppId)
2753 META_END(NODEMODULE_CLASS)
2754 
2755 MEMHEAP_DEFAULT
2756 
2757 void NodeContext_Init(nodecontext* p,const nodemeta* Custom, const cc_memheap* Heap, const cc_memheap* ConstHeap)
2758 {
2759     fourcc_t ClassId = NODECONTEXT_CLASS;
2760     node_vmt Tmp;
2761 
2762     memset(p,0,sizeof(nodecontext));
2763 
2764     if (Heap)
2765     {
2766         ArrayInitEx(&p->Collect,Heap);
2767         ArrayInitEx(&p->NodeSingleton,Heap);
2768         ArrayInitEx(&p->NodeClass,Heap);
2769     }
2770     else
2771         Heap = &MemHeap_Default;
2772 
2773     if (!ConstHeap)
2774         ConstHeap=Heap;
2775 
2776 #if defined(CONFIG_MULTITHREAD)
2777     p->PostNotifyParam = p;
2778 #endif
2779 	p->NodeLock = LockCreate();
2780     p->NodeHeap = Heap;
2781     p->NodeConstHeap = ConstHeap;
2782 
2783     Tmp.Context = p;
2784     p->Base.Base.VMT = &Tmp;
2785     p->Base.Found = 1;
2786     p->Base.Func = (void*)(uintptr_t)NodeContext_Init;
2787 
2788 	NodeRegisterClassEx(&p->Base,Node_Class);
2789     NodeRegisterClassEx(&p->Base,NodeTree_Class);
2790 
2791     if (Custom)
2792     {
2793         NodeRegisterClassEx(&p->Base,Custom);
2794         ClassId = (fourcc_t)Custom->Data;
2795     }
2796 
2797     Node_Constructor(p,(node*)p,0,ClassId);
2798 }
2799 
NodeContext_Done(nodecontext * p)2800 void NodeContext_Done(nodecontext* p)
2801 {
2802 	nodeclass **i;
2803 
2804     NodeSingletonEvent(p,NODE_SINGLETON_SHUTDOWN,NULL);
2805 
2806 	NodeContext_Cleanup(p,1); // first unregister all plugins
2807 
2808 	UnRegisterModule(p,&p->Base,1); // unregister common.dll classes
2809 
2810     // free modules
2811     while (p->Base.Next)
2812     {
2813         node* v = (node*)p->Base.Next;
2814         p->Base.Next = p->Base.Next->Next;
2815 		Node_Release(v);
2816     }
2817 
2818     Node_Destructor((node*)p);
2819 
2820 #if defined(CONFIG_DEBUG_LEAKS)
2821     if (p->Base.Base.RefCount!=1)
2822     {
2823         class_ref_t *Item;
2824         for (Item=ARRAYBEGIN(p->Base.ClassRefs,class_ref_t);Item!=ARRAYEND(p->Base.ClassRefs,class_ref_t);++Item)
2825         {
2826             DebugMessage(T("remaining class %r (%d times)"),Item->Class->FourCC,Item->Count);
2827         }
2828     }
2829 #endif
2830     assert(p->Base.Base.RefCount==1); // node memory leaking?
2831 
2832     // free classes
2833 	for (i=ARRAYBEGIN(p->NodeClass,nodeclass*);i!=ARRAYEND(p->NodeClass,nodeclass*);++i)
2834 	{
2835 		assert(!(*i)->Meta && !(*i)->MetaGet && !(*i)->MetaSet && !(*i)->MetaUnSet);
2836 		MemHeap_Free(p->NodeHeap,*i,sizeof(nodeclass)+(*i)->VMTSize);
2837 	}
2838 
2839     assert(ARRAYEMPTY(p->Collect));
2840 	ArrayClear(&p->Collect);
2841 	ArrayClear(&p->NodeSingleton);
2842 	ArrayClear(&p->NodeClass);
2843 	LockDelete(p->NodeLock);
2844 	p->NodeLock = NULL;
2845 }
2846 
NodeEnumDef(node * p,array * List)2847 void NodeEnumDef(node* p,array* List)
2848 {
2849     ArrayInit(List);
2850     if (p)
2851     {
2852         dataid* i;
2853         datadef Def;
2854         array Id;
2855 
2856         Node_Enum(p,&Id);
2857 
2858         for (i=ARRAYBEGIN(Id,dataid);i!=ARRAYEND(Id,dataid);++i)
2859             if (NodeDataDef(p,*i,&Def))
2860                 ArrayAppend(List,&Def,sizeof(Def),256);
2861 
2862         ArrayClear(&Id);
2863     }
2864 }
2865 
NodeDataDef(node * p,dataid Id,datadef * DataDef)2866 bool_t NodeDataDef(node* p, dataid Id, datadef* DataDef)
2867 {
2868     uintptr_t Flags = Node_Meta(p,Id,META_PARAM_TYPE);
2869     if (!Flags)
2870         return 0;
2871     //assert((Flags & TYPE_MASK)!=0);
2872 
2873     DataDef->Id = Id;
2874     DataDef->Flags = (dataflags)Flags;
2875     return 1;
2876 }
2877 
Node_Toggle(void * Node,dataid Id)2878 err_t Node_Toggle(void* Node,dataid Id)
2879 {
2880     bool_t Bool = 0;
2881     Node_GET(Node,Id,&Bool);
2882     Bool = !Bool;
2883     return Node_SET(Node,Id,&Bool);
2884 }
2885 
NodeDup_Replace(array * Dup,node ** Ptr)2886 NOINLINE void NodeDup_Replace(array* Dup, node** Ptr)
2887 {
2888     if (Dup)
2889     {
2890         node* p = *Ptr;
2891         nodedup* i;
2892         for (i=ARRAYBEGIN(*Dup,nodedup);i!=ARRAYEND(*Dup,nodedup);++i)
2893             if (i->Orig == p)
2894             {
2895                 *Ptr = i->Dup;
2896                 return;
2897             }
2898     }
2899 }
2900 
CopyData(const nodeclass * Class,node * p,node * Src,array * Dup,uint8_t * Data)2901 static NOINLINE void CopyData(const nodeclass* Class, node* p, node* Src, array* Dup,  uint8_t* Data)
2902 {
2903     if (Class->ParentClass)
2904         CopyData(Class->ParentClass,p,Src,Dup,Data);
2905 
2906     if (Class->Meta)
2907     {
2908         const nodemeta* m;
2909         for (m=Class->Meta;m->Meta != META_CLASS_PARENT_ID;++m)
2910         {
2911             uintptr_t Type;
2912 			if (m->Meta == META_PARAM_TYPE)
2913                 Type = m->Data;
2914             else
2915             if (m->Meta != META_PARAM_META || !((bool_t(*)(node*,dataid,datameta,uintptr_t*))m->Data)(Src,m->Id,META_PARAM_TYPE,&Type)) // we need to use the Src because dynamic flags (like UIButton_Value)
2916                 continue;
2917 
2918             if (!(Type & (TFLAG_RDONLY|TFLAG_NOSAVE)) && (Type & TYPE_MASK))
2919 			{
2920                 dataid Id = m->Id;
2921                 Type &= TYPE_MASK;
2922                 if (Type != TYPE_EXPR) // batch expressions are already copied
2923                 {
2924                     size_t Size = Node_MaxDataSize(Src,Id,Type,META_PARAM_GET);
2925                     assert((Id & ~DATA_ENUM)==Id);
2926                     if (Size && Node_Get(Src,Id,Data,Size) == ERR_NONE)
2927                     {
2928                         if (Type == TYPE_PIN)
2929                             NodeDup_Replace(Dup,&((pin*)Data)->Node);
2930 
2931                         if (Type == TYPE_NODE)
2932                             NodeDup_Replace(Dup,(node**)Data);
2933 
2934                         Node_Set(p,Id,Data,Size);
2935                     }
2936                 }
2937             }
2938         }
2939     }
2940 }
2941 
Node_Copy(node * p,node * Src,array * Dup)2942 void Node_Copy(node* p, node* Src, array* Dup)
2943 {
2944     nodedata* i;
2945 	const nodeclass* Class = NodeGetClass(p);
2946     uint8_t Data[MAXDATA];
2947 
2948     // at moment only same ClassId will be copied
2949     if (Class != NodeGetClass(Src))
2950         return;
2951 
2952     for (i=Src->Data;i;i=i->Next)
2953     {
2954         datatype Type = i->Code & TYPE_MASK;
2955         if (Type == TYPE_EXPRSTRING || Type == TYPE_EXPRPARAM || Type == TYPE_EXPR)
2956         {
2957             void* Data = Node_AddData(p,i->Code>>8,Type,NodeData_Data(i));
2958             if (Type == TYPE_EXPR && Data)
2959                 NodeClass_Context(Class)->ExprDup(p,(nodeexpr*)Data,Dup);
2960         }
2961     }
2962 
2963     CopyData(Class,p,Src,Dup,Data);
2964 }
2965 
Node_InheritedVMT(node * p,fourcc_t ClassId)2966 const void* Node_InheritedVMT(node* p,fourcc_t ClassId)
2967 {
2968     const nodeclass* Class = NodeGetClass(p);
2969     while (NodeClass_ClassId(Class) != ClassId)
2970     {
2971         assert(Class->ParentClass);
2972         Class=Class->ParentClass;
2973     }
2974     assert(Class->ParentClass);
2975     return Class->ParentClass+1;
2976 }
2977 
NodeReportError(anynode * AnyNode,node * Sender,fourcc_t Class,int No,...)2978 void NodeReportError(anynode* AnyNode, node* Sender, fourcc_t Class, int No,...)
2979 {
2980     nodecontext* Context = Node_Context(AnyNode);
2981 	if (Context->ReportError)
2982 	{
2983 	    va_list Args;
2984 	    va_start(Args,No);
2985 		Context->ReportError(Context,Sender,Class,No,Args);
2986 		va_end(Args);
2987     }
2988 }
2989 
NodeSingletonEvent(anynode * Any,dataid Cmd,nodemodule * Module)2990 void NodeSingletonEvent(anynode* Any, dataid Cmd, nodemodule* Module)
2991 {
2992     array List;
2993     node** i;
2994 
2995     NodeEnumSingletonsEx(Any,&List,Module);
2996 
2997     for (i=ARRAYBEGIN(List,node*);i!=ARRAYEND(List,node*);++i)
2998         Node_Trigger(*i,Cmd);
2999 
3000     ArrayClear(&List);
3001 }
3002 
NodeHeap_Alloc(anynode * AnyNode,size_t Size)3003 void* NodeHeap_Alloc(anynode* AnyNode, size_t Size)
3004 {
3005     return MemHeap_Alloc(Node_Context(AnyNode)->NodeHeap,Size,0);
3006 }
3007 
NodeHeap_Free(anynode * AnyNode,void * Ptr,size_t Size)3008 void NodeHeap_Free(anynode* AnyNode, void* Ptr, size_t Size)
3009 {
3010     MemHeap_Free(Node_Context(AnyNode)->NodeHeap,Ptr,Size);
3011 }
3012 
3013 typedef struct memcollectitem
3014 {
3015     memcollect Func;
3016     void* Cookie;
3017 
3018 } memcollectitem;
3019 
NodeHibernate(anynode * AnyNode)3020 bool_t NodeHibernate(anynode* AnyNode)
3021 {
3022     nodecontext* p = Node_Context(AnyNode);
3023 	bool_t Changed = 0;
3024 
3025 	if (!p->InCollect)
3026 	{
3027         int Level;
3028         int NextLevel;
3029         memcollectitem* i;
3030 		p->InCollect = 1;
3031 
3032         for (Level=COLLECT_UNUSED;!Changed;Level=NextLevel)
3033         {
3034             NextLevel = INT_MAX;
3035             for (i=ARRAYBEGIN(p->Collect,memcollectitem);i!=ARRAYEND(p->Collect,memcollectitem);++i)
3036             {
3037                 int v=i->Func(i->Cookie,Level);
3038                 if (v==COLLECT_FOUND)
3039                     Changed=1;
3040                 else
3041                 if (NextLevel>v && v>Level)
3042                     NextLevel=v;
3043             }
3044             if (NextLevel==INT_MAX)
3045                 break;
3046         }
3047 
3048 		if (!Changed && NodeContext_Cleanup(p,0))
3049 			Changed = 1;
3050 
3051 		p->InCollect = 0;
3052 	}
3053 
3054 	return Changed;
3055 }
3056 
Mem_AddCollector(anynode * AnyNode,memcollect Func,void * Cookie)3057 void Mem_AddCollector(anynode* AnyNode, memcollect Func, void* Cookie)
3058 {
3059     memcollectitem Item;
3060     Item.Func = Func;
3061     Item.Cookie = Cookie;
3062     ArrayAppend(&Node_Context(AnyNode)->Collect,&Item,sizeof(Item),0);
3063 }
3064 
Mem_RemoveCollector(anynode * AnyNode,memcollect Func,void * Cookie)3065 void Mem_RemoveCollector(anynode* AnyNode, memcollect Func, void* Cookie)
3066 {
3067     memcollectitem Item;
3068     Item.Func = Func;
3069     Item.Cookie = Cookie;
3070     ArrayRemove(&Node_Context(AnyNode)->Collect,memcollectitem,&Item,NULL,NULL);
3071 }
3072