Skip to content

Commit 4d8ef4b

Browse files
committed
ZIP Streaming
IB-7625 Signed-off-by: Raul Metsma <[email protected]>
1 parent 0cafa3f commit 4d8ef4b

File tree

11 files changed

+145
-89
lines changed

11 files changed

+145
-89
lines changed

src/ASiC_E.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ ASiC_E::ASiC_E(const string &path)
6767
: ASiContainer(MIMETYPE_ASIC_E)
6868
, d(make_unique<Private>())
6969
{
70-
auto zip = load(path, true, {MIMETYPE_ASIC_E, MIMETYPE_ADOC});
70+
auto *zip = load(path, true, {MIMETYPE_ASIC_E, MIMETYPE_ADOC});
7171
parseManifestAndLoadFiles(*zip);
7272
}
7373

@@ -229,12 +229,11 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)
229229

230230
try
231231
{
232-
stringstream manifestdata;
233-
z.extract("META-INF/manifest.xml", manifestdata);
232+
unique_ptr<istream> manifestdata = z.stream("META-INF/manifest.xml");
234233
xml_schema::Properties p;
235234
p.schema_location(ASiC_E::MANIFEST_NAMESPACE,
236235
File::fullPathUrl(Conf::instance()->xsdPath() + "/OpenDocument_manifest.xsd"));
237-
unique_ptr<xercesc::DOMDocument> doc = SecureDOMParser(p.schema_location(), true).parseIStream(manifestdata);
236+
unique_ptr<xercesc::DOMDocument> doc = SecureDOMParser(p.schema_location(), true).parseIStream(*manifestdata);
238237
unique_ptr<manifest::Manifest> manifest = manifest::manifest(*doc, {}, p);
239238

240239
set<string> manifestFiles;
@@ -267,9 +266,9 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)
267266
if(mediaType() == MIMETYPE_ADOC &&
268267
(file.full_path().compare(0, 9, "META-INF/") == 0 ||
269268
file.full_path().compare(0, 9, "metadata/") == 0))
270-
d->metadata.push_back(new DataFilePrivate(dataStream(file.full_path(), z), file.full_path(), file.media_type()));
269+
d->metadata.push_back(dataFile(file.full_path(), file.media_type()));
271270
else
272-
addDataFilePrivate(dataStream(file.full_path(), z), file.full_path(), file.media_type());
271+
addDataFilePrivate(file.full_path(), file.media_type());
273272
}
274273
if(!mimeFound)
275274
THROW("Manifest is missing mediatype file entry.");
@@ -288,9 +287,7 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)
288287
THROW("Multiple signature files with same name found '%s'", file.c_str());
289288
try
290289
{
291-
stringstream data;
292-
z.extract(file, data);
293-
auto signatures = make_shared<Signatures>(data, this);
290+
auto signatures = make_shared<Signatures>(*z.stream(file), this);
294291
for(size_t i = 0, count = signatures->count(); i < count; ++i)
295292
addSignature(make_unique<SignatureXAdES_LTA>(signatures, i, this));
296293
}

src/ASiC_S.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ ASiC_S::ASiC_S(): ASiContainer(MIMETYPE_ASIC_S)
4343
*/
4444
ASiC_S::ASiC_S(const string &path): ASiContainer(MIMETYPE_ASIC_S)
4545
{
46-
auto z = load(path, false, {mediaType()});
46+
auto *z = load(path, false, {mediaType()});
4747
static const string_view metaInf = "META-INF/";
4848

4949
for(const string &file: z->list())
@@ -55,17 +55,13 @@ ASiC_S::ASiC_S(const string &path): ASiContainer(MIMETYPE_ASIC_S)
5555
{
5656
if(!signatures().empty())
5757
THROW("Can not add signature to ASiC-S container which already contains a signature.");
58-
stringstream data;
59-
z->extract(file, data);
60-
addSignature(make_unique<SignatureTST>(data, this));
58+
addSignature(make_unique<SignatureTST>(*z->stream(file), this));
6159
}
6260
if(file == "META-INF/signatures.xml")
6361
{
6462
if(!signatures().empty())
6563
THROW("Can not add signature to ASiC-S container which already contains a signature.");
66-
stringstream data;
67-
z->extract(file, data);
68-
auto signatures = make_shared<Signatures>(data, this);
64+
auto signatures = make_shared<Signatures>(*z->stream(file), this);
6965
for(size_t i = 0, count = signatures->count(); i < count; ++i)
7066
addSignature(make_unique<SignatureXAdES_LTA>(signatures, i, this));
7167
}
@@ -77,7 +73,7 @@ ASiC_S::ASiC_S(const string &path): ASiContainer(MIMETYPE_ASIC_S)
7773
{
7874
if(!dataFiles().empty())
7975
THROW("Can not add document to ASiC-S container which already contains a document.");
80-
addDataFile(dataStream(file, *z), file, "application/octet-stream");
76+
addDataFilePrivate(file, "application/octet-stream");
8177
}
8278
}
8379

