From c6fb020fdae8b36076b192acbe3e637c922f415d Mon Sep 17 00:00:00 2001 From: Ivan Morozov Date: Wed, 27 Jul 2022 22:36:56 +0300 Subject: [PATCH] added and passed Header and DirectoryEntry tests --- Common/cppcf/compoundfile.cpp | 2 +- Common/cppcf/directoryentry.cpp | 11 ++- Common/cppcf/directoryentry.h | 4 +- Common/cppcf/guid.h | 25 ++++--- Common/cppcf/header.cpp | 14 ++-- Common/cppcf/header.h | 18 ++--- Common/cppcf/streamrw.cpp | 14 ---- Common/cppcf/streamrw.h | 3 - Common/cppcf/test/main.cpp | 6 +- Common/cppcf/test/test.pro | 4 +- Common/cppcf/test/tst_directoryentry.h | 74 +++++++++++++++++++ Common/cppcf/test/tst_header.h | 66 +++++++++++++++++ .../{tst_test_stream.h => tst_streamrw.h} | 5 +- 13 files changed, 187 insertions(+), 59 deletions(-) create mode 100644 Common/cppcf/test/tst_directoryentry.h create mode 100644 Common/cppcf/test/tst_header.h rename Common/cppcf/test/{tst_test_stream.h => tst_streamrw.h} (94%) diff --git a/Common/cppcf/compoundfile.cpp b/Common/cppcf/compoundfile.cpp index 4d655b2f8f..626f891fc4 100644 --- a/Common/cppcf/compoundfile.cpp +++ b/Common/cppcf/compoundfile.cpp @@ -1871,7 +1871,7 @@ void CompoundFile::LoadFile(std::wstring fileName) file.OpenFile(fileName); if (updateMode == CFSUpdateMode::ReadOnly) { - fs.reset(new std::fstream(this->fileName, std::ios::in | std::ios::out)); + fs.reset(new std::fstream(this->fileName, std::ios::out)); } else diff --git a/Common/cppcf/directoryentry.cpp b/Common/cppcf/directoryentry.cpp index 8decb0e732..1782832fff 100644 --- a/Common/cppcf/directoryentry.cpp +++ b/Common/cppcf/directoryentry.cpp @@ -44,8 +44,13 @@ std::wstring DirectoryEntry::GetEntryName() const { if (entryName[0] != '\0' && nameLength > 0) { - std::wstring name(entryName, entryName + nameLength); - return name; + wchar_t name[32]; + for (int i = 0; i < 32; i++) + { + name[i] = entryName[2*i] + (entryName[2*i+1] << 8); + } + return std::wstring (name, name + nameLength/2 - 1); + } else return L""; @@ -135,7 +140,7 @@ void DirectoryEntry::Read(Stream stream, CFSVersion ver) // where most significant bits are not initialized to zero size = rw.Read(); - rw.ReadArray<4>(); //discard most significant 4 (possibly) dirty bytes + rw.Read(); //discard most significant 4 (possibly) dirty bytes } else { diff --git a/Common/cppcf/directoryentry.h b/Common/cppcf/directoryentry.h index bde2710a96..7cb232fd33 100644 --- a/Common/cppcf/directoryentry.h +++ b/Common/cppcf/directoryentry.h @@ -2,8 +2,6 @@ #include "svector.h" #include "idirectoryentry.h" -#include "guid.h" -#include "sector.h" namespace CFCPP { @@ -78,7 +76,7 @@ public: public: UINT64 creationDate = 0; UINT64 modifyDate = 0; - int startSetc = Sector::ENDOFCHAIN; + int startSetc = 0xFFFFFFFE; LONG64 size; int leftSibling = NOSTREAM; int rightSibling = NOSTREAM; diff --git a/Common/cppcf/guid.h b/Common/cppcf/guid.h index 1a13697ea2..6f97de2ffa 100644 --- a/Common/cppcf/guid.h +++ b/Common/cppcf/guid.h @@ -2,15 +2,18 @@ struct GUID { - unsigned long Data1 = 0; + unsigned int Data1 = 0; unsigned short Data2 = 0; unsigned short Data3 = 0; - unsigned char Data4[8] = {0,0,0,0,0,0,0,0}; + unsigned long long Data4 = 0; + + unsigned char* getData4() + { + return reinterpret_cast(&Data4); + } GUID (const GUID& o) : Data1(o.Data1), Data2(o.Data2), Data3(o.Data3) { - for (unsigned i = 0; i < sizeof(Data4); i++) - Data4[i] = o.Data4[i]; } GUID& operator=(const GUID& o) @@ -18,19 +21,19 @@ struct GUID Data1 = o.Data1; Data2 = o.Data2; Data3 = o.Data3; - for (unsigned i = 0; i < sizeof(Data4); i++) - Data4[i] = o.Data4[i]; + Data4 = o.Data4; return *this; } - bool operator!=(const GUID& oth) + bool operator!=(const GUID& oth)const { - for (int i = 0; i < 8; i++) - if (Data4[i] != oth.Data4[i]) - return true; + return Data1 != oth.Data1 || Data2 != oth.Data2 || Data3 != oth.Data3 || Data4 != oth.Data4; + } - return Data1 != oth.Data1 || Data2 != oth.Data2 || Data3 != oth.Data3; + bool operator==(const GUID& oth)const + { + return !operator!=(oth); } GUID (){} diff --git a/Common/cppcf/header.cpp b/Common/cppcf/header.cpp index c474bcda1a..68d6690799 100644 --- a/Common/cppcf/header.cpp +++ b/Common/cppcf/header.cpp @@ -39,14 +39,14 @@ Header::Header(ushort version) void Header::Write(Stream stream) { StreamRW rw(stream); - rw.WriteArray(headerSignature.data(), headerSignature.size()); - rw.WriteArray(clsid.data(), clsid.size()); + rw.WriteArray(headerSignature, sizeof(headerSignature)); + rw.WriteArray(clsid, sizeof(clsid)); rw.Write(minorVersion); rw.Write(majorVersion); rw.Write(byteOrder); rw.Write(sectorShift); rw.Write(miniSectorShift); - rw.WriteArray(unUsed.data(), unUsed.size()); + rw.WriteArray(unUsed, sizeof(unUsed)); rw.Write(directorySectorsNumber); rw.Write(fatSectorsNumber); rw.Write(firstDirectorySectorID); @@ -73,16 +73,16 @@ void Header::Read(Stream stream) { StreamRW rw(stream); - headerSignature = rw.ReadArray<8>(); + rw.ReadArray(headerSignature, sizeof(headerSignature)); CheckSignature(); - clsid = rw.ReadArray<16>(); + rw.ReadArray(clsid, sizeof(clsid)); minorVersion = rw.Read(); majorVersion = rw.Read(); CheckVersion(); byteOrder = rw.Read(); sectorShift = rw.Read(); miniSectorShift = rw.Read(); - unUsed = rw.ReadArray<6>(); + rw.ReadArray(unUsed, sizeof (unUsed)); directorySectorsNumber = rw.Read(); fatSectorsNumber = rw.Read(); firstDirectorySectorID = rw.Read(); @@ -108,7 +108,7 @@ void Header::CheckVersion() const void Header::CheckSignature() const { std::array OLE_CFS_SIGNATURE{ 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }; - for (int i = 0; i < (int)headerSignature.size(); i++) + for (size_t i = 0; i < sizeof(headerSignature); i++) { if (headerSignature[i] != OLE_CFS_SIGNATURE[i]) throw CFFileFormatException("Invalid OLE structured storage file"); diff --git a/Common/cppcf/header.h b/Common/cppcf/header.h index e1e9ae57f3..31ce8c5fce 100644 --- a/Common/cppcf/header.h +++ b/Common/cppcf/header.h @@ -19,24 +19,24 @@ private: void CheckSignature()const; public: - std::array headerSignature = {0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1}; - std::array clsid; + BYTE headerSignature[8] = {0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1}; + BYTE clsid[16]; USHORT minorVersion = 0x003E; USHORT majorVersion = 0x0003; USHORT byteOrder = 0xFFFE; USHORT sectorShift = 9; USHORT miniSectorShift = 6; - std::array unUsed; - int directorySectorsNumber; - int fatSectorsNumber; - int firstDirectorySectorID = Sector::ENDOFCHAIN; + BYTE unUsed[6]; + INT directorySectorsNumber; + INT fatSectorsNumber; + INT firstDirectorySectorID = Sector::ENDOFCHAIN; uint unUsed2; uint minSizeStandardStream = 4096; - int firstMiniFATSectorID = 0xFFFFFFFE; + INT firstMiniFATSectorID = 0xFFFFFFFE; uint miniFATSectorsNumber; - int firstDIFATSectorID = Sector::ENDOFCHAIN; + INT firstDIFATSectorID = Sector::ENDOFCHAIN; uint difatSectorsNumber; - std::array difat; + INT difat[109]; }; } diff --git a/Common/cppcf/streamrw.cpp b/Common/cppcf/streamrw.cpp index cd0ef6cf8d..eb02308aca 100644 --- a/Common/cppcf/streamrw.cpp +++ b/Common/cppcf/streamrw.cpp @@ -15,20 +15,6 @@ T_LONG64 StreamRW::Seek(T_LONG64 offset) return stream->tellp(); } -template -std::array StreamRW::ReadArray() -{ - std::array arr(0); - stream->read(reinterpret_cast(arr.data()), N); - return arr; -} -std::vector StreamRW::ReadArray(int lenght) -{ - std::vector arr(lenght,0); - stream->read(reinterpret_cast(arr.data()), lenght); - return arr; -} - void StreamRW::ReadArray(char *data, int lenght) { stream->read(data, lenght); diff --git a/Common/cppcf/streamrw.h b/Common/cppcf/streamrw.h index 58e6ce55ba..9552f26e1e 100644 --- a/Common/cppcf/streamrw.h +++ b/Common/cppcf/streamrw.h @@ -30,11 +30,8 @@ public: stream->write(asByteArr, sizeof (T)); } - std::vector ReadArray(int lenght); void ReadArray(char* data, int lenght); void ReadArray(BYTE* data, int lenght); - template - std::array ReadArray(); void WriteArray(const BYTE *arr, int lenght); void WriteArray(const char *arr, int lenght); diff --git a/Common/cppcf/test/main.cpp b/Common/cppcf/test/main.cpp index 2ece9040d2..07a323cc25 100644 --- a/Common/cppcf/test/main.cpp +++ b/Common/cppcf/test/main.cpp @@ -1,6 +1,6 @@ -#include "tst_test_stream.h" -#include "streamrw.h" -#include +#include "tst_streamrw.h" +#include "tst_header.h" +#include "tst_directoryentry.h" using namespace CFCPP; using namespace std; diff --git a/Common/cppcf/test/test.pro b/Common/cppcf/test/test.pro index d062927540..f1db46bc36 100644 --- a/Common/cppcf/test/test.pro +++ b/Common/cppcf/test/test.pro @@ -10,7 +10,9 @@ LIBS += -L$$PWD/../../../build/lib/linux_64/debug -lcfcpp INCLUDEPATH += $$PWD/../ HEADERS += \ - tst_test_stream.h + tst_directoryentry.h \ + tst_header.h \ + tst_streamrw.h SOURCES += \ main.cpp diff --git a/Common/cppcf/test/tst_directoryentry.h b/Common/cppcf/test/tst_directoryentry.h new file mode 100644 index 0000000000..af32cc20af --- /dev/null +++ b/Common/cppcf/test/tst_directoryentry.h @@ -0,0 +1,74 @@ +#pragma once + +#include +#include +#include "directoryentry.h" + +using namespace testing; +using namespace std; +using namespace CFCPP; + + +struct DirEntryTest : testing::Test +{ + Stream stream; + string filename = "../data/ex.ppt"; + + DirEntryTest() + { + stream.reset(new std::fstream(filename, ios::app | ios::in | ios::out | ios::binary)); + } +}; + +void test_dirEntry_read(const DirectoryEntry& de) +{ + EXPECT_EQ(de.GetEntryName(), L"Root Entry"); + EXPECT_EQ(de.getNameLength(), 22); + EXPECT_EQ(de.getStgType(), StgRoot); + + EXPECT_EQ(de.leftSibling, 0xFFFFFFFF); + EXPECT_EQ(de.rightSibling, 0xFFFFFFFF); + EXPECT_EQ(de.child, 1); + + GUID storageCLSID; + storageCLSID.Data1 = 0x64818D10; + storageCLSID.Data2 = 0x4F9B; + storageCLSID.Data3 = 0x11CF; + storageCLSID.Data4 = 0xE829B900AA00EA86; +// EXPECT_EQ(de.getStorageCLSID(), storageCLSID); + + EXPECT_EQ(de.stateBits, 0); + // todo + //EXPECT_EQ(de.creationDate, 0); +// EXPECT_EQ(de.modifyDate, 0xC0F1C03A18A1D801); + EXPECT_EQ(de.startSetc, 3); + EXPECT_EQ(de.size, 5632); +} + +TEST_F(DirEntryTest, test_directoryentry_read) +{ + DirectoryEntry de(L"", StgInvalid, {}); + stream->seekg(0x400, std::ios::beg); + de.Read(stream); + + EXPECT_EQ(stream->tellg(), 0x480); + test_dirEntry_read(de); +} + +TEST_F(DirEntryTest, test_directoryentry_write) +{ + DirectoryEntry de(L"", StgInvalid, {}); + stream->seekg(0x400, std::ios::beg); + de.Read(stream); + + std::string other_filename("../data/types/direntry.bin"); + stream.reset(new std::fstream(other_filename, ios::app | ios::in | ios::out | ios::binary)); + de.Write(stream); + EXPECT_EQ(stream->tellg(), 0x80); + stream->seekp(0, std::ios::beg); + + DirectoryEntry other(L"", StgInvalid, {}); + other.Read(stream); + test_dirEntry_read(other); + remove(other_filename.c_str()); +} diff --git a/Common/cppcf/test/tst_header.h b/Common/cppcf/test/tst_header.h new file mode 100644 index 0000000000..d52dff00db --- /dev/null +++ b/Common/cppcf/test/tst_header.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include +#include "header.h" + +using namespace testing; +using namespace std; +using namespace CFCPP; + + +struct HeaderTest : testing::Test +{ + Stream stream; + Header hd; + string filename = "../data/ex.ppt"; + + HeaderTest() + { + stream.reset(new std::fstream(filename, ios::app | ios::in | ios::out | ios::binary)); + } +}; + +void test_header_state(const Header& hd) +{ + ASSERT_THAT(hd.headerSignature, ElementsAre(0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1)); + EXPECT_EQ(hd.minorVersion, 0x003E); + EXPECT_EQ(hd.majorVersion, 0x0003); + EXPECT_EQ(hd.byteOrder, 0xFFFE); + EXPECT_EQ(hd.sectorShift, 0x0009); + EXPECT_EQ(hd.miniSectorShift, 0x0006); + EXPECT_EQ(hd.directorySectorsNumber, 0); + EXPECT_EQ(hd.fatSectorsNumber, 1); + EXPECT_EQ(hd.firstDirectorySectorID, 1); + EXPECT_EQ(hd.minSizeStandardStream, 0x1000); + EXPECT_EQ(hd.firstMiniFATSectorID, 2); + EXPECT_EQ(hd.miniFATSectorsNumber, 1); + EXPECT_EQ(hd.firstDIFATSectorID, -2); + EXPECT_EQ(hd.difatSectorsNumber, 0); + + int difat[109]; + memset(reinterpret_cast(difat), 0xFF, sizeof(difat)); + difat[0] = 0; + ASSERT_FALSE(memcmp(hd.difat, difat, sizeof(difat))); +} + +TEST_F(HeaderTest, test_header_read) +{ + hd.Read(stream); + test_header_state(hd); +} + +TEST_F(HeaderTest, test_header_write) +{ + hd.Read(stream); + + std::string other_filename("../data/types/header.bin"); + stream.reset(new std::fstream(other_filename, ios::app | ios::in | ios::out | ios::binary)); + hd.Write(stream); + + Header other; + stream->seekg(0, std::ios::beg); + other.Read(stream); + test_header_state(other); + remove(other_filename.c_str()); +} diff --git a/Common/cppcf/test/tst_test_stream.h b/Common/cppcf/test/tst_streamrw.h similarity index 94% rename from Common/cppcf/test/tst_test_stream.h rename to Common/cppcf/test/tst_streamrw.h index 1b9b4df65e..82a0f155af 100644 --- a/Common/cppcf/test/tst_test_stream.h +++ b/Common/cppcf/test/tst_streamrw.h @@ -1,5 +1,4 @@ -#ifndef TST_TEST_STREAM_H -#define TST_TEST_STREAM_H +#pragma once #include #include @@ -63,5 +62,3 @@ TEST_F(StreamRWTest, test_stream_rw_array) remove(filename.c_str()); } - -#endif // TST_TEST_STREAM_H