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