fix
This commit is contained in:
@@ -27,11 +27,9 @@ public:
|
||||
double numberValue = 0.0;
|
||||
bool boolValue = false;
|
||||
|
||||
// We use a vector of shared_ptr for recursive data structures so the node is easily copyable/movable
|
||||
std::vector<std::shared_ptr<AstNode>> arrayItems;
|
||||
std::unordered_map<std::string, std::shared_ptr<AstNode>> dictItems;
|
||||
|
||||
// Constructors for convenience
|
||||
AstNode() = default;
|
||||
explicit AstNode(AstNodeType t) : type(t) {}
|
||||
};
|
||||
@@ -41,4 +39,4 @@ struct Operation {
|
||||
std::vector<std::shared_ptr<AstNode>> operands;
|
||||
};
|
||||
|
||||
} // namespace pdfengine
|
||||
}
|
||||
|
||||
@@ -32,12 +32,10 @@ class TextObject : public ContentObject {
|
||||
public:
|
||||
ContentObjectType getType() const override { return ContentObjectType::Text; }
|
||||
|
||||
std::string text; // The decoded text string
|
||||
std::string fontName; // Font resource name (e.g. "F1")
|
||||
double fontSize = 0.0; // Font size
|
||||
std::string text;
|
||||
std::string fontName;
|
||||
double fontSize = 0.0;
|
||||
|
||||
// Text Transformation Matrix (a, b, c, d, e, f)
|
||||
// Default is identity matrix: [1 0 0 1 0 0]
|
||||
double tm[6] = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
|
||||
};
|
||||
|
||||
@@ -53,10 +51,8 @@ public:
|
||||
int bitsPerComponent = 8;
|
||||
bool hasSoftMask = false;
|
||||
|
||||
// Decoded raw pixels (RGBA format for Skia)
|
||||
std::vector<uint8_t> pixelData;
|
||||
|
||||
// The Current Transformation Matrix (CTM) at the time the 'Do' operator was invoked
|
||||
Matrix transform;
|
||||
};
|
||||
|
||||
@@ -76,4 +72,4 @@ public:
|
||||
Matrix transform;
|
||||
};
|
||||
|
||||
} // namespace pdfengine
|
||||
}
|
||||
|
||||
@@ -5,12 +5,6 @@
|
||||
|
||||
namespace pdfengine {
|
||||
|
||||
/// Result of extracting a raw PDF content stream from a page.
|
||||
/// rawContent — bytes as-found in the PDF (may be compressed)
|
||||
/// decodedContent — after applying all /Filter chains (FlateDecode, etc.)
|
||||
/// pageIndex — 0-based page index
|
||||
/// filters — list of filter names applied, e.g. {"FlateDecode"}
|
||||
/// compressed — true if at least one filter was applied
|
||||
struct ExtractedStream {
|
||||
std::string rawContent;
|
||||
std::string decodedContent;
|
||||
@@ -20,16 +14,14 @@ struct ExtractedStream {
|
||||
bool multiStream = false;
|
||||
};
|
||||
|
||||
/// Verifies structural integrity of a decoded content stream.
|
||||
/// Returns true if all of: BT, ET, Tf, Tj/TJ are present.
|
||||
struct StreamVerification {
|
||||
bool hasBT = false;
|
||||
bool hasET = false;
|
||||
bool hasTf = false;
|
||||
bool hasTj = false; // Tj or TJ
|
||||
bool multiStream = false; // page had multiple /Contents streams
|
||||
bool hasTj = false;
|
||||
bool multiStream = false;
|
||||
};
|
||||
|
||||
StreamVerification verifyContentStream(const ExtractedStream& stream);
|
||||
|
||||
} // namespace pdfengine
|
||||
}
|
||||
|
||||
@@ -10,13 +10,11 @@ namespace pdfengine {
|
||||
|
||||
class CommandVisitor;
|
||||
|
||||
// Base class for all drawing commands
|
||||
struct Command {
|
||||
virtual ~Command() = default;
|
||||
virtual void accept(CommandVisitor& visitor) const = 0;
|
||||
};
|
||||
|
||||
// --- Specific Command Types ---
|
||||
|
||||
struct SaveStateCommand : public Command {
|
||||
void accept(CommandVisitor& visitor) const override;
|
||||
@@ -41,7 +39,6 @@ struct FillRectCommand : public Command {
|
||||
struct DrawTextCommand : public Command {
|
||||
std::string text;
|
||||
float x, y;
|
||||
// We would eventually have a font reference here too
|
||||
DrawTextCommand(std::string text, float x, float y) : text(std::move(text)), x(x), y(y) {}
|
||||
void accept(CommandVisitor& visitor) const override;
|
||||
};
|
||||
@@ -77,9 +74,7 @@ struct DrawImageCommand : public Command {
|
||||
};
|
||||
|
||||
|
||||
// --- Visitor Interface ---
|
||||
|
||||
// The visitor interface that the renderer (or replay engine) implements
|
||||
class CommandVisitor {
|
||||
public:
|
||||
virtual ~CommandVisitor() = default;
|
||||
@@ -94,20 +89,15 @@ public:
|
||||
virtual void visit(const DrawImageCommand& cmd) = 0;
|
||||
};
|
||||
|
||||
// --- Display List Container ---
|
||||
|
||||
// A container that stores a sequence of drawing commands.
|
||||
class DisplayList {
|
||||
public:
|
||||
DisplayList() = default;
|
||||
|
||||
// Add commands directly
|
||||
void addCommand(std::unique_ptr<Command> cmd);
|
||||
|
||||
// Replay the commands to a visitor (renderer)
|
||||
void replay(CommandVisitor& visitor) const;
|
||||
|
||||
// Helper methods to easily append common commands
|
||||
void saveState();
|
||||
void restoreState();
|
||||
void setTransform(const Matrix& m);
|
||||
@@ -125,4 +115,4 @@ private:
|
||||
std::vector<std::unique_ptr<Command>> m_commands;
|
||||
};
|
||||
|
||||
} // namespace pdfengine
|
||||
}
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
|
||||
namespace pdfengine {
|
||||
|
||||
// 2D Affine Transformation Matrix (3x3 matrix optimized for 2D)
|
||||
// [ a b 0 ]
|
||||
// [ c d 0 ]
|
||||
// [ e f 1 ]
|
||||
struct Matrix {
|
||||
float a = 1.0f, b = 0.0f;
|
||||
float c = 0.0f, d = 1.0f;
|
||||
@@ -18,10 +14,8 @@ struct Matrix {
|
||||
Matrix(float a, float b, float c, float d, float e, float f)
|
||||
: a(a), b(b), c(c), d(d), e(e), f(f) {}
|
||||
|
||||
// Multiply this matrix by another matrix
|
||||
[[nodiscard]] Matrix multiply(const Matrix& other) const noexcept;
|
||||
|
||||
// Transform a 2D point using this matrix
|
||||
void transform(float& x, float& y) const noexcept;
|
||||
};
|
||||
|
||||
@@ -31,32 +25,22 @@ struct Color {
|
||||
float b = 0.0f;
|
||||
};
|
||||
|
||||
// Represents the current graphics state in a PDF document
|
||||
struct GraphicsState {
|
||||
Matrix ctm; // Current Transformation Matrix
|
||||
Matrix ctm;
|
||||
Color fillColor;
|
||||
Color strokeColor;
|
||||
float lineWidth = 1.0f;
|
||||
|
||||
// In the future, this will also hold:
|
||||
// - Clipping paths
|
||||
// - Font state (current font, font size)
|
||||
// - Dash patterns
|
||||
// - Line cap/join styles
|
||||
};
|
||||
|
||||
// Manages the q/Q stack of graphics states
|
||||
class GraphicsStateStack {
|
||||
public:
|
||||
GraphicsStateStack();
|
||||
|
||||
// Corresponds to the 'q' operator (save graphics state)
|
||||
void push();
|
||||
|
||||
// Corresponds to the 'Q' operator (restore graphics state)
|
||||
void pop();
|
||||
|
||||
// Access the current active graphics state
|
||||
[[nodiscard]] GraphicsState& current();
|
||||
[[nodiscard]] const GraphicsState& current() const;
|
||||
|
||||
@@ -64,4 +48,4 @@ private:
|
||||
std::vector<GraphicsState> m_stack;
|
||||
};
|
||||
|
||||
} // namespace pdfengine
|
||||
}
|
||||
|
||||
@@ -1,15 +1,3 @@
|
||||
// Resource limits for hardening against malicious / malformed PDFs.
|
||||
//
|
||||
// These guard the allocation-sizing arithmetic in the load and render paths
|
||||
// against integer overflow and pathological out-of-memory inputs (a 2-billion-pt
|
||||
// page, a million-page document, a multi-gigabyte raster). The ceilings are set
|
||||
// far above anything a legitimate document needs, so enforcing them never
|
||||
// rejects real files — they exist purely to turn "crash / OOM" into a clean,
|
||||
// recoverable error, which is exactly what a fuzzer needs to make progress.
|
||||
//
|
||||
// Header-only and dependency-free so the fuzz harness and the engine share one
|
||||
// source of truth.
|
||||
|
||||
#ifndef PDFENGINE_HARDENED_LIMITS_H
|
||||
#define PDFENGINE_HARDENED_LIMITS_H
|
||||
|
||||
@@ -17,33 +5,21 @@
|
||||
|
||||
namespace pdfengine::limits {
|
||||
|
||||
// Largest input document we will even attempt to parse (1 GiB).
|
||||
inline constexpr std::uint64_t kMaxDocumentBytes = 1ull << 30;
|
||||
|
||||
// PDF hard-caps a page at 14,400 user units (200 in) per side; allow a very
|
||||
// generous multiple of that to tolerate odd-but-real documents.
|
||||
inline constexpr double kMaxPageDimensionPt = 200'000.0; // ~2,777 inches
|
||||
inline constexpr double kMaxPageDimensionPt = 200'000.0;
|
||||
|
||||
// No legitimate document has this many pages; stops runaway iteration.
|
||||
inline constexpr int kMaxPageCount = 100'000;
|
||||
|
||||
// MAX_OBJECTS: ceiling on the number of content objects on a single page. Guards
|
||||
// against content-stream "object bombs" that would explode parsing/rendering
|
||||
// time and memory. No real page comes near this.
|
||||
inline constexpr int kMaxObjects = 5'000'000;
|
||||
|
||||
// Cap a single rasterised page at ~256 megapixels (≈1 GiB at 4 bytes/px). At
|
||||
// 96 dpi that is roughly a 16k × 16k page — well beyond any real render.
|
||||
inline constexpr std::int64_t kMaxRasterPixels = 256ll * 1024 * 1024;
|
||||
|
||||
// True if a raw page size (in points) is sane to render.
|
||||
inline constexpr bool pageDimensionsOk(double widthPt, double heightPt) noexcept {
|
||||
return widthPt > 0.0 && heightPt > 0.0 && widthPt <= kMaxPageDimensionPt &&
|
||||
heightPt <= kMaxPageDimensionPt;
|
||||
}
|
||||
|
||||
// True if a target raster (in pixels) fits the pixel budget without overflowing
|
||||
// the width*height*4 byte computation.
|
||||
inline constexpr bool rasterSizeOk(std::int64_t widthPx, std::int64_t heightPx) noexcept {
|
||||
if (widthPx <= 0 || heightPx <= 0) return false;
|
||||
if (widthPx > kMaxRasterPixels || heightPx > kMaxRasterPixels) return false;
|
||||
@@ -62,6 +38,6 @@ inline constexpr bool objectCountOk(int objects) noexcept {
|
||||
return objects >= 0 && objects <= kMaxObjects;
|
||||
}
|
||||
|
||||
} // namespace pdfengine::limits
|
||||
}
|
||||
|
||||
#endif // PDFENGINE_HARDENED_LIMITS_H
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
namespace pdfengine {
|
||||
|
||||
// Basic color spaces we might encounter
|
||||
enum class ColorSpace {
|
||||
DeviceGray,
|
||||
DeviceRGB,
|
||||
@@ -13,12 +12,11 @@ enum class ColorSpace {
|
||||
Indexed
|
||||
};
|
||||
|
||||
// Holds decoded image data ready for the display list (typically RGBA)
|
||||
struct ImageInfo {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int channels = 4; // 4 = RGBA
|
||||
std::vector<uint8_t> pixelData; // Decoded raw pixels
|
||||
int channels = 4;
|
||||
std::vector<uint8_t> pixelData;
|
||||
};
|
||||
|
||||
} // namespace pdfengine
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ struct Point {
|
||||
float y = 0.0f;
|
||||
};
|
||||
|
||||
// Represents a 2D vector path constructed from basic drawing commands.
|
||||
class Path {
|
||||
public:
|
||||
enum class Verb {
|
||||
@@ -27,7 +26,7 @@ public:
|
||||
|
||||
struct Segment {
|
||||
Verb verb;
|
||||
Point points[3]; // Up to 3 points depending on verb (e.g., Cubic bezier)
|
||||
Point points[3];
|
||||
};
|
||||
|
||||
Path() = default;
|
||||
@@ -48,7 +47,6 @@ public:
|
||||
m_segments.push_back({Verb::Close, {{}, {}, {}}});
|
||||
}
|
||||
|
||||
// Helper for 're' (rectangle) operator
|
||||
void addRect(float x, float y, float w, float h) {
|
||||
moveTo(x, y);
|
||||
lineTo(x + w, y);
|
||||
@@ -68,4 +66,4 @@ private:
|
||||
std::vector<Segment> m_segments;
|
||||
};
|
||||
|
||||
} // namespace pdfengine
|
||||
}
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
// pdfengine — public umbrella header for the PDF SDK core.
|
||||
//
|
||||
// Phase 0 surface only: version + build introspection. The real document API
|
||||
// (PdfDocument / PdfPage) is frozen at Gate G0b and added in Phase 1 — see
|
||||
// pdf_document.hpp.
|
||||
#pragma once
|
||||
|
||||
#include <pdfengine/version.hpp>
|
||||
@@ -10,19 +5,14 @@
|
||||
|
||||
namespace pdfengine {
|
||||
|
||||
// Human-readable engine version, e.g. "0.1.0".
|
||||
[[nodiscard]] std::string_view engineVersion() noexcept;
|
||||
|
||||
// One-line build descriptor, e.g. "pdfengine 0.1.0 (pdfium=off)".
|
||||
[[nodiscard]] std::string_view engineBuildInfo() noexcept;
|
||||
|
||||
// True if this build was compiled and linked against the PDFium parser core.
|
||||
[[nodiscard]] bool engineHasPdfium() noexcept;
|
||||
|
||||
// True if this build was compiled and linked against the Skia graphics core.
|
||||
[[nodiscard]] bool engineHasSkia() noexcept;
|
||||
|
||||
// Emits engineBuildInfo() through spdlog at info level.
|
||||
void engineLogBuildInfo();
|
||||
|
||||
} // namespace pdfengine
|
||||
}
|
||||
|
||||
@@ -7,11 +7,8 @@ class SkCanvas;
|
||||
|
||||
namespace pdfengine {
|
||||
|
||||
// A visitor that replays a DisplayList onto a Skia canvas.
|
||||
class SkiaRenderer : public CommandVisitor {
|
||||
public:
|
||||
// Takes a pointer to an external SkCanvas.
|
||||
// The caller is responsible for the canvas's lifecycle.
|
||||
explicit SkiaRenderer(SkCanvas* canvas);
|
||||
|
||||
void visit(const SaveStateCommand& cmd) override;
|
||||
@@ -23,7 +20,6 @@ public:
|
||||
void visit(const StrokePathCommand& cmd) override;
|
||||
void visit(const FillStrokePathCommand& cmd) override;
|
||||
void visit(const DrawImageCommand& cmd) override;
|
||||
// Renders the entire display list to the canvas
|
||||
void render(const DisplayList& displayList);
|
||||
|
||||
private:
|
||||
@@ -31,4 +27,4 @@ private:
|
||||
GraphicsStateStack m_stateStack;
|
||||
};
|
||||
|
||||
} // namespace pdfengine
|
||||
}
|
||||
|
||||
@@ -7,29 +7,28 @@
|
||||
namespace pdfengine {
|
||||
|
||||
enum class TokenType {
|
||||
Operator, // e.g., "Tj", "BT", "ET", "Tf", "re", "f"
|
||||
String, // e.g., "(Hello World)", fully unescaped
|
||||
HexString, // e.g., "<48656C6C6F>", fully decoded to bytes
|
||||
Name, // e.g., "/F1" (without the slash, unescaped)
|
||||
Number, // e.g., "12.3", "-4", stored as string/double
|
||||
ArrayStart, // "["
|
||||
ArrayEnd, // "]"
|
||||
DictStart, // "<<"
|
||||
DictEnd, // ">>"
|
||||
Boolean, // "true", "false"
|
||||
Null, // "null"
|
||||
EndOfStream // EOF marker
|
||||
Operator,
|
||||
String,
|
||||
HexString,
|
||||
Name,
|
||||
Number,
|
||||
ArrayStart,
|
||||
ArrayEnd,
|
||||
DictStart,
|
||||
DictEnd,
|
||||
Boolean,
|
||||
Null,
|
||||
EndOfStream
|
||||
};
|
||||
|
||||
struct Token {
|
||||
TokenType type;
|
||||
std::string stringValue; // Used for Operator, String, Name
|
||||
std::vector<uint8_t> bytesValue; // Used for HexString
|
||||
double numberValue = 0.0; // Used for Number
|
||||
std::string stringValue;
|
||||
std::vector<uint8_t> bytesValue;
|
||||
double numberValue = 0.0;
|
||||
|
||||
// Position tracking for error reporting (optional but helpful)
|
||||
size_t startOffset = 0;
|
||||
size_t endOffset = 0;
|
||||
};
|
||||
|
||||
} // namespace pdfengine
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user