/***************************************************************************** * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: node.c 585 2006-01-16 09:48:55Z picard $ * * The Core Pocket Media Player * Copyright (c) 2004-2005 Gabor Kovacs * ****************************************************************************/ #include "common.h" #define MODULE_PATH FOURCC('M','P','A','T') #define PLUGIN_KEEPALIVE 3*60 typedef struct nodeclass { nodedef Def; bool_t Registered; int ModuleNo; struct nodeclass* Parent; } nodeclass; typedef struct nodemodule { int Id; int ObjectCount; bool_t Tmp; int64_t Date; int KeepAlive; void* Module; void* Db; void* Func; uint8_t* Min; uint8_t* Max; } nodemodule; static NOINLINE void FreeModule(nodemodule* p) { NodeFreeModule(p->Module,p->Db); p->Module = NULL; p->Db = NULL; p->Func = NULL; p->Min = NULL; } void NodeAddModule(const tchar_t* Path,int Id,int64_t Date,bool_t Load,bool_t Tmp) { context* p = Context(); LockEnter(p->NodeLock); if (ArrayAppend(&p->NodeModule,NULL,sizeof(nodemodule),256)) { int No = ARRAYCOUNT(p->NodeModule,nodemodule)-1; nodemodule* Module = ARRAYBEGIN(p->NodeModule,nodemodule)+No; memset(Module,0,sizeof(nodemodule)); Module->Id = Id; Module->Date = Date; Module->Tmp = Tmp; StringAdd(1,MODULE_PATH,No,Path); if (Load) { p->LoadModuleNo = No; Module->Module = NodeLoadModule(Path,&Module->Id,&Module->Func,&Module->Db); p->LoadModuleNo = 0; #ifdef PLUGINCLEANUP FreeModule(Module); #endif } } LockLeave(p->NodeLock); } static NOINLINE bool_t TmpModule(context* p,int No) { return ARRAYBEGIN(p->NodeModule,nodemodule)[No].Tmp; } static NOINLINE int FindModule(context* p,const tchar_t* Path,int Id) { // important to find from the begining for Palm OS // so the exising plugins are found first int No,Count; int Result = -1; LockEnter(p->NodeLock); Count = ARRAYCOUNT(p->NodeModule,nodemodule); if (!Path) Path = T(""); for (No=0;NoNodeModule,nodemodule)[No].Id == Id; bool_t SameName = tcsicmp(Path,LangStrDef(MODULE_PATH,No))==0; if (SameId && Id!=0) // same Id means same module SameName = 1; if (SameName && !Id) SameId = 1; if (SameId && SameName) { Result = No; break; } } LockLeave(p->NodeLock); return Result; } int NodeGetClassCount() { return ARRAYCOUNT(Context()->NodeClass,nodeclass*); } const nodedef* NodeGetClass(int No,int* Module) { nodeclass* i = ARRAYBEGIN(Context()->NodeClass,nodeclass*)[No]; if (Module) *Module = i->ModuleNo; return &i->Def; } int NodeGetModuleCount() { return ARRAYCOUNT(Context()->NodeModule,nodemodule); } const tchar_t* NodeGetModule(int No,int* Id,int64_t* Date) { *Id = ARRAYBEGIN(Context()->NodeModule,nodemodule)[No].Id; *Date = ARRAYBEGIN(Context()->NodeModule,nodemodule)[No].Date; return LangStrDef(MODULE_PATH,No); } bool_t NodeFindModule(const tchar_t* Path,int Id) { return FindModule(Context(),Path,Id)>0; } static int CmpClass(const nodeclass* const* a, const nodeclass* const* b) { int AClass = (*a)->Def.Class; int BClass = (*b)->Def.Class; if (AClass > BClass) return 1; if (AClass < BClass) return -1; return 0; } static int CmpClassPri(const nodeclass* const* a, const nodeclass* const* b) { int APriority = (*a)->Def.Priority; int BPriority = (*b)->Def.Priority; if (APriority > BPriority) return -1; if (APriority < BPriority) return 1; return CmpClass(a,b); } static NOINLINE nodeclass* FindClass(context* p,int Class) { int Pos; bool_t Found; nodeclass Item; nodeclass* Ptr = &Item; LockEnter(p->NodeLock); Item.Def.Class = Class; Pos = ArrayFind(&p->NodeClass,ARRAYCOUNT(p->NodeClass,nodeclass*), sizeof(nodeclass*),&Ptr,(arraycmp)CmpClass,&Found); if (Found) Ptr = ARRAYBEGIN(p->NodeClass,nodeclass*)[Pos]; else Ptr = NULL; LockLeave(p->NodeLock); return Ptr; } static int CmpNodePri(const node* const* a,const node* const* b) { context* p = Context(); const nodeclass* ca = FindClass(p,(*a)->Class); const nodeclass* cb = FindClass(p,(*b)->Class); return CmpClassPri(&ca,&cb); } static NOINLINE int ReleaseModules(context* p,bool_t Force) { int n=0; int Time = Force ? MAX_INT:GetTimeTick(); nodemodule* j; LockEnter(p->NodeLock); for (j=ARRAYBEGIN(p->NodeModule,nodemodule);j!=ARRAYEND(p->NodeModule,nodemodule);++j) if (j->ObjectCount==0 && j->Module && j->KeepAlive < Time) { //DEBUG_MSG1(-1,T("FreeModule %s"),LangStrDef(MODULE_PATH,j-ARRAYBEGIN(p->NodeModule,nodemodule))); FreeModule(j); ++n; } LockLeave(p->NodeLock); return n; } static NOINLINE void UnlockModule(context* p,int No) { nodemodule* Module = ARRAYBEGIN(p->NodeModule,nodemodule)+No; if (--Module->ObjectCount==0 && Module->Module) { #ifdef PLUGINCLEANUP Module->KeepAlive = GetTimeTick() + GetTimeFreq()*PLUGIN_KEEPALIVE; ReleaseModules(p,0); #endif } } static NOINLINE void CallDelete(context* p,node* Node,nodeclass* Class0,bool_t Global) { nodeclass* Class; for (Class=Class0;Class;Class=Class->Parent) if (Class->Def.Delete) Class->Def.Delete(Node); if (!Global) for (Class=Class0;Class;Class=Class->Parent) UnlockModule(p,Class->ModuleNo); } static NOINLINE nodemodule* LoadModule(context* p,int No) { nodemodule* Module = ARRAYBEGIN(p->NodeModule,nodemodule)+No; if (!Module->Module && No>0 && p->LoadModuleNo!=No) { //DEBUG_MSG1(-1,T("LoadModule %s"),LangStrDef(MODULE_PATH,No)); p->LoadModuleNo = No; Module->Module = NodeLoadModule(LangStrDef(MODULE_PATH,No),&Module->Id,&Module->Func,&Module->Db); p->LoadModuleNo = 0; if (!Module->Module) return NULL; } return Module; } static int CallCreate(context* p,node* Node,nodeclass* Class,bool_t Global) { if (Class) { nodemodule* Module = LoadModule(p,Class->ModuleNo); if (!Module) return ERR_NOT_SUPPORTED; if (Class->Def.ParentClass && !Class->Parent) return ERR_NOT_SUPPORTED; if (CallCreate(p,Node,Class->Parent,Global)!=ERR_NONE) return ERR_NOT_SUPPORTED; if (!Class->Registered || (Class->Def.Create && Class->Def.Create(Node) != ERR_NONE)) { CallDelete(p,Node,Class->Parent,Global); return ERR_NOT_SUPPORTED; } if (!Global) Module->ObjectCount++; } return ERR_NONE; } static void Delete(context* p,node** i) { node* Node = *i; nodeclass* Item = FindClass(p,Node->Class); *i = NULL; if (Item) CallDelete(p,Node,Item,(Item->Def.Flags & CF_GLOBAL)!=0); free(Node); } static void Register(context* p,const nodedef* Def,bool_t Registered,int ModuleNo) { nodeclass* Class; LockEnter(p->NodeLock); Class = FindClass(p,Def->Class); if (!Class) { nodeclass **c; Class = (nodeclass*) malloc(sizeof(nodeclass)); if (!Class) { LockLeave(p->NodeLock); return; } Class->Def.Class = Def->Class; Class->Def.ParentClass = 0; Class->Registered = 0; Class->ModuleNo = 0; Class->Def.Flags = 0; Class->Def.Priority = -1; if (!ArrayAdd(&p->NodeClass,ARRAYCOUNT(p->NodeClass,nodeclass*), sizeof(nodeclass*),&Class,(arraycmp)CmpClass,128)) { free(Class); LockLeave(p->NodeLock); return; } // fix possible child classes for (c=ARRAYBEGIN(p->NodeClass,nodeclass*);c!=ARRAYEND(p->NodeClass,nodeclass*);++c) if ((*c)->Def.ParentClass == Def->Class) (*c)->Parent = Class; } else if (!Registered) { LockLeave(p->NodeLock); return; } if (Registered) { if (Class->Def.Priority > Def->Priority && Class->ModuleNo != ModuleNo) { LockLeave(p->NodeLock); return; // already exits with higher priority in another module } #ifndef REGISTRY_GLOBAL if (ModuleNo>0 && (Class->ModuleNo != ModuleNo || Class->Def.ParentClass != Def->ParentClass || Class->Def.Flags != Def->Flags)) { // save settings to registry for new classes NodeRegSaveString(Def->Class,NODE_NAME); NodeRegSaveString(Def->Class,NODE_CONTENTTYPE); NodeRegSaveString(Def->Class,NODE_EXTS); NodeRegSaveString(Def->Class,NODE_PROBE); NodeRegSaveValue(Def->Class,NODE_MODULE_PATH,LangStrDef(MODULE_PATH,ModuleNo),MAXPATH,TYPE_STRING); NodeRegSaveValue(Def->Class,NODE_PARENT,&Def->ParentClass,sizeof(int),TYPE_INT); NodeRegSaveValue(Def->Class,NODE_FLAGS,&Def->Flags,sizeof(int),TYPE_INT); } #endif } if (Class->Def.Priority != Def->Priority) { ArrayRemove(&p->NodeClassPri,ARRAYCOUNT(p->NodeClassPri,nodeclass*), sizeof(nodeclass*),&Class,(arraycmp)CmpClassPri); Class->Def.Priority = Def->Priority; ArrayAdd(&p->NodeClassPri,ARRAYCOUNT(p->NodeClassPri,nodeclass*), sizeof(nodeclass*),&Class,(arraycmp)CmpClassPri,128); #ifndef REGISTRY_GLOBAL if (ModuleNo>0 && Registered) NodeRegSaveValue(Def->Class,NODE_PRIORITY,Def->Priority!=PRI_DEFAULT?&Def->Priority:NULL,sizeof(int),TYPE_INT); #endif } Class->Def = *Def; Class->ModuleNo = ModuleNo; Class->Parent = FindClass(p,Def->ParentClass); Class->Registered = Registered; LockLeave(p->NodeLock); } void NodeLoadClass(const nodedef* Def,const tchar_t* Module,int ModuleId) { context* p = Context(); int ModuleNo = FindModule(p,Module,ModuleId); if (ModuleNo>=0) Register(p,Def,0,ModuleNo); } void NodeUnRegisterClass(int ClassId) { context* p = Context(); nodeclass* Class = FindClass(p,ClassId); if (Class && Class->Registered) { node **i; LockEnter(p->NodeLock); Class->Registered = 0; // delete all objects for (i=ARRAYBEGIN(p->Node,node*);i!=ARRAYEND(p->Node,node*);++i) if (*i && NodeIsClass((*i)->Class,ClassId)) Delete(p,i); Class->Def.Create = NULL; Class->Def.Delete = NULL; LockLeave(p->NodeLock); } } static node* NodeCreateFromClass(context* p, nodeclass* Class) { node **Empty = NULL; node **i; nodemodule* Module; node* Node; int Size; nodeclass *j; if (!Class || (Class->Def.Flags & CF_ABSTRACT)) return NULL; Size = 0; for (j=Class;j;j=j->Parent) if (Size < (j->Def.Flags & CF_SIZE)) Size = (j->Def.Flags & CF_SIZE); if (!Size) return NULL; LockEnter(p->NodeLock); if ((Class->Def.Flags & CF_GLOBAL) && (Module = LoadModule(p,Class->ModuleNo))!=NULL && (Node = NodeEnumObject(NULL,Class->Def.Class))!=NULL) { ++Module->ObjectCount; LockLeave(p->NodeLock); return Node; } for (i=ARRAYBEGIN(p->Node,node*);i!=ARRAYEND(p->Node,node*);++i) if (!*i) { Empty = i; break; } if (!Empty) { if (!ArrayAppend(&p->Node,NULL,sizeof(node**),256)) { LockLeave(p->NodeLock); return NULL; } Empty = ARRAYEND(p->Node,node*)-1; } *Empty = Node = (node*) malloc(Size); if (Node) { memset(Node,0,Size); Node->Class = Class->Def.Class; if (CallCreate(p,Node,Class,(Class->Def.Flags & CF_GLOBAL)!=0) != ERR_NONE) { for (i=ARRAYBEGIN(p->Node,node*);i!=ARRAYEND(p->Node,node*);++i) if (*i == Node) *i = NULL; free(Node); Node = NULL; } else { #ifndef REGISTRY_GLOBAL if (Class->Def.Flags & CF_GLOBAL) NodeRegLoad(Node); #endif Node->Set(Node,NODE_SETTINGSCHANGED,NULL,0); // should be after NodeRegLoad } } LockLeave(p->NodeLock); return Node; } void NodeRegisterClass(const nodedef* Def) { context* p = Context(); if (Def->Flags & CF_GLOBAL) { //create global object with fake class and don't register if fails nodeclass Class; memset(&Class,0,sizeof(Class)); Class.Def = *Def; Class.ModuleNo = p->LoadModuleNo; Class.Parent = FindClass(p,Def->ParentClass); Class.Registered = 1; if (!Class.Parent || !NodeCreateFromClass(p,&Class)) return; } Register(p,Def,1,p->LoadModuleNo); } node* NodeCreate(int ClassId) { context* p = Context(); return NodeCreateFromClass(p,FindClass(p,ClassId)); } void NodeDelete(node* Node) { if (Node) { nodeclass* Class; context* p = Context(); LockEnter(p->NodeLock); Class = FindClass(p,Node->Class); if (Class && (Class->Def.Flags & CF_GLOBAL)) UnlockModule(p,Class->ModuleNo); else { node **i; for (i=ARRAYBEGIN(p->Node,node*);i!=ARRAYEND(p->Node,node*);++i) if (*i == Node) { Delete(p,i); break; } } LockLeave(p->NodeLock); } } const nodedef* NodeClassDef(int Class) { nodeclass* i = FindClass(Context(),Class); return i?&i->Def:NULL; } static NOINLINE bool_t GetNode(context* p,int n,node** Node) { node** i; bool_t Result = 0; LockEnter(p->NodeLock); i = ARRAYBEGIN(p->Node,node*)+n; if (iNode,node*)) { *Node = *i; Result = 1; } LockLeave(p->NodeLock); return Result; } bool_t NodeHibernate() { int Mode; int No; node* Node; context* p = Context(); bool_t Changed = 0; if (p && !p->InHibernate) { p->InHibernate = 1; #ifdef PLUGINCLEANUP if (ReleaseModules(p,1)) Changed = 1; #endif for (Mode=0;!Changed && ModeSet && Node->Set(Node,NODE_HIBERNATE,&Mode,sizeof(int))==ERR_NONE) Changed = 1; if (!Changed && ReleaseModules(p,1)) Changed = 1; p->InHibernate = 0; } return Changed; } int NodeBroadcast(int Msg,const void* Data,int Size) { int No; context* p = Context(); node* Node; for (No=0;GetNode(p,No,&Node);++No) if (Node && Node->Set) Node->Set(Node,Msg,Data,Size); return ERR_NONE; } int NodeSettingsChanged() { return NodeBroadcast(NODE_SETTINGSCHANGED,NULL,0); } node* NodeEnumObject(array* List, int Class) { context* p = Context(); node **i; if (List) memset(List,0,sizeof(array)); LockEnter(p->NodeLock); for (i=ARRAYBEGIN(p->Node,node*);i!=ARRAYEND(p->Node,node*);++i) if (*i && NodeIsClass((*i)->Class,Class)) { if (!List) { node* Node = *i; LockLeave(p->NodeLock); return Node; } ArrayAppend(List,i,sizeof(node**),64); } LockLeave(p->NodeLock); if (List) ArraySort(List,ARRAYCOUNT(*List,node*),sizeof(node*),(arraycmp)CmpNodePri); return NULL; } bool_t NodeIsClass(int ClassId, int PartOfClass) { nodeclass* Item; for (Item = FindClass(Context(),ClassId);Item;Item=Item->Parent) if (Item->Def.Class == PartOfClass) return 1; return 0; } static void DumpPtr(stream* File, tchar_t* s, node* Ptr, int No) { if (Ptr) { tchar_t v[32]; if (No) stprintf_s(v,TSIZEOF(v),T(":%d"),No); else v[0] = 0; StreamPrintf(File,T("%s%s%s (0x%08x)\n"),s,LangStrDef(Ptr->Class,0),v,(int)Ptr); } else StreamPrintf(File,T("%sNULL\n"),s); } static void DumpFormat(stream* File, tchar_t* s,const packetformat* Format) { tchar_t v[8]; switch (Format->Type) { case PACKET_VIDEO: StreamPrintf(File,T("%svideo"),s); if (Format->Format.Video.Pixel.Flags & PF_FOURCC) { FourCCToString(v,TSIZEOF(v),Format->Format.Video.Pixel.FourCC); StreamPrintf(File,T(" fourcc=%s"),v); } else StreamPrintf(File,T(" bitcount=%d rmask=%04x gmask=%04x bmask=%04x"),Format->Format.Video.Pixel.BitCount, Format->Format.Video.Pixel.BitMask[0],Format->Format.Video.Pixel.BitMask[1],Format->Format.Video.Pixel.BitMask[2]); if (Format->Format.Video.Width) StreamPrintf(File,T(" width=%d"),Format->Format.Video.Width); if (Format->Format.Video.Height) StreamPrintf(File,T(" height=%d"),Format->Format.Video.Height); if (Format->Format.Video.Pitch) StreamPrintf(File,T(" pitch=%d"),Format->Format.Video.Pitch); if (Format->Format.Video.Direction) StreamPrintf(File,T(" dir=%d"),Format->Format.Video.Direction); if (Format->ByteRate) StreamPrintf(File,T(" bitrate=%d"),Format->ByteRate*8); StreamPrintf(File,T("\n")); break; case PACKET_AUDIO: StreamPrintf(File,T("%saudio"),s); if (Format->Format.Audio.Format) StreamPrintf(File,T(" fmt=%04x"),Format->Format.Audio.Format); if (Format->Format.Audio.SampleRate) StreamPrintf(File,T(" rate=%d"),Format->Format.Audio.SampleRate); if (Format->Format.Audio.Channels) StreamPrintf(File,T(" ch=%d"),Format->Format.Audio.Channels); if (Format->Format.Audio.Bits) StreamPrintf(File,T(" bits=%d"),Format->Format.Audio.Bits); if (Format->ByteRate) StreamPrintf(File,T(" bitrate=%d"),Format->ByteRate*8); StreamPrintf(File,T("\n")); break; case PACKET_SUBTITLE: FourCCToString(v,TSIZEOF(v),Format->Format.Subtitle.FourCC); StreamPrintf(File,T("%ssubtitle fourcc=%s\n"),s,v); break; case PACKET_NONE: StreamPrintf(File,T("%sempty packet format\n"),s); break; default: StreamPrintf(File,T("%sunknown packet format (%d)\n"),s,Format->Type); break; } } void NodeDump(struct stream* File) { context* p = Context(); node **i; nodemodule* j; nodeclass** k; int No; for (No=0,j=ARRAYBEGIN(p->NodeModule,nodemodule);j!=ARRAYEND(p->NodeModule,nodemodule);++j,++No) TRY_BEGIN { int ClassCount = 0; for (k=ARRAYBEGIN(p->NodeClass,nodeclass*);k!=ARRAYEND(p->NodeClass,nodeclass*);++k) if ((*k)->ModuleNo == No) ++ClassCount; if (j->Func && !j->Min) CodeFindPages(j->Func,&j->Min,&j->Max,NULL); StreamPrintf(File,T("%s %08x-%08x obj:%d class:%d\n"),LangStrDef(MODULE_PATH,No),j->Min,j->Max,j->ObjectCount,ClassCount); } TRY_END StreamPrintf(File,T("\n\n")); //no NodeLock, becase may be stayed locked when dumping after crash for (i=ARRAYBEGIN(p->Node,node*);i!=ARRAYEND(p->Node,node*);++i) if (*i) TRY_BEGIN { tchar_t Flags[64]; tchar_t s[256]; tchar_t Buffer[512]; const tchar_t* Name; rect Rect; packetformat Format; pin Pin; rgb RGB; point Point; bool_t Bool; tick_t Tick; fraction Fraction; node* Ptr; int Int,No; node* p = *i; datadef DataDef; StreamPrintf(File,T("%s (0x%08x)\n"),LangStrDef(p->Class,0),(int)p); for (No=0;NodeEnum(p,No,&DataDef)==ERR_NONE;++No) { TRY_BEGIN { Name = LangStrDef(DataDef.Class,DataDef.No); if (!Name[0]) Name = DataDef.Name ? DataDef.Name : T(""); Flags[0] = 0; if (DataDef.Flags & DF_INPUT) tcscat_s(Flags,TSIZEOF(Flags),T(":IN")); if (DataDef.Flags & DF_OUTPUT) tcscat_s(Flags,TSIZEOF(Flags),T(":OUT")); stprintf_s(s,TSIZEOF(s),T(" %s(%d)%s="),Name,DataDef.No,Flags); switch (DataDef.Type) { case TYPE_BOOL: if (p->Get(p,DataDef.No,&Bool,sizeof(bool_t))==ERR_NONE) { BoolToString(Buffer,TSIZEOF(Buffer),Bool); StreamPrintf(File,T("%s%s\n"),s,Buffer); } break; case TYPE_TICK: if (p->Get(p,DataDef.No,&Tick,sizeof(tick_t))==ERR_NONE) { TickToString(Buffer,TSIZEOF(Buffer),Tick,TickGet(p,DataDef.No,&Int,sizeof(int))==ERR_NONE) { IntToString(Buffer,TSIZEOF(Buffer),Int,(DataDef.Flags & DF_HEX)!=0); StreamPrintf(File,T("%s%s\n"),s,Buffer); } break; case TYPE_HOTKEY: if (p->Get(p,DataDef.No,&Int,sizeof(int))==ERR_NONE) { HotKeyToString(Buffer,TSIZEOF(Buffer),Int); StreamPrintf(File,T("%s%s\n"),s,Buffer); } break; case TYPE_FRACTION: if (p->Get(p,DataDef.No,&Fraction,sizeof(fraction))==ERR_NONE) { FractionToString(Buffer,TSIZEOF(Buffer),&Fraction,1,2); StreamPrintf(File,T("%s%s\n"),s,Buffer); } break; case TYPE_STRING: if (p->Get(p,DataDef.No,Buffer,sizeof(Buffer))==ERR_NONE) StreamPrintf(File,T("%s%s\n"),s,Buffer); break; case TYPE_RECT: if (p->Get(p,DataDef.No,&Rect,sizeof(rect))==ERR_NONE) StreamPrintf(File,T("%s%d:%d:%d:%d\n"),s,Rect.x,Rect.y,Rect.Width,Rect.Height); break; case TYPE_POINT: if (p->Get(p,DataDef.No,&Point,sizeof(point))==ERR_NONE) StreamPrintf(File,T("%s%d:%d\n"),s,Point.x,Point.y); break; case TYPE_RGB: if (p->Get(p,DataDef.No,&RGB.v,sizeof(RGB.v))==ERR_NONE) StreamPrintf(File,T("%s0x%082%082%082\n"),s,RGB.c.r,RGB.c.b,RGB.c.b); break; case TYPE_COMMENT: if (p->Get(p,DataDef.No,&Pin,sizeof(Pin))==ERR_NONE) DumpPtr(File,s,Pin.Node,Pin.No); break; case TYPE_PACKET: if (p->Get(p,DataDef.No|PIN_FORMAT,&Format,sizeof(Format))==ERR_NONE) DumpFormat(File,s,&Format); if (p->Get(p,DataDef.No,&Pin,sizeof(Pin))==ERR_NONE) DumpPtr(File,s,Pin.Node,Pin.No); break; case TYPE_NODE: if (p->Get(p,DataDef.No,&Ptr,sizeof(Ptr)) == ERR_NONE) DumpPtr(File,s,Ptr,0); break; } } TRY_END } } TRY_END StreamPrintf(File,T("\n\n")); for (k=ARRAYBEGIN(p->NodeClass,nodeclass*);k!=ARRAYEND(p->NodeClass,nodeclass*);++k) TRY_BEGIN { tchar_t s[16],s2[16]; int Class = (*k)->Def.Class; FourCCToString(s,TSIZEOF(s),Class); FourCCToString(s2,TSIZEOF(s2),(*k)->Def.ParentClass); StreamPrintf(File,T("%s %s p:%d r:%d "),s,s2,(*k)->Parent!=NULL,(*k)->Registered); StreamPrintf(File,T("c:%s e:%s p:%s m:%s\n"), LangStrDef(Class,NODE_CONTENTTYPE), LangStrDef(Class,NODE_EXTS), LangStrDef(Class,NODE_PROBE), LangStrDef(MODULE_PATH,(*k)->ModuleNo)); } TRY_END } int NodeEnumTable(int* No, datadef* Out, const datatable* p) { int Count; for (Count=0;p[Count].Type>=0;++Count); if (*No < Count) { Out->Class = p[Count].No; p += *No; Out->No = p->No; Out->Type = p->Type; Out->Flags = p->Flags; Out->Format1 = p->Format1; Out->Format2 = p->Format2; switch (Out->Type) { case TYPE_BOOL: Out->Size = sizeof(bool_t); break; case TYPE_INT: Out->Size = sizeof(int); break; case TYPE_HOTKEY: Out->Size = sizeof(int); break; case TYPE_FRACTION: Out->Size = sizeof(fraction); break; case TYPE_STRING: Out->Size = MAXDATA; break; case TYPE_RECT: Out->Size = sizeof(rect); break; case TYPE_POINT: Out->Size = sizeof(point); break; case TYPE_RGB: Out->Size = sizeof(rgbval_t); break; case TYPE_BINARY: Out->Size = Out->Format1; break; case TYPE_NODE: Out->Size = sizeof(node*); break; case TYPE_NOTIFY: Out->Size = sizeof(notify); break; case TYPE_COMMENT: case TYPE_PACKET: Out->Size = sizeof(pin); break; case TYPE_TICK: Out->Size = sizeof(tick_t); break; case TYPE_BLITFX: Out->Size = sizeof(blitfx); break; default: Out->Size = 0; break; } Out->Name = LangStr(Out->Class,Out->No); return ERR_NONE; } *No -= Count; return ERR_INVALID_PARAM; } bool_t NodeDataDef(node* p, int No, datadef* Out) { int i; for (i=0;NodeEnum(p,i,Out)==ERR_NONE;++i) if (Out->No == No) return 1; return 0; } int NodeEnum(node* p,int No,datadef* Param) { if (!p) return ERR_INVALID_PARAM; return p->Enum(p,&No,Param); } int NodeEnumClass(array* List, int Class) { return NodeEnumClassEx(List,Class,NULL,NULL,NULL,0); } int NodeEnumClassEx(array* List, int Class, const tchar_t* ContentType, const tchar_t* URL, const void* Data, int Length) { context* p = Context(); nodeclass* v; nodeclass **i; if (ContentType && !ContentType[0]) ContentType = NULL; if (URL && !URL[0]) URL = NULL; if (List) memset(List,0,sizeof(array)); LockEnter(p->NodeLock); for (i=ARRAYBEGIN(p->NodeClassPri,nodeclass*);i!=ARRAYEND(p->NodeClassPri,nodeclass*);++i) if (!((*i)->Def.Flags & CF_ABSTRACT) && !TmpModule(p,(*i)->ModuleNo)) // skip abstract for (v=*i;v;v=v->Parent) if (v->Def.Class == Class) { int Id = (*i)->Def.Class; if ((ContentType || URL || Data) && (!ContentType || !CheckContentType(ContentType,LangStrDef(Id,NODE_CONTENTTYPE))) && (!URL || !CheckExts(URL,LangStrDef(Id,NODE_EXTS))) && (!Data || !DataProbe(Data,Length,LangStrDef(Id,NODE_PROBE)))) continue; if (!List) { LockLeave(p->NodeLock); return Id; } ArrayAppend(List,&Id,sizeof(int),64); break; } LockLeave(p->NodeLock); return 0; } static int Enum(void* This,int* EnumNo,datadef* Out) { return ERR_INVALID_PARAM; } static int Get(void* This,int No,void* Data,int Size) { return ERR_INVALID_PARAM; } static int Set(void* This,int No,const void* Data,int Size) { return ERR_INVALID_PARAM; } static int Create(node* p) { p->Enum = Enum; p->Get = Get; p->Set = Set; return ERR_NONE; } static const nodedef Node = { CF_ABSTRACT, NODE_CLASS, 0, PRI_DEFAULT, (nodecreate)Create }; void Node_Init() { context* p = Context(); ArrayAlloc(&p->NodeClass,sizeof(nodeclass*)*100,128); ArrayAlloc(&p->NodeClassPri,sizeof(nodeclass*)*100,128); p->NodeLock = LockCreate(); NodeAddModule(T("common"),0,0,0,0); if (!ARRAYEMPTY(p->NodeModule)) *(void(**)())&ARRAYBEGIN(p->NodeModule,nodemodule)->Func = Node_Init; NodeRegisterClass(&Node); } void Node_Done() { context* p = Context(); nodeclass **i; NodeUnRegisterClass(NODE_CLASS); #ifndef NDEBUG { nodemodule* j; for (j=ARRAYBEGIN(p->NodeModule,nodemodule);j!=ARRAYEND(p->NodeModule,nodemodule);++j) { if (j->ObjectCount!=0) DebugMessage(T("module problem %s"),LangStr(MODULE_PATH,j-ARRAYBEGIN(p->NodeModule,nodemodule))); assert(j->ObjectCount==0); } } #endif ReleaseModules(p,1); for (i=ARRAYBEGIN(p->NodeClass,nodeclass*);i!=ARRAYEND(p->NodeClass,nodeclass*);++i) free(*i); ArrayClear(&p->Node); ArrayClear(&p->NodeClass); ArrayClear(&p->NodeClassPri); ArrayClear(&p->NodeModule); LockDelete(p->NodeLock); p->NodeLock = NULL; } bool_t NodeLocatePtr(void* Ptr, tchar_t* OutName, int OutLen, int* OutBase) { if (Ptr) { context* p = Context(); if (p) { int No; uint8_t* v = (uint8_t*)Ptr; nodemodule *i; // no locking (dump after crash) for (No=0,i=ARRAYBEGIN(p->NodeModule,nodemodule);i!=ARRAYEND(p->NodeModule,nodemodule);++i,++No) { if (i->Func) { if (!i->Min) CodeFindPages(i->Func,&i->Min,&i->Max,NULL); if (i->Min <= v && i->Max > v) { tcscpy_s(OutName,OutLen,LangStrDef(MODULE_PATH,No)); *OutBase = v - i->Min; return 1; } } } } } return 0; } #ifndef REGISTRY_GLOBAL bool_t NodeRegLoadString(int Class, int Id) { uint8_t Buffer[MAXDATA]; if (NodeRegLoadValue(Class,Id,Buffer,sizeof(Buffer),TYPE_STRING)) { StringAdd(1,Class,Id,(tchar_t*)Buffer); return 1; } return 0; } void NodeRegSaveString(int Class, int Id) { const tchar_t* s = LangStrDef(Class,Id); int Len = tcslen(s); if (Len) ++Len; else s = NULL; NodeRegSaveValue(Class,Id,s,Len*sizeof(tchar_t),TYPE_STRING); } #endif