Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

192 eml email electronic mail format plugin #327

Merged
merged 27 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
40da23f
Merge branch 'main' of https://github.com/gdt050579/GView into 192-em…
Cosmin765 Mar 17, 2024
0741371
Merge branch '192-eml-email-electronic-mail-format-plugin' of https:/…
Cosmin765 May 3, 2024
b0c7994
Solve empty headers parsing for eml files
Cosmin765 May 5, 2024
6e3b8af
Add more info to ListItem elements
Cosmin765 May 5, 2024
7b68b0a
Avoid getting data
Cosmin765 May 10, 2024
6b9284d
Fix merge conflicts
Cosmin765 May 18, 2024
0dc58fd
Last sync
Cosmin765 Jun 1, 2024
ccdca64
Add primitive parsing for dir and Module streams
Cosmin765 Jun 1, 2024
855d7ad
Add support for extracting a stream from the vbaProject.bin file
Cosmin765 Jun 3, 2024
2961042
Refactor code and parse all VBA modules
Cosmin765 Jun 3, 2024
20c5821
Add naive VBA lexical display
Cosmin765 Jun 3, 2024
add20d4
Finish VBA dummy text parsing and find generic modules path within vb…
Cosmin765 Jun 4, 2024
3e15680
Add view for plugin
Cosmin765 Jun 5, 2024
8059285
Add info about vba and fix parsing bug for certain files
Cosmin765 Jun 5, 2024
e2aecbc
Fix decompress bug for multiple chunks
Cosmin765 Jun 5, 2024
f4e0cb0
Fix base64 trailing bytes & zip issue when opening archive from DataC…
Cosmin765 Jun 6, 2024
877bf8d
Add DocString to VBA module
Cosmin765 Jun 8, 2024
69644f0
Patch VBA parsing
Cosmin765 Jun 9, 2024
a6cba1c
Small refactoring
Cosmin765 Jun 10, 2024
ce4c70c
Merge branch 'main' into 192-eml-email-electronic-mail-format-plugin
gheorghitamutu Jul 26, 2024
6bdfcd9
Merge branch '192-eml-email-electronic-mail-format-plugin' into 315-s…
gheorghitamutu Jul 26, 2024
e8eee97
Merge pull request #325 from gdt050579/315-support-for-extracting-vba…
gheorghitamutu Jul 26, 2024
88a20f5
[EML][DOC] # fix build (merge issues)
gheorghitamutu Jul 26, 2024
c84639f
[DOC] # fix ubuntu build (header for log2 and ceil functions)
gheorghitamutu Jul 26, 2024
520a32e
[DOC] # fix CodeQL warnings
gheorghitamutu Jul 30, 2024
74bf523
Merge branch 'main' into 192-eml-email-electronic-mail-format-plugin
gheorghitamutu Jul 30, 2024
9da37ce
[EML] ^ AppCUI update
gheorghitamutu Jul 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ if(NOT DEFINED CMAKE_TESTING_ENABLED)
add_subdirectory(Types/SQLite)
add_subdirectory(Types/JCLASS)
add_subdirectory(Types/EML)
add_subdirectory(Types/JPG)
add_subdirectory(Types/DOC)
add_subdirectory(Types/JPG)

# Generic plugins supported by GView
add_subdirectory(GenericPlugins/CharacterTable)
Expand Down
7 changes: 4 additions & 3 deletions GViewCore/include/GView.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1068,15 +1068,15 @@ namespace View
return u16string_view{ text + start, (size_t) (end - start) };
return u16string_view();
}
uint32 ParseUntillEndOfLine(uint32 index) const;
uint32 ParseUntillStartOfNextLine(uint32 index) const;
uint32 ParseUntilEndOfLine(uint32 index) const;
uint32 ParseUntilStartOfNextLine(uint32 index) const;
uint32 Parse(uint32 index, bool (*validate)(char16 character)) const;
uint32 ParseBackwards(uint32 index, bool (*validate)(char16 character)) const;
uint32 ParseSameGroupID(uint32 index, uint32 (*charToID)(char16 character)) const;
uint32 ParseSpace(uint32 index, SpaceType type = SpaceType::SpaceAndTabs) const;
uint32 ParseString(uint32 index, StringFormat format = StringFormat::All) const;
uint32 ParseNumber(uint32 index, NumberFormat format = NumberFormat::All) const;
uint32 ParseUntillText(uint32 index, string_view textToFind, bool ignoreCase) const;
uint32 ParseUntilText(uint32 index, string_view textToFind, bool ignoreCase) const;
uint32 ParseUntilNextCharacterAfterText(uint32 index, string_view textToFind, bool ignoreCase) const;
uint64 ComputeHash64(uint32 start, uint32 end, bool ignoreCase) const;
uint32 ComputeHash32(uint32 start, uint32 end, bool ignoreCase) const;
Expand Down Expand Up @@ -1493,6 +1493,7 @@ namespace Unpack
namespace Base64
{
CORE_EXPORT void Encode(BufferView view, Buffer& output);
CORE_EXPORT bool Decode(BufferView view, Buffer& output, bool& hasWarning, String& warningMessage);
CORE_EXPORT bool Decode(BufferView view, Buffer& output);
} // namespace Base64
namespace QuotedPrintable
Expand Down
26 changes: 22 additions & 4 deletions GViewCore/src/Unpack/Base64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,16 @@ void Encode(BufferView view, Buffer& output)
output.AddMultipleTimes(string_view("=", 1), (3 - sequenceIndex) % 3);
}

