export function decodeFinalFrameBodyHeader()

in modules/serialize/src/decode_body_header.ts [129:195]


export function decodeFinalFrameBodyHeader(
  buffer: Uint8Array,
  headerInfo: HeaderInfo,
  readPos: number
): FrameBodyHeader | false {
  /* Precondition: The contentType must be FRAMED_DATA to be a Final Frame. */
  needs(
    ContentType.FRAMED_DATA === headerInfo.messageHeader.contentType,
    'Unknown contentType'
  )

  const { ivLength, tagLength } = headerInfo.algorithmSuite

  /* Uint8Array is a view on top of the underlying ArrayBuffer.
   * This means that raw underlying memory stored in the ArrayBuffer
   * may be larger than the Uint8Array.  This is especially true of
   * the Node.js Buffer object.  The offset and length *must* be
   * passed to the DataView otherwise I will get unexpected results.
   */
  const dataView = new DataView(
    buffer.buffer,
    buffer.byteOffset,
    buffer.byteLength
  )

  /* Precondition: decodeFinalFrameBodyHeader readPos must be within the byte length of the buffer given. */
  needs(
    dataView.byteLength >= readPos && readPos >= 0,
    'readPos out of bounds.'
  )
  /* Check for early return (Postcondition): There must be enough data to decodeFinalFrameBodyHeader.
   * The format expressed here is
   * SEQUENCE_NUMBER_END: Uint32(FFFF)
   * SequenceIdentifier: Uint32
   * IVLength: Uint8
   * Reserved: Uint32
   * ContentLength: Uint32
   */
  if (4 + 4 + ivLength + 4 + readPos > dataView.byteLength) return false

  /* The precondition SEQUENCE_NUMBER_END: Uint32(FFFF) is handled above. */
  const sequenceEnd = dataView.getUint32(readPos, false) // big endian
  /* Postcondition: sequenceEnd must be SEQUENCE_NUMBER_END. */
  needs(
    sequenceEnd === SequenceIdentifier.SEQUENCE_NUMBER_END,
    'Malformed final frame: Invalid sequence number end value'
  )
  const sequenceNumber = dataView.getUint32((readPos += 4), false) // big endian
  /* Postcondition: decodeFinalFrameBodyHeader sequenceNumber must be greater than 0. */
  needs(sequenceNumber > 0, 'Malformed sequenceNumber.')
  const iv = buffer.slice((readPos += 4), (readPos += ivLength))
  const contentLength = dataView.getUint32(readPos)
  /* Postcondition: The final frame MUST NOT exceed the frameLength. */
  needs(
    headerInfo.messageHeader.frameLength >= contentLength,
    'Final frame length exceeds frame length.'
  )
  return {
    sequenceNumber,
    iv,
    contentLength,
    readPos: readPos + 4,
    tagLength,
    isFinalFrame: true,
    contentType: ContentType.FRAMED_DATA,
  }
}