Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions src/ASiC_E.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ void ASiC_E::addAdESSignature(istream &data)
THROW("'%s' format is not supported", mediaType().c_str());
try
{
loadSignatures(data, d->unique_name());
loadSignatures(XMLDocument::openStream(data), d->unique_name());
}
catch(const Exception &e)
{
Expand All @@ -149,9 +149,9 @@ unique_ptr<Container> ASiC_E::openInternal(const string &path)
return unique_ptr<Container>(new ASiC_E(path));
}

void ASiC_E::loadSignatures(istream &data, const string &file)
void ASiC_E::loadSignatures(XMLDocument &&doc, const string &file)
{
auto signatures = make_shared<Signatures>(data, mediaType());
auto signatures = make_shared<Signatures>(std::move(doc), mediaType());
d->signatures.emplace(file, signatures.get());
for(auto s = signatures->signature(); s; s++)
addSignature(make_unique<SignatureXAdES_LTA>(signatures, s, this));
Expand All @@ -170,8 +170,7 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)

try
{
auto manifestdata = z.extract<stringstream>("META-INF/manifest.xml");
auto doc = XMLDocument::openStream(manifestdata, {"manifest", MANIFEST_NS});
auto doc = XMLDocument::open(z.read("META-INF/manifest.xml"), {"manifest", MANIFEST_NS});
doc.validateSchema(File::path(Conf::instance()->xsdPath(), "OpenDocument_manifest_v1_2.xsd"));

set<string_view> manifestFiles;
Expand All @@ -182,7 +181,7 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)
auto media_type = file[{"media-type", MANIFEST_NS}];
DEBUG("full_path = '%s', media_type = '%s'", full_path.data(), media_type.data());

if(manifestFiles.find(full_path) != manifestFiles.end())
if(manifestFiles.contains(full_path))
THROW("Manifest multiple entries defined for file '%s'.", full_path.data());

// ODF does not specify that mimetype should be first in manifest
Expand All @@ -198,11 +197,11 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)

