#include "mupdf/fitz.h"
#include "mupdf/pdf.h"
#include "Collection.h"
#include "Stream.h"
#ifndef __PDFOBJECT
#define __PDFOBJECT
#pragma once
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Text;
struct pdf_obj {
short refs;
unsigned char kind;
unsigned char flags;
};
namespace MuPDF {
public enum class Kind {
Null,
Boolean,
Name,
Integer,
Float,
String,
Array,
Dictionary,
Reference,
Stream,
Unknown
};
///
/// Encapsulates the PDF obj used by MuPDF
///
public ref class PdfObject : IDisposable, IEquatable {
public:
///
/// Gets or sets whether this object is dirty (modified).
///
property bool IsDirty {
bool get() { return pdf_obj_is_dirty(_ctx, _obj); }
void set(bool value) {
if (value) {
pdf_dirty_obj(_ctx, _obj);
}
else {
pdf_clean_obj(_ctx, _obj);
}
}
}
///
/// Provides direct object kind info.
///
property Kind TypeKind {
virtual Kind get();
}
property bool IsIndirect {
bool get() { return pdf_is_indirect(_ctx, _obj); }
}
property bool IsStream {
bool get() { return pdf_is_stream(_ctx, _obj); }
}
property bool IsName {
bool get() { return pdf_is_name(_ctx, _obj); }
}
property bool IsNull {
bool get() { return pdf_is_null(_ctx, _obj); }
}
property bool IsBoolean {
bool get() { return pdf_is_bool(_ctx, _obj); }
}
property bool IsInteger {
bool get() { return pdf_is_int(_ctx, _obj); }
}
property bool IsFloat {
bool get() { return pdf_is_real(_ctx, _obj); }
}
property bool IsNumber {
bool get() { return pdf_is_number(_ctx, _obj); }
}
property bool IsString {
bool get() { return pdf_is_string(_ctx, _obj); }
}
property bool IsArray {
bool get() { return pdf_is_array(_ctx, _obj); }
}
property bool IsDictionary {
bool get() { return pdf_is_dict(_ctx, _obj); }
}
property bool IsPredefined {
bool get() { return _obj < PDF_LIMIT; }
}
property int IntegerValue {
int get() { return pdf_to_int(_ctx, _obj); }
}
property int LongValue {
int get() { return pdf_to_int64(_ctx, _obj); }
}
property float FloatValue {
float get() { return pdf_to_real(_ctx, _obj); }
}
property PdfObject^ UnderlyingObject {
PdfObject^ get() {
return pdf_is_indirect(_ctx, _obj)
? Wrap(pdf_resolve_indirect_chain(_ctx, _obj))
: this;
}
}
void MarkDirty() {
pdf_dirty_obj(_ctx, _obj);
}
static bool operator == (PdfObject^ x, PdfObject^ y) {
return Object::ReferenceEquals(x, y) || x && y && pdf_objcmp(x->_ctx, x->Ptr, y->Ptr) == 0;
}
static bool operator != (PdfObject^ x, PdfObject^ y) {
return !Object::ReferenceEquals(x, y) && x && y && pdf_objcmp(x->_ctx, x->Ptr, y->Ptr) != 0;
}
virtual bool Equals(PdfObject^ other);
virtual bool Equals(Object^ obj) override {
PdfObject^ p;
return (p = dynamic_cast(obj)) && _obj == p->_obj;
}
virtual int GetHashCode() override {
return (int)_obj;
}
virtual String^ ToString() override {
return TypeKind.ToString();
}
internal:
PdfObject(pdf_obj* obj) : _obj(obj) {
if (obj >= PDF_LIMIT) {
pdf_keep_obj(_ctx = Context::Ptr, obj);
}
}
~PdfObject() {
ReleaseHandle();
}
!PdfObject() {
ReleaseHandle();
}
property fz_context* Ctx { fz_context* get() { return _ctx; } }
property pdf_obj* Ptr { pdf_obj* get() { return _obj; } }
static PdfObject^ Wrap(pdf_obj* obj);
private:
pdf_obj* _obj;
fz_context* _ctx;
void ReleaseHandle() {
if (_obj && _ctx) {
pdf_drop_obj(_ctx, _obj);
_obj = NULL;
_ctx = NULL;
}
}
};
public ref class PdfNull : PdfObject {
public:
property Kind TypeKind {
virtual Kind get() override { return Kind::Null; }
}
static const PdfNull^ Instance = gcnew PdfNull();
virtual String^ ToString() override { return ""; }
internal:
PdfNull() : PdfObject(PDF_NULL) {}
};
public ref class PdfBoolean : PdfObject {
public:
property Kind TypeKind {
virtual Kind get() override { return Kind::Boolean; }
}
static const PdfBoolean^ True = gcnew PdfBoolean(true);
static const PdfBoolean^ False = gcnew PdfBoolean(false);
property bool Value {
bool get() { return Ptr == PDF_TRUE; }
}
virtual String^ ToString() override { return Ptr == PDF_TRUE ? "" : ""; }
internal:
PdfBoolean(bool value) : PdfObject(value ? PDF_TRUE : PDF_FALSE) {}
};
#define PDF_MAKE_NAME(STRING,NAME) NAME,
public enum class PdfNames {
Undefined,
True,
False,
#include "name-table.h"
AllPredefinedNames
};
public ref class PdfName : PdfObject {
public:
property Kind TypeKind {
virtual Kind get() override { return Kind::Name; }
}
property String^ Name {
String^ get() { return gcnew String(pdf_to_name(Context::Ptr, Ptr)); }
}
static operator PdfName^(PdfNames value) {
return gcnew PdfName((pdf_obj*)value);
}
virtual String^ ToString() override { return "/" + Name; }
internal:
PdfName(pdf_obj* obj) : PdfObject(obj) {};
};
public ref class PdfInteger : PdfObject {
public:
property Kind TypeKind {
virtual Kind get() override { return Kind::Integer; }
}
property int Value {
int get() { return pdf_to_int(Context::Ptr, Ptr); }
void set(int value) { pdf_set_int(Context::Ptr, Ptr, value); }
}
property long LongValue {
long get() { return pdf_to_int64(Context::Ptr, Ptr); }
void set(long value) { pdf_set_int(Context::Ptr, Ptr, value); }
}
virtual String^ ToString() override { return LongValue.ToString(); }
internal:
PdfInteger(pdf_obj* obj) : PdfObject(obj) {};
};
public ref class PdfFloat : PdfObject {
public:
property Kind TypeKind {
virtual Kind get() override { return Kind::Float; }
}
property float Value {
float get() { return pdf_to_real(Context::Ptr, Ptr); }
}
virtual String^ ToString() override { return Value.ToString(); }
internal:
PdfFloat(pdf_obj* obj) : PdfObject(obj) {};
};
public ref class PdfString : PdfObject {
public:
property Kind TypeKind {
virtual Kind get() override { return Kind::String; }
}
property String^ Value {
String^ get();
}
property int Length {
int get() { return pdf_to_str_len(Context::Ptr, Ptr); }
}
///
/// Gets underlying bytes in a PDF string.
///
array^ GetBytes();
virtual String^ ToString() override { return Value; }
internal:
PdfString(pdf_obj* obj) : PdfObject(obj) {};
private:
String^ _string;
String^ DecodePdfString();
};
public ref class PdfContainer abstract : PdfObject {
public:
property int Count {
virtual int get() abstract;
}
protected:
pdf_obj* NewPdfString(String^ text);
PdfContainer(pdf_obj* obj) : PdfObject(obj) {};
private:
static Encoding^ AsciiEncoding = Encoding::ASCII;
};
public ref class PdfDictionary : PdfContainer, System::Collections::Generic::IEnumerable>, IIndexableCollection> {
public:
property int Count {
virtual int get() override { return pdf_dict_len(Context::Ptr, Ptr); }
}
property PdfName^ Type {
PdfName^ get() {
auto o = pdf_dict_get(Context::Ptr, Ptr, PDF_NAME(Type));
return pdf_is_name(Context::Ptr, o) ? gcnew PdfName(o) : nullptr;
}
}
property Kind TypeKind {
virtual Kind get() override { return Kind::Dictionary; }
}
PdfName^ GetKey(int index) {
return gcnew PdfName(pdf_dict_get_key(Context::Ptr, Ptr, index));
}
PdfObject^ GetValue(int index) {
return PdfObject::Wrap(pdf_dict_get_val(Context::Ptr, Ptr, index));
}
PdfObject^ GetValue(PdfNames key) {
return PdfObject::Wrap(pdf_dict_get(Context::Ptr, Ptr, (pdf_obj*)key));
}
PdfObject^ GetValue(PdfNames key, PdfNames abbrev) {
return PdfObject::Wrap(pdf_dict_geta(Context::Ptr, Ptr, (pdf_obj*)key, (pdf_obj*)abbrev));
}
PdfObject^ InheritableGet(PdfNames key) {
return PdfObject::Wrap(pdf_dict_get_inheritable(Context::Ptr, Ptr, (pdf_obj*)key));
}
PdfObject^ Locate(... array^ names);
void Set(PdfNames key, PdfNames value) {
pdf_dict_put_drop(Context::Ptr, Ptr, (pdf_obj*)key, (pdf_obj*)value);
}
void Set(PdfNames key, String^ value) {
pdf_dict_put_drop(Context::Ptr, Ptr, (pdf_obj*)key, NewPdfString(value));
}
void Set(PdfNames key, DateTime dateTime) {
pdf_dict_put_date(Context::Ptr, Ptr, (pdf_obj*)key, dateTime.ToUniversalTime().Subtract(DateTime(1970, 1, 1)).TotalSeconds);
}
void Sort() {
pdf_sort_dict(Context::Ptr, Ptr);
}
bool Remove(PdfNames key) {
int i = pdf_dict_len(Context::Ptr, Ptr);
pdf_dict_del(Context::Ptr, Ptr, (pdf_obj*)key);
return i != pdf_dict_len(Context::Ptr, Ptr);
}
PdfDictionary^ DeepClone() {
return gcnew PdfDictionary(pdf_deep_copy_obj(Context::Ptr, Ptr));
}
virtual String^ ToString() override {
PdfName^ type = Type;
return type ? String::Concat("{", type->ToString(), "}") : "{}";
}
virtual System::Collections::Generic::IEnumerator>^ GetEnumerator() sealed = System::Collections::Generic::IEnumerable>::GetEnumerator {
return gcnew IndexableEnumerator>(this);
}
virtual System::Collections::IEnumerator^ GetEnumeratorBase() sealed =
System::Collections::IEnumerable::GetEnumerator {
return GetEnumerator();
}
internal:
PdfDictionary(pdf_obj* obj) : PdfContainer(obj) {};
public:
property KeyValuePair default[int] {
virtual KeyValuePair get(int index) {
return KeyValuePair(GetKey(index), GetValue(index));
};
}
property PdfObject^ default[PdfNames] {
PdfObject^ get(PdfNames key) { return PdfObject::Wrap(pdf_dict_get(Context::Ptr, Ptr, (pdf_obj*)key)); }
void set(PdfNames key, PdfObject^ value) { pdf_dict_put(Context::Ptr, Ptr, (pdf_obj*)key, value->Ptr); }
}
property PdfObject^ default[PdfName^] {
PdfObject^ get(PdfName^ key) { return PdfObject::Wrap(pdf_dict_get(Context::Ptr, Ptr, key->Ptr)); }
void set(PdfName^ key, PdfObject^ value) { pdf_dict_put(Context::Ptr, Ptr, key->Ptr, value->Ptr); }
}
};
public ref class PdfStream : PdfDictionary {
public:
property Kind TypeKind {
virtual Kind get() override { return Kind::Stream; }
}
Stream^ Open() {
return gcnew Stream(pdf_open_stream(Context::Ptr, Ptr));
}
Stream^ OpenRaw() {
return gcnew Stream(pdf_open_raw_stream(Context::Ptr, Ptr));
}
array^ GetBytes() {
Stream^ s = Open();
try {
return s->ReadAll();
}
finally {
delete s;
}
}
array^ GetRawBytes() {
Stream^ s = OpenRaw();
try {
return s->ReadAll();
}
finally {
delete s;
}
}
///
/// Replaces bytes in the stream. The data must match /Filter, if is true.
///
/// The data to be placed into the stream.
/// Whether the data is compressed. If not compressed, /Filter and /DecodeParms will be removed.
void SetBytes(array^ data, bool compress);
internal:
PdfStream(pdf_obj* obj) : PdfDictionary(obj) {};
};
public ref class PdfDocumentInfo : PdfDictionary {
public:
property String^ Title {
String^ get() { return GetString(PdfNames::Title); }
}
property String^ Subject {
String^ get() { return GetString(PdfNames::Subject); }
}
property String^ Producer {
String^ get() { return GetString(PdfNames::Producer); }
}
property String^ Creator {
String^ get() { return GetString(PdfNames::Creator); }
}
property String^ Author {
String^ get() { return GetString(PdfNames::Author); }
}
property String^ Keywords {
String^ get() { return GetString(PdfNames::Keywords); }
}
property String^ CreationDate {
String^ get() { return GetString(PdfNames::CreationDate); }
}
property String^ ModificationDate {
String^ get() { return GetString(PdfNames::ModDate); }
}
internal:
PdfDocumentInfo(pdf_obj* obj) : PdfDictionary(obj) {};
private:
String^ GetString(PdfNames key) {
return GetValue(key)->ToString();
}
};
public ref class PdfArray : PdfContainer, System::Collections::Generic::IEnumerable, IIndexableCollection {
public:
property int Count {
virtual int get() override { return pdf_array_len(Context::Ptr, Ptr); }
}
property Kind TypeKind {
virtual Kind get() override { return Kind::Array; }
}
PdfObject^ Get(int index) {
return Wrap(pdf_array_get(Context::Ptr, Ptr, index));
}
bool Contains(PdfObject^ obj) {
return pdf_array_contains(Context::Ptr, Ptr, obj->Ptr);
}
int IndexOf(PdfObject^ obj) {
return pdf_array_find(Context::Ptr, Ptr, obj->Ptr);
}
void Append(bool value) {
pdf_array_push_bool(Context::Ptr, Ptr, value);
}
void Append(long value) {
pdf_array_push_int(Context::Ptr, Ptr, value);
}
void Append(double value) {
pdf_array_push_real(Context::Ptr, Ptr, value);
}
void Append(PdfNames value) {
pdf_array_push_drop(Context::Ptr, Ptr, (pdf_obj*)value);
}
void Append(String^ value) {
pdf_array_push_drop(Context::Ptr, Ptr, NewPdfString(value));
}
void Append(PdfObject^ value) {
pdf_array_push_drop(Context::Ptr, Ptr, value->Ptr);
}
void Set(int index, bool value) {
pdf_array_put_bool(Context::Ptr, Ptr, index, value);
}
void Set(int index, long value) {
pdf_array_put_int(Context::Ptr, Ptr, index, value);
}
void Set(int index, double value) {
pdf_array_put_real(Context::Ptr, Ptr, index, value);
}
void Set(int index, PdfNames value) {
pdf_array_put(Context::Ptr, Ptr, index, (pdf_obj*)value);
}
void Set(int index, String^ value) {
pdf_array_put_drop(Context::Ptr, Ptr, index, NewPdfString(value));
}
void Set(int index, PdfObject^ value) {
pdf_array_put_drop(Context::Ptr, Ptr, index, value->Ptr);
}
void InsertAt(int index, PdfObject^ value) {
pdf_array_insert_drop(Context::Ptr, Ptr, value->Ptr, index);
}
void RemoveAt(int index) {
pdf_array_delete(Context::Ptr, Ptr, index);
}
PdfArray^ DeepClone() {
return gcnew PdfArray(pdf_deep_copy_obj(Context::Ptr, Ptr));
}
virtual String^ ToString() override { return String::Concat("[", Count.ToString(), "]"); }
virtual System::Collections::Generic::IEnumerator^ GetEnumerator() sealed = System::Collections::Generic::IEnumerable::GetEnumerator{
return gcnew IndexableEnumerator(this);
}
virtual System::Collections::IEnumerator^ GetEnumeratorBase() sealed = System::Collections::IEnumerable::GetEnumerator {
return GetEnumerator();
}
internal:
PdfArray(pdf_obj* obj) : PdfContainer(obj) {};
public:
property PdfObject^ default[int] {
virtual PdfObject^ get(int index) { return Wrap(pdf_array_get(Context::Ptr, Ptr, index)); }
void set(int index, PdfObject^ value) { pdf_array_put_drop(Context::Ptr, Ptr, index, value->Ptr); }
}
};
public ref class PdfReference : PdfObject {
public:
property int Number {
int get() { return pdf_to_num(Context::Ptr, Ptr); }
}
property int Generation {
int get() { return pdf_to_gen(Context::Ptr, Ptr); }
}
property Kind TypeKind {
virtual Kind get() override { return Kind::Reference; }
}
PdfObject^ Resolve() {
return Wrap(pdf_resolve_indirect_chain(Context::Ptr, Ptr));
}
virtual String^ ToString() override {
return Number.ToString() + " " + Generation.ToString() + " R";
}
internal:
PdfReference(pdf_obj* obj) : PdfObject(obj) {};
};
};
#endif // !__PDFOBJECT