teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

1

追記1

2020/11/25 01:56

投稿

BeatStar
BeatStar

スコア4962

title CHANGED
File without changes
body CHANGED
@@ -18,248 +18,66 @@
18
18
 
19
19
  未完成で、あっているかどうかはわかりませんが、一応、上記でいうファイルエントリなるものを取り出すことに成功しました。
20
20
 
21
- ```C++
22
- // インクルードされているとして
21
+ [コード](https://pastebin.com/JMnjS4iH)
23
22
 
24
- using namespace std;
23
+ 字数制限の為、別のサイトをお借りしています。
25
24
 
26
- namespace Test1{
27
- using SingnaturesQueue = std::queue<char>;
28
- using UCharQueue = std::queue<unsigned char>;
25
+ そこで、今回は、**「取り出したファイルエントリのデータを、どうやって元に戻すのか」**が知りたいのです。
29
- using UCharStack = std::stack<unsigned char>;
30
- }
31
26
 
32
- namespace Test1{
33
- unsigned long convertHexStringToULong( const std::string &str ){
34
- char* endptr;
35
- unsigned res = strtoul( str.c_str(), &endptr, 16 );
27
+ 参考1の「ZIPセントラルディレクトリファイルヘッダ」の項目で、
36
- return res;
37
- }
38
- }
39
28
 
40
- namespace Test1{
41
- std::string convertUCharToHexString( unsigned char val ){
42
- stringstream ss;
29
+ > 圧縮メソッド
30
+ > ファイルエントリがどのプロトコルで格納されたかが書いてあります。
43
- ss << std::hex << static_cast<unsigned int>(val);
31
+ > 今回は無圧縮なので0が入っていますが8のDeflateが一般的です。
44
- return ss.str();
45
- }
46
- }
47
32
 
48
- namespace Test1{
49
- class ICompressedItem{
50
- public:
51
- using TYPE = unsigned char;
52
- public:
53
- virtual ~ICompressedItem(){}
54
- virtual std::string filename( void ) const = 0;
33
+ とあります。それで(以前、別のzipファイルで試したとき)試してみると、8になっていました。
55
- virtual std::list<ICompressedItem::TYPE> fileEntry( void ) const = 0;
34
+ そのため、「Deflate」状態になっているのだと思いますが、
56
- };
57
- using CompressedItemList = std::list<ICompressedItem*>;
35
+ これをもとの状態(圧縮前の状態)にするにはどのようにやればいいのでしょうか。
58
- }
59
36
 
60
- namespace Test1{
61
- class IReader{
37
+ [情報]
62
- public:
38
+ 言語: C++
63
- virtual ~IReader(){}
39
+ コンパイラ: MinGW (g++)
64
- virtual Test1::CompressedItemList read( void ) = 0;
65
- };
66
- }
67
40
 
68
- namespace Test1::ZipFiles{
41
+ ---
69
- class CompressedItem : public Test1::ICompressedItem{
70
- public:
42
+ [追記1]
71
- CompressedItem( const Test1::UCharQueue &all ) : all_(all){
72
- int versionNeeded2Extract = CompressedItem::extractIntDecimal( 2 );
73
- cout << "version needed to extract = " << versionNeeded2Extract << endl;
74
- int generalPurposeBitFlag = CompressedItem::extractIntDecimal( 2 );
75
- int compressionMethod = CompressedItem::extractIntDecimal( 2 );
76
- cout << "compressionMethod = " << compressionMethod << endl;
77
- int lastModFileTime = CompressedItem::extractIntDecimal( 2 );
78
- int lastModeFileDate = CompressedItem::extractIntDecimal( 2 );
79
- int crc_32 = CompressedItem::extractIntDecimal( 4 );
80
- int compressedSize = CompressedItem::extractIntDecimal( 4 );
81
- int uncompressedSize = CompressedItem::extractIntDecimal( 4 );
82
- int fileNameLength = CompressedItem::extractULongDecimal( 2 );
83
- int extraFieldLength = CompressedItem::extractIntDecimal( 2 );
84
-
85
- {
86
- for( int i = 0; i < fileNameLength; i++ ){
87
- filename_ += static_cast<char>(all_.front());
88
- all_.pop();
89
- }
90
- }
91
-
92
- for( int i = 0; i < extraFieldLength; i++ ) all_.pop();
93
-
94
- {
95
- Test1::UCharStack cs;
96
- while( !all_.empty() ){
97
- ICompressedItem::TYPE uc = all_.front();
98
- all_.pop();
99
- cs.push( uc );
100
- }
101
- while( !cs.empty() ){
102
- ICompressedItem::TYPE uc = cs.top();
103
- cs.pop();
104
- fileEntry_.push_back( uc );
105
- }
106
- }
107
- // 前に余計なシグネチャ(3バイト分)が付いているため、そぎ落とす
108
- for( int i = 0; i < 3; i++ ) fileEntry_.pop_front();
109
- }
110
- ~CompressedItem(){}
111
-
112
- std::string filename( void ) const{ return filename_; }
113
- std::list<ICompressedItem::TYPE> fileEntry( void ) const{ return fileEntry_; }
114
- protected:
115
- int extractIntDecimal( int nbytes ){
116
- Test1::UCharStack cs;
117
- // データをnbytes分取り出す
118
- for( int i = 0; i < nbytes; i++ ){
119
- unsigned char c = all_.front();
120
- all_.pop();
121
- cs.push( c );
122
- }
123
-
124
- // 16進数に変換
125
- std::string ss = "";
126
- while( !cs.empty() ){
127
- unsigned char t = cs.top();
128
- cs.pop();
129
- ss += Test1::convertUCharToHexString( static_cast<unsigned char>(t) );
130
- }
131
- // 10進数の整数に変換
132
- unsigned long res = Test1::convertHexStringToULong( ss );
133
- return static_cast<int>(res);
134
- }
135
- protected:
136
- unsigned long extractULongDecimal( int nbytes ){
137
- Test1::UCharStack cs;
138
- // データをnbytes分取り出す
139
- for( int i = 0; i < nbytes; i++ ){
140
- unsigned char c = all_.front();
141
- all_.pop();
142
- cs.push( c );
143
- }
144
-
145
- // 16進数に変換
146
- std::string ss = "";
147
- while( !cs.empty() ){
148
- unsigned char t = cs.top();
149
- cs.pop();
150
- ss += Test1::convertUCharToHexString( static_cast<unsigned char>(t) );
151
- }
152
- // 10進数の整数に変換
153
- return Test1::convertHexStringToULong( ss );
154
- }
155
- private:
156
- Test1::UCharQueue all_;
157
- private:
158
- std::string filename_;
159
- std::list<ICompressedItem::TYPE> fileEntry_;
160
- };
161
- }
162
43
 
163
- namespace Test1::ZipFiles{
164
- class Reader : public Test1::IReader{
165
- public:
166
- Reader( const std::string &compressedFilePath ) : file_(new Util::BinaryFileReader(compressedFilePath)),zipLocalHeaderSignature_(Reader::createZipLocalHeaderSignature()),centralDirectoryFileHeaderSignature_(Reader::createCentralDirectoryFileHeaderSignature()){
167
-
168
- }
169
- ~Reader(){ delete file_; }
170
- std::string filepath( void ) const{ return file_->filepath(); }
171
- bool isEnabled( void ) const{ return file_->isEnabled(); }
172
- virtual Test1::CompressedItemList read( void ){
173
- Test1::CompressedItemList items; // 結果を保持するリスト
174
- Test1::UCharQueue all; // 一時的に保持しておくキュー
175
- Test1::SingnaturesQueue signature; // シグネチャとして保存してチェックするためのもの
176
- // バイナリデータが存在している間
177
- while( !file_->isEof() ){
178
- // シグネチャは4バイトまで
179
- if( signature.size() >= 4 ) signature.pop();
180
-
181
- // ファイルから1バイト分読み込む
182
- char c[1];
183
- file_->read( c, 1, 1 );
184
-
185
- // 読み込んだデータを16進数としてシグネチャキューに突っ込む
186
- signature.push( c[0] );
187
-
188
- if( signature == zipLocalHeaderSignature_ ){ // ZIPローカルヘッダのシグネチャと一致する場合
189
- // allを itemsに追加
190
- if( !all.empty() ) items.push_back( new Test1::ZipFiles::CompressedItem( all ) );
191
- // all を破棄
192
- all = Test1::UCharQueue();
193
- }else if( signature == centralDirectoryFileHeaderSignature_ ){ // セントラルディレクトリファイルヘッダのシグネチャと一致する場合
194
- // allを itemsに追加
195
- if( !all.empty() ) items.push_back( new Test1::ZipFiles::CompressedItem( all ) );
196
- // これ以上はないのでbreak
197
- break;
198
- }else{ // それ以外はそのままallに追加
199
- all.push( c[0] );
200
- }
201
- }
202
- return items;
203
- }
204
- protected:
205
- Test1::SingnaturesQueue createZipLocalHeaderSignature( void );
206
- Test1::SingnaturesQueue createCentralDirectoryFileHeaderSignature( void );
207
- private:
208
- Util::BinaryFileReader* file_;
209
- Test1::SingnaturesQueue zipLocalHeaderSignature_;
210
- Test1::SingnaturesQueue centralDirectoryFileHeaderSignature_;
211
- };
212
- }
44
+ 一応、SaitoAtsushiさんのおっしゃるように、zlibなるものをDLして実際に使ってみました。
213
45
 
46
+ 一旦、今回の私のコードとは別の実行ファイルとしてzlibを使ったプログラムを生成しておき、
47
+ 何らかの画像ファイルとそれをzipファイルにした圧縮ファイルのそれぞれを用意します。
48
+
49
+ ```ここに言語を入力
50
+ [準備0]
214
- int main( int argc, char* argv[] ){
51
+ zlibを使った解凍系プログラム (便宜上、zlibmain.exe とする)
215
- if( argc < 2 ){
216
- cout << "cmd: main FILE" << endl;
217
- return -1;
218
- }
219
-
220
- Test1::ZipFiles::Reader* reader = new Test1::ZipFiles::Reader( argv[1] );
221
- if( !reader->isEnabled() ){
52
+ 今回の自分のプログラム (main.exe とする)
222
- cout << "Cannnot read " << reader->filepath() << endl;
223
- return -2;
224
- }
225
-
226
- Test1::CompressedItemList itemList = reader->read();
227
-
228
- delete reader;
229
- cout << "size = " << itemList.size() << endl;
230
-
231
- Test1::CompressedItemList::iterator it = itemList.begin();
232
- {
233
- Util::BinaryFileWriter fileWriter( (*it)->filename() );
234
- if( !fileWriter.isEnabled() ){
53
+ 適当な画像ファイル (image1.jpgとする)
235
- cout << "Cannot open " << fileWriter.filepath() << endl;
236
- return -2;
237
- }
238
-
239
- std::list<Test1::ICompressedItem::TYPE> file = (*it)->fileEntry();
240
- for( Test1::ICompressedItem::TYPE c : file ){
241
- fileWriter.write( &c, 1, 1 );
54
+ ■ image1.jpgをzipファイルにしたもの (arc1.zipとする)
242
- }
243
- }
244
- return 0;
245
- }
246
55
  ```
247
- ※ 字数制限のため一部省略. Util::BinaryFileReaderはファイルの読み取りとする
248
56
 
249
- (コードの一部変更していす)
57
+ ※ zlibmain.exe のコードは [zlib 入門](https://oku.edu.mie-u.ac.jp/~okumura/compression/zlib.html) にある comptest2.c そのま流用。
250
58
 
251
- そこで、今回は、**「取り出したファイルエントリのデータを、どうやって元に戻すのか」**が知りたいのです。
252
59
 
253
- 参考1の「ZIPセントラルディレクトリファイルヘッダ」の項目で、
254
60
 
255
- > 圧縮メソッド
61
+ ```ここに言語を入力
62
+ [やったこと1]
63
+ 1. main.exeでarc1.zipからimage1.jpgをファイルとして取り出す
256
- > ファイルエントリがどのプロトコルで格納されたかが書いあります。
64
+  → そのファイルをcomp2.bin とし生成しておく
65
+ 2. zlibmain.exe で image1.jpg を comp.bin として圧縮する( "c" オプションにて )
66
+ 2. comp.bin と comp2.bin を それぞれ、BzEditor なるバイナリエディタでダンプリストを生成
257
- > 今回は無圧縮なの0が入っいますが8のDeflateが一般的です。
67
+ 3. (3)生成されたダンプリストを二つ、比較しみる
68
+ ```
258
69
 
259
- とあります。それで(以前、別のzipファイルで試したとき)試してみると、8になっていました。
260
- そのため、「Deflate」状態になっているのだと思いますが、
261
- れをもと状態(圧縮前の状態)にするにはどのようにればいいのでしょ
70
+ この"ったこと1" では、そもそもデータが合ってです
262
71
 
72
+ 私が使った comp.bin では { ED, 02, 00, 00, 78, ... } となっていますが、
263
- [情報]
73
+ comp2.bin では { 01, FF, E0, F3, ... } のようになっています。
74
+
75
+ 逆さなのかなぁと思い、(comp2.binを)逆から読んでみても、該当するデータ列が見つかりません。
76
+ 単純に、ランダムに comp.bin にある { 00, 00 } をcomp2.bin から探し出して、
264
- 言語: C++
77
+ その周辺の16進数を比較しても同じデータになっていませんでした。
78
+
79
+ つまり、本来は同じファイルのデータを読んでいるはずなのに、別のデータ列になっているのです。
80
+
265
- コンパイラ: MinGW (g++)
81
+ 私の組み方が悪いのでしょうか。
82
+
83
+ あまりバイナリファイルを扱わないため、混乱しています…。