__ATTR_LIB_C__ short LoadDLL(const char *DLL_name, long ID, short major, short minor) { SYM_ENTRY *entry; HANDLE h; unsigned char *bptr,*sptr; unsigned short len,offset=0,wrongver=0; unsigned long pc; unsigned long signature[]={__DLL_SIGNATURE,ID}; asm volatile("bsr 0f; 0:move.l (%%sp)+,%0":"=g"(pc)); if(HW_VERSION==2 && pc<0x40000) return DLL_NOTINGHOSTSPACE; if(__DLL_body_ptr) return DLL_ALREADYLOADED; entry=SymFindFirst(NULL,2); do { if(!strcmp(entry->name,DLL_name)&&entry->handle&&!entry->flags.bits.twin &&(entry->flags.bits.archived||!HeapGetLock(entry->handle))) { len=peek_w(bptr=HeapDeref(entry->handle))+2; if(!memcmp(bptr+len-5,"DLL\x00\xF8",5)) { offset=0; for(sptr=bptr+2;(sptr<bptr+len-1)&&!offset;sptr+=2) if(!memcmp(sptr,signature,8)) { if((unsigned short)major!=((__DLL_interface_struct*)sptr)->major ||(unsigned short)minor>((__DLL_interface_struct*)sptr)->minor) wrongver=1; else offset=sptr-bptr,wrongver=0; } if(offset) break; } } } while((entry=SymFindNext())); if(wrongver) return DLL_WRONGVERSION; if(!entry) return DLL_NOTFOUND; if(!HeapLock(h=entry->handle)) return DLL_LOCKFAILED; if(!(__DLL_body_ptr=malloc(len=peek_w(bptr=HeapDeref(h)+2)+2))) { HeapUnlock(h); return DLL_OUTOFMEM; } memcpy(__DLL_body_ptr,bptr,len); EX_patch((char*)__DLL_body_ptr+(HW_VERSION==2?0x40000:0)+2,(char*)__DLL_body_ptr+(HW_VERSION==2?0x40000:0)+len-1); __DLL_interface_ptr=(__DLL_interface_struct*)((char*)__DLL_body_ptr+offset-2); HeapUnlock(h); return DLL_OK; }
//assumes SongFolderExists short CountValidSongs(void) { if (SongCount) return SongCount; SYM_ENTRY *GrvSym; GrvSym = SymFindFirst(SONGFOLDER, FO_SINGLE_FOLDER); while (GrvSym) { if (isValidFile(GrvSym -> handle)) SongCount++; GrvSym = SymFindNext(); } return SongCount; }
//Loads SongHeaders with information needed for songselect menu //assumes SongFolderExists. //returns false if memory allocation fails. short LoadHeaders(void) { short GrvFileIndex = 0; short SongHeadersIndex = 0; unsigned short *shortPointer = NULL; GrvHeader *CurrSongHeader = NULL; SYM_ENTRY *GrvSym; MULTI_EXPR *GrvFile; SongHeaders = malloc(SongCount * sizeof(GrvHeader)); if (!SongHeaders) { return FALSE; } GrvSym = SymFindFirst(SONGFOLDER, FO_SINGLE_FOLDER); while (GrvSym) { GrvFile = HeapDeref(GrvSym -> handle); if (isValidFile(GrvSym -> handle)) { GrvFileIndex = 0; CurrSongHeader = &SongHeaders[SongHeadersIndex]; CurrSongHeader-> SongTitle = &GrvFile-> Expr[GrvFileIndex]; while (GrvFile-> Expr[GrvFileIndex]) GrvFileIndex++; GrvFileIndex++; CurrSongHeader-> SongArtist = &GrvFile-> Expr[GrvFileIndex]; while (GrvFile-> Expr[GrvFileIndex]) GrvFileIndex++; GrvFileIndex++; if (GrvFileIndex % 2) GrvFileIndex++; shortPointer = (unsigned short*)&GrvFile-> Expr[GrvFileIndex]; CurrSongHeader-> MinBPM = *shortPointer; GrvFileIndex += 2; shortPointer = (unsigned short*)&GrvFile-> Expr[GrvFileIndex]; CurrSongHeader-> MaxBPM = *shortPointer; GrvFileIndex += 2; shortPointer = (unsigned short*)&GrvFile-> Expr[GrvFileIndex]; CurrSongHeader-> ModeBPM = *shortPointer; GrvFileIndex += 2; shortPointer = (unsigned short*)&GrvFile-> Expr[GrvFileIndex]; CurrSongHeader-> DifficultyFlags = *shortPointer; GrvFileIndex += 2; CurrSongHeader-> DifficultyHeaders = (DifficultyHeader*)&GrvFile-> Expr[GrvFileIndex]; //determine number of difficulties by counting bits set //uses Brian Kernighan's method -- thanks! unsigned char DiffFlagsForCount = CurrSongHeader-> DifficultyFlags & 0xF800; unsigned char DiffCount; for (DiffCount = 0; DiffFlagsForCount; DiffCount++) { DiffFlagsForCount &= DiffFlagsForCount - 1; } GrvFileIndex += DiffCount * sizeof(DifficultyHeader); CurrSongHeader-> BPMListOffset = GrvFileIndex; SongHeadersIndex++; } GrvSym = SymFindNext(); } return TRUE; }