Skip to content

Commit

Permalink
Merge pull request #327 from gdt050579/192-eml-email-electronic-mail-…
Browse files Browse the repository at this point in the history
…format-plugin

192 eml email electronic mail format plugin
  • Loading branch information
gheorghitamutu authored Jul 30, 2024
2 parents 8214711 + 9da37ce commit 47c9509
Show file tree
Hide file tree
Showing 23 changed files with 1,545 additions and 191 deletions.
2 changes: 1 addition & 1 deletion AppCUI
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

0 comments on commit 47c9509

Please sign in to comment.