Exemple #1
0
Result_t
ASDCP::KLReader::ReadKLFromFile(Kumu::FileReader& Reader)
{
  ui32_t read_count;
  ui32_t header_length = SMPTE_UL_LENGTH + MXF_BER_LENGTH;
  Result_t result = Reader.Read(m_KeyBuf, header_length, &read_count);

  if ( ASDCP_FAILURE(result) )
    return result;

  if ( read_count != header_length )
    return RESULT_READFAIL;

  const byte_t* ber_start = m_KeyBuf + SMPTE_UL_LENGTH;

  if ( ( *ber_start & 0x80 ) == 0 )
    {
      DefaultLogSink().Error("BER encoding error.\n");
      return RESULT_FORMAT;
    }

  ui8_t ber_size = ( *ber_start & 0x0f ) + 1;

  if ( ber_size > 9 )
    {
      DefaultLogSink().Error("BER size encoding error.\n");
      return RESULT_FORMAT;
    }

  if ( ber_size < MXF_BER_LENGTH )
    {
      DefaultLogSink().Error("BER size %d shorter than AS-DCP/AS-02 minimum %d.\n",
			     ber_size, MXF_BER_LENGTH);
      return RESULT_FORMAT;
    }

  if ( ber_size > MXF_BER_LENGTH )
    {
      ui32_t diff = ber_size - MXF_BER_LENGTH;
      assert((SMPTE_UL_LENGTH + MXF_BER_LENGTH + diff) <= (SMPTE_UL_LENGTH * 2));
      result = Reader.Read(m_KeyBuf + SMPTE_UL_LENGTH + MXF_BER_LENGTH, diff, &read_count);

      if ( ASDCP_FAILURE(result) )
	return result;

      if ( read_count != diff )
	return RESULT_READFAIL;

      header_length += diff;
    }

  return InitFromBuffer(m_KeyBuf, header_length);
}
  Result_t OpenReadFrame(const char* filename, FrameBuffer& FB)
  {
    ASDCP_TEST_NULL_STR(filename);
    m_File.Close();
    Result_t result = m_File.OpenRead(filename);

    if ( ASDCP_SUCCESS(result) )
    {
        Kumu::fsize_t file_size = m_File.Size();

        if ( FB.Capacity() < file_size )
        {
            DefaultLogSink().Error("FrameBuf.Capacity: %u frame length: %u\n", FB.Capacity(), (ui32_t)file_size);
            return RESULT_SMALLBUF;
        }
    }

    ui32_t read_count;

    if ( ASDCP_SUCCESS(result) )
        result = m_File.Read(FB.Data(), FB.Capacity(), &read_count);

    if ( ASDCP_SUCCESS(result) )
        FB.Size(read_count);

    return result;
  }