src/ASiContainer.cpp

Lines changed: 23 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class ASiContainer::Private
4646
vector<DataFile*> documents;
4747
vector<Signature*> signatures;
4848
map<string, ZipSerialize::Properties> properties;
49+
unique_ptr<ZipSerialize> z;
4950
};
5051

5152
const string_view ASiContainer::ASICE_EXTENSION = "asice";
@@ -76,12 +77,12 @@ ASiContainer::ASiContainer(const string &mimetype)
7677
* @param supported supported mimetypes.
7778
* @return returns zip serializer for the container.
7879
*/
79-
unique_ptr<ZipSerialize> ASiContainer::load(const string &path, bool mimetypeRequired, const set<string> &supported)
80+
ZipSerialize* ASiContainer::load(const string &path, bool mimetypeRequired, const set<string> &supported)
8081
{
8182
DEBUG("ASiContainer::ASiContainer(path = '%s')", path.c_str());
82-
auto z = make_unique<ZipSerialize>(d->path = path, false);
83+
d->z = make_unique<ZipSerialize>(d->path = path, false);
8384

84-
vector<string> list = z->list();
85+
vector<string> list = d->z->list();
8586
if(list.empty())
8687
THROW("Failed to parse container");
8788

@@ -91,16 +92,16 @@ unique_ptr<ZipSerialize> ASiContainer::load(const string &path, bool mimetypeReq
9192
// ETSI TS 102 918: mimetype has to be the first in the archive
9293
if(list.front() == "mimetype")
9394
{
94-
d->mimetype = readMimetype(*z);
95+
d->mimetype = readMimetype(*d->z);
9596
DEBUG("mimetype = '%s'", d->mimetype.c_str());
9697
if(supported.find(d->mimetype) == supported.cend())
9798
THROW("Incorrect mimetype '%s'", d->mimetype.c_str());
9899
}
99100

100101
for(const string &file: list)
101-
d->properties[file] = z->properties(file);
102+
d->properties[file] = d->z->properties(file);
102103

103-
return z;
104+
return d->z.get();
104105
}
105106

106107
string ASiContainer::mediaType() const
@@ -138,25 +139,9 @@ vector<Signature *> ASiContainer::signatures() const
138139
return d->signatures;
139140
}
140141

141-
/**
142-
* <p>
143-
* Read a datafile from container.
144-
* </p>
145-
* If expected size of the data is too big, then stream is written to temp file.
146-
*
147-
* @param path name of the file in zip container stream is used to read from.
148-
* @param z Zip container.
149-
* @return returns data as a stream.
150-
*/
151-
unique_ptr<iostream> ASiContainer::dataStream(const string &path, const ZipSerialize &z) const
142+
DataFilePrivate* ASiContainer::dataFile(const std::string &path, const std::string &mediaType) const
152143
{
153-
unique_ptr<iostream> data;
154-
if(d->properties[path].size > MAX_MEM_FILE)
155-
data = make_unique<fstream>(File::encodeName(File::tempFileName()), fstream::in|fstream::out|fstream::binary|fstream::trunc);
156-
else
157-
data = make_unique<stringstream>();
158-
z.extract(path, *data);
159-
return data;
144+
return new DataFilePrivate(d->z->stream(path), path, mediaType, d->properties[path].size);
160145
}
161146

