x64 and x86 JCalG1 Decompressor (faster than PB)

Share your advanced PureBasic knowledge/code with the community.
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

x64 and x86 JCalG1 Decompressor (faster than PB)

Post by Thorium »

I have ported the JCalG1 decompressor from 32bit to 64bit.

I am not a asm freak and i don't realy understand the original source code. But after 4 houres of work it finaly works. ^^

It does not take any advantage of the 64bit architecture. It just works on it.
Have fun using it. And if anyone wants to optimize it, feel free to do, just share the source. :D

I don't know how to use makros on inline asm, so i solved them. That's why the source code is so big.

And i removed CRC32 check.

Code: Select all

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
  ;64bit code
  Procedure.i UnpackMemory_JCalG1(SrcBuffer.i, DestBuffer.i)
  
    Define IndexBase.l      ;+64
    Define LiteralBits.l    ;+72
    Define MinimumLiteral.b ;+80
  
    !cld
    
  	!push	rbx
  	!push	rdi
  	!push	rsi
  
    !mov rsi, [rsp+104]         ;SrcBuffer        ; rsi->source
    !mov rdi, [rsp+112]         ;DestBuffer       ; rdi->destination
  
    !cmp word [rsi], 'JC'       ;check for signature
    !jnz UnpMemJc64_DecompDone
    
    !add rsi, 10
    
    !xor ebx, ebx               ;zero ebx
    !mov edx, 80000000h         ;initialize edx, placeholder bit at highest position, force load of new dword.
    !mov dword [rsp+64], 8      ;IndexBase,INITIAL_BASE
    !inc ebx                    ;most recently encoded index assumed to be one at start.
    
    !align 4
    ;the main decompression loop
  !UnpMemJc64_DecodeLoop:
  
    ;_getbit
    !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
    !jnz UnpMemJc64_noload1     ;if not, then return carry bit
    !mov edx, dword [rsi]
    !add rsi, 4
    !stc
    !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
    !UnpMemJc64_noload1:
  
    !jnc UnpMemJc64_IsntLiteral ;if not zero bit, then is not literal
  !UnpMemJc64_DoLiteral:
    !mov ecx, [rsp+72]          ;LiteralBits
    
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc64_getbitsloop1:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload2   ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload2:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc64_getbitsloop1
    
    !add	al, [rsp+80]          ;MinimumLiteral
  !UnpMemJc64_DecodeZero:
    !mov [rdi], al
    !inc rdi
    !jmp UnpMemJc64_DecodeLoop
    
  !UnpMemJc64_IsntLiteral:
  
    ;_getbit
    !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
    !jnz UnpMemJc64_noload3     ;if not, then return carry bit
    !mov edx, dword [rsi]
    !add rsi, 4
    !stc
    !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
    !UnpMemJc64_noload3:
    
    !jc UnpMemJc64_NormalPhrase ; if 1, then normal phrase (01)
    ; else grab next control bit
    
    ;_getbit
    !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
    !jnz UnpMemJc64_noload4     ;if not, then return carry bit
    !mov edx, dword [rsi]
    !add rsi, 4
    !stc
    !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
    !UnpMemJc64_noload4:
    
    !jnc UnpMemJc64_ShortMatch  ;if 0, then short phrase (000)
    ;else, one byte phrase or literal size change
    !mov ecx, 4                 ;ONEBYTE_PHRASE_BITS
    ;get one byte phrase index
    
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc64_getbitsloop2:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload5   ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload5:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc64_getbitsloop2
    
    !dec eax
    !jz	UnpMemJc64_DecodeZero
    !jns UnpMemJc64_docopy_inc
  
    ;_getbit
    !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
    !jnz UnpMemJc64_noload6     ;if not, then return carry bit
    !mov edx, dword [rsi]
    !add rsi, 4
    !stc
    !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
    !UnpMemJc64_noload6:
    
    !jnc UnpMemJc64_GetNewLiteralSize
    
  !UnpMemJc64_NextBlock:
  	!mov ebp, 256               ;BLOCK_SIZE
  !UnpMemJc64_CopyMe:
  
    ;_getbyte
    !mov ecx, 8                 ;8 bits
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc64_getbitsloop3:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload7   ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload7:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc64_getbitsloop3
    
    !mov byte [rdi], al
    !inc rdi
    !dec ebp
    !jnz UnpMemJc64_CopyMe
    
    ;_getbit
    !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
    !jnz UnpMemJc64_noload8     ;if not, then return carry bit
    !mov edx, dword [rsi]
    !add rsi, 4
    !stc
    !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
    !UnpMemJc64_noload8:
    
    !jc	UnpMemJc64_NextBlock
    !jmp UnpMemJc64_DecodeLoop
    
  !UnpMemJc64_GetNewLiteralSize:
    ;retrieve literal information
    !mov ecx, 1                 ;LITERAL_BITSIZE
    
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc64_getbitsloop4:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload9   ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload9:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc64_getbitsloop4
    
    !add eax, 7
    !mov [rsp+72], eax
    !mov byte [rsp+80], 0
    !cmp eax, 8
    !jz	UnpMemJc64_DecodeLoop
    
    ;_getbyte
    !mov ecx, 8                 ;8 bits
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc64_getbitsloop5:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload10   ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload10:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc64_getbitsloop5
    
    !mov [rsp+80], al
    !jmp UnpMemJc64_DecodeLoop
    
  !UnpMemJc64_ShortMatch:
    !mov ecx, 7                 ;SHORT_BITS
  
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc64_getbitsloop6:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload11   ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload11:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc64_getbitsloop6
  
    !mov ebp,eax
    !mov ecx, 2
  
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc64_getbitsloop7:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload12   ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload12:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc64_getbitsloop7
  
    !mov ecx, eax
    !mov eax, ebp
    !add ecx, 2
    !test	eax, eax
    !jz	UnpMemJc64_extendedshort
    !mov ebx, eax               ;store last used index
    !jmp UnpMemJc64_docopy      ;go copy the phrase
  !UnpMemJc64_extendedshort:
    !cmp ecx, 2
    !jz UnpMemJc64_DecompDone   ;if carry flag nonzero, then decompression finished.
    !inc ecx		                ;3+1=4
    ;retrieve new index base
   
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc64_getbitsloop8:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload13   ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload13:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc64_getbitsloop8
  
    !mov [rsp+64], eax          ;store index base
    !jmp UnpMemJc64_DecodeLoop  ;loop
   
  !UnpMemJc64_NormalPhrase:
    ;get gamma encoded high index
    
    ;_getgamma
    !mov ecx, 1
    !align 4
    !UnpMemJc64_getgammaloop1:
      ;retrieve a bit from the input stream
      
      ;_getbit
      !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload14     ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload14:
      
      !adc ecx, ecx               ;add it to destination
      ;retrieve another bit
  
      ;_getbit
      !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload15     ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload15:
  
    !jc UnpMemJc64_getgammaloop1  ;if one, continue on, if zero, end of integer
    
    !dec ecx                      ;decrement once
    !dec ecx                      ;decrement twice
    !jnz UnpMemJc64_notsamefull   ;if not zero, then low bits follow
    !mov eax, ebx                 ;else, index is same as last used
    ;decode the phrase length
  
    ;_getgamma
    !mov ecx, 1
    !align 4
    !UnpMemJc64_getgammaloop2:
      ;retrieve a bit from the input stream
      
      ;_getbit
      !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload16     ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload16:
      
      !adc ecx, ecx               ;add it to destination
      ;retrieve another bit
  
      ;_getbit
      !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload17     ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload17:
  
    !jc UnpMemJc64_getgammaloop2  ;if one, continue on, if zero, end of integer
  
    !jmp UnpMemJc64_docopy        ;copy the phrase
  !UnpMemJc64_notsamefull:
    !dec ecx                      ;third decrementation
    !mov eax, ecx                 ;store the high bits of index in eax
    !mov ecx, [rsp+64]            ;ecx=current index base
    !mov ebp, eax                 ;save the high bits of index
    !xor eax, eax
    !shl ebp, cl                  ;shift high bits CURRENT_BASE bits lt
    ;get CURRENT_BASE bits
  
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc64_getbitsloop9:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload18   ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload18:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc64_getbitsloop9
   
    !or eax, ebp 	              ;or together high and low bits
    !mov ebx, eax               ;store last used index
    ;retrieve the phrase length
  
    ;_getgamma
    !mov ecx, 1
    !align 4
    !UnpMemJc64_getgammaloop3:
      ;retrieve a bit from the input stream
      
      ;_getbit
      !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload19     ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload19:
      
      !adc ecx, ecx               ;add it to destination
      ;retrieve another bit
  
      ;_getbit
      !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc64_noload20     ;if not, then return carry bit
      !mov edx, dword [rsi]
      !add rsi, 4
      !stc
      !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc64_noload20:
  
    !jc UnpMemJc64_getgammaloop3  ;if one, continue on, if zero, end of integer
  
    ;perform index range decremenation
    !cmp eax, 010000h                    ;DecrementIndex3
    !jae UnpMemJc64_docopy_threeincs
    !cmp eax, 037ffh                     ;DecrementIndex2
    !jae UnpMemJc64_docopy_twoincs
    !cmp eax, 027fh                      ;DecrementIndex1
    !jae UnpMemJc64_docopy_inc
    !cmp eax, 1111111b                   ;SHORT_RANGE
    !ja UnpMemJc64_docopy
    !inc ecx
  !UnpMemJc64_docopy_threeincs:
    !inc ecx
  !UnpMemJc64_docopy_twoincs:
    !inc ecx
  !UnpMemJc64_docopy_inc:
    !inc ecx
  
  !UnpMemJc64_docopy:
  
    !mov rbp, rsi
    !mov rsi, rdi                ;rsi=P
    !sub rsi, rax                ;subtract relative index for absolute
  
    !mov r8d, ecx
    !shr ecx,2
    !rep movsd
    !mov ecx, r8d
    !and ecx,3
    !rep movsb
  
    !mov rsi, rbp
    !jmp UnpMemJc64_DecodeLoop   ;loop
  
  !UnpMemJc64_DecompDone:
    !lea rbp, [rsp+48]
    !mov rsi, [rsp+104]
    !cmp dword [rsi+6], 0       ;check for checksumme
    
    !jmp UnpMemJc64_DecompGood
  
  !UnpMemJc64_DecompBad:
          !XOr rax,rax
          !jmp UnpMemJc64_DecompExit
  
  !UnpMemJc64_DecompGood:
          !mov rax,rdi        ; eax->end of uncompressed data
          !sub rax,[rsp+112]  ; eax=end of uncompressed data - start of uncompressed Data = size of uncompressed Data
  
  !UnpMemJc64_DecompExit:
    !pop rsi
    !pop rdi
    !pop rbx
  
   ProcedureReturn
  
  EndProcedure
