1//
2// ZipArchive.cpp
3//
4// Library: Zip
5// Package: Zip
6// Module: ZipArchive
7//
8// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Zip/ZipArchive.h"
16#include "Poco/Zip/SkipCallback.h"
17#include "Poco/Exception.h"
18#include <cstring>
19
20
21namespace Poco {
22namespace Zip {
23
24
25const std::string ZipArchive::EMPTY_COMMENT;
26
27
28ZipArchive::ZipArchive(std::istream& in):
29 _entries(),
30 _infos(),
31 _disks(),
32 _disks64()
33{
34 poco_assert_dbg (in);
35 SkipCallback skip;
36 parse(in, skip);
37}
38
39
40ZipArchive::ZipArchive(const FileHeaders& entries, const FileInfos& infos, const DirectoryInfos& dirs, const DirectoryInfos64& dirs64):
41 _entries(entries),
42 _infos(infos),
43 _disks(dirs),
44 _disks64(dirs64)
45{
46}
47
48
49ZipArchive::ZipArchive(std::istream& in, ParseCallback& pc):
50 _entries(),
51 _infos(),
52 _disks(),
53 _disks64()
54{
55 poco_assert_dbg (in);
56 parse(in, pc);
57}
58
59
60ZipArchive::~ZipArchive()
61{
62}
63
64
65void ZipArchive::parse(std::istream& in, ParseCallback& pc)
66{
67 // read 4 bytes
68 bool haveSynced = false;
69 while (in.good() && !in.eof())
70 {
71 char header[ZipCommon::HEADER_SIZE]={'\x00', '\x00', '\x00', '\x00'};
72 in.read(header, ZipCommon::HEADER_SIZE);
73 if (in.eof())
74 return;
75 if (std::memcmp(header, ZipLocalFileHeader::HEADER, ZipCommon::HEADER_SIZE) == 0)
76 {
77 ZipLocalFileHeader entry(in, true, pc);
78 poco_assert (_entries.insert(std::make_pair(entry.getFileName(), entry)).second);
79 haveSynced = false;
80 }
81 else if (std::memcmp(header, ZipFileInfo::HEADER, ZipCommon::HEADER_SIZE) == 0)
82 {
83 ZipFileInfo info(in, true);
84 FileHeaders::iterator it = _entries.find(info.getFileName());
85 if (it != _entries.end())
86 {
87 it->second.setStartPos(info.getOffset());
88 }
89 poco_assert (_infos.insert(std::make_pair(info.getFileName(), info)).second);
90 haveSynced = false;
91 }
92 else if (std::memcmp(header, ZipArchiveInfo::HEADER, ZipCommon::HEADER_SIZE) == 0)
93 {
94 ZipArchiveInfo nfo(in, true);
95 poco_assert (_disks.insert(std::make_pair(nfo.getDiskNumber(), nfo)).second);
96 haveSynced = false;
97 }
98 else if (std::memcmp(header, ZipArchiveInfo64::HEADER, ZipCommon::HEADER_SIZE) == 0)
99 {
100 ZipArchiveInfo64 nfo(in, true);
101 poco_assert (_disks64.insert(std::make_pair(nfo.getDiskNumber(), nfo)).second);
102 haveSynced = false;
103 }
104 else
105 {
106 if (!haveSynced)
107 {
108 // Some Zip files have extra data behind the ZipLocalFileHeader.
109 // Try to re-sync.
110 ZipUtil::sync(in);
111 haveSynced = true;
112 }
113 else
114 {
115 if (_disks.empty() && _disks64.empty())
116 throw Poco::IllegalStateException("Illegal header in zip file");
117 else
118 throw Poco::IllegalStateException("Garbage after directory header");
119 }
120 }
121 }
122}
123
124
125const std::string& ZipArchive::getZipComment() const
126{
127 // It seems that only the "first" disk is populated (look at Compress::close()), so getting the first ZipArchiveInfo
128 DirectoryInfos::const_iterator it = _disks.begin();
129 if (it != _disks.end())
130 {
131 return it->second.getZipComment();
132 }
133 else
134 {
135 DirectoryInfos64::const_iterator it64 = _disks64.begin();
136 if (it64 != _disks64.end())
137 return it->second.getZipComment();
138 else
139 return EMPTY_COMMENT;
140 }
141}
142
143
144} } // namespace Poco::Zip
145