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