;****** Auto-Revision Header (do not edit) *******************************
;*
;* © Copyright by PetiWare
;*
;* Filename         : PatchEm.asm
;* Created on       : 24-Jan-93
;* Created by       : Peter Simons
;* Current revision : V0.004
;*
;*
;* Purpose: Patched ein altes File zu einem neuen um, unter Verwendung
;*          der mit MakePatch erstellten Daten.
;*
;*
;* V0.004 : Nachdem das gepatchte File erzeugt wurde, wird ebenfalls die
;*          CRC-Prüfsumme verglichen, um Fehler zu vermeiden!
;*
;* V0.003 : Nach dem Laden wird die OriginalCRC mit der im PatchFile
;*          angegebenen verglichen und bei Verschiedenheit abgebrochen!
;*
;* V0.002 : Patch'Em auf das neue FileFormat umgestellt.
;*
;* V0.001 : Basiert auf dem Programmgerüst von MakePatch.
;*
;* V0.000 : --- Initial release ---
;*
;*************************************************************************
;
;
;

;***************************************************************************
;*                                                                         *
;* SEKTION: Labels, Macros, Switches, Structures                           *
;*                                                                         *
;***************************************************************************

;-------------------------------------- Switches -----------
                MC68000
                NEWSYNTAX
                EXEOBJ
                OBJFILE "RAM:PatchEm"
                DEBUG on
                SYM
                MULTIPASS
;               VERBOSEOPTIM

;-------------------------------------- Structures --------
PatchChunk      CLRSO
pc_DataType     SO.w    1
pc_ChunkLen     SO.l    1
pc_ChunkData    SOVAL
pc_SIZEOF       SOVAL

PatchFile       CLRSO
pf_PatchedSize  SO.l    1
pf_OrigCRC      SO.w    1
pf_PatchedCRC   SO.w    1
pf_PatchData    SOVAL

;-------------------------------------- Labels ------------
                MACLIB  "DATAS:Includes.preass"
                MACLIB  "DATAS:Offsets.preass"
                MACFILE "A:Sources/PetiToolLibrary/PToolLibrary.i"

KICKVERSION     equ     37

;-------------------------------------- Datatypes ---------
DT_NOMOREDATA   equ     0
DT_ORIGINAL     equ     1
DT_PATCHED      equ     2
DT_SKIPPED      equ     3
DT_INSERTED     equ     4

;-------------------------------------- Macros ------------
REVISION        MACRO
                dc.b "0.004"
                ENDM
REVDATE         MACRO
                dc.b "11-Feb-93"
                ENDM
PUSHM           MACRO
saveregs        setrl   \1
                movem.l saveregs,-(SP)
                ENDM
POPM            MACRO
                movem.l (SP)+,saveregs
                ENDM


;***************************************************************************
;*                                                                         *
;* SEKTION: Programm                                                       *
;*                                                                         *
;***************************************************************************

;---------------------- Systemumgebung initialisieren ---------------------
START:          lea     (DATA_Seg,PC),a5
                BASEREG a5,DATA_Seg

                lea     (ptoollibname,PC),a1
                moveq   #1,d0
                move.l  ($4).W,a6
                jsr     (_LVOOpenLibrary,a6)
                move.l  d0,(_PToolBase)
                bne.b   .PToolLibOkay
                bsr     _NoPToolLibrary
                bra     .Exit
.PToolLibOkay   move.l  d0,a6
                move.l  (ptl_DOSBase,a6),(_DOSBase)

                move.l  #CCF_OS_VERSION,d0
                move.w  #KICKVERSION,d1
                jsr     (_LVOCheckConfig,a6)
                tst.l   d0
                beq.b   .ConfigOkay
                lea     (PrgName,PC),a0
                moveq   #0,d2
                jsr     (_LVODisplayConfigErrorDos,a6)
                bra     .ClosePToolLib
.ConfigOkay
;------------------------------ Argument-Parsing --------------------------
                lea     (RDArgsTemplate,PC),a0
                move.l  a0,d1
                lea     (_Original,PC),a0
                move.l  a0,d2
                moveq   #0,d3
                move.l  (_DOSBase,PC),a6
                jsr     (_LVOReadArgs,a6)
                move.l  d0,(_RDArgsStruct)
                bne.b   .RDArgsOkay
                moveq   #0,d0
                moveq   #0,d1
                lea     (PrgName,PC),a0
                move.l  (_PToolBase,PC),a6
                jsr     (_LVOErrorHandleDos,a6)
                bra     .ClosePToolLib
.RDArgsOkay
;----------------------------- Puffer reservieren -------------------------
                move.l  (_Original,PC),a0
                move.l  (_PToolBase,PC),a6
                jsr     (_LVOLoadFile,a6)
                move.l  d0,(_SourceBuffer)
                bne.b   .SourceOkay
                moveq   #1,d0
                move.l  (_Original,PC),-(SP)
                move.l  SP,a1
                bsr     _ErrorHandle
                addq.w  #4,SP
                bra     .FreeRDArgs

