package org.hccp.pdf;
import java.util.Vector;
/**
*The cross-reference table contains information that permits random access to indirect
*objects within the file, so that the entire file need not be read to locate any
*particular object. The table contains a one-line entry for each indirect object,
*specifying the location of that object within the body of the file.
*
*
*The cross-reference table is the only part of a PDF file with a fixed format; this
*permits entries in the table to be accessed randomly. The table comprises one or
*more cross-reference sections. Initially, the entire table consists of a single section;
*one additional section is added each time the file is updated.
*
*
*Each cross-reference section begins with a line containing the keyword xref. Following
*this line are one or more cross-reference subsections, which may appear in
*any order. The subsection structure is useful for incremental updates, since it
*allows a new cross-reference section to be added to the PDF file, containing
*entries only for objects that have been added or deleted. For a file that has never
*been updated, the cross-reference section contains only one subsection, whose
*object numbering begins at 0.
*
* @see CrossReferenceTableEntryException
* @see SubSection
*
**/
public class CrossReferenceTable implements DocumentObject {
private static final String XREF = "xref";
private Vector subSections;
private Entry defaultEntry;
private Body body;
private Header header;
public CrossReferenceTable() {
subSections = new Vector();
defaultEntry = new Entry();
}
public CrossReferenceTable(Header header, Body body) {
subSections = new Vector();
defaultEntry = new Entry();
this.body = body;
this.header = header;
SubSection subsection = new SubSection();
defaultEntry.setObjectNumber("");
defaultEntry.setGenNumber("65535"); // not sure if remember what this is doing. must check spec.
defaultEntry.setIsFree(true);
subsection.addEntry(defaultEntry);
Vector vector = body.getBodyObjects();
int i = header.getValue().getBytes().length;
for(int j = 0; j < vector.size(); j++) {
Entry entry = new Entry();
defaultEntry.setObjectNumber("" + i);
defaultEntry.setGenNumber("");
subsection.addEntry(entry);
i += ((DocumentObject)vector.elementAt(j)).getValue().getBytes().length;
}
subSections.add(subsection);
}
/**
* Updates the cross-reference table in regards to document objects added to the PDF
* document. Should be called prior to serialization, generation, or output of file.
**/
public void refresh() {
SubSection subsection = (SubSection)subSections.elementAt(subSections.size() - 1);
Vector vector = body.getBodyObjects();
int i = header.getValue().getBytes().length;
for(int j = 0; j < vector.size(); j++) {
Entry entry = new Entry();
entry.setObjectNumber("" + i);
entry.setGenNumber("");
subsection.addEntry(entry);
i += ((DocumentObject)vector.elementAt(j)).getValue().getBytes().length;
}
}
public void update(Header header, Body body) {
// no-op?
}
/**
*
* returns the specified subsection from this cross-reference table
*
* @param firstObject the object number of the start of the subsection to be returned.
* @param objectCount the number of objects in the subsection to be returned.
* @see SubSection
* @return a {@link SubSection} object defined by the starting object number and number of objects in the subsection
**/
public SubSection getSubSection(int firstObject, int objectCount) {
return new SubSection(firstObject, objectCount);
}
public String getValue() {
StringBuffer sb = new StringBuffer();
sb.append(XREF);
sb.append("\n");
try {
for(int i = 0; i < subSections.size(); i++) {
sb.append(((SubSection)subSections.elementAt(i)).getValue());
}
} catch(CrossReferenceTableEntryException crtee) {
sb.append(crtee.getMessage());
}
return sb.toString();
}
}