001/*
002 * $Id: PdfFileSpecification.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;
045
046import java.io.File;
047import java.io.FileInputStream;
048import java.io.IOException;
049import java.io.InputStream;
050import java.net.URL;
051import com.itextpdf.text.error_messages.MessageLocalization;
052
053import com.itextpdf.text.pdf.collection.PdfCollectionItem;
054/** Specifies a file or an URL. The file can be extern or embedded.
055 *
056 * @author Paulo Soares
057 */
058public class PdfFileSpecification extends PdfDictionary {
059    protected PdfWriter writer;
060    protected PdfIndirectReference ref;
061    
062    /** Creates a new instance of PdfFileSpecification. The static methods are preferred. */
063    public PdfFileSpecification() {
064        super(PdfName.FILESPEC);
065    }
066    
067    /**
068     * Creates a file specification of type URL.
069     * @param writer the <CODE>PdfWriter</CODE>
070     * @param url the URL
071     * @return the file specification
072     */    
073    public static PdfFileSpecification url(PdfWriter writer, String url) {
074        PdfFileSpecification fs = new PdfFileSpecification();
075        fs.writer = writer;
076        fs.put(PdfName.FS, PdfName.URL);
077        fs.put(PdfName.F, new PdfString(url));
078        return fs;
079    }
080
081    /**
082     * Creates a file specification with the file embedded. The file may
083     * come from the file system or from a byte array. The data is flate compressed.
084     * @param writer the <CODE>PdfWriter</CODE>
085     * @param filePath the file path
086     * @param fileDisplay the file information that is presented to the user
087     * @param fileStore the byte array with the file. If it is not <CODE>null</CODE>
088     * it takes precedence over <CODE>filePath</CODE>
089     * @throws IOException on error
090     * @return the file specification
091     */    
092    public static PdfFileSpecification fileEmbedded(PdfWriter writer, String filePath, String fileDisplay, byte fileStore[]) throws IOException {
093        return fileEmbedded(writer, filePath, fileDisplay, fileStore, PdfStream.BEST_COMPRESSION);
094    }
095
096    /**
097     * Creates a file specification with the file embedded. The file may
098     * come from the file system or from a byte array. The data is flate compressed.
099     * @param writer the <CODE>PdfWriter</CODE>
100     * @param filePath the file path
101     * @param fileDisplay the file information that is presented to the user
102     * @param fileStore the byte array with the file. If it is not <CODE>null</CODE>
103     * it takes precedence over <CODE>filePath</CODE>
104     * @param compressionLevel  the compression level to be used for compressing the file
105     * it takes precedence over <CODE>filePath</CODE>
106     * @throws IOException on error
107     * @return the file specification
108     * @since   2.1.3
109     */    
110    public static PdfFileSpecification fileEmbedded(PdfWriter writer, String filePath, String fileDisplay, byte fileStore[], int compressionLevel) throws IOException {
111        return fileEmbedded(writer, filePath, fileDisplay, fileStore, null, null, compressionLevel);
112    }
113    
114    
115    /**
116     * Creates a file specification with the file embedded. The file may
117     * come from the file system or from a byte array.
118     * @param writer the <CODE>PdfWriter</CODE>
119     * @param filePath the file path
120     * @param fileDisplay the file information that is presented to the user
121     * @param fileStore the byte array with the file. If it is not <CODE>null</CODE>
122     * it takes precedence over <CODE>filePath</CODE>
123     * @param compress sets the compression on the data. Multimedia content will benefit little
124     * from compression
125     * @throws IOException on error
126     * @return the file specification
127     */    
128    public static PdfFileSpecification fileEmbedded(PdfWriter writer, String filePath, String fileDisplay, byte fileStore[], boolean compress) throws IOException {
129        return fileEmbedded(writer, filePath, fileDisplay, fileStore, null, null, compress ? PdfStream.BEST_COMPRESSION : PdfStream.NO_COMPRESSION);
130    }
131    
132    /**
133     * Creates a file specification with the file embedded. The file may
134     * come from the file system or from a byte array.
135     * @param writer the <CODE>PdfWriter</CODE>
136     * @param filePath the file path
137     * @param fileDisplay the file information that is presented to the user
138     * @param fileStore the byte array with the file. If it is not <CODE>null</CODE>
139     * it takes precedence over <CODE>filePath</CODE>
140     * @param compress sets the compression on the data. Multimedia content will benefit little
141     * from compression
142     * @param mimeType the optional mimeType
143     * @param fileParameter the optional extra file parameters such as the creation or modification date
144     * @throws IOException on error
145     * @return the file specification
146     */    
147    public static PdfFileSpecification fileEmbedded(PdfWriter writer, String filePath, String fileDisplay, byte fileStore[], boolean compress, String mimeType, PdfDictionary fileParameter) throws IOException {
148        return fileEmbedded(writer, filePath, fileDisplay, fileStore, mimeType, fileParameter, compress ? PdfStream.BEST_COMPRESSION : PdfStream.NO_COMPRESSION);
149    }
150    
151    /**
152     * Creates a file specification with the file embedded. The file may
153     * come from the file system or from a byte array.
154     * @param writer the <CODE>PdfWriter</CODE>
155     * @param filePath the file path
156     * @param fileDisplay the file information that is presented to the user
157     * @param fileStore the byte array with the file. If it is not <CODE>null</CODE>
158     * it takes precedence over <CODE>filePath</CODE>
159     * @param mimeType the optional mimeType
160     * @param fileParameter the optional extra file parameters such as the creation or modification date
161     * @param compressionLevel the level of compression
162     * @throws IOException on error
163     * @return the file specification
164     * @since   2.1.3
165     */    
166    public static PdfFileSpecification fileEmbedded(PdfWriter writer, String filePath, String fileDisplay, byte fileStore[], String mimeType, PdfDictionary fileParameter, int compressionLevel) throws IOException {
167        PdfFileSpecification fs = new PdfFileSpecification();
168        fs.writer = writer;
169        fs.put(PdfName.F, new PdfString(fileDisplay));
170        fs.setUnicodeFileName(fileDisplay, false);
171        PdfEFStream stream;
172        InputStream in = null;
173        PdfIndirectReference ref;
174        PdfIndirectReference refFileLength = null;
175        try {
176            if (fileStore == null) {
177                refFileLength = writer.getPdfIndirectReference();
178                File file = new File(filePath);
179                if (file.canRead()) {
180                    in = new FileInputStream(filePath);
181                }
182                else {
183                    if (filePath.startsWith("file:/") || filePath.startsWith("http://") || filePath.startsWith("https://") || filePath.startsWith("jar:")) {
184                        in = new URL(filePath).openStream();
185                    }
186                    else {
187                        in = BaseFont.getResourceStream(filePath);
188                        if (in == null)
189                            throw new IOException(MessageLocalization.getComposedMessage("1.not.found.as.file.or.resource", filePath));
190                    }
191                }
192                stream = new PdfEFStream(in, writer);
193            }
194            else {
195                stream = new PdfEFStream(fileStore);
196            }
197            stream.put(PdfName.TYPE, PdfName.EMBEDDEDFILE);
198            stream.flateCompress(compressionLevel);
199            PdfDictionary param = new PdfDictionary();
200            if (fileParameter != null) {
201                param.merge(fileParameter);
202            }
203
204            if (fileStore != null) {
205                param.put(PdfName.SIZE, new PdfNumber(stream.getRawLength()));
206                stream.put(PdfName.PARAMS, param);
207            }
208            else
209                stream.put(PdfName.PARAMS, refFileLength);
210
211            if (mimeType != null)
212                stream.put(PdfName.SUBTYPE, new PdfName(mimeType));
213
214            ref = writer.addToBody(stream).getIndirectReference();
215            if (fileStore == null) {
216                stream.writeLength();
217                param.put(PdfName.SIZE, new PdfNumber(stream.getRawLength()));
218                writer.addToBody(param, refFileLength);
219            }
220        }
221        finally {
222            if (in != null)
223                try{in.close();}catch(Exception e){}
224        }
225        PdfDictionary f = new PdfDictionary();
226        f.put(PdfName.F, ref);
227        f.put(PdfName.UF, ref);
228        fs.put(PdfName.EF, f);
229        return fs;
230    }
231    
232    /**
233     * Creates a file specification for an external file.
234     * @param writer the <CODE>PdfWriter</CODE>
235     * @param filePath the file path
236     * @return the file specification
237     */
238    public static PdfFileSpecification fileExtern(PdfWriter writer, String filePath) {
239        PdfFileSpecification fs = new PdfFileSpecification();
240        fs.writer = writer;
241        fs.put(PdfName.F, new PdfString(filePath));
242        fs.setUnicodeFileName(filePath, false);
243        return fs;
244    }
245    
246    /**
247     * Gets the indirect reference to this file specification.
248     * Multiple invocations will retrieve the same value.
249     * @throws IOException on error
250     * @return the indirect reference
251     */    
252    public PdfIndirectReference getReference() throws IOException {
253        if (ref != null)
254            return ref;
255        ref = writer.addToBody(this).getIndirectReference();
256        return ref;
257    }
258    
259    /**
260     * Sets the file name (the key /F) string as an hex representation
261     * to support multi byte file names. The name must have the slash and
262     * backslash escaped according to the file specification rules
263     * @param fileName the file name as a byte array
264     */    
265    public void setMultiByteFileName(byte fileName[]) {
266        put(PdfName.F, new PdfString(fileName).setHexWriting(true));
267    }
268    
269    /**
270     * Adds the unicode file name (the key /UF). This entry was introduced
271     * in PDF 1.7. The filename must have the slash and backslash escaped
272     * according to the file specification rules.
273     * @param filename  the filename
274     * @param unicode   if true, the filename is UTF-16BE encoded; otherwise PDFDocEncoding is used;
275     */    
276    public void setUnicodeFileName(String filename, boolean unicode) {
277        put(PdfName.UF, new PdfString(filename, unicode ? PdfObject.TEXT_UNICODE : PdfObject.TEXT_PDFDOCENCODING));
278    }
279    
280    /**
281     * Sets a flag that indicates whether an external file referenced by the file
282     * specification is volatile. If the value is true, applications should never
283     * cache a copy of the file.
284     * @param volatile_file     if true, the external file should not be cached
285     */
286    public void setVolatile(boolean volatile_file) {
287        put(PdfName.V, new PdfBoolean(volatile_file));
288    }
289    
290    /**
291     * Adds a description for the file that is specified here.
292     * @param description       some text
293     * @param unicode           if true, the text is added as a unicode string
294     */
295    public void addDescription(String description, boolean unicode) {
296        put(PdfName.DESC, new PdfString(description, unicode ? PdfObject.TEXT_UNICODE : PdfObject.TEXT_PDFDOCENCODING));
297    }
298    
299    /**
300     * Adds the Collection item dictionary.
301     */
302    public void addCollectionItem(PdfCollectionItem ci) {
303        put(PdfName.CI, ci);
304    }
305}