31#include <wx/filename.h>
32#include <wx/translation.h>
43 FILE* fp = wxFopen( aFileName, wxT(
"rb" ) );
47 THROW_IO_ERROR( wxString::Format(
_(
"Cannot open file '%s'." ), aFileName ) );
50 fseek( fp, 0, SEEK_END );
51 long len = ftell( fp );
57 wxString::Format(
_(
"Cannot determine length of file '%s'." ), aFileName ) );
60 m_data.resize(
static_cast<size_t>( len ) );
62 fseek( fp, 0, SEEK_SET );
64 size_t bytesRead = fread(
m_data.data(), 1,
m_data.size(), fp );
67 if( bytesRead !=
m_data.size() )
69 THROW_IO_ERROR( wxString::Format(
_(
"Error reading file '%s'." ), aFileName ) );
84 if( aOffset >
m_data.size() )
86 THROW_IO_ERROR( wxString::Format(
_(
"Seek past end of file (offset %zu, size %zu)." ),
87 aOffset,
m_data.size() ) );
123 int raw = (
static_cast<int>( p[0] ) << 16 )
124 | (
static_cast<int>( p[1] ) << 8 )
125 | (
static_cast<int>( p[2] ) );
137 unsigned int raw = (
static_cast<unsigned int>( p[0] ) << 24 )
138 | (
static_cast<unsigned int>( p[1] ) << 16 )
139 | (
static_cast<unsigned int>( p[2] ) << 8 )
140 | (
static_cast<unsigned int>( p[3] ) );
142 return static_cast<int>( raw ) -
INT4_BIAS;
187 _(
"Unexpected end of file at offset 0x%06zX: need 3 bytes for int3, "
188 "have %zu remaining." ),
193 int raw = (
static_cast<int>( p[0] ) << 16 )
194 | (
static_cast<int>( p[1] ) << 8 )
195 | (
static_cast<int>( p[2] ) );
205 _(
"Unexpected end of file at offset 0x%06zX: need 4 bytes for int4, "
206 "have %zu remaining." ),
211 unsigned int raw = (
static_cast<unsigned int>( p[0] ) << 24 )
212 | (
static_cast<unsigned int>( p[1] ) << 16 )
213 | (
static_cast<unsigned int>( p[2] ) << 8 )
214 | (
static_cast<unsigned int>( p[3] ) );
215 return static_cast<int>( raw ) -
INT4_BIAS;
224 _(
"Unexpected end of file at offset 0x%06zX: need 1 byte." ),
m_offset ) );
236 return static_cast<int>(
static_cast<int64_t
>( aDipTraceCoord ) * 100 / 3 );
250 size_t aStart,
size_t aEnd )
const
252 if( aEnd == 0 || aEnd >
m_data.size() )
255 if( aStart >= aEnd || aPatternLen == 0 || aPatternLen > ( aEnd - aStart ) )
256 return std::string::npos;
258 auto it = std::search(
m_data.begin() + aStart,
261 aPattern + aPatternLen );
263 if( it ==
m_data.begin() + aEnd )
264 return std::string::npos;
266 return static_cast<size_t>( it -
m_data.begin() );
273 return std::string::npos;
277 wxMBConvUTF16BE conv;
281 size_t charCount = aStr.length();
282 std::vector<uint8_t> encoded( charCount * 2 );
284 for(
size_t i = 0; i < charCount; i++ )
287 encoded[i * 2] =
static_cast<uint8_t
>( ( ch >> 8 ) & 0xFF );
288 encoded[i * 2 + 1] =
static_cast<uint8_t
>( ch & 0xFF );
292 size_t matchPos =
FindPattern( encoded.data(), encoded.size(), aStart, aEnd );
294 if( matchPos == std::string::npos )
295 return std::string::npos;
299 return std::string::npos;
344 if( asciiOk && !utf16Ok )
346 else if( utf16Ok && !asciiOk )
360 int charCount = (
static_cast<int>( p[0] ) << 8 ) |
static_cast<int>( p[1] );
369 _(
"Unreasonable string length %d at offset 0x%06zX." ),
373 size_t byteCount =
static_cast<size_t>( charCount ) * 2;
379 wxMBConvUTF16BE conv;
398 _(
"Unreasonable v37 string length %d at offset 0x%06zX." ),
402 size_t count =
static_cast<size_t>( byteCount );
407 wxString
result = wxString::From8BitData(
422 int charCount = (
static_cast<int>( p[0] ) << 8 ) |
static_cast<int>( p[1] );
427 aResult = wxString();
431 if( charCount < 0 || charCount > 500 )
437 size_t byteCount =
static_cast<size_t>( charCount ) * 2;
445 wxMBConvUTF16BE conv;
446 wxString candidate = wxString(
reinterpret_cast<const char*
>( &
m_data[
m_offset] ),
469 int byteCount = (
static_cast<int>( p[0] ) << 16 )
470 | (
static_cast<int>( p[1] ) << 8 )
471 | (
static_cast<int>( p[2] ) );
477 aResult = wxString();
481 if( byteCount < 0 || byteCount > 500 )
487 size_t count =
static_cast<size_t>( byteCount );
495 wxString candidate = wxString::From8BitData(
512 for(
size_t i = 0; i < aStr.length(); i++ )
516 if( ch ==
'\r' || ch ==
'\n' || ch ==
'\t' )
532 _(
"Unexpected end of file at offset 0x%06zX: need %zu bytes, have %zu remaining." ),
533 m_offset, aBytesNeeded, remaining ) );
bool TryReadStringUTF16(wxString &aResult)
Attempt to read a UTF-16-BE string with validation.
size_t FindString(const wxString &aStr, size_t aStart, size_t aEnd) const
Search for a UTF-16-BE encoded string in the file data, including its two-byte length prefix.
int PeekInt3() const
Peek at the next 3-byte biased integer without advancing the position.
wxString ReadStringASCII()
Read a v37 legacy ASCII string: int3(byte_count) + raw ASCII bytes.
bool TryReadStringASCII(wxString &aResult)
Attempt to read a legacy ASCII string with validation.
void ReadBytes(uint8_t *aDst, size_t aCount)
Read a block of raw bytes into the caller's buffer.
int m_version
DipTrace format version.
void Skip(size_t aBytes)
Advance the read position by the given number of bytes.
uint8_t ReadByte()
Read a single unsigned byte and advance the position by 1.
size_t m_offset
Current read position (byte offset).
uint8_t PeekByte() const
Peek at the next byte without advancing the position.
void ThrowEOFError(size_t aBytesNeeded) const
Throw IO_ERROR with a message indicating a read past end of file.
void DetectStringEncoding(size_t aProbeOffset)
Detect the string encoding from the bytes at aProbeOffset, which must sit at the start of a non-empty...
STRING_ENCODING m_stringEncoding
Explicit string encoding override.
static bool IsPrintableString(const wxString &aStr)
Verify that all characters in aStr are printable or common whitespace (space, tab,...
void ReadColor(uint8_t &r, uint8_t &g, uint8_t &b)
Read a 3-byte RGB color value.
int ReadInt4()
Read a 4-byte big-endian biased integer (bias 1,000,000,000) and advance the position by 4.
int ReadInt3()
Read a 3-byte big-endian biased integer (bias 1,000,000) and advance the position by 3.
static int DipTraceToKiCadNm(int aDipTraceCoord)
Convert a DipTrace coordinate value (10 nm units) to KiCad nanometers.
size_t FindPattern(const uint8_t *aPattern, size_t aPatternLen, size_t aStart, size_t aEnd) const
Search for a byte pattern in the file data.
void SetOffset(size_t aOffset)
Set the read position to an absolute byte offset.
bool TryReadString(wxString &aResult)
Attempt to read a string at the current position.
wxString ReadStringUTF16()
Read a v39+ UTF-16-BE string: uint16-BE char count + UTF-16-BE data.
BINARY_READER(const wxString &aFileName)
Construct a reader by loading the given file into memory.
int PeekInt4() const
Peek at the next 4-byte biased integer without advancing the position.
static double DipTraceToMM(int aDipTraceCoord)
Convert a DipTrace coordinate value (10 nm units) to millimeters.
wxString ReadString()
Read a string using the configured encoding.
std::vector< uint8_t > m_data
Entire file contents loaded into memory.
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
constexpr double DIPTRACE_COORD_TO_MM
DipTrace uses 762 units per mil (30 000 units per mm).
constexpr int MAX_STRING_CHARS
Maximum sane string length (in characters) accepted by the reader.
constexpr int INT4_BIAS
Bias value added to stored 4-byte unsigned integers.
constexpr int LEGACY_STRING_VERSION
Format version at or below which strings use the legacy ASCII encoding (int3 byte-count + raw ASCII b...
constexpr int INT3_BIAS
Bias value added to stored 3-byte unsigned integers.
wxString result
Test unit parsing edge cases and error handling.