Skip to content

Instantly share code, notes, and snippets.

@fogmoon
Forked from freecnjet/zip_file_format
Created August 3, 2022 15:52
Show Gist options
  • Save fogmoon/84f4a1541afef8e596acbc1786ea96de to your computer and use it in GitHub Desktop.
Save fogmoon/84f4a1541afef8e596acbc1786ea96de to your computer and use it in GitHub Desktop.
Zip file format.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#pragma warning(disable:4996)
/************************************************************************/
/* Zip file struct */
/* */
/* FileEntry0,[..., FileEntryN] + DirEntry0,[..., DirEntryN] */
/* + DigitalSignature + EndEntry*/
/* [FileEntryHeader + Data + [DataDesc]] */
/************************************************************************/
#pragma pack(push)
#pragma pack(2)
struct ZipDate
{
unsigned short Mday:5; /* day of the month - [1,31] */
unsigned short Mon:4; /* months since January - [0,11] */
unsigned short Year:7; /* years - [1980..2044] */
};
struct ZipTime
{
unsigned short Sec:5; /* seconds after the minute - [0,59] */
unsigned short Min:6; /* minutes after the hour - [0,59] */
unsigned short Hour:5; /* hours since midnight - [0,23] */
};
#define ZIP_FILE_MAGIC_NUMBER 0x04034b50
struct ZipFileEntryHeader {
//unsigned long m_MagicNumber; /* Magic number 4 bytes, must be 0x04034b50 */
unsigned short m_VersionNeeded; /* version needed to extract 2 bytes */
unsigned short m_Flag; /* general purpose bit flag 2 bytes */
unsigned short m_CompressionMethod; /* compression method 2 bytes */
ZipTime m_LastModTime; /* last mod file time in Dos fmt 2 bytes */
ZipDate m_LastModDate; /* last mod file time in Dos date 2 bytes */
unsigned long m_CRC; /* crc-32 4 bytes */
unsigned long m_CompressedSize; /* compressed size 4 bytes */
unsigned long m_UncompressedSize; /* uncompressed size 4 bytes */
unsigned short m_FilenameSize; /* filename length 2 bytes */
unsigned short m_FileExtraSize; /* extra field length 2 bytes */
/* file name (variable size) */
/* extra field (variable size) */
};
/**
* This part only availably when the 3rd bit is 1 of 'm_Flag' in 'ZipEntryHeader'
*/
struct ZipDataDesc {
unsigned long m_CRC; /* crc-32 4 bytes */
unsigned long m_CompressedSize; /* compressed size 4 bytes */
unsigned long m_UncompressedSize; /* uncompressed size 4 bytes */
};
#define ZIP_DIR_MAGIC_NUMBER 0x02014b50
struct ZipDirEntry {
//unsigned long m_MagicNumber; /* Magic number 4 bytes (0x02014b50) */
unsigned short m_VersionMade; /* version made by 2 bytes */
unsigned short m_VersionNeeded; /* version needed to extract 2 bytes */
unsigned short m_Flag; /* general purpose bit flag 2 bytes */
unsigned short m_CompressionMethod; /* compression method 2 bytes */
ZipTime m_LastModTime; /* last mod file time in Dos fmt 2 bytes */
ZipDate m_LastModData; /* last mod file time in Dos fmt 2 bytes */
unsigned long m_CRC; /* crc-32 4 bytes */
unsigned long m_CompressedSize; /* compressed size 4 bytes */
unsigned long m_UncompressedSize; /* uncompressed size 4 bytes */
unsigned short m_FilenameSize; /* filename length 2 bytes */
unsigned short m_FileExtraSize; /* extra field length 2 bytes */
unsigned short m_FileCommentSize; /* file comment length 2 bytes */
unsigned short m_DiskNumberStart; /* disk number start 2 bytes */
unsigned short m_InternalFileAttribute;/* internal file attributes 2 bytes */
unsigned long m_ExternalFileAttribute; /* external file attributes 4 bytes */
unsigned long m_OffsetOfLocalHeader; /* relative offset of local header 4 bytes */
/* file name (variable size) */
/* extra field (variable size) */
/* file comment (variable size) */
};
#define ZIP_DIR_SIGN_MAGIC_NUMBER 0x05054b50
struct ZipDirSignature {
//unsigned long m_MagicNumber; /*header signature 4 bytes (0x05054b50) */
unsigned short m_DataSize; /* size of data 2 bytes */
/* signature data (variable size) */
};
#define ZIP_DIR_END_MAGIC_NUMBER 0x06054b50
struct ZipEndDir {
//unsigned long m_MagicNumber; /* end of central dir signature 4 bytes (0x06054b50) */
unsigned short m_DiskNumber; /* number of this disk 2 bytes */
unsigned short m_DiskNumWithStart; /* number of the disk with the start of the central directory 2 bytes */
unsigned short m_DiskEntryCount; /* total number of entries in the central directory on this disk 2 bytes */
unsigned short m_EntryCount; /* total number of entries in the central directory 2 bytes */
unsigned long m_DirCount; /* size of the central directory 4 bytes */
unsigned long m_DiskOffset; /* offset of start of central directory with respect to the starting disk number 4 bytes */
unsigned short m_Comment; /* .ZIP file comment length 2 bytes */
/* .ZIP file comment (variable size) */
};
#pragma pack(pop)
int main(int argc, char** argv)
{
FILE* fp = ::fopen( "Test.zip", "rb" );
unsigned long magic_number = 0;
char szFileName[256];
::fread( &magic_number, sizeof(unsigned long), 1, fp );
while( ZIP_FILE_MAGIC_NUMBER==magic_number ) {
printf( "A local file: " );
ZipFileEntryHeader zip_local_header;
::fread( &zip_local_header, sizeof(ZipFileEntryHeader), 1, fp );
if( zip_local_header.m_FilenameSize> 0 ) {
::fread(szFileName, zip_local_header.m_FilenameSize, 1, fp );
szFileName[zip_local_header.m_FilenameSize] = 0;
printf( " name:%s.", szFileName );
if( (zip_local_header.m_Flag & 0x00000001) ) { //an encrypt data
printf( " encrypted." );
}
}
if( zip_local_header.m_FileExtraSize> 0 ) {
::fseek(fp, zip_local_header.m_FileExtraSize, SEEK_CUR);
}
// file data
::fseek(fp, zip_local_header.m_CompressedSize, SEEK_CUR);
printf( "\n" );
::fread( &magic_number, sizeof(unsigned long), 1, fp );
if( 0x08074b50==magic_number || (zip_local_header.m_Flag & (0x00000001<<3)) ) {
if( 0x08074b50!=magic_number )
::fseek(fp, -4, SEEK_CUR);
//when the 3rd bit is 1 of 'm_Flag' in 'ZipEntryHeader'
ZipDataDesc data_desc;
::fread( &data_desc, sizeof(ZipDataDesc), 1, fp );
zip_local_header.m_CRC = data_desc.m_CRC;
zip_local_header.m_CompressedSize = data_desc.m_CompressedSize;
zip_local_header.m_UncompressedSize = data_desc.m_UncompressedSize;
::fread( &magic_number, sizeof(unsigned long), 1, fp );
}
}
while( ZIP_DIR_MAGIC_NUMBER==magic_number ) {
printf( "A dir: " );
ZipDirEntry zip_dir;
::fread( &zip_dir, sizeof(ZipDirEntry), 1, fp );
if( zip_dir.m_FilenameSize> 0 ) {
::fread(szFileName, zip_dir.m_FilenameSize, 1, fp );
szFileName[zip_dir.m_FilenameSize] = 0;
printf( "name:%s.", szFileName );
}
if( zip_dir.m_FileExtraSize> 0 ) {
::fseek(fp, zip_dir.m_FileExtraSize, SEEK_CUR);
}
if( zip_dir.m_FileCommentSize> 0 ) {
::fseek(fp, zip_dir.m_FileCommentSize, SEEK_CUR);
}
printf( "\n" );
::fread( &magic_number, sizeof(unsigned long), 1, fp );
}
while( ZIP_DIR_SIGN_MAGIC_NUMBER==magic_number ) {
printf( "A dir sign.\n" );
ZipDirSignature zip_dir_sign;
::fread( &zip_dir_sign, sizeof(ZipDirSignature), 1, fp );
if( zip_dir_sign.m_DataSize> 0 ) {
::fseek(fp, zip_dir_sign.m_DataSize, SEEK_CUR);
}
::fread( &magic_number, sizeof(unsigned long), 1, fp );
}
if( ZIP_DIR_END_MAGIC_NUMBER==magic_number ) {
printf( "A dir end." );
ZipEndDir zip_dir_end;
::fread( &zip_dir_end, sizeof(ZipEndDir), 1, fp );
if( zip_dir_end.m_Comment> 0 ) {
::fread(szFileName, zip_dir_end.m_Comment, 1, fp );
szFileName[zip_dir_end.m_Comment] = 0;
printf( " Comment:%s.", szFileName );
}
printf( "\n" );
}
::fclose( fp );
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment