27#include <wx/filename.h>
28#include <wx/translation.h>
37 const char16_t SCM_COMPONENT_STREAM[] = u
"[ScmComponent]";
47 void requireEnd(
const ARCHIVE& aAr,
const wxString& aWhat )
52 wxString::Format(
_(
"Easy-PC %s ends at offset %zu of %zu." ), aWhat, aAr.Pos(), aAr.Size() ) );
58 LOAD_TASK readItemList(
ARCHIVE& aAr, std::vector<SOURCE_PROJECT_ITEM*>& aItems )
60 for( uint32_t i = aAr.Count(); i > 0; --i )
63 aItems.push_back( item );
97 if( uint32_t oleItems = aAr.
U32() )
98 THROW_IO_ERROR( wxString::Format(
_(
"Easy-PC project holds %u OLE items." ), oleItems ) );
107 co_await readItemList( aAr,
Boards );
110 std::vector<SOURCE_PROJECT_ITEM*> other;
113 co_await readItemList( aAr, other );
118 for(
int i = 0; i < 11; ++i )
121 for( int32_t i = aAr.
I32(); i > 0; --i )
130std::unique_ptr<DESIGN_DOCUMENT>
LoadDesign(
const wxString& aPath )
133 std::unique_ptr<DESIGN_DOCUMENT> doc = std::make_unique<DESIGN_DOCUMENT>();
139 THROW_IO_ERROR( wxString::Format(
_(
"'%s' is a %s, not a design." ), aPath,
145 if( !contents || !contents->
IsStream() )
146 THROW_IO_ERROR( wxString::Format(
_(
"'%s' has no Contents stream." ), aPath ) );
149 u
"SummaryInformation" ) )
150 doc->SummaryInformation = file.
ReadStream( *summary );
154 std::vector<uint8_t> data = file.
ReadStream( *contents );
155 const char* root = doc->Kind ==
DOC_KIND::PCB ?
"CPcbDesign" :
"CScmDesign";
158 ARCHIVE ar( data.data(), data.size(), doc->Kind, 0 );
161 requireEnd( ar,
_(
"design" ) );
169 wxFileName fn( aPath );
170 return fn.FileExists() ? fn.GetModificationTime().GetValue().GetValue() : 0;
179 if( !isLibrary(
m_kind ) )
192 if( child->IsAppStream() )
195 if( wantStorage ? !child->IsStorage() : !child->IsStream() )
197 THROW_IO_ERROR( wxString::Format( _(
"Library '%s' holds '%s', which is not an item." ), m_path,
198 UnescapeItemName( child->Name ) ) );
204 std::set<wxString> originalNames;
209 for(
size_t i = 0; i < m_entries.size(); ++i )
211 wxString name = UnescapeItemName( m_entries[i]->Name );
213 if( m_byName.count( name ) )
215 const wxString original = name;
217 for( int suffix = 2; m_byName.count( name ) || originalNames.count( name ); ++suffix )
218 name = wxString::Format( wxS(
"%s (%d)" ), original, suffix );
220 m_warnings.push_back( wxString::Format( _(
"Library '%s' lists duplicate item '%s' as '%s'." ), m_path,
224 m_names.push_back(
name );
225 m_byName.emplace(
name, i );
232 auto it =
m_byName.find( aItemName );
238 std::unique_ptr<LIBRARY_ITEM> item = std::make_unique<LIBRARY_ITEM>();
241 item->Name = aItemName;
243 std::vector<const SOURCE_FB_ENTRY*> streams = { &entry };
252 THROW_IO_ERROR( wxString::Format(
_(
"Component '%s' has no [ScmComponent] stream." ), aItemName ) );
260 streams.push_back( child );
266 std::vector<uint8_t> data =
m_file.ReadStream( *stream );
271 for( std::unique_ptr<OBJECT>& obj : ar.
TakeObjects() )
272 item->Objects.push_back( std::move( obj ) );
279std::unique_ptr<PROJECT_DOCUMENT>
LoadProject(
const wxString& aPath )
283 std::unique_ptr<PROJECT_DOCUMENT> doc = std::make_unique<PROJECT_DOCUMENT>();
285 doc->Project = std::make_unique<SOURCE_PROJECT>();
287 requireEnd( ar,
_(
"project" ) );
296 wxString
name = aItemName;
297 name.Replace( wxS(
"\\" ), wxS(
"/" ) );
299 wxFileName fn(
name, wxPATH_UNIX );
300 fn.MakeAbsolute( wxFileName( aProjectPath ).GetPath() );
302 if( fn.FileExists() )
303 return fn.GetFullPath();
306 wxDir folder( fn.GetPath() );
309 for(
bool more = folder.IsOpened() && folder.GetFirst( &found, wxEmptyString, wxDIR_FILES ); more;
310 more = folder.GetNext( &found ) )
312 if( found.CmpNoCase( fn.GetFullName() ) == 0 )
314 fn.SetFullName( found );
319 return fn.GetFullPath();
327 if( wxFileName( aPath ).GetExt().CmpNoCase( wxS(
"prj" ) ) == 0 )
330 return {
true, std::nullopt };
335 catch(
const std::exception& )
One archive load stream; it owns every object it creates.
int CurrentReadFormat() const
static std::unique_ptr< OBJECT > Create(const char *aClass)
An object of a registered class, not yet loaded.
wxString ReadString()
ANSI (windows-1252) or the 0xFF 0xFFFE UTF-16 form.
std::vector< std::unique_ptr< OBJECT > > TakeObjects()
void SetReadFormat(int aFormat)
OBJECT * ReadObject()
ReadObject and LoadEmbedded outside any loader, running the nested loads to completion.
void LoadEmbedded(OBJECT &aObject, const char *aClass)
A compound file held in memory; any malformed structure throws IO_ERROR.
std::vector< uint8_t > ReadStream(const SOURCE_FB_ENTRY &aStream) const
const SOURCE_FB_ENTRY & Root() const
FILE_KIND FileKind() const
const SOURCE_FB_ENTRY * FindChild(const SOURCE_FB_ENTRY &aStorage, const std::u16string &aName) const
std::vector< const SOURCE_FB_ENTRY * > m_entries
std::unique_ptr< LIBRARY_ITEM > LoadItem(const wxString &aItemName) const
Throws IO_ERROR if no item has that name.
LIBRARY_FILE(const wxString &aPath)
Throws IO_ERROR when the file is not a library or is malformed.
std::map< wxString, size_t > m_byName
static long long Timestamp(const wxString &aPath)
A library file's modification time, 0 when it does not exist.
A loader coroutine. Awaiting one queues it on its archive's frame stack instead of nesting the call.
The project file (.prj), a bare archive stream.
Loading designs, library items and projects.
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
FILE_INFO Probe(const wxString &aPath)
Identify a file; projects are parsed fully, while designs and libraries are only inspected....
std::vector< uint8_t > ReadWholeFile(const wxString &aPath)
The whole content of a file; throws IO_ERROR when it cannot be read.
std::unique_ptr< DESIGN_DOCUMENT > LoadDesign(const wxString &aPath)
const char * FileKindString(FILE_KIND aKind)
DOC_KIND
Document kind, from the FileType stream or the file extension for projects.
@ SCH_SYMBOL
one item stream of a Schematic Symbol Library
@ COMPONENT
one stream of a Component Library storage
@ PCB_SYMBOL
one item stream of a PCB Symbol Library
FILE_KIND
The FileType strings the importer reads.
@ SCHEMATIC_SYMBOL_LIBRARY
wxString UnescapeItemName(const std::u16string &aName)
Undo the item name escaping, which stores # ! \ / : * ? " < > | as 0x06..0x10.
wxString ResolveProjectItem(const wxString &aProjectPath, const wxString &aItemName)
The file a project item names, as Easy-PC opens it: the Windows path relative to the project's direct...
std::unique_ptr< PROJECT_DOCUMENT > LoadProject(const wxString &aPath)
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
wxString Name
Windows path relative to the project directory.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
std::vector< SOURCE_PROJECT_ITEM * > Schematics
in sheet order
std::vector< SOURCE_PROJECT_ITEM * > Boards
at most one