CompilerElse
  ;32bit code
  Procedure.i UnpackMemory_JCalG1(SrcBuffer.i, DestBuffer.i)
  
    Define IndexBase.l      ;+12
    Define LiteralBits.l    ;+16
    Define MinimumLiteral.b ;+20
  
    !cld
    
  	!push	ebx
  	!push	edi
  	!push	esi
  
    !mov esi, [esp+28]         ;SrcBuffer        ; rsi->source
    !mov edi, [esp+32]         ;DestBuffer       ; rdi->destination

    !cmp word [esi], 'JC'       ;check for signature
    !jnz UnpMemJc32_DecompDone
    
    !add esi, 10
    
    !xor ebx, ebx               ;zero ebx
    !mov edx, 80000000h         ;initialize edx, placeholder bit at highest position, force load of new dword.
    !mov dword [esp+12], 8      ;IndexBase,INITIAL_BASE
    !inc ebx                    ;most recently encoded index assumed to be one at start.
    
    !align 4
    ;the main decompression loop
  !UnpMemJc32_DecodeLoop:
  
    ;_getbit
    !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
    !jnz UnpMemJc32_noload1     ;if not, then return carry bit
    !mov edx, dword [esi]
    !add esi, 4
    !stc
    !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
    !UnpMemJc32_noload1:
  
    !jnc UnpMemJc32_IsntLiteral ;if not zero bit, then is not literal
  !UnpMemJc32_DoLiteral:
    !mov ecx, [esp+16]          ;LiteralBits
    
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc32_getbitsloop1:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload2   ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload2:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc32_getbitsloop1
    
    !add	al, [esp+20]          ;MinimumLiteral
  !UnpMemJc32_DecodeZero:
    !mov [edi], al
    !inc edi
    !jmp UnpMemJc32_DecodeLoop
    
  !UnpMemJc32_IsntLiteral:
  
    ;_getbit
    !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
    !jnz UnpMemJc32_noload3     ;if not, then return carry bit
    !mov edx, dword [esi]
    !add esi, 4
    !stc
    !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
    !UnpMemJc32_noload3:
    
    !jc UnpMemJc32_NormalPhrase ; if 1, then normal phrase (01)
    ; else grab next control bit
    
    ;_getbit
    !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
    !jnz UnpMemJc32_noload4     ;if not, then return carry bit
    !mov edx, dword [esi]
    !add esi, 4
    !stc
    !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
    !UnpMemJc32_noload4:
    
    !jnc UnpMemJc32_ShortMatch  ;if 0, then short phrase (000)
    ;else, one byte phrase or literal size change
    !mov ecx, 4                 ;ONEBYTE_PHRASE_BITS
    ;get one byte phrase index
    
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc32_getbitsloop2:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload5   ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload5:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc32_getbitsloop2
    
    !dec eax
    !jz	UnpMemJc32_DecodeZero
    !jns UnpMemJc32_docopy_inc
  
    ;_getbit
    !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
    !jnz UnpMemJc32_noload6     ;if not, then return carry bit
    !mov edx, dword [esi]
    !add esi, 4
    !stc
    !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
    !UnpMemJc32_noload6:
    
    !jnc UnpMemJc32_GetNewLiteralSize
    
  !UnpMemJc32_NextBlock:
  	!mov ebp, 256               ;BLOCK_SIZE
  !UnpMemJc32_CopyMe:
  
    ;_getbyte
    !mov ecx, 8                 ;8 bits
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc32_getbitsloop3:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload7   ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload7:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc32_getbitsloop3
    
    !mov byte [edi], al
    !inc edi
    !dec ebp
    !jnz UnpMemJc32_CopyMe
    
    ;_getbit
    !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
    !jnz UnpMemJc32_noload8     ;if not, then return carry bit
    !mov edx, dword [esi]
    !add esi, 4
    !stc
    !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
    !UnpMemJc32_noload8:
    
    !jc	UnpMemJc32_NextBlock
    !jmp UnpMemJc32_DecodeLoop
    
  !UnpMemJc32_GetNewLiteralSize:
    ;retrieve literal information
    !mov ecx, 1                 ;LITERAL_BITSIZE
    
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc32_getbitsloop4:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload9   ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload9:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc32_getbitsloop4
    
    !add eax, 7
    !mov [esp+16], eax
    !mov byte [esp+20], 0
    !cmp eax, 8
    !jz	UnpMemJc32_DecodeLoop
    
    ;_getbyte
    !mov ecx, 8                 ;8 bits
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc32_getbitsloop5:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload10   ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload10:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc32_getbitsloop5
    
    !mov [esp+20], al
    !jmp UnpMemJc32_DecodeLoop
    
  !UnpMemJc32_ShortMatch:
    !mov ecx, 7                 ;SHORT_BITS
  
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc32_getbitsloop6:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload11   ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload11:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc32_getbitsloop6
  
    !mov ebp,eax
    !mov ecx, 2
  
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc32_getbitsloop7:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload12   ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload12:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc32_getbitsloop7
  
    !mov ecx, eax
    !mov eax, ebp
    !add ecx, 2
    !test	eax, eax
    !jz	UnpMemJc32_extendedshort
    !mov ebx, eax               ;store last used index
    !jmp UnpMemJc32_docopy      ;go copy the phrase
  !UnpMemJc32_extendedshort:
    !cmp ecx, 2
    !jz UnpMemJc32_DecompDone   ;if carry flag nonzero, then decompression finished.
    !inc ecx		                ;3+1=4
    ;retrieve new index base
   
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc32_getbitsloop8:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload13   ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload13:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc32_getbitsloop8
  
    !mov [esp+12], eax          ;store index base
    !jmp UnpMemJc32_DecodeLoop  ;loop
   
  !UnpMemJc32_NormalPhrase:
    ;get gamma encoded high index
    
    ;_getgamma
    !mov ecx, 1
    !align 4
    !UnpMemJc32_getgammaloop1:
      ;retrieve a bit from the input stream
      
      ;_getbit
      !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload14     ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload14:
      
      !adc ecx, ecx               ;add it to destination
      ;retrieve another bit
  
      ;_getbit
      !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload15     ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload15:
  
    !jc UnpMemJc32_getgammaloop1  ;if one, continue on, if zero, end of integer
    
    !dec ecx                      ;decrement once
    !dec ecx                      ;decrement twice
    !jnz UnpMemJc32_notsamefull   ;if not zero, then low bits follow
    !mov eax, ebx                 ;else, index is same as last used
    ;decode the phrase length
  
    ;_getgamma
    !mov ecx, 1
    !align 4
    !UnpMemJc32_getgammaloop2:
      ;retrieve a bit from the input stream
      
      ;_getbit
      !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload16     ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload16:
      
      !adc ecx, ecx               ;add it to destination
      ;retrieve another bit
  
      ;_getbit
      !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload17     ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload17:
  
    !jc UnpMemJc32_getgammaloop2  ;if one, continue on, if zero, end of integer
  
    !jmp UnpMemJc32_docopy        ;copy the phrase
  !UnpMemJc32_notsamefull:
    !dec ecx                      ;third decrementation
    !mov eax, ecx                 ;store the high bits of index in eax
    !mov ecx, [esp+12]            ;ecx=current index base
    !mov ebp, eax                 ;save the high bits of index
    !xor eax, eax
    !shl ebp, cl                  ;shift high bits CURRENT_BASE bits lt
    ;get CURRENT_BASE bits
  
    ;_getbits
    !xor eax, eax
    !align 4
    !UnpMemJc32_getbitsloop9:
      ;_getbit
      !add edx, edx             ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload18   ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx             ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload18:
      
      !adc eax,eax              ;add bit to eax
      !dec ecx
    !jnz UnpMemJc32_getbitsloop9
   
    !or eax, ebp 	              ;or together high and low bits
    !mov ebx, eax               ;store last used index
    ;retrieve the phrase length
  
    ;_getgamma
    !mov ecx, 1
    !align 4
    !UnpMemJc32_getgammaloop3:
      ;retrieve a bit from the input stream
      
      ;_getbit
      !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload19     ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload19:
      
      !adc ecx, ecx               ;add it to destination
      ;retrieve another bit
  
      ;_getbit
      !add edx, edx               ;edx*2, equiv. to shl edx,1 if placeholder bit (1) is shifted off into carry then result is zero.
      !jnz UnpMemJc32_noload20     ;if not, then return carry bit
      !mov edx, dword [esi]
      !add esi, 4
      !stc
      !adc edx, edx               ;minimum value now one, lowest bit used as placeholder, highest bit shifted off for return
      !UnpMemJc32_noload20:
  
    !jc UnpMemJc32_getgammaloop3  ;if one, continue on, if zero, end of integer
  
    ;perform index range decremenation
    !cmp eax, 010000h                    ;DecrementIndex3
    !jae UnpMemJc32_docopy_threeincs
    !cmp eax, 037ffh                     ;DecrementIndex2
    !jae UnpMemJc32_docopy_twoincs
    !cmp eax, 027fh                      ;DecrementIndex1
    !jae UnpMemJc32_docopy_inc
    !cmp eax, 1111111b                   ;SHORT_RANGE
    !ja UnpMemJc32_docopy
    !inc ecx
  !UnpMemJc32_docopy_threeincs:
    !inc ecx
  !UnpMemJc32_docopy_twoincs:
    !inc ecx
  !UnpMemJc32_docopy_inc:
    !inc ecx
  
  !UnpMemJc32_docopy:
  
    !mov ebp, esi
    !mov esi, edi                ;esi=P
    !sub esi, eax                ;subtract relative index for absolute
  
    !push ecx
    !shr ecx,2
    !rep movsd
    !pop ecx
    !and ecx,3
    !rep movsb
  
    !mov esi, ebp
    !jmp UnpMemJc32_DecodeLoop   ;loop
  
  !UnpMemJc32_DecompDone:
    !lea ebp, [esp+24]
    !mov esi, [esp+28]
    !cmp dword [esi+6], 0       ;check for checksumme
    
    !jmp UnpMemJc32_DecompGood
  
  !UnpMemJc32_DecompBad:
          !xor eax, eax
          !jmp UnpMemJc32_DecompExit
  
  !UnpMemJc32_DecompGood:
          !mov eax,edi        ; eax->end of uncompressed data
          !sub eax,[esp+32]   ; eax=end of uncompressed data - start of uncompressed Data = size of uncompressed Data
  
  !UnpMemJc32_DecompExit:
    !pop esi
    !pop edi
    !pop ebx
  
   ProcedureReturn
  
  EndProcedure
