I threw this together, it might be useful for someone.
It works on two files as a differential patcher, up to about 1 GB of data (increase the two long variables for more space).
New features can be easily added, such as patching multiple files, integrity checking, diff file compression, etc.
Edit: Added 2 more functions, to generate and apply patches via memory.
Code: Select all
;----
;Patchdata File format
;byte: needs truncating
;long: current position
;long: number of replaced byte(s)
;byte(s): the actual replaced data
;----
;error codes
;0: success
;-1: old file not found
;-2 new file not found
;-3 patch file already exists
;----
Procedure.b GenPatch(oldfile.s, newfile.s, patchdata.s)
If FileSize(oldfile)<1
ProcedureReturn -1
EndIf
If FileSize(newfile)<1
ProcedureReturn -2
EndIf
If FileSize(patchdata)>0
ProcedureReturn -3
EndIf
Protected obyte.b, nbyte.b, bReplace.l, needTruncating.b, nrbpos.l, fpos.l
Protected curpos.l=-1
ReadFile(0,oldfile)
ReadFile(1,newfile)
OpenFile(2,patchdata)
FileSeek(2,1,#PB_Relative)
While Eof(0)=0
obyte=ReadByte(0)
If Eof(1)=0
nbyte=ReadByte(1)
If obyte<>nbyte
If curpos<0
curpos=Loc(0)-1
WriteLong(2,curpos)
nrbpos=Loc(2)
FileSeek(2,SizeOf(long),#PB_Relative)
EndIf
WriteByte(2,nbyte)
bReplace+1
Else
If curpos>-1
fpos=Loc(2)
FileSeek(2,nrbpos)
WriteLong(2,bReplace)
FileSeek(2,fpos)
EndIf
curpos=-1
bReplace=0
EndIf
Else
needTruncating=1
Break
EndIf
Wend
If curpos>-1
fpos=Loc(2)
FileSeek(2,nrbpos)
WriteLong(2,bReplace)
FileSeek(2,fpos)
bReplace=0
EndIf
If Eof(1)=0
WriteLong(2,Loc(0))
nrbpos=Loc(2)
FileSeek(2,SizeOf(long),#PB_Relative)
While Eof(1)=0
bReplace+1
WriteByte(2,ReadByte(1))
Wend
FileSeek(2,nrbpos)
WriteLong(2,bReplace)
EndIf
FileSeek(2,0)
WriteByte(2,needTruncating)
CloseFile(0)
CloseFile(1)
CloseFile(2)
ProcedureReturn 0
EndProcedure
Procedure Apply(oldfile.s, patchdata.s)
OpenFile(0,oldfile)
ReadFile(1,patchdata)
Protected needsTrunc=ReadByte(1)
Protected i, nrb.l
While Eof(1)=0
FileSeek(0,ReadLong(1))
nrb=ReadLong(1)
For i=1 To nrb
WriteByte(0,ReadByte(1))
Next
Wend
If needsTrunc
;FileSeek(0,-1,#PB_Relative)
TruncateFile(0)
EndIf
CloseFile(0)
CloseFile(1)
EndProcedure
Procedure.q GenerateMem(oldfile.s, newfile.s, BuffSize.q)
If FileSize(oldfile)<1
ProcedureReturn -1
EndIf
If FileSize(newfile)<1
ProcedureReturn -2
EndIf
Protected obyte.b, nbyte.b, bReplace.l, needTruncating.b, *nrbpos, *fpos, msize.q, *nbuff
Protected curpos.l=-1
Protected *pBuff=AllocateMemory(BuffSize)
If Not *pBuff
ProcedureReturn -3
EndIf
Protected *ptmp=*pbuff
ReadFile(0,oldfile)
ReadFile(1,newfile)
*ptmp+SizeOf(Byte)
msize+SizeOf(Byte)
While Eof(0)=0
obyte=ReadByte(0)
If Eof(1)=0
nbyte=ReadByte(1)
If obyte<>nbyte
If curpos<0
curpos=Loc(0)-1
PokeL(*ptmp,curpos)
*ptmp+SizeOf(Long)
msize+SizeOf(long)
*nrbpos=*ptmp
*ptmp+SizeOf(Long)
msize+SizeOf(long)
EndIf
PokeB(*ptmp,nbyte)
*ptmp+SizeOf(Byte)
msize+SizeOf(Byte)
bReplace+1
Else
If curpos>-1
*fpos=*ptmp
*ptmp=*nrbpos
PokeL(*ptmp,bReplace)
*ptmp=*fpos
EndIf
curpos=-1
bReplace=0
EndIf
Else
needTruncating=1
Break
EndIf
Wend
If curpos>-1
*fpos=*ptmp
*ptmp=*nrbpos
PokeL(*ptmp,bReplace)
*ptmp=*fpos
bReplace=0
EndIf
If Eof(1)=0
PokeL(*ptmp,Loc(0))
*ptmp+SizeOf(Long)
msize+SizeOf(long)
*nrbpos=*ptmp
*ptmp+SizeOf(Long)
msize+SizeOf(long)
While Eof(1)=0
bReplace+1
PokeB(*ptmp,ReadByte(1))
*ptmp+SizeOf(Byte)
msize+SizeOf(Byte)
Wend
*ptmp=*nrbpos
PokeL(*ptmp,bReplace)
EndIf
PokeB(*pBuff,needTruncating)
*nbuff=AllocateMemory(msize)
If *nbuff
CopyMemory(*pBuff,*nbuff,msize)
Else
CloseFile(0)
CloseFile(1)
FreeMemory(*pBuff)
ProcedureReturn -3
EndIf
FreeMemory(*pBuff)
CloseFile(0)
CloseFile(1)
ProcedureReturn *nbuff
EndProcedure
Procedure ApplyMem(oldfile.s, *patchdata)
OpenFile(0,oldfile)
Protected *pd=*patchdata
Protected pdsize=MemorySize(*patchdata)
Protected needsTrunc=PeekB(*pd)
*pd+SizeOf(Byte)
Protected i, nrb.l
While *pd<*patchdata+(pdsize-1)
FileSeek(0,PeekL(*pd))
*pd+SizeOf(long)
nrb=PeekL(*pd)
*pd+SizeOf(long)
For i=1 To nrb
WriteByte(0,PeekB(*pd))
*pd+SizeOf(byte)
Next
Wend
If needsTrunc
;FileSeek(0,-1,#PB_Relative)
TruncateFile(0)
EndIf
CloseFile(0)
FreeMemory(*patchdata)
EndProcedure