bool Decode(BufferView view, Buffer& output)
bool Decode(BufferView view, Buffer& output, bool& hasWarning, String& warningMessage)
{
uint32 sequence = 0;
uint32 sequenceIndex = 0;
char lastEncoded = 0;
uint8 paddingCount = 0;
hasWarning = false;
output.Reserve((view.GetLength() / 4) * 3);

for (uint32 i = 0; i < view.GetLength(); ++i)
{
for (uint32 i = 0; i < view.GetLength(); ++i) {
char encoded = view[i];
CHECK(encoded < sizeof(BASE64_DECODE_TABLE) / sizeof(*BASE64_DECODE_TABLE), false, "");

Expand All @@ -60,7 +62,8 @@ bool Decode(BufferView view, Buffer& output)
}

if (lastEncoded == '=' && sequenceIndex == 0) {
AppCUI::Dialogs::MessageBox::ShowError("Warning!", "Ignoring extra bytes after the end of buffer");
hasWarning = true;
warningMessage = "Ignoring extra bytes after the end of buffer";
break;
}

Expand All @@ -69,6 +72,7 @@ bool Decode(BufferView view, Buffer& output)
if (encoded == '=') {
// padding
decoded = 0;
paddingCount++;
} else {
decoded = BASE64_DECODE_TABLE[encoded];
CHECK(decoded != -1, false, "");
Expand All @@ -79,6 +83,7 @@ bool Decode(BufferView view, Buffer& output)

if (sequenceIndex % 4 == 0) {
char* buffer = (char*) &sequence;

output.Add(string_view(buffer + 3, 1));
output.Add(string_view(buffer + 2, 1));
output.Add(string_view(buffer + 1, 1));
Expand All @@ -90,6 +95,19 @@ bool Decode(BufferView view, Buffer& output)
lastEncoded = encoded;
}

// trim the trailing bytes
CHECK(paddingCount < 3, false, "");
output.Resize(output.GetLength() - paddingCount);

return true;
}

bool Decode(BufferView view, Buffer& output)
{
bool tempHasWarning;
String tempWarningMessage;

return Decode(view, output, tempHasWarning, tempWarningMessage);
}

} // namespace GView::Unpack::Base64
8 changes: 4 additions & 4 deletions GViewCore/src/View/LexicalViewer/TextParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ TextParser::TextParser(u16string_view _text)
if (this->text == nullptr)
this->size = 0; // sanity check
}
uint32 TextParser::ParseUntillEndOfLine(uint32 index) const
uint32 TextParser::ParseUntilEndOfLine(uint32 index) const
{
if (index >= size)
return size;
Expand All @@ -114,7 +114,7 @@ uint32 TextParser::ParseUntillEndOfLine(uint32 index) const
}
return index;
}
uint32 TextParser::ParseUntillStartOfNextLine(uint32 index) const
uint32 TextParser::ParseUntilStartOfNextLine(uint32 index) const
{
if (index >= size)
return size;
Expand Down Expand Up @@ -225,7 +225,7 @@ uint32 TextParser::ParseSpace(uint32 index, SpaceType type) const
}
return index;
}
uint32 TextParser::ParseUntillText(uint32 index, string_view textToFind, bool ignoreCase) const
uint32 TextParser::ParseUntilText(uint32 index, string_view textToFind, bool ignoreCase) const
{
if (index >= size)
return size;
Expand Down Expand Up @@ -281,7 +281,7 @@ uint32 TextParser::ParseUntillText(uint32 index, string_view textToFind, bool ig
}
uint32 TextParser::ParseUntilNextCharacterAfterText(uint32 index, string_view textToFind, bool ignoreCase) const
{
auto pos = ParseUntillText(index, textToFind, ignoreCase);
auto pos = ParseUntilText(index, textToFind, ignoreCase);
if (pos >= size)
return size;
return pos + (uint32) textToFind.size();
Expand Down
38 changes: 35 additions & 3 deletions GViewCore/src/ZIP/zip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ bool GetInfo(std::u16string_view path, Info& info)

size_t entryIndex = internalInfo->entries.size();
auto& entry = internalInfo->entries.emplace_back();

ConvertZipFileInfoToEntry(zipFile, entry);

std::u8string_view filename = entry.filename;
Expand All @@ -388,7 +388,7 @@ bool GetInfo(std::u16string_view path, Info& info)
}

size_t offset = 0;

while (true) {
size_t pos = filename.find_first_of('/', offset);

Expand All @@ -399,7 +399,7 @@ bool GetInfo(std::u16string_view path, Info& info)
auto parentFilename = entry.filename.substr(0, pos + 1);

auto it = std::find_if(
internalInfo->entries.begin(), internalInfo->entries.end(), [&](const _Entry& e) -> bool { return e.filename == parentFilename; });
internalInfo->entries.begin(), internalInfo->entries.end(), [&](const _Entry& e) -> bool { return e.filename == parentFilename; });
if (it == internalInfo->entries.end()) {
auto& parentEntry = internalInfo->entries.emplace_back();
parentEntry.filename = parentFilename;
Expand Down Expand Up @@ -449,9 +449,41 @@ bool GetInfo(Utils::DataCache& cache, Info& info)
CHECKBK(mz_zip_reader_entry_get_info(internalInfo->reader.value, &zipFile) == MZ_OK, "");
mz_zip_reader_set_pattern(internalInfo->reader.value, nullptr, 1); // do we need a pattern?

size_t entryIndex = internalInfo->entries.size();
auto& entry = internalInfo->entries.emplace_back();

ConvertZipFileInfoToEntry(zipFile, entry);

std::u8string_view filename = entry.filename;
if (entry.type == EntryType::Directory && filename[filename.size() - 1] == '/') {
filename = { filename.data(), filename.size() - 1 };
}

size_t offset = 0;

while (true) {
size_t pos = filename.find_first_of('/', offset);

CHECKBK(pos != std::string::npos, "");

// add the parent as well if not already present
auto& entry = internalInfo->entries[entryIndex];
auto parentFilename = entry.filename.substr(0, pos + 1);

auto it = std::find_if(
internalInfo->entries.begin(), internalInfo->entries.end(), [&](const _Entry& e) -> bool { return e.filename == parentFilename; });
if (it == internalInfo->entries.end()) {
auto& parentEntry = internalInfo->entries.emplace_back();
parentEntry.filename = parentFilename;
parentEntry.filename_size = parentFilename.size();
parentEntry.type = EntryType::Directory;
parentEntry.version_madeby = entry.version_madeby;
parentEntry.version_needed = entry.version_needed;
}

offset = pos + 1;
}

CHECKBK(mz_zip_reader_goto_next_entry(internalInfo->reader.value) == MZ_OK, "");
} while (true);

Expand Down
96 changes: 2 additions & 94 deletions GenericPlugins/Unpacker/src/Unpacker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,8 @@ namespace GView::GenericPlugins::Unpackers
using namespace AppCUI::Graphics;
using namespace GView::View;

constexpr char BASE64_ENCODE_TABLE[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };

constexpr char BASE64_DECODE_TABLE[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 };

Plugin::Plugin() : Window("Unpacker", "d:c,w:140,h:40", WindowFlags::FixedPosition)
Plugin::Plugin() : Window("Unpackers", "d:c,w:140,h:40", WindowFlags::FixedPosition)
{
sync = Factory::CheckBox::Create(this, "&Unpackers", "x:2%,y:1,w:30");
sync->SetChecked(false);
Expand Down Expand Up @@ -70,7 +61,7 @@ void Plugin::Update()
}
list->DeleteAllItems();

auto item = list->AddItem({ "Cosmin", "ViewName", "CevaFormat", "Base64" });
auto item = list->AddItem({ "Ceva", "ViewName", "CevaFormat", "Base64" });

// auto desktop = AppCUI::Application::GetDesktop();
// const auto windowsNo = desktop->GetChildrenCount();
Expand Down Expand Up @@ -119,89 +110,6 @@ void Plugin::Update()
//}
}

