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 }