Skip to content

Commit

Permalink
PDF - fixed trailer endBuffer, added table of sections with GOTO and …
Browse files Browse the repository at this point in the history
…Select
  • Loading branch information
D1n03 committed Aug 19, 2024
1 parent e057bf6 commit df60e9f
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 11 deletions.
37 changes: 32 additions & 5 deletions Types/PDF/include/pdf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ namespace Type
constexpr uint8_t PDF_TRUE_SIZE = 4;
constexpr uint8_t PDF_FALSE[] = "false";
constexpr uint8_t PDF_FALSE_SIZE = 5;
constexpr uint8_t PDF_NULL[] = "null";
constexpr uint8_t PDF_NULL[] = "null";
constexpr uint8_t PDF_NULL_SIZE = 4;

constexpr uint8_t PDF_XREF[] = "xref";
Expand All @@ -107,10 +107,10 @@ namespace Type
constexpr uint8_t PDF_EOF[] = "%%EOF";
constexpr uint8_t PDF_EOF_SIZE = 5;

constexpr uint8_t PDF_XREF_ENTRY = 20;
constexpr uint8_t PDF_FREE_ENTRY = 'f';
constexpr uint8_t ZERO = 0;
constexpr uint8_t PDF_INDIRECTOBJ = 'R';
constexpr uint8_t PDF_XREF_ENTRY = 20;
constexpr uint8_t PDF_FREE_ENTRY = 'f';
constexpr uint8_t ZERO = 0;
constexpr uint8_t PDF_INDIRECTOBJ = 'R';
} // namespace KEY

namespace PREDICTOR
Expand Down Expand Up @@ -163,13 +163,21 @@ namespace Type
uint8 bitsPerComponent;
};

struct PDFObject {
uint64 startBuffer;
uint64 endBuffer;
uint8 type;
uint32 number;
};

#pragma pack(pop) // Back to default packing

class PDFFile : public TypeInterface, public View::ContainerViewer::EnumerateInterface, public View::ContainerViewer::OpenItemInterface
{
public:
Header header{};
bool versionUnder5;
vector<PDFObject> pdfObjects;
Reference<GView::Utils::SelectionZoneInterface> selectionZoneInterface;

public:
Expand All @@ -179,6 +187,7 @@ namespace Type
}

bool Update();
void AddPDFObject(Reference<GView::Type::PDF::PDFFile> pdf, const PDF::PDFObject& obj);

std::string_view GetTypeName() override
{
Expand Down Expand Up @@ -213,6 +222,24 @@ namespace Type
};
namespace Panels
{
class Sections : public AppCUI::Controls::TabPage
{
Reference<GView::Type::PDF::PDFFile> pdf;
Reference<GView::View::WindowInterface> win;
Reference<AppCUI::Controls::ListView> list;
int Base;

std::string_view GetValue(NumericFormatter& n, uint32 value);
void GoToSelectedSection();
void SelectCurrentSection();

public:
Sections(Reference<GView::Type::PDF::PDFFile> pdf, Reference<GView::View::WindowInterface> win);

void Update();
bool OnUpdateCommandBar(AppCUI::Application::CommandBar& commandBar) override;
bool OnEvent(Reference<Control>, Event evnt, int controlID) override;
};
class Information : public AppCUI::Controls::TabPage
{
Reference<GView::Type::PDF::PDFFile> pdf;
Expand Down
1 change: 1 addition & 0 deletions Types/PDF/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
target_sources(PDF PRIVATE
pdf.cpp
PDFFile.cpp
Sections.cpp
PanelInformation.cpp)
8 changes: 8 additions & 0 deletions Types/PDF/src/PDFFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ bool PDFFile::Update()
return true;
}

void PDFFile::AddPDFObject(Reference<GView::Type::PDF::PDFFile> pdf, const PDFObject& obj)
{
auto it = std::lower_bound(
pdf->pdfObjects.begin(), pdf->pdfObjects.end(), obj, [](const PDFObject& a, const PDFObject& b) { return a.startBuffer < b.startBuffer; });

pdf->pdfObjects.insert(it, obj);
}

bool PDFFile::BeginIteration(std::u16string_view path, AppCUI::Controls::TreeViewItem parent)
{
return true;
Expand Down
102 changes: 102 additions & 0 deletions Types/PDF/src/Sections.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include "pdf.hpp"

using namespace GView::Type::PDF;
using namespace AppCUI::Controls;
using namespace AppCUI::Input;

constexpr int PDF_SECTIONS_GOTO = 1;
constexpr int PDF_SECTIONS_SELECT = 2;

Panels::Sections::Sections(Reference<GView::Type::PDF::PDFFile> _pdf, Reference<GView::View::WindowInterface> _win) : TabPage("&Sections")
{
pdf = _pdf;
win = _win;
Base = 16;

list = Factory::ListView::Create(this, "d:c", { "n:Name,w:16", "n:ObjectPoz,a:r,w:12", "n:Size,a:r,w:12" }, ListViewFlags::AllowMultipleItemsSelection);
Update();
}

void Panels::Sections::GoToSelectedSection()
{
auto sect = list->GetCurrentItem().GetData<PDF::PDFObject>();
if (sect.IsValid()) {
win->GetCurrentView()->GoTo(sect->startBuffer);
}
}

void Panels::Sections::SelectCurrentSection()
{
auto sect = list->GetCurrentItem().GetData<PDF::PDFObject>();
if (sect.IsValid()) {
win->GetCurrentView()->Select(sect->startBuffer, (sect->endBuffer - sect->startBuffer));
}
}

void Panels::Sections::Update()
{
LocalString<128> temp;
NumericFormatter n;
list->DeleteAllItems();

for (auto& object : pdf->pdfObjects) {
temp.Clear();
switch (object.type) {
case 1:
temp.Add("Object ");
temp.Add(std::to_string(object.number));
break;
case 2:
temp.Add("Cross-ref Table");
break;
case 3:
temp.Add("Cross-ref Stream");
break;
case 4:
temp.Add("Trailer");
break;
}
auto item = list->AddItem(temp);

item.SetData<PDF::PDFObject>(&object);

item.SetText(1, GetValue(n, object.startBuffer));
item.SetText(2, GetValue(n, object.endBuffer - object.startBuffer));
}
}

std::string_view Panels::Sections::GetValue(NumericFormatter& n, uint32 value)
{
if (Base == 10)
return n.ToString(value, { NumericFormatFlags::None, 10, 3, ',' });
else
return n.ToString(value, { NumericFormatFlags::HexPrefix, 16 });
}

bool Panels::Sections::OnUpdateCommandBar(AppCUI::Application::CommandBar& commandBar)
{
commandBar.SetCommand(Key::Enter, "GoTo", PDF_SECTIONS_GOTO);
commandBar.SetCommand(Key::F9, "Select", PDF_SECTIONS_SELECT);
return true;
}

bool Panels::Sections::OnEvent(Reference<Control> ctrl, Event evnt, int controlID)
{
if (TabPage::OnEvent(ctrl, evnt, controlID))
return true;
if (evnt == Event::ListViewItemPressed) {
GoToSelectedSection();
return true;
}
if (evnt == Event::Command) {
switch (controlID) {
case PDF_SECTIONS_GOTO:
GoToSelectedSection();
return true;
case PDF_SECTIONS_SELECT:
SelectCurrentSection();
return true;
}
}
return false;
}
51 changes: 45 additions & 6 deletions Types/PDF/src/pdf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,12 +290,24 @@ void ApplyPNGFilter(Buffer& data, const uint16_t& column, const uint8_t& predict
data = std::move(filteredData);
}

void HighlightObjectTypes(GView::Utils::DataCache& data, BufferViewer::Settings& settings, const uint64_t& offset, const uint64_t& dataSize)
void HighlightObjectTypes(
GView::Utils::DataCache& data,
Reference<PDF::PDFFile> pdf,
BufferViewer::Settings& settings,
const uint64_t& offset,
const uint64_t& dataSize,
const uint64 objNum)
{
uint8_t buffer;
uint64_t lengthVal = 0;
bool found_length = false;
uint64_t object_offset = offset;

PDF::PDFObject pdfObject;
pdfObject.startBuffer = offset;
pdfObject.type = 1;
pdfObject.number = objNum;

while (object_offset < dataSize && (data.Copy(object_offset, buffer) && (buffer != PDF::WSC::LINE_FEED && buffer != PDF::WSC::CARRIAGE_RETURN))) {
object_offset++;
}
Expand All @@ -304,6 +316,8 @@ void HighlightObjectTypes(GView::Utils::DataCache& data, BufferViewer::Settings&
break;
}
if (CheckType(data, object_offset, PDF::KEY::PDF_ENDOBJ_SIZE, PDF::KEY::PDF_ENDOBJ)) {
pdfObject.endBuffer = object_offset + PDF::KEY::PDF_ENDOBJ_SIZE;
pdf->AddPDFObject(pdf, pdfObject);
break;
} else if (
CheckType(data, object_offset, PDF::KEY::PDF_DIC_SIZE, PDF::KEY::PDF_DIC_START) ||
Expand Down Expand Up @@ -488,6 +502,10 @@ void CreateBufferView(Reference<GView::View::WindowInterface> win, Reference<PDF
if (pdf->versionUnder5) {
bool next_table = true;
while (next_table) {
PDF::PDFObject pdfObject;
pdfObject.startBuffer = crossRefOffset;
pdfObject.type = 2;
pdfObject.number = 0;
// get the offsets from the Cross-Reference Table
const uint64 numEntries = GetNumberOfEntries(crossRefOffset, offset, dataSize, data);
while (offset < dataSize) {
Expand All @@ -502,15 +520,21 @@ void CreateBufferView(Reference<GView::View::WindowInterface> win, Reference<PDF

GetObjectsOffsets(numEntries, offset, data, objectOffsets);

pdfObject.endBuffer = offset;
pdf->AddPDFObject(pdf, pdfObject);

uint64 trailerOffset = 0;
const bool foundTrailer = GetTrailerOffset(offset, dataSize, data, trailerOffset);

pdfObject.startBuffer = trailerOffset;
pdfObject.type = 4;
pdfObject.number = 0;
// Find /Prev in the trailer segment
bool found_prev = false;
if (foundTrailer) {
for (offset = trailerOffset; offset < eofOffset - PDF::KEY::PDF_PREV_SIZE; ++offset) {
const bool match = CheckType(data, offset, PDF::KEY::PDF_PREV_SIZE, PDF::KEY::PDF_PREV);
if (match) {
offset = trailerOffset;
while (offset < dataSize) {
if (CheckType(data, offset, PDF::KEY::PDF_PREV_SIZE, PDF::KEY::PDF_PREV)) {
offset += PDF::KEY::PDF_PREV_SIZE;

while (offset < dataSize && (data.Copy(offset, buffer) &&
Expand All @@ -520,17 +544,24 @@ void CreateBufferView(Reference<GView::View::WindowInterface> win, Reference<PDF

prevOffset = GetTypeValue(data, offset, dataSize);
found_prev = true;
} else if (CheckType(data, offset, PDF::KEY::PDF_EOF_SIZE, PDF::KEY::PDF_EOF)) {
offset += PDF::KEY::PDF_EOF_SIZE;
break;
} else {
offset++;
}
}
if (!found_prev) {
next_table = false;
}
}

pdfObject.endBuffer = offset;
pdf->AddPDFObject(pdf, pdfObject);

if (foundTrailer) {
settings.AddZone(crossRefOffset, trailerOffset - crossRefOffset, ColorPair{ Color::Green, Color::DarkBlue }, "Cross-Reference Table");
settings.AddZone(trailerOffset, eofOffset - trailerOffset + PDF::KEY::PDF_EOF_SIZE, ColorPair{ Color::Red, Color::DarkBlue }, "Trailer");
settings.AddZone(trailerOffset, offset - trailerOffset, ColorPair{ Color::Red, Color::DarkBlue }, "Trailer");
}
crossRefOffset = prevOffset;
}
Expand All @@ -549,6 +580,11 @@ void CreateBufferView(Reference<GView::View::WindowInterface> win, Reference<PDF
PDF::WValues wValues = { 0, 0, 0 };
PDF::DecodeParms decodeParms = { 1, 1, 8 };

PDF::PDFObject pdfObject;
pdfObject.startBuffer = crossRefOffset;
pdfObject.type = 3;
pdfObject.number = 0;

while (!end_tag) {
if (CheckType(data, offset, PDF::KEY::PDF_STREAM_SIZE, PDF::KEY::PDF_STREAM)) {
end_tag = true;
Expand Down Expand Up @@ -634,6 +670,8 @@ void CreateBufferView(Reference<GView::View::WindowInterface> win, Reference<PDF
found_eof = CheckType(data, offset, PDF::KEY::PDF_EOF_SIZE, PDF::KEY::PDF_EOF);
if (found_eof) {
offset += PDF::KEY::PDF_EOF_SIZE;
pdfObject.endBuffer = offset;
pdf->AddPDFObject(pdf, pdfObject);
settings.AddZone(crossRefOffset, offset - crossRefOffset, ColorPair{ Color::Green, Color::DarkBlue }, "Cross-Reference Stream");
break;
} else {
Expand Down Expand Up @@ -686,7 +724,7 @@ void CreateBufferView(Reference<GView::View::WindowInterface> win, Reference<PDF
uint64_t objOffset = objectOffsets[i];
uint64_t length = (i + 1 < objectOffsets.size()) ? objectOffsets[i + 1] - objOffset : eofOffset - objOffset;
settings.AddZone(objOffset, length, { Color::Teal, Color::DarkBlue }, "Obj " + std::to_string(i + 1));
HighlightObjectTypes(data, settings, objOffset, dataSize);
HighlightObjectTypes(data, pdf, settings, objOffset, dataSize, i + 1);
}

pdf->selectionZoneInterface = win->GetSelectionZoneInterfaceFromViewerCreation(settings);
Expand All @@ -701,6 +739,7 @@ PLUGIN_EXPORT bool PopulateWindow(Reference<WindowInterface> win)
CreateBufferView(win, pdf);
// win->CreateViewer<TextViewer::Settings>();

win->AddPanel(Pointer<TabPage>(new PDF::Panels::Sections(pdf, win)), false);
win->AddPanel(Pointer<TabPage>(new PDF::Panels::Information(pdf)), true);

return true;
Expand Down

0 comments on commit df60e9f

Please sign in to comment.