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