#include #include #include #include #include #include #include using namespace std; #pragma pack(push, 1) struct LocalFileHeader { uint32_t signature = 0x04034b50u; uint16_t versionNeeded = 0; uint16_t flag = 0; uint16_t compression = 0; uint16_t modifiedTime = 0; uint16_t modifiedDate = 0; uint32_t crc = 0; uint32_t compressedSize = 0; uint32_t uncompressedSize = 0; uint16_t fileNameLength = 0; uint16_t extraFieldLength = 0; }; struct CentralDirectoryHeader { uint32_t signature = 0x02014b50u; uint16_t versionMade = 0; uint16_t versionNeeded = 0; uint16_t flag = 0; uint16_t compression = 0; uint16_t modifiedTime = 0; uint16_t modifiedDate = 0; uint32_t crc = 0; uint32_t compressedSize = 0; uint32_t uncompressedSize = 0; uint16_t fileNameLength = 0; uint16_t extraFieldLength = 0; uint16_t commentLength = 0; uint16_t disk = 0; uint16_t internalAttr = 0; uint32_t externalAttr = 0; uint32_t offset = 0; }; struct ExtraFieldHeader { uint16_t id = 0; uint16_t size = 0; }; struct EndOfCentralDirectoryRecord { uint32_t signature = 0x06054b50u; uint16_t disk = 0; uint16_t centralDirDisk = 0; uint16_t entryNumber = 0; uint16_t totalEntryNumber = 0; uint32_t centralDirSize = 0; uint32_t centralDirOffset = 0; uint16_t commentLength = 0; }; #pragma pack(pop) /* int main() { FILE *f = fopen("empty.zip", "wb"); EndOfCentralDirectoryRecord end; fwrite(&end, sizeof end, 1, f); fclose(f); } */ /* int main() { FILE *f = fopen("comment.zip", "wb"); EndOfCentralDirectoryRecord end; end.commentLength = 7; fwrite(&end, sizeof end, 1, f); fwrite("comment", 1, 7, f); fclose(f); } */ uint32_t crc_tmp1(vector data) { // 被除数 vector a; for (size_t i=0; i>j&1); for (int i=0; i<32; i++) a.push_back(0); for (int i=0; i<32; i++) a[i] ^= 1; // 除数 vector b(1, 1); for (int i=31; i>=0; i--) b.push_back(0x04C11DB7>>i&1); // 除算 for (size_t i=0; i stringToUint8(string str) { vector uint8; for (char c: str) uint8.push_back((uint8_t)c); return uint8; } /* int main() { printf("%08x\n", crc_tmp1(stringToUint8("understand zip"))); // 3cde314f } */ uint32_t crc_tmp2(vector data) { uint32_t c = 0; for (size_t i=0; i>j&1 : 0) ^ (i<4 ? 1 : 0))<<31 | c>>1; if (lsb != 0) c ^= 0xedb88320; } return ~c; } uint32_t crc_tmp3(vector data) { uint32_t c = 0xffffffffu; for (size_t i=0; i>j&1; c >>= 1; if (lsb != 0) c ^= 0xedb88320; } return ~c; } uint32_t crcTable[256]; void makeCrcTable() { for (int i=0; i<256; i++) { uint32_t c = i; for (int j=0; j<8; j++) c = c>>1 ^ ((c&1)!=0 ? 0xedb88320 : 0); crcTable[i] = c; } } uint32_t crc32(uint32_t c, uint8_t d) { return c>>8 ^ crcTable[c&0xff^d]; } uint32_t crc(vector data) { uint32_t c = 0xffffffffu; for (size_t i=0; iversionNeeded = central.versionNeeded; local->flag = central.flag; local->compression = central.compression; local->modifiedTime = central.modifiedTime; local->modifiedDate = central.modifiedDate; local->crc = central.crc; local->compressedSize = central.compressedSize; local->uncompressedSize = central.uncompressedSize; local->fileNameLength = central.fileNameLength; local->extraFieldLength = central.extraFieldLength; } void timeToDos(time_t time, uint16_t *dosTime, uint16_t *dosDate) { tm *local = localtime(&time); *dosTime = local->tm_hour<<11 | local->tm_min<<5 | local->tm_sec/2; *dosDate = (local->tm_year + 1900 - 1980)<<9 | (local->tm_mon + 1)<<5 | local->tm_mday; } /* int main() { makeCrcTable(); string name[3] = {"file1.txt", "file2.txt", "file3.txt"}; string content[3] = {"understand zip", "abc", ""}; FILE *f = fopen("uncompressed.zip", "wb"); uint16_t modTime, modDate; timeToDos(time(nullptr), &modTime, &modDate); CentralDirectoryHeader central[3]; for (int i=0; i<3; i++) { central[i].versionMade = 0<<8 | 20; central[i].versionNeeded = 20; central[i].modifiedTime = modTime; central[i].modifiedDate = modDate; central[i].crc = crc(stringToUint8(content[i])); central[i].compressedSize = (uint32_t)content[i].size(); central[i].uncompressedSize = (uint32_t)content[i].size(); central[i].fileNameLength = (uint32_t)name[i].size(); central[i].offset = (uint32_t)ftell(f); LocalFileHeader local; copyHeader(central[i], &local); fwrite(&local, sizeof local, 1, f); fwrite(name[i].c_str(), name[i].size(), 1, f); fwrite(content[i].c_str(), content[i].size(), 1, f); } EndOfCentralDirectoryRecord end; end.centralDirOffset = (uint32_t)ftell(f); for (int i=0; i<3; i++) { fwrite(¢ral[i], sizeof central[i], 1, f); fwrite(name[i].c_str(), name[i].size(), 1, f); } end.entryNumber = 3; end.totalEntryNumber = 3; end.centralDirSize = (uint32_t)ftell(f) - end.centralDirOffset; fwrite(&end, sizeof end, 1, f); fclose(f); } */ vector packMerge(vector count, int L) { struct Coin { int value; vector symbol; Coin(int value, vector symbol): value(value), symbol(symbol) {} bool operator<(const Coin &c) const {return value> denom(L+1); size_t n = 0; for (size_t i=0; i0) { for (int d=0; d(1, (int)n))); n++; } vector lengthTmp(n); switch (n) { case 0: break; case 1: lengthTmp[0] = 1; break; default: for (int d=0; d length; size_t c = 0; for (size_t i=0; i0 ? lengthTmp[c++] : 0); return length; } /* int main() { vector length = packMerge({1, 17, 2, 3, 5, 5}, 4); //vector length = packMerge({1, 17, 2, 3, 5, 5}, 3) for (size_t i=0; i data; size_t c; BitStream(): c(0) {} void write(int bit) { if (c%8 == 0) data.push_back(0); data[data.size()-1] |= bit<>i&1); } }; class Huffman { vector code; vector length; public: Huffman(vector length): length(length) { code = vector(length.size()); size_t n = 0; for (int l: length) if (l==0) n++; int c = 0; for (int l=1; n=0; i--) stream->write(code[symbol]>>i&1); } }; /* int main() { Huffman huffman({4, 1, 4, 3, 3, 3}); BitStream stream; for (int i=0; i<6; i++) huffman.write(i, &stream); for (uint8_t c: stream.data) printf(" %02x", c); printf("\n"); // e7 d3 01 } */ struct Code { int code = 0; int ext = 0; int extLen = 0; Code() {} Code(int code, int ext, int extLen): code(code), ext(ext), extLen(extLen) {} }; // valueからコードと拡張ビットを求める Code calcCodeExt(int value, const int *table, int tableLen, int offset) { for (int i=0; i deflate(vector data) { // リテラル・一致長と一致距離の拡張ビット長 static int literalExtTable[29] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, }; static int distExtTable[30] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 11,11,12,12,13,13, }; // 入力をリテラル・一致長と一致距離に圧縮する vector literal; vector dist; // 添え字の3文字が過去に出現した位置を記録する map hash; for (size_t i=0; i 0 && i-hash[h] <= 32768) { // 過去に出現していれば、一致長と一致距離に圧縮 size_t p = hash[h]; len = 3; while (len<258 && i+len literalCount(286); for (Code l: literal) literalCount[l.code]++; vector literalLen = packMerge(literalCount, 15); vector distCount(30); for (Code d: dist) if (d.code>=0) distCount[d.code]++; vector distLen = packMerge(distCount, 15); // ビット長の配列を作り、圧縮する int HLIT = 286 - 257; while (0 codeLen; for (int i=0; i codeLenCode; for (size_t i=0; i0) while (prevLen<6 && i+prevLen=11) { codeLenCode.push_back(Code(18, zeroLen-11, 7)); i += zeroLen; } else if (zeroLen>=3) { codeLenCode.push_back(Code(17, zeroLen-3, 3)); i += zeroLen; } else if (prevLen>=3) { codeLenCode.push_back(Code(16, prevLen-3, 3)); i += prevLen; } else { codeLenCode.push_back(Code(codeLen[i], 0, 0)); i++; } } vector codeLenCount(19); for (Code c: codeLenCode) codeLenCount[c.code]++; vector codeLenCodeLen = packMerge(codeLenCount, 7); static int codeLenTrans[] = { 16,17,18, 0, 8, 7, 9, 6, 10, 5,11, 4,12, 3,13, 2, 14, 1,15 }; int HCLEN = 19 - 4; while (0=0) { huffmanDist.write(dist[i].code, &stream); stream.writeBits(dist[i].ext, dist[i].extLen); } } return stream.data; } /* int main() { vector data; for (int i=0; i<8; i++) { data.push_back(122); data.push_back(105); data.push_back(112); } vector comp = deflate(data); for (uint8_t c: comp) printf(" %02x", c); printf("\n"); // 6d c2 31 0d 00 00 00 83 30 bd fb 76 a3 1e 03 24 65 4f 02 } */ /* int main() { makeCrcTable(); FILE *f = fopen("compressed.zip", "wb"); string name = "zip.txt"; string content_ = ""; for (int i=0; i<8; i++) content_ += "zip"; vector content = stringToUint8(content_); vector compressed = deflate(content); CentralDirectoryHeader central; central.versionMade = 0<<8 | 20; central.versionNeeded = 20; central.compression = 8; // Deflate central.crc = crc(content); central.compressedSize = (uint32_t)compressed.size(); central.uncompressedSize = (uint32_t)content.size(); central.fileNameLength = (uint32_t)name.size(); central.offset = 0; LocalFileHeader local; copyHeader(central, &local); fwrite(&local, sizeof local, 1, f); fwrite(name.c_str(), name.size(), 1, f); fwrite(&compressed[0], compressed.size(), 1, f); EndOfCentralDirectoryRecord end; end.centralDirOffset = (uint32_t)ftell(f); fwrite(¢ral, sizeof central, 1, f); fwrite(name.c_str(), name.size(), 1, f); end.entryNumber = 1; end.totalEntryNumber = 1; end.centralDirSize = (uint32_t)ftell(f) - end.centralDirOffset; fwrite(&end, sizeof end, 1, f); fclose(f); } */ struct Key { uint32_t key0 = 0x12345678U; uint32_t key1 = 0x23456789U; uint32_t key2 = 0x34567890U; void update_keys(uint8_t c) { key0 = crc32(key0, c); key1 = (key1 + (key0&0xff)) * 0x08088405U + 1; key2 = crc32(key2, key1>>24); } uint8_t decrypt_byte() { uint16_t temp = (uint16_t)(key2 | 2); return (temp*(temp^1))>>8; } }; /* int main() { makeCrcTable(); Key key; for (uint8_t c=0; c<8; c++) { key.update_keys(c); printf(" %02x", key.decrypt_byte()); } printf("\n"); // 1a 63 54 9f e7 41 0e 83 } */ int main() { makeCrcTable(); FILE *f = fopen("encrypted.zip", "wb"); string name = "secret.txt"; vector content = stringToUint8("secret message"); vector password = stringToUint8("p@ssw0rd"); vector encryption(12); random_device rand; for (size_t i=0; i<11; i++) encryption[i] = (uint8_t)rand(); uint32_t crc32 = crc(content); encryption[11] = (uint8_t)(crc32>>24); // 暗号化 Key key; for (uint8_t c: password) key.update_keys(c); for (uint8_t &c: encryption) { uint8_t t = key.decrypt_byte(); key.update_keys(c); c ^= t; } for (uint8_t &c: content) { uint8_t t = key.decrypt_byte(); key.update_keys(c); c ^= t; } CentralDirectoryHeader central; central.versionMade = 0<<8 | 20; central.versionNeeded = 20; central.flag = 1; // encrypted central.crc = crc32; central.compressedSize = (uint32_t)content.size() + 12; central.uncompressedSize = (uint32_t)content.size(); central.fileNameLength = (uint32_t)name.size(); central.offset = 0; LocalFileHeader local; copyHeader(central, &local); fwrite(&local, sizeof local, 1, f); fwrite(name.c_str(), name.size(), 1, f); fwrite(&encryption[0], 12, 1, f); fwrite(&content[0], content.size(), 1, f); EndOfCentralDirectoryRecord end; end.centralDirOffset = (uint32_t)ftell(f); fwrite(¢ral, sizeof central, 1, f); fwrite(name.c_str(), name.size(), 1, f); end.entryNumber = 1; end.totalEntryNumber = 1; end.centralDirSize = (uint32_t)ftell(f) - end.centralDirOffset; fwrite(&end, sizeof end, 1, f); fclose(f); }