// File: /workspace/github_cpp_makefile_star2_O1/zeeev[P]DASVC/bamtools/src/api/BamAlignment.cpp
// Function: BamTools::BamAlignment::BuildCharData()
bool BamAlignment::BuildCharData(void) {

    // skip if char data already parsed
    if ( !SupportData.HasCoreOnly )
        return true;

    // check system endianness
    bool IsBigEndian = BamTools::SystemIsBigEndian();

    // calculate character lengths/offsets
    const unsigned int dataLength     = SupportData.BlockLength - Constants::BAM_CORE_SIZE;
    const unsigned int seqDataOffset  = SupportData.QueryNameLength + (SupportData.NumCigarOperations*4);
    const unsigned int qualDataOffset = seqDataOffset + (SupportData.QuerySequenceLength+1)/2;
    const unsigned int tagDataOffset  = qualDataOffset + SupportData.QuerySequenceLength;
    const unsigned int tagDataLength  = dataLength - tagDataOffset;

    // check offsets to see what char data exists
    const bool hasSeqData  = ( seqDataOffset  < qualDataOffset );
    const bool hasQualData = ( qualDataOffset < tagDataOffset );
    const bool hasTagData  = ( tagDataOffset  < dataLength );

    // store alignment name (relies on null char in name as terminator)
    Name.assign(SupportData.AllCharData.data());

    // save query sequence
    QueryBases.clear();
    if ( hasSeqData ) {
        const char* seqData = SupportData.AllCharData.data() + seqDataOffset;
        QueryBases.reserve(SupportData.QuerySequenceLength);
        for ( size_t i = 0; i < SupportData.QuerySequenceLength; ++i ) {
            const char singleBase = Constants::BAM_DNA_LOOKUP[ ( (seqData[(i/2)] >> (4*(1-(i%2)))) & 0xf ) ];
            QueryBases.append(1, singleBase);
        }
    }

    // save qualities

    Qualities.clear();
    if ( hasQualData ) {
        const char* qualData = SupportData.AllCharData.data() + qualDataOffset;

        // if marked as unstored (sequence of 0xFF) - don't do conversion, just fill with 0xFFs
        if ( qualData[0] == (char)0xFF )
            Qualities.resize(SupportData.QuerySequenceLength, (char)0xFF);

        // otherwise convert from numeric QV to 'FASTQ-style' ASCII character
        else {
            Qualities.reserve(SupportData.QuerySequenceLength);
            for ( size_t i = 0; i < SupportData.QuerySequenceLength; ++i )
                Qualities.append(1, qualData[i]+33);
        }
    }

    // clear previous AlignedBases
    AlignedBases.clear();

    // if QueryBases has data, build AlignedBases using CIGAR data
    // otherwise, AlignedBases will remain empty (this case IS allowed)
    if ( !QueryBases.empty() && QueryBases != "*" ) {

        // resize AlignedBases
        AlignedBases.reserve(SupportData.QuerySequenceLength);

        // iterate over CigarOps
        int k = 0;
        vector<CigarOp>::const_iterator cigarIter = CigarData.begin();
        vector<CigarOp>::const_iterator cigarEnd  = CigarData.end();
        for ( ; cigarIter != cigarEnd; ++cigarIter ) {
            const CigarOp& op = (*cigarIter);

            switch ( op.Type ) {

                // for 'M', 'I', '=', 'X' - write bases
                case (Constants::BAM_CIGAR_MATCH_CHAR)    :
                case (Constants::BAM_CIGAR_INS_CHAR)      :
                case (Constants::BAM_CIGAR_SEQMATCH_CHAR) :
                case (Constants::BAM_CIGAR_MISMATCH_CHAR) :
                    AlignedBases.append(QueryBases.substr(k, op.Length));
                    // fall through

                // for 'S' - soft clip, do not write bases
                // but increment placeholder 'k'
                case (Constants::BAM_CIGAR_SOFTCLIP_CHAR) :
                    k += op.Length;
                    break;

                // for 'D' - write gap character
                case (Constants::BAM_CIGAR_DEL_CHAR) :
                    AlignedBases.append(op.Length, Constants::BAM_DNA_DEL);
                    break;

                // for 'P' - write padding character
                case (Constants::BAM_CIGAR_PAD_CHAR) :
                    AlignedBases.append( op.Length, Constants::BAM_DNA_PAD );
                    break;

                // for 'N' - write N's, skip bases in original query sequence
                case (Constants::BAM_CIGAR_REFSKIP_CHAR) :
                    AlignedBases.append( op.Length, Constants::BAM_DNA_N );
                    break;

                // for 'H' - hard clip, do nothing to AlignedBases, move to next op
                case (Constants::BAM_CIGAR_HARDCLIP_CHAR) :
                    break;

                // invalid CIGAR op-code
                default:
                    const string message = string("invalid CIGAR operation type: ") + op.Type;
                    SetErrorString("BamAlignment::BuildCharData", message);
                    return false;
            }
        }
    }

    // save tag data
    TagData.clear();
    if ( hasTagData ) {

        char* tagData = (((char*)SupportData.AllCharData.data()) + tagDataOffset);

        if ( IsBigEndian ) {
            size_t i = 0;
            while ( i < tagDataLength ) {

                i += Constants::BAM_TAG_TAGSIZE;  // skip tag chars (e.g. "RG", "NM", etc.)
                const char type = tagData[i];     // get tag type at position i
                ++i;                              // move i past tag type

                switch (type) {

                    case(Constants::BAM_TAG_TYPE_ASCII) :
                    case(Constants::BAM_TAG_TYPE_INT8)  :
                    case(Constants::BAM_TAG_TYPE_UINT8) :
                        // no endian swapping necessary for single-byte data
                        ++i;
                        break;

                    case(Constants::BAM_TAG_TYPE_INT16)  :
                    case(Constants::BAM_TAG_TYPE_UINT16) :
                        BamTools::SwapEndian_16p(&tagData[i]);
                        i += sizeof(uint16_t);
                        break;

                    case(Constants::BAM_TAG_TYPE_FLOAT)  :
                    case(Constants::BAM_TAG_TYPE_INT32)  :
                    case(Constants::BAM_TAG_TYPE_UINT32) :
                        BamTools::SwapEndian_32p(&tagData[i]);
                        i += sizeof(uint32_t);
                        break;

                    case(Constants::BAM_TAG_TYPE_HEX) :
                    case(Constants::BAM_TAG_TYPE_STRING) :
                        // no endian swapping necessary for hex-string/string data
                        while ( tagData[i] )
                            ++i;
                        // increment one more for null terminator
                        ++i;
                        break;

                    case(Constants::BAM_TAG_TYPE_ARRAY) :

                    {
                        // read array type
                        const char arrayType = tagData[i];
                        ++i;

                        // swap endian-ness of number of elements in place, then retrieve for loop
                        BamTools::SwapEndian_32p(&tagData[i]);
                        uint32_t numElements;
                        memcpy(&numElements, &tagData[i], sizeof(uint32_t));
                        i += sizeof(uint32_t);

                        // swap endian-ness of array elements
                        for ( size_t j = 0; j < numElements; ++j ) {
                            switch (arrayType) {
                                case (Constants::BAM_TAG_TYPE_INT8)  :
                                case (Constants::BAM_TAG_TYPE_UINT8) :
                                    // no endian-swapping necessary
                                    ++i;
                                    break;
                                case (Constants::BAM_TAG_TYPE_INT16)  :
                                case (Constants::BAM_TAG_TYPE_UINT16) :
                                    BamTools::SwapEndian_16p(&tagData[i]);
                                    i += sizeof(uint16_t);
                                    break;
                                case (Constants::BAM_TAG_TYPE_FLOAT)  :
                                case (Constants::BAM_TAG_TYPE_INT32)  :
                                case (Constants::BAM_TAG_TYPE_UINT32) :
                                    BamTools::SwapEndian_32p(&tagData[i]);
                                    i += sizeof(uint32_t);
                                    break;
                                default:
                                    const string message = string("invalid binary array type: ") + arrayType;
                                    SetErrorString("BamAlignment::BuildCharData", message);
                                    return false;
                            }
                        }

                        break;
                    }

                    // invalid tag type-code
                    default :
                        const string message = string("invalid tag type: ") + type;
                        SetErrorString("BamAlignment::BuildCharData", message);
                        return false;
                }
            }
        }

        // store tagData in alignment
        TagData.resize(tagDataLength);
        memcpy((char*)(TagData.data()), tagData, tagDataLength);
    }

    // clear core-only flag & return success
    SupportData.HasCoreOnly = false;
    return true;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x68, %rsp
movb $0x1, %al
cmpb $0x1, 0x130(%rdi)
jne 0x2e336
movq %rdi, %r14
movl 0x124(%rdi), %ebp
shll $0x2, %ebp
addl 0x128(%rdi), %ebp
movl 0x120(%rdi), %eax
movl %eax, 0x54(%rsp)
movl 0x12c(%rdi), %eax
leal 0x1(%rax), %r13d
shrl %r13d
addl %ebp, %r13d
addl %r13d, %eax
movq %rax, 0x58(%rsp)
movq 0x8(%rdi), %r15
movq 0x100(%rdi), %r12
movq %r12, %rdi
callq 0x268a0
movq %r14, %rdi
xorl %esi, %esi
movq %r15, %rdx
movq %r12, %rcx
movq %rax, %r8
callq 0x285b0
leaq 0x28(%r14), %rbx
movq $0x0, 0x30(%r14)
movq 0x28(%r14), %rax
movb $0x0, (%rax)
movl %r13d, 0x8(%rsp)
cmpl %r13d, %ebp
jae 0x2e033
movl %ebp, %r12d
addq 0x100(%r14), %r12
movl 0x12c(%r14), %esi
movq %rbx, %rdi
callq 0x28660
cmpl $0x0, 0x12c(%r14)
je 0x2e033
xorl %r13d, %r13d
leaq 0x2707b(%rip), %rbp     # 0x55068
xorl %r15d, %r15d
movq %r15, %rax
shrq %rax
movsbl (%r12,%rax), %eax
movl %r13d, %ecx
notb %cl
andb $0x4, %cl
sarl %cl, %eax
andl $0xf, %eax
movsbl (%rax,%rbp), %r8d
movq 0x30(%r14), %rsi
movl $0x1, %ecx
movq %rbx, %rdi
xorl %edx, %edx
callq 0x28f30
incq %r15
movl 0x12c(%r14), %eax
addl $0x4, %r13d
cmpq %rax, %r15
jb 0x2dff0
movq %rbx, 0x60(%rsp)
movq $0x0, 0x70(%r14)
movq 0x68(%r14), %rax
movb $0x0, (%rax)
movq 0x58(%rsp), %r15
movl 0x8(%rsp), %eax
cmpl %r15d, %eax
jae 0x2e0c4
leaq 0x68(%r14), %r12
movq 0x100(%r14), %r13
movl %eax, %ebx
cmpb $-0x1, (%r13,%rbx)
movl 0x12c(%r14), %esi
je 0x2e0b7
movq %r12, %rdi
callq 0x28660
cmpl $0x0, 0x12c(%r14)
je 0x2e0c4
addq %rbx, %r13
xorl %ebx, %ebx
movb (%r13,%rbx), %al
addb $0x21, %al
movq 0x70(%r14), %rsi
movsbl %al, %r8d
movl $0x1, %ecx
movq %r12, %rdi
xorl %edx, %edx
callq 0x28f30
incq %rbx
movl 0x12c(%r14), %eax
cmpq %rax, %rbx
jb 0x2e088
jmp 0x2e0c4
movq %r12, %rdi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x26590
movq $0x0, 0x50(%r14)
movq 0x48(%r14), %rax
movb $0x0, (%rax)
cmpq $0x0, 0x30(%r14)
je 0x2e2d8
leaq 0x26f94(%rip), %rsi     # 0x55079
movq 0x60(%rsp), %rdi
callq 0x264c0
testl %eax, %eax
je 0x2e2d8
leaq 0x48(%r14), %rdi
movl 0x12c(%r14), %esi
movq %rdi, 0x8(%rsp)
callq 0x28660
movq 0xb8(%r14), %rbx
movq 0xc0(%r14), %rbp
cmpq %rbp, %rbx
je 0x2e2d8
xorl %r12d, %r12d
leaq 0x10(%rsp), %rdi
movzbl (%rbx), %eax
movb $0x1, %r13b
leal -0x48(%rax), %ecx
cmpl $0x10, %ecx
ja 0x2e162
leaq 0x26ec0(%rip), %rdx     # 0x55000
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movl 0x4(%rbx), %ecx
movq 0x50(%r14), %rsi
movq 0x8(%rsp), %rdi
xorl %edx, %edx
movl $0x4e, %r8d
jmp 0x2e2bc
cmpl $0x44, %eax
je 0x2e2a8
cmpl $0x3d, %eax
jne 0x2e1b6
movslq %r12d, %rdx
movl 0x4(%rbx), %ecx
movq 0x60(%rsp), %rsi
callq 0x277f0
movq 0x10(%rsp), %rsi
movq 0x18(%rsp), %rdx
movq 0x8(%rsp), %rdi
callq 0x265d0
movq 0x10(%rsp), %rdi
leaq 0x20(%rsp), %rax
cmpq %rax, %rdi
je 0x2e1a8
callq 0x27560
leaq 0x10(%rsp), %rdi
addl 0x4(%rbx), %r12d
jmp 0x2e2c6
leaq 0x40(%rsp), %r13
movq %r13, 0x30(%rsp)
leaq 0x30(%rsp), %rdi
leaq 0x26eaf(%rip), %rsi     # 0x5507b
leaq 0x26ec6(%rip), %rdx     # 0x55099
callq 0x26750
movb (%rbx), %r15b
leaq 0x20(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x30(%rsp), %rsi
movq 0x38(%rsp), %rdx
addq %rsi, %rdx
leaq 0x10(%rsp), %r13
movq %r13, %rdi
callq 0x267c0
movq 0x18(%rsp), %rsi
movsbl %r15b, %r8d
movl $0x1, %ecx
movq %r13, %rdi
xorl %edx, %edx
callq 0x28f30
movq 0x30(%rsp), %rdi
leaq 0x40(%rsp), %rax
cmpq %rax, %rdi
movq 0x58(%rsp), %r15
leaq 0x30(%rsp), %r13
je 0x2e235
callq 0x27560
leaq 0x40(%rsp), %rax
movq %rax, 0x30(%rsp)
movq %r13, %rdi
leaq 0x26e51(%rip), %rsi     # 0x5509a
leaq 0x26e65(%rip), %rdx     # 0x550b5
callq 0x26750
movq %r14, %rdi
movq %r13, %rsi
leaq 0x10(%rsp), %rdx
callq 0x260e0
movq 0x30(%rsp), %rdi
leaq 0x40(%rsp), %rax
cmpq %rax, %rdi
je 0x2e279
callq 0x27560
movq 0x10(%rsp), %rdi
leaq 0x20(%rsp), %rax
cmpq %rax, %rdi
je 0x2e28d
callq 0x27560
xorl %r13d, %r13d
jmp 0x2e2c1
movl 0x4(%rbx), %ecx
movq 0x50(%r14), %rsi
movq 0x8(%rsp), %rdi
xorl %edx, %edx
movl $0x2a, %r8d
jmp 0x2e2bc
movl 0x4(%rbx), %ecx
movq 0x50(%r14), %rsi
movq 0x8(%rsp), %rdi
xorl %edx, %edx
movl $0x2d, %r8d
callq 0x28f30
leaq 0x10(%rsp), %rdi
testb %r13b, %r13b
je 0x2e345
addq $0x8, %rbx
cmpq %rbp, %rbx
jne 0x2e12b
movl 0x54(%rsp), %ecx
addl $-0x20, %ecx
movq $0x0, 0x90(%r14)
movq 0x88(%r14), %rax
movb $0x0, (%rax)
cmpl %r15d, %ecx
jbe 0x2e32c
subl %r15d, %ecx
leaq 0x88(%r14), %rdi
movl %r15d, %r15d
addq 0x100(%r14), %r15
movl %ecx, %r12d
movq %r12, %rsi
xorl %edx, %edx
callq 0x26590
movq 0x88(%r14), %rdi
movq %r15, %rsi
movq %r12, %rdx
callq 0x27260
movb $0x0, 0x130(%r14)
movb $0x1, %al
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
xorl %eax, %eax
jmp 0x2e336
movq %rax, %rbx
movq 0x30(%rsp), %rdi
leaq 0x40(%rsp), %rax
cmpq %rax, %rdi
je 0x2e394
callq 0x27560
jmp 0x2e394
jmp 0x2e391
movq %rax, %rbx
movq 0x10(%rsp), %rdi
leaq 0x20(%rsp), %rax
cmpq %rax, %rdi
je 0x2e380
callq 0x27560
jmp 0x2e380
movq %rax, %rbx
movq 0x30(%rsp), %rdi
leaq 0x40(%rsp), %rax
jmp 0x2e39e
movq %rax, %rbx
jmp 0x2e3a8
movq %rax, %rbx
movq 0x10(%rsp), %rdi
leaq 0x20(%rsp), %rax
cmpq %rax, %rdi
je 0x2e3a8
callq 0x27560
movq %rbx, %rdi
callq 0x28c20