// File: /workspace/github_cpp_makefile_star2_O3/dm4[P]huffman-homework/decode.cc
// Function: main
int main(int argc, const char *argv[]) {
    if (argc != 4) {
        fprintf(stderr, "Usage:\n");
        fprintf(stderr, "    %s huff_table_name compressed.txt decoded_symbol.txt\n", argv[0]);
        exit(1);
    }

    // read symbol-codeword table to construct symbol vector
    printf("Read symbol-codeword table from file: %s\n", argv[1]);
    FILE *fp = fopen(argv[1], "r");
    if (fp == NULL) {
        fprintf(stderr, "Invalid file: %s\n", argv[1]);
        exit(1);
    }
    Symbol tmp;
    while (fscanf(fp, "%s\n%s\n", tmp.symbol, tmp.codeword) != EOF) {
        Symbol *ptr = (Symbol *)malloc(sizeof(Symbol));
        strcpy(ptr->symbol, tmp.symbol);
        strcpy(ptr->codeword, tmp.codeword);
        ptr->cl = strlen(tmp.codeword);
        symbols.push_back(ptr);
    }
    fclose(fp);

    // sort
    printf("Sort by codewords\n");
    sort(symbols.begin(), symbols.end(), cmpSymbol);

    // LUT
    printf("Construct LUT\n");
    map<int, int> buildLUT;
    int height = 0;
    int previousBuildLUT = -1;
    for (int i = 0; i < symbols.size(); i++) {
        Symbol *p = symbols[i];
        if (p->cl > height) {
            height += 4;
        }

        // build new lookup
        int nowBuildLUT = bin2dec(0, height - 4, p->codeword);
        if (nowBuildLUT != previousBuildLUT) {
            Lookup *ptr = (Lookup *)malloc(sizeof(Lookup));
            LUT.push_back(ptr);
            buildLUT[nowBuildLUT] = LUT.size() - 1;
            previousBuildLUT = nowBuildLUT;

            // set link
            if (height >= 8) {
                int previousLUT = buildLUT[bin2dec(0, height - 8, p->codeword)];
                Lookup *previous = LUT[previousLUT];
                int index = bin2dec(height - 8, height - 4, p->codeword);
                previous->isSymbol[index] = false;
                previous->next[index] = LUT.size() - 1;
            }
        }

        // set lookup entries
        int depth = height - p->cl;
        int subNum  = 1 << depth;
        // 1111 1111 10, base is 8
        int base = calcBase(height, p->codeword);
        for (int j = 0; j < subNum; j++) {
            LUT[LUT.size() - 1]->isSymbol[base + j] = true;
            LUT[LUT.size() - 1]->next[base + j] = i;
        }
    }

    // print LUT
    if (1) {
        for (int i = 0; i < LUT.size(); i++) {
            printf("LUT[%d]\n", i);
            for (int j = 0; j < 16; j++) {
                Lookup *ptr = LUT[i];
                if (ptr->isSymbol[j]) {
                    printf("[%2d] %s %s\n", j, symbols[ptr->next[j]]->symbol, symbols[ptr->next[j]]->codeword);
                }
                else {
                    printf("[%2d] LUT[%d]\n", j, ptr->next[j]);
                }
            }
        }
    }

    // read from compressed text file
    printf("Read compressed text from file: %s\n", argv[2]);
    FILE *cfp = fopen(argv[2], "r");
    if (cfp == NULL) {
        fprintf(stderr, "Invalid file: %s\n", argv[2]);
        exit(1);
    }
    FILE *fout = fopen(argv[3], "w");
    if (fout == NULL) {
        fprintf(stderr, "Couldn't open file: %s\n", argv[3]);
        exit(1);
    }
    char buf[5] = {0};
    int  nowLUT = 0;
    int  nowCL  = 0;
    while(!feof(cfp)) {
        // align buffer to left
        alignBuf(buf);

        // read from compressed text
        bool isEOF = false;
        for (int i = 0; i < 4; i++) {
            if (buf[i] == 0) {
                int c;
                while (c = fgetc(cfp)) {
                    if (c == '0' || c == '1' || c == EOF)
                        break;
                }
                if (c == EOF) {
                    isEOF = true;
                    break;
                }
                buf[i] = c;
            }
        }
        if (isEOF && strlen(buf) == 0)
            break;

        //
        int index = bin2dec(0, 4, buf);
        printf("Bufffer %s\n", buf);
        Lookup *table = LUT[nowLUT];
        if (table->isSymbol[index]) {
            Symbol *s = symbols[table->next[index]];
            printf("Symbol  %s\n", s->symbol);
            fprintf(fout, "%s\n", s->symbol);
            int shift = s->cl - nowCL;
            for (int i = 0; i < shift; i++) {
                buf[i] = 0;
            }
            nowCL  = 0;
            nowLUT = 0;
        }
        else {
            printf("Jump to LUT[%d]\n", table->next[index]);
            nowLUT = table->next[index];
            nowCL += 4;
            for (int i = 0; i < 4; i++) {
                buf[i] = 0;
            }
        }
    }
    fclose(cfp);
    fclose(fout);

    // deconstruct symbol vector
    for (int i = 0; i < symbols.size(); i++) {
        free(symbols[i]);
    }

    // deconstruct LUT
    for (int i = 0; i < LUT.size(); i++) {
        free(LUT[i]);
    }
    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movq %rsi, %rbx
cmpl $0x4, %edi
jne 0x1c5c
movq 0x8(%rbx), %rsi
leaq 0x1aa8(%rip), %rdi      # 0x3062
xorl %eax, %eax
callq 0x1030
movq 0x8(%rbx), %rdi
leaq 0x1ac0(%rip), %rsi      # 0x308c
callq 0x1130
testq %rax, %rax
je 0x1c64
movq %rax, %r14
movq %rbx, -0x50(%rbp)
leaq -0x98(%rbp), %r15
leaq 0x1ab1(%rip), %rsi      # 0x30a0
leaq -0x9c(%rbp), %rdx
movq %rax, %rdi
movq %r15, %rcx
xorl %eax, %eax
callq 0x1210
cmpl $-0x1, %eax
je 0x1692
leaq -0x9c(%rbp), %r12
leaq 0x1a86(%rip), %r13      # 0x30a0
movl $0x1c, %edi
callq 0x1160
movq %rax, %rbx
movq %rax, -0x80(%rbp)
movq %rax, %rdi
movq %r12, %rsi
callq 0x10e0
leaq 0x4(%rbx), %rdi
movq %r15, %rsi
callq 0x10e0
movq %r15, %rdi
callq 0x1080
movl %eax, 0x18(%rbx)
movq 0x3aec(%rip), %rsi      # 0x5140
cmpq 0x3aed(%rip), %rsi      # 0x5148
je 0x166a
movq %rbx, (%rsi)
addq $0x8, 0x3ad8(%rip)      # 0x5140
jmp 0x167a
leaq 0x3ac7(%rip), %rdi      # 0x5138
leaq -0x80(%rbp), %rdx
callq 0x1e16
movq %r14, %rdi
movq %r13, %rsi
movq %r12, %rdx
movq %r15, %rcx
xorl %eax, %eax
callq 0x1210
cmpl $-0x1, %eax
jne 0x161a
movq %r14, %rdi
callq 0x10f0
leaq 0x1aa3(%rip), %rdi      # 0x3144
callq 0x11b0
movq 0x3a8b(%rip), %rbx      # 0x5138
movq 0x3a8c(%rip), %r14      # 0x5140
cmpq %r14, %rbx
je 0x16f3
movq %r14, %rax
subq %rbx, %rax
sarq $0x3, %rax
bsrq %rax, %rdx
xorl $0x3f, %edx
addl %edx, %edx
xorq $0x7e, %rdx
leaq -0x25b(%rip), %r15      # 0x147c
movq %rbx, %rdi
movq %r14, %rsi
movq %r15, %rcx
callq 0x1f56
movq %rbx, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x2081
leaq 0x1a5c(%rip), %rdi      # 0x3156
callq 0x11b0
leaq -0x78(%rbp), %rax
movl $0x0, (%rax)
xorl %ebx, %ebx
movq %rbx, 0x8(%rax)
movq %rax, 0x10(%rax)
movq %rax, 0x18(%rax)
movq %rbx, 0x20(%rax)
movq 0x3a16(%rip), %rax      # 0x5138
cmpq %rax, 0x3a17(%rip)      # 0x5140
je 0x193a
movl $0xffffffff, %r10d      # imm = 0xFFFFFFFF
xorl %r15d, %r15d
movl %ebx, %ecx
movq (%rax,%r15,8), %r13
movl 0x18(%r13), %eax
leal 0x4(%rcx), %ebx
cmpl %ecx, %eax
cmovlel %ecx, %ebx
leal -0x4(%rbx), %edx
xorl %ecx, %ecx
cmpl $0x5, %ebx
jl 0x1782
leal -0x5(%rbx), %ecx
movl $0x1, %esi
shll %cl, %esi
movl %edx, %edi
xorl %r8d, %r8d
xorl %ecx, %ecx
cmpb $0x31, 0x4(%r13,%r8)
movl $0x0, %r9d
cmovel %esi, %r9d
addl %r9d, %ecx
shrl %esi
incq %r8
cmpq %r8, %rdi
jne 0x1765
movl %ecx, -0x34(%rbp)
movslq %edx, %r12
cmpl %r10d, %ecx
je 0x18b7
movq %rbx, -0x40(%rbp)
movl $0x50, %edi
callq 0x1160
movq %rax, -0x30(%rbp)
movq 0x39ae(%rip), %rsi      # 0x5158
cmpq 0x39af(%rip), %rsi      # 0x5160
je 0x17ca
movq %rax, (%rsi)
movq 0x399b(%rip), %r14      # 0x5158
addq $0x8, %r14
movq %r14, 0x3990(%rip)      # 0x5158
jmp 0x17e1
leaq 0x397f(%rip), %rdi      # 0x5150
leaq -0x30(%rbp), %rdx
callq 0x241a
movq 0x3977(%rip), %r14      # 0x5158
movq 0x3968(%rip), %rbx      # 0x5150
leaq -0x80(%rbp), %rdi
leaq -0x34(%rbp), %rsi
callq 0x1cda
subq %rbx, %r14
shrq $0x3, %r14
decl %r14d
movl %r14d, (%rax)
movl -0x34(%rbp), %r10d
movq -0x40(%rbp), %rbx
cmpl $0x8, %ebx
jl 0x18b3
movl %ebx, %r14d
addl $-0x8, %r14d
movl %r10d, -0x44(%rbp)
je 0x184d
leal -0x9(%rbx), %ecx
movl $0x1, %eax
shll %cl, %eax
movl %r14d, %ecx
xorl %esi, %esi
xorl %edx, %edx
cmpb $0x31, 0x4(%r13,%rsi)
movl $0x0, %edi
cmovel %eax, %edi
addl %edi, %edx
shrl %eax
incq %rsi
cmpq %rsi, %rcx
jne 0x1831
jmp 0x184f
xorl %edx, %edx
movl %edx, -0x48(%rbp)
leaq -0x80(%rbp), %rdi
leaq -0x48(%rbp), %rsi
callq 0x1d42
movslq (%rax), %rax
movq 0x38e7(%rip), %rcx      # 0x5150
movq (%rcx,%rax,8), %rax
movslq %r14d, %rdx
movl $0x8, %edi
xorl %esi, %esi
movl -0x44(%rbp), %r10d
cmpb $0x31, 0x4(%r13,%rdx)
movl $0x0, %r8d
cmovel %edi, %r8d
addl %r8d, %esi
shrl %edi
incq %rdx
cmpq %rdx, %r12
jne 0x187b
movslq %esi, %rdx
movb $0x0, 0x40(%rax,%rdx)
movq 0x38b1(%rip), %rsi      # 0x5158
subq %rcx, %rsi
shrq $0x3, %rsi
decl %esi
movl %esi, (%rax,%rdx,4)
movl 0x18(%r13), %eax
movl %ebx, %ecx
subl %eax, %ecx
leaq (%r12,%r13), %rdx
addq $0x4, %rdx
xorl %eax, %eax
movl $0x8, %esi
movzbl (%rdx), %edi
cmpl $0x31, %edi
je 0x18d8
testl %edi, %edi
jne 0x18da
jmp 0x18e1
addl %esi, %eax
shrl %esi
incq %rdx
jmp 0x18ca
cmpl $0x1f, %ecx
je 0x1919
movl $0x1, %edx
shll %cl, %edx
movq 0x3864(%rip), %rcx      # 0x5158
movq -0x8(%rcx), %rcx
movslq %eax, %rsi
leaq (%rcx,%rsi), %rax
addq $0x40, %rax
leaq (%rcx,%rsi,4), %rcx
xorl %esi, %esi
movb $0x1, (%rax,%rsi)
movl %r15d, (%rcx,%rsi,4)
incq %rsi
cmpq %rsi, %rdx
jne 0x1909
incq %r15
movq 0x381d(%rip), %rcx      # 0x5140
movq 0x380e(%rip), %rax      # 0x5138
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %r15, %rcx
ja 0x1738
movq 0x3817(%rip), %rax      # 0x5158
cmpq 0x3808(%rip), %rax      # 0x5150
je 0x19d7
leaq 0x1765(%rip), %r14      # 0x30ba
leaq 0x174b(%rip), %r15      # 0x30a7
leaq 0x1751(%rip), %r12      # 0x30b4
xorl %r13d, %r13d
movq %r14, %rdi
movl %r13d, %esi
xorl %eax, %eax
callq 0x1030
xorl %ebx, %ebx
movq 0x37d4(%rip), %rax      # 0x5150
movq (%rax,%r13,8), %rax
movslq (%rax,%rbx,4), %rdx
cmpb $0x1, 0x40(%rax,%rbx)
jne 0x19a8
movq 0x37a6(%rip), %rax      # 0x5138
movq (%rax,%rdx,8), %rdx
leaq 0x4(%rdx), %rcx
movq %r15, %rdi
movl %ebx, %esi
xorl %eax, %eax
callq 0x1030
jmp 0x19b4
movq %r12, %rdi
movl %ebx, %esi
xorl %eax, %eax
callq 0x1030
incq %rbx
cmpq $0x10, %rbx
jne 0x1975
incq %r13
movq 0x3791(%rip), %rax      # 0x5158
subq 0x3782(%rip), %rax      # 0x5150
sarq $0x3, %rax
cmpq %r13, %rax
ja 0x1966
movq -0x50(%rbp), %rbx
movq 0x10(%rbx), %rsi
leaq 0x16dd(%rip), %rdi      # 0x30c3
xorl %eax, %eax
callq 0x1030
movq 0x10(%rbx), %rdi
leaq 0x1694(%rip), %rsi      # 0x308c
callq 0x1130
testq %rax, %rax
je 0x1c70
movq %rax, %r14
movq 0x18(%rbx), %rdi
leaq 0x16d3(%rip), %rsi      # 0x30e7
callq 0x1130
movq %rax, -0x40(%rbp)
testq %rax, %rax
je 0x1c7c
movb $0x0, -0x2c(%rbp)
movl $0x0, -0x30(%rbp)
movq %r14, %rdi
callq 0x11c0
testl %eax, %eax
jne 0x1bc1
xorl %ebx, %ebx
xorl %r12d, %r12d
xorl %ecx, %ecx
xorl %eax, %eax
xorl %edx, %edx
movb -0x30(%rbp,%rcx), %sil
testb %sil, %sil
je 0x1a62
movslq %edx, %rdi
incl %edx
movb %sil, -0x30(%rbp,%rdi)
incl %eax
incq %rcx
cmpq $0x4, %rcx
jne 0x1a4c
cmpl $0x3, %eax
jg 0x1a8c
movslq %eax, %rcx
leaq (%rcx,%rbp), %rdi
addq $-0x30, %rdi
movl $0x3, %edx
subl %eax, %edx
incq %rdx
xorl %esi, %esi
callq 0x10a0
movb $0x1, %r15b
xorl %r13d, %r13d
cmpb $0x0, -0x30(%rbp,%r13)
jne 0x1ab8
movq %r14, %rdi
callq 0x11d0
leal -0x30(%rax), %ecx
cmpl $0x2, %ecx
jb 0x1ab3
cmpl $-0x1, %eax
je 0x1acf
testl %eax, %eax
jne 0x1a9a
movb %al, -0x30(%rbp,%r13)
cmpq $0x3, %r13
leaq 0x1(%r13), %rax
setb %r15b
movq %rax, %r13
cmpq $0x4, %rax
jne 0x1a92
jmp 0x1adf
cmpb $0x0, -0x30(%rbp)
sete %al
testb %al, %r15b
jne 0x1bc1
movl $0x8, %eax
xorl %ecx, %ecx
xorl %r15d, %r15d
cmpb $0x31, -0x30(%rbp,%rcx)
movl $0x0, %edx
cmovel %eax, %edx
addl %edx, %r15d
shrl %eax
incq %rcx
cmpq $0x4, %rcx
jne 0x1ae9
leaq 0x15f6(%rip), %rdi      # 0x3101
leaq -0x30(%rbp), %rsi
xorl %eax, %eax
callq 0x1030
movslq %r12d, %rax
movq 0x3630(%rip), %rcx      # 0x5150
movq (%rcx,%rax,8), %r12
movslq %r15d, %r15
movslq (%r12,%r15,4), %rsi
cmpb $0x1, 0x40(%r12,%r15)
jne 0x1b8f
movq 0x35fe(%rip), %rax      # 0x5138
movq (%rax,%rsi,8), %r13
xorl %r12d, %r12d
leaq 0x15c5(%rip), %rdi      # 0x310d
movq %r13, %rsi
xorl %eax, %eax
callq 0x1030
movq -0x40(%rbp), %rdi
leaq 0x1546(%rip), %rsi      # 0x30a3
movq %r13, %rdx
xorl %eax, %eax
callq 0x1190
movl 0x18(%r13), %edx
movl $0x0, %r15d
cmpl %ebx, %edx
jle 0x1bae
notl %ebx
addl %ebx, %edx
incq %rdx
xorl %r12d, %r12d
leaq -0x30(%rbp), %rdi
xorl %esi, %esi
callq 0x10a0
xorl %r15d, %r15d
jmp 0x1bae
leaq 0x1583(%rip), %rdi      # 0x3119
xorl %eax, %eax
callq 0x1030
movl (%r12,%r15,4), %r12d
movl $0x0, -0x30(%rbp)
addl $0x4, %ebx
movl %ebx, %r15d
movq %r14, %rdi
callq 0x11c0
movl %r15d, %ebx
testl %eax, %eax
je 0x1a46
movq %r14, %rdi
callq 0x10f0
movq -0x40(%rbp), %rdi
callq 0x10f0
movq 0x355f(%rip), %rax      # 0x5138
cmpq %rax, 0x3560(%rip)      # 0x5140
je 0x1c0a
xorl %ebx, %ebx
movq (%rax,%rbx,8), %rdi
callq 0x1140
incq %rbx
movq 0x3549(%rip), %rcx      # 0x5140
movq 0x353a(%rip), %rax      # 0x5138
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
ja 0x1be4
movq 0x353f(%rip), %rax      # 0x5150
cmpq %rax, 0x3540(%rip)      # 0x5158
je 0x1c42
xorl %ebx, %ebx
movq (%rax,%rbx,8), %rdi
callq 0x1140
incq %rbx
movq 0x3529(%rip), %rcx      # 0x5158
movq 0x351a(%rip), %rax      # 0x5150
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
ja 0x1c1c
leaq -0x80(%rbp), %rdi
callq 0x1db8
xorl %eax, %eax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rbx, %rdi
callq 0x1240
addq $0x8, %rbx
movq %rbx, %rdi
callq 0x12d6
addq $0x10, %rbx
movq %rbx, %rdi
callq 0x12ac
addq $0x18, %rbx
movq %rbx, %rdi
callq 0x1282
jmp 0x1c8a
movq %rax, %rbx
leaq -0x80(%rbp), %rdi
callq 0x1db8
movq %rbx, %rdi
callq 0x1200