tracy/server/TracyFileWrite.hpp
Bartosz Taudul 764792d8db Try to not crash when opening invalid files.
Tracy will now perform a number of checks when trying to read a dump
file:
1. The file must have at least 4 bytes of data.
2. There should be a 4 byte header to indicate the file was saved by
   tracy. This is a breaking change in file format.
3. Old header-less files are still supported, but there's a new check
   for data validity. The first 4 bytes of file (as an uint32) must be
   less or equal to max LZ4 data packet size. This requires the first
   two bytes to be 00 00 or 00 01, which should catch most invalid
   files.
2018-04-21 14:53:40 +02:00

103 lines
2.2 KiB
C++

#ifndef __TRACYFILEWRITE_HPP__
#define __TRACYFILEWRITE_HPP__
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include "TracyFileHeader.hpp"
#include "../common/tracy_lz4.hpp"
#include "../common/TracyForceInline.hpp"
namespace tracy
{
class FileWrite
{
public:
static FileWrite* Open( const char* fn )
{
auto f = fopen( fn, "wb" );
return f ? new FileWrite( f ) : nullptr;
}
~FileWrite()
{
if( m_offset > 0 )
{
WriteLz4Block();
}
fclose( m_file );
LZ4_freeStream( m_stream );
}
tracy_force_inline void Write( const void* ptr, size_t size )
{
if( m_offset + size <= BufSize )
{
WriteSmall( ptr, size );
}
else
{
WriteBig( ptr, size );
}
}
private:
FileWrite( FILE* f )
: m_stream( LZ4_createStream() )
, m_file( f )
, m_offset( 0 )
, m_active( 0 )
{
fwrite( Lz4Header, 1, sizeof( Lz4Header ), m_file );
}
tracy_force_inline void WriteSmall( const void* ptr, size_t size )
{
memcpy( m_buf[m_active] + m_offset, ptr, size );
m_offset += size;
}
void WriteBig( const void* ptr, size_t size )
{
auto src = (const char*)ptr;
while( size > 0 )
{
const auto sz = std::min( size, BufSize - m_offset );
memcpy( m_buf[m_active] + m_offset, src, sz );
m_offset += sz;
src += sz;
size -= sz;
if( m_offset == BufSize )
{
WriteLz4Block();
}
}
}
void WriteLz4Block()
{
char lz4[LZ4Size];
const uint32_t sz = LZ4_compress_fast_continue( m_stream, m_buf[m_active], lz4, m_offset, LZ4Size, 1 );
fwrite( &sz, 1, sizeof( sz ), m_file );
fwrite( lz4, 1, sz, m_file );
m_offset = 0;
m_active = 1 - m_active;
}
enum { BufSize = 64 * 1024 };
enum { LZ4Size = LZ4_COMPRESSBOUND( BufSize ) };
LZ4_stream_t* m_stream;
FILE* m_file;
char m_buf[2][BufSize];
size_t m_offset;
uint8_t m_active;
};
}
#endif