FreeCAD

Форк
0
/
ZipHeader.cpp 
187 строк · 6.1 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2022 Werner Mayer <wmayer[at]users.sourceforge.net>     *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23

24
#include "PreCompiled.h"
25

26
#include "ZipHeader.h"
27
#include <zipios++/zipinputstream.h>
28

29
using zipios::ConstEntryPointer;
30
using zipios::FileCollection;
31
using zipios::ZipHeader;
32

33

34
ZipHeader::ZipHeader(std::istream& inp, int s_off, int e_off)
35
    : _input(inp)
36
    , _vs(s_off, e_off)
37
{
38
    init(_input);
39
}
40

41
/** Create a copy of this instance. */
42
FileCollection* ZipHeader::clone() const
43
{
44
    return new ZipHeader(*this);
45
}
46

47
void ZipHeader::close()
48
{
49
    _valid = false;
50
}
51

52
std::istream* ZipHeader::getInputStream(const ConstEntryPointer& entry)
53
{
54
    if (!_valid) {
55
        throw zipios::InvalidStateException("Attempt to use an invalid FileCollection");
56
    }
57
    return getInputStream(entry->getName());
58
}
59

60
std::istream* ZipHeader::getInputStream(const std::string& entry_name, MatchPath matchpath)
61
{
62
    if (!_valid) {
63
        throw zipios::InvalidStateException("Attempt to use an invalid ZipHeader");
64
    }
65

66
    zipios::ConstEntryPointer ent = getEntry(entry_name, matchpath);
67

68
    if (!ent) {
69
        return nullptr;
70
    }
71

72
    return new zipios::ZipInputStream(
73
        _input,
74
        static_cast<const zipios::ZipCDirEntry*>(ent.get())->getLocalHeaderOffset()
75
            + _vs.startOffset());
76
}
77

78
bool ZipHeader::init(std::istream& _zipfile)
79
{
80
    // Check stream error state
81
    if (!_zipfile) {
82
        setError("Error reading from file");
83
        return false;
84
    }
85

86
    _valid = readCentralDirectory(_zipfile);
87
    return _valid;
88
}
89

90
bool ZipHeader::readCentralDirectory(std::istream& _zipfile)
91
{
92
    // Find and read eocd.
93
    if (!readEndOfCentralDirectory(_zipfile)) {
94
        throw zipios::FCollException("Unable to find zip structure: End-of-central-directory");
95
    }
96

97
    // Position read pointer to start of first entry in central dir.
98
    _vs.vseekg(_zipfile, _eocd.offset(), std::ios::beg);
99

100
    int entry_num = 0;
101
    // Giving the default argument in the next line to keep Visual C++ quiet
102
    _entries.resize(_eocd.totalCount(), nullptr);
103
    while ((entry_num < _eocd.totalCount())) {
104
        zipios::ZipCDirEntry* ent = new zipios::ZipCDirEntry;
105
        _entries[entry_num] = ent;
106
        _zipfile >> *ent;
107
        if (!_zipfile) {
108
            if (_zipfile.bad()) {
109
                throw zipios::IOException(
110
                    "Error reading zip file while reading zip file central directory");
111
            }
112
            if (_zipfile.fail()) {
113
                throw zipios::FCollException("Zip file consistency problem. Failure while reading "
114
                                             "zip file central directory");
115
            }
116
            if (_zipfile.eof()) {
117
                throw zipios::IOException(
118
                    "Premature end of file while reading zip file central directory");
119
            }
120
        }
121
        ++entry_num;
122
    }
123

124
    // Consistency check. eocd should start here
125

126
    int pos = _vs.vtellg(_zipfile);
127
    _vs.vseekg(_zipfile, 0, std::ios::end);
128
    int remaining = static_cast<int>(_vs.vtellg(_zipfile)) - pos;
129
    if (remaining != _eocd.eocdOffSetFromEnd()) {
130
        throw zipios::FCollException("Zip file consistency problem. Zip file data fields are "
131
                                     "inconsistent with zip file layout");
132
    }
133

134
    // Consistency check 2, are local headers consistent with
135
    // cd headers
136
    if (!confirmLocalHeaders(_zipfile)) {
137
        throw zipios::FCollException("Zip file consistency problem. Zip file data fields are "
138
                                     "inconsistent with zip file layout");
139
    }
140

141
    return true;
142
}
143

144
bool ZipHeader::readEndOfCentralDirectory(std::istream& _zipfile)
145
{
146
    zipios::BackBuffer bb(_zipfile, _vs);
147
    int read_p = -1;
148
    bool found = false;
149
    while (!found) {
150
        if (read_p < 0) {
151
            if (!bb.readChunk(read_p)) {
152
                found = false;
153
                break;
154
            }
155
        }
156
        if (_eocd.read(bb, read_p)) {
157
            found = true;
158
            break;
159
        }
160
        --read_p;
161
    }
162

163
    return found;
164
}
165

166
bool ZipHeader::confirmLocalHeaders(std::istream& _zipfile)
167
{
168
    zipios::Entries::const_iterator it;
169
    zipios::ZipCDirEntry* ent {};
170
    int inconsistencies = 0;
171
    zipios::ZipLocalEntry zlh;
172
    for (it = _entries.begin(); it != _entries.end(); ++it) {
173
        ent = static_cast<zipios::ZipCDirEntry*>((*it).get());
174
        _vs.vseekg(_zipfile, ent->getLocalHeaderOffset(), std::ios::beg);
175
        _zipfile >> zlh;
176
        if (!_zipfile || zlh != *ent) {
177
            inconsistencies++;
178
            _zipfile.clear();
179
        }
180
    }
181
    return !inconsistencies;
182
}
183

184
void ZipHeader::setError(std::string /*error_str*/)
185
{
186
    _valid = false;
187
}
188

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.