// File: /workspace/github_c_makefile_star2_O3/snej[P]zdelta/inffast.c
// Function: inflate_fast
int inflate_fast(bl, bd, bzd, tl, td, tzd, s, z)
uInt bl, bd, bzd;
inflate_huft *tl;
inflate_huft *td;
inflate_huft *tzd; /* need separate declaration for Borland C++ */
inflate_blocks_statef *s;
zd_streamp z;
{
  inflate_huft *t;      /* temporary pointer */
  uInt e;               /* extra bits or operation */
  uLong b;              /* bit buffer */
  uInt k;               /* bits in bit buffer */
  Bytef *p;             /* input data pointer */
  uInt n;               /* bytes available there */
  Bytef *q;             /* output window write pointer */
  uInt m;               /* bytes to end of window or read pointer */
  uInt ml;              /* mask for literal/length tree */
  uInt md;              /* mask for distance tree */
  uInt mzd;             /* mask for zdelta code tree */
  uInt c;               /* bytes to copy */
  uInt d;               /* distance back to copy from */
  Bytef *r;             /* copy source pointer */

  /* zdelta local variables, needed to handle the reference window ptrs */
  uInt sign;
  uInt best_ptr;
  ulg ptr;
  ulg *rwptr = s->rwptr;         /* zdelta: reference window ptr */
  /* uInt zd_bcode; */                /* zdelta: byte code */
  /* load input, output, bit values */
  LOAD

  /* initialize masks */
  ml = inflate_mask[bl];
  md = inflate_mask[bd];
  mzd = inflate_mask[bzd];

  /* do until not enough input or output space for fast loop */
  do {                          /* assume called with m >= 258 && n >= 10 */
    /* get literal/distance code */
    GRABBITS(15) /* max bits for literal/distance code */
    if ((e = (t = td + ((uInt)b & md))->exop) == 0)
    {
      Assert(t->bits <= k, "dumping too many bits (literal)");
      DUMPBITS(t->bits)
      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
                "inflate:        * literal '%c'\n" :
                "inflate:        * literal 0x%02x\n", t->base));
      /* output the literal here */
      *q++ = (Byte)t->base;
      TraceHuf( (stderr, "d:%u\n", t->base) );
      m--;
      continue;
    }
    do {
      Assert(t->bits <= k, "dumping too many bits (dist)");
      DUMPBITS(t->bits)
      if (e & 16)
      {
	e &= 15;
	GRABBITS(e) /* get extra bits for distance (up to 13) */
	d = t->base + ((uInt)b & inflate_mask[e]);
	Assert(e <= k, "dumping too many bits (dist extra)");
	DUMPBITS(e)
        Tracevv((stderr, "inflate:         * distance %u\n", c));

        /* decode length base of block to copy */
        GRABBITS(24);           /* max bits for length code and extra */
        e = (t = tl + ((uInt)b & ml))->exop;
        do {
	  Assert(t->bits <= k, "dumping too many bits (len)");
          DUMPBITS(t->bits)
          if (e & 16)
          {
            /* get extra bits to add to distance base */
            e &= 15;
            c = t->base + ((uInt)b & inflate_mask[e]);
	    Assert(e <= k, "dumping too many bits (len extra)");
            DUMPBITS(e)
            Tracevv((stderr, "inflate:         * length %u\n", d));

	    if( c & REFMATCH ) {             /* if reference copy          */
	      sign = (c >> 8) & ZD_MINUS;    /* get distance sign          */
	      c   &= (REFMATCH-1);
	      
	      GRABBITS(15)                  /* max bits for ZDELTA flag code */
	      e = (t = tzd + ((uInt)b & mzd))->exop;
	      do{
		Assert(t->bits <= k, "dumping too many bits (zdelta)");
		DUMPBITS(t->bits);
		if(e == 0){
		  best_ptr = (Byte)t->base;  /* get reference pointer      */

		  /* jump to the beginning of the copy */
                  if(ZD_PLUS == sign) {
                    ptr = rwptr[best_ptr] + d;
                  } else {
                    ptr = rwptr[best_ptr] - d;
                  }

		  /* do the copy */
		  memcpy(q,z->base[best_ptr/2]+ptr,c);
		  q += c;                    /* update pointers            */
		  m -= c;   /* update the number of available output bytes */

		  if(d > ZD_FAR){ 	     /* update reference pointers  */
		    if(s->stable[best_ptr])
		      s->stable[best_ptr] = 0;
		    else
		      rwptr[best_ptr] = ptr + c;
		  }
		  else{
		    s->stable[best_ptr] = 1;
		    rwptr[best_ptr] = ptr + c;
		  }
		  break;
		}
		if( (e & 64) == 0 ){
		  t += t->base;
		  e = (t += ((uInt)b & inflate_mask[e]))->exop;
		}
		else{
		  z->msg = (char*)"invalid zdelta code";
		  UNGRAB
		  UPDATE
		  return ZD_DATA_ERROR;
		}
	      } while(1); /* zdelta code */
	    }
	    else{
	      m -= c;    /* update the number of available output bytes     */
	      if ((uInt)(q - s->window) >= d)   /*    offset before dest    */
	      {                                 /*    just copy             */
		r = q - d;
		*q++ = *r++;  c--;              /* minimum count is three,  */
		*q++ = *r++;  c--;              /* so unroll loop a little  */
	      }
	      else                        /* else offset after destination  */
	      {
		e = d - (uInt)(q - s->window);  /* bytes from offset to end */
		r = s->end - e;                 /* pointer to offset        */
		if (c > e)                      /* if source crosses,       */
		{	
		  c -= e;                       /* copy to end of window    */
		  do {
		    *q++ = *r++;
		  } while (--e);
		  r = s->window;          /* copy rest from start of window */
		}
	      }
	      do {                              /* copy all or what's left  */
		*q++ = *r++;
	      } while (--c);
	    }
	    break;
          }
          else if ((e & 64) == 0)
	  {
	    t += t->base;
	    e = (t += ((uInt)b & inflate_mask[e]))->exop;
	  }
          else
	  {
	    z->msg = (char*)"invalid length code";
	    UNGRAB
	    UPDATE
	    return ZD_DATA_ERROR;
          }
        } while (1);                                        /* length code */
        break;
      }
      if ((e & 64) == 0)
      {
	t += t->base;
	if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
        {
	  DUMPBITS(t->bits)
	  Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
		   "inflate:         * literal '%c'\n" :
		   "inflate:         * literal 0x%02x\n", t->base));
	  *q++ = (Byte)t->base;
	  m--;
	  break;
	}
      }
      else if (e & 32)
      {
	Tracevv((stderr, "inflate:         * end of block\n"));
	UNGRAB
        UPDATE
	return ZD_STREAM_END;
      }
      else
      {
	z->msg = (char*)"invalid literal/distance code";
	UNGRAB
        UPDATE
	return ZD_DATA_ERROR;
      }
    } while (1);                                          /* distance code */
