001/*
002 * $Id: PdfReaderInstance.java 4784 2011-03-15 08:33:00Z blowagie $
003 *
004 * This file is part of the iText (R) project.
005 * Copyright (c) 1998-2011 1T3XT BVBA
006 * Authors: Bruno Lowagie, Paulo Soares, et al.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU Affero General Public License version 3
010 * as published by the Free Software Foundation with the addition of the
011 * following permission added to Section 15 as permitted in Section 7(a):
012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
014 *
015 * This program is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 * or FITNESS FOR A PARTICULAR PURPOSE.
018 * See the GNU Affero General Public License for more details.
019 * You should have received a copy of the GNU Affero General Public License
020 * along with this program; if not, see http://www.gnu.org/licenses or write to
021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
022 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
023 * http://itextpdf.com/terms-of-use/
024 *
025 * The interactive user interfaces in modified source and object code versions
026 * of this program must display Appropriate Legal Notices, as required under
027 * Section 5 of the GNU Affero General Public License.
028 *
029 * In accordance with Section 7(b) of the GNU Affero General Public License,
030 * a covered work must retain the producer line in every PDF that is created
031 * or manipulated using iText.
032 *
033 * You can be released from the requirements of the license by purchasing
034 * a commercial license. Buying such a license is mandatory as soon as you
035 * develop commercial activities involving the iText software without
036 * disclosing the source code of your own applications.
037 * These activities include: offering paid services to customers as an ASP,
038 * serving PDFs on the fly in a web application, shipping iText with a closed
039 * source product.
040 *
041 * For more information, please contact iText Software Corp. at this
042 * address: sales@itextpdf.com
043 */
044package com.itextpdf.text.pdf;
045import java.io.IOException;
046import java.util.ArrayList;
047import java.util.HashMap;
048import java.util.HashSet;
049
050import com.itextpdf.text.error_messages.MessageLocalization;
051/**
052 * Instance of PdfReader in each output document.
053 *
054 * @author Paulo Soares
055 */
056class PdfReaderInstance {
057    static final PdfLiteral IDENTITYMATRIX = new PdfLiteral("[1 0 0 1 0 0]");
058    static final PdfNumber ONE = new PdfNumber(1);
059    int myXref[];
060    PdfReader reader;
061    RandomAccessFileOrArray file;
062    HashMap<Integer, PdfImportedPage> importedPages = new HashMap<Integer, PdfImportedPage>();
063    PdfWriter writer;
064    HashSet<Integer> visited = new HashSet<Integer>();
065    ArrayList<Integer> nextRound = new ArrayList<Integer>();
066
067    PdfReaderInstance(PdfReader reader, PdfWriter writer) {
068        this.reader = reader;
069        this.writer = writer;
070        file = reader.getSafeFile();
071        myXref = new int[reader.getXrefSize()];
072    }
073
074    PdfReader getReader() {
075        return reader;
076    }
077
078    PdfImportedPage getImportedPage(int pageNumber) {
079        if (!reader.isOpenedWithFullPermissions())
080            throw new IllegalArgumentException(MessageLocalization.getComposedMessage("pdfreader.not.opened.with.owner.password"));
081        if (pageNumber < 1 || pageNumber > reader.getNumberOfPages())
082            throw new IllegalArgumentException(MessageLocalization.getComposedMessage("invalid.page.number.1", pageNumber));
083        Integer i = Integer.valueOf(pageNumber);
084        PdfImportedPage pageT = importedPages.get(i);
085        if (pageT == null) {
086            pageT = new PdfImportedPage(this, writer, pageNumber);
087            importedPages.put(i, pageT);
088        }
089        return pageT;
090    }
091
092    int getNewObjectNumber(int number, int generation) {
093        if (myXref[number] == 0) {
094            myXref[number] = writer.getIndirectReferenceNumber();
095            nextRound.add(Integer.valueOf(number));
096        }
097        return myXref[number];
098    }
099
100    RandomAccessFileOrArray getReaderFile() {
101        return file;
102    }
103
104    PdfObject getResources(int pageNumber) {
105        PdfObject obj = PdfReader.getPdfObjectRelease(reader.getPageNRelease(pageNumber).get(PdfName.RESOURCES));
106        return obj;
107    }
108
109    /**
110     * Gets the content stream of a page as a PdfStream object.
111     * @param   pageNumber                      the page of which you want the stream
112     * @param   compressionLevel        the compression level you want to apply to the stream
113     * @return  a PdfStream object
114     * @since   2.1.3 (the method already existed without param compressionLevel)
115     */
116    PdfStream getFormXObject(int pageNumber, int compressionLevel) throws IOException {
117        PdfDictionary page = reader.getPageNRelease(pageNumber);
118        PdfObject contents = PdfReader.getPdfObjectRelease(page.get(PdfName.CONTENTS));
119        PdfDictionary dic = new PdfDictionary();
120        byte bout[] = null;
121        if (contents != null) {
122            if (contents.isStream())
123                dic.putAll((PRStream)contents);
124            else
125                bout = reader.getPageContent(pageNumber, file);
126        }
127        else
128            bout = new byte[0];
129        dic.put(PdfName.RESOURCES, PdfReader.getPdfObjectRelease(page.get(PdfName.RESOURCES)));
130        dic.put(PdfName.TYPE, PdfName.XOBJECT);
131        dic.put(PdfName.SUBTYPE, PdfName.FORM);
132        PdfImportedPage impPage = importedPages.get(Integer.valueOf(pageNumber));
133        dic.put(PdfName.BBOX, new PdfRectangle(impPage.getBoundingBox()));
134        PdfArray matrix = impPage.getMatrix();
135        if (matrix == null)
136            dic.put(PdfName.MATRIX, IDENTITYMATRIX);
137        else
138            dic.put(PdfName.MATRIX, matrix);
139        dic.put(PdfName.FORMTYPE, ONE);
140        PRStream stream;
141        if (bout == null) {
142            stream = new PRStream((PRStream)contents, dic);
143        }
144        else {
145            stream = new PRStream(reader, bout, compressionLevel);
146            stream.putAll(dic);
147        }
148        return stream;
149    }
150
151    void writeAllVisited() throws IOException {
152        while (!nextRound.isEmpty()) {
153            ArrayList<Integer> vec = nextRound;
154            nextRound = new ArrayList<Integer>();
155            for (int k = 0; k < vec.size(); ++k) {
156                Integer i = vec.get(k);
157                if (!visited.contains(i)) {
158                    visited.add(i);
159                    int n = i.intValue();
160                    writer.addToBody(reader.getPdfObjectRelease(n), myXref[n]);
161                }
162            }
163        }
164    }
165
166    void writeAllPages() throws IOException {
167        try {
168            file.reOpen();
169            for (Object element : importedPages.values()) {
170                PdfImportedPage ip = (PdfImportedPage)element;
171                if (ip.isToCopy()) {
172                        writer.addToBody(ip.getFormXObject(writer.getCompressionLevel()), ip.getIndirectReference());
173                        ip.setCopied();
174                }
175            }
176            writeAllVisited();
177        }
178        finally {
179            try {
180                reader.close();
181                file.close();
182            }
183            catch (Exception e) {
184                //Empty on purpose
185            }
186        }
187    }
188}