Page 1 of 1

ADFLib and PureBASIC

Posted: Mon Jun 02, 2014 1:42 pm
by djes
A friend just bought a Gotek USB drive for his Amiga, allowing him to replace his defective floppy drive. The software actually just recognised ADF or DMS files, so executable intros or demos running from a shell would need some file manipulation.

He asked me to make a tool to create autoboot adf files to launch automatically these files, from his large collection of demos and intros.

I found the nice ADFLib from Laurent Clevy, but had some problems with the adflib.dll I found on the internet, so I downloaded the source and built the needed static lib thanks to the great Dev-C++ by BloodSheedSoftware. I converted some headers to use it directly from PureBASIC.

The result is a little example on using the ADFLib in PureBASIC.

The static library is included so anybody should be able to use it directly in PureBASIC. Just inspire yourself with the included source.

I've not converted all headers and functions, but it wouldn't be too difficult.

Here you can found the whole zip package : http://www.pbfrance.com/?url=source&cmd=viewer&val=29

Below the example source.

Code: Select all

;*****************************************************************************
;
; ADFLib for PureBASIC example
; Creates ADF files from a master and copy exe files from a source directory.
;
; (C)opyright J. Benoist (djes) on 2014
;
; ADFLib documentation is in the main ADFlib-master directory.
;
; Notes :
;   Beware of non-checked headers !
;   C sources modified strdup->_strdup to avoid msvcrt dependancy
;   Static library .a created, no dll needed.
;
;*****************************************************************************

IncludeFile "incpb\adf_str.pbi"
IncludeFile "incpb\adf_blk.pbi"

EnableExplicit

Import "adflib.a"
	adfEnvInitDefault()
	adfEnvCleanUp()
	
	adfInstallBootBlock(*vol,*code)       ;PREFIX RETCODE adfInstallBootBlock(struct Volume *vol,uint8_t*);
	adfMount(*dev, nPart.i, readOnly.i)   ;PREFIX struct Volume* adfMount( struct Device *dev, int nPart, BOOL readOnly );
	adfUnMount(*vol)                      ;PREFIX void adfUnMount(struct Volume *vol);
	adfVolumeInfo(*vol)                   ;PREFIX void adfVolumeInfo(struct Volume *vol);
	
	adfMountDev(filename$, readOnly.i)    ;PREFIX struct Device* adfMountDev( char* filename,BOOL ro);
	adfUnMountDev(*dev)                   ;PREFIX void adfUnMountDev( struct Device* dev);
	adfCreateFlop(*dev, volName$, volType.l);PREFIX RETCODE adfCreateFlop(struct Device* dev, char* volName, int volType );
	adfDeviceInfo(*dev)                   ;PREFIX void adfDeviceInfo(struct Device *dev);
	
	adfCreateDumpDevice(filename$, cylinders.l, heads.l, sectors.l);PREFIX struct Device* adfCreateDumpDevice(char* filename, int32_t cyl, int32_t heads, int32_t sec); 
	
	adfToRootDir(*vol)                    ;PREFIX RETCODE adfToRootDir(struct Volume *vol);
	adfCreateDir(*vol, parent.l, name$)   ;PREFIX RETCODE adfCreateDir(struct Volume* vol, SECTNUM parent, char* name);
	adfChangeDir(*vol, name$)             ;PREFIX RETCODE adfChangeDir(struct Volume* vol, char *name);
	adfParentDir(*vol)                    ;PREFIX RETCODE adfParentDir(struct Volume* vol);
	adfRemoveEntry(*vol, parent.l, name$) ;PREFIX RETCODE adfRemoveEntry(struct Volume *vol, SECTNUM pSect, char *name);
	adfGetDirEnt(*vol, parent.l )         ;PREFIX struct List* adfGetDirEnt(struct Volume* vol, SECTNUM nSect );
	adfGetRDirEnt(*vol, parSect.l, recurs.l ); PREFIX struct List* adfGetRDirEnt(struct Volume* vol, SECTNUM nSect, BOOL recurs );   
	printEntry(*entry)                    ;PREFIX void printEntry(struct Entry* entry);
	adfFreeDirList(*list)                 ;PREFIX void adfFreeDirList(struct List* List);
	adfFreeEntry(*Entry)                  ;PREFIX void adfFreeEntry(struct Entry *);
	adfRenameEntry(*vol, oldDir.l, old$, newDir.l, new$)  ;PREFIX RETCODE adfRenameEntry(struct Volume *vol, SECTNUM, char *old,SECTNUM,char *pNew);
	adfSetEntryAccess(*Volume, parent.l, name$, newAcc.l) ;PREFIX RETCODE adfSetEntryAccess(struct Volume*, SECTNUM, char*, int32_t);
	adfSetEntryComment(*vol, parSect.l, name$, newCmt$)   ;PREFIX RETCODE adfSetEntryComment(struct Volume*, SECTNUM, char*, char*);
	
	adfOpenFile(*vol, name$, mode$)       ;PREFIX struct File* adfOpenFile(struct Volume *vol, char* name, char *mode);
	adfFlushFile(*file)                   ;PREFIX void adfFlushFile(struct File *file);
	adfCloseFile(*file)                   ;PREFIX void adfCloseFile(struct File *file);
	adfFileRealSize(size.l, blockSize.l, *dataN, *extN);PREFIX int32_t adfFileRealSize(uint32_t size, int blockSize, int32_t *dataN, int32_t *extN);
	adfReadFile(*file, n.l, *buffer)      ;PREFIX int32_t adfReadFile(struct File* file, int32_t n, uint8_t *buffer);
	adfEndOfFile(*file)                   ;PREFIX BOOL adfEndOfFile(struct File* file);
	adfWriteFile(*file, n.l, *buffer)     ;PREFIX int32_t adfWriteFile(struct File *file, int32_t n, uint8_t *buffer);
	adfFileSeek(*file, pos.l)             ;PREFIX void adfFileSeek(struct File *file, uint32_t pos);
