zipの読み込みについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら

トピックに返信する


答えを正確にご入力ください。答えられるかどうかでスパムボットか否かを判定します。

BBCode: ON
[img]: ON
[flash]: OFF
[url]: ON
スマイリー: OFF

トピックのレビュー
   

展開ビュー トピックのレビュー: zipの読み込みについて

Re: zipの読み込みについて

#3

by しょしんにかえる » 7年前

ありがとうございます。うまくいきました。トピックを分けてしまいましたが、実は同じ問題だったとは...。恥ずかしい限りです。こちらは解決とさせていただきます。

Re: zipの読み込みについて

#2

by かずま » 7年前

境界調整のため、ZIP_EOCD では、_commentlength と _comment の
間に 2バイトのパディングが入っているからではありませんか?
LocalFileHeader は _lastModDate のあとに、ZIP_OCD は
_inFileAttr のあとにパディングが入っているようです。

VC++ では、#pragma pack で詰めることができます。

コード:

#include <iostream>
#include <string>

typedef struct _tagEOCD
{
	int16_t           _diskCount;
	int16_t           _diskNumber;
	int16_t           _CDcount;
	int16_t           _CDcountAll;
	int32_t           _CDsize;
	int32_t           _CDoffset;
	int16_t           _commentLength; //ZIPファイルに対するコメントの長さ
	std::string       _comment; //コメント
}ZIP_EOCD;

typedef struct _tagLocalFileHeader
{
	int8_t  _signature[4];
	int16_t _minVer;
	int16_t _bitFlag;
	int16_t _method;
	int16_t _lastModTime;
	int16_t _lastModDate;
	int32_t _CRC32;
	int32_t _originalSize;
	int32_t _zippedSize;
	int16_t _fNameLen;
	int16_t _exFiledLen;

}LocalFileHeader;

typedef struct _tagDataDescriptor
{
	int32_t _field[3];
}DataDescriptor;

typedef struct _tagZIPLocalHeader
{
	uint8_t  _signnature[4];
	uint16_t _formatVer;
	uint16_t _minVer;
	uint16_t _bitFlag;
	uint16_t _method;
	uint16_t _modTime;
	uint16_t _modDate;
	uint32_t _crc_32;
	uint32_t _compressed_size;
	uint32_t _uncompressed_size;
	uint16_t _fNameLen;
	uint16_t _exFieldLen;
	uint16_t _fCommentLen;
	uint16_t _diskNumberStart;
	uint16_t _inFileAttr;
	uint32_t _exFileAttr;
	uint32_t _lhfOffset;
}ZIP_OCD;

#pragma pack(push, 2)
typedef struct _tagEOCD2
{
	int16_t           _diskCount;
	int16_t           _diskNumber;
	int16_t           _CDcount;
	int16_t           _CDcountAll;
	int32_t           _CDsize;
	int32_t           _CDoffset;
	int16_t           _commentLength; //ZIPファイルに対するコメントの長さ
	std::string       _comment; //コメント
}ZIP_EOCD2;

typedef struct _tagLocalFileHeader2
{
	int8_t  _signature[4];
	int16_t _minVer;
	int16_t _bitFlag;
	int16_t _method;
	int16_t _lastModTime;
	int16_t _lastModDate;
	int32_t _CRC32;
	int32_t _originalSize;
	int32_t _zippedSize;
	int16_t _fNameLen;
	int16_t _exFiledLen;

}LocalFileHeader2;

typedef struct _tagDataDescriptor2
{
	int32_t _field[3];
}DataDescriptor2;

typedef struct _tagZIPLocalHeader2
{
	uint8_t  _signnature[4];
	uint16_t _formatVer;
	uint16_t _minVer;
	uint16_t _bitFlag;
	uint16_t _method;
	uint16_t _modTime;
	uint16_t _modDate;
	uint32_t _crc_32;
	uint32_t _compressed_size;
	uint32_t _uncompressed_size;
	uint16_t _fNameLen;
	uint16_t _exFieldLen;
	uint16_t _fCommentLen;
	uint16_t _diskNumberStart;
	uint16_t _inFileAttr;
	uint32_t _exFileAttr;
	uint32_t _lhfOffset;
}ZIP_OCD2;
#pragma pack(pop)

template<typename T, typename T2>
void print(const char *name)
{
	std::cout << sizeof(T) << " " << sizeof(T2) << ": " << name << std::endl;
}

int main()
{
	print<ZIP_EOCD, ZIP_EOCD2>("ZIP_EOCD");
	print<LocalFileHeader, LocalFileHeader2>("LocalFileHeader");
	print<DataDescriptor, DataDescriptor2>("DataDescriptor");
	print<ZIP_OCD, ZIP_OCD2>("ZIP_OCD");
}
実行結果

コード:

44 42: ZIP_EOCD
32 30: LocalFileHeader
12 12: DataDescriptor
48 46: ZIP_OCD

zipの読み込みについて

#1

by しょしんにかえる » 7年前

