23#include <wx/filename.h>
25#include <wx/mstream.h>
26#include <wx/wfstream.h>
42 if(
HasFile( aName.GetFullName() ) )
45 return m_files[aName.GetFullName()];
47 m_files.erase( aName.GetFullName() );
50 wxFFileInputStream file( aName.GetFullPath() );
51 wxMemoryBuffer buffer;
56 wxFileOffset length = file.GetLength();
58 std::unique_ptr<EMBEDDED_FILE> efile = std::make_unique<EMBEDDED_FILE>();
59 efile->name = aName.GetFullName();
60 efile->decompressedData.resize( length );
62 wxString ext = aName.GetExt().Upper();
65 if( ext ==
"STP" || ext ==
"STPZ" || ext ==
"STEP" || ext ==
"WRL" || ext ==
"WRZ" )
69 else if( ext ==
"WOFF" || ext ==
"WOFF2" || ext ==
"TTF" || ext ==
"OTF" )
73 else if( ext ==
"PDF" )
77 else if( ext ==
"KICAD_WKS" )
82 if( !efile->decompressedData.data() )
85 char* data = efile->decompressedData.data();
86 wxFileOffset total_read = 0;
88 while( !file.Eof() && total_read < length )
90 file.Read( data, length - total_read );
92 size_t read = file.LastRead();
100 efile->is_valid =
true;
102 m_files[aName.GetFullName()] = efile.release();
104 return m_files[aName.GetFullName()];
147 bool aWriteData )
const
150 aOut.
Print( aNestLevel,
"(embedded_files\n" );
156 aOut.
Print( aNestLevel + 1,
"(file\n" );
157 aOut.
Print( aNestLevel + 2,
"(name \"%s\")\n", file.
name.c_str().AsChar() );
159 const char* type =
nullptr;
180 aOut.
Print( aNestLevel + 2,
"(type %s)\n", type );
184 aOut.
Print( 2,
"(data\n" );
195 aOut.
Print( aNestLevel + 3,
"%1s%.*s%s\n", first ?
"" :
"|", length, view.data(),
196 remaining == length ?
"|" :
"" );
199 aOut.
Print( aNestLevel + 2,
")\n" );
202 aOut.
Print( aNestLevel + 2,
"(checksum \"%s\")\n", file.
data_sha.c_str() );
203 aOut.
Print( aNestLevel + 1,
")\n" );
206 aOut.
Print( aNestLevel,
")\n" );
212 std::vector<char> compressedData;
213 size_t estCompressedSize = ZSTD_compressBound( aFile.
decompressedData.size() );
214 compressedData.resize( estCompressedSize );
215 size_t compressedSize = ZSTD_compress( compressedData.data(), estCompressedSize,
219 if( ZSTD_isError( compressedSize ) )
221 compressedData.clear();
225 const size_t dstLen = wxBase64EncodedSize( compressedSize );
228 compressedData.data(), compressedSize );
229 if( retval != dstLen )
243 std::vector<char> compressedData;
246 if( compressedSize == 0 )
248 wxLogTrace( wxT(
"KICAD_EMBED" ),
249 wxT(
"%s:%s:%d\n * Base64DecodedSize failed for file '%s' with size %zu" ),
254 compressedData.resize( compressedSize );
255 void* compressed = compressedData.data();
261 unsigned long long estDecompressedSize = ZSTD_getFrameContentSize( compressed, compressedSize );
263 if( estDecompressedSize > 1e9 )
266 if( estDecompressedSize == ZSTD_CONTENTSIZE_ERROR
267 || estDecompressedSize == ZSTD_CONTENTSIZE_UNKNOWN )
275 size_t decompressedSize = ZSTD_decompress( decompressed, estDecompressedSize,
276 compressed, compressedSize );
278 if( ZSTD_isError( decompressedSize ) )
280 wxLogTrace( wxT(
"KICAD_EMBED" ),
281 wxT(
"%s:%s:%d\n * ZSTD_decompress failed with error '%s'" ),
282 __FILE__, __FUNCTION__, __LINE__, ZSTD_getErrorName( decompressedSize ) );
294 wxLogTrace( wxT(
"KICAD_EMBED" ),
295 wxT(
"%s:%s:%d\n * Checksum error in embedded file '%s'" ),
296 __FILE__, __FUNCTION__, __LINE__, aFile.
name );
309 CurLineNumber(), CurOffset() );
311 using namespace EMBEDDED_FILES_T;
313 std::unique_ptr<EMBEDDED_FILES::EMBEDDED_FILE> file(
nullptr );
315 for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
317 if( token != T_LEFT )
322 if( token != T_file )
327 if( !file->compressedEncodedData.empty() )
331 if( !file->Validate() )
333 CurLine(), CurLineNumber(), CurOffset() );
336 aFiles->
AddFile( file.release() );
339 file = std::unique_ptr<EMBEDDED_FILES::EMBEDDED_FILE>(
nullptr );
342 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
344 if( token != T_LEFT )
353 NeedSYMBOLorNUMBER();
355 if( !IsSymbol( token ) )
356 Expecting(
"checksum data" );
358 file->data_sha = CurStr();
366 file->compressedEncodedData.reserve( 1 << 17 );
368 while( token != T_BAR )
370 if( !IsSymbol( token ) )
371 Expecting(
"base64 file data" );
373 file->compressedEncodedData += CurStr();
377 file->compressedEncodedData.shrink_to_fit();
386 wxLogTrace( wxT(
"KICAD_EMBED" ),
387 wxT(
"Duplicate 'name' tag in embedded file %s" ), file->name );
390 NeedSYMBOLorNUMBER();
392 file = std::make_unique<EMBEDDED_FILES::EMBEDDED_FILE>();
393 file->name = CurStr();
420 Expecting(
"datasheet, font, model, worksheet or other" );
427 Expecting(
"checksum, data or name" );
435 if( !file->compressedEncodedData.empty() )
439 if( !file->Validate() )
441 CurLine(), CurLineNumber(), CurOffset() );
444 aFiles->
AddFile( file.release() );
451 wxFileName cacheFile;
453 auto it =
m_files.find( aName );
459 cacheFile.AppendDir( wxT(
"embed" ) );
463 wxLogTrace( wxT(
"KICAD_EMBED" ),
464 wxT(
"%s:%s:%d\n * failed to create embed cache directory '%s'" ),
465 __FILE__, __FUNCTION__, __LINE__, cacheFile.GetPath() );
467 cacheFile.SetPath( wxFileName::GetTempDir() );
470 wxFileName inputName( aName );
474 cacheFile.SetName(
"kicad_embedded_" + it->second->data_sha );
475 cacheFile.SetExt( inputName.GetExt() );
477 if( cacheFile.FileExists() && cacheFile.IsFileReadable() )
480 wxFFileOutputStream out( cacheFile.GetFullPath() );
488 out.Write( it->second->decompressedData.data(), it->second->decompressedData.size() );
void ParseEmbedded(EMBEDDED_FILES *aFiles)
std::vector< wxString > m_fontFiles
void RemoveFile(const wxString &name, bool aErase=true)
Removes a file from the collection and frees the memory.
wxFileName GetTemporaryFileName(const wxString &aName) const
const std::vector< wxString > * UpdateFontFiles()
Helper function to get a list of fonts for fontconfig to add to the library.
static RETURN_CODE DecompressAndDecode(EMBEDDED_FILE &aFile)
Takes data from the #compressedEncodedData buffer and Base64 decodes it.
bool HasFile(const wxString &name) const
void WriteEmbeddedFiles(OUTPUTFORMATTER &aOut, int aNestLevel, bool aWriteData) const
Output formatter for the embedded files.
void ClearEmbeddedFonts()
Removes all embedded fonts from the collection.
EMBEDDED_FILE * AddFile(const wxFileName &aName, bool aOverwrite)
Loads a file from disk and adds it to the collection.
const std::vector< wxString > * GetFontFiles() const
If we just need the cached version of the font files, we can use this function which is const and wil...
static RETURN_CODE CompressAndEncode(EMBEDDED_FILE &aFile)
Takes data from the #decompressedData buffer and compresses it using ZSTD into the #compressedEncoded...
std::map< wxString, EMBEDDED_FILE * > m_files
static bool EnsurePathExists(const wxString &aPath)
Attempts to create a given path if it does not exist.
static wxString GetUserCachePath()
Gets the stock (install) 3d viewer plugins path.
#define MIME_BASE64_LENGTH
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
std::vector< char > decompressedData
std::string compressedEncodedData