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}