first worked version
This commit is contained in:
Родитель
dd2502c17c
Коммит
d0f3914ac1
|
@ -0,0 +1,63 @@
|
|||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
|
@ -0,0 +1,38 @@
|
|||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
out/
|
||||
|
||||
# Visual Studio temp files
|
||||
*.vcxproj.user
|
||||
*.sdf
|
||||
*.suo
|
||||
*.opensdf
|
||||
*.opendb
|
||||
*.VC.db
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
46
README.md
46
README.md
|
@ -1,2 +1,46 @@
|
|||
# compoundfilereader
|
||||
A simple header file to read Microsoft compound file(Structured Storage File) with minimal efforts.
|
||||
simple standalone c++ header file to read compound file (Structured Storage File) content.
|
||||
|
||||
# Source code structure
|
||||
- **src/include/compoundfilereader.h**
|
||||
The only header file needed for parsing compound file.
|
||||
- **src/include/utf.h**
|
||||
The helper header file used for converting between utf16, utf8, and unicode. It's used by samples.
|
||||
- **test/data**
|
||||
Real world compound files for tests.
|
||||
- **samples/cfb**
|
||||
command line tool to list and dump compound files.
|
||||
- **samples/IEOpenedTabParser**
|
||||
command line tool to show IE opened tab information.
|
||||
- **vsproject**
|
||||
project and solution files for Microsoft Visual Studio.
|
||||
|
||||
# Usage
|
||||
- copy compoundfilereader.h to your source tree
|
||||
or: install "compoundfilereader" by git sub-module
|
||||
- #include <compoundfilereader.h> in your source code
|
||||
- construct a **CompoundFileReader** object by giving the buffer (see compoundfilereader.h for details)
|
||||
|
||||
# Build the samples
|
||||
## Linux
|
||||
run `make'
|
||||
(requires gcc and g++)
|
||||
## Windows
|
||||
option1: double click 'vsproject\cfbreader\cfbreader.sln' then build in Visual Studio
|
||||
option2: run 'build.bat' in Visual Studio Command Prompt
|
||||
(requires visual studio)
|
||||
## Run the samples
|
||||
try the following:
|
||||
``` batchfile
|
||||
out/ieot "test/data/{BC59C035-E8AC-11E4-825B-10604B7CB9F0}.dat"
|
||||
out/cfb list "test/data/a test email message.msg"
|
||||
out/cfb dump "test/data/a test email message.msg" __properties_version1.0
|
||||
```
|
||||
|
||||
# TODO
|
||||
- unit tests
|
||||
- make the reader able to connect to abstract interfaces such as istream
|
||||
|
||||
#Microsoft Open Source Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
:: this script can only be run under visual studio tools command line
|
||||
:: (search "Command Prompt" on start menu to pick one)
|
||||
|
||||
devenv.com vsproject\cfbreader\cfbreader.sln /build Debug
|
|
@ -0,0 +1,21 @@
|
|||
IDIR=src/include
|
||||
CFBHDR=$(wildcard $(IDIR)/*.h)
|
||||
CC=g++
|
||||
CFLAGS=-I$(IDIR) -std=c++11 -Wall
|
||||
|
||||
ODIR=out
|
||||
|
||||
all: out/ieot out/cfb
|
||||
|
||||
out/ieot: samples/IEOpenedTabParser/openedtab.cpp samples/IEOpenedTabParser/IEOpenedTabParser.h $(CFBHDR)
|
||||
mkdir -p out
|
||||
$(CC) -o $@ $< $(CFLAGS)
|
||||
|
||||
out/cfb: samples/cfb/cfb.cpp $(CFBHDR)
|
||||
mkdir -p out
|
||||
$(CC) -o $@ $< $(CFLAGS)
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
clean:
|
||||
rm -rf out
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
IE opened tab dat file parser
|
||||
opened tab files are in %localappdata%\Microsoft\Internet Explorer\TabRoaming\{GUID}\NNNN, (N is digit 0-9).
|
||||
They are compound file.
|
||||
*/
|
||||
|
||||
#include <compoundfilereader.h>
|
||||
#include <utf.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct OPENED_TAB_INFO
|
||||
{
|
||||
std::wstring url;
|
||||
std::wstring title;
|
||||
std::wstring faviconUrl;
|
||||
};
|
||||
|
||||
struct OpenedTabFileParser
|
||||
{
|
||||
static const CFB::COMPOUND_FILE_ENTRY* GetOpenedTabPropertyStream(CFB::CompoundFileReader& reader)
|
||||
{
|
||||
const CFB::COMPOUND_FILE_ENTRY* entry = nullptr;
|
||||
reader.EnumFiles(reader.GetRootEntry(), -1,
|
||||
[&](const CFB::COMPOUND_FILE_ENTRY* e, const CFB::utf16string&, int)->void
|
||||
{
|
||||
if (reader.IsPropertyStream(e))
|
||||
{
|
||||
entry = e;
|
||||
}
|
||||
});
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static bool GetOpenedTabInfo(const void* buffer, size_t bufferLen, OPENED_TAB_INFO* info)
|
||||
{
|
||||
CFB::CompoundFileReader reader(buffer, bufferLen);
|
||||
const CFB::COMPOUND_FILE_ENTRY* propertyFile = GetOpenedTabPropertyStream(reader);
|
||||
|
||||
bool ret = false;
|
||||
if (propertyFile != nullptr && propertyFile->size <= std::numeric_limits<size_t>::max())
|
||||
{
|
||||
size_t size = static_cast<size_t>(propertyFile->size);
|
||||
|
||||
char* data = new char[size];
|
||||
reader.ReadFile(propertyFile, 0, data, size);
|
||||
CFB::PropertySetStream propertySetStream(data, size);
|
||||
CFB::PropertySet propertySet = propertySetStream.GetPropertySet(0);
|
||||
info->url = UTF16ToWstring(propertySet.GetStringProperty(3));
|
||||
info->title = UTF16ToWstring(propertySet.GetStringProperty(5));
|
||||
info->faviconUrl = UTF16ToWstring(propertySet.GetStringProperty(1002));
|
||||
ret = true;
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,52 @@
|
|||
#include "IEOpenedTabParser.h"
|
||||
#include <utf.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <clocale>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
#include <wchar.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
printf("please give a path\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE* fp = fopen(argv[1], "rb");
|
||||
if (fp == NULL)
|
||||
{
|
||||
perror("read file error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t len = ftell(fp);
|
||||
unsigned char* buffer = new unsigned char[len];
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
len = fread(buffer, 1, len, fp);
|
||||
printf("file length: %lu\n", len);
|
||||
|
||||
OPENED_TAB_INFO info;
|
||||
if (!OpenedTabFileParser::GetOpenedTabInfo(buffer, len, &info))
|
||||
{
|
||||
printf("cannot find the property set\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("url: %s\ntitle: %s\nfavicon url: %s\n",
|
||||
WstringToUTF8(info.url.c_str()).c_str(),
|
||||
WstringToUTF8(info.title.c_str()).c_str(),
|
||||
WstringToUTF8(info.faviconUrl.c_str()).c_str());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
#include <compoundfilereader.h>
|
||||
#include <utf.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void ShowUsage()
|
||||
{
|
||||
cout <<
|
||||
"usage:\n"
|
||||
"cfb list FILENAME\n"
|
||||
"cfb dump FILENAME STREAM_PATH\n"
|
||||
"cfb info FILENAME\n"
|
||||
"cfb info FILENAME STREAM_PATH\n"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
void DumpBuffer(const void* buffer, size_t len)
|
||||
{
|
||||
const unsigned char* str = static_cast<const unsigned char*>(buffer);
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
if (i > 0 && i % 16 == 0)
|
||||
cout << endl;
|
||||
cout << setw(2) << setfill('0') << hex << static_cast<int>(str[i]) << ' ';
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void DumpText(const char* buffer, size_t len)
|
||||
{
|
||||
cout << std::string(buffer, len) << endl;
|
||||
}
|
||||
|
||||
void OutputFileInfo(const CFB::CompoundFileReader& reader)
|
||||
{
|
||||
const CFB::COMPOUND_FILE_HDR* hdr = reader.GetFileInfo();
|
||||
cout
|
||||
<< "file version: " << hdr->majorVersion << "." << hdr->minorVersion << endl
|
||||
<< "difat sector: " << hdr->numDIFATSector << endl
|
||||
<< "directory sector: " << hdr->numDirectorySector << endl
|
||||
<< "fat sector: " << hdr->numFATSector << endl
|
||||
<< "mini fat sector: " << hdr->numMiniFATSector << endl;
|
||||
}
|
||||
|
||||
void OutputEntryInfo(const CFB::CompoundFileReader& reader, const CFB::COMPOUND_FILE_ENTRY* entry)
|
||||
{
|
||||
cout
|
||||
<< "entry type: " << (reader.IsPropertyStream(entry) ? "property" : (reader.IsStream(entry) ? "stream" : "directory")) << endl
|
||||
<< "color flag: " << entry->colorFlag << endl
|
||||
<< "creation time: " << entry->creationTime << endl
|
||||
<< "modified time: " << entry->modifiedTime << endl
|
||||
<< "child ID: " << entry->childID << endl
|
||||
<< "left sibling ID: " << entry->leftSiblingID << endl
|
||||
<< "right sibling ID: " << entry->startSectorLocation << entry->rightSiblingID << endl
|
||||
<< "start sector: " << entry->startSectorLocation << endl
|
||||
<< "size: " << entry->size << endl;
|
||||
}
|
||||
|
||||
const void ListDirectory(const CFB::CompoundFileReader& reader)
|
||||
{
|
||||
reader.EnumFiles(reader.GetRootEntry(), -1,
|
||||
[&](const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string& dir, int level)->void
|
||||
{
|
||||
bool isDirectory = !reader.IsStream(entry);
|
||||
std::string name = UTF16ToUTF8(entry->name);
|
||||
std::string indentstr(level * 4 - 4, ' ');
|
||||
cout << indentstr.c_str() << (isDirectory ? "[" : "") << name.c_str() << (isDirectory ? "]" : "") << endl;
|
||||
});
|
||||
}
|
||||
|
||||
const CFB::COMPOUND_FILE_ENTRY* FindStream(const CFB::CompoundFileReader& reader, const char* streamName)
|
||||
{
|
||||
const CFB::COMPOUND_FILE_ENTRY* ret = nullptr;
|
||||
reader.EnumFiles(reader.GetRootEntry(), -1,
|
||||
[&](const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string& u16dir, int level)->void
|
||||
{
|
||||
if (reader.IsStream(entry))
|
||||
{
|
||||
std::string name = UTF16ToUTF8(entry->name);
|
||||
if (u16dir.length() > 0)
|
||||
{
|
||||
std::string dir = UTF16ToUTF8(u16dir.c_str());
|
||||
if (strncmp(streamName, dir.c_str(), dir.length()) == 0 &&
|
||||
streamName[dir.length()] == '\\' &&
|
||||
strcmp(streamName + dir.length() + 1, name.c_str()) == 0)
|
||||
{
|
||||
ret = entry;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strcmp(streamName, name.c_str()) == 0)
|
||||
{
|
||||
ret = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main_internal(int argc, char* argv[])
|
||||
{
|
||||
const char* cmd = nullptr;
|
||||
const char* file = nullptr;
|
||||
const char* streamName = nullptr;
|
||||
bool dumpraw = false;
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
if (i == 1)
|
||||
{
|
||||
cmd = argv[i];
|
||||
}
|
||||
else if (strcmp(argv[i], "-r") == 0)
|
||||
{
|
||||
dumpraw = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file == nullptr)
|
||||
file = argv[i];
|
||||
else
|
||||
streamName = argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == nullptr || file == nullptr)
|
||||
{
|
||||
ShowUsage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE* fp = fopen(file, "rb");
|
||||
if (fp == NULL)
|
||||
{
|
||||
cerr << "read file error" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t len = ftell(fp);
|
||||
std::unique_ptr<unsigned char> buffer(new unsigned char[len]);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
len = fread(buffer.get(), 1, len, fp);
|
||||
CFB::CompoundFileReader reader(buffer.get(), len);
|
||||
|
||||
if (strcmp(cmd, "list") == 0)
|
||||
{
|
||||
ListDirectory(reader);
|
||||
}
|
||||
else if (strcmp(cmd, "dump") == 0 && streamName != nullptr)
|
||||
{
|
||||
const CFB::COMPOUND_FILE_ENTRY* entry = FindStream(reader, streamName);
|
||||
if (entry == nullptr)
|
||||
{
|
||||
cerr << "error: stream doesn't exist" << endl;
|
||||
return 2;
|
||||
}
|
||||
cout << "size: " << entry->size << endl;
|
||||
if (entry->size > std::numeric_limits<size_t>::max())
|
||||
{
|
||||
cerr << "error: stream too large" << endl;
|
||||
return 2;
|
||||
}
|
||||
size_t size = static_cast<size_t>(entry->size);
|
||||
std::unique_ptr<char> content(new char[size]);
|
||||
reader.ReadFile(entry, 0, content.get(), size);
|
||||
if (dumpraw)
|
||||
DumpText(content.get(), size);
|
||||
else
|
||||
DumpBuffer(content.get(), size);
|
||||
}
|
||||
else if (strcmp(cmd, "info") == 0)
|
||||
{
|
||||
if (streamName == nullptr)
|
||||
{
|
||||
OutputFileInfo(reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
const CFB::COMPOUND_FILE_ENTRY* entry = FindStream(reader, streamName);
|
||||
if (entry == NULL)
|
||||
{
|
||||
cerr << "error: stream doesn't exist" << endl;
|
||||
return 2;
|
||||
}
|
||||
OutputEntryInfo(reader, entry);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowUsage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
try
|
||||
{
|
||||
return main_internal(argc, argv);
|
||||
}
|
||||
catch (CFB::CFBException& e)
|
||||
{
|
||||
cerr << "error: " << e.what() << endl;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,480 @@
|
|||
/**
|
||||
Microsoft Compound File (and Property Set) Reader
|
||||
http://en.wikipedia.org/wiki/Compound_File_Binary_Format
|
||||
|
||||
Format specification:
|
||||
MS-CFB: https://msdn.microsoft.com/en-us/library/dd942138.aspx
|
||||
MS-OLEPS: https://msdn.microsoft.com/en-us/library/dd942421.aspx
|
||||
|
||||
Note:
|
||||
1. For simplification, the code assumes that the target system is little-endian.
|
||||
|
||||
2. The reader operates the passed buffer in-place.
|
||||
You must keep the input buffer valid when you are using the reader.
|
||||
|
||||
3. Single thread usage.
|
||||
|
||||
Example 1: print all streams in a compound file
|
||||
\code
|
||||
CFB::CompoundFileReader reader(buffer, len);
|
||||
reader.EnumFiles(reader.GetRootEntry(), -1,
|
||||
[&](const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string& dir, int level)->void
|
||||
{
|
||||
bool isDirectory = !reader.IsStream(entry);
|
||||
std::string name = UTF16ToUTF8(entry->name);
|
||||
std::string indentstr(level * 4, ' ');
|
||||
printf("%s%s%s%s\n", indentstr.c_str(), isDirectory ? "[" : "", name.c_str(), isDirectory ? "]" : "");
|
||||
});
|
||||
\endcode
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
|
||||
namespace CFB
|
||||
{
|
||||
struct CFBException : public std::runtime_error
|
||||
{
|
||||
CFBException(const char* desc) : std::runtime_error(desc) {}
|
||||
};
|
||||
struct WrongFormat : public CFBException
|
||||
{
|
||||
WrongFormat() : CFBException("Wrong file format") {}
|
||||
};
|
||||
struct FileCorrupted : public CFBException
|
||||
{
|
||||
FileCorrupted() : CFBException("File corrupted") {}
|
||||
};
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
struct COMPOUND_FILE_HDR
|
||||
{
|
||||
unsigned char signature[8];
|
||||
unsigned char unused_clsid[16];
|
||||
uint16_t minorVersion;
|
||||
uint16_t majorVersion;
|
||||
uint16_t byteOrder;
|
||||
uint16_t sectorShift;
|
||||
uint16_t miniSectorShift;
|
||||
unsigned char reserved[6];
|
||||
uint32_t numDirectorySector;
|
||||
uint32_t numFATSector;
|
||||
uint32_t firstDirectorySectorLocation;
|
||||
uint32_t transactionSignatureNumber;
|
||||
uint32_t miniStreamCutoffSize;
|
||||
uint32_t firstMiniFATSectorLocation;
|
||||
uint32_t numMiniFATSector;
|
||||
uint32_t firstDIFATSectorLocation;
|
||||
uint32_t numDIFATSector;
|
||||
uint32_t headerDIFAT[109];
|
||||
};
|
||||
|
||||
struct COMPOUND_FILE_ENTRY
|
||||
{
|
||||
uint16_t name[32];
|
||||
uint16_t nameLen;
|
||||
uint8_t type;
|
||||
uint8_t colorFlag;
|
||||
uint32_t leftSiblingID; // Note that it's actually the left/right child in the RB-tree.
|
||||
uint32_t rightSiblingID; // So entry.leftSibling.rightSibling does NOT go back to entry.
|
||||
uint32_t childID;
|
||||
unsigned char clsid[16];
|
||||
uint32_t stateBits;
|
||||
uint64_t creationTime;
|
||||
uint64_t modifiedTime;
|
||||
uint32_t startSectorLocation;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
struct PROPERTY_SET_STREAM_HDR
|
||||
{
|
||||
unsigned char byteOrder[2];
|
||||
uint16_t version;
|
||||
uint32_t systemIdentifier;
|
||||
unsigned char clsid[16];
|
||||
uint32_t numPropertySets;
|
||||
struct
|
||||
{
|
||||
char fmtid[16];
|
||||
uint32_t offset;
|
||||
} propertySetInfo[1];
|
||||
};
|
||||
|
||||
struct PROPERTY_SET_HDR
|
||||
{
|
||||
uint32_t size;
|
||||
uint32_t NumProperties;
|
||||
struct
|
||||
{
|
||||
uint32_t id;
|
||||
uint32_t offset;
|
||||
} propertyIdentifierAndOffset[1];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
const size_t MAXREGSECT = 0xFFFFFFFA;
|
||||
|
||||
struct helper
|
||||
{
|
||||
static uint32_t ParseUint32(const void* buffer)
|
||||
{
|
||||
return *static_cast<const uint32_t*>(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::basic_string<uint16_t> utf16string;
|
||||
typedef std::function<void(const COMPOUND_FILE_ENTRY*, const utf16string& dir, int level)>
|
||||
EnumFilesCallback;
|
||||
|
||||
class CompoundFileReader
|
||||
{
|
||||
public:
|
||||
CompoundFileReader(const void* buffer, size_t len)
|
||||
: m_buffer(static_cast<const unsigned char*>(buffer))
|
||||
, m_bufferLen(len)
|
||||
, m_hdr(static_cast<const COMPOUND_FILE_HDR*>(buffer))
|
||||
, m_sectorSize(512)
|
||||
, m_minisectorSize(64)
|
||||
, m_miniStreamStartSector(0)
|
||||
{
|
||||
if (buffer == NULL || len == 0) throw std::invalid_argument("");
|
||||
|
||||
if (m_bufferLen < sizeof(*m_hdr) ||
|
||||
memcmp(m_hdr->signature, "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1", 8) != 0)
|
||||
{
|
||||
throw WrongFormat();
|
||||
}
|
||||
|
||||
m_sectorSize = m_hdr->majorVersion == 3 ? 512 : 4096;
|
||||
|
||||
// The file must contains at least 3 sectors
|
||||
if (m_bufferLen < m_sectorSize * 3) throw FileCorrupted();
|
||||
|
||||
const COMPOUND_FILE_ENTRY* root = GetEntry(0);
|
||||
if (root == NULL) throw FileCorrupted();
|
||||
|
||||
m_miniStreamStartSector = root->startSectorLocation;
|
||||
}
|
||||
|
||||
/// Get entry (directory or file) by its ID.
|
||||
/// Pass "0" to get the root directory entry. -- This is the start point to navigate the compound file.
|
||||
/// Use the returned object to access child entries.
|
||||
const COMPOUND_FILE_ENTRY* GetEntry(size_t entryID) const
|
||||
{
|
||||
if (entryID == 0xFFFFFFFF)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (m_bufferLen / sizeof(COMPOUND_FILE_ENTRY) <= entryID)
|
||||
{
|
||||
throw std::invalid_argument("");
|
||||
}
|
||||
|
||||
size_t sector = 0;
|
||||
size_t offset = 0;
|
||||
LocateFinalSector(m_hdr->firstDirectorySectorLocation, entryID * sizeof(COMPOUND_FILE_ENTRY), §or, &offset);
|
||||
return reinterpret_cast<const COMPOUND_FILE_ENTRY*>(SectorOffsetToAddress(sector, offset));
|
||||
}
|
||||
|
||||
const COMPOUND_FILE_ENTRY* GetRootEntry() const
|
||||
{
|
||||
return GetEntry(0);
|
||||
}
|
||||
|
||||
const COMPOUND_FILE_HDR* GetFileInfo() const
|
||||
{
|
||||
return m_hdr;
|
||||
}
|
||||
|
||||
/// Get file(stream) data start with "offset".
|
||||
/// The buffer must have enough space to store "len" bytes. Typically "len" is derived by the steam length.
|
||||
void ReadFile(const COMPOUND_FILE_ENTRY* entry, size_t offset, char* buffer, size_t len) const
|
||||
{
|
||||
if (entry->size < offset || entry->size - offset < len) throw std::invalid_argument("");
|
||||
|
||||
if (entry->size < m_hdr->miniStreamCutoffSize)
|
||||
{
|
||||
ReadMiniStream(entry->startSectorLocation, offset, buffer, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadStream(entry->startSectorLocation, offset, buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsPropertyStream(const COMPOUND_FILE_ENTRY* entry) const
|
||||
{
|
||||
// defined in [MS-OLEPS] 2.23 "Property Set Stream and Storage Names"
|
||||
return entry->name[0] == 5;
|
||||
}
|
||||
|
||||
bool IsStream(const COMPOUND_FILE_ENTRY* entry) const
|
||||
{
|
||||
return entry->type == 2;
|
||||
}
|
||||
|
||||
void EnumFiles(const COMPOUND_FILE_ENTRY* entry, int maxLevel, EnumFilesCallback callback) const
|
||||
{
|
||||
utf16string dir;
|
||||
EnumNodes(GetEntry(entry->childID), 0, maxLevel, dir, callback);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Enum entries with same level, including 'entry' itself
|
||||
void EnumNodes(const COMPOUND_FILE_ENTRY* entry, int currentLevel, int maxLevel,
|
||||
const utf16string& dir, EnumFilesCallback callback) const
|
||||
{
|
||||
if (maxLevel > 0 && currentLevel >= maxLevel)
|
||||
return;
|
||||
if (entry == nullptr)
|
||||
return;
|
||||
|
||||
callback(entry, dir, currentLevel + 1);
|
||||
|
||||
const COMPOUND_FILE_ENTRY* child = GetEntry(entry->childID);
|
||||
if (child != nullptr)
|
||||
{
|
||||
utf16string newDir = dir;
|
||||
if (dir.length() != 0)
|
||||
newDir.append(1, '\n');
|
||||
newDir.append(entry->name, entry->nameLen / 2);
|
||||
EnumNodes(GetEntry(entry->childID), currentLevel + 1, maxLevel, newDir, callback);
|
||||
}
|
||||
|
||||
EnumNodes(GetEntry(entry->leftSiblingID), currentLevel, maxLevel, dir, callback);
|
||||
EnumNodes(GetEntry(entry->rightSiblingID), currentLevel, maxLevel, dir, callback);
|
||||
}
|
||||
|
||||
void ReadStream(size_t sector, size_t offset, char* buffer, size_t len) const
|
||||
{
|
||||
LocateFinalSector(sector, offset, §or, &offset);
|
||||
|
||||
// copy as many as possible in each step
|
||||
// copylen typically iterate as: m_sectorSize - offset --> m_sectorSize --> m_sectorSize --> ... --> remaining
|
||||
while (len > 0)
|
||||
{
|
||||
const unsigned char* src = SectorOffsetToAddress(sector, offset);
|
||||
size_t copylen = std::min(len, m_sectorSize - offset);
|
||||
if (m_buffer + m_bufferLen < src + copylen) throw FileCorrupted();
|
||||
|
||||
memcpy(buffer, src, copylen);
|
||||
buffer += copylen;
|
||||
len -= copylen;
|
||||
sector = GetNextSector(sector);
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Same logic as "ReadStream" except that use MiniStream functions instead
|
||||
void ReadMiniStream(size_t sector, size_t offset, char* buffer, size_t len) const
|
||||
{
|
||||
LocateFinalMiniSector(sector, offset, §or, &offset);
|
||||
|
||||
// copy as many as possible in each step
|
||||
// copylen typically iterate as: m_sectorSize - offset --> m_sectorSize --> m_sectorSize --> ... --> remaining
|
||||
while (len > 0)
|
||||
{
|
||||
const unsigned char* src = MiniSectorOffsetToAddress(sector, offset);
|
||||
size_t copylen = std::min(len, m_minisectorSize - offset);
|
||||
if (m_buffer + m_bufferLen < src + copylen) throw FileCorrupted();
|
||||
|
||||
memcpy(buffer, src, copylen);
|
||||
buffer += copylen;
|
||||
len -= copylen;
|
||||
sector = GetNextMiniSector(sector);
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t GetNextSector(size_t sector) const
|
||||
{
|
||||
// lookup FAT
|
||||
size_t entriesPerSector = m_sectorSize / 4;
|
||||
size_t fatSectorNumber = sector / entriesPerSector;
|
||||
size_t fatSectorLocation = GetFATSectorLocation(fatSectorNumber);
|
||||
return helper::ParseUint32(SectorOffsetToAddress(fatSectorLocation, sector % entriesPerSector * 4));
|
||||
}
|
||||
|
||||
size_t GetNextMiniSector(size_t miniSector) const
|
||||
{
|
||||
size_t sector, offset;
|
||||
LocateFinalSector(m_hdr->firstMiniFATSectorLocation, miniSector * 4, §or, &offset);
|
||||
return helper::ParseUint32(SectorOffsetToAddress(sector, offset));
|
||||
}
|
||||
|
||||
// Get absolute address from sector and offset.
|
||||
const unsigned char* SectorOffsetToAddress(size_t sector, size_t offset) const
|
||||
{
|
||||
if (sector >= MAXREGSECT ||
|
||||
offset >= m_sectorSize ||
|
||||
m_bufferLen <= static_cast<uint64_t>(m_sectorSize) * sector + m_sectorSize + offset)
|
||||
{
|
||||
throw FileCorrupted();
|
||||
}
|
||||
|
||||
return m_buffer + m_sectorSize + m_sectorSize * sector + offset;
|
||||
}
|
||||
|
||||
const unsigned char* MiniSectorOffsetToAddress(size_t sector, size_t offset) const
|
||||
{
|
||||
if (sector >= MAXREGSECT ||
|
||||
offset >= m_minisectorSize ||
|
||||
m_bufferLen <= static_cast<uint64_t>(m_minisectorSize) * sector + offset)
|
||||
{
|
||||
throw FileCorrupted();
|
||||
}
|
||||
|
||||
|
||||
LocateFinalSector(m_miniStreamStartSector, sector * m_minisectorSize + offset, §or, &offset);
|
||||
return SectorOffsetToAddress(sector, offset);
|
||||
}
|
||||
|
||||
// Locate the final sector/offset when original offset expands multiple sectors
|
||||
void LocateFinalSector(size_t sector, size_t offset, size_t* finalSector, size_t* finalOffset) const
|
||||
{
|
||||
while (offset >= m_sectorSize)
|
||||
{
|
||||
offset -= m_sectorSize;
|
||||
sector = GetNextSector(sector);
|
||||
}
|
||||
*finalSector = sector;
|
||||
*finalOffset = offset;
|
||||
}
|
||||
|
||||
void LocateFinalMiniSector(size_t sector, size_t offset, size_t* finalSector, size_t* finalOffset) const
|
||||
{
|
||||
while (offset >= m_minisectorSize)
|
||||
{
|
||||
offset -= m_minisectorSize;
|
||||
sector = GetNextMiniSector(sector);
|
||||
}
|
||||
*finalSector = sector;
|
||||
*finalOffset = offset;
|
||||
}
|
||||
|
||||
size_t GetFATSectorLocation(size_t fatSectorNumber) const
|
||||
{
|
||||
if (fatSectorNumber < 109)
|
||||
{
|
||||
return m_hdr->headerDIFAT[fatSectorNumber];
|
||||
}
|
||||
else
|
||||
{
|
||||
fatSectorNumber -= 109;
|
||||
size_t entriesPerSector = m_sectorSize / 4 - 1;
|
||||
size_t difatSectorLocation = m_hdr->firstDIFATSectorLocation;
|
||||
while (fatSectorNumber >= entriesPerSector)
|
||||
{
|
||||
fatSectorNumber -= entriesPerSector;
|
||||
const unsigned char* addr = SectorOffsetToAddress(difatSectorLocation, m_sectorSize - 4);
|
||||
difatSectorLocation = helper::ParseUint32(addr);
|
||||
}
|
||||
return helper::ParseUint32(SectorOffsetToAddress(difatSectorLocation, fatSectorNumber * 4));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const unsigned char * m_buffer;
|
||||
size_t m_bufferLen;
|
||||
|
||||
const COMPOUND_FILE_HDR* m_hdr;
|
||||
size_t m_sectorSize;
|
||||
size_t m_minisectorSize;
|
||||
size_t m_miniStreamStartSector;
|
||||
};
|
||||
|
||||
class PropertySet
|
||||
{
|
||||
public:
|
||||
PropertySet(const void* buffer, size_t len, const char* fmtid)
|
||||
: m_buffer(static_cast<const unsigned char*>(buffer))
|
||||
, m_bufferLen(len)
|
||||
, m_hdr(reinterpret_cast<const PROPERTY_SET_HDR*>(buffer))
|
||||
, m_fmtid(fmtid)
|
||||
{
|
||||
if (m_bufferLen < sizeof(*m_hdr) ||
|
||||
m_bufferLen < sizeof(*m_hdr) + (m_hdr->NumProperties - 1) * sizeof(m_hdr->propertyIdentifierAndOffset[0]))
|
||||
{
|
||||
throw FileCorrupted();
|
||||
}
|
||||
}
|
||||
|
||||
/// return the string property in UTF-16 format
|
||||
const uint16_t* GetStringProperty(uint32_t propertyID)
|
||||
{
|
||||
for (uint32_t i = 0; i < m_hdr->NumProperties; i++)
|
||||
{
|
||||
if (m_hdr->propertyIdentifierAndOffset[i].id == propertyID)
|
||||
{
|
||||
uint32_t offset = m_hdr->propertyIdentifierAndOffset[i].offset;
|
||||
if (m_bufferLen < offset + 8) throw FileCorrupted();
|
||||
uint32_t stringLengthInChar = helper::ParseUint32(m_buffer + offset + 4);
|
||||
if (m_bufferLen < offset + 8 + stringLengthInChar*2) throw FileCorrupted();
|
||||
return reinterpret_cast<const uint16_t*>(m_buffer + offset + 8);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Note: Getting property of types other than "string" is not implemented yet.
|
||||
/// However most other types are simpler than string so can be easily added. see [MS-OLEPS]
|
||||
|
||||
const char* GetFmtID()
|
||||
{
|
||||
return m_fmtid;
|
||||
}
|
||||
|
||||
private:
|
||||
const unsigned char* m_buffer;
|
||||
size_t m_bufferLen;
|
||||
const PROPERTY_SET_HDR* m_hdr;
|
||||
const char* m_fmtid; // 16 bytes
|
||||
};
|
||||
|
||||
class PropertySetStream
|
||||
{
|
||||
public:
|
||||
PropertySetStream(const void* buffer, size_t len)
|
||||
: m_buffer(static_cast<const unsigned char*>(buffer))
|
||||
, m_bufferLen(len)
|
||||
, m_hdr(reinterpret_cast<const PROPERTY_SET_STREAM_HDR*>(buffer))
|
||||
{
|
||||
if (m_bufferLen < sizeof(*m_hdr) ||
|
||||
m_bufferLen < sizeof(*m_hdr) + (m_hdr->numPropertySets - 1) * sizeof(m_hdr->propertySetInfo[0]))
|
||||
{
|
||||
throw FileCorrupted();
|
||||
}
|
||||
}
|
||||
|
||||
size_t GetPropertySetCount()
|
||||
{
|
||||
return m_hdr->numPropertySets;
|
||||
}
|
||||
|
||||
PropertySet GetPropertySet(size_t index)
|
||||
{
|
||||
if (index >= GetPropertySetCount()) throw FileCorrupted();
|
||||
uint32_t offset = m_hdr->propertySetInfo[index].offset;
|
||||
if (m_bufferLen < offset + 4) throw FileCorrupted();
|
||||
uint32_t size = helper::ParseUint32(m_buffer + offset);
|
||||
if (m_bufferLen < offset + size) throw FileCorrupted();
|
||||
return PropertySet(m_buffer + offset, size, m_hdr->propertySetInfo[index].fmtid);
|
||||
}
|
||||
|
||||
private:
|
||||
const unsigned char * m_buffer;
|
||||
size_t m_bufferLen;
|
||||
const PROPERTY_SET_STREAM_HDR* m_hdr;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
template <typename T>
|
||||
static bool GetNextCodePointFromUTF16z(const T* u16, size_t* pos, uint32_t* cp)
|
||||
{
|
||||
*cp = static_cast<uint32_t>(u16[*pos]);
|
||||
if (*cp == 0)
|
||||
return false;
|
||||
|
||||
(*pos)++;
|
||||
if ((*cp & 0xFC00) == 0xD800)
|
||||
{
|
||||
uint16_t cp2 = static_cast<uint16_t>(u16[*pos]);
|
||||
if ((cp2 & 0xFC00) == 0xDC00)
|
||||
{
|
||||
(*pos)++;
|
||||
*cp = (*cp << 10) + cp2 - 0x35FDC00;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool GetNextCodePointFromUTF16(const T* u16, size_t len, size_t* pos, uint32_t* cp)
|
||||
{
|
||||
if (len == 0)
|
||||
return GetNextCodePointFromUTF16z(u16, pos, cp);
|
||||
|
||||
if (*pos >= len)
|
||||
return false;
|
||||
|
||||
*cp = static_cast<uint32_t>(u16[*pos]);
|
||||
(*pos)++;
|
||||
if ((*cp & 0xFC00) == 0xD800)
|
||||
{
|
||||
if (*pos < len)
|
||||
{
|
||||
uint16_t cp2 = static_cast<uint16_t>(u16[*pos]);
|
||||
if ((cp2 & 0xFC00) == 0xDC00)
|
||||
{
|
||||
(*pos)++;
|
||||
*cp = (*cp << 10) + cp2 - 0x35FDC00;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int CodePointToUTF8(uint32_t cp, uint32_t* c1, uint32_t* c2, uint32_t* c3, uint32_t* c4)
|
||||
{
|
||||
if (cp < 0x80)
|
||||
{
|
||||
*c1 = cp;
|
||||
return 1;
|
||||
}
|
||||
else if (cp <= 0x7FF)
|
||||
{
|
||||
*c1 = (cp >> 6) + 0xC0;
|
||||
*c2 = (cp & 0x3F) + 0x80;
|
||||
return 2;
|
||||
}
|
||||
else if (cp <= 0xFFFF)
|
||||
{
|
||||
*c1 = (cp >> 12) + 0xE0;
|
||||
*c2 = ((cp >> 6) & 0x3F) + 0x80;
|
||||
*c3 = (cp & 0x3F) + 0x80;
|
||||
return 3;
|
||||
}
|
||||
else if (cp <= 0x10FFFF)
|
||||
{
|
||||
*c1 = (cp >> 18) + 0xF0;
|
||||
*c2 = ((cp >> 12) & 0x3F) + 0x80;
|
||||
*c3 = ((cp >> 6) & 0x3F) + 0x80;
|
||||
*c4 = (cp & 0x3F) + 0x80;
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string UTF16ToUTF8(const T* u16, size_t len = 0)
|
||||
{
|
||||
std::string u8;
|
||||
uint32_t cp;
|
||||
size_t pos = 0;
|
||||
while (GetNextCodePointFromUTF16(u16, len, &pos, &cp))
|
||||
{
|
||||
uint32_t c[4];
|
||||
int count = CodePointToUTF8(cp, c, c+1, c+2, c+3);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
u8 += static_cast<char>(c[i]);
|
||||
}
|
||||
}
|
||||
return u8;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::wstring UTF16ToWstring(const T* u16, size_t len = 0)
|
||||
{
|
||||
std::wstring ret;
|
||||
#ifdef _MSC_VER
|
||||
while (*u16) ret += *u16++;
|
||||
#else
|
||||
uint32_t cp;
|
||||
size_t pos = 0;
|
||||
while (GetNextCodePointFromUTF16(u16, len, &pos, &cp))
|
||||
{
|
||||
ret += cp;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string WstringToUTF8(const T* wstr)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return UTF16ToUTF8(wstr);
|
||||
#else
|
||||
std::string u8;
|
||||
uint32_t cp;
|
||||
while ((cp = *wstr++) != 0)
|
||||
{
|
||||
uint32_t c[4];
|
||||
int count = CodePointToUTF8(cp, c, c+1, c+2, c+3);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
u8 += static_cast<char>(c[i]);
|
||||
}
|
||||
}
|
||||
return u8;
|
||||
#endif
|
||||
}
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{7CD5AD07-5FE9-465D-A290-CAB53C97D545}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>IEOpenedTabParser</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)..\..\out\</OutDir>
|
||||
<IntDir>$(SolutionDir)..\..\out\intermediate\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)..\..\out\</OutDir>
|
||||
<IntDir>$(SolutionDir)..\..\out\intermediate\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)/../../src/include</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)/../../src/include</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\samples\IEOpenedTabParser\IEOpenedTabParser.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\samples\IEOpenedTabParser\openedtab.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\samples\IEOpenedTabParser\IEOpenedTabParser.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\samples\IEOpenedTabParser\openedtab.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{CED76631-0BBD-4775-9284-E3CF0E5A7A92}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>cfb</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)..\..\out\</OutDir>
|
||||
<IntDir>$(SolutionDir)..\..\out\intermediate\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)..\..\out\</OutDir>
|
||||
<IntDir>$(SolutionDir)..\..\out\intermediate\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)/../../src/include</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)/../../src/include</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\samples\cfb\cfb.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\samples\cfb\cfb.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.21005.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IEOpenedTabParser", "IEOpenedTabParser\IEOpenedTabParser.vcxproj", "{7CD5AD07-5FE9-465D-A290-CAB53C97D545}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cfb", "cfb\cfb.vcxproj", "{CED76631-0BBD-4775-9284-E3CF0E5A7A92}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{7CD5AD07-5FE9-465D-A290-CAB53C97D545}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{7CD5AD07-5FE9-465D-A290-CAB53C97D545}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{7CD5AD07-5FE9-465D-A290-CAB53C97D545}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{7CD5AD07-5FE9-465D-A290-CAB53C97D545}.Release|Win32.Build.0 = Release|Win32
|
||||
{CED76631-0BBD-4775-9284-E3CF0E5A7A92}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{CED76631-0BBD-4775-9284-E3CF0E5A7A92}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{CED76631-0BBD-4775-9284-E3CF0E5A7A92}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{CED76631-0BBD-4775-9284-E3CF0E5A7A92}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
Загрузка…
Ссылка в новой задаче