You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

279 lines
7.8 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software: you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation, either version 3 of the License, or (at your
  9. * option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #pragma once
  20. #include <map>
  21. #include <set>
  22. #include <wx/string.h>
  23. #include <wx/filename.h>
  24. #include <mmh3_hash.h>
  25. #include <picosha2.h>
  26. #include <wildcards_and_files_ext.h>
  27. #include <functional>
  28. class OUTPUTFORMATTER;
  29. namespace KIFONT
  30. {
  31. class OUTLINE_FONT;
  32. }
  33. class EMBEDDED_FILES
  34. {
  35. public:
  36. struct EMBEDDED_FILE
  37. {
  38. enum class FILE_TYPE
  39. {
  40. FONT,
  41. MODEL,
  42. WORKSHEET,
  43. DATASHEET,
  44. OTHER
  45. };
  46. EMBEDDED_FILE() :
  47. type( FILE_TYPE::OTHER ),
  48. is_valid( false )
  49. {}
  50. bool Validate()
  51. {
  52. MMH3_HASH hash( EMBEDDED_FILES::Seed() );
  53. hash.add( decompressedData );
  54. is_valid = ( hash.digest().ToString() == data_hash );
  55. return is_valid;
  56. }
  57. // This is the old way of validating the file. It is deprecated and retained only
  58. // to validate files that were previously embedded.
  59. bool Validate_SHA256()
  60. {
  61. std::string new_sha;
  62. picosha2::hash256_hex_string( decompressedData, new_sha );
  63. is_valid = ( new_sha == data_hash );
  64. return is_valid;
  65. }
  66. wxString GetLink() const
  67. {
  68. return wxString::Format( "%s://%s", FILEEXT::KiCadUriPrefix, name );
  69. }
  70. wxString name;
  71. FILE_TYPE type;
  72. bool is_valid;
  73. std::string compressedEncodedData;
  74. std::vector<char> decompressedData;
  75. std::string data_hash;
  76. };
  77. enum class RETURN_CODE : int
  78. {
  79. OK, ///< Success.
  80. FILE_NOT_FOUND, ///< File not found on disk.
  81. PERMISSIONS_ERROR, ///< Could not read/write file.
  82. FILE_ALREADY_EXISTS, ///< File already exists in the collection.
  83. OUT_OF_MEMORY, ///< Could not allocate memory.
  84. CHECKSUM_ERROR, ///< Checksum in file does not match data.
  85. };
  86. EMBEDDED_FILES() = default;
  87. EMBEDDED_FILES( EMBEDDED_FILES&& other ) noexcept;
  88. EMBEDDED_FILES( const EMBEDDED_FILES& other );
  89. ~EMBEDDED_FILES()
  90. {
  91. for( auto& file : m_files )
  92. delete file.second;
  93. }
  94. using FileAddedCallback = std::function<void(EMBEDDED_FILE*)>;
  95. void SetFileAddedCallback(FileAddedCallback callback)
  96. {
  97. m_fileAddedCallback = callback;
  98. }
  99. FileAddedCallback GetFileAddedCallback() const
  100. {
  101. return m_fileAddedCallback;
  102. }
  103. /**
  104. * Load a file from disk and adds it to the collection.
  105. *
  106. * @param aName is the name of the file to load.
  107. * @param aOverwrite is true if the file should be overwritten if it already exists.
  108. */
  109. EMBEDDED_FILE* AddFile( const wxFileName& aName, bool aOverwrite );
  110. /**
  111. * Append a file to the collection.
  112. */
  113. void AddFile( EMBEDDED_FILE* aFile );
  114. /**
  115. * Remove a file from the collection and frees the memory.
  116. *
  117. * @param aName is the name of the file to remove.
  118. */
  119. void RemoveFile( const wxString& name, bool aErase = true );
  120. /**
  121. * Output formatter for the embedded files.
  122. *
  123. * @param aOut is the output formatter.
  124. * @param aWriteData is true if the actual data should be written. This is false when writing
  125. * an element that is already embedded in a file that itself has embedded
  126. * files (boards, schematics, etc.).
  127. */
  128. void WriteEmbeddedFiles( OUTPUTFORMATTER& aOut, bool aWriteData ) const;
  129. /**
  130. * Return the link for an embedded file.
  131. *
  132. * @param aFile is the file to get the link for.
  133. * @return the link for the file to be used in a hyperlink.
  134. */
  135. wxString GetEmbeddedFileLink( const EMBEDDED_FILE& aFile ) const
  136. {
  137. return aFile.GetLink();
  138. }
  139. bool HasFile( const wxString& name ) const
  140. {
  141. wxFileName fileName( name );
  142. return m_files.find( fileName.GetFullName() ) != m_files.end();
  143. }
  144. bool IsEmpty() const
  145. {
  146. return m_files.empty();
  147. }
  148. /**
  149. * Helper function to get a list of fonts for fontconfig to add to the library.
  150. *
  151. * This is necessary because EMBEDDED_FILES lives in common at the moment and
  152. * fontconfig is in libkicommon. This will create the cache files in the KiCad
  153. * cache directory (if they do not already exist) and return the temp files names
  154. */
  155. const std::vector<wxString>* UpdateFontFiles();
  156. /**
  157. * If we just need the cached version of the font files, we can use this function which
  158. * is const and will not update the font files.
  159. */
  160. const std::vector<wxString>* GetFontFiles() const;
  161. /**
  162. * Remove all embedded fonts from the collection.
  163. */
  164. void ClearEmbeddedFonts();
  165. /**
  166. * Take data from the #decompressedData buffer and compresses it using ZSTD
  167. * into the #compressedEncodedData buffer.
  168. *
  169. * The data is then Base64 encoded. This call is used when adding a new file to the
  170. * collection from disk.
  171. */
  172. static RETURN_CODE CompressAndEncode( EMBEDDED_FILE& aFile );
  173. /**
  174. * Takes data from the #compressedEncodedData buffer and Base64 decodes it.
  175. *
  176. * The data is then decompressed using ZSTD and stored in the #decompressedData buffer.
  177. * This call is used when loading the embedded files using the parsers.
  178. */
  179. static RETURN_CODE DecompressAndDecode( EMBEDDED_FILE& aFile );
  180. /**
  181. * Returns the embedded file with the given name or nullptr if it does not exist.
  182. */
  183. EMBEDDED_FILE* GetEmbeddedFile( const wxString& aName ) const
  184. {
  185. auto it = m_files.find( aName );
  186. return it == m_files.end() ? nullptr : it->second;
  187. }
  188. const std::map<wxString, EMBEDDED_FILE*>& EmbeddedFileMap() const
  189. {
  190. return m_files;
  191. }
  192. wxFileName GetTemporaryFileName( const wxString& aName ) const;
  193. wxFileName GetTemporaryFileName( EMBEDDED_FILE* aFile ) const;
  194. void ClearEmbeddedFiles( bool aDeleteFiles = true )
  195. {
  196. for( auto& file : m_files )
  197. {
  198. if( aDeleteFiles )
  199. delete file.second;
  200. }
  201. m_files.clear();
  202. }
  203. virtual void EmbedFonts() {};
  204. virtual std::set<KIFONT::OUTLINE_FONT*> GetFonts() const
  205. {
  206. return std::set<KIFONT::OUTLINE_FONT*>();
  207. };
  208. void SetAreFontsEmbedded( bool aEmbedFonts )
  209. {
  210. m_embedFonts = aEmbedFonts;
  211. }
  212. bool GetAreFontsEmbedded() const
  213. {
  214. return m_embedFonts;
  215. }
  216. static uint32_t Seed()
  217. {
  218. return 0xABBA2345;
  219. }
  220. EMBEDDED_FILES& operator=(EMBEDDED_FILES&& other) noexcept;
  221. EMBEDDED_FILES& operator=( const EMBEDDED_FILES& other );
  222. private:
  223. std::map<wxString, EMBEDDED_FILE*> m_files;
  224. std::vector<wxString> m_fontFiles;
  225. FileAddedCallback m_fileAddedCallback;
  226. protected:
  227. bool m_embedFonts = false; ///< If set, fonts will be embedded in the element on save.
  228. ///< Otherwise, font files embedded in the element will be
  229. ///< removed on save.
  230. };