583 lines
14 KiB
C
Executable File
583 lines
14 KiB
C
Executable File
/*****************************************************************************
|
|
*
|
|
* 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_palmos.c 345 2005-11-19 15:57:54Z picard $
|
|
*
|
|
* The Core Pocket Media Player
|
|
* Copyright (c) 2004-2005 Gabor Kovacs
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "../common.h"
|
|
|
|
#if defined(TARGET_PALMOS)
|
|
|
|
#define PREFID_NODE 2
|
|
#define PREFID_PLUGINS 100
|
|
|
|
#define FTRID_START 64
|
|
#define FTRID_STEP 64
|
|
#define FTRID_COUNT 60
|
|
|
|
#include "pace.h"
|
|
|
|
#ifdef HAVE_PALMONE_SDK
|
|
#include <68K/System/PmPalmOSNVFS.h>
|
|
#endif
|
|
|
|
void NodeRegSaveGlobal()
|
|
{
|
|
uint8_t Data[MAXDATA];
|
|
array Buffer = {NULL};
|
|
array List;
|
|
node **i;
|
|
UInt16 PrefId=PREFID_NODE;
|
|
uint32_t ProgramId = Context()->ProgramId;
|
|
|
|
NodeEnumObject(&List,NODE_CLASS);
|
|
|
|
for (i=ARRAYBEGIN(List,node*);i!=ARRAYEND(List,node*);++i)
|
|
{
|
|
int No,Total;
|
|
datadef Type;
|
|
|
|
for (No=0;NodeEnum(*i,No,&Type)==ERR_NONE;++No)
|
|
{
|
|
node* Node = *i;
|
|
if ((Type.Flags & DF_SETUP) && !(Type.Flags & (DF_NOSAVE|DF_RDONLY)))
|
|
{
|
|
int Result = Node->Get(Node,Type.No,Data,Type.Size);
|
|
if (Result == ERR_NONE || Result == ERR_NOT_SUPPORTED) // not supported settings should be still saved
|
|
{
|
|
if (Type.Type == TYPE_STRING)
|
|
Type.Size = (tcslen((tchar_t*)Data)+1)*sizeof(tchar_t);
|
|
|
|
Total = sizeof(int32_t)*3+ALIGN4(Type.Size);
|
|
|
|
if (ARRAYCOUNT(Buffer,uint8_t)+Total > 0xF000)
|
|
{
|
|
PrefSetAppPreferences(ProgramId,PrefId++,CONTEXT_VERSION,ARRAYBEGIN(Buffer,uint8_t),(UInt16)ARRAYCOUNT(Buffer,uint8_t),0);
|
|
ArrayDrop(&Buffer);
|
|
}
|
|
|
|
if (ArrayAppend(&Buffer,NULL,Total,4096))
|
|
{
|
|
int32_t* p = (int32_t*)(ARRAYEND(Buffer,uint8_t) - Total);
|
|
memset(p,0,Total);
|
|
p[0] = Node->Class;
|
|
p[1] = Type.No;
|
|
p[2] = Type.Size;
|
|
memcpy(p+3,Data,Type.Size);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ARRAYEMPTY(Buffer))
|
|
PrefSetAppPreferences(ProgramId,PrefId++,CONTEXT_VERSION,ARRAYBEGIN(Buffer,uint8_t),(UInt16)ARRAYCOUNT(Buffer,uint8_t),0);
|
|
|
|
ArrayClear(&List);
|
|
ArrayClear(&Buffer);
|
|
|
|
for (;;)
|
|
{
|
|
UInt16 PrefSize = 0;
|
|
if (PrefGetAppPreferences(ProgramId, PrefId, NULL, &PrefSize, 0) == noPreferenceFound)
|
|
break;
|
|
PrefSetAppPreferences(ProgramId,PrefId++,CONTEXT_VERSION,NULL,0,0);
|
|
}
|
|
}
|
|
|
|
void NodeRegLoadGlobal()
|
|
{
|
|
array Buffer = {NULL};
|
|
array List;
|
|
node **i;
|
|
int32_t* p;
|
|
UInt16 PrefId;
|
|
UInt16 PrefSize;
|
|
uint32_t ProgramId = Context()->ProgramId;
|
|
|
|
NodeEnumObject(&List,NODE_CLASS);
|
|
|
|
for (PrefId=PREFID_NODE;;++PrefId)
|
|
{
|
|
PrefSize = 0;
|
|
if (PrefGetAppPreferences(ProgramId, PrefId, NULL, &PrefSize, 0) == noPreferenceFound)
|
|
break;
|
|
|
|
ArrayDrop(&Buffer);
|
|
if (ArrayAppend(&Buffer,NULL,PrefSize,16) &&
|
|
PrefGetAppPreferences(ProgramId, PrefId, ARRAYBEGIN(Buffer,int32_t), &PrefSize, 0) != noPreferenceFound)
|
|
{
|
|
for (p=ARRAYBEGIN(Buffer,int32_t);p<ARRAYEND(Buffer,int32_t);p+=3+(p[2]+3)/4)
|
|
for (i=ARRAYBEGIN(List,node*);i!=ARRAYEND(List,node*);++i)
|
|
if ((*i)->Class == p[0])
|
|
{
|
|
(*i)->Set(*i,p[1],p+3,p[2]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ArrayClear(&List);
|
|
ArrayClear(&Buffer);
|
|
}
|
|
|
|
static NOINLINE void AddModule(const tchar_t* Path,int Type,int Date,int32_t* Modules)
|
|
{
|
|
int No=0;
|
|
int Count=0;
|
|
|
|
if (Modules)
|
|
{
|
|
//don't load if already registered with same date
|
|
Count = Modules[-1];
|
|
for (No=0;No<Count;++No)
|
|
{
|
|
if ((!Type || Modules[0] == Type) &&
|
|
tcscmp((const tchar_t*)(Modules+3),Path)==0)
|
|
{
|
|
Type = Modules[0];
|
|
if (Modules[1] == Date)
|
|
{
|
|
Modules[1] = -1;
|
|
break;
|
|
}
|
|
Modules[1] = -2;
|
|
}
|
|
Modules += 1+1+1+Modules[2]/4;
|
|
}
|
|
}
|
|
|
|
NodeAddModule(Path,Type,Date,No>=Count,0);
|
|
}
|
|
|
|
static void VFSFindPlugins(uint16_t Ref,tchar_t* Path,int PathLen,int32_t* Modules,const tchar_t* Skip)
|
|
{
|
|
FileRef File;
|
|
|
|
int PathPos = tcslen(Path);
|
|
if (PathPos>0 && Path[PathPos-1]=='/')
|
|
Path[PathPos-1] = 0;
|
|
|
|
if (Skip && tcscmp(Path,Skip)==0)
|
|
return;
|
|
|
|
if (VFSFileOpen(Ref,Path,vfsModeRead,&File)==errNone)
|
|
{
|
|
FileInfoType Info;
|
|
UInt32 Iter = vfsIteratorStart;
|
|
|
|
tcscat_s(Path,PathLen,"/");
|
|
PathPos = tcslen(Path);
|
|
|
|
Info.nameP = Path + PathPos;
|
|
Info.nameBufLen = (UInt16)((PathLen-PathPos)*sizeof(tchar_t));
|
|
|
|
while (Iter != vfsIteratorStop && VFSDirEntryEnumerate(File,&Iter,&Info)==errNone)
|
|
{
|
|
if (tcsnicmp(Path+PathPos,T("tcpmp"),5)==0 &&
|
|
(Path[PathPos+5]=='_' || Path[PathPos+5]==' '))
|
|
{
|
|
FileRef File = 0;
|
|
VFSFileOpen(Ref,Path,vfsModeRead,&File);
|
|
if (File)
|
|
{
|
|
UInt32 Date;
|
|
if (VFSFileGetDate(File,vfsFileDateModified,&Date)==errNone)
|
|
{
|
|
tchar_t URL[MAXPATH];
|
|
if (VFSFromVol(Ref,Path,URL,TSIZEOF(URL)))
|
|
AddModule(URL,0,Date,Modules);
|
|
}
|
|
VFSFileClose(File);
|
|
}
|
|
}
|
|
}
|
|
|
|
VFSFileClose(File);
|
|
}
|
|
}
|
|
|
|
static void FindPlugins(int32_t* Modules)
|
|
{
|
|
bool_t CheckVFS = 1;
|
|
Boolean New = 1;
|
|
LocalID CurrentDB;
|
|
UInt16 Card;
|
|
DmSearchStateType SearchState;
|
|
tchar_t Name[48];
|
|
tchar_t URL[MAXPATH];
|
|
UInt32 Type;
|
|
UInt32 Date;
|
|
|
|
CurrentDB = 0;
|
|
while (DmGetNextDatabaseByTypeCreator(New, &SearchState, 0, Context()->ProgramId, 1, &Card, &CurrentDB)==errNone)
|
|
{
|
|
DmDatabaseInfo(Card,CurrentDB,Name,NULL,NULL,NULL,&Date,NULL,NULL,NULL,NULL,&Type,NULL);
|
|
if ((Type >> 24) == 'X')
|
|
{
|
|
stprintf_s(URL,TSIZEOF(URL),T("mem://%s.prc"),Name);
|
|
AddModule(URL,Type,Date,Modules);
|
|
CheckVFS = 0;
|
|
}
|
|
New = 0;
|
|
}
|
|
|
|
if (NodeEnumClass(NULL,VFS_ID))
|
|
{
|
|
UInt16 Ref;
|
|
uint32_t LaunchPath = 0;
|
|
URL[0] = 0;
|
|
|
|
if (FtrGet(Context()->ProgramId,20,&LaunchPath)==errNone)
|
|
{
|
|
Ref = ((vfspath*)LaunchPath)->volRefNum;
|
|
SplitURL(((vfspath*)LaunchPath)->path,URL,TSIZEOF(URL),URL,TSIZEOF(URL),NULL,0,NULL,0);
|
|
VFSFindPlugins(Ref,URL,TSIZEOF(URL),Modules,NULL);
|
|
}
|
|
|
|
if (CheckVFS || QueryAdvanced(ADVANCED_CARDPLUGINS))
|
|
{
|
|
UInt32 Iter = vfsIteratorStart;
|
|
while (Iter != vfsIteratorStop && VFSVolumeEnumerate(&Ref,&Iter)==errNone)
|
|
{
|
|
tchar_t Path[MAXPATH];
|
|
UInt16 Size = sizeof(Path);
|
|
|
|
if (VFSGetDefaultDirectory(Ref,T(".prc"),Path,&Size)==errNone)
|
|
VFSFindPlugins(Ref,Path,TSIZEOF(Path),Modules,URL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static NOINLINE int32_t* GetString(int32_t* p,const tchar_t** s)
|
|
{
|
|
if (p[0])
|
|
{
|
|
*s = (const tchar_t*)(p+1);
|
|
p+=1+p[0]/4;
|
|
}
|
|
else
|
|
{
|
|
*s = NULL;
|
|
++p;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
void Plugins_Init()
|
|
{
|
|
array Buffer = {NULL};
|
|
int32_t* p;
|
|
int32_t* Modules;
|
|
int i,No,Count;
|
|
bool_t b;
|
|
UInt16 PrefSize;
|
|
uint32_t ProgramId = Context()->ProgramId;
|
|
node* Advanced = Context()->Advanced;
|
|
|
|
PrefSize = 0;
|
|
if (PrefGetAppPreferences(ProgramId, PREFID_PLUGINS, NULL, &PrefSize, 0) != noPreferenceFound &&
|
|
ArrayAppend(&Buffer,NULL,PrefSize,16) &&
|
|
PrefGetAppPreferences(ProgramId, PREFID_PLUGINS, ARRAYBEGIN(Buffer,int32_t), &PrefSize, 0) != noPreferenceFound)
|
|
{
|
|
// add all plugins and load changed/new ones
|
|
p = ARRAYBEGIN(Buffer,int32_t);
|
|
if (*p<0)
|
|
{
|
|
// params
|
|
if (Advanced)
|
|
{
|
|
b = p[1] != 0;
|
|
Advanced->Set(Advanced,ADVANCED_CARDPLUGINS,&b,sizeof(b));
|
|
}
|
|
p += 1-*p;
|
|
}
|
|
|
|
Count = *(p++);
|
|
Modules = p;
|
|
|
|
FindPlugins(Modules);
|
|
|
|
// also add non existing modules (maybe SD card removed temporarily)
|
|
for (No=0;No<Count;++No)
|
|
{
|
|
if (p[1] != -1 && p[1] != -2)
|
|
NodeAddModule((const tchar_t*)(p+3),p[0],p[1],0,1);
|
|
p += 1+1+1+p[2]/4;
|
|
}
|
|
|
|
// load classes (only if not exists already. don't want to override changed loaded plugins)
|
|
while (*p)
|
|
{
|
|
nodedef Def;
|
|
int Module;
|
|
const tchar_t* Name;
|
|
const tchar_t* ContentType;
|
|
const tchar_t* Exts;
|
|
const tchar_t* Probe;
|
|
|
|
memset(&Def,0,sizeof(Def));
|
|
|
|
Module = *p-1; ++p;
|
|
Def.Class = *p; ++p;
|
|
Def.ParentClass = *p; ++p;
|
|
Def.Flags = *p; ++p;
|
|
Def.Priority = *p; ++p;
|
|
p = GetString(p,&Name);
|
|
p = GetString(p,&ContentType);
|
|
p = GetString(p,&Exts);
|
|
p = GetString(p,&Probe);
|
|
|
|
if (Module<Modules[-1] && !NodeEnumClass(NULL,Def.Class))
|
|
{
|
|
int32_t* p = Modules;
|
|
for (i=0;i<Module;++i)
|
|
p += 1+1+1+p[2]/4;
|
|
|
|
if (Name) StringAdd(1,Def.Class,NODE_NAME,Name);
|
|
if (ContentType) StringAdd(1,Def.Class,NODE_CONTENTTYPE,ContentType);
|
|
if (Exts) StringAdd(1,Def.Class,NODE_EXTS,Exts);
|
|
if (Probe) StringAdd(1,Def.Class,NODE_PROBE,Probe);
|
|
|
|
NodeLoadClass(&Def,(const tchar_t*)(p+3),p[0]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
FindPlugins(NULL);
|
|
|
|
ArrayClear(&Buffer);
|
|
}
|
|
|
|
bool_t NOINLINE AppendInt(array* Buffer,int Data)
|
|
{
|
|
return ArrayAppend(Buffer,&Data,sizeof(Data),4096);
|
|
}
|
|
|
|
bool_t NOINLINE AppendStr(array* Buffer,const tchar_t* Data)
|
|
{
|
|
int Len = (tcslen((tchar_t*)Data)+1)*sizeof(tchar_t);
|
|
int Total = ALIGN4(Len);
|
|
if (!AppendInt(Buffer,Total) || !ArrayAppend(Buffer,NULL,Total,4096))
|
|
return 0;
|
|
memcpy(ARRAYEND(*Buffer,uint8_t)-Total,Data,Len);
|
|
memset(ARRAYEND(*Buffer,uint8_t)-Total+Len,0,Total-Len);
|
|
return 1;
|
|
}
|
|
|
|
bool_t NOINLINE AppendString(array* Buffer,int Class,int Id)
|
|
{
|
|
if (StringIsBinary(Class,Id))
|
|
return AppendInt(Buffer,0);
|
|
return AppendStr(Buffer,LangStrDef(Class,Id));
|
|
}
|
|
|
|
void Plugins_Done()
|
|
{
|
|
array Buffer = {NULL};
|
|
uint32_t ProgramId = Context()->ProgramId;
|
|
int64_t Date;
|
|
int No,Count;
|
|
int Id;
|
|
|
|
AppendInt(&Buffer,-1);
|
|
AppendInt(&Buffer,QueryAdvanced(ADVANCED_CARDPLUGINS));
|
|
|
|
Count = NodeGetModuleCount();
|
|
AppendInt(&Buffer,Count-1);
|
|
for (No=1;No<Count;++No)
|
|
{
|
|
const tchar_t* Path = NodeGetModule(No,&Id,&Date);
|
|
AppendInt(&Buffer,Id);
|
|
AppendInt(&Buffer,(int)Date);
|
|
AppendStr(&Buffer,Path);
|
|
}
|
|
|
|
Count = NodeGetClassCount();
|
|
for (No=0;No<Count;++No)
|
|
{
|
|
const nodedef* Def = NodeGetClass(No,&Id);
|
|
if (Id)
|
|
{
|
|
AppendInt(&Buffer,Id);
|
|
AppendInt(&Buffer,Def->Class);
|
|
AppendInt(&Buffer,Def->ParentClass);
|
|
AppendInt(&Buffer,Def->Flags);
|
|
AppendInt(&Buffer,Def->Priority);
|
|
AppendString(&Buffer,Def->Class,NODE_NAME);
|
|
AppendString(&Buffer,Def->Class,NODE_CONTENTTYPE);
|
|
AppendString(&Buffer,Def->Class,NODE_EXTS);
|
|
AppendString(&Buffer,Def->Class,NODE_PROBE);
|
|
}
|
|
}
|
|
AppendInt(&Buffer,0);
|
|
|
|
if (ARRAYCOUNT(Buffer,uint8_t)<0x8000)
|
|
PrefSetAppPreferences(ProgramId,PREFID_PLUGINS,CONTEXT_VERSION,ARRAYBEGIN(Buffer,uint8_t),(UInt16)ARRAYCOUNT(Buffer,uint8_t),0);
|
|
ArrayClear(&Buffer);
|
|
}
|
|
|
|
static void* Modules[FTRID_COUNT] = {NULL};
|
|
|
|
void NodeFreeModule(void* Module,void* Db)
|
|
{
|
|
if (Module)
|
|
{
|
|
int i;
|
|
void* UnRegister = PealGetSymbol(Module,T("DLLUnRegister"));
|
|
if (UnRegister)
|
|
((void(*)())UnRegister)();
|
|
|
|
for (i=0;i<FTRID_COUNT;++i)
|
|
if (Modules[i] == Module)
|
|
{
|
|
Modules[i] = NULL;
|
|
break;
|
|
}
|
|
|
|
PealFreeModule(Module);
|
|
if (Db)
|
|
DmCloseDatabase(Db);
|
|
}
|
|
}
|
|
|
|
static void* LoadPlugin(UInt16 Card,LocalID CurrentDB,bool_t TmpDb,void** Db,int* Id)
|
|
{
|
|
void* Module = NULL;
|
|
char Name[48];
|
|
UInt32 Type;
|
|
UInt16 Attr;
|
|
Boolean MemDup = 0;
|
|
Boolean MemSema = 0;
|
|
int No;
|
|
|
|
DmDatabaseInfo(Card,CurrentDB,Name,&Attr,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&Type,NULL);
|
|
if ((Type >> 24) != 'X')
|
|
{
|
|
if (TmpDb)
|
|
DmDeleteDatabase(Card,CurrentDB);
|
|
return NULL;
|
|
}
|
|
|
|
*Id = Type;
|
|
|
|
#ifdef ARM
|
|
{
|
|
UInt32 Version;
|
|
FtrGet(sysFtrCreator, sysFtrNumROMVersion, &Version);
|
|
MemSema = (Boolean)(Version < sysMakeROMVersion(6,0,0,sysROMStageDevelopment,0));
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_PALMONE_SDK
|
|
// duplicate plugins to memory with NVFS, because writing back reallocation
|
|
// causes the plugins to disappear sometimes from storage flash memory.
|
|
if (!MemSema) // but don't care if can use memory semaphore
|
|
{
|
|
UInt32 Version;
|
|
if (FtrGet(sysFtrCreator,sysFtrNumDmAutoBackup,&Version)==errNone && Version==1)
|
|
MemDup = 1;
|
|
}
|
|
#endif
|
|
|
|
if (TmpDb)
|
|
{
|
|
Attr |= dmHdrAttrRecyclable;
|
|
DmSetDatabaseInfo(Card,CurrentDB,NULL,&Attr,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
|
|
}
|
|
|
|
*Db = DmOpenDatabaseByTypeCreator(Type,Context()->ProgramId,dmModeReadOnly);
|
|
if (*Db)
|
|
{
|
|
for (No=0;No<FTRID_COUNT;++No)
|
|
if (!Modules[No])
|
|
break;
|
|
|
|
if (No<FTRID_COUNT)
|
|
{
|
|
Module = PealLoadModule((UInt16)(FTRID_START+No*FTRID_STEP),
|
|
MemDup,(Boolean)Context()->LowMemory,MemSema);
|
|
|
|
if (Module)
|
|
{
|
|
void* Register = PealGetSymbol(Module,T("DLLRegister"));
|
|
if (Register)
|
|
{
|
|
int Result = ((int(*)(int))Register)(CONTEXT_VERSION);
|
|
if (Result != ERR_NONE)
|
|
{
|
|
Register = NULL;
|
|
if (Result == ERR_NOT_COMPATIBLE)
|
|
{
|
|
int n = tcslen(Name);
|
|
if (n>7 && tcsnicmp(Name+n-7,T(" plugin"),7)==0)
|
|
Name[n-7] = 0;
|
|
ShowError(0,ERR_ID,ERR_NOT_COMPATIBLE,Name);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!Register)
|
|
{
|
|
PealFreeModule(Module);
|
|
Module = NULL;
|
|
}
|
|
else
|
|
Modules[No] = Module;
|
|
}
|
|
}
|
|
|
|
if (!Module || MemDup)
|
|
{
|
|
DmCloseDatabase(*Db);
|
|
*Db = NULL;
|
|
}
|
|
}
|
|
|
|
return Module;
|
|
}
|
|
|
|
void* NodeLoadModule(const tchar_t* URL,int* Id,void** AnyFunc,void** Db)
|
|
{
|
|
void* Module = NULL;
|
|
UInt16 Card;
|
|
LocalID CurrentDB;
|
|
|
|
if (tcsncmp(URL,"mem",3)!=0)
|
|
{
|
|
uint16_t Vol;
|
|
const tchar_t* Path = VFSToVol(URL,&Vol);
|
|
if (Path && VFSImportDatabaseFromFile(Vol,Path,&Card,&CurrentDB)==errNone)
|
|
Module = LoadPlugin(Card,CurrentDB,1,Db,Id);
|
|
}
|
|
else
|
|
{
|
|
DmSearchStateType SearchState;
|
|
CurrentDB = 0;
|
|
if (DmGetNextDatabaseByTypeCreator(1, &SearchState, *Id, Context()->ProgramId, 1, &Card, &CurrentDB)==errNone)
|
|
Module = LoadPlugin(Card,CurrentDB,0,Db,Id);
|
|
}
|
|
|
|
return Module;
|
|
}
|
|
|
|
#endif
|