/* zdelta: maximum match length is 1026 
 * } while (m >= 258 && n >= 10); 
 */
  } while (m >= MAX_MATCH && n >= 10); 
  /* not enough input or output--restore pointers and return */
  UNGRAB
  UPDATE
  return ZD_OK;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %r9, 0x40(%rsp)
movq %rcx, %r9
movq 0x88(%rsp), %r10
movq 0x80(%rsp), %r11
movq 0x58(%r11), %rbx
movq 0x50(%r11), %rcx
cmpq %rcx, %rbx
jae 0x8166
movq %rbx, %rax
notq %rax
addq %rax, %rcx
jmp 0x816d
movq 0x48(%r11), %rcx
subq %rbx, %rcx
movq (%r10), %r13
movl 0x8(%r10), %r12d
movq 0x30(%r11), %r15
movl 0x2c(%r11), %r14d
movl %edi, %eax
leaq 0x801b(%rip), %rdi      # 0x101a0
movl (%rdi,%rax,4), %eax
movl %eax, 0x28(%rsp)
movl %esi, %eax
movl (%rdi,%rax,4), %eax
movl %eax, 0x2c(%rsp)
movl %edx, %eax
movl (%rdi,%rax,4), %eax
movl %eax, 0x24(%rsp)
cmpl $0xe, %r14d
movq %rcx, (%rsp)
ja 0x81c9
movl %r14d, %r14d
movq %r14, %rcx
decl %r12d
movzbl (%r13), %eax
shlq %cl, %rax
incq %r13
orq %rax, %r15
addq $0x8, %r14
cmpq $0x7, %rcx
jb 0x81ab
movl 0x2c(%rsp), %eax
andl %r15d, %eax
leaq (%r8,%rax,8), %rdx
movb (%rdx), %sil
testb %sil, %sil
je 0x8216
movzbl 0x1(%rdx), %ecx
shrq %cl, %r15
movzbl %sil, %edi
subl %ecx, %r14d
testb $0x10, %dil
jne 0x824b
testb $0x40, %sil
jne 0x8500
movl 0x4(%rdx), %eax
leaq (%rdx,%rax,8), %rax
movl %edi, %ecx
leaq 0x7f96(%rip), %rdx      # 0x101a0
movl (%rdx,%rcx,4), %ecx
andl %r15d, %ecx
leaq (%rax,%rcx,8), %rdx
jmp 0x81d4
movzbl 0x1(%rdx), %ecx
shrq %cl, %r15
subl %ecx, %r14d
movb 0x4(%rdx), %al
movb %al, (%rbx)
incq %rbx
movq (%rsp), %rcx
decl %ecx
xorl %eax, %eax
cmpl $0x1002, %ecx           # imm = 0x1002
jb 0x8530
cmpl $0x9, %r12d
ja 0x819e
jmp 0x8530
andl $0xf, %edi
movl %edi, %eax
cmpl %edi, %r14d
jae 0x8275
movl %r14d, %r14d
decl %r12d
movzbl (%r13), %esi
movl %r14d, %ecx
shlq %cl, %rsi
incq %r13
orq %rsi, %r15
addq $0x8, %r14
cmpq %rax, %r14
jb 0x8258
movq %r15, %rsi
movl %eax, %ecx
shrq %cl, %rsi
subl %edi, %r14d
cmpl $0x17, %r14d
ja 0x82a7
movl %r14d, %r14d
movq %r14, %rcx
decl %r12d
movzbl (%r13), %edi
shlq %cl, %rdi
incq %r13
orq %rdi, %rsi
addq $0x8, %r14
cmpq $0x10, %rcx
jb 0x8289
leaq 0x7ef2(%rip), %rcx      # 0x101a0
andl (%rcx,%rax,4), %r15d
movl %r15d, %ebp
addl 0x4(%rdx), %ebp
movl 0x28(%rsp), %eax
andl %esi, %eax
leaq (%r9,%rax,8), %rdx
movzbl 0x1(%rdx), %eax
movl %eax, %ecx
shrq %cl, %rsi
movb (%rdx), %dil
movzbl %dil, %ecx
subl %eax, %r14d
testb $0x10, %cl
jne 0x8300
testb $0x40, %cl
jne 0x8514
movl 0x4(%rdx), %eax
leaq (%rdx,%rax,8), %rax
movzbl %dil, %ecx
leaq 0x7eab(%rip), %rdx      # 0x101a0
movl (%rdx,%rcx,4), %ecx
andl %esi, %ecx
leaq (%rax,%rcx,8), %rdx
jmp 0x82c2
andl $0xf, %ecx
leaq 0x7e96(%rip), %rax      # 0x101a0
movl (%rax,%rcx,4), %eax
andl %esi, %eax
movq %rsi, %r15
shrq %cl, %r15
addl 0x4(%rdx), %eax
subl %ecx, %r14d
btl $0xe, %eax
jb 0x8363
movl 0x40(%r11), %ecx
movl %ebx, %esi
subl %ecx, %esi
movl %ebp, %edx
subl %esi, %edx
jbe 0x8471
movq 0x48(%r11), %rcx
subq %rdx, %rcx
cmpl %edx, %eax
jbe 0x84b6
xorl %edi, %edi
movb (%rcx,%rdi), %sil
movb %sil, (%rbx,%rdi)
incq %rdi
cmpl %edi, %edx
jne 0x8344
movl %eax, %esi
subl %edx, %esi
movq 0x40(%r11), %rcx
addq %rdi, %rbx
jmp 0x84b8
cmpl $0xe, %r14d
ja 0x838a
movl %r14d, %r14d
movq %r14, %rcx
decl %r12d
movzbl (%r13), %edx
shlq %cl, %rdx
incq %r13
orq %rdx, %r15
addq $0x8, %r14
cmpq $0x7, %rcx
jb 0x836c
movl 0x24(%rsp), %ecx
andl %r15d, %ecx
movq 0x40(%rsp), %rdx
leaq (%rdx,%rcx,8), %rdx
movzbl 0x1(%rdx), %ecx
shrq %cl, %r15
movb (%rdx), %sil
subl %ecx, %r14d
testb %sil, %sil
je 0x83d4
testb $0x40, %sil
jne 0x8520
movl 0x4(%rdx), %ecx
leaq (%rdx,%rcx,8), %rcx
movzbl %sil, %edx
leaq 0x7dd8(%rip), %rsi      # 0x101a0
movl (%rsi,%rdx,4), %edx
andl %r15d, %edx
leaq (%rcx,%rdx,8), %rdx
jmp 0x839a
movq %r9, 0x8(%rsp)
movq %r8, 0x10(%rsp)
movl %eax, %ecx
andl $0x3fff, %ecx           # imm = 0x3FFF
movl %ecx, %edi
movl %ecx, 0x1c(%rsp)
movl 0x4(%rdx), %ecx
movzbl %cl, %esi
movl %ebp, 0x20(%rsp)
movl %ebp, %edx
movq %rdx, %rbp
negq %rbp
testw %ax, %ax
movq %rsi, 0x30(%rsp)
movl %esi, %eax
cmovnsq %rdx, %rbp
addq 0x70(%r11,%rax,8), %rbp
andl $0xfe, %ecx
movq 0x30(%r10,%rcx,4), %rsi
addq %rbp, %rsi
movl %edi, %edx
movq %rdx, 0x38(%rsp)
movq %rbx, %rdi
callq 0x10f0
movq 0x38(%rsp), %rdx
addq %rdx, %rbx
movq (%rsp), %rcx
subl 0x1c(%rsp), %ecx
cmpl $0x101, 0x20(%rsp)      # imm = 0x101
jb 0x8490
movq 0x30(%rsp), %rax
movq 0x80(%rsp), %rsi
cmpq $0x0, 0x80(%rsi,%rax,8)
movq %rsi, %r11
je 0x84e1
movq $0x0, 0x80(%r11,%rax,8)
jmp 0x84e9
movl %ebp, %edx
movq %rbx, %rcx
subq %rdx, %rcx
movb (%rcx), %dl
movb %dl, (%rbx)
movb 0x1(%rcx), %dl
addq $0x2, %rcx
movb %dl, 0x1(%rbx)
addq $0x2, %rbx
leal -0x2(%rax), %esi
jmp 0x84b8
movq 0x30(%rsp), %rax
movq 0x80(%rsp), %rsi
movq $0x1, 0x80(%rsi,%rax,8)
addq %rdx, %rbp
movq %rbp, 0x70(%rsi,%rax,8)
movq %rsi, %r11
jmp 0x84e9
movl %eax, %esi
movq (%rsp), %rdx
subl %eax, %edx
movq %rdx, (%rsp)
movl %esi, %eax
xorl %edx, %edx
movb (%rcx,%rdx), %sil
movb %sil, (%rbx,%rdx)
incq %rdx
cmpl %edx, %eax
jne 0x84c6
addq %rdx, %rbx
movq (%rsp), %rcx
jmp 0x822e
addq %rdx, %rbp
movq %rbp, 0x70(%r11,%rax,8)
movq 0x88(%rsp), %r10
movq 0x10(%rsp), %r8
movq 0x8(%rsp), %r9
jmp 0x822e
movl $0x1, %eax
testb $0x20, %sil
jne 0x8530
leaq 0x1cac(%rip), %rax      # 0xa1be
jmp 0x8527
movq %rsi, %r15
leaq 0x1c8c(%rip), %rax      # 0xa1aa
jmp 0x8527
leaq 0x1c6f(%rip), %rax      # 0xa196
movq %rax, 0x50(%r10)
movl $0xfffffffd, %eax       # imm = 0xFFFFFFFD
movl 0x8(%r10), %ecx
subl %r12d, %ecx
movl %r14d, %edx
shrl $0x3, %edx
cmpl %ecx, %edx
cmovael %ecx, %edx
addl %edx, %r12d
subq %rdx, %r13
shll $0x3, %edx
subl %edx, %r14d
movq %r15, 0x30(%r11)
movl %r14d, 0x2c(%r11)
movl %r12d, 0x8(%r10)
movq %r13, %rcx
subq (%r10), %rcx
addq %rcx, 0x10(%r10)
movq %r13, (%r10)
movq %rbx, 0x58(%r11)
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop