Skip to content

Commit

Permalink
Merge pull request #304 from gdt050579/300-eml-add-more-descriptions-…
Browse files Browse the repository at this point in the history
…to-the-eml-plugin

300 eml add more descriptions to the eml plugin
  • Loading branch information
rzaharia authored Apr 17, 2024
2 parents 5e848d9 + 08e9765 commit 9a6fcac
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 11 deletions.
16 changes: 12 additions & 4 deletions GViewCore/include/GView.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1437,11 +1437,19 @@ namespace App

}; // namespace App

namespace Unpack::Base64
namespace Unpack
{
CORE_EXPORT void Encode(BufferView view, Buffer& output);
CORE_EXPORT bool Decode(BufferView view, Buffer& output);
}
namespace Base64
{
CORE_EXPORT void Encode(BufferView view, Buffer& output);
CORE_EXPORT bool Decode(BufferView view, Buffer& output);
} // namespace Base64
namespace QuotedPrintable
{
CORE_EXPORT void Encode(BufferView view, Buffer& output);
CORE_EXPORT bool Decode(BufferView view, Buffer& output);
} // namespace QuotedPrintable
} // namespace Unpack
}; // namespace GView

ADD_FLAG_OPERATORS(GView::View::LexicalViewer::StringFormat, AppCUI::uint32);
Expand Down
1 change: 1 addition & 0 deletions GViewCore/src/Unpack/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
target_sources(GViewCore PRIVATE
Base64.cpp
QuotedPrintable.cpp
)
96 changes: 96 additions & 0 deletions GViewCore/src/Unpack/QuotedPrintable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include "Internal.hpp"

//TODO: THIS WAS NOT TESTED!
void GView::Unpack::QuotedPrintable::Encode(BufferView view, Buffer& output)
{
// Iterate over each character in the input buffer
for (size_t i = 0; i < view.GetLength(); i++) {
// Get the current character
const char character = view[i];

// Check if the character is printable
if (character >= 33 && character <= 126) {
// Write the character to the output buffer
output.Add(string_view(&character, 1));
} else {
// Write the character to the output buffer
output.Add(string_view("=", 1));

// Convert the character to its hexadecimal representation
char hex1 = (character >> 4) & 0xF;
char hex2 = character & 0xF;

// Convert the hexadecimal digits to their ASCII representation
hex1 = (hex1 < 10) ? hex1 + '0' : hex1 - 10 + 'A';
hex2 = (hex2 < 10) ? hex2 + '0' : hex2 - 10 + 'A';

// Write the hexadecimal digits to the output buffer
output.Add(string_view(&hex1, 1));
output.Add(string_view(&hex2, 1));
}
}
}

//TODO: Consider more testing!
bool GView::Unpack::QuotedPrintable::Decode(BufferView view, Buffer& output)
{
char temp_buffer[2] = {};
// Iterate over each character in the input buffer
for (size_t i = 0; i < view.GetLength(); i++) {
// Check if the character is an encoded character
if (view[i] == '=') {
// Check if there are enough characters remaining for an encoded sequence
if (i + 2 < view.GetLength()) {
// Get the two hexadecimal digits following the '=' character
const char hex1 = view[i + 1];
const char hex2 = view[i + 2];

if (hex1 == '2' && hex2 == 'E') {
temp_buffer[0] = '.';
output.Add(string_view(temp_buffer, 1));
i += 2;
continue;
}
if (hex1 == '\r' && hex2 == '\n') {
i += 2;
continue;
}

// Convert the hexadecimal digits to their decimal values
int value = 0;
if (hex1 >= '0' && hex1 <= '9') {
value += (hex1 - '0') * 16;
} else if (hex1 >= 'A' && hex1 <= 'F') {
value += (hex1 - 'A' + 10) * 16;
} else if (hex1 >= 'a' && hex1 <= 'f') {
value += (hex1 - 'a' + 10) * 16;
}

if (hex2 >= '0' && hex2 <= '9') {
value += hex2 - '0';
} else if (hex2 >= 'A' && hex2 <= 'F') {
value += hex2 - 'A' + 10;
} else if (hex2 >= 'a' && hex2 <= 'f') {
value += hex2 - 'a' + 10;
}

// Write the decoded character to the output buffer
temp_buffer[0] = static_cast<char>(value);
output.Add(string_view(temp_buffer, 1));

// Skip the next two characters in the input buffer
i += 2;
} else {
// If '=' is at the end of the line, it should be treated as a literal '='
temp_buffer[0] = '=';
output.Add(string_view(temp_buffer, 1));
}
} else {
// Write the character to the output buffer
temp_buffer[0] = view[i];
output.Add(string_view(temp_buffer, 1));
}
}

return true;
}
1 change: 1 addition & 0 deletions Types/EML/include/eml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace Type
std::optional<std::u16string> TryGetNameQuotes(std::u16string& contentTypeToSearch, bool removeIfFound = false);
std::u16string GetIdentifierFromContentType(std::u16string& contentTypeToChange);
std::u16string GetBufferNameFromHeaderFields();
std::u16string GetGViewFileName(const std::u16string& value, const std::u16string& prefix);
std::vector<std::pair<std::u16string, std::u16string>> headerFields;

