;------------------------------------------------------------------------------
;
;   File    :	BitStream.a
;
;   Author  :	Stéphane TAVENARD
;
;   $VER:   BitStream.a  1.2  (29/07/1995)
;
;   (C) Copyright 1995-1995 Stéphane TAVENARD
;	All Rights Reserved
;
;   #Rev|   Date   |			  Comment
;   ----|----------|--------------------------------------------------------
;   0	|12/04/1995| Initial revision					  ST
;   1	|03/06/1995| First release (no more C code)                       ST
;   2	|23/06/1995| Aminet release					  ST
;   3	|29/07/1995| Added a6 register save				  ST
;
;   ------------------------------------------------------------------------
;
;   BitStream files handling
;
;------------------------------------------------------------------------------

		  IFND	   INCLUDE_SOURCE
		  incdir   "include:"
		  include  "exec/funcdef.i"
		  include  "exec/exec.i"
		  include  "exec/exec_lib.i"
		  include  "dos/dos.i"
		  include  "dos/dos_lib.i"
		  XREF	   _DOSBase
		  ENDC

		  include  "bitstream.i"

		  XDEF	   @BSTR_open
		  XDEF	   @BSTR_close
		  XDEF	   @BSTR_rewind
		  XDEF	   @BSTR_end
		  XDEF	   @BSTR_seek_tell
		  XDEF	   @BSTR_read_bit
		  XDEF	   @BSTR_read_bits
		  XDEF	   @BSTR_read_signed_bits
		  XDEF	   @BSTR_skip_bits
		  XDEF	   @BSTR_read3_bits
		  XDEF	   @BSTR_read2_bits
		  XDEF	   @BSTR_seek_sync
;
		  IFND	   INCLUDE_SOURCE
CALLEXEC	  MACRO
		  move.l  (_SysBase).w,a6
		  jsr	  _LVO\1(a6)
		  ENDM
_SysBase	  EQU	  4

CALLDOS 	  MACRO
		  move.l  _DOSBase,a6
		  jsr	  _LVO\1(a6)
		  ENDM
		  ENDC

;
		  section  ASMCODE,code


;		  Close a bitstream file
;
;		  a0 = bitstream structure ptr
;
@BSTR_close
		  movem.l  a2/a6/d2,-(sp)
		  move.l   a0,a2
		  tst.l    a2
		  beq	   BSTR_close9
		  move.l   BSTR_file_ptr(a2),d1
		  beq	   BSTR_close7
		  CALLDOS  Close
		  clr.l    BSTR_file_ptr(a2)
BSTR_close7	  move.l   BSTR_buffer(a2),a1
		  tst.l    a1
		  beq	   BSTR_close8
		  move.l   BSTR_buffer_size(a2),d0
		  CALLEXEC FreeMem
		  clr.l    BSTR_buffer(a2)
BSTR_close8	  move.l   a2,a1
		  moveq.l  #BSTR_SIZEOF,d0
		  CALLEXEC FreeMem
BSTR_close9	  movem.l  (sp)+,a2/a6/d2
		  rts

;		  Open a bitstream file
;
;		  a0 = name
;		  d0.l = buffer size
;		  d1.l = access mode
;		  -> d0.l = bitstream structure ptr (=0 if error)
@BSTR_open
		  movem.l  a2/a6/d2,-(sp)
		  move.l   a0,name
		  move.l   d0,buffer_size
		  move.l   d1,mode
		  clr.l    bstr_ptr
		  cmp.l    #BSTR_MODE_READ,d1
		  bne	   BSTR_open8		; not implemented yet

		  moveq.l  #BSTR_SIZEOF,d0
		  move.l   #MEMF_ANY|MEMF_CLEAR,d1
		  CALLEXEC AllocMem
		  move.l   d0,bstr_ptr
		  beq	   BSTR_open7		; fail
		  move.l   d0,a2
		  move.l   buffer_size,d0
		  move.l   d0,BSTR_buffer_size(a2)
		  move.l   #MEMF_ANY,d1
		  CALLEXEC AllocMem
		  move.l   d0,BSTR_buffer(a2)
		  beq	   BSTR_open7		; fail
		  move.l   mode,BSTR_mode(a2)
		  move.l   name,d1
		  move.l   #MODE_OLDFILE,d2
		  CALLDOS  Open
		  move.l   d0,BSTR_file_ptr(a2)
		  beq	   BSTR_open7		; fail
		  move.l   a2,d0
		  bra	   BSTR_open9		; success
