// File: /workspace/github_cpp_makefile_star2_O1/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 $0x88, %rsp
movq %rsi, %rbx
cmpl $0x4, %edi
jne 0x1c77
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 0x1c7f
movq %rax, %r14
movq %rbx, -0x58(%rbp)
leaq -0xa0(%rbp), %r15
leaq 0x1ab1(%rip), %rsi      # 0x30a0
leaq -0xa4(%rbp), %rdx
movq %rax, %rdi
movq %r15, %rcx
xorl %eax, %eax
callq 0x1210
cmpl $-0x1, %eax
je 0x1698
leaq -0xa4(%rbp), %r12
leaq 0x1a86(%rip), %r13      # 0x30a0
movl $0x1c, %edi
callq 0x1160
movq %rax, %rbx
movq %rax, -0x88(%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 0x3ae9(%rip), %rsi      # 0x5140
cmpq 0x3aea(%rip), %rsi      # 0x5148
je 0x166d
movq %rbx, (%rsi)
addq $0x8, 0x3ad5(%rip)      # 0x5140
jmp 0x1680
leaq 0x3ac4(%rip), %rdi      # 0x5138
leaq -0x88(%rbp), %rdx
callq 0x1e34
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 0x1a9d(%rip), %rdi      # 0x3144
callq 0x11b0
movq 0x3a85(%rip), %rbx      # 0x5138
movq 0x3a86(%rip), %r14      # 0x5140
cmpq %r14, %rbx
je 0x16f9
movq %r14, %rax
subq %rbx, %rax
sarq $0x3, %rax
bsrq %rax, %rdx
xorl $0x3f, %edx
addl %edx, %edx
xorq $0x7e, %rdx
leaq -0x261(%rip), %r15      # 0x147c
movq %rbx, %rdi
movq %r14, %rsi
movq %r15, %rcx
callq 0x1f74
movq %rbx, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x209f
leaq 0x1a56(%rip), %rdi      # 0x3156
callq 0x11b0
leaq -0x80(%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 0x3a10(%rip), %rax      # 0x5138
cmpq %rax, 0x3a11(%rip)      # 0x5140
je 0x1934
movl $0xffffffff, %r8d       # imm = 0xFFFFFFFF
xorl %r14d, %r14d
movl %ebx, %ecx
movq (%rax,%r14,8), %r13
leal 0x4(%rcx), %ebx
cmpl %ecx, 0x18(%r13)
cmovlel %ecx, %ebx
leal -0x4(%rbx), %ecx
xorl %eax, %eax
movslq %ecx, %r12
cmpl $0x5, %ebx
jl 0x1783
leal -0x5(%rbx), %ecx
movl $0x1, %edx
shll %cl, %edx
xorl %ecx, %ecx
xorl %eax, %eax
cmpb $0x31, 0x4(%r13,%rcx)
movl $0x0, %esi
cmovel %edx, %esi
addl %esi, %eax
shrl %edx
incq %rcx
cmpq %rcx, %r12
jne 0x1769
movl %eax, -0x44(%rbp)
cmpl %r8d, %eax
je 0x18a4
movq %rbx, -0x40(%rbp)
movl $0x50, %edi
callq 0x1160
movq %rax, -0x30(%rbp)
movq 0x39b0(%rip), %rsi      # 0x5158
cmpq 0x39b1(%rip), %rsi      # 0x5160
je 0x17be
movq %rax, (%rsi)
addq $0x8, 0x399c(%rip)      # 0x5158
jmp 0x17ce
leaq 0x398b(%rip), %rdi      # 0x5150
leaq -0x30(%rbp), %rdx
callq 0x245e
movq 0x3983(%rip), %r15      # 0x5158
movq 0x3974(%rip), %rbx      # 0x5150
leaq -0x88(%rbp), %rdi
leaq -0x44(%rbp), %rsi
callq 0x1cf8
subq %rbx, %r15
shrq $0x3, %r15
decl %r15d
movl %r15d, (%rax)
movl -0x44(%rbp), %r8d
movq -0x40(%rbp), %rbx
cmpl $0x8, %ebx
jl 0x18a4
movl %r8d, -0x34(%rbp)
leal -0x8(%rbx), %ecx
xorl %eax, %eax
movslq %ecx, %r15
cmpl $0x8, %ebx
je 0x1843
leal -0x9(%rbx), %ecx
movl $0x1, %edx
shll %cl, %edx
xorl %ecx, %ecx
xorl %eax, %eax
cmpb $0x31, 0x4(%r13,%rcx)
movl $0x0, %esi
cmovel %edx, %esi
addl %esi, %eax
shrl %edx
incq %rcx
cmpq %rcx, %r15
jne 0x1829
movl %eax, -0x48(%rbp)
leaq -0x88(%rbp), %rdi
leaq -0x48(%rbp), %rsi
callq 0x1d60
movslq (%rax), %rax
movq 0x38f0(%rip), %rcx      # 0x5150
movq (%rcx,%rax,8), %rax
movl $0x8, %esi
xorl %edx, %edx
movl -0x34(%rbp), %r8d
cmpb $0x31, 0x4(%r13,%r15)
movl $0x0, %edi
cmovel %esi, %edi
addl %edi, %edx
shrl %esi
incq %r15
cmpq %r15, %r12
jne 0x186f
movslq %edx, %rdx
movb $0x0, 0x40(%rax,%rdx)
movq 0x38c0(%rip), %rsi      # 0x5158
subq %rcx, %rsi
shrq $0x3, %rsi
decl %esi
movl %esi, (%rax,%rdx,4)
movl %ebx, %ecx
subl 0x18(%r13), %ecx
leaq (%r12,%r13), %rdx
addq $0x4, %rdx
xorl %eax, %eax
movl $0x8, %esi
movzbl (%rdx), %edi
cmpl $0x31, %edi
je 0x18c7
testl %edi, %edi
jne 0x18c9
jmp 0x18d0
addl %esi, %eax
shrl %esi
incq %rdx
jmp 0x18b9
cmpl $0x1f, %ecx
je 0x1913
movl $0x1, %edx
shll %cl, %edx
movq 0x3875(%rip), %rcx      # 0x5158
movq -0x8(%rcx), %rcx
cmpl $0x2, %edx
movl $0x1, %esi
cmovll %esi, %edx
movslq %eax, %rsi
leaq (%rcx,%rsi), %rax
addq $0x40, %rax
leaq (%rcx,%rsi,4), %rcx
xorl %esi, %esi
movb $0x1, (%rax,%rsi)
movl %r14d, (%rcx,%rsi,4)
incq %rsi
cmpq %rsi, %rdx
jne 0x1903
incq %r14
movq 0x3823(%rip), %rcx      # 0x5140
movq 0x3814(%rip), %rax      # 0x5138
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %r14, %rcx
ja 0x173e
movq 0x381d(%rip), %rax      # 0x5158
cmpq 0x380e(%rip), %rax      # 0x5150
je 0x19d1
leaq 0x176b(%rip), %r14      # 0x30ba
leaq 0x1751(%rip), %r15      # 0x30a7
leaq 0x1757(%rip), %r12      # 0x30b4
xorl %r13d, %r13d
movq %r14, %rdi
movl %r13d, %esi
xorl %eax, %eax
callq 0x1030
xorl %ebx, %ebx
movq 0x37da(%rip), %rax      # 0x5150
movq (%rax,%r13,8), %rax
movslq (%rax,%rbx,4), %rdx
cmpb $0x1, 0x40(%rax,%rbx)
jne 0x19a2
movq 0x37ac(%rip), %rax      # 0x5138
movq (%rax,%rdx,8), %rdx
leaq 0x4(%rdx), %rcx
movq %r15, %rdi
movl %ebx, %esi
xorl %eax, %eax
callq 0x1030
jmp 0x19ae
movq %r12, %rdi
movl %ebx, %esi
xorl %eax, %eax
callq 0x1030
incq %rbx
cmpq $0x10, %rbx
jne 0x196f
incq %r13
movq 0x3797(%rip), %rax      # 0x5158
subq 0x3788(%rip), %rax      # 0x5150
sarq $0x3, %rax
cmpq %r13, %rax
ja 0x1960
movq -0x58(%rbp), %rbx
movq 0x10(%rbx), %rsi
leaq 0x16e3(%rip), %rdi      # 0x30c3
xorl %eax, %eax
callq 0x1030
movq 0x10(%rbx), %rdi
leaq 0x169a(%rip), %rsi      # 0x308c
callq 0x1130
testq %rax, %rax
je 0x1c8b
movq %rax, %r14
movq 0x18(%rbx), %rdi
leaq 0x16d9(%rip), %rsi      # 0x30e7
callq 0x1130
movq %rax, -0x50(%rbp)
testq %rax, %rax
je 0x1c97
leaq -0x30(%rbp), %rax
movb $0x0, 0x4(%rax)
movl $0x0, (%rax)
movabsq $0x6000000000003, %r12  # imm = 0x6000000000003
movl $0x0, -0x40(%rbp)
xorl %ebx, %ebx
movq %r14, %rdi
callq 0x11c0
testl %eax, %eax
jne 0x1bd6
xorl %ecx, %ecx
xorl %eax, %eax
xorl %edx, %edx
movb -0x30(%rbp,%rcx), %sil
testb %sil, %sil
je 0x1a6d
movslq %edx, %rdi
incl %edx
movb %sil, -0x30(%rbp,%rdi)
incl %eax
incq %rcx
cmpq $0x4, %rcx
jne 0x1a57
cmpl $0x3, %eax
jg 0x1a97
movslq %eax, %rcx
leaq (%rcx,%rbp), %rdi
addq $-0x30, %rdi
movl $0x3, %edx
subl %eax, %edx
incq %rdx
xorl %esi, %esi
callq 0x10a0
xorl %r15d, %r15d
xorl %r13d, %r13d
cmpb $0x0, -0x30(%rbp,%r15)
jne 0x1acf
movq %r14, %rdi
callq 0x11d0
leal 0x1(%rax), %ecx
cmpl $0x32, %ecx
ja 0x1aa5
btq %rcx, %r12
jae 0x1aa5
cmpl $-0x1, %eax
je 0x1ac7
movb %al, -0x30(%rbp,%r15)
jmp 0x1aca
movb $0x1, %r13b
cmpl $-0x1, %eax
je 0x1ad8
incq %r15
cmpq $0x4, %r15
jne 0x1a9d
cmpb $0x0, -0x30(%rbp)
sete %r15b
andb %r13b, %r15b
je 0x1aec
movl %ebx, %eax
jmp 0x1bcb
movl %ebx, -0x34(%rbp)
movl $0x8, %eax
xorl %ecx, %ecx
xorl %r13d, %r13d
cmpb $0x31, -0x30(%rbp,%rcx)
movl $0x0, %edx
cmovel %eax, %edx
addl %edx, %r13d
shrl %eax
incq %rcx
cmpq $0x4, %rcx
jne 0x1af9
leaq 0x15e6(%rip), %rdi      # 0x3101
leaq -0x30(%rbp), %rsi
xorl %eax, %eax
callq 0x1030
movslq -0x40(%rbp), %rax
movq 0x361f(%rip), %rcx      # 0x5150
movq (%rcx,%rax,8), %rbx
movslq %r13d, %r13
movslq (%rbx,%r13,4), %rsi
cmpb $0x1, 0x40(%rbx,%r13)
jne 0x1ba9
movq 0x35ed(%rip), %rax      # 0x5138
movq (%rax,%rsi,8), %r13
movl $0x0, -0x40(%rbp)
leaq 0x15b0(%rip), %rdi      # 0x310d
movq %r13, %rsi
xorl %eax, %eax
callq 0x1030
movq -0x50(%rbp), %rdi
leaq 0x1531(%rip), %rsi      # 0x30a3
movq %r13, %rdx
xorl %eax, %eax
callq 0x1190
movl 0x18(%r13), %edx
movl $0x0, %eax
movl -0x34(%rbp), %ecx
cmpl %ecx, %edx
jle 0x1bcb
notl %ecx
addl %ecx, %edx
incq %rdx
movl $0x0, -0x40(%rbp)
leaq -0x30(%rbp), %rdi
xorl %esi, %esi
callq 0x10a0
xorl %eax, %eax
jmp 0x1bcb
leaq 0x1569(%rip), %rdi      # 0x3119
xorl %eax, %eax
callq 0x1030
movl (%rbx,%r13,4), %eax
movl %eax, -0x40(%rbp)
movl $0x0, -0x30(%rbp)
movl -0x34(%rbp), %eax
addl $0x4, %eax
movl %eax, %ebx
testb %r15b, %r15b
je 0x1a41
movq %r14, %rdi
callq 0x10f0
movq -0x50(%rbp), %rdi
callq 0x10f0
movq 0x354a(%rip), %rax      # 0x5138
cmpq %rax, 0x354b(%rip)      # 0x5140
je 0x1c1f
xorl %ebx, %ebx
movq (%rax,%rbx,8), %rdi
callq 0x1140
incq %rbx
movq 0x3534(%rip), %rcx      # 0x5140
movq 0x3525(%rip), %rax      # 0x5138
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
ja 0x1bf9
movq 0x352a(%rip), %rax      # 0x5150
cmpq %rax, 0x352b(%rip)      # 0x5158
je 0x1c57
xorl %ebx, %ebx
movq (%rax,%rbx,8), %rdi
callq 0x1140
incq %rbx
movq 0x3514(%rip), %rcx      # 0x5158
movq 0x3505(%rip), %rax      # 0x5150
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
ja 0x1c31
leaq -0x88(%rbp), %rdi
callq 0x1dd6
xorl %eax, %eax
addq $0x88, %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 0x1ca5
movq %rax, %rbx
leaq -0x88(%rbp), %rdi
callq 0x1dd6
movq %rbx, %rdi
callq 0x1200