;*ADFSave
;---------
;Save an ADF/JFD image back to disc
;Entry:
; R0 - pointer to command tail / filename
; R1 - no. of parameters

;Exit:
; R12 - corrupt
#set autoflush_debug = 0

.Entry_ADFSave
 STMFD   R13!, {R1-R11, R14}
 LDR     R12, [R12, #0]

 MOV     R8, R0				;R8=filename
#if autoflush_debug == 1	;dark green
 MOV     R14, #&3400000
 MOV     R1, #(%01000000<<24) OR %10000000
 STR     R1, [R14]
#endif

 BL      hourglass_on 

 ADR     R0, Delta_write_callback	;clear any existing callbacks
 MOV     R1, R12
 SWI     XOS_RemoveTickerEvent
 ADR     R0, Entry_Auto_Flush
 SWI     XOS_RemoveCallBack
 
 LDRB    R1, [R12, #Type_Mounted - VARS]
 TEQ     R1, #Type_None			;is an image mounted?
 ADREQ   R0, Error_Disc_Empty		;NO,
 BEQ     _error				; |+ report an error

 TEQ     R1, #Type_APD			;is it an APD
 TEQNE   R1, #Type_JFD			;is it a JFD?
 BEQ     _use_deflate			;YES, needs to be compressed

 MOV     R1, R8				;filename
 MOV     R2, #O_FileType		;FCE - FileCoreFloppyImage
 LDR     R4, [R12, #ADF_Buffer_Address - VARS]	;start address
 LDR     R5, [R12, #ADF_Buffer_Length - VARS]
 ADD     R5, R5, R4			;end address
 MOV     R0, #10			;save block of memory to file and date stamp it
 SWI     XOS_File			;PRM2-35 save file
 MOVVC   R0, #0
 B       _exit_ADFSave

._error
 MOV     R1, #1 << 31
 ADDS    R1, R1, R1

._exit_ADFSave
#if autoflush_debug == 1	;green
 MOVVC   R14, #&3400000
 MOVVC   R1, #(%01000000<<24) OR %000011110000
 STRVC   R1, [R14]
#endif
 MOVVS   R4, R0
 MOVVC   R4, #0
 STRVCB  R4, [R12, #floppy_content_changed - VARS]

 BL      hourglass_off

 MOV     R0, #0
 STRB    R0, [R12, #flush_in_progress - VARS]
 MOVS    R0, R4
 MOVNE   R1, #1 << 31
 ADDNES  R1, R1, R1
 LDMFD   R13!, {R1-R11, PC}


;Entry:
; R0 - filename pointer

 ._use_deflate
 MOV     R0, #Module_Claim
 MOV     R3, #streamCB.size		;claim space for stream control block
 SWI     XOS_Module			;PRM1-237
#if autoflush_debug == 1	;dark red
 MOVVS   R14, #&3400000
 MOVVS   R1, #(%01000000<<24) OR %00001000
 STRVS   R1, [R14]
#endif
 BVS     _error
 MOV     R11, R2			;R11=streamCB

 MOV     R3, #ZLib_BufferSize		;claim space for compression buffer
 SWI     XOS_Module			;PRM1-237
#if autoflush_debug == 1	;red
 MOVVS   R14, #&3400000
 MOVVS   R1, #(%01000000<<24) OR %00001111
 STRVS   R1, [R14]
#endif
 BVS     _error2
 MOV     R10, R2			;R10=compression buffer

 LDR     R0, [R12, #JFD_tmp - VARS + JFD_MinVersion]
 SUBS    R0, R0, #JFD_Supports_Autoflush	;does the mounted file support delta writes?
 BMI     _write_full			;NO

 LDR     R0, [R12, #Current_File_Mounted - VARS]
 TEQ     R8, R0				;do we already have the file mounted?
 BNE     _write_full			;NO, so it can't be a flush

 MOV     R1, #0				;calculate size of buffer required
 BL      _build_delta_tables		;R1=track table size in bytes
					;R2=sector table size in bytes
 TEQ     R2, #0				;do we have any delta data?
 BEQ     _no_delta_changes

 LDR     R1, [R12, #JFD_Tracks - VARS]
 LDR     R0, [R12, #JFD_Sectors - VARS]
 LDR     R2, [R12, #JFD_TrackSector_size - VARS]
 SUB     R1, R0, R1			;R1=track table size
 SUB     R2, R2, R1			;R2=sector table size

 STMFD   R13!, {R1-R2}			;update existing image via delta flush
 MOV     R0, #&CF			;open existing as read/write
 MOV     R1, R8				;filename
 SWI     XOS_Find
#if autoflush_debug == 1	;orange
 MOVVS   R14, #&3400000
 MOVVS   R1, #(%01000000<<24) OR %001010001111
 STRVS   R1, [R14]
#endif
 LDMFD   R13!, {R1-R2}
 BVS     _error3
 MOV     R9, R0				;R9=file handle

 LDR     R4, [R12, #JFD_tmp - VARS + JFD_Track_Delta]
 TEQ     R4, #0				;do we know the offset to the delta tables?
 BNE     _delta_table_exists		;YES

 STMFD   R13!, {R1-R2}			;NO, use the file extend
 MOV     R0, #2
 MOV     R1, R9
 SWI     XOS_Args
 MOV     R4, R2				;R4=offset to Delta Track Table in JFD
 LDMFD   R13!, {R1-R2}

#if debug_Delta == 1	;no Delta table
SWI XOS_WriteS
DCB "JFD has no Delta table", 0
ALIGN
SWI XOS_NewLine
#endif

 ADD     R5, R4, R1			;R5=Delta Track Table offset + Delta Track Table size
 ADD     R6, R5, R2			;R6=Delta Sector Table offset + Delta Sector Table size
 STR     R4, [R12, #JFD_tmp - VARS + JFD_Track_Delta]
 STR     R5, [R12, #JFD_tmp - VARS + JFD_Sector_Delta]
 STR     R6, [R12, #JFD_tmp - VARS + JFD_Data_Delta]
 ._delta_table_exists
#if debug_Delta == 1	;table file offset
SWI XOS_WriteS
DCB "Delta table file offset: ", 0
ALIGN
STMFD R13!, {R1}
MOV R1, R4
BL outputHexTruncated
LDMFD R13!, {R1}
SWI XOS_NewLine
#endif
 BL      _write_header			;overwrite the header
#if autoflush_debug == 1	;yellow
 MOVVS   R14, #&3400000
 MOVVS   R1, #(%01000000<<24) OR %000011111111
 STRVS   R1, [R14]
#endif
 BVS     _error4

 MOV     R0, #1				;seek to JFD_Track_Delta in open file
 MOV     R1, R9
 LDR     R2, [R12, #JFD_tmp - VARS + JFD_Track_Delta]
 SWI     XOS_Args

 LDR     R0, [R12, #JFD_Tracks - VARS]
 LDR     R1, [R12, #JFD_TrackSector_size - VARS]
 BL      _deflate			;compress the delta track/sector tables
#if autoflush_debug == 1	;white
 MOVVS   R14, #&3400000
 MOVVS   R1, #(%01000000<<24) OR %111111111111
 STRVS   R1, [R14]
#endif
 BVS     _error4
 BL      _write_buffer
#if autoflush_debug == 1	;magenta
 MOVVS   R14, #&3400000
 MOVVS   R1, #(%01000000<<24) OR %111100001111
 STRVS   R1, [R14]
#endif
 BVS     _error4

 MOV     R1, #2
 BL      _build_delta_tables		;store delta data
#if autoflush_debug == 1	;blue
 MOVVS   R14, #&3400000
 MOVVS   R1, #(%01000000<<24) OR %111100000000
 STRVS   R1, [R14]
#endif
 BVS     _error4
 BL      _write_final_buffer		;write what's left in the buffer
#if autoflush_debug == 1	;cyan
 MOVVS   R14, #&3400000
 MOVVS   R1, #(%01000000<<24) OR %111111110000
 STRVS   R1, [R14]
#endif
 BVS     _error4
 B       _exit_ADFSave


._no_delta_changes
 BL      _free_allocations
 B       _exit_ADFSave


;Entry:
; R1  = 0 to calculate sizes
;       2 to write sector data to the JFD
; R2  = address to build table (if R1=0)
; R11 = streamCB if R1=2
; R12 = VARS pointer
;
;Exit:
; if R1=0 or 1
;   R1=track table size in bytes
;   R2=sector table size in bytes
; if R2=2
;   Delta Sector data is written to file


._build_delta_tables
 STMFD   R13!, {R3-R10, R14}

 LDR     R10, [R12, #JFD_Tracks - VARS]		;track info pointer
 LDR     R5, [R12, #JFD_Sectors - VARS]		;sector info pointer
 MOV     R4, #0					;R4=size of sector table
 MOV     R8, #0					;R8=Delta Table offset
 MOV     R6, #0					;R6=% processed (0-25730)>>8
 ._build_delta_tracks
   ADD     R6, R6, #((99<<8) DIV 160)+1
   LDR     R0, [R10], #4			;R0=offset into Sector table
   CMN     R0, #1				;does sector info exist for this track?
   BEQ     _next_track				;NO

   ADD     R0, R0, R5				;R0=pointer to sector info
   MOV     R9, #0				;R9=0 if no sectors changed for this track
   ._build_delta_sectors
     LDR     R3, [R0], #8
     CMN     R3, #1				;last sector?
     BEQ     _last_sector			; |+  go to next track

     TST     R3, #bit_delta_write		;is this sector a delta change?
     BEQ     _build_delta_sectors		;NO

     ADD     R4, R4, #8				;YES, increase size of delta sector table
     MOV     R9, #1				;and note that there are delta sectors
     TEQ     R1, #2				;are we writing the Delta Data?
     BNE     _build_delta_sectors

     STMFD   R13!, {R0-R1}
     MOV     R0, R6, LSR #8
     BL      hourglass_percentage
     LDMFD   R13, {R0}

     LDR     R1, [R0, #-4]			;R1=offset to data
     LDR     R0, [R12, #ADF_Buffer_Address - VARS]
     ADD     R0, R0, R1				;R0=start of buffer
     AND     R14, R3, #%1111			;sector size bits
     ADD     R14, R14, #7
     MOV     R3, #1
     MOV     R1, R3, LSL R14			;R1=size in bytes
     BL      _deflate				;write delta track / delta sector
     ADDVS   R13, R13, #4			;drop R0
     LDMVSFD R13!, {R1, R3-R10, PC}
     LDMFD   R13!, {R0-R1}
   B       _build_delta_sectors

   ._last_sector
   TEQ     R9, #0				;are there delta sectors for this track?
   ADDNE   R4, R4, #4				;YES, so we'll need a terminator on the sector list

   ._next_track
   CMP     R10, R5				;last track?
 BNE     _build_delta_tracks

 TEQ     R1, #0					;calc table size?
 TEQEQ   R4, #0					;did we find any delta changes?
 MOVEQ   R2, #0
 LDRNE   R10, [R12, #JFD_Tracks - VARS]		;track info pointer
 LDRNE   R5, [R12, #JFD_Sectors - VARS]		;sector info pointer
 SUBNE   R1, R5, R10				;R1=size of track table
 MOVNE   R2, R4
 LDMFD   R13!, {R3-R10, PC}


._write_full
 MOV     R0, #&8F				;create empty file
 MOV     R1, R8					;filename
 SWI     XOS_Find				;create file
 BVS     _error3
 MOV     R9, R0					;R9=file handle

 LDRB    R0, [R12, #flush_in_progress - VARS]
 TEQ     R0, #0					;is this an auto-flush?
 BNE     _1st_time_flush			;YES
 STR     R0, [R12, #JFD_tmp - VARS + JFD_Release]	;NO, clear the release/modified values
 STR     R0, [R12, #JFD_tmp - VARS + JFD_Track_Delta]
 STR     R0, [R12, #JFD_tmp - VARS + JFD_Sector_Delta]
 STR     R0, [R12, #JFD_tmp - VARS + JFD_Data_Delta]

 LDR     R0, [R12, #JFD_tmp - VARS + JFD_MinVersion]
 SUBS    R0, R0, #JFD_Supports_Autoflush	;does the mounted file support delta writes?
 MOVMI   R0, #0					;NO, we're recreating the file, so clear the delta flags
 STRMIB  R0, [R12, #flush_in_progress - VARS]
 ._1st_time_flush

 BL      _write_header
 BVS     _error4
 LDR     R5, [R12, #JFD_Sectors - VARS]		;R5=sector table pointer
 LDR     R7, [R12, #ADF_Buffer_Address - VARS]	;R7=Data pointer
 LDR     R3, [R12, #JFD_Tracks - VARS]		;R0=track table pointer
 LDR     R1, [R12, #JFD_TrackSector_size - VARS]	;R1=size of Track+Sector tables

 LDRB    R14, [R12, #flush_in_progress - VARS]
 TEQ     R14, #0				;flush?
 BNE     _skip_delta_reset			;YES

 ADD     R4, R1, R3				;R4=R1-(R5-R3)
 SUB     R4, R4, R5				;R4=size of sector table
 MOV     R2, R5					;R2=pointer to sector list
 ._reset_delta_L1
   LDR      R0, [R2], #4
   CMN      R0, #1				;end of track?
   SUBEQ    R4, R4, #4
   BEQ      _reset_delta_P1

   TST      R0, #bit_delta_write		;clear delta write bit
   BICNE    R0, R0, #bit_delta_write		;NO, clear delta bit
   STRNE    R0, [R2, #-4]
   ADD      R2, R2, #4
   SUB      R4, R4, #8
   ._reset_delta_P1
   CMP      R4, #4				;stop at 0 or 4 (last word will be a terminator)
 BHI      _reset_delta_L1

 ._skip_delta_reset
 MOV     R0, R3
 BL      _deflate				;compress Track+Sector tables
 BVS     _error4

 ;now write the Data table
 LDR     R0, [R12, #JFD_tmp - VARS + JFD_Size]
 LDR     R1, [R12, #JFD_tmp - VARS + JFD_Data]
 LDR     R2, [R12, #ADF_Buffer_Address - VARS]	;R2=Data
 SUB     R7, R0, R1				;R7=size of Data + obey file if it exists

 ; % = offset into data * 100 / R1]
 MOV     R6, R7					;R6=amount left
 MOV     R4, R7, LSR #10
 MOV     R1, #100<<16
 BL      full_flush_div				;R7=R1 DIV R4

 LDR     R0, [R12, #ADF_Buffer_Address - VARS]
 MOV     R4, #0					;R4=offset in Data
 ._full_flush_L1
   MOV     R14, R4, LSR #10
   MUL     R0, R14, R7
   MOV     R0, R0, LSR #16
   BL      hourglass_percentage

   ADD     R0, R2, R4				;start of block
   MOV     R1, R6				;size of block
   CMP     R1, #8*1024				;max we want to compress in one go
   MOVHI   R1, #8*1024
   ADD     R4, R4, R1				;track how far we've progressed
   BL      _deflate				;1 block
   BVS     _error4
   SUBS    R6, R6, R1				;reduce what's left
 BNE     _full_flush_L1

 BL      _write_final_buffer			;write what's left in the buffer
 BVS     _error4
 B       _exit_ADFSave

 

._write_header
 STMFD   R13!, {R14}
 MOV     R0, #Z_NO_COMPRESSION
 BL      _init_streamCB

 ADR     R0, _JFD_validation		;add the verification header
 MOV     R1, #4
 BL      _deflate
 LDMVSFD R13!, {PC}

 ADD     R0, R12, #JFD_tmp - VARS	;buffer address
 LDR     R3, [R0, #JFD_Release]		;update the modified count
 MOV     R2, R3, LSR #20		;R2=Major release
 EOR     R3, R3, R2, LSL #20		;clear major release
 ADD     R3, R3, #1			;increase minor version
 CMP     R3, #&100000			;has it wrapped?
 SUBHS   R3, R3, #1			;YES, cap
 ORR     R3, R3, R2, LSL #20		;put major release back
 STR     R3, [R0, #JFD_Release]

 MOV     R1, #module_version
 STR     R1, [R0, #JFD_MinVersion]	;need this version of ADFFS to load

 MOV     R1, #JFD_Header - 4
 BL      _full_flush			;compress the header
 LDMVSFD R13!, {PC}

 #if compile_RO == 311 
   MOV     R0, #Z_BEST_SPEED+4		;speed up on ARM2/3
 #else
   MOV     R0, #Z_BEST_COMPRESSION
 #endif
 BL      _init_streamCB
 LDMFD   R13!, {PC}


._full_flush
 STMFD   R13!, {R14}
 BL      _deflate
 LDMVSFD R13!, {PC}

 MOV     R0, R11
 MOV     R1, #Z_FINISH
 SWI     XZLib_Deflate
 TEQ     R0, #Z_OK
 TEQNE   R0, #Z_STREAM_END
 BLNE    _deflate_error
 LDMVSFD R13!, {PC}

 BL      _write_buffer
 MOV     R0, R11
 SWI     XZLib_DeflateEnd	;ask ZLib to free its RMA allocations
 LDMFD   R13!, {PC}


;entry:
; R0  - start of buffer to compress
; R1  - size
; R8  - filename
; R9  - file handle
; R10 - compression buffer
; R11 - streamCB
;exit:
; R0 - error or corrupt

._deflate
 STMFD   R13!, {R1-R2, R14}

 STR     R0, [R11, #streamCB.next_in]
 STR     R1, [R11, #streamCB.avail_in]

 ._deflate_L1
   MOV     R0, R11
   MOV     R1, #Z_NO_FLUSH
   SWI     XZLib_Deflate
   TEQ     R0, #Z_OK			;did the deflate partially complete
   TEQNE   R0, #Z_STREAM_END
   BLNE    _deflate_error		;NO, must have errored
   LDMVSFD R13!, {R1-R2, PC}

   LDR     R0, [R11, #streamCB.avail_out]
   TEQ     R0, #0			;is the output buffer full?
   BLEQ    _write_buffer
   LDMVSFD R13!, {R1-R2, PC}
   LDR     R14, [R11, #streamCB.avail_in]
   TEQ     R14, #0			;any data left?
 BNE     _deflate_L1			;YES
 LDMFD   R13!, {R1-R2, PC}
 


;exit:
; R0, R1, R2 - corrupt
._write_final_buffer
 STMFD   R13!, {R5, R14}

 ._write_final_buffer_L1
   MOV     R0, R11			;flush the stream
   MOV     R1, #Z_FINISH
   SWI     XZLib_Deflate		;YES
   TEQ     R0, #Z_OK			;did the deflate partially complete
   TEQNE   R0, #Z_STREAM_END		;NO, did it complete?
   BLNE    _deflate_error		; |+ must have errored
   MOVVC   R5, R0			;R5=ZLib status
   BLVC    _write_buffer
   LDMVSFD R13!, {R5, PC}
   TEQ     R5, #Z_STREAM_END		;did the deflate partially complete
 BNE     _write_final_buffer_L1		;YES

 BL      _full_flush
 BL      _close_file
 BL      _free_allocations

 MOV     R0, #18			;set filetype
 MOV     R1, R8				;filename
 MOV     R2, #O_FileType
 SWI     XOS_File			;PRM2-36
 MOV     R0, #9				;date stamp file
 MOV     R1, R8				;filename
 SWI     XOS_File			;PRM2-36
 LDMFD   R13!, {R5, PC}


._free_allocations
 STR     R14, [R13, #-4]!
 MOV     R0, #Module_Free		;free claimed space
 MOV     R2, R10
 SWI     XOS_Module			;PRM1-238
 MOV     R2, R11
 SWI     XOS_Module			;PRM1-238
 LDR     PC, [R13], #4



; flush the write buffer back to disc
;exit:
; R0, R1, R2 - corrupt
._write_buffer
 STMFD   R13!, {R3-R4, R14}
 LDR     R0, [R11, #streamCB.next_out]
 SUBS    R3, R0, R10			;anything to write?
 LDMEQFD R13!, {R3-R4, PC}			;NO

 MOV     R0, #2				;write stream data
 MOV     R1, R9				;file handle
 MOV     R2, R10			;buffer address
 SWI     XOS_GBPB

 LDMFD   R13!, {R3-R4, R14}

._reset_streamCB
 STR     R10, [R11, #streamCB.next_out]	;reset output buffer
 MOV     R0, #ZLib_BufferSize
 STR     R0, [R11, #streamCB.avail_out]
MOV     PC, R14

._close_file
 STR     R14, [R13, #-4]!

 MOV     R0, R11
 SWI     XZLib_DeflateEnd		;finalise the stream

 MOV     R0, #0
 MOV     R1, R9				;file handle
 SWI     XOS_Find
 LDR     PC, [R13], #4


; R0=compression method
; R10=compression buffer
; R11=streamCB
._init_streamCB
 STMFD   R13!, {R14}
 MOV     R5, R0

 MOV     R0, R11
 ADD     R1, R0, #streamCB.size
 BL      ZeroBlock
 BL      _reset_streamCB

 SWI     XZLib_Version			;get the ZLib version string
 MOV     R6, R0
 MOV     R0, R11
 MOV     R1, R5
 MOV     R2, #Z_DEFLATED
 #if compile_RO == 311 
   MOV     R3, #12+16			;reduce RMA requirement under RO 3.11
   MOV     R4, #2
 #else
   MOV     R3, #15+16
   MOV     R4, #9
 #endif
 MOV     R5, #Z_DEFAULT_STRATEGY
 MOV     R7, #streamCB.size
 SWI     XZLib_DeflateInit2
 LDMFD   R13!, {PC}


 ._deflate_error
 MOV     R0, #1<<31
 ADDS    R0, R0, R0			;set V
 ADR     R0, Error_ZLib
 MOV     PC, R14
 
 ._error4
 MOV     R4, R0
 BL      _close_file
 MOV     R0, R4

 ._error3
 MOV     R4, R0				;free claimed space
 MOV     R0, #Module_Free
 MOV     R2, R10
 SWI     XOS_Module			;PRM1-238
 B       _error2_P1

 ._error2
 MOV     R4, R0				;free claimed space
 MOV     R0, #Module_Free
 ._error2_P1
 MOV     R2, R11
 SWI     XOS_Module			;PRM1-238
 MOV     R0, R4
 B       _error

 ._JFD_validation	DCB "JFDI"

.full_flush_div
 TEMP    R0
 oDIV    R7, R1, R4
 LOCK    R0
MOV     PC, R14