// File: /workspace/github_cpp_makefile_star2_O2/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 0x38f4c
movq %rdi, %rbx
movl 0x120(%rdi), %eax
movl %eax, 0x1c(%rsp)
movl 0x124(%rdi), %ebp
shll $0x2, %ebp
addl 0x128(%rdi), %ebp
movl 0x12c(%rdi), %eax
leal 0x1(%rax), %r14d
shrl %r14d
addl %ebp, %r14d
addl %r14d, %eax
movq %rax, 0x20(%rsp)
movq 0x100(%rdi), %rsi
callq 0x35550
andq $0x0, 0x30(%rbx)
leaq 0x28(%rbx), %rax
movq %rax, 0x10(%rsp)
movq 0x28(%rbx), %rax
movb $0x0, (%rax)
movl %r14d, 0x8(%rsp)
cmpl %r14d, %ebp
jae 0x38d84
movl %ebp, %r12d
addq 0x100(%rbx), %r12
movl 0x12c(%rbx), %esi
movq 0x10(%rsp), %rdi
callq 0x34730
xorl %r13d, %r13d
leaq 0x22328(%rip), %rbp     # 0x5b068
pushq $0x1
popq %r15
xorl %r14d, %r14d
movl 0x12c(%rbx), %eax
cmpq %rax, %r14
jae 0x38d84
movq %r14, %rax
shrq %rax
movsbl (%r12,%rax), %eax
movl %r13d, %ecx
notb %cl
andb $0x4, %cl
sarl %cl, %eax
andl $0xf, %eax
movsbl (%rax,%rbp), %edx
movq 0x10(%rsp), %rdi
movq %r15, %rsi
callq 0x333e0
incq %r14
addl $0x4, %r13d
jmp 0x38d47
andq $0x0, 0x70(%rbx)
movq 0x68(%rbx), %rax
movb $0x0, (%rax)
movl 0x8(%rsp), %eax
cmpl 0x20(%rsp), %eax
jae 0x38df6
leaq 0x68(%rbx), %r15
movq 0x100(%rbx), %r13
movl %eax, %eax
cmpb $-0x1, (%r13,%rax)
movl 0x12c(%rbx), %esi
je 0x38deb
addq %rax, %r13
movq %r15, %rdi
callq 0x34730
xorl %r14d, %r14d
pushq $0x1
popq %r12
movl 0x12c(%rbx), %eax
cmpq %rax, %r14
jae 0x38df6
movsbl (%r13,%r14), %edx
addl $0x21, %edx
movq %r15, %rdi
movl %r12d, %esi
callq 0x34d30
incq %r14
jmp 0x38dc7
pushq $-0x1
popq %rdx
movq %r15, %rdi
callq 0x31860
andq $0x0, 0x50(%rbx)
movq 0x48(%rbx), %rax
movb $0x0, (%rax)
cmpq $0x0, 0x30(%rbx)
je 0x38ef1
leaq 0x22265(%rip), %rsi     # 0x5b079
movq 0x10(%rsp), %rdi
callq 0x32a70
testb %al, %al
je 0x38ef1
leaq 0x48(%rbx), %rdi
movl 0x12c(%rbx), %esi
movq %rdi, 0x8(%rsp)
callq 0x34730
movq 0xb8(%rbx), %r12
movq 0xc0(%rbx), %rbp
xorl %r13d, %r13d
leaq 0x28(%rsp), %r14
leaq 0x221a9(%rip), %r15     # 0x5b000
cmpq %rbp, %r12
je 0x38ef1
movzbl (%r12), %eax
leal -0x48(%rax), %ecx
cmpl $0x10, %ecx
ja 0x38e84
movslq (%r15,%rcx,4), %rax
addq %r15, %rax
jmpq *%rax
movl 0x4(%r12), %esi
movq 0x8(%rsp), %rdi
pushq $0x4e
jmp 0x38edd
cmpl $0x44, %eax
je 0x38ed1
cmpl $0x3d, %eax
jne 0x38f5b
movslq %r13d, %rdx
movl 0x4(%r12), %ecx
movq %r14, %rdi
movq 0x10(%rsp), %rsi
callq 0x332a0
movq 0x8(%rsp), %rdi
movq %r14, %rsi
callq 0x35680
movq %r14, %rdi
callq 0x33a00
addl 0x4(%r12), %r13d
jmp 0x38ee8
movl 0x4(%r12), %esi
movq 0x8(%rsp), %rdi
pushq $0x2a
jmp 0x38edd
movl 0x4(%r12), %esi
movq 0x8(%rsp), %rdi
pushq $0x2d
popq %rdx
callq 0x333e0
leaq 0x28(%rsp), %r14
addq $0x8, %r12
jmp 0x38e57
andq $0x0, 0x90(%rbx)
movl 0x1c(%rsp), %ecx
addl $-0x20, %ecx
movq 0x88(%rbx), %rax
movb $0x0, (%rax)
movq 0x20(%rsp), %rax
cmpl %eax, %ecx
jbe 0x38f43
subl %eax, %ecx
leaq 0x88(%rbx), %rdi
movl %eax, %r14d
addq 0x100(%rbx), %r14
movl %ecx, %r15d
movq %r15, %rsi
callq 0x34000
movq 0x88(%rbx), %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x32b40
movb $0x0, 0x130(%rbx)
movb $0x1, %al
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x22119(%rip), %rsi     # 0x5b07b
leaq 0x48(%rsp), %rdi
leaq 0x7(%rsp), %rdx
callq 0x31b30
movsbl (%r12), %edx
leaq 0x28(%rsp), %rdi
leaq 0x48(%rsp), %rsi
callq 0x32560
leaq 0x48(%rsp), %rdi
callq 0x33a00
leaq 0x22104(%rip), %rsi     # 0x5b09a
leaq 0x48(%rsp), %rdi
leaq 0x7(%rsp), %rdx
callq 0x31b30
leaq 0x48(%rsp), %rsi
leaq 0x28(%rsp), %rdx
movq %rbx, %rdi
callq 0x31120
leaq 0x48(%rsp), %rdi
callq 0x33a00
leaq 0x28(%rsp), %rdi
callq 0x33a00
xorl %eax, %eax
jmp 0x38f4c
movq %rax, %rbx
leaq 0x48(%rsp), %rdi
callq 0x33a00
jmp 0x38ff3
movq %rax, %rbx
leaq 0x48(%rsp), %rdi
callq 0x33a00
jmp 0x39011
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x33a00
jmp 0x39011
movq %rax, %rbx
jmp 0x39011
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x33a00
movq %rbx, %rdi
callq 0x34ed0
movq %rax, %rdi
callq 0x39b2f
nop