BSTR_open7
		  move.l   bstr_ptr,a0
		  bsr	   @BSTR_close
BSTR_open8	  clr.l d0
BSTR_open9	  movem.l  (sp)+,a2/a6/d2
		  rts

;		  Seek to start of the bitstream
;
;		  a0 = bitstream structure ptr
;		  -> d0.l = 0 if fail
;
@BSTR_rewind	  movem.l  a2/a6/d2-d3,-(sp)
		  tst.l    a0
		  move.l   a0,a2
		  beq	   BSTR_rewind9
		  move.l   BSTR_file_ptr(a2),d1
		  moveq.l  #0,d2
		  moveq.l  #OFFSET_BEGINNING,d3
		  CALLDOS  Seek
		  tst.l    d0
		  bmi	   BSTR_rewind8
		  clr.l    BSTR_current_bit_index(a2)
		  clr.l    BSTR_remaining_bits(a2)
		  clr.l    BSTR_bitstream_size(a2)
		  clr.l    BSTR_end_of_stream(a2)
		  moveq.l  #1,d0
		  bra	   BSTR_rewind9
BSTR_rewind8	  clr.l    d0
BSTR_rewind9	  movem.l  (sp)+,a2/a6/d2-d3
		  rts

;		  Test if end of bistream is reached
;
;		  a0 = bitstream structure ptr
;		  -> d0.l = 0 if not end of bitstream
@BSTR_end
		  move.l   BSTR_end_of_stream(a0),d0
		  rts

;		  Get the current seek bit of bistream
;		  a0 = bitstream structure ptr
;		  -> d0.l = seek value
@BSTR_seek_tell
		  move.l   BSTR_bitstream_size(a0),d0
		  rts


;		  Fill in the read buffer of a bitstream
;
;		  a0 = bitstream
BSTR_fill_buffer
		  movem.l  d0-d7/a0-a6,-(sp)
		  tst.l    BSTR_end_of_stream(a0)
		  bne	   BSTR_fill_buffer9	    ; end of stream !
		  move.l   BSTR_buffer(a0),a1
		  move.l   BSTR_buffer_size(a0),d3
		  move.l   BSTR_current_bit_index(a0),d0
		  asr.l    #3,d0		    ; current byte index
		  lea.l    (a1,d0.l),a2             ; last unread bytes
		  and.l    #7,BSTR_current_bit_index(a0) ; reset current bit index
		  move.l   BSTR_remaining_bits(a0),d0
BSTR_fill_buffer1 tst.l    d0
		  ble	   BSTR_fill_buffer2	    ; no remaining bits
		  move.b   (a2)+,(a1)+              ; copy remaining bytes
		  subq.l   #8,d0
		  subq.l   #1,d3		    ; bytes to read --
		  bra	   BSTR_fill_buffer1
BSTR_fill_buffer2 move.l   a0,-(sp)
		  move.l   BSTR_file_ptr(a0),d1
		  move.l   a1,d2		   ; read buffer
		  CALLDOS  Read
		  move.l   (sp)+,a0
		  asl.l    #3,d0		   ; read bytes * 8 -> read bits
		  ble	   BSTR_fill_buffer8	   ; read bits <= 0 -> end of stream
		  add.l    d0,BSTR_remaining_bits(a0)
		  bra	   BSTR_fill_buffer9
BSTR_fill_buffer8 move.l   #-1,BSTR_end_of_stream(a0)   ; end of stream !
BSTR_fill_buffer9 movem.l  (sp)+,d0-d7/a0-a6
		  rts


;		  Read 1 bit (unsigned) from a bitstream
;
;		  a0 = bitstream
;		  -> d0 = bit value
;		  a0 is preserved
;		  a1 & d1 are affected
;
@BSTR_read_bit
		  moveq.l  #1,d1
