2323#include " DataFile_p.h"
2424#include " SignatureXAdES_LTA.h"
2525#include " XMLDocument.h"
26- #include " crypto/Digest.h"
2726#include " crypto/Signer.h"
2827#include " util/File.h"
2928
3029#include < algorithm>
3130#include < set>
32- #include < sstream>
3331
3432using namespace digidoc ;
3533using namespace digidoc ::util;
@@ -51,21 +49,83 @@ class ASiC_E::Private
5149/* *
5250 * Initialize BDOC container.
5351 */
54- ASiC_E::ASiC_E ()
55- : ASiContainer(MIMETYPE_ASIC_E )
52+ ASiC_E::ASiC_E (const string &path, bool create) try
53+ : ASiContainer(path, MIMETYPE_ASIC_E )
5654 , d(make_unique<Private>())
5755{
58- }
56+ if (create)
57+ return ;
58+ auto z = load (true , {MIMETYPE_ASIC_E , MIMETYPE_ADOC });
59+ auto doc = XMLDocument::open (z.read (" META-INF/manifest.xml" ), {" manifest" , MANIFEST_NS });
60+ doc.validateSchema (File::path (Conf::instance ()->xsdPath (), " OpenDocument_manifest_v1_2.xsd" ));
61+
62+ set<string_view> manifestFiles;
63+ bool mimeFound = false ;
64+ for (auto file = doc/" file-entry" ; file; file++)
65+ {
66+ auto full_path = file[{" full-path" , MANIFEST_NS }];
67+ auto media_type = file[{" media-type" , MANIFEST_NS }];
68+ DEBUG (" full_path = '%.*s', media_type = '%.*s'" , STR_VIEW_FMT (full_path), STR_VIEW_FMT (media_type));
5969
60- /* *
61- * Opens ASiC container from a file
62- */
63- ASiC_E::ASiC_E (const string &path)
64- : ASiContainer(MIMETYPE_ASIC_E )
65- , d(make_unique<Private>())
70+ // ODF does not specify that mimetype should be first in manifest
71+ if (full_path == " /" )
72+ {
73+ if (mimeFound)
74+ THROW (" Manifest multiple entries defined for file '/'." );
75+ if (mediaType () != media_type)
76+ THROW (" Manifest has incorrect container media type defined '%.*s', expecting '%s'." , STR_VIEW_FMT (media_type), mediaType ().c_str ());
77+ mimeFound = true ;
78+ continue ;
79+ }
80+ if (full_path.back () == ' /' ) // Skip Directory entries
81+ continue ;
82+
83+ if (const auto &[pos, inserted] = manifestFiles.insert (full_path); !inserted)
84+ THROW (" Manifest multiple entries defined for file '%.*s'." , STR_VIEW_FMT (full_path));
85+ if (mediaType () == MIMETYPE_ADOC &&
86+ (full_path.starts_with (" META-INF/" ) || full_path.starts_with (" metadata/" )))
87+ d->metadata .push_back (new DataFilePrivate (z, string (full_path), string (media_type)));
88+ else
89+ addDataFilePrivate (new DataFilePrivate (z, string (full_path), string (media_type)));
90+ }
91+ if (!mimeFound)
92+ THROW (" Manifest is missing mediatype file entry." );
93+
94+ for (const string &file: z.list ())
95+ {
96+ /* *
97+ * http://www.etsi.org/deliver/etsi_ts/102900_102999/102918/01.03.01_60/ts_102918v010301p.pdf
98+ * 6.2.2 Contents of Container
99+ * 3) The root element of each "*signatures*.xml" content shall be either:
100+ */
101+ if (file.starts_with (" META-INF/" ) && file.contains (" signatures" ))
102+ {
103+ try
104+ {
105+ loadSignatures (XMLDocument::open (z.read (file)), file);
106+ }
107+ catch (const Exception &e)
108+ {
109+ THROW_CAUSE (e, " Failed to parse signature '%s'." , file.c_str ());
110+ }
111+ continue ;
112+ }
113+
114+ if (file == " mimetype" || file.starts_with (" META-INF" ))
115+ continue ;
116+ if (manifestFiles.erase (file) == 0 )
117+ THROW (" File '%s' found in container is not described in manifest." , file.c_str ());
118+ }
119+ if (!manifestFiles.empty ())
120+ THROW (" Manifest describes files that are not found in container." );
121+ }
122+ catch (const Exception &e)
66123{
67- auto zip = load (path, true , {MIMETYPE_ASIC_E , MIMETYPE_ADOC });
68- parseManifestAndLoadFiles (zip);
124+ THROW_CAUSE (e, " Failed to parse manifest" );
125+ }
126+ catch (...)
127+ {
128+ THROW (" Failed to parse manifest XML: Unknown exception" );
69129}
70130
71131ASiC_E::~ASiC_E ()
@@ -110,9 +170,7 @@ void ASiC_E::save(const ZipSerialize &s)
110170unique_ptr<Container> ASiC_E::createInternal (const string &path)
111171{
112172 DEBUG (" ASiC_E::createInternal(%s)" , path.c_str ());
113- unique_ptr<ASiC_E> doc = unique_ptr<ASiC_E>(new ASiC_E);
114- doc->zpath (path);
115- return doc;
173+ return unique_ptr<Container>(new ASiC_E (path, true ));
116174}
117175
118176/* *
@@ -146,7 +204,7 @@ void ASiC_E::canSave()
146204unique_ptr<Container> ASiC_E::openInternal (const string &path)
147205{
148206 DEBUG (" ASiC_E::openInternal(%s)" , path.c_str ());
149- return unique_ptr<Container>(new ASiC_E (path));
207+ return unique_ptr<Container>(new ASiC_E (path, false ));
150208}
151209
152210void ASiC_E::loadSignatures (XMLDocument &&doc, const string &file)
@@ -157,92 +215,6 @@ void ASiC_E::loadSignatures(XMLDocument &&doc, const string &file)
157215 addSignature (make_unique<SignatureXAdES_LTA>(signatures, s, this ));
158216}
159217
160- /* *
161- * Parses manifest file and checks that files described in manifest exist, also
162- * checks that no extra file do exist that are not described in manifest.xml.
163- *
164- * @param path directory on disk of the BDOC container.
165- * @throws Exception exception is thrown if the manifest.xml file parsing failed.
166- */
167- void ASiC_E::parseManifestAndLoadFiles (const ZipSerialize &z)
168- {
169- DEBUG (" ASiC_E::readManifest()" );
170-
171- try
172- {
173- auto doc = XMLDocument::open (z.read (" META-INF/manifest.xml" ), {" manifest" , MANIFEST_NS });
174- doc.validateSchema (File::path (Conf::instance ()->xsdPath (), " OpenDocument_manifest_v1_2.xsd" ));
175-
176- set<string_view> manifestFiles;
177- bool mimeFound = false ;
178- for (auto file = doc/" file-entry" ; file; file++)
179- {
180- auto full_path = file[{" full-path" , MANIFEST_NS }];
181- auto media_type = file[{" media-type" , MANIFEST_NS }];
182- DEBUG (" full_path = '%s', media_type = '%s'" , full_path.data (), media_type.data ());
183-
184- if (manifestFiles.contains (full_path))
185- THROW (" Manifest multiple entries defined for file '%s'." , full_path.data ());
186-
187- // ODF does not specify that mimetype should be first in manifest
188- if (full_path == " /" )
189- {
190- if (mediaType () != media_type)
191- THROW (" Manifest has incorrect container media type defined '%s', expecting '%s'." , media_type.data (), mediaType ().c_str ());
192- mimeFound = true ;
193- continue ;
194- }
195- if (full_path.back () == ' /' ) // Skip Directory entries
196- continue ;
197-
198- manifestFiles.insert (full_path);
199- if (mediaType () == MIMETYPE_ADOC &&
200- (full_path.starts_with (" META-INF/" ) ||
201- full_path.starts_with (" metadata/" )))
202- d->metadata .push_back (new DataFilePrivate (z, string (full_path), string (media_type)));
203- else
204- addDataFilePrivate (new DataFilePrivate (z, string (full_path), string (media_type)));
205- }
206- if (!mimeFound)
207- THROW (" Manifest is missing mediatype file entry." );
208-
209- for (const string &file: z.list ())
210- {
211- /* *
212- * http://www.etsi.org/deliver/etsi_ts/102900_102999/102918/01.03.01_60/ts_102918v010301p.pdf
213- * 6.2.2 Contents of Container
214- * 3) The root element of each "*signatures*.xml" content shall be either:
215- */
216- if (file.starts_with (" META-INF/" ) &&
217- file.find (" signatures" ) != string::npos)
218- {
219- try
220- {
221- loadSignatures (XMLDocument::open (z.read (file)), file);
222- }
223- catch (const Exception &e)
224- {
225- THROW_CAUSE (e, " Failed to parse signature '%s'." , file.c_str ());
226- }
227- continue ;
228- }
229-
230- if (file == " mimetype" || file.starts_with (" META-INF" ))
231- continue ;
232- if (!manifestFiles.contains (file))
233- THROW (" File '%s' found in container is not described in manifest." , file.c_str ());
234- }
235- }
236- catch (const Exception &e)
237- {
238- THROW_CAUSE (e, " Failed to parse manifest" );
239- }
240- catch (...)
241- {
242- THROW (" Failed to parse manifest XML: Unknown exception" );
243- }
244- }
245-
246218Signature* ASiC_E::prepareSignature (Signer *signer)
247219{
248220 if (mediaType () != MIMETYPE_ASIC_E )
0 commit comments