EndImport

;*****************************************************************************

Procedure TheEnd(Msg$)
	MessageRequester("Error", Msg$, #PB_MessageRequester_Ok)
	End
EndProcedure

;*****************************************************************************

Define ExeFilename$, Dest$

ExeFilename$ = OpenFileRequester("Please choose some exe files","","Exe files|*.exe|All files|*.*", 0, #PB_Requester_MultiSelection)
If ExeFilename$ = ""
	TheEnd("No file selected...")
EndIf
Dest$ = PathRequester("Please select ADFs destination directory", GetPathPart(ProgramFilename()))
If Dest$ = ""
	TheEnd("No destination choosen...")
EndIf

While ExeFilename$
	
	Debug "---------------------------------------"
	Debug "Processing file " + ExeFilename$
	Debug "  to dir " + Dest$
	
	Define *dev.Device, *vol.Volume
	Define NewADFFilename$
	Define *file.File, Length.l, *MemoryID, bytes.l, written.l
	
	NewADFFilename$ = Dest$ + GetFilePart(ExeFilename$) + ".adf" : Debug "New ADF file to create : " + NewADFFilename$
	
	If CopyFile("MasterA500-1200.adf", NewADFFilename$)
		
		;Master could also be created with things like this, but it wouldn't be so easily customisable by user.
		;*dev = adfCreateDumpDevice("newfloppy.adf", 80, 2, 11)
		;adfCreateFlop(*dev, "empty", #FSMASK_DIRCACHE )
		
		Debug "Copying master file"
			
		adfEnvInitDefault()
		*dev.Device = adfMountDev(NewADFFilename$ , #False);
		*vol.Volume = adfMount(*dev, 0, #False);
		adfRemoveEntry(*vol, *vol\curDirPtr, "Intro.exe") : Debug "Removing original intro.exe file"
		*file = adfOpenFile(*vol, "Intro.exe", "w") : Debug "Creating new intro.exe"
		
		If *file <> 0	
			If ReadFile(0, ExeFilename$) : Debug "Opening original exe file"
				Length = Lof(0)                            ; Lit la taille en octets du fichier 
				If Length <> 0
					*MemoryID = AllocateMemory(Length) : Debug "Allocating exe memory : " + Str(Length) + " bytes"
					If *MemoryID
						bytes = ReadData(0, *MemoryID, Length) : Debug "Copying exe from original path"
						If bytes <> 0
							written = adfWriteFile(*file, Length, *MemoryID) : Debug "... to ADF."
							If written <> bytes
								MessageRequester("Error", "Something wrong occured while writing " + ExeFilename$ + " in the ADF", #PB_MessageRequester_Ok)
						  EndIf
						Else
							MessageRequester("Error", "Can't read " + ExeFilename$ + " content", #PB_MessageRequester_Ok)
						EndIf
					Else
						MessageRequester("Error", "Can't allocate " + Str(Length) + " bytes for " + ExeFilename$, #PB_MessageRequester_Ok)
					EndIf
				Else
					MessageRequester("Error", ExeFilename$ + " is empty...", #PB_MessageRequester_Ok)
				EndIf
			Else
				MessageRequester("Error", "Can't open " + ExeFilename$, #PB_MessageRequester_Ok)
			EndIf					
			adfCloseFile(*file)
		Else
			MessageRequester("Error", "Can't create Intro.exe in the " + GetFilePart(ExeFilename$) + " adf file", #PB_MessageRequester_Ok)
		EndIf			
		
		adfUnMount(*vol)
		adfUnMountDev(*dev)
		
	Else
		TheEnd("Can't copy master file 'MasterA500-1200.adf' to '" + ExeFilename$ + ".ADF'")
	EndIf
	adfEnvCleanUp()
	
	ExeFilename$ = NextSelectedFileName()
Wend

Debug "--- END"

MessageRequester("Information", "Done.", #PB_MessageRequester_Ok)

End
;--- Feel free to try these others functions
; *cell.List = adfGetDirEnt(*vol, *vol\curDirPtr);
; *List = *cell
; While *cell
;   *Entry.Entry = *cell\content
;   If *Entry\type = #ST_DIR
;     Debug *Entry\name$ + "/"
;   Else
;     Debug *Entry\name$
;     If *Entry\name$ = "Intro.exe"
;       adfRemoveEntry(*vol, *vol\curDirPtr, *Entry\name$)
;       adfRenameEntry(*vol, *vol\curDirPtr, *Entry\name$, *vol\curDirPtr, "Test")
;       *file.File = adfOpenFile(*vol, *Entry\Name$, "rw");
;       adfFlushFile(*file)
;       adfCloseFile(*file)
;     EndIf
;   EndIf
;   *cell = *cell\Next;
; Wend
;               
; adfFreeDirList(*List);
; 

Re: ADFLib and PureBASIC

Posted: Thu Jun 05, 2014 12:37 pm
by Frontier
Nice work djes, thank you very much for your effors :)

Re: ADFLib and PureBASIC

Posted: Mon Jun 09, 2014 8:37 pm
by Flype
Looks good, Thank you djes.

I will have a close look at it.

Re: ADFLib and PureBASIC

Posted: Fri Jun 13, 2014 10:41 pm
by gally
Thank you, Djes.

GallyHC