.SourceOkay     move.l  (_PatchFile,PC),a0
                jsr     (_LVOLoadFile,a6)
                move.l  d0,(_PatchBuffer)
                bne.b   .PatchOkay
                moveq   #1,d0
                move.l  (_NewVersion,PC),-(SP)
                move.l  SP,a1
                bsr     _ErrorHandle
                addq.w  #4,SP
                bra     .FreeTargetBuffer

.PatchOkay      move.l  (_PatchBuffer,PC),a0
                move.l  (4+pf_PatchedSize,a0),d2
                move.l  d2,d0
                move.l  #MEMF_PUBLIC,d1
                move.l  ($4).w,a6
                jsr     (_LVOAllocVec,a6)
                move.l  d0,(_TargetBuffer)
                bne.b   .TargetOkay
                moveq   #2,d0
                pea     (PublicMemStr,PC)
                move.l  d2,-(SP)
                move.l  SP,a1
                bsr     _ErrorHandle
                addq.w  #8,SP
                bra     .FreeSourceBuffer
.TargetOkay
;------------------------------- CRC vergleichen --------------------------
                move.l  (_SourceBuffer,PC),a0
                move.l  (a0)+,d0
                move.l  (_PToolBase,PC),a6
                jsr     (_LVOCRC16Buffer,a6)
                move.l  (_PatchBuffer,PC),a0
                cmp.w   (4+pf_OrigCRC,a0),d0
                beq.b   .SourceCRCOkay
                moveq   #11,d0
                pea     (SourceCRCFalse,PC)
                move.l  SP,a1
                bsr     _ErrorHandle
                addq.w  #4,SP
                bra     .FreeSourceBuffer
.SourceCRCOkay
;------------------------------ Patch erstellen ---------------------------
                move.l  (_SourceBuffer,PC),a0
                addq.w  #4,a0
                move.l  (_TargetBuffer,PC),a1
                move.l  (_PatchBuffer,PC),a2
                add.w   #pf_PatchData+4,a2
                bsr     _PatchData

;------------------------------- CRC vergleichen --------------------------
                move.l  (_PatchBuffer,PC),a0
                move.l  (4+pf_PatchedSize,a0),d0
                move.l  (_TargetBuffer,PC),a0
                move.l  (_PToolBase,PC),a6
                jsr     (_LVOCRC16Buffer,a6)
                move.l  (_PatchBuffer,PC),a0
                cmp.w   (4+pf_PatchedCRC,a0),d0
                beq.b   .TargetCRCOkay
                moveq   #11,d0
                pea     (TargetCRCFalse,PC)
                move.l  SP,a1
                bsr     _ErrorHandle
                addq.w  #4,SP
                bra     .FreeSourceBuffer
.TargetCRCOkay
;----------------------------- ZielPuffer speichern -----------------------
                move.l  (_NewVersion,PC),d1
                move.l  #MODE_NEWFILE,d2
                move.l  (_DOSBase,PC),a6
                jsr     (_LVOOpen,a6)
                ERRORHANDLE d5,0,(.FreePatchBuffer,PC)

                move.l  d5,d1
                move.l  (_TargetBuffer,PC),d2
                move.l  (_PatchBuffer,PC),a0
                move.l  (4+pf_PatchedSize,a0),d3
                move.l  (_PToolBase,PC),a6
                jsr     (_LVOSaveBreak,a6)
                cmp.l   #-1,d0
                bne.b   .CloseDestFile
                move.l  (_DOSBase,PC),a6
                jsr     (_LVOIoErr,a6)
                tst.l   d0
                bne.b   .SaveError
                bsr     _BreakError
.SaveError      moveq   #11,d0
                pea     (SaveError,PC)
                move.l  SP,a1
                bsr     _ErrorHandle
                addq.w  #4,SP

.CloseDestFile  move.l  d5,d1
                move.l  (_DOSBase,PC),a6
                jsr     (_LVOClose,a6)

;-------------------------- Systemumgebung freigeben ----------------------
.FreePatchBuffer:
                move.l  (_PatchBuffer,PC),a1
                move.l  ($4).w,a6
                jsr     (_LVOFreeVec,a6)

.FreeTargetBuffer:
                move.l  (_TargetBuffer,PC),a1
                move.l  ($4).w,a6
                jsr     (_LVOFreeVec,a6)

.FreeSourceBuffer:
                move.l  (_SourceBuffer,PC),a1
                move.l  ($4).w,a6
                jsr     (_LVOFreeVec,a6)

.FreeRDArgs     move.l  (_RDArgsStruct,PC),d1
                beq.b   .ClosePToolLib
                move.l  (_DOSBase,PC),a6
                jsr     (_LVOFreeArgs,a6)

.ClosePToolLib  move.l  (_PToolBase,PC),a1
                move.l  ($4).W,a6
                jsr     (_LVOCloseLibrary,a6)

.Exit           moveq   #0,d0
                rts

;***************************************************************************
;*                                                                         *
;* SEKTION: Unterroutinen                                                  *
;*                                                                         *
;***************************************************************************

;-------------------------------- Patchgeneration -------------------------
_PatchData:
                ; Erstellt aus dem Patch- und dem Originalfile das Zielfile.
                ;
                ; Parameter: A0=&Original A1=&Target A2=&PatchBuffer
                ; Result   : D0=PatchLength

                PUSHM   d2-d7/a2-a4/a6
                lea     (.DataTypeTab,PC),a3
                moveq   #0,d7

...             move.w  (pc_DataType,a2),d0
                beq.b   .exit
                lsl.w   #1,d0
                lea     (a3,d0.w),a4
                add.w   (a4),a4
                jsr     (a4)
                bra.b   ...


.exit           move.l  d7,d0
                POPM
                rts

.Original       move.l  (pc_ChunkLen,a2),d0
                addq.w  #pc_SIZEOF,a2
                bra     _CopyBlock

.Patched        rts                     ; Not supportet yet

.Skipped        add.l   (pc_ChunkLen,a2),a0
                addq.w  #pc_SIZEOF,a2
                rts

.Inserted       move.l  (pc_ChunkLen,a2),d0
                lea     (pc_ChunkData,a2),a2
                exg.l   a2,a0
                bsr     _CopyBlock
                exg.l   a2,a0
                btst    #0,d0
                beq.b   .NotOdd
                addq.w  #1,a2
.NotOdd         rts


.DataTypeTab    dc.w    0                       ; DT_NOMOREDATA
                dc.w    .Original-*             ; DT_ORIGINAL
                dc.w    .Patched-*              ; DT_PATCHED
                dc.w    .Skipped-*              ; DT_SKIPPED
                dc.w    .Inserted-*             ; DT_INSERTED

_CopyBlock:     move.l  d0,-(SP)
                beq.b   .exit
...             move.b  (a0)+,(a1)+
                subq.l  #1,d0
                bne.b   ...
.exit           move.l  (SP)+,d0
                rts



;-------------------------------- Fehlerhandhabung ------------------------
_BreakError:
                ; Gibt den "Received CTRL/C"-String aus
                ;
                ; Parameter: keine
                ; Result   : keins

                PUSHM   d0-d1/a0-a1/a6
                lea     (PrgName,PC),a0
                moveq   #0,d1
                moveq   #5,d0
                move.l  (_PToolBase,PC),a6
                jsr     (_LVOErrorHandleDos,a6)
                POPM
                rts

_ErrorHandle:
                ; Erzeut über ErrorHandleIntuition() die Fehlermeldung.
                ;
                ; Parameter: A1=&DataFlow D0=Errornumber
                ; Result   : keins

                PUSHM   d0-d1/a0-a2/a6
                lea     (PrgName,PC),a0
                sub.l   a2,a2
                move.l  (_PToolBase,PC),a6
                jsr     (_LVOErrorHandleIntuition,a6)
                POPM
                rts


_NoPToolLibrary:
                ; Gibt einen Fehler aus, falls die PTool.Library nicht ge-
                ; öffnet werden konnte.
                ;
                ; Parameter: keine
                ; Result   : keins

                lea     (dosname,PC),a1
                move.l  ($4).W,a6
                jsr     (_LVOOldOpenLibrary,a6)
                tst.l   d0
                beq.b   .exit
                move.l  d0,a6
                jsr     (_LVOOutput,a6)
                move.l  d0,d1
                beq.b   .CloseDosLib
                lea     (PrgName,PC),a0
                move.l  a0,d2
                moveq   #NoPToolError_len,d3
                jsr     (_LVOWrite,a6)
.CloseDosLib    move.l  a6,a1
                move.l  ($4).W,a6
                jsr     (_LVOCloseLibrary,a6)
.exit           rts



;***************************************************************************
;*                                                                         *
;* SEKTION: Daten                                                          *
;*                                                                         *
;***************************************************************************
DATA_Seg:
                dc.b    "$VER: "
PrgName         dc.b    "Patch'Em v"
                REVISION
                dc.b    " ("
                REVDATE
                dc.b    ")"
                dc.b    0
                dc.b    " requires the PTool.Library!!",$0A,$0A
NoPToolError_len equ (*-PrgName)

ptoollibname    CSTR    "ptool.library"
dosname         CSTR    "dos.library"
PublicMemStr    CSTR    "PublicMem"
RDArgsTemplate  CSTR    "Original/A,NewVersion/A,PatchFile/A"
PatchTooLong    CSTR    "Sorry, but the patch would have been longer, than the new-version!"
SaveError       CSTR    "File couldn't been saved succesfully!"
SourceCRCFalse  CSTR    "Sorry, but the patch wasn't made for that sourcefile!"
TargetCRCFalse  CSTR    "INTERNAL ERROR!! Please report to the author!"

                CNOP    0,4
_PToolBase      ds.l    1
_DOSBase        ds.l    1
_RDArgsStruct   ds.l    1
_SourceBuffer   ds.l    1
_TargetBuffer   ds.l    1
_PatchBuffer    ds.l    1

_Original       ds.l    1                       ; Array für ReadArgs()
_NewVersion     ds.l    1
_PatchFile      ds.l    1

                END