void Plugin::Base64Encode(BufferView view, Buffer& output)
{
uint32 sequence = 0;
uint32 sequenceIndex = 0;

// TODO: same as before, pass something that doesn't need extra preprocessing
for (uint32 i = 0; i < view.GetLength(); i += 2) {
char decoded = view[i];

sequence |= decoded << ((3 - sequenceIndex) * 8);
sequenceIndex++;

if (sequenceIndex % 3 == 0) {
// get 4 encoded components out of this one
// 0x3f -> 0b00111111

char buffer[] = {
BASE64_ENCODE_TABLE[(sequence >> 26) & 0x3f],
BASE64_ENCODE_TABLE[(sequence >> 20) & 0x3f],
BASE64_ENCODE_TABLE[(sequence >> 14) & 0x3f],
BASE64_ENCODE_TABLE[(sequence >> 8) & 0x3f],
};

output.Add(string_view(buffer, 4));

sequence = 0;
sequenceIndex = 0;
}
}

output.AddMultipleTimes(string_view("=", 1), (3 - sequenceIndex) % 3);
}

bool Plugin::Base64Decode(BufferView view, Buffer& output)
{
uint32 sequence = 0;
uint32 sequenceIndex = 0;
char lastEncoded = 0;

// TODO: pass something else as a parameter, not needing extra pasing in the function
for (uint32 i = 0; i < view.GetLength(); i += 2) // skip the second byte in the character
{
char encoded = view[i];
CHECK(encoded < sizeof(BASE64_DECODE_TABLE) / sizeof(*BASE64_DECODE_TABLE), false, "");

if (encoded == '\r' || encoded == '\n') {
continue;
}

if (lastEncoded == '=' && sequenceIndex == 0) {
AppCUI::Dialogs::MessageBox::ShowError("Warning!", "Ignoring extra bytes after the end of buffer");
break;
}

uint32 decoded;

if (encoded == '=') {
// padding
decoded = 0;
} else {
decoded = BASE64_DECODE_TABLE[encoded];
CHECK(decoded != -1, false, "");
}

sequence |= decoded << (2 + (4 - sequenceIndex) * 6);
sequenceIndex++;

if (sequenceIndex % 4 == 0) {
char* buffer = (char*) &sequence;
output.Add(string_view(buffer + 3, 1));
output.Add(string_view(buffer + 2, 1));
output.Add(string_view(buffer + 1, 1));

sequence = 0;
sequenceIndex = 0;
}

lastEncoded = encoded;
}

return true;
}