manifestFiles.insert(full_path);
if(mediaType() == MIMETYPE_ADOC &&
(full_path.compare(0, 9, "META-INF/") == 0 ||
full_path.compare(0, 9, "metadata/") == 0))
d->metadata.push_back(new DataFilePrivate(dataStream(full_path, z), string(full_path), string(media_type)));
(full_path.starts_with("META-INF/") ||
full_path.starts_with("metadata/")))
d->metadata.push_back(new DataFilePrivate(z, string(full_path), string(media_type)));
else
addDataFilePrivate(dataStream(full_path, z), string(full_path), string(media_type));
addDataFilePrivate(new DataFilePrivate(z, string(full_path), string(media_type)));
}
if(!mimeFound)
THROW("Manifest is missing mediatype file entry.");
Expand All @@ -214,13 +213,12 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)
* 6.2.2 Contents of Container
* 3) The root element of each "*signatures*.xml" content shall be either:
*/
if(file.compare(0, 9, "META-INF/") == 0 &&
if(file.starts_with("META-INF/") &&
file.find("signatures") != string::npos)
{
try
{
auto data = z.extract<stringstream>(file);
loadSignatures(data, file);
loadSignatures(XMLDocument::open(z.read(file)), file);
}
catch(const Exception &e)
{
Expand All @@ -229,9 +227,9 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)
continue;
}

if(file == "mimetype" || file.compare(0, 8,"META-INF") == 0)
if(file == "mimetype" || file.starts_with("META-INF"))
continue;
if(manifestFiles.count(file) == 0)
if(!manifestFiles.contains(file))
THROW("File '%s' found in container is not described in manifest.", file.c_str());
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/ASiC_E.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ namespace digidoc
ASiC_E(const std::string &path);
DISABLE_COPY(ASiC_E);
void canSave() final;
void loadSignatures(std::istream &data, const std::string &file);
void loadSignatures(XMLDocument &&doc, const std::string &file);
void parseManifestAndLoadFiles(const ZipSerialize &z);
void save(const ZipSerialize &s) final;

Expand Down
9 changes: 6 additions & 3 deletions src/ASiC_S.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "ASiC_S.h"

#include "DataFile_p.h"
#include "SignatureTST.h"
#include "SignatureXAdES_LTA.h"
#include "crypto/Signer.h"
Expand Down Expand Up @@ -65,8 +66,7 @@ ASiC_S::ASiC_S(const string &path)
{
if(!signatures().empty())
THROW("Can not add signature to ASiC-S container which already contains a signature.");
auto data = z.extract<stringstream>(file);
auto signatures = make_shared<Signatures>(data, mediaType());
auto signatures = make_shared<Signatures>(XMLDocument::open(z.read(file)), mediaType());
for(auto s = signatures->signature(); s; s++)
addSignature(make_unique<SignatureXAdES_LTA>(signatures, s, this));
}
Expand All @@ -78,7 +78,10 @@ ASiC_S::ASiC_S(const string &path)
else if(!dataFiles().empty())
THROW("Can not add document to ASiC-S container which already contains a document.");
else
addDataFile(dataStream(file, z), file, "application/octet-stream");
{
addDataFileChecks(file, "application/octet-stream");
addDataFilePrivate(new DataFilePrivate(z, file, "application/octet-stream"));
}
}
if(foundTimestamp && !foundManifest)
{
Expand Down
48 changes: 3 additions & 45 deletions src/ASiContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ using namespace digidoc;
using namespace digidoc::util;
using namespace std;

constexpr unsigned long MAX_MEM_FILE = 500UL*1024UL*1024UL;

class ASiContainer::Private
{
public:
Expand Down Expand Up @@ -92,7 +90,7 @@ ZipSerialize ASiContainer::load(const string &path, bool mimetypeRequired, const

if(list.front() == "mimetype")
{
d->mimetype = readMimetype(z);
d->mimetype = z.mimetype();
if(!contains(supported, d->mimetype))
THROW("Incorrect mimetype '%s'", d->mimetype.c_str());
}
Expand Down Expand Up @@ -139,23 +137,6 @@ vector<Signature *> ASiContainer::signatures() const
return d->signatures;
}

/**
* <p>
* Read a datafile from container.
* </p>
* If expected size of the data is too big, then stream is written to temp file.
*
* @param path name of the file in zip container stream is used to read from.
* @param z Zip container.
* @return returns data as a stream.
*/
unique_ptr<iostream> ASiContainer::dataStream(string_view path, const ZipSerialize &z) const
{
if(auto i = d->properties.find(path); i != d->properties.cend() && i->second.size > MAX_MEM_FILE)
return make_unique<fstream>(z.extract<fstream>(path));
return make_unique<stringstream>(z.extract<stringstream>(path));
}

/**
* Adds document to the container. Documents can be removed from container only
* after all signatures are removed.
Expand Down Expand Up @@ -208,9 +189,9 @@ void ASiContainer::addDataFileChecks(const string &fileName, const string &media
THROW("MediaType does not meet format requirements (RFC2045, section 5.1) '%s'.", mediaType.c_str());
}

void ASiContainer::addDataFilePrivate(unique_ptr<istream> is, string fileName, string mediaType)
void ASiContainer::addDataFilePrivate(DataFile *dataFile)
{
d->documents.push_back(new DataFilePrivate(std::move(is), std::move(fileName), std::move(mediaType)));
d->documents.push_back(dataFile);
}

/**
Expand Down Expand Up @@ -304,26 +285,3 @@ const ZipSerialize::Properties& ASiContainer::zproperty(string_view file) const
return i->second;
return d->properties[string(file)] = { appInfo(), time(nullptr), 0 };
}

/**
* Reads and parses container mimetype. Checks that the mimetype is supported.
*
* @param path path to container directory.
* @throws IOException exception is thrown if there was error reading mimetype file from disk.
* @throws ContainerException exception is thrown if the parsed mimetype is incorrect.
*/
string ASiContainer::readMimetype(const ZipSerialize &z)
{
DEBUG("ASiContainer::readMimetype()");
string text = z.extract<stringstream>("mimetype").str();
text.erase(text.find_last_not_of(" \n\r\f\t\v") + 1);
if(text.empty())
THROW("Failed to read mimetype.");
// Contains UTF-16 BOM
if(text.find("\xFF\xEF") == 0 || text.find("\xEF\xFF") == 0)
THROW("Mimetype file must be UTF-8 format.");
// contains UTF-8 BOM, remove
if(text.find("\xEF\xBB\xBF") == 0)
text.erase(text.cbegin(), text.cbegin() + 3);
return text;
}
5 changes: 1 addition & 4 deletions src/ASiContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,14 @@ namespace digidoc
void save(const std::string &path) override;
std::vector<Signature*> signatures() const override;

static std::string readMimetype(const ZipSerialize &z);

protected:
ASiContainer(std::string_view mimetype);

virtual void addDataFileChecks(const std::string &path, const std::string &mediaType);
void addDataFilePrivate(std::unique_ptr<std::istream> is, std::string fileName, std::string mediaType);
void addDataFilePrivate(DataFile *dataFile);
Signature* addSignature(std::unique_ptr<Signature> &&signature);
virtual void canSave() = 0;
XMLDocument createManifest() const;
std::unique_ptr<std::iostream> dataStream(std::string_view path, const ZipSerialize &z) const;
ZipSerialize load(const std::string &path, bool requireMimetype, const std::set<std::string_view> &supported);
virtual void save(const ZipSerialize &s) = 0;
void deleteSignature(Signature* s);
Expand Down
29 changes: 28 additions & 1 deletion src/DataFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@
#include "crypto/Digest.h"
#include "util/File.h"
#include "util/log.h"
#include "util/ZipSerialize.h"

#include <array>
#include <fstream>
#include <sstream>

using namespace digidoc;
using namespace digidoc::util;
using namespace std;


/**
* @class digidoc::DataFile
*
Expand Down Expand Up @@ -96,6 +98,31 @@ DataFilePrivate::DataFilePrivate(unique_ptr<istream> &&is, string filename, stri
{
}

DataFilePrivate::DataFilePrivate(const ZipSerialize &z, string filename, string mediatype)
: d(make_unique<Private>())
, m_filename(std::move(filename))
, m_mediatype(std::move(mediatype))
{
auto r = z.read(m_filename);
d->size.emplace(r.size);
if(r.size > MAX_MEM_FILE)
{
auto fs = make_unique<fstream>(util::File::tempFileName(), fstream::in|fstream::out|fstream::binary|fstream::trunc);
if(!fs->is_open())
THROW("Failed to open destination file");
array<char,10240> buf{};
for(size_t size = 0, currentStreamSize = 0;
(size = r(buf.data(), buf.size())) > 0; currentStreamSize += size)
{
if(!fs->write(buf.data(), size))
THROW("Failed to write '%s' data to stream. Stream size: %d", m_filename.c_str(), currentStreamSize);
}
m_is = std::move(fs);
}
else
m_is = make_unique<stringstream>(r.operator string());
}

void DataFilePrivate::digest(const Digest &digest) const
{
m_is->clear();
Expand Down
5 changes: 5 additions & 0 deletions src/DataFile_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,17 @@

namespace digidoc
{

constexpr unsigned long MAX_MEM_FILE = 500UL*1024UL*1024UL;

class Digest;
class ZipSerialize;

class DataFilePrivate final: public DataFile
{
public:
DataFilePrivate(std::unique_ptr<std::istream> &&is, std::string filename, std::string mediatype, std::string id = {});
DataFilePrivate(const ZipSerialize &z, std::string filename, std::string mediatype);

std::string id() const final { return m_id.empty() ? m_filename : m_id; }
std::string fileName() const final { return m_filename; }
Expand Down
Loading