More robust file reading for simulator files.

This commit is contained in:
Jeff Young 2023-04-24 11:58:03 +01:00
parent afc6b325b2
commit c381b6d024
12 changed files with 88 additions and 56 deletions

View File

@ -106,6 +106,47 @@ std::string StrPrintf( const char* format, ... )
}
wxString SafeReadFile( const wxString& aFilePath, const wxString& aReadType )
{
auto FROM_UTF8_WINE =
[]( const char* cstring )
{
wxString line = wxString::FromUTF8( cstring );
if( line.IsEmpty() ) // happens when cstring is not a valid UTF8 sequence
line = wxConvCurrent->cMB2WC( cstring ); // try to use locale conversion
// We have trouble here *probably* because Wine-hosted LTSpice writes out MSW
// encoded text on a macOS, where it isn't expected. In any case, wxWidgets'
// wxSafeConvert() appears to get around it.
if( line.IsEmpty() )
line = wxSafeConvertMB2WX( cstring );
// I'm not sure what the source of this style of line-endings is, but it can be
// found in some Fairchild Semiconductor SPICE files.
line.Replace( wxS( "\r\r\n" ), wxS( "\n" ) );
return line;
};
// Open file
FILE* fp = wxFopen( aFilePath, aReadType );
if( !fp )
THROW_IO_ERROR( wxString::Format( _( "Cannot open file '%s'." ), aFilePath ) );
FILE_LINE_READER fileReader( fp, aFilePath );
wxString contents;
while( fileReader.ReadLine() )
contents += FROM_UTF8_WINE( fileReader.Line() );
return contents;
}
//-----<LINE_READER>------------------------------------------------------
LINE_READER::LINE_READER( unsigned aMaxLineLength ) :

View File

@ -88,8 +88,8 @@ wxString SIM_LIB_MGR::ResolveLibraryPath( const wxString& aLibraryPath, const PR
}
std::string SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const std::string& aLibPath,
const std::string& aRelativeLib )
wxString SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const wxString& aLibPath,
const wxString& aRelativeLib )
{
wxFileName testPath( aLibPath );
wxString fullPath( aLibPath );
@ -123,7 +123,7 @@ std::string SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const std::string& aLibPath
catch( ... )
{}
return fullPath.ToStdString();
return fullPath;
}
@ -133,7 +133,7 @@ void SIM_LIB_MGR::SetLibrary( const wxString& aLibraryPath )
{
wxString path = ResolveLibraryPath( aLibraryPath, m_project );
std::function<std::string(const std::string&, const std::string&)> f2 =
std::function<wxString(const wxString&, const wxString&)> f2 =
std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, _1, _2 );
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( path, m_reporter, &f2 );
@ -287,7 +287,7 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath,
{
path = ResolveLibraryPath( aLibraryPath, m_project );
std::function<std::string( const std::string&, const std::string& )> f2 =
std::function<wxString( const wxString&, const wxString& )> f2 =
std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, _1, _2 );
auto it = m_libraries.try_emplace( path, SIM_LIBRARY::Create( path, m_reporter, &f2 ) ).first;

View File

@ -76,9 +76,7 @@ public:
std::vector<std::reference_wrapper<SIM_MODEL>> GetModels() const;
static wxString ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT* aProject );
std::string ResolveEmbeddedLibraryPath( const std::string& aLibPath,
const std::string& aRelativeLib );
wxString ResolveEmbeddedLibraryPath( const wxString& aLibPath, const wxString& aRelativeLib );
private:
const PROJECT* m_project;

View File

