1 16 17 package org.apache.poi.hpsf; 18 19 import java.io.ByteArrayOutputStream ; 20 import java.io.IOException ; 21 import java.io.OutputStream ; 22 import java.util.Collections ; 23 import java.util.Comparator ; 24 import java.util.Iterator ; 25 import java.util.LinkedList ; 26 import java.util.List ; 27 import java.util.ListIterator ; 28 import java.util.Map ; 29 30 import org.apache.poi.hpsf.wellknown.PropertyIDMap; 31 import org.apache.poi.util.LittleEndian; 32 33 42 public class MutableSection extends Section 43 { 44 48 private boolean dirty = true; 49 50 51 52 57 private List preprops; 58 59 60 61 66 private byte[] sectionBytes; 67 68 69 70 73 public MutableSection() 74 { 75 dirty = true; 76 formatID = null; 77 offset = -1; 78 preprops = new LinkedList (); 79 } 80 81 82 83 91 public MutableSection(final Section s) 92 { 93 setFormatID(s.getFormatID()); 94 final Property[] pa = s.getProperties(); 95 final MutableProperty[] mpa = new MutableProperty[pa.length]; 96 for (int i = 0; i < pa.length; i++) 97 mpa[i] = new MutableProperty(pa[i]); 98 setProperties(mpa); 99 setDictionary(s.getDictionary()); 100 } 101 102 103 104 112 public void setFormatID(final ClassID formatID) 113 { 114 this.formatID = formatID; 115 } 116 117 118 119 128 public void setFormatID(final byte[] formatID) 129 { 130 ClassID fid = getFormatID(); 131 if (fid == null) 132 { 133 fid = new ClassID(); 134 setFormatID(fid); 135 } 136 fid.setBytes(formatID); 137 } 138 139 140 141 146 public void setProperties(final Property[] properties) 147 { 148 this.properties = properties; 149 preprops = new LinkedList (); 150 for (int i = 0; i < properties.length; i++) 151 preprops.add(properties[i]); 152 dirty = true; 153 } 154 155 156 157 170 public void setProperty(final int id, final String value) 171 { 172 setProperty(id, Variant.VT_LPWSTR, value); 173 dirty = true; 174 } 175 176 177 178 193 public void setProperty(final int id, final long variantType, 194 final Object value) 195 { 196 final MutableProperty p = new MutableProperty(); 197 p.setID(id); 198 p.setType(variantType); 199 p.setValue(value); 200 setProperty(p); 201 dirty = true; 202 } 203 204 205 206 219 public void setProperty(final Property p) 220 { 221 final long id = p.getID(); 222 removeProperty(id); 223 preprops.add(p); 224 dirty = true; 225 } 226 227 228 229 234 public void removeProperty(final long id) 235 { 236 for (final Iterator i = preprops.iterator(); i.hasNext();) 237 if (((Property) i.next()).getID() == id) 238 { 239 i.remove(); 240 break; 241 } 242 dirty = true; 243 } 244 245 246 247 258 protected void setPropertyBooleanValue(final int id, final boolean value) 259 { 260 setProperty(id, (long) Variant.VT_BOOL, new Boolean (value)); 261 } 262 263 264 265 270 public int getSize() 271 { 272 if (dirty) 273 { 274 try 275 { 276 size = calcSize(); 277 dirty = false; 278 } 279 catch (HPSFRuntimeException ex) 280 { 281 throw ex; 282 } 283 catch (Exception ex) 284 { 285 throw new HPSFRuntimeException(ex); 286 } 287 } 288 return size; 289 } 290 291 292 293 300 private int calcSize() throws WritingNotSupportedException, IOException 301 { 302 final ByteArrayOutputStream out = new ByteArrayOutputStream (); 303 write(out); 304 out.close(); 305 307 sectionBytes = Util.pad4(out.toByteArray()); 308 return sectionBytes.length; 309 } 310 311 312 313 328 public int write(final OutputStream out) 329 throws WritingNotSupportedException, IOException 330 { 331 333 if (!dirty && sectionBytes != null) 334 { 335 out.write(sectionBytes); 336 return sectionBytes.length; 337 } 338 339 340 final ByteArrayOutputStream propertyStream = 341 new ByteArrayOutputStream (); 342 343 346 final ByteArrayOutputStream propertyListStream = 347 new ByteArrayOutputStream (); 348 349 350 int position = 0; 351 352 355 position += 2 * LittleEndian.INT_SIZE + 356 getPropertyCount() * 2 * LittleEndian.INT_SIZE; 357 358 361 int codepage = -1; 362 if (getProperty(PropertyIDMap.PID_DICTIONARY) != null) 363 { 364 final Object p1 = getProperty(PropertyIDMap.PID_CODEPAGE); 365 if (p1 != null) 366 { 367 if (!(p1 instanceof Integer )) 368 throw new IllegalPropertySetDataException 369 ("The codepage property (ID = 1) must be an " + 370 "Integer object."); 371 } 372 else 373 throw new IllegalPropertySetDataException 374 ("The codepage property (ID = 1) must be set if the " + 375 "section contains a dictionary."); 376 codepage = getCodepage(); 377 } 378 379 380 Collections.sort(preprops, new Comparator () 381 { 382 public int compare(final Object o1, final Object o2) 383 { 384 final Property p1 = (Property) o1; 385 final Property p2 = (Property) o2; 386 if (p1.getID() < p2.getID()) 387 return -1; 388 else if (p1.getID() == p2.getID()) 389 return 0; 390 else 391 return 1; 392 } 393 }); 394 395 397 for (final ListIterator i = preprops.listIterator(); i.hasNext();) 398 { 399 final MutableProperty p = (MutableProperty) i.next(); 400 final long id = p.getID(); 401 402 403 TypeWriter.writeUIntToStream(propertyListStream, p.getID()); 404 TypeWriter.writeUIntToStream(propertyListStream, position); 405 406 410 if (id != 0) 411 413 position += p.write(propertyStream, getCodepage()); 414 else 415 { 416 if (codepage == -1) 417 throw new IllegalPropertySetDataException 418 ("Codepage (property 1) is undefined."); 419 position += writeDictionary(propertyStream, dictionary, 420 codepage); 421 } 422 } 423 propertyStream.close(); 424 propertyListStream.close(); 425 426 427 byte[] pb1 = propertyListStream.toByteArray(); 428 byte[] pb2 = propertyStream.toByteArray(); 429 430 431 TypeWriter.writeToStream(out, LittleEndian.INT_SIZE * 2 + 432 pb1.length + pb2.length); 433 434 435 TypeWriter.writeToStream(out, getPropertyCount()); 436 437 438 out.write(pb1); 439 440 441 out.write(pb2); 442 443 int streamLength = LittleEndian.INT_SIZE * 2 + pb1.length + pb2.length; 444 return streamLength; 445 } 446 447 448 449 458 private static int writeDictionary(final OutputStream out, 459 final Map dictionary, final int codepage) 460 throws IOException 461 { 462 int length = TypeWriter.writeUIntToStream(out, dictionary.size()); 463 for (final Iterator i = dictionary.keySet().iterator(); i.hasNext();) 464 { 465 final Long key = (Long ) i.next(); 466 final String value = (String ) dictionary.get(key); 467 468 if (codepage == Constants.CP_UNICODE) 469 { 470 471 int sLength = value.length() + 1; 472 if (sLength % 2 == 1) 473 sLength++; 474 length += TypeWriter.writeUIntToStream(out, key.longValue()); 475 length += TypeWriter.writeUIntToStream(out, sLength); 476 final char[] ca = value.toCharArray(); 477 for (int j = 0; j < ca.length; j++) 478 { 479 int high = (ca[j] & 0x0ff00) >> 8; 480 int low = (ca[j] & 0x000ff); 481 out.write(low); 482 out.write(high); 483 length += 2; 484 sLength--; 485 } 486 while (sLength > 0) 487 { 488 out.write(0x00); 489 out.write(0x00); 490 length += 2; 491 sLength--; 492 } 493 } 494 else 495 { 496 498 length += TypeWriter.writeUIntToStream(out, key.longValue()); 499 length += TypeWriter.writeUIntToStream(out, value.length() + 1); 500 final byte[] ba = 501 value.getBytes(VariantSupport.codepageToEncoding(codepage)); 502 for (int j = 0; j < ba.length; j++) 503 { 504 out.write(ba[j]); 505 length++; 506 } 507 out.write(0x00); 508 length++; 509 } 510 } 511 return length; 512 } 513 514 515 516 523 public int getPropertyCount() 524 { 525 return preprops.size(); 526 } 527 528 529 530 535 public Property[] getProperties() 536 { 537 properties = (Property[]) preprops.toArray(new Property[0]); 538 return properties; 539 } 540 541 542 543 549 public Object getProperty(final long id) 550 { 551 553 getProperties(); 554 return super.getProperty(id); 555 } 556 557 558 559 575 public void setDictionary(final Map dictionary) 576 throws IllegalPropertySetDataException 577 { 578 if (dictionary != null) 579 { 580 for (final Iterator i = dictionary.keySet().iterator(); 581 i.hasNext();) 582 if (!(i.next() instanceof Long )) 583 throw new IllegalPropertySetDataException 584 ("Dictionary keys must be of type Long."); 585 for (final Iterator i = dictionary.values().iterator(); 586 i.hasNext();) 587 if (!(i.next() instanceof String )) 588 throw new IllegalPropertySetDataException 589 ("Dictionary values must be of type String."); 590 this.dictionary = dictionary; 591 592 595 setProperty(PropertyIDMap.PID_DICTIONARY, -1, dictionary); 596 597 600 setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, 601 new Integer (Constants.CP_UNICODE)); 602 } 603 else 604 606 removeProperty(PropertyIDMap.PID_DICTIONARY); 607 } 608 609 } 610 | Popular Tags |