162147
/**
@@ -191,15 +176,16 @@ void ASiContainer::addDataFile(const string &path, const string &mediaType)
191176
*data << file.rdbuf();
192177
is = std::move(data);
193178
}
194-
addDataFilePrivate(std::move(is), fileName, mediaType);
179+
d->documents.push_back(new DataFilePrivate(std::move(is), fileName, mediaType, prop.size));
195180
}
196181

197182
void ASiContainer::addDataFile(unique_ptr<istream> is, const string &fileName, const string &mediaType)
198183
{
199184
addDataFileChecks(fileName, mediaType);
200185
if(fileName.find_last_of("/\\") != string::npos)
201186
THROW("Document file '%s' cannot contain directory path.", fileName.c_str());
202-
addDataFilePrivate(std::move(is), fileName, mediaType);
187+
istream::pos_type pos = is->tellg();
188+
d->documents.push_back(new DataFilePrivate(std::move(is), fileName, mediaType, pos < 0 ? 0 : (unsigned long)pos));
203189
}
204190

205191
void ASiContainer::addDataFileChecks(const string &fileName, const string &mediaType)
@@ -214,9 +200,9 @@ void ASiContainer::addDataFileChecks(const string &fileName, const string &media
214200
THROW("MediaType does not meet format requirements (RFC2045, section 5.1) '%s'.", mediaType.c_str());
215201
}
216202

217-
void ASiContainer::addDataFilePrivate(unique_ptr<istream> is, const string &fileName, const string &mediaType)
203+
void ASiContainer::addDataFilePrivate(const string &fileName, const string &mediaType)
218204
{
219-
d->documents.push_back(new DataFilePrivate(std::move(is), fileName, mediaType));
205+
d->documents.push_back(dataFile(fileName, mediaType));
220206
}
221207

222208
/**
@@ -298,23 +284,17 @@ void ASiContainer::zproperty(const string &file, ZipSerialize::Properties &&prop
298284
string ASiContainer::readMimetype(const ZipSerialize &z)
299285
{
300286
DEBUG("ASiContainer::readMimetype()");
301-
stringstream is;
302-
z.extract("mimetype", is);
303-
304-
array<unsigned char,3> bom{};
305-
is.read((char*)bom.data(), bom.size());
287+
auto is = z.stream("mimetype");
288+
string text;
289+
*is >> text;
290+
if(!is)
291+
THROW("Failed to read mimetype.");
306292
// Contains UTF-16 BOM
307-
if((bom[0] == 0xFF && bom[1] == 0xEF) ||
308-
(bom[0] == 0xEF && bom[1] == 0xFF))
293+
if((text[0] == 0xFF && text[1] == 0xEF) ||
294+
(text[0] == 0xEF && text[1] == 0xFF))
309295
THROW("Mimetype file must be UTF-8 format.");
310296
// does not contain UTF-8 BOM reset pos
311-
if(bom[0] != 0xEF || bom[1] != 0xBB || bom[2] != 0xBF)
312-
is.seekg(0, ios::beg);
313-
314-
string text;
315-
is >> text;
316-
if(is.fail())
317-
THROW("Failed to read mimetype.");
318-
297+
if(text[0] == 0xEF && text[1] == 0xBB && text[2] != 0xBF)
298+
text.erase(text.cbegin(), text.cbegin() + 3);
319299
return text;
320300
}

src/ASiContainer.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
namespace digidoc
2828
{
29+
class DataFilePrivate;
2930
/**
3031
* Base class for the ASiC (Associated Signature Container) documents.
3132
* Implements the operations and data structures common for more specific ASiC
@@ -61,10 +62,10 @@ namespace digidoc
6162
protected:
6263
ASiContainer(const std::string &mimetype);
6364

64-
void addDataFilePrivate(std::unique_ptr<std::istream> is, const std::string &fileName, const std::string &mediaType);
65+
void addDataFilePrivate(const std::string &fileName, const std::string &mediaType);
6566
Signature* addSignature(std::unique_ptr<Signature> &&signature);
66-
std::unique_ptr<std::iostream> dataStream(const std::string &path, const ZipSerialize &z) const;
67-
std::unique_ptr<ZipSerialize> load(const std::string &path, bool requireMimetype, const std::set<std::string> &supported);
67+
DataFilePrivate *dataFile(const std::string &path, const std::string &mediaType) const;
68+
ZipSerialize* load(const std::string &path, bool requireMimetype, const std::set<std::string> &supported);
6869
void deleteSignature(Signature* s);
6970

7071
void zpath(const std::string &file);

src/DataFile.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,13 @@ DataFile::DataFile() = default;
8787
DataFile::~DataFile() = default;
8888

8989

90-
DataFilePrivate::DataFilePrivate(unique_ptr<istream> &&is, string filename, string mediatype, string id)
90+
DataFilePrivate::DataFilePrivate(unique_ptr<istream> &&is, string filename, string mediatype, unsigned long size, string id)
9191
: m_is(std::move(is))
9292
, m_id(std::move(id))
9393
, m_filename(std::move(filename))
9494
, m_mediatype(std::move(mediatype))
95-
{
96-
m_is->seekg(0, istream::end);
97-
istream::pos_type pos = m_is->tellg();
98-
m_size = pos < 0 ? 0 : (unsigned long)pos;
99-
}
95+
, m_size(size)
96+
{}
10097

10198
vector<unsigned char> DataFilePrivate::calcDigest(const string &method) const
10299
{

src/DataFile_p.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace digidoc
3030
class DataFilePrivate final: public DataFile
3131
{
3232
public:
33-
DataFilePrivate(std::unique_ptr<std::istream> &&is, std::string filename, std::string mediatype, std::string id = {});
33+
DataFilePrivate(std::unique_ptr<std::istream> &&is, std::string filename, std::string mediatype, unsigned long size, std::string id = {});
3434

3535
std::string id() const final { return m_id.empty() ? m_filename : m_id; }
3636
std::string fileName() const final { return m_filename; }

src/SiVaContainer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ SiVaContainer::SiVaContainer(const string &path, const string &ext, bool useHash
159159
else
160160
{
161161
d->mediaType = "application/pdf";
162-
d->dataFiles.push_back(new DataFilePrivate(std::move(ifs), fileName, "application/pdf"));
162+
d->dataFiles.push_back(new DataFilePrivate(std::move(ifs), fileName, "application/pdf", File::fileSize(d->path)));
163163
}
164164

165165
array<XMLByte, 48*100> buf{};
@@ -351,6 +351,7 @@ unique_ptr<istream> SiVaContainer::parseDDoc(bool useHashCode)
351351
d->dataFiles.push_back(new DataFilePrivate(make_unique<stringstream>(base64_decode(b64)),
352352
xml::transcode<char>(item->getAttribute(cpXMLCh(u"Filename"))),
353353
xml::transcode<char>(item->getAttribute(cpXMLCh(u"MimeType"))),
354+
0,
354355
xml::transcode<char>(item->getAttribute(cpXMLCh(u"Id")))));
355356
}
356357

src/SignatureTST.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,16 @@
2626
#include "util/DateTime.h"
2727
#include "util/log.h"
2828

29+
#include <sstream>
30+
2931
using namespace digidoc;
3032
using namespace std;
3133

3234
SignatureTST::SignatureTST(istream &is, ASiC_S *asicSDoc): asicSDoc(asicSDoc)
3335
{
34-
is.seekg(0, istream::end);
35-
istream::pos_type pos = is.tellg();
36-
const auto size = pos < 0 ? 0 : (unsigned long)pos;
37-
is.clear();
38-
is.seekg(0, istream::beg);
39-
40-
vector<unsigned char> buf(size, 0);
41-
is.read((char*)buf.data(), streamsize(buf.size()));
42-
43-
timestampToken = make_unique<TS>(buf.data(), buf.size());
36+
stringstream data;
37+
data << is.rdbuf();
38+
timestampToken = make_unique<TS>(data.str());
4439
}
4540

4641
SignatureTST::~SignatureTST() = default;

src/crypto/TS.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class TS
3131
{
3232
public:
3333
TS(const std::string &url, const Digest &digest);
34+
template <class Container>
35+
inline TS(const Container &data): TS((const unsigned char*)data.data(), data.size()) {}
3436
TS(const unsigned char *data = nullptr, size_t size = 0);
3537

3638
X509Cert cert() const;

0 commit comments

Comments
 (0)