void ParsePart(GView::View::LexicalViewer::TextParser text, uint32 start, uint32 end);
Expand Down
40 changes: 33 additions & 7 deletions Types/EML/src/EMLFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,22 +105,34 @@ void EMLFile::OnOpenItem(std::u16string_view path, AppCUI::Controls::TreeViewIte
BufferView itemBufferView(bufferView.GetData() + itemData->startIndex, itemData->dataLength);

if (!itemData->leafNode) {
GView::App::OpenBuffer(itemBufferView, currentContentType, path, GView::App::OpenMethod::ForceType, "eml");
auto bufferName = GetGViewFileName(currentContentType, itemData->identifier);
GView::App::OpenBuffer(itemBufferView, bufferName, path, GView::App::OpenMethod::ForceType, "eml");
} else {
const auto& encodingHeader =
std::find_if(headerFields.begin(), headerFields.end(), [](const auto& item) { return item.first == u"Content-Transfer-Encoding"; });

if (encodingHeader != headerFields.end() && encodingHeader->second == u"base64") {
const auto headerValueName = GetBufferNameFromHeaderFields();
const auto bufferName = GetGViewFileName(headerValueName, itemData->identifier);

if (encodingHeader != headerFields.end()) {
Buffer output;
if (GView::Unpack::Base64::Decode(itemBufferView, output)) {
auto bufferName = GetBufferNameFromHeaderFields();
GView::App::OpenBuffer(output, bufferName, path, GView::App::OpenMethod::BestMatch);
if (encodingHeader->second == u"base64") {
if (GView::Unpack::Base64::Decode(itemBufferView, output)) {
GView::App::OpenBuffer(output, bufferName, path, GView::App::OpenMethod::BestMatch);
} else {
AppCUI::Dialogs::MessageBox::ShowError("Error!", "Malformed base64 buffer!");
}
} else if (encodingHeader->second == u"quoted-printable") {
if (GView::Unpack::QuotedPrintable::Decode(itemBufferView, output)) {
GView::App::OpenBuffer(output, bufferName, path, GView::App::OpenMethod::BestMatch);
} else {
AppCUI::Dialogs::MessageBox::ShowError("Error!", "Malformed quoted-printable buffer!");
}
} else {
AppCUI::Dialogs::MessageBox::ShowError("Error!", "Malformed base64 buffer!");
GView::App::OpenBuffer(itemBufferView, bufferName, path, GView::App::OpenMethod::BestMatch);
}

} else {
auto bufferName = GetBufferNameFromHeaderFields();
GView::App::OpenBuffer(itemBufferView, bufferName, path, GView::App::OpenMethod::BestMatch);
}
}
Expand Down Expand Up @@ -223,6 +235,20 @@ std::u16string EMLFile::GetBufferNameFromHeaderFields()
return std::u16string(obj->GetName());
}

std::u16string EMLFile::GetGViewFileName(const std::u16string& value, const std::u16string& prefix)
{
LocalUnicodeStringBuilder<64> sb = {};
if (!prefix.empty()) {
sb.Add(prefix);
sb.AddChar(':');
sb.AddChar(' ');
}
sb.Add(value);
std::u16string output;
sb.ToString(output);
return output;
}

void EMLFile::ParsePart(GView::View::LexicalViewer::TextParser text, uint32 start, uint32 end)
{
ParseHeaders(text, start);
Expand Down

0 comments on commit 9a6fcac

Please sign in to comment.