;		   bra	    @BSTR_read_bits

;		  Read some bits (unsigned) from a bitstream
;
;		  a0 = bitstream
;		  d1 = bit count (max=32)
;		  -> d0 = bits value (=0 if bitstream is empty)
;		  a0 & d1 are preserved
;		  a1 is affected
;
@BSTR_read_bits
BSTR_read_bits1   sub.l    d1,BSTR_remaining_bits(a0)
		  bmi.s    BSTR_read_bits2	      ; no more bits available
		  move.l   BSTR_current_bit_index(a0),d0
		  move.l   BSTR_buffer(a0),a1
		  bfextu   (a1){d0:d1},d0             ; read bits -> d0
		  add.l    d1,BSTR_current_bit_index(a0)
		  add.l    d1,BSTR_bitstream_size(a0)
		  rts
BSTR_read_bits2   add.l    d1,BSTR_remaining_bits(a0)      ; restore old count
		  bsr	   BSTR_fill_buffer
		  tst.l    BSTR_end_of_stream(a0)
		  beq	   BSTR_read_bits1	      ; not end of bitstream
BSTR_read_bits9   moveq.l  #0,d0
		  rts

;		  Read some bits (signed) from a bitstream
;
;		  a0 = bitstream
;		  d1 = bit count (max=32)
;		  -> d0 = bits value (=0 if bitstream is empty)
;		  a0 & d1 are preserved
;		  a1 is affected
;
@BSTR_read_signed_bits
BSTR_read_sbits1  sub.l    d1,BSTR_remaining_bits(a0)
		  bmi	   BSTR_read_sbits2	      ; no more bits available
		  move.l   BSTR_current_bit_index(a0),d0
		  move.l   BSTR_buffer(a0),a1
		  bfexts   (a1){d0:d1},d0             ; read signed bits -> d0
		  add.l    d1,BSTR_current_bit_index(a0)
		  add.l    d1,BSTR_bitstream_size(a0)
		  rts
BSTR_read_sbits2  add.l    d1,BSTR_remaining_bits(a0)      ; restore old count
		  bsr	   BSTR_fill_buffer
		  tst.l    BSTR_end_of_stream(a0)
		  beq	   BSTR_read_sbits1	      ; not end of bitstream
BSTR_read_sbits9  moveq.l  #0,d0
		  rts

;		  Skip some bits from a bitstream
;
;		  a0 = bitstream
;		  d1 = length (can be > 32)
;		  -> d0 = bit skipped count
;		  a0, a1 & d1 are preserved
;
@BSTR_skip_bits
BSTR_skip_bits1   sub.l    d1,BSTR_remaining_bits(a0)
		  bmi.s    BSTR_skip_bits2		 ; no more bits available
		  add.l    d1,BSTR_current_bit_index(a0)
		  add.l    d1,BSTR_bitstream_size(a0)
		  move.l   d1,d0
		  rts
BSTR_skip_bits2   add.l    d1,BSTR_remaining_bits(a0)    ; restore old count
		  bsr	   BSTR_fill_buffer
		  tst.l    BSTR_end_of_stream(a0)
		  beq	   BSTR_skip_bits1		 ; not end of bitstream
		  clr.l    d0
		  rts

;		  Read three bits-packets (unsigned) from a bitstream
;
;		  a0 = bitstream
;		  d1 = bit count for each packet (max=32)
;		  -> d4, d5, d6 = bits values packets
;		  a0 & d1 are preserved
;		  a1 & d2 are modified !!!
;
@BSTR_read3_bits
BSTR_read3_bits1  move.l   d1,d2
		  add.l    d2,d2
		  add.l    d1,d2		      ; d2 = 3*d1
		  sub.l    d2,BSTR_remaining_bits(a0)
		  bmi.s    BSTR_read3_bits2	      ; no more bits available
		  move.l   BSTR_current_bit_index(a0),d0
		  move.l   BSTR_buffer(a0),a1
		  bfextu   (a1){d0:d1},d4             ; read bits -> d4
		  add.l    d1,d0		      ; next packet
		  bfextu   (a1){d0:d1},d5             ; read bits -> d5
		  add.l    d1,d0		      ; next packet
		  bfextu   (a1){d0:d1},d6             ; read bits -> d6
		  add.l    d2,BSTR_current_bit_index(a0)
		  add.l    d2,BSTR_bitstream_size(a0)
		  rts