CompilerEndIf
Last edited by Thorium on Sun Aug 16, 2009 9:59 pm, edited 4 times in total.
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Post by Thorium »

I just done a quick speed test and my 64bit port is 4% faster than the routine of PureBasic.
Maybe i can make it more fast...

Edit: Updated code. Now it's 9% faster than the PureBasic routine.

The memory copy routine was unoptimized.
I changed this:

Code: Select all

!UnpMemJc64_docopy:

  !mov rbp, rsi
  !mov rsi, rdi                ;rsi=P
  !sub rsi, rax                ;subtract relative index for absolute
  !rep movsb
  !mov rsi, rbp
  !jmp UnpMemJc64_DecodeLoop   ;loop
To this:

Code: Select all

!UnpMemJc64_docopy:

  !mov rbp, rsi
  !mov rsi, rdi                ;rsi=P
  !sub rsi, rax                ;subtract relative index for absolute

  !mov r8d, ecx
  !shr ecx,2
  !rep movsd
  !mov ecx, r8d
  !and ecx,3
  !rep movsb

  !mov rsi, rbp
  !jmp UnpMemJc64_DecodeLoop   ;loop
Well, you just want to ask why i don't use movsq, since it's a 64bit code. I tried it, but it resultet in a loss of 10% speed. I think it's because the data blocks are smaler than 8 byte most of the time. Well it depends on the data you want to compress. I have done the speed test with a photo.

Edit: Updated code.
I ported my 64bit portation back to 32bit and take the optimizions from 64bit for the 32bit code. Now the source have both 64bit and 32bit versions with the same procedure name. It only compiles the matching version.

The 32bit code is as fast as the 64bit code. So it's faster than the PureBasic integrated decompression routine.
Marco2007
Enthusiast
Enthusiast
Posts: 648
Joined: Tue Jun 12, 2007 10:30 am
Location: not there...

Post by Marco2007 »

I don`t even understand the comments in the code :shock:
PureBasic for Windows
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Post by Thorium »

Marco2007 wrote:I don`t even understand the comments in the code :shock:
Well, then we have something in common. :D
Actually i don't understand the source, i just understand small parts of it. And i was surprised that i got it to work.

You can get the original source code directly from the developer: http://www.bitsum.com/files/jcalg1_r534.zip
Post Reply