// File: VanAndelInstitute[P]intent/include/zstr.hpp
// Function: zstr::istreambuf::underflow()
virtual std::streambuf::int_type underflow()
    {
        if (this->gptr() == this->egptr())
        {
            // pointers for free region in output buffer
            char * out_buff_free_start = out_buff;
            do
            {
                // read more input if none available
                if (in_buff_start == in_buff_end)
                {
                    // empty input buffer: refill from the start
                    in_buff_start = in_buff;
                    std::streamsize sz = sbuf_p->sgetn(in_buff, buff_size);
                    in_buff_end = in_buff + sz;
                    if (in_buff_end == in_buff_start) break; // end of input
                }
                // auto detect if the stream contains text or deflate data
                if (auto_detect && ! auto_detect_run)
                {
                    auto_detect_run = true;
                    unsigned char b0 = *reinterpret_cast< unsigned char * >(in_buff_start);
                    unsigned char b1 = *reinterpret_cast< unsigned char * >(in_buff_start + 1);
                    // Ref:
                    // http://en.wikipedia.org/wiki/Gzip
                    // http://stackoverflow.com/questions/9050260/what-does-a-zlib-header-look-like
                    is_text = ! (in_buff_start + 2 <= in_buff_end
                                 && ((b0 == 0x1F && b1 == 0x8B)         // gzip header
                                     || (b0 == 0x78 && (b1 == 0x01      // zlib header
                                                        || b1 == 0x9C
                                                        || b1 == 0xDA))));
                }
                if (is_text)
                {
                    // simply swap in_buff and out_buff, and adjust pointers
                    assert(in_buff_start == in_buff);
                    std::swap(in_buff, out_buff);
                    out_buff_free_start = in_buff_end;
                    in_buff_start = in_buff;
                    in_buff_end = in_buff;
                }
                else
                {
                    // run inflate() on input
                    if (! zstrm_p) zstrm_p = new detail::z_stream_wrapper(true);
                    zstrm_p->next_in = reinterpret_cast< decltype(zstrm_p->next_in) >(in_buff_start);
                    zstrm_p->avail_in = in_buff_end - in_buff_start;
                    zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff_free_start);
                    zstrm_p->avail_out = (out_buff + buff_size) - out_buff_free_start;
                    int ret = inflate(zstrm_p, Z_NO_FLUSH);
                    // process return code
                    if (ret != Z_OK && ret != Z_STREAM_END) throw Exception(zstrm_p, ret);
                    // update in&out pointers following inflate()
                    in_buff_start = reinterpret_cast< decltype(in_buff_start) >(zstrm_p->next_in);
                    in_buff_end = in_buff_start + zstrm_p->avail_in;
                    out_buff_free_start = reinterpret_cast< decltype(out_buff_free_start) >(zstrm_p->next_out);
                    assert(out_buff_free_start + zstrm_p->avail_out == out_buff + buff_size);
                    // if stream ended, deallocate inflator
                    if (ret == Z_STREAM_END)
                    {
                        delete zstrm_p;
                        zstrm_p = nullptr;
                    }
                }
            } while (out_buff_free_start == out_buff);
            // 2 exit conditions:
            // - end of input: there might or might not be output available
            // - out_buff_free_start != out_buff: output available
            this->setg(out_buff, out_buff, out_buff_free_start);
        }
        return this->gptr() == this->egptr()
            ? traits_type::eof()
            : traits_type::to_int_type(*this->gptr());
    }

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x70, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0x40(%rbp)
callq 0x81a0
movq -0x40(%rbp), %rdi
movq %rax, -0x38(%rbp)
callq 0x88a0
movq %rax, %rcx
movq -0x38(%rbp), %rax
cmpq %rcx, %rax
jne 0x376c6
movq -0x40(%rbp), %rax
movq 0x60(%rax), %rax
movq %rax, -0x10(%rbp)
movq -0x40(%rbp), %rcx
movq 0x50(%rcx), %rax
cmpq 0x58(%rcx), %rax
jne 0x373b2
movq -0x40(%rbp), %rax
movq 0x48(%rax), %rcx
movq %rcx, 0x50(%rax)
movq 0x40(%rax), %rdi
movq 0x48(%rax), %rsi
movq 0x70(%rax), %rdx
callq 0x8100
movq -0x40(%rbp), %rcx
movq %rax, -0x18(%rbp)
movq 0x48(%rcx), %rax
addq -0x18(%rbp), %rax
movq %rax, 0x58(%rcx)
movq 0x58(%rcx), %rax
cmpq 0x50(%rcx), %rax
jne 0x373b0
jmp 0x376b1
jmp 0x373b2
movq -0x40(%rbp), %rax
testb $0x1, 0x78(%rax)
je 0x37474
movq -0x40(%rbp), %rax
testb $0x1, 0x79(%rax)
jne 0x37474
movq -0x40(%rbp), %rdx
movb $0x1, 0x79(%rdx)
movq 0x50(%rdx), %rax
movb (%rax), %al
movb %al, -0x19(%rbp)
movq 0x50(%rdx), %rax
movb 0x1(%rax), %al
movb %al, -0x1a(%rbp)
movq 0x50(%rdx), %rcx
addq $0x2, %rcx
xorl %eax, %eax
cmpq 0x58(%rdx), %rcx
movb %al, -0x41(%rbp)
ja 0x37464
movzbl -0x19(%rbp), %eax
cmpl $0x1f, %eax
jne 0x37416
movzbl -0x1a(%rbp), %ecx
movb $0x1, %al
cmpl $0x8b, %ecx
movb %al, -0x42(%rbp)
je 0x3745e
movzbl -0x19(%rbp), %ecx
xorl %eax, %eax
cmpl $0x78, %ecx
movb %al, -0x43(%rbp)
jne 0x37458
movzbl -0x1a(%rbp), %ecx
movb $0x1, %al
cmpl $0x1, %ecx
movb %al, -0x44(%rbp)
je 0x37452
movzbl -0x1a(%rbp), %ecx
movb $0x1, %al
cmpl $0x9c, %ecx
movb %al, -0x44(%rbp)
je 0x37452
movzbl -0x1a(%rbp), %eax
cmpl $0xda, %eax
sete %al
movb %al, -0x44(%rbp)
movb -0x44(%rbp), %al
movb %al, -0x43(%rbp)
movb -0x43(%rbp), %al
movb %al, -0x42(%rbp)
movb -0x42(%rbp), %al
movb %al, -0x41(%rbp)
movq -0x40(%rbp), %rax
movb -0x41(%rbp), %cl
xorb $-0x1, %cl
andb $0x1, %cl
movb %cl, 0x7a(%rax)
movq -0x40(%rbp), %rax
testb $0x1, 0x7a(%rax)
je 0x374e2
movq -0x40(%rbp), %rcx
movq 0x50(%rcx), %rax
cmpq 0x48(%rcx), %rax
jne 0x3748e
jmp 0x374ad
leaq 0x381d0(%rip), %rdi     # 0x6f665
leaq 0x38176(%rip), %rsi     # 0x6f612
movl $0xab, %edx
leaq 0x381d6(%rip), %rcx     # 0x6f67e
callq 0x83e0
movq -0x40(%rbp), %rsi
movq %rsi, %rdi
addq $0x48, %rdi
addq $0x60, %rsi
callq 0x37770
movq -0x40(%rbp), %rax
movq 0x58(%rax), %rcx
movq %rcx, -0x10(%rbp)
movq 0x48(%rax), %rcx
movq %rcx, 0x50(%rax)
movq 0x48(%rax), %rcx
movq %rcx, 0x58(%rax)
jmp 0x3769d
movq -0x40(%rbp), %rax
cmpq $0x0, 0x68(%rax)
jne 0x3753f
movl $0x78, %edi
callq 0x8550
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x50(%rbp)
movl $0x1, %esi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x377b0
jmp 0x37512
movq -0x40(%rbp), %rax
movq -0x50(%rbp), %rcx
movq %rcx, 0x68(%rax)
jmp 0x3753f
movq -0x50(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
movl $0x78, %esi
callq 0x8560
jmp 0x3770f
movq -0x40(%rbp), %rax
movq 0x50(%rax), %rdx
movq 0x68(%rax), %rcx
movq %rdx, (%rcx)
movq 0x58(%rax), %rcx
movq 0x50(%rax), %rdx
subq %rdx, %rcx
movl %ecx, %edx
movq 0x68(%rax), %rcx
movl %edx, 0x8(%rcx)
movq -0x10(%rbp), %rdx
movq 0x68(%rax), %rcx
movq %rdx, 0x18(%rcx)
movq 0x60(%rax), %rcx
addq 0x70(%rax), %rcx
movq -0x10(%rbp), %rdx
subq %rdx, %rcx
movl %ecx, %edx
movq 0x68(%rax), %rcx
movl %edx, 0x20(%rcx)
movq 0x68(%rax), %rdi
xorl %esi, %esi
callq 0x8470
movl %eax, -0x30(%rbp)
cmpl $0x0, -0x30(%rbp)
je 0x375f7
cmpl $0x1, -0x30(%rbp)
je 0x375f7
movl $0x28, %edi
callq 0x82f0
movq %rax, %rdi
movq -0x40(%rbp), %rax
movq %rdi, %rcx
movq %rcx, -0x58(%rbp)
movq 0x68(%rax), %rsi
movl -0x30(%rbp), %edx
callq 0x378c0
jmp 0x375c6
movq -0x58(%rbp), %rdi
leaq 0x5615f(%rip), %rsi     # 0x8d730
leaq 0x5b8(%rip), %rdx       # 0x37b90
callq 0x8920
movq -0x58(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
callq 0x8440
jmp 0x3770f
movq -0x40(%rbp), %rdx
movq 0x68(%rdx), %rax
movq (%rax), %rax
movq %rax, 0x50(%rdx)
movq 0x50(%rdx), %rax
movq 0x68(%rdx), %rcx
movl 0x8(%rcx), %ecx
addq %rcx, %rax
movq %rax, 0x58(%rdx)
movq 0x68(%rdx), %rax
movq 0x18(%rax), %rax
movq %rax, -0x10(%rbp)
movq -0x10(%rbp), %rax
movq 0x68(%rdx), %rcx
movl 0x20(%rcx), %ecx
addq %rcx, %rax
movq 0x60(%rdx), %rcx
addq 0x70(%rdx), %rcx
cmpq %rcx, %rax
jne 0x37641
jmp 0x37660
leaq 0x38075(%rip), %rdi     # 0x6f6bd
leaq 0x37fc3(%rip), %rsi     # 0x6f612
movl $0xc0, %edx
leaq 0x38023(%rip), %rcx     # 0x6f67e
callq 0x83e0
cmpl $0x1, -0x30(%rbp)
jne 0x3769b
movq -0x40(%rbp), %rax
movq 0x68(%rax), %rax
movq %rax, -0x60(%rbp)
cmpq $0x0, %rax
je 0x3768f
movq -0x60(%rbp), %rdi
callq 0x37720
movq -0x60(%rbp), %rdi
movl $0x78, %esi
callq 0x8560
movq -0x40(%rbp), %rax
movq $0x0, 0x68(%rax)
jmp 0x3769d
jmp 0x3769f
movq -0x40(%rbp), %rcx
movq -0x10(%rbp), %rax
cmpq 0x60(%rcx), %rax
je 0x37362
movq -0x40(%rbp), %rdi
movq 0x60(%rdi), %rsi
movq 0x60(%rdi), %rdx
movq -0x10(%rbp), %rcx
callq 0x8820
movq -0x40(%rbp), %rdi
callq 0x81a0
movq -0x40(%rbp), %rdi
movq %rax, -0x68(%rbp)
callq 0x88a0
movq %rax, %rcx
movq -0x68(%rbp), %rax
cmpq %rcx, %rax
jne 0x376f2
callq 0x37bd0
movl %eax, -0x6c(%rbp)
jmp 0x37706
movq -0x40(%rbp), %rdi
callq 0x81a0
movq %rax, %rdi
callq 0x37be0
movl %eax, -0x6c(%rbp)
movl -0x6c(%rbp), %eax
addq $0x70, %rsp
popq %rbp
retq
movq -0x28(%rbp), %rdi
callq 0x8970
nopl (%rax,%rax)