filepos_t EbmlString::ReadData(IOCallback & input, ScopeMode ReadFully) { if (ReadFully != SCOPE_NO_DATA) { if (GetSize() == 0) { Value = ""; SetValueIsSet(); } else { char *Buffer = new char[GetSize() + 1]; if (Buffer == NULL) { // unable to store the data, skip it input.setFilePointer(GetSize(), seek_current); } else { input.readFully(Buffer, GetSize()); if (Buffer[GetSize()-1] != '\0') { Buffer[GetSize()] = '\0'; } Value = Buffer; delete [] Buffer; SetValueIsSet(); } } } return GetSize(); }
/*! \todo remove the hack for possible endianess pb (test on little & big endian) */ filepos_t EbmlFloat::ReadData(IOCallback & input, ScopeMode ReadFully) { if (ReadFully != SCOPE_NO_DATA) { binary Buffer[20]; assert(GetSize() <= 20); input.readFully(Buffer, GetSize()); if (GetSize() == 4) { big_int32 TmpRead; TmpRead.Eval(Buffer); int32 tmpp = int32(TmpRead); float val; memcpy(&val, &tmpp, 4); Value = val; SetValueIsSet(); } else if (GetSize() == 8) { big_int64 TmpRead; TmpRead.Eval(Buffer); int64 tmpp = int64(TmpRead); double val; memcpy(&val, &tmpp, 8); Value = val; SetValueIsSet(); } } return GetSize(); }
START_LIBEBML_NAMESPACE EbmlMaster::EbmlMaster(const EbmlSemanticContext & aContext, bool bSizeIsknown) :EbmlElement(0), Context(aContext), bChecksumUsed(bChecksumUsedByDefault) { SetSizeIsFinite(bSizeIsknown); SetValueIsSet(); ProcessMandatory(); }
KaxBlockVirtual::KaxBlockVirtual(const KaxBlockVirtual & ElementToClone) :EbmlBinary(ElementToClone) ,Timecode(ElementToClone.Timecode) ,TrackNumber(ElementToClone.TrackNumber) ,ParentCluster(ElementToClone.ParentCluster) ///< \todo not exactly { SetBuffer(DataBlock,sizeof(DataBlock)); SetValueIsSet(false); }
EbmlString & EbmlString::operator=(const std::string & NewString) { Value = NewString; SetValueIsSet(); /* done automatically SetSize_(Value.length()); if (GetDefaultSize() > GetSize()) SetSize_(GetDefaultSize());*/ return *this; }
void EbmlCrc32::Finalize() { //Finalize the CRC32 m_crc ^= CRC32_NEGL; //Copy it over to completed CRC32 memeber m_crc_final = m_crc; //Reset the holding CRC member (m_crc) ResetCRC(); //This EbmlElement has been set SetValueIsSet(); }
filepos_t EbmlUInteger::ReadData(IOCallback & input, ScopeMode ReadFully) { if (ReadFully != SCOPE_NO_DATA) { binary Buffer[8]; input.readFully(Buffer, GetSize()); Value = 0; for (unsigned int i=0; i<GetSize(); i++) { Value <<= 8; Value |= Buffer[i]; } SetValueIsSet(); } return GetSize(); }
filepos_t EbmlBinary::ReadData(IOCallback & input, ScopeMode ReadFully) { if (Data != NULL) free(Data); if (ReadFully == SCOPE_NO_DATA || !GetSize()) { Data = NULL; return GetSize(); } Data = (binary *)malloc(GetSize()); if (Data == NULL) throw CRTError(std::string("Error allocating data")); SetValueIsSet(); return input.read(Data, GetSize()); }
filepos_t EbmlDate::ReadData(IOCallback & input, ScopeMode ReadFully) { if ((ReadFully == SCOPE_NO_DATA) || (GetSize() == 0)) return GetSize(); assert(GetSize() == 8); binary Buffer[8]; input.readFully(Buffer, GetSize()); big_int64 b64; b64.Eval(Buffer); myDate = b64; SetValueIsSet(); return GetSize(); }
filepos_t EbmlCrc32::ReadData(IOCallback & input, ScopeMode ReadFully) { if (ReadFully != SCOPE_NO_DATA) { binary *Buffer = new binary[GetSize()]; if (Buffer == NULL) { // impossible to read, skip it input.setFilePointer(GetSize(), seek_current); } else { input.readFully(Buffer, GetSize()); memcpy((void *)&m_crc_final, Buffer, 4); delete [] Buffer; SetValueIsSet(); } } return GetSize(); }
void KaxCuePoint::PositionSet(const KaxBlockBlob & BlobReference, uint64 GlobalTimecodeScale) { const KaxInternalBlock &BlockReference = BlobReference; // fill me KaxCueTime & NewTime = GetChild<KaxCueTime>(*this); *static_cast<EbmlUInteger*>(&NewTime) = BlockReference.GlobalTimecode() / GlobalTimecodeScale; KaxCueTrackPositions & NewPositions = AddNewChild<KaxCueTrackPositions>(*this); KaxCueTrack & TheTrack = GetChild<KaxCueTrack>(NewPositions); *static_cast<EbmlUInteger*>(&TheTrack) = BlockReference.TrackNum(); KaxCueClusterPosition & TheClustPos = GetChild<KaxCueClusterPosition>(NewPositions); *static_cast<EbmlUInteger*>(&TheClustPos) = BlockReference.ClusterPosition(); #if 0 // MATROSKA_VERSION >= 2 // handle reference use if (BlockReference.ReferenceCount() != 0) { unsigned int i; for (i=0; i<BlockReference.ReferenceCount(); i++) { KaxCueReference & NewRefs = AddNewChild<KaxCueReference>(NewPositions); NewRefs.AddReference(BlockReference.Reference(i).RefBlock(), GlobalTimecodeScale); } } #endif // MATROSKA_VERSION #if MATROSKA_VERSION >= 2 if (!BlobReference.IsSimpleBlock()) { const KaxBlockGroup &BlockGroup = BlobReference; const KaxCodecState *CodecState = static_cast<KaxCodecState *>(BlockGroup.FindFirstElt(EBML_INFO(KaxCodecState))); if (CodecState != NULL) { KaxCueCodecState &CueCodecState = AddNewChild<KaxCueCodecState>(NewPositions); *static_cast<EbmlUInteger*>(&CueCodecState) = BlockGroup.GetParentCluster()->GetParentSegment()->GetRelativePosition(CodecState->GetElementPosition()); } } #endif // MATROSKA_VERSION SetValueIsSet(); }
filepos_t EbmlSInteger::ReadData(IOCallback & input, ScopeMode ReadFully) { if (ReadFully != SCOPE_NO_DATA) { binary Buffer[8]; input.readFully(Buffer, GetSize()); if (Buffer[0] & 0x80) Value = -1; // this is a negative value else Value = 0; // this is a positive value for (unsigned int i=0; i<GetSize(); i++) { Value <<= 8; Value |= Buffer[i]; } SetValueIsSet(); } return GetSize(); }
START_LIBMATROSKA_NAMESPACE /*! \todo handle codec state checking \todo remove duplicate references (reference to 2 frames that each reference the same frame) */ void KaxCuePoint::PositionSet(const KaxBlockGroup & BlockReference, uint64 GlobalTimecodeScale) { // fill me KaxCueTime & NewTime = GetChild<KaxCueTime>(*this); *static_cast<EbmlUInteger*>(&NewTime) = BlockReference.GlobalTimecode() / GlobalTimecodeScale; KaxCueTrackPositions & NewPositions = AddNewChild<KaxCueTrackPositions>(*this); KaxCueTrack & TheTrack = GetChild<KaxCueTrack>(NewPositions); *static_cast<EbmlUInteger*>(&TheTrack) = BlockReference.TrackNumber(); KaxCueClusterPosition & TheClustPos = GetChild<KaxCueClusterPosition>(NewPositions); *static_cast<EbmlUInteger*>(&TheClustPos) = BlockReference.ClusterPosition(); #if MATROSKA_VERSION >= 2 // handle reference use if (BlockReference.ReferenceCount() != 0) { unsigned int i; for (i=0; i<BlockReference.ReferenceCount(); i++) { KaxCueReference & NewRefs = AddNewChild<KaxCueReference>(NewPositions); NewRefs.AddReference(BlockReference.Reference(i).RefBlock(), GlobalTimecodeScale); } } KaxCodecState *CodecState = static_cast<KaxCodecState *>(BlockReference.FindFirstElt(EBML_INFO(KaxCodecState))); if (CodecState != NULL) { KaxCueCodecState &CueCodecState = AddNewChild<KaxCueCodecState>(NewPositions); *static_cast<EbmlUInteger*>(&CueCodecState) = BlockReference.GetParentCluster()->GetParentSegment()->GetRelativePosition(CodecState->GetElementPosition()); } #endif // MATROSKA_VERSION SetValueIsSet(); }
/*! \todo handle flags \todo hardcoded limit of the number of frames in a lace should be a parameter \return true if more frames can be added to this Block */ bool KaxInternalBlock::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing, bool invisible) { SetValueIsSet(); if (myBuffers.size() == 0) { // first frame Timecode = timecode; TrackNumber = track.TrackNumber(); mInvisible = invisible; mLacing = lacing; } myBuffers.push_back(&buffer); // we don't allow more than 8 frames in a Block because the overhead improvement is minimal if (myBuffers.size() >= 8 || lacing == LACING_NONE) return false; if (lacing == LACING_XIPH) // decide wether a new frame can be added or not // a frame in a lace is not efficient when the place necessary to code it in a lace is bigger // than the size of a simple Block. That means more than 6 bytes (4 in struct + 2 for EBML) to code the size return (buffer.Size() < 6*0xFF); else return true; }
/*! \todo better zero copy handling */ filepos_t KaxInternalBlock::ReadData(IOCallback & input, ScopeMode ReadFully) { filepos_t Result; FirstFrameLocation = input.getFilePointer(); // will be updated accordingly below if (ReadFully == SCOPE_ALL_DATA) { Result = EbmlBinary::ReadData(input, ReadFully); binary *cursor = EbmlBinary::GetBuffer(); uint8 BlockHeadSize = 4; // update internal values TrackNumber = *cursor++; if ((TrackNumber & 0x80) == 0) { // there is extra data if ((TrackNumber & 0x40) == 0) { // We don't support track numbers that large ! return Result; } TrackNumber = (TrackNumber & 0x3F) << 8; TrackNumber += *cursor++; BlockHeadSize++; } else { TrackNumber &= 0x7F; } big_int16 b16; b16.Eval(cursor); LocalTimecode = int16(b16); bLocalTimecodeUsed = true; cursor += 2; if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) { bIsKeyframe = (*cursor & 0x80) != 0; bIsDiscardable = (*cursor & 0x01) != 0; } mInvisible = (*cursor & 0x08) >> 3; mLacing = LacingType((*cursor++ & 0x06) >> 1); // put all Frames in the list if (mLacing == LACING_NONE) { FirstFrameLocation += cursor - EbmlBinary::GetBuffer(); DataBuffer * soloFrame = new DataBuffer(cursor, GetSize() - BlockHeadSize); myBuffers.push_back(soloFrame); SizeList.resize(1); SizeList[0] = GetSize() - BlockHeadSize; } else { // read the number of frames in the lace uint32 LastBufferSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame uint8 FrameNum = *cursor++; // number of frames in the lace - 1 // read the list of frame sizes uint8 Index; int32 FrameSize; uint32 SizeRead; uint64 SizeUnknown; SizeList.resize(FrameNum + 1); switch (mLacing) { case LACING_XIPH: for (Index=0; Index<FrameNum; Index++) { // get the size of the frame FrameSize = 0; do { FrameSize += uint8(*cursor); LastBufferSize--; } while (*cursor++ == 0xFF); SizeList[Index] = FrameSize; LastBufferSize -= FrameSize; } SizeList[Index] = LastBufferSize; break; case LACING_EBML: SizeRead = LastBufferSize; FrameSize = ReadCodedSizeValue(cursor, SizeRead, SizeUnknown); SizeList[0] = FrameSize; cursor += SizeRead; LastBufferSize -= FrameSize + SizeRead; for (Index=1; Index<FrameNum; Index++) { // get the size of the frame SizeRead = LastBufferSize; FrameSize += ReadCodedSizeSignedValue(cursor, SizeRead, SizeUnknown); SizeList[Index] = FrameSize; cursor += SizeRead; LastBufferSize -= FrameSize + SizeRead; } SizeList[Index] = LastBufferSize; break; case LACING_FIXED: for (Index=0; Index<=FrameNum; Index++) { // get the size of the frame SizeList[Index] = LastBufferSize / (FrameNum + 1); } break; default: // other lacing not supported assert(0); } FirstFrameLocation += cursor - EbmlBinary::GetBuffer(); for (Index=0; Index<=FrameNum; Index++) { DataBuffer * lacedFrame = new DataBuffer(cursor, SizeList[Index]); myBuffers.push_back(lacedFrame); cursor += SizeList[Index]; } } SetValueIsSet(); }
/*! \brief Method to help reading a Master element and all subsequent children quickly \todo add an option to discard even unknown elements \todo handle when a mandatory element is not found */ void EbmlMaster::Read(EbmlStream & inDataStream, const EbmlSemanticContext & sContext, int & UpperEltFound, EbmlElement * & FoundElt, bool AllowDummyElt, ScopeMode ReadFully) { if (ReadFully != SCOPE_NO_DATA) { EbmlElement * ElementLevelA; // remove all existing elements, including the mandatory ones... size_t Index; for (Index=0; Index<ElementList.size(); Index++) { if (!(*ElementList[Index]).IsLocked()) { delete ElementList[Index]; } } ElementList.clear(); uint64 MaxSizeToRead; if (IsFiniteSize()) MaxSizeToRead = GetSize(); else MaxSizeToRead = 0x7FFFFFFF; // read blocks and discard the ones we don't care about if (MaxSizeToRead > 0) { inDataStream.I_O().setFilePointer(GetSizePosition() + GetSizeLength(), seek_beginning); ElementLevelA = inDataStream.FindNextElement(sContext, UpperEltFound, MaxSizeToRead, AllowDummyElt); while (ElementLevelA != NULL && UpperEltFound <= 0 && MaxSizeToRead > 0) { if (IsFiniteSize()) MaxSizeToRead = GetEndPosition() - ElementLevelA->GetEndPosition(); // even if it's the default value if (!AllowDummyElt && ElementLevelA->IsDummy()) { ElementLevelA->SkipData(inDataStream, sContext); delete ElementLevelA; // forget this unknown element } else { // more logical to do it afterward ElementList.push_back(ElementLevelA); ElementLevelA->Read(inDataStream, EBML_CONTEXT(ElementLevelA), UpperEltFound, FoundElt, AllowDummyElt, ReadFully); // just in case ElementLevelA->SkipData(inDataStream, EBML_CONTEXT(ElementLevelA)); } if (UpperEltFound > 0) { UpperEltFound--; if (UpperEltFound > 0 || MaxSizeToRead <= 0) goto processCrc; ElementLevelA = FoundElt; continue; } if (UpperEltFound < 0) { UpperEltFound++; if (UpperEltFound < 0) goto processCrc; } if (MaxSizeToRead <= 0) goto processCrc;// this level is finished ElementLevelA = inDataStream.FindNextElement(sContext, UpperEltFound, MaxSizeToRead, AllowDummyElt); } if (UpperEltFound > 0) { FoundElt = ElementLevelA; } } processCrc: EBML_MASTER_ITERATOR Itr, CrcItr; for (Itr = ElementList.begin(); Itr != ElementList.end();) { if ((EbmlId)(*(*Itr)) == EBML_ID(EbmlCrc32)) { bChecksumUsed = true; // remove the element Checksum = *(static_cast<EbmlCrc32*>(*Itr)); CrcItr = Itr; break; } ++Itr; } if (bChecksumUsed) { delete *CrcItr; Remove(CrcItr); } SetValueIsSet(); } }
/*! \todo better zero copy handling */ filepos_t KaxInternalBlock::ReadData(IOCallback & input, ScopeMode ReadFully) { filepos_t Result; FirstFrameLocation = input.getFilePointer(); // will be updated accordingly below SetValueIsSet(false); try { if (ReadFully == SCOPE_ALL_DATA) { Result = EbmlBinary::ReadData(input, ReadFully); if (Result != GetSize()) throw SafeReadIOCallback::EndOfStreamX(GetSize() - Result); binary *BufferStart = EbmlBinary::GetBuffer(); SafeReadIOCallback Mem(*this); uint8 BlockHeadSize = 4; // update internal values TrackNumber = Mem.GetUInt8(); if ((TrackNumber & 0x80) == 0) { // there is extra data if ((TrackNumber & 0x40) == 0) { // We don't support track numbers that large ! throw SafeReadIOCallback::EndOfStreamX(0); } TrackNumber = (TrackNumber & 0x3F) << 8; TrackNumber += Mem.GetUInt8(); BlockHeadSize++; } else { TrackNumber &= 0x7F; } LocalTimecode = int16(Mem.GetUInt16BE()); bLocalTimecodeUsed = true; uint8 Flags = Mem.GetUInt8(); if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) { bIsKeyframe = (Flags & 0x80) != 0; bIsDiscardable = (Flags & 0x01) != 0; } mInvisible = (Flags & 0x08) >> 3; mLacing = LacingType((Flags & 0x06) >> 1); // put all Frames in the list if (mLacing == LACING_NONE) { FirstFrameLocation += Mem.GetPosition(); DataBuffer * soloFrame = new DataBuffer(BufferStart + Mem.GetPosition(), GetSize() - BlockHeadSize); myBuffers.push_back(soloFrame); SizeList.resize(1); SizeList[0] = GetSize() - BlockHeadSize; } else { // read the number of frames in the lace uint32 LastBufferSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame uint8 FrameNum = Mem.GetUInt8(); // number of frames in the lace - 1 // read the list of frame sizes uint8 Index; int32 FrameSize; uint32 SizeRead; uint64 SizeUnknown; SizeList.resize(FrameNum + 1); switch (mLacing) { case LACING_XIPH: for (Index=0; Index<FrameNum; Index++) { // get the size of the frame FrameSize = 0; uint8 Value; do { Value = Mem.GetUInt8(); FrameSize += Value; LastBufferSize--; } while (Value == 0xFF); SizeList[Index] = FrameSize; LastBufferSize -= FrameSize; } SizeList[Index] = LastBufferSize; break; case LACING_EBML: SizeRead = LastBufferSize; FrameSize = ReadCodedSizeValue(BufferStart + Mem.GetPosition(), SizeRead, SizeUnknown); SizeList[0] = FrameSize; Mem.Skip(SizeRead); LastBufferSize -= FrameSize + SizeRead; for (Index=1; Index<FrameNum; Index++) { // get the size of the frame SizeRead = LastBufferSize; FrameSize += ReadCodedSizeSignedValue(BufferStart + Mem.GetPosition(), SizeRead, SizeUnknown); SizeList[Index] = FrameSize; Mem.Skip(SizeRead); LastBufferSize -= FrameSize + SizeRead; } if (Index <= FrameNum) // Safety check if FrameNum == 0 SizeList[Index] = LastBufferSize; break; case LACING_FIXED: for (Index=0; Index<=FrameNum; Index++) { // get the size of the frame SizeList[Index] = LastBufferSize / (FrameNum + 1); } break; default: // other lacing not supported assert(0); } FirstFrameLocation += Mem.GetPosition(); for (Index=0; Index<=FrameNum; Index++) { DataBuffer * lacedFrame = new DataBuffer(BufferStart + Mem.GetPosition(), SizeList[Index]); myBuffers.push_back(lacedFrame); Mem.Skip(SizeList[Index]); } } binary *BufferEnd = BufferStart + GetSize(); size_t NumFrames = myBuffers.size(); // Sanity checks for frame pointers and boundaries. for (size_t Index = 0; Index < NumFrames; ++Index) { binary *FrameStart = myBuffers[Index]->Buffer(); binary *FrameEnd = FrameStart + myBuffers[Index]->Size(); binary *ExpectedEnd = (Index + 1) < NumFrames ? myBuffers[Index + 1]->Buffer() : BufferEnd; if ((FrameStart < BufferStart) || (FrameEnd > BufferEnd) || (FrameEnd != ExpectedEnd)) throw SafeReadIOCallback::EndOfStreamX(0); } SetValueIsSet(); } else if (ReadFully == SCOPE_PARTIAL_DATA) { binary _TempHead[5]; Result = input.read(_TempHead, 5); if (Result != 5) throw SafeReadIOCallback::EndOfStreamX(0); binary *cursor = _TempHead; binary *_tmpBuf; uint8 BlockHeadSize = 4; // update internal values TrackNumber = *cursor++; if ((TrackNumber & 0x80) == 0) { // there is extra data if ((TrackNumber & 0x40) == 0) { // We don't support track numbers that large ! return Result; } TrackNumber = (TrackNumber & 0x3F) << 8; TrackNumber += *cursor++; BlockHeadSize++; } else { TrackNumber &= 0x7F; } big_int16 b16; b16.Eval(cursor); LocalTimecode = int16(b16); bLocalTimecodeUsed = true; cursor += 2; if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) { bIsKeyframe = (*cursor & 0x80) != 0; bIsDiscardable = (*cursor & 0x01) != 0; } mInvisible = (*cursor & 0x08) >> 3; mLacing = LacingType((*cursor++ & 0x06) >> 1); if (cursor == &_TempHead[4]) { _TempHead[0] = _TempHead[4]; } else { Result += input.read(_TempHead, 1); } FirstFrameLocation += cursor - _TempHead; // put all Frames in the list if (mLacing != LACING_NONE) { // read the number of frames in the lace uint32 LastBufferSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame uint8 FrameNum = _TempHead[0]; // number of frames in the lace - 1 // read the list of frame sizes uint8 Index; int32 FrameSize; uint32 SizeRead; uint64 SizeUnknown; SizeList.resize(FrameNum + 1); switch (mLacing) { case LACING_XIPH: for (Index=0; Index<FrameNum; Index++) { // get the size of the frame FrameSize = 0; do { Result += input.read(_TempHead, 1); FrameSize += uint8(_TempHead[0]); LastBufferSize--; FirstFrameLocation++; } while (_TempHead[0] == 0xFF); FirstFrameLocation++; SizeList[Index] = FrameSize; LastBufferSize -= FrameSize; } SizeList[Index] = LastBufferSize; break; case LACING_EBML: SizeRead = LastBufferSize; cursor = _tmpBuf = new binary[FrameNum*4]; /// \warning assume the mean size will be coded in less than 4 bytes Result += input.read(cursor, FrameNum*4); FrameSize = ReadCodedSizeValue(cursor, SizeRead, SizeUnknown); SizeList[0] = FrameSize; cursor += SizeRead; LastBufferSize -= FrameSize + SizeRead; for (Index=1; Index<FrameNum; Index++) { // get the size of the frame SizeRead = LastBufferSize; FrameSize += ReadCodedSizeSignedValue(cursor, SizeRead, SizeUnknown); SizeList[Index] = FrameSize; cursor += SizeRead; LastBufferSize -= FrameSize + SizeRead; } FirstFrameLocation += cursor - _tmpBuf; SizeList[Index] = LastBufferSize; delete [] _tmpBuf; break; case LACING_FIXED: for (Index=0; Index<=FrameNum; Index++) { // get the size of the frame SizeList[Index] = LastBufferSize / (FrameNum + 1); } break; default: // other lacing not supported assert(0); } } else { SizeList.resize(1); SizeList[0] = GetSize() - BlockHeadSize; } SetValueIsSet(false); Result = GetSize(); } else {
EbmlVoid::EbmlVoid() { SetValueIsSet(); }