# Low level CObjects

Pdf file consists of objects. These objects are referenced from a special structure forming a tree. Objects can be either simple (number, string, name, boolean value, reference, null) or complex (array, dictionary, stream).

CObject class hierarchy

## General description

CObjects are objects in pdfedit which represent objects in pdf file. All cobjects are derived from one base class `IProperty`. Objects form a tree like structure so we can divide objects into single objects (leafs) and composite objects (nodes). This is an example of . This is a different approach to xpdf implementation where each pdf object is represented by the same huge class.

The concept of having exactly one class representing each pdf object leads to many problems:

- inheriting - unclear oo design, unmanagable, it breaks the idiom of one entity for one purpose

- adding changing operations - would result in even more monstrous class

- sometimes value inside class, sometimes outside - unclear oo design

There are many interesting design decisions in xpdf objects implementation. For example memory handling makes it almost unsound to delete objects from complex types. Memory allocation policy, that means who/when/how is to deallocate xpdf `Object` is a mess which could easily lead to either memory leaks or memory corruption.

The new design counted with new object for each different pdf object. Because of the pdf decoding complexity (pdf can be encoded using many filters) these objects use xpdf `Object` just for initializing and dispatching changes to `CXref` object.

Objects can not be simply copied, because it is not clear if a copy is a deep copy with all indirect object copied or not.

Object class hierarchy

Object class hierarchy

### Base class

Every object is derived from one base class - `IProperty`. This base class is a hanger which can be used to access child objects uniformly. This class is a read only interface for all properties. Objects can be created uninitialized or can be initialized from an xpdf Object of the same type and simple objects cat be initialized directly from a value.

### Simple objects

Simple objects are very similar. They share behaviour and because of this also method names (only value keeper is different). They are represented by one class using c++ templates. One template class (`CObjectSimple`), parameterized by object type, represents all 7 types of simple objects.

### Complex objects

It is more difficult with complex types. Each complex type must contain references to its children which are also pdf objects. A design decision was made to use smart pointers for referencing child objects. The reasons are:

1. Allocation and deallocation policy - we cannot be sure when an object is deallocated nobody holds a pointer to the object. This could be solved by implementing reference counting, but why reimplement the wheel.

2. Automatic deallocating when not needed.

Pdf objects can be referenced using ids which are similar to pointers. This brings many problems. One of them is the impossibility to delete such objects. Many of the problems are automatically handled by smart pointers.

#### Array and dictionary

`CArray` stores its children in a simple container indexed by position. `CDict` stores its children in container indexed by string which uniquely identifies a property. The beauty of smart pointers arise when deallocating an array, it automatically deallocates its children when not referenced and this is done recursively.

#### Streams

Streams are the most complicated from all pdf objects. The problem is that xpdf can decode pdf files but it can not do it the other way round. (it is because it never needs it) Xpdf impelementation of streams is very rough.

We use boost filtering iostream which provide us with the necessary general concept of encoded streams. However we have to implement the filters ourselves. (the easiest way is to save decoded streams without any filters) We do not know the filters as long as we do not change the object. We can modify either raw encoded stream or we can save decoded stream which is automatically encoded when saved using avaliable filters.

Each stream consists of a dictionary and stream buffer. The dictionary can not be accessed directly. Dictionary interface is simulated by simple methods which delegate the calls to the dictionary object. Buffer is stored in encoded form allowing us to return the same byte representation of an unchanged object as read from a pdf file. At the time of writing this not all reversed filters have been implemented.

##### Accessing streams

We access streams using implementing open/close interface. We need to be able to read from more streams byte per byte because content streams can be splitted anywhere. We decided to return only xpdf objects.

## Changing objects

Every object can be obtained from `CXref` (see ) when knowing its reference number and then changed using iproperty interface. Internal state of special object (cpage, ccontentstream, etc.) depends on these raw objects. Therefore a mechanism was designed to allow special object to be notified about raw changes. Objects implement subject interface from Observer design pattern which allows everyone to register observers on these objects. This observer gets notified each time the object was changed.