BSTR_read3_bits2  add.l    d2,BSTR_remaining_bits(a0)      ; restore old count
		  bsr	   BSTR_fill_buffer
		  tst.l    BSTR_end_of_stream(a0)
		  beq	   BSTR_read3_bits1	      ; not end of bitstream
		  moveq.l  #0,d4
		  move.l   d4,d5
		  move.l   d4,d6
		  rts

;		  Read two bits-packets (unsigned) from a bitstream
;
;		  a0 = bitstream
;		  d1 = bit count for each packet (max=32)
;		  -> d4, d5 = bits values packets
;		  a0 & d1 are preserved
;		  a1 & d2 are modified !!!
;
@BSTR_read2_bits
BSTR_read2_bits1  move.l   d1,d2
		  add.l    d2,d2		      ; d2 = 2*d1
		  sub.l    d2,BSTR_remaining_bits(a0)
		  bmi.s    BSTR_read2_bits2	      ; no more bits available
		  move.l   BSTR_current_bit_index(a0),d0
		  move.l   BSTR_buffer(a0),a1
		  bfextu   (a1){d0:d1},d4             ; read bits -> d4
		  add.l    d1,d0		      ; next packet
		  bfextu   (a1){d0:d1},d5             ; read bits -> d5
		  add.l    d2,BSTR_current_bit_index(a0)
		  add.l    d2,BSTR_bitstream_size(a0)
		  rts
BSTR_read2_bits2  add.l    d2,BSTR_remaining_bits(a0)      ; restore old count
		  bsr	   BSTR_fill_buffer
		  tst.l    BSTR_end_of_stream(a0)
		  beq	   BSTR_read2_bits1	      ; not end of bitstream
		  moveq.l  #0,d4
		  move.l   d4,d5
		  rts

;		  Seek to the next sync. 8-bit aligned pattern
;
;		  a0 = bitstream structure ptr
;		  d0.l = sync. value
;		  d1.l = sync. length
;		  -> d0.l = 0 if not found
;
@BSTR_seek_sync
		  movem.l  a2/d2-d4,-(sp)
		  move.l   d0,d2
		  move.l   d1,d3
		  clr.l    d4
		  bset	   d1,d4
		  subq.l   #1,d4		   ; d4 = bits mask
		  move.l   BSTR_bitstream_size(a0),d0
		  and.l    #7,d0
		  beq	   BSTR_seek_sync3	   ; already 8-bit aligned
		  moveq.l  #8,d1
		  sub.l    d0,d1		   ; d1 = bits to skip
		  bsr	   @BSTR_skip_bits
BSTR_seek_sync3   move.l   d3,d1
		  bsr	   @BSTR_read_bits	   ; read first packet
		  move.l   d0,d3
		  moveq.l  #8,d1
BSTR_seek_sync5   cmp.l    d3,d2
		  beq	   BSTR_seek_sync8	   ; ok sync. found
		  tst.l    BSTR_end_of_stream(a0)
		  bne	   BSTR_seek_sync7	   ; end of bitstream reached
		  lsl.l    d1,d3
		  and.l    d4,d3
		  bsr	   @BSTR_read_bits	   ; read next 8 bits
		  or.l	   d0,d3		   ; update bit packet
		  bra	   BSTR_seek_sync5
BSTR_seek_sync7   clr.l    d0
		  bra	   BSTR_seek_sync9
BSTR_seek_sync8   moveq.l  #-1,d0
BSTR_seek_sync9   movem.l  (sp)+,a2/d2-d4
		  rts

		  section  ASMVARS,bss

		  even

name		  ds.l	   1
buffer_size	  ds.l	   1
mode		  ds.l	   1
bstr_ptr	  ds.l	   1

