HeavyThing - examples/minigzip/minigzip.asm

Jeff Marrison

	; ------------------------------------------------------------------------
	; HeavyThing x86_64 assembly language library and showcase programs
	; Copyright © 2015-2018 2 Ton Digital 
	; Homepage: https://2ton.com.au/
	; Author: Jeff Marrison <jeff@2ton.com.au>
	;       
	; This file is part of the HeavyThing library.
	;       
	; HeavyThing is free software: you can redistribute it and/or modify
	; it under the terms of the GNU General Public License, or
	; (at your option) any later version.
	;       
	; HeavyThing is distributed in the hope that it will be useful, 
	; but WITHOUT ANY WARRANTY; without even the implied warranty of
	; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
	; GNU General Public License for more details.
	;       
	; You should have received a copy of the GNU General Public License along
	; with the HeavyThing library. If not, see <http://www.gnu.org/licenses/>.
	; ------------------------------------------------------------------------
	;       minigzip.asm: HeavyThing gzip demo
	;
	;	with one arguments, will compress whatever filename it is passed and
	;	send the compressed results to stdout
	;
	;	with two arguments, will uncompress the last argument and
	;	send the uncompressed results to stdout
	;
	;	NOTE: our compression level is a compile-time constant for
	;	the HeavyThing library and defaults to 6, same as the real gzip
	;
	; first things first, include the library defaults, and the
	; library main include:
include '../../ht_defaults.inc'
include '../../ht.inc'

public _start
_start:
	; every HeavyThing program needs to start with a call to initialise it
	call	ht$init

	cmp	dword [argc], 1
	je	.needinputfile

	; regardless of whether we are inflating or deflating, last arg must be
	; our input file (noting here we could go through a lot more effort for
	; argument parsing of course, but for a minigzip, simple works fine)
	mov	rdi, [argv]
	call	list$pop_back
	; pass that straight to privmapped to get a private mmap of it
	mov	rdi, rax
	xor	esi, esi
	call	privmapped$new
	test	rax, rax
	jz	.badinputfile
	; save our privmapped object
	mov	rbx, rax

	; the HeavyThing zlib requires buffer objects for its i/o
	; since we don't really need/want to read the entire file from our
	; privmapped object into a separate buffer object, we'll create a
	; "fake" buffer object, since we know the zlib routines do not actually
	; modify the input
	call	buffer$new
	; save our buffer object
	mov	r12, rax
	; get our privmapped base and size
	mov	rdx, [rbx+privmapped_base_ofs]
	mov	rcx, [rbx+privmapped_size_ofs]
	; save the actual buffer object for later retrieval
	mov	r13, [rax+buffer_itself_ofs]
	; now set the buffer object's goods to our privmapped object's
	mov	[rax+buffer_itself_ofs], rdx
	mov	[rax+buffer_length_ofs], rcx
	mov	[rax+buffer_size_ofs], rcx

	; additionally, we need an output buffer
	call	buffer$new
	; hangon to our output buffer object as well
	mov	r14, rax

	; now determine whether we are inflating or deflating
	cmp	dword [argc], 2
	jne	.inflate

	; otherwise, deflate it is, use the stack for our zlib_stream
	sub	rsp, zlib_stream_size
	mov	rdi, rsp
	; zlib requires a wrap level to determine what headers if any to use
	; wrap == 2 == gzip
	mov	esi, 2
	call	zlib$deflateInit

	; set the inbuf and outbuf
	mov	[rsp+zlib_inbuf_ofs], r12
	mov	[rsp+zlib_outbuf_ofs], r14

	; do the deflate deed
	mov	rdi, rsp
	mov	esi, zlib_finish
	call	zlib$deflate

	; cleanup our zlib state
	mov	rdi, rsp
	call	zlib$deflateEnd
	add	rsp, zlib_stream_size

	; cleanup the rest and output the results
	jmp	.allgood
calign
.inflate:
	sub	rsp, zlib_stream_size
	mov	rdi, rsp
	; zlib requires a wrap level to determine what headers if any to use
	; wrap == 2 == gzip
	mov	esi, 2
	call	zlib$inflateInit

	; set the inbuf and outbuf
	mov	[rsp+zlib_inbuf_ofs], r12
	mov	[rsp+zlib_outbuf_ofs], r14

	; do the inflate deed
	mov	rdi, rsp
	mov	esi, zlib_finish
	call	zlib$inflate

	; cleanup our zlib state
	mov	rdi, rsp
	call	zlib$inflateEnd
	add	rsp, zlib_stream_size

calign
.allgood:
	; restore the buffer's original pointer
	mov	[r12+buffer_itself_ofs], r13
	; cleanup the buffer and privmapped objects
	mov	rdi, r12
	call	buffer$destroy
	mov	rdi, rbx
	call	privmapped$destroy

	; all thats left is our output
	mov	eax, syscall_write
	mov	edi, 1
	mov	rsi, [r14+buffer_itself_ofs]
	mov	rdx, [r14+buffer_length_ofs]
	syscall

	mov	rdi, r14
	call	buffer$destroy

	mov	eax, syscall_exit
	xor	edi, edi
	syscall

calign
.badinputfile:
	mov	rdi, .badinput
	call	string$to_stderrln
	mov	eax, syscall_exit
	mov	edi, 1
	syscall
cleartext .badinput, 'unable to open input file'
calign
.needinputfile:
	mov	rdi, .inputfile
	call	string$to_stderrln
	mov	eax, syscall_exit
	mov	edi, 1
	syscall
cleartext .inputfile, 'input filename required.'

	; include the global data segment:
include '../../ht_data.inc'