zipファイルを読み込もうとしているのですが、セントラルディレクトリを読み込む段階でうまくいきません。
セントラルディレクトリの構造体の定義はwikipediaを参考にしたのですが、どこかで2byte分ずれてしまうのです。(_lhfOffsetがおかしな値を示します...)
どなたか解決法をご教示いただけないでしょうか。

コード:

#include "stdafx.h"

typedef struct _tagEOCD
{
	int16_t           _diskCount;
	int16_t           _diskNumber;
	int16_t           _CDcount;
	int16_t           _CDcountAll;
	int32_t           _CDsize;
	int32_t           _CDoffset;
	int16_t           _commentLength; //ZIPファイルに対するコメントの長さ
	std::string       _comment; //コメント
}ZIP_EOCD;

typedef struct _tagLocalFileHeader
{
	int8_t  _signature[4];
	int16_t _minVer;
	int16_t _bitFlag;
	int16_t _method;
	int16_t _lastModTime;
	int16_t _lastModDate;
	int32_t _CRC32;
	int32_t _originalSize;
	int32_t _zippedSize;
	int16_t _fNameLen;
	int16_t _exFiledLen;

}LocalFileHeader;

typedef struct _tagDataDescriptor
{
	int32_t _field[3];
}DataDescriptor;

typedef struct _tagZIPLocalHeader
{
	uint8_t  _signnature[4];
	uint16_t _formatVer;
	uint16_t _minVer;
	uint16_t _bitFlag;
	uint16_t _method;
	uint16_t _modTime;
	uint16_t _modDate;
	uint32_t _crc_32;
	uint32_t _compressed_size;
	uint32_t _uncompressed_size;
	uint16_t _fNameLen;
	uint16_t _exFieldLen;
	uint16_t _fCommentLen;
	uint16_t _diskNumberStart;
	uint16_t _inFileAttr;
	uint32_t _exFileAttr;
	uint32_t _lhfOffset;
}ZIP_OCD;

inline int16_t swapVal(const int16_t Value)
{
	return (Value << 8) | (Value >> 8);
}

inline int32_t swapVal(const int32_t Value)
{
	return (Value << 24) | ((Value & 0x0000ff00) << 8) | ((Value & 0x0000ff00) >> 8) |
		(Value >> 24);
}

bool getEOCD(std::ifstream& InStream, ZIP_EOCD& Buffer)
{
	char _CurrentVal;
	char _Magic[4] = { 0x50,0x4b,0x05,0x06 };

	//ファイル終端から探す
	//シグネチャを見つけるので、最小サイズ(16)分戻しておく
	InStream.seekg(-18, std::ios_base::end);
	while (!InStream.bad()){
		InStream.read(&_CurrentVal,1);
		printf("0x%x,", _CurrentVal);

		if (_CurrentVal == _Magic[3]) {
			char _Temp[3];
			//3Byte分読み込む
			InStream.seekg(-4, std::ios_base::cur);
			InStream.read(_Temp, 3);

			//すでに1Byteは正しいことは確定している
			if (!memcmp(_Temp, _Magic, sizeof(_Magic) - 1)) {
				break; //正しかった
			}
			else {
				//2Byte進めてやり直し
				InStream.seekg(2, std::ios_base::cur);
			}
		}

		//1byte分戻す(1Byteは読み込むときに進むため+1)
		InStream.seekg(-2, std::ios_base::cur);
	}

	//0x06分進める
	InStream.seekg(1, std::ios_base::cur);
	//読み込んで終了
	InStream.read(reinterpret_cast<char*>(&Buffer), sizeof(ZIP_EOCD));


	return InStream.eof();
}

bool getOCD(std::ifstream& InStream, std::vector<ZIP_OCD>& ZipOcdBuffer,
	std::vector<std::string>& FileNameBuffer)
{
	ZIP_EOCD _EocdBuffer;

	if (!getEOCD(InStream, _EocdBuffer)) {
		return false;
	}

	//バッファを確保
	ZipOcdBuffer.resize(_EocdBuffer._CDcount);
	FileNameBuffer.resize(_EocdBuffer._CDcount);
	InStream.clear();
	//移動
	InStream.seekg(_EocdBuffer._CDoffset, std::ios_base::beg);

	for (auto i = 0; i < _EocdBuffer._CDcountAll; ++i) {
		//読み込み
		InStream.read(reinterpret_cast<char*>(&ZipOcdBuffer[i]), sizeof(ZIP_OCD));
		//バッファ確保
		FileNameBuffer[i].resize(ZipOcdBuffer[i]._fNameLen);
		//ファイル名読み込み
		InStream.read(&FileNameBuffer[i][0], ZipOcdBuffer[i]._fNameLen);
		//それ以外は読み飛ばす
		InStream.seekg(ZipOcdBuffer[i]._exFieldLen + ZipOcdBuffer[i]._fCommentLen);


	}

	return true;
}

int main()
{
	auto path = "C:\\Games\\Minecraft\\1.12.2\\ic\\mods\\CutAllSMP_v2.5.2.zip";
	std::ifstream input_file(path, std::ios_base::binary);
	std::vector<ZIP_OCD> Buffer;
	std::vector<std::string> FileName;

	if (!input_file) {
		return false;
	}

	getOCD(input_file, Buffer, FileName);
}


ページトップ