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(); } }