;ZIP_extract
;-----------
;Extracts a file from a ZIP into either memory or to disc

;Entry:
; R1 - ZIP filename
; R2 - file to extract
; R3 - filename to extract as
; R12 - pointer to VARS

.ZIP_extract
 STMFD   R13!, {R1-R11, R14}

 MOV     R0, #&4F			;open read only
 SWI     XOS_Find			;PRM2-78
 LDMVSFD R13!, {R1-R11, PC}		;file not found
 MOV     R11, R0			;R11=file handle
 MOV     R10, #0			;R10=current file pointer
 MOV     R9, #0				;R9=pointer to memory block

 MOV     R3, #Max_File_Length
 MOV     R0, #Module_Claim		;claim space for reading filenames
 SWI     XOS_Module			;PRM1-237
 BVS     _extract_failed		;claim failed
 STR     R2, [R12, #ZIP_workspace - VARS]
 ._L1
   BL      _get32			;get header
   EORS    R0, R0, #&04034B50		;ZIP file header?
   BNE     _extract_failed		;NO, file not found

   MOV     R0, #2+2+2+2+2+4
   BL      _skip			;skip to compressed size

   BL      _get32
   MOV     R6, R0			;R6=compressed size

   BL      _get32
   MOV     R7, R0			;R7=uncompressed size

   BL      _get16
   MOV     R8, R0			;R8=filename size

   BL      _get16
   MOV     R5, R0			;R5=extra field length

   MOV     R0, #4			;read from current pointer
   MOV     R1, R11			;file handle
   LDR     R2, [R12, #ZIP_workspace - VARS]
   MOV     R3, R8			;read the filename
   SWI     XOS_GBPB			;PRM2-69
   MOV     R10, R4			;update file pointer

   MOV     R0, R5
   BL      _skip			;skip the extra field

   LDR     R5, [R13, #1 * 4]		;pointer to file to search for (R2 on stack)
   LDR     R4, [R12, #ZIP_workspace - VARS]	;ZIP filename
   MOV     R3, R8			;length of file
   ._L2
     LDRB    R0, [R5], #1
     LDRB    R1, [R4], #1
     BIC     R0, R0, #32
     BIC     R1, R1, #32		;ignore case
     TEQ     R0, R1			;chars match?
     BNE     _wrong_file		;NO
     SUBS    R3, R3, #1			;last char?
   BNE     _L2				;NO

   LDRB    R0, [R5], #1
   CMP     R0, #32			;does the string match?
   BLS     _expand_file			;YES, extract it

   ._wrong_file
   MOV     R0, R6
   BL      _skip			;skip the compressed stream
 B       _L1


 ._expand_file
 ADD     R3, R6, R7			;space required to extract
 ADD     R3, R3, #56 + 7		;add some extra space for stream block
 BIC     R3, R3, #3			;align
 MOV     R0, #Module_Claim		;claim space
 SWI     XOS_Module			;PRM1-237
 BVS     _extract_failed		;claim failed
 MOV     R9, R2				;R9=pointer to space

 MOV     R0, #4				;read from current pointer
 MOV     R1, R11			;file handle
 ADD     R2, R9, #56			;use allocated space for data
 MOV     R3, R6				;read the compressed stream
 SWI     XOS_GBPB			;PRM2-69
 MOV     R10, R4			;update file pointer

 MOV     R1, #56 - 4			;clear streamCB
 MOV     R0, #0
 ._L3
   STR     R0, [R9, R1]
   SUBS    R1, R1, #4
 BNE     _L3

 ADD     R0, R9, #56
 STR     R0, [R9, #0]			;pointer to compressed data

 STR     R6, [R9, #4]			;available compressed data
 STR     R7, [R9, #16]			;available for uncompressed data

 ADD     R8, R0, R6			;R8=pointer to uncompressed data
 STR     R8, [R9, #12]			;next free for uncompressed data

 SWI     XZLib_Version			;get the ZLib version string
 MOV     R2, R0
 MOV     R0, R9
 MOV     R1, #-15
 MOV     R3, #56
 SWI     XZLib_InflateInit2		;initialise streamCB
 TEQ     R0, #0				;did init work?
 BNE     _extract_failed		;NO

 MOV     R0, R9
 MOV     R1, #Z_FINISH			;Z_FINISH
 SWI     XZLib_Inflate			;inflate the compressed stream
 MOV     R1, R0				;store the return code

 MOV     R0, R9
 SWI     XZLib_InflateEnd		;clear down ZLib
 TEQ     R1, #0				;did inflate work?
 TEQNE   R1, #1
 BNE     _extract_failed		;NO

 LDR     R1, [R13, #2 * 4]		;save filename (R3 on stack)
 MOV     R0, #&8F			;open for writing
 SWI     XOS_Find			;PRM2-78
 TEQ     R0, #0				;did we create the file?
 BEQ     _extract_failed		;NO

 MOV     R2, R8				;buffer address
 MOV     R3, R7				;length of Obey file
 MOV     R1, R0				;file handle
 MOV     R0, #2				;write from current pointer
 SWI     XOS_GBPB			;PRM2-68

 MOV     R0, #0
 SWI     XOS_Find			;close the file

 TEQ     R3, #0				;did the write succeed?
 BNE     _extract_failed
 BL      _close_down

 SUBS    R0, R0, R0			;clear V
 LDMFD   R13!, {R1-R11, PC}		;clear down stack


 ._extract_failed
 BL      _close_down

 MOV     R0, #1<<31
 ADDS    R0, R0, R0			;set V and return R0=error
 ADR     R0, Error_ExtractFailed
 LDMFD   R13!, {R1-R11, PC}		;file not found


 ._close_down
 STR     R14, [R13, #-4]!
 MOV     R0, #0
 MOV     R1, R11
 SWI     XOS_Find			;close ADFFS:Obey

 MOVS    R2, R9				;did we allocate any space
 MOVNE   R0, #Module_Free		;YES,
 SWINE   XOS_Module			; |+  free allocation

 LDR     R2, [R12, #ZIP_workspace - VARS]
 TEQ     R2, #0
 MOVNE   R3, #0
 STRNE   R3, [R12, #ZIP_workspace - VARS]
 SWINE   XOS_Module
 LDR     PC, [R13], #4


;_get8
;------
;read a bytes

 ._get8
 MOV     R3, #1				;read BYTE
 B       _read_data

;_get16
;------
;read two bytes

 ._get16
 MOV     R3, #2				;read WORD
 B       _read_data

;_get32
;------
;read four bytes

 ._get32
 MOV     R3, #4				;read DWORD

 ._read_data
 MOV     R0, #0
 STMFD   R13!, {R0, R14}

 MOV     R0, #4				;read from current pointer
 MOV     R1, R11			;file handle
 MOV     R2, R13			;use stack for data
 SWI     XOS_GBPB			;PRM2-69
 MOV     R10, R4			;update file pointer

 LDMFD   R13!, {R0, PC}


;_skip
;-----
;increase file pointer

 ._skip
 STR     R14, [R13, #-4]!
 ADD     R2, R0, R10			;new file pointer
 MOV     R10, R2
 MOV     R0, #1
 MOV     R1, R11			;file handle
 SWI     XOS_Args			;PRM2-52
 LDR     PC, [R13], #4
