/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id: CrossReferenceStream.java 1661887 2015-02-24 11:23:44Z ssteiner $ */

package org.apache.fop.pdf.xref;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.fop.pdf.PDFArray;
import org.apache.fop.pdf.PDFDictionary;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFFilterList;
import org.apache.fop.pdf.PDFName;
import org.apache.fop.pdf.PDFObjectNumber;
import org.apache.fop.pdf.PDFStream;

A cross-reference stream, as described in Section 3.4.7 of the PDF 1.5 Reference.
/** * A cross-reference stream, as described in Section 3.4.7 of the PDF 1.5 Reference. */
public class CrossReferenceStream extends CrossReferenceObject { private static final PDFName XREF = new PDFName("XRef"); private final PDFDocument document; private final int objectNumber; private final List<ObjectReference> objectReferences; public CrossReferenceStream(PDFDocument document, int objectNumber, TrailerDictionary trailerDictionary, long startxref, List<Long> uncompressedObjectReferences, List<CompressedObjectReference> compressedObjectReferences) { super(trailerDictionary, startxref); this.document = document; this.objectNumber = objectNumber; this.objectReferences = new ArrayList<ObjectReference>(uncompressedObjectReferences.size()); for (Long offset : uncompressedObjectReferences) { objectReferences.add(offset == null ? null : new UncompressedObjectReference(offset)); } for (CompressedObjectReference ref : compressedObjectReferences) { while (ref.getObjectNumber().getNumber() > objectReferences.size()) { objectReferences.add(null); } this.objectReferences.set(ref.getObjectNumber().getNumber() - 1, ref); } }
{@inheritDoc}
/** {@inheritDoc} */
public void output(OutputStream stream) throws IOException { populateDictionary(); PDFStream helperStream = new PDFStream(trailerDictionary.getDictionary(), false) { @Override protected void setupFilterList() { PDFFilterList filterList = getFilterList(); assert !filterList.isInitialized(); filterList.addDefaultFilters(document.getFilterMap(), getDefaultFilterName()); } }; helperStream.setObjectNumber(new PDFObjectNumber(objectNumber)); helperStream.setDocument(document); ByteArrayOutputStream byteArray = new ByteArrayOutputStream(); DataOutputStream data = new DataOutputStream(byteArray); addFreeEntryForObject0(data); for (ObjectReference objectReference : objectReferences) { assert objectReference != null; objectReference.output(data); } new UncompressedObjectReference(startxref).output(data); data.close(); helperStream.setData(byteArray.toByteArray()); PDFDocument.outputIndirectObject(helperStream, stream); } private void populateDictionary() throws IOException { int objectCount = objectReferences.size() + 1; PDFDictionary dictionary = trailerDictionary.getDictionary(); dictionary.put("/Type", XREF); dictionary.put("/Size", objectCount + 1); dictionary.put("/W", new PDFArray(1, 8, 2)); } private void addFreeEntryForObject0(DataOutputStream data) throws IOException { data.write(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xff, (byte) 0xff}); } }