// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// /* OdTvMessage implementation */ #include "OdaCommon.h" #include "TvMessage.h" template< typename T > void putToBuffer( char* pBuffer, const T* pData, size_t& offset ) { memcpy( pBuffer + offset, pData, sizeof( T ) ); offset += sizeof( T ); } template< typename T > void getFromBuffer( const char* pBuffer, T* pData, size_t& offset ) { memcpy( pData, pBuffer + offset, sizeof( T ) ); offset += sizeof( T ); } bool OdTvMessage::writeTo( char* pBuffer, size_t bufferSize ) const { if( currentOffset() > m_binData.size() ) { bool stop = true; } if( bufferSize < headerSize() ) return false; //New writing, prepare header if( m_currentOffset == 0 ) { size_t offset = 0; OdUInt8 t = (OdUInt8)m_type; putToBuffer< OdUInt8 >( pBuffer, &t, offset ); putToBuffer< OdUInt64 >( pBuffer, &m_id, offset ); putToBuffer< OdUInt32 >( pBuffer, &m_dataSize, offset ); if( m_binData.empty() || m_currentOffset == m_binData.size() ) return true; unsigned nBytes = m_binData.size() - m_currentOffset; if( nBytes > bufferSize - ( headerSize() + m_currentOffset ) ) { nBytes = (unsigned)( bufferSize - ( headerSize() + m_currentOffset ) ); } memcpy( pBuffer + offset, m_binData.asArrayPtr() + m_currentOffset, nBytes ); m_currentOffset += nBytes; } else { //Part of message already written, only add data with no header unsigned nBytes = m_binData.size() - m_currentOffset; if( nBytes > bufferSize - m_currentOffset ) { nBytes = (unsigned)( bufferSize - m_currentOffset ); } memcpy( pBuffer, m_binData.asArrayPtr() + m_currentOffset, nBytes ); m_currentOffset += nBytes; } return true; } std::shared_ptr< OdTvMessage > OdTvMessage::readFrom( const char* pBuffer, size_t bufferSize, size_t& endPosition ) { if( bufferSize < headerSize() ) return std::shared_ptr< OdTvMessage >( nullptr ); size_t offset = 0; OdUInt8 t = 0; getFromBuffer< OdUInt8 >( pBuffer, &t, offset ); Type tp = (Type)( t ); if( tp == Type::kUnknown ) return std::shared_ptr< OdTvMessage >( nullptr ); std::shared_ptr< OdTvMessage > pRes = std::make_shared< OdTvMessage >(); pRes->m_type = tp; getFromBuffer< OdUInt64 >( pBuffer, &pRes->m_id, offset ); getFromBuffer< OdUInt32 >( pBuffer, &pRes->m_dataSize, offset ); if( pRes->m_dataSize == 0 ) return pRes; unsigned nBytes = pRes->m_dataSize; if( (unsigned)( bufferSize - headerSize() ) < nBytes ) { nBytes = (unsigned)( bufferSize - headerSize() ); } pRes->m_binData.resize( nBytes ); memcpy( pRes->m_binData.asArrayPtr(), pBuffer + offset, nBytes ); endPosition = offset + nBytes; return pRes; } void OdTvMessageBuilder::buildFromBuffer( const char* pBuffer, size_t bufferSize, OdTvMessageBuilder::OdTvMessageBuilderReactor* pReactor ) { const char* pInputBuffer = pBuffer; size_t bufSize = bufferSize; OdVector< char > tmp; if( !m_unparsedBuffer.empty() ) { tmp.resize( (unsigned)( m_unparsedBuffer.size() + bufferSize ) ); memcpy( tmp.asArrayPtr(), m_unparsedBuffer.asArrayPtr(), m_unparsedBuffer.size() ); memcpy( tmp.asArrayPtr() + m_unparsedBuffer.size(), pBuffer, bufferSize ); pInputBuffer = tmp.asArrayPtr(); bufSize = tmp.size(); } size_t offset = 0; for( ;; ) { size_t curOffset = offset; size_t newOffset = 0; OdTvMessagePtr pMsg = OdTvMessage::readFrom( pInputBuffer + curOffset, bufSize - curOffset, newOffset ); offset += newOffset; if( pMsg ) { if( pMsg->expectedDataSize() == pMsg->binDataSize() ) { pReactor->onMessage( pMsg ); } else { pReactor->onIncompleteMessage( pMsg ); offset = curOffset; break; } if( offset == bufSize ) break; } else { break; } } if( offset != bufSize ) { m_unparsedBuffer.resize( (unsigned)( bufSize - offset ) ); memcpy( m_unparsedBuffer.asArrayPtr(), pInputBuffer + offset, m_unparsedBuffer.size() ); } else { m_unparsedBuffer.clear(); } } OdTvMessagePtr OdTvMessageBuilder::buildBinaryMessage( const char* pBuffer, size_t bufferSize ) { OdTvMessagePtr pMessage = std::make_shared< OdTvMessage >(); pMessage->setType( OdTvMessage::Type::kBinData ); pMessage->setId( 0 ); pMessage->setBinData( (unsigned)bufferSize, pBuffer ); pMessage->setExpectedDataSize( pMessage->binDataSize() ); return pMessage; } OdTvMessagePtr OdTvMessageBuilder::buildCommandMessage( OdTvMessage::Commands command ) { OdTvMessagePtr pMessage = std::make_shared< OdTvMessage >(); pMessage->setType( OdTvMessage::Type::kCommand ); pMessage->setId( 0 ); OdUInt16 cmd = (OdUInt16)command; pMessage->setBinData( (unsigned)sizeof( command ), (const char*)( &cmd ) ); pMessage->setExpectedDataSize( pMessage->binDataSize() ); return pMessage; } OdTvMessagePtr OdTvMessageBuilder::buildFileStatusMessage( OdTvMessage::FileStatus st ) { OdTvMessagePtr pMessage = std::make_shared< OdTvMessage >(); pMessage->setType( OdTvMessage::Type::kFileStatus ); pMessage->setId( 0 ); OdUInt16 cmd = (OdUInt16)st; pMessage->setBinData( (unsigned)sizeof( st ), (const char*)( &cmd ) ); pMessage->setExpectedDataSize( pMessage->binDataSize() ); return pMessage; } OdTvMessagePtr OdTvMessageBuilder::buildFileRequestMessage( const OdString& filename ) { OdTvMessagePtr pMessage = std::make_shared< OdTvMessage >(); pMessage->setType( OdTvMessage::Type::kFileRequest ); pMessage->setId( 0 ); OdUInt16 l = (OdUInt16)filename.getLength(); unsigned sz = sizeof( OdUInt16 ) + l * 2; OdVector< char > buffer; buffer.resize( sz ); size_t offset = 0; putToBuffer< OdUInt16 >( buffer.asArrayPtr(), &l, offset ); memcpy( buffer.asArrayPtr() + offset, filename.c_str(), 2 * l ); pMessage->setBinData( buffer.size(), buffer.asArrayPtr() ); pMessage->setExpectedDataSize( pMessage->binDataSize() ); return pMessage; } OdTvMessagePtr OdTvMessageBuilder::buildStringListMessage( const OdVector< OdString >& strs ) { OdTvMessagePtr pMessage = std::make_shared< OdTvMessage >(); pMessage->setType( OdTvMessage::Type::kStringList ); pMessage->setId( 0 ); OdVector< char > buffer; unsigned sz = sizeof( unsigned ); //num items for( unsigned int i = 0; i < strs.size(); ++i ) { sz += sizeof( OdUInt16 ); //string length sz += strs[ i ].getLength() * 2; } buffer.resize( sz ); size_t offset = 0; unsigned nStr = (unsigned)( strs.size() ); putToBuffer< unsigned >( buffer.asArrayPtr(), &nStr, offset ); for( unsigned int i = 0; i < strs.size(); ++i ) { OdUInt16 l = (OdUInt16)strs[ i ].getLength(); putToBuffer< OdUInt16 >( buffer.asArrayPtr(), &l, offset ); memcpy( buffer.asArrayPtr() + offset, strs[ i ].c_str(), 2 * l ); offset += 2 * l; } pMessage->setBinData( buffer.size(), buffer.asArrayPtr() ); pMessage->setExpectedDataSize( pMessage->binDataSize() ); return pMessage; } bool OdTvMessageBuilder::extractStringListFromMessage( OdTvMessagePtr pMsg, OdVector< OdString >& strs ) { strs.clear(); if( !pMsg ) return false; if( pMsg->type() != OdTvMessage::Type::kStringList ) return false; if( pMsg->binDataSize() < sizeof( unsigned ) ) return false; size_t offset = 0; unsigned nStrings = 0; getFromBuffer( pMsg->binData(), &nStrings, offset ); for( unsigned i = 0; i < nStrings; ++i ) { OdString str; OdUInt16 l = 0; getFromBuffer( pMsg->binData(), &l, offset ); OdChar* pBuf = str.getBufferSetLength( l ); memcpy( pBuf, pMsg->binData() + offset, l * 2 ); offset += l * 2; strs.push_back( str ); } return true; } OdTvMessage::Commands OdTvMessageBuilder::extractCommandFromMessage( OdTvMessagePtr pMsg ) { if( !pMsg ) return OdTvMessage::Commands::kUnknown; if( pMsg->type() != OdTvMessage::Type::kCommand ) return OdTvMessage::Commands::kUnknown; if( pMsg->binDataSize() < sizeof( OdUInt16 ) ) return OdTvMessage::Commands::kUnknown; OdUInt16 cmd = 0; size_t offset = 0; getFromBuffer( pMsg->binData(), &cmd, offset ); return (OdTvMessage::Commands)cmd; } OdTvMessage::FileStatus OdTvMessageBuilder::extractStatusFromMessage( OdTvMessagePtr pMsg ) { if( !pMsg ) return OdTvMessage::FileStatus::kNotFound; if( pMsg->type() != OdTvMessage::Type::kFileStatus ) return OdTvMessage::FileStatus::kNotFound; if( pMsg->binDataSize() < sizeof( OdUInt16 ) ) return OdTvMessage::FileStatus::kNotFound; OdUInt16 cmd = 0; size_t offset = 0; getFromBuffer( pMsg->binData(), &cmd, offset ); return (OdTvMessage::FileStatus)cmd; } OdString OdTvMessageBuilder::extractFileRequestMessage( OdTvMessagePtr pMsg ) { if( !pMsg ) return OdString::kEmpty; if( pMsg->type() != OdTvMessage::Type::kFileRequest ) return OdString::kEmpty; if( pMsg->binDataSize() < sizeof( OdUInt16 ) ) return OdString::kEmpty; size_t offset = 0; OdUInt16 l = 0; OdString str; getFromBuffer( pMsg->binData(), &l, offset ); OdChar* pBuf = str.getBufferSetLength( l ); memcpy( pBuf, pMsg->binData() + offset, l * 2 ); return str; } OdTvMessagePtr OdTvMessageBuilder::buildFilePartsRequestMessage( const OdString& filename, const OdVector< OdTvMessage::FilePart >& parts ) { OdTvMessagePtr pMessage = std::make_shared< OdTvMessage >(); pMessage->setType( OdTvMessage::Type::kFilePartsRequest ); pMessage->setId( 0 ); OdVector< char > buffer; OdUInt16 l = (OdUInt16)filename.getLength(); unsigned sz = sizeof( OdUInt16 ) + l * 2; sz += sizeof( unsigned ); //num items sz += sizeof( OdTvMessage::FilePart ) * parts.size(); buffer.resize( sz ); size_t offset = 0; putToBuffer< OdUInt16 >( buffer.asArrayPtr(), &l, offset ); memcpy( buffer.asArrayPtr() + offset, filename.c_str(), 2 * l ); offset += 2 * l; unsigned nParts = (unsigned)( parts.size() ); putToBuffer< unsigned >( buffer.asArrayPtr(), &nParts, offset ); for( unsigned int i = 0; i < nParts; ++i ) { putToBuffer< OdUInt64 >( buffer.asArrayPtr(), &parts[ i ].offset, offset ); putToBuffer< OdUInt64 >( buffer.asArrayPtr(), &parts[ i ].size, offset ); } pMessage->setBinData( buffer.size(), buffer.asArrayPtr() ); pMessage->setExpectedDataSize( pMessage->binDataSize() ); return pMessage; } bool OdTvMessageBuilder::extractFilePartsFromMessage( OdTvMessagePtr pMsg, OdString& fileName, OdVector< OdTvMessage::FilePart >& parts ) { fileName = OdString::kEmpty; parts.clear(); if( !pMsg ) return false; if( pMsg->type() != OdTvMessage::Type::kFilePartsRequest ) return false; if( pMsg->binDataSize() < sizeof( OdUInt16 ) ) return false; size_t offset = 0; OdUInt16 l = 0; getFromBuffer( pMsg->binData(), &l, offset ); OdChar* pBuf = fileName.getBufferSetLength( l ); memcpy( pBuf, pMsg->binData() + offset, l * 2 ); offset += 2 * l; unsigned nParts = 0; getFromBuffer( pMsg->binData(), &nParts, offset ); for( unsigned i = 0; i < nParts; ++i ) { OdTvMessage::FilePart part; getFromBuffer( pMsg->binData(), &part.offset, offset ); getFromBuffer( pMsg->binData(), &part.size, offset ); parts.push_back( part ); } return true; }