// File: /workspace/github_cpp_makefile_star2_O3/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 $0x58, %rsp
movb $0x1, %al
cmpb $0x1, 0x130(%rdi)
jne 0x2e226
movq %rdi, %rbx
movl 0x124(%rdi), %r12d
shll $0x2, %r12d
addl 0x128(%rdi), %r12d
movl 0x120(%rdi), %eax
movl %eax, 0x28(%rsp)
movl 0x12c(%rdi), %eax
leal 0x1(%rax), %r13d
shrl %r13d
addl %r12d, %r13d
addl %r13d, %eax
movq %rax, 0x30(%rsp)
movq 0x8(%rdi), %r14
movq 0x100(%rdi), %r15
movq %r15, %rdi
callq 0x268a0
movq %rbx, %rdi
xorl %esi, %esi
movq %r14, %rdx
movq %r15, %rcx
movq %rax, %r8
callq 0x285a0
leaq 0x28(%rbx), %rbp
movq $0x0, 0x30(%rbx)
movq 0x28(%rbx), %rax
movb $0x0, (%rax)
movl %r13d, 0x2c(%rsp)
cmpl %r13d, %r12d
jae 0x2e023
movl %r12d, %r15d
addq 0x100(%rbx), %r15
movl 0x12c(%rbx), %esi
movq %rbp, %rdi
callq 0x28650
cmpl $0x0, 0x12c(%rbx)
je 0x2e023
xorl %r12d, %r12d
leaq 0x2708a(%rip), %r13     # 0x55068
xorl %r14d, %r14d
movq %r14, %rax
shrq %rax
movsbl (%r15,%rax), %eax
movl %r12d, %ecx
notb %cl
andb $0x4, %cl
sarl %cl, %eax
andl $0xf, %eax
movsbl (%rax,%r13), %r8d
movq 0x30(%rbx), %rsi
movl $0x1, %ecx
movq %rbp, %rdi
xorl %edx, %edx
callq 0x28f20
incq %r14
movl 0x12c(%rbx), %eax
addl $0x4, %r12d
cmpq %rax, %r14
jb 0x2dfe1
movq $0x0, 0x70(%rbx)
movq 0x68(%rbx), %rax
movb $0x0, (%rax)
movl 0x2c(%rsp), %eax
cmpl 0x30(%rsp), %eax
jae 0x2e0a8
leaq 0x68(%rbx), %r15
movq 0x100(%rbx), %r12
movl %eax, %r14d
cmpb $-0x1, (%r12,%r14)
movl 0x12c(%rbx), %esi
je 0x2e09b
movq %r15, %rdi
callq 0x28650
cmpl $0x0, 0x12c(%rbx)
je 0x2e0a8
addq %r14, %r12
xorl %r14d, %r14d
movb (%r12,%r14), %al
addb $0x21, %al
movq 0x70(%rbx), %rsi
movsbl %al, %r8d
movl $0x1, %ecx
movq %r15, %rdi
xorl %edx, %edx
callq 0x28f20
incq %r14
movl 0x12c(%rbx), %eax
cmpq %rax, %r14
jb 0x2e06e
jmp 0x2e0a8
movq %r15, %rdi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x26590
movq $0x0, 0x50(%rbx)
movq 0x48(%rbx), %rax
movb $0x0, (%rax)
cmpq $0x0, 0x30(%rbx)
je 0x2e1c6
movq %rbp, %r14
leaq 0x26fad(%rip), %rsi     # 0x55079
movq %rbp, %rdi
callq 0x264c0
testl %eax, %eax
je 0x2e1c6
leaq 0x48(%rbx), %r15
movl 0x12c(%rbx), %esi
movq %r15, %rdi
callq 0x28650
movq 0xb8(%rbx), %r12
movq 0xc0(%rbx), %r13
cmpq %r13, %r12
je 0x2e1c6
xorl %ebp, %ebp
movzbl (%r12), %eax
leal -0x48(%rax), %ecx
cmpl $0x10, %ecx
ja 0x2e13a
leaq 0x26ee5(%rip), %rdx     # 0x55000
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movl 0x4(%r12), %ecx
movq 0x50(%rbx), %rsi
movq %r15, %rdi
xorl %edx, %edx
movl $0x4e, %r8d
jmp 0x2e1b4
cmpl $0x44, %eax
je 0x2e1a0
cmpl $0x3d, %eax
jne 0x2e235
movslq %ebp, %rdx
movl 0x4(%r12), %ecx
leaq 0x8(%rsp), %rdi
movq %r14, %rsi
callq 0x277f0
movq 0x8(%rsp), %rsi
movq 0x10(%rsp), %rdx
movq %r15, %rdi
callq 0x265d0
movq 0x8(%rsp), %rdi
leaq 0x18(%rsp), %rax
cmpq %rax, %rdi
je 0x2e183
callq 0x27560
addl 0x4(%r12), %ebp
jmp 0x2e1b9
movl 0x4(%r12), %ecx
movq 0x50(%rbx), %rsi
movq %r15, %rdi
xorl %edx, %edx
movl $0x2a, %r8d
jmp 0x2e1b4
movl 0x4(%r12), %ecx
movq 0x50(%rbx), %rsi
movq %r15, %rdi
xorl %edx, %edx
movl $0x2d, %r8d
callq 0x28f20
addq $0x8, %r12
cmpq %r13, %r12
jne 0x2e107
movl 0x28(%rsp), %ecx
addl $-0x20, %ecx
movq $0x0, 0x90(%rbx)
movq 0x88(%rbx), %rax
movb $0x0, (%rax)
movq 0x30(%rsp), %rax
cmpl %eax, %ecx
jbe 0x2e21d
subl %eax, %ecx
leaq 0x88(%rbx), %rdi
movl %eax, %r14d
addq 0x100(%rbx), %r14
movl %ecx, %r15d
movq %r15, %rsi
xorl %edx, %edx
callq 0x26590
movq 0x88(%rbx), %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x27260
movb $0x0, 0x130(%rbx)
movb $0x1, %al
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x48(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0x26e36(%rip), %rsi     # 0x5507b
leaq 0x26e4d(%rip), %rdx     # 0x55099
leaq 0x38(%rsp), %rdi
callq 0x26750
movb (%r12), %bpl
leaq 0x8(%rsp), %rdi
leaq 0x18(%rsp), %rax
movq %rax, (%rdi)
movq 0x38(%rsp), %rsi
movq 0x40(%rsp), %rdx
addq %rsi, %rdx
callq 0x267c0
leaq 0x8(%rsp), %rdi
movq 0x8(%rdi), %rsi
movsbl %bpl, %r8d
movl $0x1, %ecx
xorl %edx, %edx
callq 0x28f20
movq 0x38(%rsp), %rdi
cmpq %r14, %rdi
je 0x2e2a1
callq 0x27560
leaq 0x38(%rsp), %rdi
movq %r14, (%rdi)
leaq 0x26dea(%rip), %rsi     # 0x5509a
leaq 0x26dfe(%rip), %rdx     # 0x550b5
callq 0x26750
leaq 0x38(%rsp), %rsi
leaq 0x8(%rsp), %rdx
movq %rbx, %rdi
callq 0x260e0
movq 0x38(%rsp), %rdi
cmpq %r14, %rdi
je 0x2e2dd
callq 0x27560
movq 0x8(%rsp), %rdi
leaq 0x18(%rsp), %rax
cmpq %rax, %rdi
je 0x2e2f1
callq 0x27560
xorl %eax, %eax
jmp 0x2e226
movq %rax, %rbx
movq 0x38(%rsp), %rdi
cmpq %r14, %rdi
je 0x2e33e
callq 0x27560
jmp 0x2e33e
jmp 0x2e33b
movq %rax, %rbx
movq 0x8(%rsp), %rdi
leaq 0x18(%rsp), %rax
cmpq %rax, %rdi
je 0x2e32a
callq 0x27560
jmp 0x2e32a
movq %rax, %rbx
movq 0x38(%rsp), %rdi
cmpq %r14, %rdi
jne 0x2e34d
jmp 0x2e352
movq %rax, %rbx
jmp 0x2e352
movq %rax, %rbx
movq 0x8(%rsp), %rdi
leaq 0x18(%rsp), %rax
cmpq %rax, %rdi
je 0x2e352
callq 0x27560
movq %rbx, %rdi
callq 0x28c10