@ -29,8 +29,9 @@
#include <macros.h>
std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( const wxString& aFilePath, REPORTER* aReporter,
std::function<std::string( const std::string&, const std::string& )> *aResolver )
std::unique_ptr<SIM_LIBRARY>
SIM_LIBRARY::Create( const wxString& aFilePath, REPORTER* aReporter,
std::function<wxString( const wxString&, const wxString& )>* aResolver )
{
std::unique_ptr<SIM_LIBRARY> library;
@ -41,13 +42,13 @@ std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( const wxString& aFilePath, REP
library->m_reporter = aReporter;
library->m_pathResolver = aResolver;
library->ReadFile( std::string( TO_UTF8( aFilePath ) ), aReporter );
library->ReadFile( aFilePath, aReporter );
return library;
}
void SIM_LIBRARY::ReadFile( const std::string& aFilePath, REPORTER* aReporter )
void SIM_LIBRARY::ReadFile( const wxString& aFilePath, REPORTER* aReporter )
{
m_filePath = aFilePath;
}

View File

@ -52,9 +52,9 @@ public:
* @param aReporter The reporter the library reports to
* @return The library loaded in a newly constructed object.
*/
static std::unique_ptr<SIM_LIBRARY> Create( const wxString& aFilePath,
REPORTER* aReporter = nullptr,
std::function<std::string( const std::string&, const std::string& )>* aResolver = nullptr);
static std::unique_ptr<SIM_LIBRARY>
Create( const wxString& aFilePath, REPORTER* aReporter,
std::function<wxString( const wxString&, const wxString& )>* aResolver );
/**
* Read library from a source file. Must be in the format appropriate to the subclass, e.g.
@ -63,15 +63,7 @@ public:
* @param aFilePath Path to the file.
* @throw IO_ERROR on read or parsing error.
*/
virtual void ReadFile( const std::string& aFilePath, REPORTER* aReporter ) = 0;
/**
* Write library to a source file (e.g. in Spice format).
*
* @param aFilePath Path to the file.
* @throw IO_ERROR on write error.
*/
virtual void WriteFile( const std::string& aFilePath ) = 0;
virtual void ReadFile( const wxString& aFilePath, REPORTER* aReporter ) = 0;
SIM_MODEL* FindModel( const std::string& aModelName ) const;
@ -83,7 +75,7 @@ protected:
std::vector<std::string> m_modelNames;
std::vector<std::unique_ptr<SIM_MODEL>> m_models;
std::function<std::string( const std::string&, const std::string& )>* m_pathResolver;
std::function<wxString( const wxString&, const wxString& )>* m_pathResolver;
std::string m_filePath;

View File

@ -29,10 +29,10 @@
#include <lib_pin.h>
void SIM_LIBRARY_KIBIS::ReadFile( const std::string& aFilePath, REPORTER* aReporter )
void SIM_LIBRARY_KIBIS::ReadFile( const wxString& aFilePath, REPORTER* aReporter )
{
SIM_LIBRARY::ReadFile( aFilePath, aReporter );
m_kibis = KIBIS( aFilePath, m_reporter );
m_kibis = KIBIS( aFilePath.ToStdString(), m_reporter );
if( !m_kibis.m_valid )
{

View File

@ -38,10 +38,7 @@ public:
static constexpr auto DIFF_FIELD = "Sim.Ibis.Diff";
// @copydoc SIM_LIBRARY::ReadFile()
void ReadFile( const std::string& aFilePath, REPORTER* aReporter ) override;
// @copydoc SIM_LIBRARY::WriteFile()
void WriteFile( const std::string& aFilePath ) override{};
void ReadFile( const wxString& aFilePath, REPORTER* aReporter ) override;
bool InitModel( SIM_MODEL_KIBIS& aModel, wxString aCompName );
bool isPinDiff( const std::string& aComp, const std::string& aPinNumber ) const;

View File

@ -33,14 +33,9 @@ SIM_LIBRARY_SPICE::SIM_LIBRARY_SPICE() :
}
void SIM_LIBRARY_SPICE::ReadFile( const std::string& aFilePath, REPORTER* aReporter )
void SIM_LIBRARY_SPICE::ReadFile( const wxString& aFilePath, REPORTER* aReporter )
{
SIM_LIBRARY::ReadFile( aFilePath, aReporter );
m_spiceLibraryParser->ReadFile( aFilePath, aReporter );
}
void SIM_LIBRARY_SPICE::WriteFile( const std::string& aFilePath )
{
// Not implemented yet.
}

View File

@ -37,10 +37,7 @@ public:
SIM_LIBRARY_SPICE();
// @copydoc SIM_LIBRARY::ReadFile()
void ReadFile( const std::string& aFilePath, REPORTER* aReporter ) override;
// @copydoc SIM_LIBRARY::WriteFile()
void WriteFile( const std::string& aFilePath ) override;
void ReadFile( const wxString& aFilePath, REPORTER* aReporter ) override;
private:
std::unique_ptr<SPICE_LIBRARY_PARSER> m_spiceLibraryParser;

View File

@ -57,17 +57,16 @@ namespace SIM_LIBRARY_SPICE_PARSER
};
void SPICE_LIBRARY_PARSER::readElement( const std::string &aFilePath, REPORTER& aReporter )
void SPICE_LIBRARY_PARSER::parseFile( const wxString &aFilePath, REPORTER& aReporter )
{
try
{
tao::pegtl::file_input in( aFilePath );
std::unique_ptr<tao::pegtl::parse_tree::node> root =
tao::pegtl::parse_tree::parse<SIM_LIBRARY_SPICE_PARSER::libraryGrammar,
tao::pegtl::string_input<> in( SafeReadFile( aFilePath, wxS( "r" ) ).ToStdString(),
aFilePath.ToStdString() );
auto root = tao::pegtl::parse_tree::parse<SIM_LIBRARY_SPICE_PARSER::libraryGrammar,
SIM_LIBRARY_SPICE_PARSER::librarySelector,
tao::pegtl::nothing,
SIM_LIBRARY_SPICE_PARSER::control>
( in );
SIM_LIBRARY_SPICE_PARSER::control> ( in );
for( const auto& node : root->children )
{
@ -88,14 +87,14 @@ void SPICE_LIBRARY_PARSER::readElement( const std::string &aFilePath, REPORTER&
}
else if( node->is_type<SIM_LIBRARY_SPICE_PARSER::dotInclude>() )
{
std::string lib = node->children.at( 0 )->string();
wxString lib = node->children.at( 0 )->string();
try
{
if( m_library.m_pathResolver )
lib = ( *m_library.m_pathResolver )( lib, aFilePath );
readElement( lib, aReporter );
parseFile( lib, aReporter );
}
catch( const IO_ERROR& e )
{
@ -112,9 +111,9 @@ void SPICE_LIBRARY_PARSER::readElement( const std::string &aFilePath, REPORTER&
}
}
}
catch( const std::filesystem::filesystem_error& e )
catch( const IO_ERROR& e )
{
aReporter.Report( e.what(), RPT_SEVERITY_ERROR );
aReporter.Report( e.What(), RPT_SEVERITY_ERROR );
}
catch( const tao::pegtl::parse_error& e )
{
@ -123,21 +122,21 @@ void SPICE_LIBRARY_PARSER::readElement( const std::string &aFilePath, REPORTER&
}
void SPICE_LIBRARY_PARSER::ReadFile( const std::string& aFilePath, REPORTER* aReporter )
void SPICE_LIBRARY_PARSER::ReadFile( const wxString& aFilePath, REPORTER* aReporter )
{
m_library.m_models.clear();
m_library.m_modelNames.clear();
if( aReporter )
{
readElement( aFilePath, *aReporter );
parseFile( aFilePath, *aReporter );
}
else
{
wxString msg;
WX_STRING_REPORTER reporter( &msg );
readElement( aFilePath, reporter );
parseFile( aFilePath, reporter );
if( reporter.HasMessage() )
THROW_IO_ERROR( msg );

View File

@ -40,10 +40,10 @@ public:
virtual ~SPICE_LIBRARY_PARSER()
{};
virtual void ReadFile( const std::string& aFilePath, REPORTER* aReporter );
virtual void ReadFile( const wxString& aFilePath, REPORTER* aReporter );
protected:
void readElement( const std::string& aFilePath, REPORTER& aReporter );
void parseFile( const wxString& aFilePath, REPORTER& aReporter );
private:
SIM_LIBRARY_SPICE& m_library;

View File

@ -70,6 +70,18 @@ std::string
StrPrintf( const char* format, ... );
/**
* Nominally opens a file and reads it into a string. But unlike other facilities, this handles
* mis-encded Wine-written files on macOS.
*
* @param aFilePath
* @param aReadType
* @throw IO_ERROR if the file can't be opened
* @return the file contents
*/
wxString SafeReadFile( const wxString& aFilePath, const wxString& aReadType );
#define LINE_READER_LINE_DEFAULT_MAX 1000000
#define LINE_READER_LINE_INITIAL_SIZE 5000