001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.text.pdf;
020
021import java.io.ByteArrayInputStream;
022import java.io.File;
023import java.io.IOException;
024import java.util.HashMap;
025import java.util.HashSet;
026import java.util.Iterator;
027import java.util.Map;
028import java.util.Set;
029
030import lucee.commons.io.IOUtil;
031import lucee.commons.io.res.Resource;
032import lucee.commons.io.res.type.file.FileResource;
033import lucee.commons.lang.StringUtil;
034import lucee.runtime.PageContext;
035import lucee.runtime.dump.DumpData;
036import lucee.runtime.dump.DumpProperties;
037import lucee.runtime.dump.DumpTable;
038import lucee.runtime.exp.ApplicationException;
039import lucee.runtime.exp.PageException;
040import lucee.runtime.exp.PageRuntimeException;
041import lucee.runtime.op.Caster;
042import lucee.runtime.type.Collection;
043import lucee.runtime.type.Struct;
044import lucee.runtime.type.StructImpl;
045import lucee.runtime.type.dt.DateTime;
046import lucee.runtime.type.util.StructSupport;
047
048import org.pdfbox.exceptions.CryptographyException;
049import org.pdfbox.exceptions.InvalidPasswordException;
050import org.pdfbox.pdmodel.PDDocument;
051
052import com.lowagie.text.pdf.PdfReader;
053import com.lowagie.text.pdf.PdfWriter;
054
055public class PDFDocument extends StructSupport implements Struct {
056
057        private byte[] barr;
058        private String password;
059        private Resource resource;
060        private Set<Integer> pages;
061
062        public PDFDocument(byte[] barr, String password) {
063                this.barr=barr;
064                this.password=password;
065        }
066
067        public PDFDocument(Resource resource, String password) {
068                this.resource=resource;
069                this.password=password;
070        }
071
072        public PDFDocument(byte[] barr, Resource resource, String password) {
073                this.resource=resource;
074                this.barr=barr;
075                this.password=password;
076        }
077        
078
079        @Override
080        public void clear() {
081                getInfo().clear();
082        }
083
084
085        @Override
086        public boolean containsKey(Key key) {
087                return getInfo().containsKey(key);
088        }
089
090        @Override
091        public Collection duplicate(boolean deepCopy) {
092                PDFDocument duplicate=new PDFDocument(barr,resource,password);
093                return duplicate;
094        }
095        
096
097        @Override
098        public Object get(Key key) throws PageException {
099                return getInfo().get(key);
100        }
101
102        @Override
103        public Object get(Key key, Object defaultValue) {
104                return getInfo().get(key, defaultValue);
105        }
106
107        @Override
108        public Key[] keys() {
109                return getInfo().keys();
110        }
111
112        @Override
113        public Object remove(Key key) throws PageException {
114                return getInfo().remove(key);
115        }
116
117        @Override
118        public Object removeEL(Key key) {
119                return getInfo().removeEL(key);
120        }
121
122        @Override
123        public Object set(Key key, Object value) throws PageException {
124                return getInfo().set(key, value);
125        }
126
127        @Override
128        public Object setEL(Key key, Object value) {
129                return getInfo().setEL(key, value);
130        }
131
132        @Override
133        public int size() {
134                return getInfo().size();
135        }
136
137        @Override
138        public DumpData toDumpData(PageContext pageContext, int maxlevel,DumpProperties properties) {
139                
140                DumpData dd = getInfo().toDumpData(pageContext, maxlevel,properties);
141                if(dd instanceof DumpTable)((DumpTable)dd).setTitle("Struct (PDFDocument)");
142                return dd;
143        }
144
145        @Override
146        public Iterator<Collection.Key> keyIterator() {
147                return getInfo().keyIterator();
148        }
149    
150    @Override
151        public Iterator<String> keysAsStringIterator() {
152        return getInfo().keysAsStringIterator();
153    }
154        
155        @Override
156        public Iterator<Entry<Key, Object>> entryIterator() {
157                return getInfo().entryIterator();
158        }
159        
160        @Override
161        public Iterator<Object> valueIterator() {
162                return getInfo().valueIterator();
163        }
164
165        @Override
166        public boolean castToBooleanValue() throws PageException {
167                return getInfo().castToBooleanValue();
168        }
169    
170    @Override
171    public Boolean castToBoolean(Boolean defaultValue) {
172        return getInfo().castToBoolean(defaultValue);
173    }
174
175        @Override
176        public DateTime castToDateTime() throws PageException {
177                return getInfo().castToDateTime();
178        }
179    
180    @Override
181    public DateTime castToDateTime(DateTime defaultValue) {
182        return getInfo().castToDateTime(defaultValue);
183    }
184
185        @Override
186        public double castToDoubleValue() throws PageException {
187                return getInfo().castToDoubleValue();
188        }
189    
190    @Override
191    public double castToDoubleValue(double defaultValue) {
192        return getInfo().castToDoubleValue(defaultValue);
193    }
194
195        @Override
196        public String castToString() throws PageException {
197                return getInfo().castToString();
198        }
199        @Override
200        public String castToString(String defaultValue) {
201                return getInfo().castToString(defaultValue);
202        }
203
204        @Override
205        public int compareTo(String str) throws PageException {
206                return getInfo().compareTo(str);
207        }
208
209        @Override
210        public int compareTo(boolean b) throws PageException {
211                return getInfo().compareTo(b);
212        }
213
214        @Override
215        public int compareTo(double d) throws PageException {
216                return getInfo().compareTo(d);
217        }
218
219        @Override
220        public int compareTo(DateTime dt) throws PageException {
221                return getInfo().compareTo(dt);
222        }
223///////////////////////////////////////////////
224        
225        public PdfReader getPdfReader() throws ApplicationException {
226                try {
227                        if(barr!=null) {
228                                if(password!=null)return new PdfReader(barr,password.getBytes());
229                                return new PdfReader(barr);
230                        }
231                        if(password!=null)return new PdfReader(IOUtil.toBytes(resource),password.getBytes());
232                        return new PdfReader(IOUtil.toBytes(resource));
233                }
234                catch(IOException ioe) {
235                        throw new ApplicationException("can not load file ["+resource+"]",ioe.getMessage());
236                }
237        }
238        
239        private String getFilePath() {
240                if(resource==null) return "";
241                return resource.getAbsolutePath();
242        }
243
244        public Struct getInfo()  {
245
246                PdfReader pr=null;
247                try {
248                        pr=getPdfReader();
249                        //PdfDictionary catalog = pr.getCatalog();
250                        int permissions = pr.getPermissions();
251                        boolean encrypted=pr.isEncrypted();
252                        
253                        Struct info=new StructImpl();
254                        info.setEL("FilePath", getFilePath());
255                        
256                        // access
257                        info.setEL("ChangingDocument", allowed(encrypted,permissions,PdfWriter.ALLOW_MODIFY_CONTENTS));
258                        info.setEL("Commenting", allowed(encrypted,permissions,PdfWriter.ALLOW_MODIFY_ANNOTATIONS));
259                        info.setEL("ContentExtraction", allowed(encrypted,permissions,PdfWriter.ALLOW_SCREENREADERS));
260                        info.setEL("CopyContent", allowed(encrypted,permissions,PdfWriter.ALLOW_COPY));
261                        info.setEL("DocumentAssembly", allowed(encrypted,permissions,PdfWriter.ALLOW_ASSEMBLY+PdfWriter.ALLOW_MODIFY_CONTENTS));
262                        info.setEL("FillingForm", allowed(encrypted,permissions,PdfWriter.ALLOW_FILL_IN+PdfWriter.ALLOW_MODIFY_ANNOTATIONS));
263                        info.setEL("Printing", allowed(encrypted,permissions,PdfWriter.ALLOW_PRINTING));
264                        info.setEL("Secure", "");
265                        info.setEL("Signing", allowed(encrypted,permissions,PdfWriter.ALLOW_MODIFY_ANNOTATIONS+PdfWriter.ALLOW_MODIFY_CONTENTS+PdfWriter.ALLOW_FILL_IN));
266                        
267                        info.setEL("Encryption", encrypted?"Password Security":"No Security");// MUST
268                        info.setEL("TotalPages", Caster.toDouble(pr.getNumberOfPages()));
269                        info.setEL("Version", "1."+pr.getPdfVersion());
270                        info.setEL("permissions", ""+permissions);
271                        info.setEL("permiss", ""+PdfWriter.ALLOW_FILL_IN);
272                        
273                        info.setEL("Application", "");
274                        info.setEL("Author", "");
275                        info.setEL("CenterWindowOnScreen", "");
276                        info.setEL("Created", "");
277                        info.setEL("FitToWindow", "");
278                        info.setEL("HideMenubar", "");
279                        info.setEL("HideToolbar", "");
280                        info.setEL("HideWindowUI", "");
281                        info.setEL("Keywords", "");
282                        info.setEL("Language", "");
283                        info.setEL("Modified", "");
284                        info.setEL("PageLayout", "");
285                        info.setEL("Producer", "");
286                        info.setEL("Properties", "");
287                        info.setEL("ShowDocumentsOption", "");
288                        info.setEL("ShowWindowsOption", "");
289                        info.setEL("Subject", "");
290                        info.setEL("Title", "");
291                        info.setEL("Trapped", "");
292        
293                        // info
294                        HashMap imap = pr.getInfo();
295                        Iterator it = imap.entrySet().iterator();
296                        Map.Entry entry;
297                        while(it.hasNext()) {
298                                entry=(Entry) it.next();
299                                info.setEL(Caster.toString(entry.getKey(),null), entry.getValue());
300                        }
301                        return info;
302                }
303                catch(PageException pe) {
304                        throw new PageRuntimeException(pe);
305                }
306                finally {
307                        if(pr!=null)pr.close();
308                }
309        }
310        
311
312        
313
314        private static Object allowed(boolean encrypted, int permissions, int permission) {
315                return (!encrypted || (permissions&permission)>0)?"Allowed":"Not Allowed";
316        }
317
318
319
320        public void setPages(String strPages) throws PageException {
321                if(StringUtil.isEmpty(strPages))return;
322                if(pages==null)
323                        pages=new HashSet<Integer>();
324                PDFUtil.parsePageDefinition(pages,strPages);
325        }
326
327        public Set<Integer> getPages() {
328                //if(pages==null)pages=new HashSet();
329                return pages;
330        }
331
332        public Resource getResource() {
333                return resource;
334        }
335        public byte[] getRaw() throws IOException {
336                if(barr!=null)return barr;
337                return IOUtil.toBytes(resource);
338        }
339
340        @Override
341        public boolean containsValue(Object value) {
342                return getInfo().containsValue(value);
343        }
344
345        @Override
346        public java.util.Collection values() {
347                return getInfo().values();
348        }
349        
350        public PDDocument toPDDocument() throws CryptographyException, InvalidPasswordException, IOException {
351                PDDocument doc;
352                if(barr!=null) 
353                        doc= PDDocument.load(new ByteArrayInputStream(barr,0,barr.length));
354                else if(resource instanceof FileResource)
355                        doc= PDDocument.load((File)resource);
356                else 
357                        doc= PDDocument.load(new ByteArrayInputStream(IOUtil.toBytes(resource),0,barr.length));
358                
359                if(password!=null)doc.decrypt(password);
360                
361                
362                return doc;
363                
364        }
365
366}