// File: /workspace/github_c_makefile_star2_O3/Cyan4973[P]FiniteStateEntropy/programs/fileio.c
// Function: FIO_decompressFilename
unsigned long long FIO_decompressFilename(const char* output_filename, const char* input_filename)
{
    FILE* finput, *foutput;
    U64   filesize = 0;
    BYTE* in_buff;
    BYTE* out_buff;
    BYTE* ip;
    U32   blockSize;
    XXH32_state_t xxhState;
    typedef size_t (*decompressor_t) (void* dst, size_t dstSize, const void* src, size_t srcSize);
    decompressor_t decompressor = FSE_decompress;

    /* Init */
    XXH32_reset(&xxhState, FSE_CHECKSUM_SEED);
    get_fileHandle(input_filename, output_filename, &finput, &foutput);

    /* check header */
    {   BYTE header[FIO_FRAMEHEADERSIZE];

        { size_t const sizeCheck = fread(header, (size_t)1, FIO_FRAMEHEADERSIZE, finput);
          if (sizeCheck != FIO_FRAMEHEADERSIZE) EXM_THROW(30, "Read error : cannot read header\n"); }

        switch(FIO_readLE32(header))   /* magic number */
        {
        case FIO_magicNumber_fse:
            DISPLAYLEVEL(5, "compressed with fse \n");
            decompressor = FSE_decompress;
            break;
        case FIO_magicNumber_huf:
            DISPLAYLEVEL(5, "compressed with huff0 \n");
            decompressor = HUF_decompress;
            break;
        case FIO_magicNumber_zlibh:
            DISPLAYLEVEL(5, "compressed with zlib's huffman \n");
            decompressor = FIO_ZLIBH_decompress;
            break;
        default :
            EXM_THROW(31, "Wrong file type : unknown header\n");
        }

        {   U32 const blockSizeId = header[4];
            if (blockSizeId > FIO_maxBlockSizeID)
                EXM_THROW(32, "Wrong version : unknown header flags\n");
            blockSize = FIO_blockID_to_blockSize(blockSizeId);
    }   }

    /* Allocate Memory */
    in_buff  = (BYTE*)malloc(blockSize + FIO_maxBlockHeaderSize);
    out_buff = (BYTE*)malloc(blockSize);
    if (!in_buff || !out_buff) EXM_THROW(33, "Allocation error : not enough memory");

    /* read first block header */
    { size_t const sizeCheck = fread(in_buff, 1, 1, finput);
      if (sizeCheck != 1) EXM_THROW(34, "Read error : cannot read header\n");
      ip = in_buff;
    }

    /* Main Loop */
    while (1) {
        size_t rSize=blockSize, cSize;

        /* Decode header */
        int const bType = (ip[0] & (BIT7+BIT6)) >> 6;
        DISPLAYLEVEL(6, "next block type == %i \n", bType);
        DISPLAYLEVEL(7, "read block descriptor : %u \n", ip[0]);
        if (bType == bt_crc) break;   /* end - frame content CRC */

        {   int const fullBlock = ip[0] & BIT5;
            DISPLAYLEVEL(6, "next block is full ? ==> %i \n", !!fullBlock);
            if (!fullBlock) {
                size_t const sizeCheck = fread(in_buff, 1, 2, finput);
                if (sizeCheck != 2) EXM_THROW(35, "Read error : cannot read header\n");
                rSize = (in_buff[0]<<8) + in_buff[1];
        }   }

        switch(bType)
        {
          case bt_compressed :
            {   size_t const sizeCheck = fread(in_buff, 1, 2, finput);
                if (sizeCheck != 2) EXM_THROW(36, "Read error : cannot read header\n");
                cSize = (in_buff[0]<<8) + in_buff[1];
                break;
            }
          case bt_raw :
            cSize = rSize;
            break;
          case bt_rle :
            cSize = 1;
            break;
          default :
          case bt_crc :
            cSize = 0;
            assert(0);   /* supposed already eliminated at this stage */
        }

        DISPLAYLEVEL(6, "next block has a compressed size of %zu, and an original size of %zu \n",
                        cSize, rSize);

        /* Fill input buffer */
        {   size_t const toReadSize = cSize + 1;
            size_t const readSize = fread(in_buff, 1, toReadSize, finput);
            if (readSize != toReadSize) EXM_THROW(38, "Read error");
            ip = in_buff + cSize;   /* end - 1 */
        }

        /* Decode block */
        switch(bType)
        {
          case bt_compressed :
            rSize = decompressor(out_buff, rSize, in_buff, cSize);
            if (FSE_isError(rSize))
                EXM_THROW(39, "Decoding error : %s", FSE_getErrorName(rSize));
            break;
          case bt_raw :
            /* will read directly from in_buff, so no need to memcpy */
            break;
          case bt_rle :
            memset(out_buff, in_buff[0], rSize);
            break;
          default :
          case bt_crc :
            assert(0);   /* supposed already eliminated at this stage */
        }

        /* Write block */
        switch(bType)
        {
          case bt_compressed :
          case bt_rle :
            { size_t const writeSizeCheck = fwrite(out_buff, 1, rSize, foutput);
              if (writeSizeCheck != rSize) EXM_THROW(41, "Write error : unable to write data block to destination file"); }
            XXH32_update(&xxhState, out_buff, rSize);
            filesize += rSize;
            break;
          case bt_raw :
            { size_t const writeSizeCheck = fwrite(in_buff, 1, cSize, foutput);
              if (writeSizeCheck != cSize) EXM_THROW(42, "Write error : unable to write data block to destination file"); }
            XXH32_update(&xxhState, in_buff, cSize);
            filesize += cSize;
            break;
          default :
          case bt_crc :
            assert(0);   /* supposed already eliminated at this stage */
        }
    }

    /* CRC verification */
    { size_t const sizeCheck = fread(ip+1, 1, 2, finput);
      if (sizeCheck != 2) EXM_THROW(43, "Read error"); }
    {   U32 const CRCsaved = ip[2] + (ip[1]<<8) + ((ip[0] & _6BITS) << 16);
        U32 const CRCcalculated = (XXH32_digest(&xxhState) >> 5) & ((1U<<22)-1);
        if (CRCsaved != CRCcalculated) EXM_THROW(44, "CRC error : wrong checksum, corrupted data");
    }

    DISPLAYLEVEL(2, "\r%79s\r", "");
    DISPLAYLEVEL(2, "Decoded %llu bytes\n", (long long unsigned)filesize);

    /* clean */
    free(in_buff);
    free(out_buff);
    fclose(finput);
    fclose(foutput);

    return filesize;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movq %rsi, %rbx
movq %rdi, %r14
leaq 0x48(%rsp), %rdi
xorl %esi, %esi
callq 0x57f1
leaq 0x40(%rsp), %r15
leaq 0x28(%rsp), %rcx
movq %rbx, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x4e18
movq (%r15), %rcx
leaq 0x8(%rsp), %rdi
movl $0x1, %esi
movl $0x5, %edx
movq %rcx, (%rsp)
callq 0x1060
cmpq $0x5, %rax
jne 0x53d5
movl 0x8(%rsp), %ecx
movl 0x15114(%rip), %eax     # 0x1a0f4
cmpl $0x183e4309, %ecx       # imm = 0x183E4309
je 0x502c
cmpl $0x183e3309, %ecx       # imm = 0x183E3309
je 0x5014
cmpl $0x183e2309, %ecx       # imm = 0x183E2309
jne 0x5460
leaq 0x3ad5(%rip), %rcx      # 0x8ad8
movq %rcx, 0x10(%rsp)
cmpl $0x5, %eax
jl 0x5041
callq 0x274a
jmp 0x5041
leaq 0xac4c(%rip), %rcx      # 0xfc67
movq %rcx, 0x10(%rsp)
cmpl $0x5, %eax
jl 0x5041
callq 0x2728
jmp 0x5041
leaq -0xc7(%rip), %rcx       # 0x4f6c
movq %rcx, 0x10(%rsp)
cmpl $0x5, %eax
jge 0x5338
movzbl 0xc(%rsp), %ecx
cmpq $0x7, %rcx
jae 0x53ed
movl $0x400, %ebx            # imm = 0x400
shlq %cl, %rbx
leaq 0x5(%rbx), %rdi
callq 0x1150
movq %rax, %rbp
movl %ebx, %edi
movq %rdi, 0x30(%rsp)
callq 0x1150
testq %rbp, %rbp
je 0x5405
movq %rax, %r15
testq %rax, %rax
je 0x5405
movl $0x1, %esi
movl $0x1, %edx
movq %rbp, %rdi
movq (%rsp), %rcx
callq 0x1060
cmpq $0x1, %rax
jne 0x541d
movq 0x28(%rsp), %rax
movq %rax, 0x20(%rsp)
movq %rbp, %r13
xorl %r14d, %r14d
movzbl (%r13), %r12d
shrl $0x6, %r12d
cmpl $0x6, 0x1502f(%rip)     # 0x1a0f4
movzbl %r12b, %ebx
jge 0x5259
cmpb $0x3, %r12b
je 0x5299
movl %ebx, 0x1c(%rsp)
movq %r14, 0x38(%rsp)
movq %r15, %rbx
movb (%r13), %r15b
andb $0x20, %r15b
cmpl $0x6, 0x15000(%rip)     # 0x1a0f4
jge 0x5268
movq 0x30(%rsp), %r14
testb %r15b, %r15b
jne 0x5130
movl $0x1, %esi
movl $0x2, %edx
movq %rbp, %rdi
movq (%rsp), %rcx
callq 0x1060
cmpq $0x2, %rax
jne 0x5372
movzwl (%rbp), %eax
rolw $0x8, %ax
movzwl %ax, %r14d
cmpl $0x2, %r12d
je 0x516d
movq %r14, %r13
cmpl $0x1, %r12d
je 0x5173
movl $0x1, %esi
movl $0x2, %edx
movq %rbp, %rdi
movq (%rsp), %rcx
callq 0x1060
cmpq $0x2, %rax
jne 0x53a5
movzwl (%rbp), %eax
rolw $0x8, %ax
movzwl %ax, %r13d
jmp 0x5173
movl $0x1, %r13d
cmpl $0x6, 0x14f7a(%rip)     # 0x1a0f4
jge 0x5276
leaq 0x1(%r13), %r15
movl $0x1, %esi
movq %rbp, %rdi
movq %r15, %rdx
movq (%rsp), %rcx
callq 0x1060
cmpq %r15, %rax
jne 0x5342
cmpb $0x2, %r12b
movq %rbx, %r15
je 0x51e4
cmpl $0x1, 0x1c(%rsp)
jne 0x51f5
movl $0x1, %esi
movq %rbp, %rdi
movq %r13, %rdx
movq 0x20(%rsp), %rcx
callq 0x1190
cmpq %r13, %rax
jne 0x53bd
leaq 0x48(%rsp), %rdi
movq %rbp, %rsi
movq %r13, %rdx
callq 0x587d
movq %r13, %r14
jmp 0x5246
movzbl (%rbp), %esi
movq %r15, %rdi
movq %r14, %rdx
callq 0x10c0
jmp 0x5218
movq %r15, %rdi
movq %r14, %rsi
movq %rbp, %rdx
movq %r13, %rcx
callq *0x10(%rsp)
movq %rax, %r14
movq %rax, %rdi
callq 0x7712
testl %eax, %eax
jne 0x538a
movl $0x1, %esi
movq %r15, %rdi
movq %r14, %rdx
movq 0x20(%rsp), %rcx
callq 0x1190
cmpq %r14, %rax
jne 0x535a
leaq 0x48(%rsp), %rdi
movq %r15, %rsi
movq %r14, %rdx
callq 0x587d
addq %rbp, %r13
movq 0x38(%rsp), %rax
addq %r14, %rax
movq %rax, %r14
jmp 0x50b5
movl %ebx, %edi
movq %r13, %rsi
callq 0x2810
jmp 0x50cf
movzbl %r15b, %edi
callq 0x285a
jmp 0x50fa
movq 0x14d7b(%rip), %rax     # 0x19ff8
movq (%rax), %rdi
leaq 0xea9e(%rip), %rsi      # 0x13d25
movq %r13, %rdx
movq %r14, %rcx
xorl %eax, %eax
callq 0x1110
jmp 0x5180
leaq 0x1(%r13), %rdi
movl $0x1, %esi
movl $0x2, %edx
movq (%rsp), %rcx
callq 0x1060
cmpq $0x2, %rax
jne 0x5435
movzwl 0x1(%r13), %eax
rolw $0x8, %ax
movzwl %ax, %eax
movzbl (%r13), %ebx
andl $0x3f, %ebx
shll $0x10, %ebx
orl %eax, %ebx
leaq 0x48(%rsp), %rdi
callq 0x5a08
shrl $0x5, %eax
andl $0x3fffff, %eax         # imm = 0x3FFFFF
movl 0x14e09(%rip), %ecx     # 0x1a0f4
cmpl %eax, %ebx
jne 0x544d
cmpl $0x2, %ecx
jge 0x532e
movq %rbp, %rdi
callq 0x1030
movq %r15, %rdi
callq 0x1030
movq 0x40(%rsp), %rdi
callq 0x1080
movq 0x28(%rsp), %rdi
callq 0x1080
movq %r14, %rax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r14, %rdi
callq 0x2b28
jmp 0x52f8
callq 0x2706
jmp 0x5041
cmpl $0x0, 0x14dab(%rip)     # 0x1a0f4
jle 0x5350
callq 0x2927
movl $0x26, %edi
callq 0x1180
cmpl $0x0, 0x14d93(%rip)     # 0x1a0f4
jle 0x5368
callq 0x2a32
movl $0x29, %edi
callq 0x1180
cmpl $0x0, 0x14d7b(%rip)     # 0x1a0f4
jle 0x5380
callq 0x2883
movl $0x23, %edi
callq 0x1180
cmpl $0x0, 0x14d63(%rip)     # 0x1a0f4
jle 0x539b
movq %r14, %rdi
callq 0x29cb
movl $0x27, %edi
callq 0x1180
cmpl $0x0, 0x14d48(%rip)     # 0x1a0f4
jle 0x53b3
callq 0x28d5
movl $0x24, %edi
callq 0x1180
cmpl $0x0, 0x14d30(%rip)     # 0x1a0f4
jle 0x53cb
callq 0x2979
movl $0x2a, %edi
callq 0x1180
cmpl $0x0, 0x14d18(%rip)     # 0x1a0f4
jle 0x53e3
callq 0x26b4
movl $0x1e, %edi
callq 0x1180
cmpl $0x0, 0x14d00(%rip)     # 0x1a0f4
jle 0x53fb
callq 0x2b75
movl $0x20, %edi
callq 0x1180
cmpl $0x0, 0x14ce8(%rip)     # 0x1a0f4
jle 0x5413
callq 0x276c
movl $0x21, %edi
callq 0x1180
cmpl $0x0, 0x14cd0(%rip)     # 0x1a0f4
jle 0x542b
callq 0x27be
movl $0x22, %edi
callq 0x1180
cmpl $0x0, 0x14cb8(%rip)     # 0x1a0f4
jle 0x5443
callq 0x2a84
movl $0x2b, %edi
callq 0x1180
testl %ecx, %ecx
jle 0x5456
callq 0x2ad6
movl $0x2c, %edi
callq 0x1180
testl %eax, %eax
jle 0x5469
callq 0x2bc7
movl $0x1f, %edi
callq 0x1180
nop