// you're passing the callbacks - this needs to be statically allocated
// but you should lazy initialize it - so make it a pointer
static std::unique_ptr<GView::GenericPlugins::Unpackers::Plugin> plugin{ nullptr };
Expand Down
4 changes: 2 additions & 2 deletions Types/CPP/src/CPPFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ uint32 CPPFile::TokenizeOperator(const GView::View::LexicalViewer::TextParser& t
}
uint32 CPPFile::TokenizePreprocessDirective(const TextParser& text, TokensList& list, BlocksList& blocks, uint32 pos)
{
auto eol = text.ParseUntillEndOfLine(pos);
auto eol = text.ParseUntilEndOfLine(pos);
auto start = pos;
pos = text.ParseSpace(pos + 1, SpaceType::SpaceAndTabs);
if ((CharType::GetCharType(text[pos])) != CharType::Word)
Expand Down Expand Up @@ -742,7 +742,7 @@ void CPPFile::Tokenize(uint32 start, uint32 end, const TextParser& text, TokensL
idx = text.ParseSpace(idx, SpaceType::All);
break;
case CharType::SingleLineComment:
next = text.ParseUntillEndOfLine(idx);
next = text.ParseUntilEndOfLine(idx);
tokenList.Add(
TokenType::Comment,
idx,
Expand Down
2 changes: 2 additions & 0 deletions Types/DOC/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include(type)
create_type(DOC)
Loading
Loading