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            /**
062             * @see railo.runtime.type.Collection#clear()
063             */
064            public void clear() {
065                    getInfo().clear();
066            }
067    
068    
069            /**
070             * @see railo.runtime.type.Collection#containsKey(railo.runtime.type.Collection.Key)
071             */
072            public boolean containsKey(Key key) {
073                    return getInfo().containsKey(key);
074            }
075    
076            /**
077             * @see railo.runtime.type.Collection#duplicate(boolean)
078             */
079            public Collection duplicate(boolean deepCopy) {
080                    PDFDocument duplicate=new PDFDocument(barr,resource,password);
081                    return duplicate;
082            }
083            
084    
085            /**
086             * @see railo.runtime.type.Collection#get(railo.runtime.type.Collection.Key)
087             */
088            public Object get(Key key) throws PageException {
089                    return getInfo().get(key);
090            }
091    
092            /**
093             * @see railo.runtime.type.Collection#get(railo.runtime.type.Collection.Key, java.lang.Object)
094             */
095            public Object get(Key key, Object defaultValue) {
096                    return getInfo().get(key, defaultValue);
097            }
098    
099            /**
100             * @see railo.runtime.type.Collection#keys()
101             */
102            public Key[] keys() {
103                    return getInfo().keys();
104            }
105    
106            /**
107             * @see railo.runtime.type.Collection#keysAsString()
108             */
109            public String[] keysAsString() {
110                    return getInfo().keysAsString();
111            }
112    
113            /**
114             * @see railo.runtime.type.Collection#remove(railo.runtime.type.Collection.Key)
115             */
116            public Object remove(Key key) throws PageException {
117                    return getInfo().remove(key);
118            }
119    
120            /**
121             * @see railo.runtime.type.Collection#removeEL(railo.runtime.type.Collection.Key)
122             */
123            public Object removeEL(Key key) {
124                    return getInfo().removeEL(key);
125            }
126    
127            /**
128             * @see railo.runtime.type.Collection#set(railo.runtime.type.Collection.Key, java.lang.Object)
129             */
130            public Object set(Key key, Object value) throws PageException {
131                    return getInfo().set(key, value);
132            }
133    
134            /**
135             * @see railo.runtime.type.Collection#setEL(railo.runtime.type.Collection.Key, java.lang.Object)
136             */
137            public Object setEL(Key key, Object value) {
138                    return getInfo().setEL(key, value);
139            }
140    
141            /**
142             * @see railo.runtime.type.Collection#size()
143             */
144            public int size() {
145                    return getInfo().size();
146            }
147    
148            /**
149             * @see railo.runtime.dump.Dumpable#toDumpData(railo.runtime.PageContext, int, railo.runtime.dump.DumpProperties)
150             */
151            public DumpData toDumpData(PageContext pageContext, int maxlevel,DumpProperties properties) {
152                    
153                    DumpData dd = getInfo().toDumpData(pageContext, maxlevel,properties);
154                    if(dd instanceof DumpTable)((DumpTable)dd).setTitle("Struct (PDFDocument)");
155                    return dd;
156            }
157    
158            /**
159             * @see railo.runtime.type.Iteratorable#keyIterator()
160             */
161            public Iterator keyIterator() {
162                    return getInfo().keyIterator();
163            }
164    
165            /**
166             * @see railo.runtime.op.Castable#castToBooleanValue()
167             */
168            public boolean castToBooleanValue() throws PageException {
169                    return getInfo().castToBooleanValue();
170            }
171        
172        /**
173         * @see railo.runtime.op.Castable#castToBoolean(java.lang.Boolean)
174         */
175        public Boolean castToBoolean(Boolean defaultValue) {
176            return getInfo().castToBoolean(defaultValue);
177        }
178    
179            /**
180             * @see railo.runtime.op.Castable#castToDateTime()
181             */
182            public DateTime castToDateTime() throws PageException {
183                    return getInfo().castToDateTime();
184            }
185        
186        /**
187         * @see railo.runtime.op.Castable#castToDateTime(railo.runtime.type.dt.DateTime)
188         */
189        public DateTime castToDateTime(DateTime defaultValue) {
190            return getInfo().castToDateTime(defaultValue);
191        }
192    
193            /**
194             * @see railo.runtime.op.Castable#castToDoubleValue()
195             */
196            public double castToDoubleValue() throws PageException {
197                    return getInfo().castToDoubleValue();
198            }
199        
200        /**
201         * @see railo.runtime.op.Castable#castToDoubleValue(double)
202         */
203        public double castToDoubleValue(double defaultValue) {
204            return getInfo().castToDoubleValue(defaultValue);
205        }
206    
207            /**
208             * @see railo.runtime.op.Castable#castToString()
209             */
210            public String castToString() throws PageException {
211                    return getInfo().castToString();
212            }
213            /**
214             * @see railo.runtime.type.util.StructSupport#castToString(java.lang.String)
215             */
216            public String castToString(String defaultValue) {
217                    return getInfo().castToString(defaultValue);
218            }
219    
220            /**
221             * @see railo.runtime.op.Castable#compareTo(java.lang.String)
222             */
223            public int compareTo(String str) throws PageException {
224                    return getInfo().compareTo(str);
225            }
226    
227            /**
228             * @see railo.runtime.op.Castable#compareTo(boolean)
229             */
230            public int compareTo(boolean b) throws PageException {
231                    return getInfo().compareTo(b);
232            }
233    
234            /**
235             * @see railo.runtime.op.Castable#compareTo(double)
236             */
237            public int compareTo(double d) throws PageException {
238                    return getInfo().compareTo(d);
239            }
240    
241            /**
242             * @see railo.runtime.op.Castable#compareTo(railo.runtime.type.dt.DateTime)
243             */
244            public int compareTo(DateTime dt) throws PageException {
245                    return getInfo().compareTo(dt);
246            }
247    ///////////////////////////////////////////////
248            
249            public PdfReader getPdfReader() throws ApplicationException {
250                    try {
251                            if(barr!=null) {
252                                    if(password!=null)return new PdfReader(barr,password.getBytes());
253                                    return new PdfReader(barr);
254                            }
255                            if(password!=null)return new PdfReader(IOUtil.toBytes(resource),password.getBytes());
256                            return new PdfReader(IOUtil.toBytes(resource));
257                    }
258                    catch(IOException ioe) {
259                            throw new ApplicationException("can not load file ["+resource+"]",ioe.getMessage());
260                    }
261            }
262            
263            private String getFilePath() {
264                    if(resource==null) return "";
265                    return resource.getAbsolutePath();
266            }
267    
268            public Struct getInfo()  {
269    
270                    PdfReader pr=null;
271                    try {
272                            pr=getPdfReader();
273                            //PdfDictionary catalog = pr.getCatalog();
274                            int permissions = pr.getPermissions();
275                            boolean encrypted=pr.isEncrypted();
276                            
277                            Struct info=new StructImpl();
278                            info.setEL("FilePath", getFilePath());
279                            
280                            // access
281                            info.setEL("ChangingDocument", allowed(encrypted,permissions,PdfWriter.ALLOW_MODIFY_CONTENTS));
282                            info.setEL("Commenting", allowed(encrypted,permissions,PdfWriter.ALLOW_MODIFY_ANNOTATIONS));
283                            info.setEL("ContentExtraction", allowed(encrypted,permissions,PdfWriter.ALLOW_SCREENREADERS));
284                            info.setEL("CopyContent", allowed(encrypted,permissions,PdfWriter.ALLOW_COPY));
285                            info.setEL("DocumentAssembly", allowed(encrypted,permissions,PdfWriter.ALLOW_ASSEMBLY+PdfWriter.ALLOW_MODIFY_CONTENTS));
286                            info.setEL("FillingForm", allowed(encrypted,permissions,PdfWriter.ALLOW_FILL_IN+PdfWriter.ALLOW_MODIFY_ANNOTATIONS));
287                            info.setEL("Printing", allowed(encrypted,permissions,PdfWriter.ALLOW_PRINTING));
288                            info.setEL("Secure", "");
289                            info.setEL("Signing", allowed(encrypted,permissions,PdfWriter.ALLOW_MODIFY_ANNOTATIONS+PdfWriter.ALLOW_MODIFY_CONTENTS+PdfWriter.ALLOW_FILL_IN));
290                            
291                            info.setEL("Encryption", encrypted?"Password Security":"No Security");// MUST
292                            info.setEL("TotalPages", Caster.toDouble(pr.getNumberOfPages()));
293                            info.setEL("Version", "1."+pr.getPdfVersion());
294                            info.setEL("permissions", ""+permissions);
295                            info.setEL("permiss", ""+PdfWriter.ALLOW_FILL_IN);
296                            
297                            info.setEL("Application", "");
298                            info.setEL("Author", "");
299                            info.setEL("CenterWindowOnScreen", "");
300                            info.setEL("Created", "");
301                            info.setEL("FitToWindow", "");
302                            info.setEL("HideMenubar", "");
303                            info.setEL("HideToolbar", "");
304                            info.setEL("HideWindowUI", "");
305                            info.setEL("Keywords", "");
306                            info.setEL("Language", "");
307                            info.setEL("Modified", "");
308                            info.setEL("PageLayout", "");
309                            info.setEL("Producer", "");
310                            info.setEL("Properties", "");
311                            info.setEL("ShowDocumentsOption", "");
312                            info.setEL("ShowWindowsOption", "");
313                            info.setEL("Subject", "");
314                            info.setEL("Title", "");
315                            info.setEL("Trapped", "");
316            
317                            // info
318                            HashMap imap = pr.getInfo();
319                            Iterator it = imap.entrySet().iterator();
320                            Map.Entry entry;
321                            while(it.hasNext()) {
322                                    entry=(Entry) it.next();
323                                    info.setEL(Caster.toString(entry.getKey(),null), entry.getValue());
324                            }
325                            return info;
326                    }
327                    catch(PageException pe) {
328                            throw new PageRuntimeException(pe);
329                    }
330                    finally {
331                            if(pr!=null)pr.close();
332                    }
333            }
334            
335    
336            
337    
338            private static Object allowed(boolean encrypted, int permissions, int permission) {
339                    return (!encrypted || (permissions&permission)>0)?"Allowed":"Not Allowed";
340            }
341    
342    
343    
344            public void setPages(String strPages) throws PageException {
345                    if(StringUtil.isEmpty(strPages))return;
346                    if(pages==null)
347                            pages=new HashSet<Integer>();
348                    PDFUtil.parsePageDefinition(pages,strPages);
349            }
350    
351            public Set<Integer> getPages() {
352                    //if(pages==null)pages=new HashSet();
353                    return pages;
354            }
355    
356            public Resource getResource() {
357                    return resource;
358            }
359            public byte[] getRaw() throws IOException {
360                    if(barr!=null)return barr;
361                    return IOUtil.toBytes(resource);
362            }
363    
364            /**
365             * @see java.util.Map#containsValue(java.lang.Object)
366             */
367            public boolean containsValue(Object value) {
368                    return getInfo().containsValue(value);
369            }
370    
371            /**
372             * @see java.util.Map#values()
373             */
374            public java.util.Collection values() {
375                    return getInfo().values();
376            }
377            
378            public PDDocument toPDDocument() throws CryptographyException, InvalidPasswordException, IOException {
379                    PDDocument doc;
380                    if(barr!=null) 
381                            doc= PDDocument.load(new ByteArrayInputStream(barr,0,barr.length));
382                    else if(resource instanceof FileResource)
383                            doc= PDDocument.load((File)resource);
384                    else 
385                            doc= PDDocument.load(new ByteArrayInputStream(IOUtil.toBytes(resource),0,barr.length));
386                    
387                    if(password!=null)doc.decrypt(password);
388                    
389                    
390                    return doc;
391                    
392            }
393    
394    }