Exemple #3
0
ASDCP::Result_t
ASDCP::AIFF::SimpleAIFFHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
{
  ui32_t read_count = 0;
  ui32_t local_data_start = 0;
  ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader);

  if ( data_start == 0 )
    data_start = &local_data_start;

  Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);

  if ( ASDCP_SUCCESS(result) )
    result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);

    return result;
}
Exemple #4
0
ASDCP::Result_t
ASDCP::RF64::SimpleRF64Header::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
{
  ui32_t read_count = 0;
  ui32_t local_data_start = 0;
  ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader);

  if ( data_start == 0 )
    data_start = &local_data_start;

  Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);

  if ( ASDCP_SUCCESS(result) )
    result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
  else
    DefaultLogSink().Error("Failed to read %d bytes from file\n", Wav::MaxWavHeader);

    return result;
}
Exemple #5
0
// base subroutine for reading a KLV packet, assumes file position is at the first byte of the packet
Result_t
ASDCP::Read_EKLV_Packet(Kumu::FileReader& File, const ASDCP::Dictionary& Dict,
			const ASDCP::WriterInfo& Info, Kumu::fpos_t& LastPosition, ASDCP::FrameBuffer& CtFrameBuf,
			ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
			const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
{
  KLReader Reader;
  Result_t result = Reader.ReadKLFromFile(File);

  if ( KM_FAILURE(result) )
    return result;

  UL Key(Reader.Key());
  ui64_t PacketLength = Reader.Length();
  LastPosition = LastPosition + Reader.KLLength() + PacketLength;

  if ( Key.MatchIgnoreStream(Dict.ul(MDD_CryptEssence)) )  // ignore the stream numbers
    {
      if ( ! Info.EncryptedEssence )
	{
	  DefaultLogSink().Error("EKLV packet found, no Cryptographic Context in header.\n");
	  return RESULT_FORMAT;
	}

      // read encrypted triplet value into internal buffer
      assert(PacketLength <= 0xFFFFFFFFL);
      CtFrameBuf.Capacity((ui32_t) PacketLength);
      ui32_t read_count;
      result = File.Read(CtFrameBuf.Data(), (ui32_t) PacketLength, &read_count);

      if ( ASDCP_FAILURE(result) )
	return result;

      if ( read_count != PacketLength )
	{
	  DefaultLogSink().Error("read length is smaller than EKLV packet length.\n");
          return RESULT_FORMAT;
        }

      CtFrameBuf.Size((ui32_t) PacketLength);

      // should be const but mxflib::ReadBER is not
      byte_t* ess_p = CtFrameBuf.Data();

      // read context ID length
      if ( ! Kumu::read_test_BER(&ess_p, UUIDlen) )
	return RESULT_FORMAT;

      // test the context ID
      if ( memcmp(ess_p, Info.ContextID, UUIDlen) != 0 )
	{
	  DefaultLogSink().Error("Packet's Cryptographic Context ID does not match the header.\n");
	  return RESULT_FORMAT;
	}
      ess_p += UUIDlen;

      // read PlaintextOffset length
      if ( ! Kumu::read_test_BER(&ess_p, sizeof(ui64_t)) )
	return RESULT_FORMAT;

      ui32_t PlaintextOffset = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(ess_p));
      ess_p += sizeof(ui64_t);

      // read essence UL length
      if ( ! Kumu::read_test_BER(&ess_p, SMPTE_UL_LENGTH) )
	return RESULT_FORMAT;

      // test essence UL
      if ( ! UL(ess_p).MatchIgnoreStream(EssenceUL) ) // ignore the stream number
	{
	  char strbuf[IntBufferLen];
	  const MDDEntry* Entry = Dict.FindUL(Key.Value());

	  if ( Entry == 0 )
	    {
	      DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen));
	    }
	  else
	    {
	      DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Entry->name);
	    }

	  return RESULT_FORMAT;
	}

      ess_p += SMPTE_UL_LENGTH;

      // read SourceLength length
      if ( ! Kumu::read_test_BER(&ess_p, sizeof(ui64_t)) )
	return RESULT_FORMAT;

      ui32_t SourceLength = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(ess_p));
      ess_p += sizeof(ui64_t);
      assert(SourceLength);
	  
      if ( FrameBuf.Capacity() < SourceLength )
	{
	  DefaultLogSink().Error("FrameBuf.Capacity: %u SourceLength: %u\n", FrameBuf.Capacity(), SourceLength);
	  return RESULT_SMALLBUF;
	}

      ui32_t esv_length = calc_esv_length(SourceLength, PlaintextOffset);

      // read ESV length
      if ( ! Kumu::read_test_BER(&ess_p, esv_length) )
	{
	  DefaultLogSink().Error("read_test_BER did not return %u\n", esv_length);
	  return RESULT_FORMAT;
	}

      ui32_t tmp_len = esv_length + (Info.UsesHMAC ? klv_intpack_size : 0);

      if ( PacketLength < tmp_len )
	{
	  DefaultLogSink().Error("Frame length is larger than EKLV packet length.\n");
	  return RESULT_FORMAT;
	}

      if ( Ctx )
	{
	  // wrap the pointer and length as a FrameBuffer for use by
	  // DecryptFrameBuffer() and TestValues()
	  FrameBuffer TmpWrapper;
	  TmpWrapper.SetData(ess_p, tmp_len);
	  TmpWrapper.Size(tmp_len);
	  TmpWrapper.SourceLength(SourceLength);
	  TmpWrapper.PlaintextOffset(PlaintextOffset);

	  result = DecryptFrameBuffer(TmpWrapper, FrameBuf, Ctx);
	  FrameBuf.FrameNumber(FrameNum);
  
	  // detect and test integrity pack
	  if ( ASDCP_SUCCESS(result) && Info.UsesHMAC && HMAC )
	    {
	      IntegrityPack IntPack;
	      result = IntPack.TestValues(TmpWrapper, Info.AssetUUID, SequenceNum, HMAC);
	    }
	}
      else // return ciphertext to caller
	{
	  if ( FrameBuf.Capacity() < tmp_len )
	    {
	      char intbuf[IntBufferLen];
	      DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %s\n",
				     FrameBuf.Capacity(), ui64sz(PacketLength, intbuf));
	      return RESULT_SMALLBUF;
	    }

	  memcpy(FrameBuf.Data(), ess_p, tmp_len);
	  FrameBuf.Size(tmp_len);
	  FrameBuf.FrameNumber(FrameNum);
	  FrameBuf.SourceLength(SourceLength);
	  FrameBuf.PlaintextOffset(PlaintextOffset);
	}
    }
  else if ( Key.MatchIgnoreStream(EssenceUL) ) // ignore the stream number
    { // read plaintext frame
       if ( FrameBuf.Capacity() < PacketLength )
	{
	  char intbuf[IntBufferLen];
	  DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %s\n",
				 FrameBuf.Capacity(), ui64sz(PacketLength, intbuf));
	  return RESULT_SMALLBUF;
	}

      // read the data into the supplied buffer
      ui32_t read_count;
      assert(PacketLength <= 0xFFFFFFFFL);
      result = File.Read(FrameBuf.Data(), (ui32_t) PacketLength, &read_count);
	  
      if ( ASDCP_FAILURE(result) )
	return result;

      if ( read_count != PacketLength )
	{
	  char intbuf1[IntBufferLen];
	  char intbuf2[IntBufferLen];
	  DefaultLogSink().Error("read_count: %s != FrameLength: %s\n",
				 ui64sz(read_count, intbuf1),
				 ui64sz(PacketLength, intbuf2) );
	  
	  return RESULT_READFAIL;
	}

      FrameBuf.FrameNumber(FrameNum);
      FrameBuf.Size(read_count);
    }
  else
    {
      char strbuf[IntBufferLen];
      const MDDEntry* Entry = Dict.FindUL(Key.Value());

      if ( Entry == 0 )
	{
	  DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Key.EncodeString(strbuf, IntBufferLen));
	}
      else
	{
	  DefaultLogSink().Warn("Unexpected Essence UL found: %s.\n", Entry->name);
	}

      return RESULT_FORMAT;
    }

  return result;
}
ASDCP::Result_t
ASDCP::RawEssenceType(const std::string& filename, EssenceType_t& type)
{
  type = ESS_UNKNOWN;
  ASDCP::FrameBuffer FB;
  Kumu::FileReader Reader;
  ASDCP::Wav::SimpleWaveHeader WavHeader;
  ASDCP::RF64::SimpleRF64Header RF64Header;
  ASDCP::AIFF::SimpleAIFFHeader AIFFHeader;
  Kumu::XMLElement TmpElement("Tmp");

  ui32_t data_offset;
  ui32_t read_count;
  Result_t result = FB.Capacity(Wav::MaxWavHeader); // using Wav max because everything else is much smaller

  if ( Kumu::PathIsFile(filename) )
    {
      result = Reader.OpenRead(filename);

      if ( ASDCP_SUCCESS(result) )
	{
	  result = Reader.Read(FB.Data(), FB.Capacity(), &read_count);
	  Reader.Close();
	}

      if ( ASDCP_SUCCESS(result) )
	{
	  const byte_t* p = FB.RoData();
	  FB.Size(read_count);

	  ui32_t i = 0;
	  while ( p[i] == 0 ) i++;

	  if ( i > 1 && p[i] == 1 &&  (p[i+1] == ASDCP::MPEG2::SEQ_START || p[i+1] == ASDCP::MPEG2::PIC_START) )
	    {
	      type = ESS_MPEG2_VES;
	    }
	  else if ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 )
	    {
	      type = ESS_JPEG_2000;
	    }
	  else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
	    {
	      switch ( WavHeader.samplespersec )
		{
		case 48000: type = ESS_PCM_24b_48k; break;
		case 96000: type = ESS_PCM_24b_96k; break;
		default:
		  return RESULT_FORMAT;
		}
	    }
	  else if ( ASDCP_SUCCESS(RF64Header.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
	    {
	      switch ( RF64Header.samplespersec )
		{
		case 48000: type = ESS_PCM_24b_48k; break;
		case 96000: type = ESS_PCM_24b_96k; break;
		default:
		  return RESULT_FORMAT;
		}
	    }
	  else if ( ASDCP_SUCCESS(AIFFHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
	    {
	      type = ESS_PCM_24b_48k;
	    }
	  else if ( string_is_xml(FB) )
	    {
	      type = ESS_TIMED_TEXT;
	    }
	  else if ( ASDCP::ATMOS::IsDolbyAtmos(filename) )
	    {
	      type = ESS_DCDATA_DOLBY_ATMOS;
	    }
	}
    }
  else if ( Kumu::PathIsDirectory(filename) )
    {
      char next_file[Kumu::MaxFilePath];
      Kumu::DirScanner Scanner;
      Result_t result = Scanner.Open(filename);

      if ( ASDCP_SUCCESS(result) )
	{
	  while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) )
	    {
	      if ( next_file[0] == '.' ) // no hidden files or internal links
		continue;

	      result = Reader.OpenRead(Kumu::PathJoin(filename, next_file));

	      if ( ASDCP_SUCCESS(result) )
		{
		  result = Reader.Read(FB.Data(), FB.Capacity(), &read_count);
		  Reader.Close();
		}

	      if ( ASDCP_SUCCESS(result) )
		{
		  if ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 )
		    {
		      type = ESS_JPEG_2000;
		    }
		  else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
		    {
		      switch ( WavHeader.samplespersec )
			{
			case 48000: type = ESS_PCM_24b_48k; break;
			case 96000: type = ESS_PCM_24b_96k; break;
			default:
			  return RESULT_FORMAT;
			}
		    }
		  else if ( ASDCP_SUCCESS(RF64Header.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) )
		    {
		      switch ( RF64Header.samplespersec )
			{
			case 48000: type = ESS_PCM_24b_48k; break;
			case 96000: type = ESS_PCM_24b_96k; break;
			default:
			  return RESULT_FORMAT;
			}
		    }
		  else if ( ASDCP::ATMOS::IsDolbyAtmos(Kumu::PathJoin(filename, next_file)) )
		    {
		      type = ESS_DCDATA_DOLBY_ATMOS;
		    }
		  else
		    {
		      type = ESS_DCDATA_UNKNOWN;
		    }
		}
	      
	      break;
	    }
	}
    }

  return result;
}
Result_t
AS_02::MXF::AS02IndexReader::InitFromFile(const Kumu::FileReader& reader, const ASDCP::MXF::RIP& rip, const bool has_header_essence)
{
  typedef std::list<Kumu::mem_ptr<ASDCP::MXF::Partition> > body_part_array_t;
  body_part_array_t body_part_array;
  body_part_array_t::const_iterator body_part_iter;

  ASDCP::MXF::Array<ASDCP::MXF::RIP::Pair>::const_iterator i;
  Result_t result = m_IndexSegmentData.Capacity(128*Kumu::Kilobyte); // will be grown if needed
  ui32_t first_body_sid = 0;

  // create a list of body parts and index parts
  for ( i = rip.PairArray.begin(); KM_SUCCESS(result) && i != rip.PairArray.end(); ++i )
    {
      if ( i->BodySID == 0 )
	continue;

      if ( first_body_sid == 0 )
	{
	  first_body_sid = i->BodySID;
	}
      else if ( i->BodySID != first_body_sid )
	{
	  DefaultLogSink().Debug("The index assembler is ignoring BodySID %d.\n", i->BodySID);
	  continue;
	}

      reader.Seek(i->ByteOffset);
      ASDCP::MXF::Partition *this_partition = new ASDCP::MXF::Partition(m_Dict);
      assert(this_partition);

      result = this_partition->InitFromFile(reader);

      if ( KM_FAILURE(result) )
	{
	  delete this_partition;
	  return result;
	}

      if ( this_partition->BodySID != i->BodySID )
	{
	  DefaultLogSink().Error("Partition BodySID %d does not match RIP BodySID %d.\n",
				 this_partition->BodySID, i->BodySID);
	}

      body_part_array.push_back(0);
      body_part_array.back().set(this_partition);
    }

  if ( body_part_array.empty() )
    {
      DefaultLogSink().Error("File has no partitions with essence data.\n");
      return RESULT_AS02_FORMAT;
    }

  body_part_iter = body_part_array.begin();

  for ( i = rip.PairArray.begin(); KM_SUCCESS(result) && i != rip.PairArray.end(); ++i )
    {
      reader.Seek(i->ByteOffset);
      ASDCP::MXF::Partition plain_part(m_Dict);
      result = plain_part.InitFromFile(reader);

      if ( KM_FAILURE(result) )
	return result;

      if ( plain_part.IndexByteCount > 0 )
	{
	  if ( body_part_iter == body_part_array.end() )
	    {
	      DefaultLogSink().Error("Index and Body partitions do not match.\n");
	      break;
	    }

	  if ( plain_part.ThisPartition == plain_part.FooterPartition )
	    {
	      DefaultLogSink().Warn("File footer partition contains index data.\n");
	    }

	  // slurp up the remainder of the partition
	  ui32_t read_count = 0;

	  assert (plain_part.IndexByteCount <= 0xFFFFFFFFL);
	  ui32_t bytes_this_partition = (ui32_t)plain_part.IndexByteCount;

	  result = m_IndexSegmentData.Capacity(m_IndexSegmentData.Length() + bytes_this_partition);

	  if ( KM_SUCCESS(result) )
	    result = reader.Read(m_IndexSegmentData.Data() + m_IndexSegmentData.Length(),
				 bytes_this_partition, &read_count);

	  if ( KM_SUCCESS(result) && read_count != bytes_this_partition )
	    {
	      DefaultLogSink().Error("Short read of index partition: got %u, expecting %u\n",
				     read_count, bytes_this_partition);
	      return RESULT_AS02_FORMAT;
	    }

	  if ( KM_SUCCESS(result) )
	    {
	      ui64_t current_body_offset = 0;
	      ui64_t current_ec_offset = 0;
	      assert(body_part_iter != body_part_array.end());

	      assert(!body_part_iter->empty());
	      ASDCP::MXF::Partition *tmp_partition = body_part_iter->get();

	      if ( has_header_essence && tmp_partition->ThisPartition == 0 )
		{
		  current_body_offset = 0;
		  current_ec_offset = tmp_partition->HeaderByteCount + tmp_partition->ArchiveSize();
		}
	      else
		{
		  current_body_offset = tmp_partition->BodyOffset;
		  current_ec_offset += tmp_partition->ThisPartition + tmp_partition->ArchiveSize();
		}

	      result = InitFromBuffer(m_IndexSegmentData.RoData() + m_IndexSegmentData.Length(), bytes_this_partition, current_body_offset, current_ec_offset);
	      m_IndexSegmentData.Length(m_IndexSegmentData.Length() + bytes_this_partition);
	      ++body_part_iter;
	    }
	}
    }

  if ( KM_SUCCESS(result) )
    {
      std::list<InterchangeObject*>::const_iterator ii;
  
      for ( ii = m_PacketList->m_List.begin(); ii != m_PacketList->m_List.end(); ++ii )
	{
	  IndexTableSegment *segment = dynamic_cast<IndexTableSegment*>(*ii);

	  if ( segment != 0 )
	    {
	      m_Duration += segment->IndexDuration;
	    }
	}
    }

#if 0
  char identbuf[IdentBufferLen];
  std::list<InterchangeObject*>::iterator j;
  std::vector<ASDCP::MXF::IndexTableSegment::IndexEntry>::iterator k;
  ui32_t entry_count = 0;

  for ( j = m_PacketList->m_List.begin(); j != m_PacketList->m_List.end(); ++j )
    {
      assert(*j);
      ASDCP::MXF::IndexTableSegment* segment = static_cast<ASDCP::MXF::IndexTableSegment*>(*j);

      fprintf(stderr, "  --------------------------------------\n");
      fprintf(stderr, "  IndexEditRate      = %d/%d\n",  segment->IndexEditRate.Numerator, segment->IndexEditRate.Denominator);
      fprintf(stderr, "  IndexStartPosition = %s\n",  i64sz(segment->IndexStartPosition, identbuf));
      fprintf(stderr, "  IndexDuration      = %s\n",  i64sz(segment->IndexDuration, identbuf));
      fprintf(stderr, "  EditUnitByteCount  = %u\n",  segment->EditUnitByteCount);
      fprintf(stderr, "  IndexSID           = %u\n",  segment->IndexSID);
      fprintf(stderr, "  BodySID            = %u\n",  segment->BodySID);
      fprintf(stderr, "  SliceCount         = %hu\n", segment->SliceCount);
      fprintf(stderr, "  PosTableCount      = %hu\n", segment->PosTableCount);
      fprintf(stderr, "  RtFileOffset       = %s\n",  i64sz(segment->RtFileOffset, identbuf));
      fprintf(stderr, "  RtEntryOffset      = %s\n",  i64sz(segment->RtEntryOffset, identbuf));
      fprintf(stderr, "  IndexEntryArray:\n");

      for ( k = segment->IndexEntryArray.begin(); k != segment->IndexEntryArray.end(); ++k )
	{
	  fprintf(stderr, "  0x%010qx\n", k->StreamOffset);
	  ++entry_count;
	}
    }

  fprintf(stderr, "Actual entries: %d\n", entry_count);
#endif

  return result;
}
Exemple #8
0
// TODO: refactor to use InitFromBuffer
ASDCP::Result_t
ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader)
{
  ui32_t read_count;
  byte_t tmp_data[tmp_read_size];
  ui64_t tmp_size;
  m_KeyStart = m_ValueStart = 0;
  m_KLLength = m_ValueLength = 0;
  m_Buffer.Size(0);

  Result_t result = Reader.Read(tmp_data, tmp_read_size, &read_count);

  if ( ASDCP_FAILURE(result) )
    return result;

  if ( read_count < (SMPTE_UL_LENGTH + 1) )
    {
      DefaultLogSink().Error("Short read of Key and Length got %u\n", read_count);
      return RESULT_READFAIL;
    }

  if ( memcmp(tmp_data, SMPTE_UL_START, 4) != 0 )
    {
      DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
			     tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);
      return RESULT_FAIL;
    }

  if ( ! Kumu::read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) )
    {
      DefaultLogSink().Error("BER Length decoding error\n");
      return RESULT_FAIL;
    }

  if ( tmp_size > MAX_KLV_PACKET_LENGTH )
    {
      Kumu::ui64Printer tmp_size_str(tmp_size);
      DefaultLogSink().Error("Packet length %s exceeds internal limit\n", tmp_size_str.c_str());
      return RESULT_FAIL;
    }

  ui32_t remainder = 0;
  ui32_t ber_len = Kumu::BER_length(tmp_data + SMPTE_UL_LENGTH);
  m_KLLength = SMPTE_UL_LENGTH + ber_len;
  assert(tmp_size <= 0xFFFFFFFFL);
  m_ValueLength = (ui32_t) tmp_size;
  ui32_t packet_length = m_ValueLength + m_KLLength;

  result = m_Buffer.Capacity(packet_length);

  if ( ASDCP_FAILURE(result) )
    return result;

  m_KeyStart = m_Buffer.Data();
  m_ValueStart = m_Buffer.Data() + m_KLLength;
  m_Buffer.Size(packet_length);

  // is the whole packet in the tmp buf?
  if ( packet_length <= tmp_read_size )
    {
      assert(packet_length <= read_count);
      memcpy(m_Buffer.Data(), tmp_data, packet_length);

      if ( (remainder = read_count - packet_length) != 0 )
	{
	  DefaultLogSink().Warn("Repositioning pointer for short packet\n");
	  Kumu::fpos_t pos = Reader.Tell();
	  assert(pos > remainder);
	  result = Reader.Seek(pos - remainder);
	}
    }
  else
    {
      if ( read_count < tmp_read_size )
	{
	  DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
				 m_Buffer.Size(), read_count);
	  return RESULT_READFAIL;
	}

      memcpy(m_Buffer.Data(), tmp_data, tmp_read_size);
      remainder = m_Buffer.Size() - tmp_read_size;

      if ( remainder > 0 )
	{
	  result = Reader.Read(m_Buffer.Data() + tmp_read_size, remainder, &read_count);
      
	  if ( read_count != remainder )
	    {
	      DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
				     remainder+tmp_read_size, read_count+tmp_read_size);
	      result = RESULT_READFAIL;
	    }
	}
    }

  return result;
}