getNextTag()

in src/engine/loaders/LoaderDicom.js [1036:1215]


  getNextTag(dataView, offset) {
    // check end of buffer
    if (offset >= dataView.byteLengh) {
      return null;
    }
    const SIZE_SHORT = 2;
    const SIZE_DWORD = 4;

    let little = true;
    let group = 0;
    let element = 0;
    let lenData = 0;
    const offsetStart = offset;
    let vr = '';

    const MAGIC_GROUP = 0x0002;

    if (this.m_metaFinished) {
      little = this.m_littleEndian;
      group = dataView.getUint16(offset, little);
    } else {
      group = dataView.getUint16(offset, 1);
      if ((this.m_metaFinishedOffset !== -1 && offset >= this.m_metaFinishedOffset) || group !== MAGIC_GROUP) {
        this.m_metaFinished = 1;
        little = this.m_littleEndian;
        group = dataView.getUint16(offset, little);
      } else {
        little = true;
      }
    }
    if (!this.m_metaFound && group === MAGIC_GROUP) {
      this.m_metaFound = true;
    }
    offset += SIZE_SHORT; // skip group number

    element = dataView.getUint16(offset, little);
    offset += SIZE_SHORT; // skip element number

    if (this.m_explicit || !this.m_metaFinished) {
      vr = LoaderDicom.getStringAt(dataView, offset, SIZE_SHORT);
      if (!this.m_metaFound && this.m_metaFinished && LoaderDicom.getVrsStringIndex(vr) === -1) {
        vr = DicomDictionary.getVr(group, element);
        lenData = dataView.getUint32(offset, little);
        // assert for lenData < 1024 * 1024 * 32
        offset += SIZE_DWORD;
        this.m_explicit = false;
      } else {
        offset += SIZE_SHORT;
        if (LoaderDicom.getDataVrsStringIndex(vr) !== -1) {
          offset += SIZE_SHORT;
          lenData = dataView.getUint32(offset, little);
          // assert for lenData < 1024 * 1024 * 32
          offset += SIZE_DWORD;
        } else {
          lenData = dataView.getUint16(offset, little);
          // assert for lenData < 1024 * 1024 * 32
          offset += SIZE_SHORT;
        }
      }
    } else {
      vr = this.m_dictionary.getVr(group, element);
      lenData = dataView.getUint32(offset, little);
      // assert for lenData < 1024 * 1024 * 32
      if (lenData === UNDEFINED_LENGTH) {
        vr = 'SQ';
      }
      offset += SIZE_DWORD;
    }
    const offsetValue = offset;
    let dataValue = null;
    if (vr === 'SQ') {
      // see nema dicom Table 7.5-3
      // for now just skip sequence items
      if (lenData === UNDEFINED_LENGTH) {
        let sqGroup = 0;
        let sqElement = 0;
        while (!(sqGroup === TAG_END_OF_SEQUENCE[0] && sqElement === TAG_END_OF_SEQUENCE[1])) {
          sqGroup = dataView.getUint16(offset, little);
          offset += SIZE_SHORT;
          sqElement = dataView.getUint16(offset, little);
          offset += SIZE_SHORT;
          const sqLength = dataView.getUint32(offset, little);
          offset += SIZE_DWORD;
          if (sqLength === UNDEFINED_LENGTH) {
            // item delim. tag (fffe, e00d)
            while (
              !(
                (sqGroup === TAG_END_OF_ITEMS[0] && sqElement === TAG_END_OF_ITEMS[1]) ||
                (sqGroup === TAG_END_OF_SEQUENCE[0] && sqElement === TAG_END_OF_SEQUENCE[1])
              )
            ) {
              const tagNew = this.getNextTag(dataView, offset);
              offset = tagNew.m_offsetEnd;
              sqGroup = dataView.getUint16(offset, little);
              sqElement = dataView.getUint16(offset + SIZE_SHORT, little);
            }
            offset += SIZE_DWORD + SIZE_DWORD; // 4 for group and element + 4 for length field
          } else {
            // if sqLength is ffffffff
            offset += sqLength;
          }
        } // while not end tag sequence
        lenData = 0;
      } // if length equal to ffffffff
    } else if (lenData > 0) {
      if (lenData === UNDEFINED_LENGTH) {
        if (group === TAG_PIXEL_DATA[0] && element === TAG_PIXEL_DATA[1]) {
          lenData = dataView.byteLength - offset;
        }
      }
      // Get data from buffer, starting from offset
      dataValue = dataView.buffer.slice(offset, offset + lenData);
    }
    const VAL_16 = 16;
    if (DEBUG_PRINT_TAGS_INFO) {
      const strDesc = this.m_dictionary.getTextDesc(group, element);
      const strGr = group.toString(VAL_16);
      const strEl = element.toString(VAL_16);
      console.log(`Tag {${strGr},${strEl}}, VR='${vr}', Length=${lenData}, Desc=${strDesc}`);
    }
    const VAL_MIN_ONE = 0xffffffff;
    if (lenData === VAL_MIN_ONE) {
      return null;
    }

    offset += lenData;
    const tag = new DicomTag(group, element, vr, dataValue, offsetStart, offsetValue, offset, this.m_littleEndian);

    if (tag) {
      this.m_newTagEvent.detail.group = group.toString(VAL_16);
      this.m_newTagEvent.detail.element = element.toString(VAL_16);
      this.m_newTagEvent.detail.desc = this.m_dictionary.getTextDesc(group, element);
      this.m_newTagEvent.detail.value = LoaderDicom.getAttrValueAsString(tag);
      if (group === TAG_IMAGE_INSTANCE_NUMBER[0] && element === TAG_IMAGE_INSTANCE_NUMBER[1]) {
        this.m_newTagEvent.detail.imageNumber = parseInt(this.m_newTagEvent.detail.value, 10);
      } else {
        this.m_newTagEvent.detail.imageNumber = -1;
      }
      dispatchEvent(this.m_newTagEvent);
    }

    if (tag.isTransformSyntax()) {
      const tagDataLen = tag.m_value.byteLength;
      const dvTag = new DataView(tag.m_value);
      const strTagVal = LoaderDicom.getStringAt(dvTag, 0, tagDataLen);
      if (strTagVal === TRANSFER_SYNTAX_IMPLICIT_LITTLE) {
        this.m_explicit = false;
        this.m_littleEndian = true;
      } else if (strTagVal === TRANSFER_SYNTAX_EXPLICIT_BIG) {
        this.m_explicit = true;
        this.m_littleEndian = false;
      } else if (strTagVal === TRANSFER_SYNTAX_COMPRESSION_DEFLATE) {
        this.m_needsDeflate = true;
        this.m_explicit = true;
        this.m_littleEndian = true;
      } else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG) {
        this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG;
      } else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG_LOSSLESS_SEL1) {
        this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG_LOSSLESS_SEL1;
      } else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG_LOSSLESS) {
        this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG_LOSSLESS;
      } else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG_BASELINE_8BIT) {
        this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG_BASELINE_8BIT;
      } else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG_BASELINE_12BIT) {
        this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG_BASELINE_12BIT;
      } else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG_2000_LOSSLESS) {
        this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG_2000_LOSSLESS;
      } else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG_2000) {
        this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG_2000;
      } else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_RLE) {
        this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_RLE;
      } else {
        this.m_explicit = true;
        this.m_littleEndian = true;
      }
    } else if (tag.isMetaLength()) {
      this.m_metaFinishedOffset = tag.m_value[0] + offset;
    }
    return tag;
  } // getNextTag