1 16 17 18 19 package org.apache.poi.hwpf.usermodel; 20 21 22 import org.apache.poi.util.LittleEndian; 23 24 import org.apache.poi.hwpf.HWPFDocument; 25 26 import org.apache.poi.hwpf.usermodel.CharacterRun; 27 import org.apache.poi.hwpf.usermodel.Paragraph; 28 import org.apache.poi.hwpf.usermodel.ParagraphProperties; 29 import org.apache.poi.hwpf.usermodel.Section; 30 31 import org.apache.poi.hwpf.model.PropertyNode; 32 import org.apache.poi.hwpf.model.StyleSheet; 33 import org.apache.poi.hwpf.model.StyleDescription; 34 import org.apache.poi.hwpf.model.CHPBinTable; 35 import org.apache.poi.hwpf.model.CHPX; 36 import org.apache.poi.hwpf.model.PAPX; 37 import org.apache.poi.hwpf.model.SEPX; 38 import org.apache.poi.hwpf.model.PAPBinTable; 39 import org.apache.poi.hwpf.model.SectionTable; 40 import org.apache.poi.hwpf.model.TextPieceTable; 41 import org.apache.poi.hwpf.model.TextPiece; 42 import org.apache.poi.hwpf.model.ListTables; 43 44 import org.apache.poi.hwpf.sprm.CharacterSprmUncompressor; 45 import org.apache.poi.hwpf.sprm.CharacterSprmCompressor; 46 import org.apache.poi.hwpf.sprm.SectionSprmUncompressor; 47 import org.apache.poi.hwpf.sprm.ParagraphSprmUncompressor; 48 import org.apache.poi.hwpf.sprm.ParagraphSprmCompressor; 49 import org.apache.poi.hwpf.sprm.SprmBuffer; 50 51 52 import java.util.List ; 53 import java.util.ArrayList ; 54 import java.util.Iterator ; 55 import java.util.NoSuchElementException ; 56 import java.io.UnsupportedEncodingException ; 57 import java.lang.ref.WeakReference ; 58 59 72 public class Range 73 { 74 75 public static final int TYPE_PARAGRAPH = 0; 76 public static final int TYPE_CHARACTER= 1; 77 public static final int TYPE_SECTION = 2; 78 public static final int TYPE_TEXT = 3; 79 public static final int TYPE_LISTENTRY = 4; 80 public static final int TYPE_TABLE = 5; 81 public static final int TYPE_UNDEFINED = 6; 82 83 84 private WeakReference _parent; 85 86 87 protected int _start; 88 89 90 protected int _end; 91 92 93 protected HWPFDocument _doc; 94 95 96 boolean _sectionRangeFound; 97 98 99 protected List _sections; 100 101 102 protected int _sectionStart; 103 104 105 protected int _sectionEnd; 106 107 108 protected boolean _parRangeFound; 109 110 111 protected List _paragraphs; 112 113 114 protected int _parStart; 115 116 117 protected int _parEnd; 118 119 120 protected boolean _charRangeFound; 121 122 123 protected List _characters; 124 125 126 protected int _charStart; 127 128 129 protected int _charEnd; 130 131 132 protected boolean _textRangeFound; 133 134 135 protected List _text; 136 137 138 protected int _textStart; 139 140 141 protected int _textEnd; 142 143 148 156 public Range(int start, int end, HWPFDocument doc) 157 { 158 _start = start; 159 _end = end; 160 _doc = doc; 161 _sections = _doc.getSectionTable().getSections(); 162 _paragraphs = _doc.getParagraphTable().getParagraphs(); 163 _characters = _doc.getCharacterTable().getTextRuns(); 164 _text = _doc.getTextTable().getTextPieces(); 165 _parent = new WeakReference (null); 166 } 167 168 169 176 protected Range(int start, int end, Range parent) 177 { 178 _start = start; 179 _end = end; 180 _doc = parent._doc; 181 _sections = parent._sections; 182 _paragraphs = parent._paragraphs; 183 _characters = parent._characters; 184 _text = parent._text; 185 _parent = new WeakReference (parent); 186 } 187 188 197 protected Range(int startIdx, int endIdx, int idxType, Range parent) 198 { 199 _doc = parent._doc; 200 _sections = parent._sections; 201 _paragraphs = parent._paragraphs; 202 _characters = parent._characters; 203 _text = parent._text; 204 _parent = new WeakReference (parent); 205 206 switch (idxType) 207 { 208 case TYPE_PARAGRAPH: 209 _parStart = parent._parStart + startIdx; 210 _parEnd = parent._parStart + endIdx; 211 _start = ((PropertyNode)_paragraphs.get(_parStart)).getStart(); 212 _end = ((PropertyNode)_paragraphs.get(_parEnd)).getEnd(); 213 _parRangeFound = true; 214 break; 215 case TYPE_CHARACTER: 216 _charStart = parent._charStart + startIdx; 217 _charEnd = parent._charStart + endIdx; 218 _start = ((PropertyNode)_characters.get(_charStart)).getStart(); 219 _end = ((PropertyNode)_characters.get(_charEnd)).getEnd(); 220 _charRangeFound = true; 221 break; 222 case TYPE_SECTION: 223 _sectionStart = parent._sectionStart + startIdx; 224 _sectionEnd = parent._sectionStart + endIdx; 225 _start = ((PropertyNode)_sections.get(_sectionStart)).getStart(); 226 _end = ((PropertyNode)_sections.get(_sectionEnd)).getEnd(); 227 _sectionRangeFound = true; 228 break; 229 case TYPE_TEXT: 230 _textStart = parent._textStart + startIdx; 231 _textEnd = parent._textStart + endIdx; 232 _start = ((PropertyNode)_text.get(_textStart)).getStart(); 233 _end = ((PropertyNode)_text.get(_textEnd)).getEnd(); 234 _textRangeFound = true; 235 break; 236 } 237 } 238 239 244 public String text() 245 { 246 initText(); 247 248 StringBuffer sb = new StringBuffer (); 249 250 for (int x = _textStart; x < _textEnd; x++) 251 { 252 TextPiece piece = (TextPiece)_text.get(x); 253 int start = _start > piece.getStart() ? _start - piece.getStart() : 0; 254 int end = _end <= piece.getEnd() ? _end - piece.getStart() : piece.getEnd() - piece.getStart(); 255 256 if(piece.usesUnicode()) { 258 start/=2; 259 end/=2; 260 } 261 sb.append(piece.getStringBuffer().substring(start, end)); 262 } 263 return sb.toString(); 264 } 265 266 272 public int numSections() 273 { 274 initSections(); 275 return _sectionEnd - _sectionStart; 276 } 277 278 284 285 public int numParagraphs() 286 { 287 initParagraphs(); 288 return _parEnd - _parStart; 289 } 290 291 295 296 public int numCharacterRuns() 297 { 298 initCharacterRuns(); 299 return _charEnd - _charStart; 300 } 301 302 308 public CharacterRun insertBefore(String text) 309 { 311 initAll(); 312 313 TextPiece tp = (TextPiece)_text.get(_textStart); 314 StringBuffer sb = (StringBuffer )tp.getStringBuffer(); 315 316 int insertIndex = _start - tp.getStart(); 319 sb.insert(insertIndex, text); 320 int adjustedLength = _doc.getTextTable().adjustForInsert(_textStart, text.length()); 321 _doc.getCharacterTable().adjustForInsert(_charStart, adjustedLength); 322 _doc.getParagraphTable().adjustForInsert(_parStart, adjustedLength); 323 _doc.getSectionTable().adjustForInsert(_sectionStart, adjustedLength); 324 adjustForInsert(text.length()); 325 326 return getCharacterRun(0); 327 } 328 329 335 public CharacterRun insertAfter(String text) 336 { 337 initAll(); 338 339 int listIndex = _textEnd - 1; 340 TextPiece tp = (TextPiece)_text.get(listIndex); 341 StringBuffer sb = (StringBuffer )tp.getStringBuffer(); 342 343 int insertIndex = _end - tp.getStart(); 344 345 if (tp.getStringBuffer().charAt(_end - 1) == '\r' && text.charAt(0) != '\u0007') 346 { 347 insertIndex--; 348 } 349 sb.insert(insertIndex, text); 350 int adjustedLength = _doc.getTextTable().adjustForInsert(listIndex, text.length()); 351 _doc.getCharacterTable().adjustForInsert(_charEnd - 1, adjustedLength); 352 _doc.getParagraphTable().adjustForInsert(_parEnd - 1, adjustedLength); 353 _doc.getSectionTable().adjustForInsert(_sectionEnd - 1, adjustedLength); 354 adjustForInsert(text.length()); 355 356 return getCharacterRun(numCharacterRuns() - 1); 357 358 } 359 360 369 public CharacterRun insertBefore(String text, CharacterProperties props) 370 { 372 initAll(); 373 PAPX papx = (PAPX)_paragraphs.get(_parStart); 374 short istd = papx.getIstd(); 375 376 StyleSheet ss = _doc.getStyleSheet(); 377 CharacterProperties baseStyle = ss.getCharacterStyle(istd); 378 byte[] grpprl = CharacterSprmCompressor.compressCharacterProperty(props, baseStyle); 379 SprmBuffer buf = new SprmBuffer(grpprl); 380 _doc.getCharacterTable().insert(_charStart, _start, buf); 381 382 return insertBefore(text); 383 } 384 385 394 public CharacterRun insertAfter(String text, CharacterProperties props) 395 { 397 initAll(); 398 PAPX papx = (PAPX)_paragraphs.get(_parEnd - 1); 399 short istd = papx.getIstd(); 400 401 StyleSheet ss = _doc.getStyleSheet(); 402 CharacterProperties baseStyle = ss.getCharacterStyle(istd); 403 byte[] grpprl = CharacterSprmCompressor.compressCharacterProperty(props, baseStyle); 404 SprmBuffer buf = new SprmBuffer(grpprl); 405 _doc.getCharacterTable().insert(_charEnd, _end, buf); 406 _charEnd++; 407 return insertAfter(text); 408 } 409 410 417 public Paragraph insertBefore(ParagraphProperties props, int styleIndex) 418 { 420 return this.insertBefore(props, styleIndex, "\r"); 421 } 422 423 435 protected Paragraph insertBefore(ParagraphProperties props, int styleIndex, String text) 436 { 438 initAll(); 439 StyleSheet ss = _doc.getStyleSheet(); 440 ParagraphProperties baseStyle = ss.getParagraphStyle(styleIndex); 441 CharacterProperties baseChp = ss.getCharacterStyle(styleIndex); 442 443 byte[] grpprl = ParagraphSprmCompressor.compressParagraphProperty(props, baseStyle); 444 byte[] withIndex = new byte[grpprl.length + LittleEndian.SHORT_SIZE]; 445 LittleEndian.putShort(withIndex, (short)styleIndex); 446 System.arraycopy(grpprl, 0, withIndex, LittleEndian.SHORT_SIZE, grpprl.length); 447 SprmBuffer buf = new SprmBuffer(withIndex); 448 449 _doc.getParagraphTable().insert(_parStart, _start, buf); 450 insertBefore(text, baseChp); 451 return getParagraph(0); 452 } 453 454 461 462 public Paragraph insertAfter(ParagraphProperties props, int styleIndex) 463 { 465 return this.insertAfter(props, styleIndex, "\r"); 466 } 467 468 480 protected Paragraph insertAfter(ParagraphProperties props, int styleIndex, String text) 481 { 483 initAll(); 484 StyleSheet ss = _doc.getStyleSheet(); 485 ParagraphProperties baseStyle = ss.getParagraphStyle(styleIndex); 486 CharacterProperties baseChp = ss.getCharacterStyle(styleIndex); 487 488 byte[] grpprl = ParagraphSprmCompressor.compressParagraphProperty(props, baseStyle); 489 byte[] withIndex = new byte[grpprl.length + LittleEndian.SHORT_SIZE]; 490 LittleEndian.putShort(withIndex, (short)styleIndex); 491 System.arraycopy(grpprl, 0, withIndex, LittleEndian.SHORT_SIZE, grpprl.length); 492 SprmBuffer buf = new SprmBuffer(withIndex); 493 494 _doc.getParagraphTable().insert(_parEnd, _end, buf); 495 _parEnd++; 496 insertAfter(text, baseChp); 497 return getParagraph(numParagraphs() - 1); 498 } 499 500 public void delete() 501 { 502 initAll(); 503 504 int numSections = _sections.size(); 505 int numRuns = _characters.size(); 506 int numParagraphs = _paragraphs.size(); 507 508 for (int x = _charStart; x < numRuns; x++) 509 { 510 CHPX chpx = (CHPX)_characters.get(x); 511 chpx.adjustForDelete(_start, _end - _start); 512 } 513 514 for (int x = _parStart; x < numParagraphs; x++) 515 { 516 PAPX papx = (PAPX)_paragraphs.get(x); 517 papx.adjustForDelete(_start, _end - _start); 518 } 519 520 for (int x = _sectionStart; x < numSections; x++) 521 { 522 SEPX sepx = (SEPX)_sections.get(x); 523 sepx.adjustForDelete(_start, _end - _start); 524 } 525 } 526 527 535 public Table insertBefore(TableProperties props, int rows) 536 { 537 ParagraphProperties parProps = new ParagraphProperties(); 538 parProps.setFInTable((byte)1); 539 parProps.setTableLevel((byte)1); 540 541 int columns = props.getItcMac(); 542 for (int x = 0; x < rows; x++) 543 { 544 Paragraph cell = this.insertBefore(parProps, StyleSheet.NIL_STYLE); 545 cell.insertAfter(String.valueOf('\u0007')); 546 for(int y = 1; y < columns; y++) 547 { 548 cell = cell.insertAfter(parProps, StyleSheet.NIL_STYLE); 549 cell.insertAfter(String.valueOf('\u0007')); 550 } 551 cell = cell.insertAfter(parProps, StyleSheet.NIL_STYLE, String.valueOf('\u0007')); 552 cell.setTableRowEnd(props); 553 } 554 return new Table(_start, _start + (rows * (columns + 1)), this, 1); 555 } 556 557 567 public ListEntry insertBefore(ParagraphProperties props, int listID, int level, int styleIndex) 568 { 569 ListTables lt = _doc.getListTables(); 570 if (lt.getLevel(listID, level) == null) 571 { 572 throw new NoSuchElementException ("The specified list and level do not exist"); 573 } 574 575 int ilfo = lt.getOverrideIndexFromListID(listID); 576 props.setIlfo(ilfo); 577 props.setIlvl((byte)level); 578 579 return (ListEntry)insertBefore(props, styleIndex); 580 } 581 582 592 public ListEntry insertAfter(ParagraphProperties props, int listID, int level, int styleIndex) 593 { 594 ListTables lt = _doc.getListTables(); 595 if (lt.getLevel(listID, level) == null) 596 { 597 throw new NoSuchElementException ("The specified list and level do not exist"); 598 } 599 int ilfo = lt.getOverrideIndexFromListID(listID); 600 props.setIlfo(ilfo); 601 props.setIlvl((byte)level); 602 603 return (ListEntry)insertAfter(props, styleIndex); 604 } 605 606 607 613 public CharacterRun getCharacterRun(int index) 614 { 615 initCharacterRuns(); 616 CHPX chpx = (CHPX)_characters.get(index + _charStart); 617 618 int[] point = findRange(_paragraphs, _parStart, Math.max(chpx.getStart(), _start), 619 chpx.getEnd()); 620 PAPX papx = (PAPX)_paragraphs.get(point[0]); 621 short istd = papx.getIstd(); 622 623 CharacterRun chp = new CharacterRun(chpx, _doc.getStyleSheet(), istd, this); 624 625 return chp; 626 } 627 628 634 public Section getSection(int index) 635 { 636 initSections(); 637 SEPX sepx = (SEPX)_sections.get(index + _sectionStart); 638 Section sep = new Section(sepx, this); 639 return sep; 640 } 641 642 648 649 public Paragraph getParagraph(int index) 650 { 651 initParagraphs(); 652 PAPX papx = (PAPX)_paragraphs.get(index + _parStart); 653 654 ParagraphProperties props = papx.getParagraphProperties(_doc.getStyleSheet()); 655 Paragraph pap = null; 656 if (props.getIlfo() > 0) 657 { 658 pap = new ListEntry(papx, this, _doc.getListTables()); 659 } 660 else 661 { 662 pap = new Paragraph(papx, this); 663 } 664 665 return pap; 666 } 667 668 674 public int type() 675 { 676 return TYPE_UNDEFINED; 677 } 678 679 686 public Table getTable(Paragraph paragraph) 687 { 688 if (!paragraph.isInTable()) 689 { 690 throw new IllegalArgumentException ("This paragraph doesn't belong to a table"); 691 } 692 693 Range r = (Range)paragraph; 694 if (r._parent.get() != this) 695 { 696 throw new IllegalArgumentException ("This paragraph is not a child of this range"); 697 } 698 699 r.initAll(); 700 int tableEnd = r._parEnd; 701 702 if (r._parStart != 0 && getParagraph(r._parStart - 1).isInTable() 703 && getParagraph(r._parStart - 1)._sectionEnd >= r._sectionStart) 704 { 705 throw new IllegalArgumentException ("This paragraph is not the first one in the table"); 706 } 707 708 int limit = _paragraphs.size(); 709 for (; tableEnd < limit; tableEnd++) 710 { 711 if (!getParagraph(tableEnd).isInTable()) 712 { 713 break; 714 } 715 } 716 717 initAll(); 718 if (tableEnd > _parEnd) 719 { 720 throw new ArrayIndexOutOfBoundsException ("The table's bounds fall outside of this Range"); 721 } 722 return new Table(r._parStart, tableEnd, r._doc.getRange(), paragraph.getTableLevel()); 723 } 724 725 728 protected void initAll() 729 { 730 initText(); 731 initCharacterRuns(); 732 initParagraphs(); 733 initSections(); 734 } 735 736 739 private void initParagraphs() 740 { 741 if (!_parRangeFound) 742 { 743 int[] point = findRange(_paragraphs, _parStart, _start, _end); 744 _parStart = point[0]; 745 _parEnd = point[1]; 746 _parRangeFound = true; 747 } 748 } 749 750 753 private void initCharacterRuns() 754 { 755 if (!_charRangeFound) 756 { 757 int[] point = findRange(_characters, _charStart, _start, _end); 758 _charStart = point[0]; 759 _charEnd = point[1]; 760 _charRangeFound = true; 761 } 762 } 763 764 767 private void initText() 768 { 769 if (!_textRangeFound) 770 { 771 int[] point = findRange(_text, _textStart, _start, _end); 772 _textStart = point[0]; 773 _textEnd = point[1]; 774 _textRangeFound = true; 775 } 776 } 777 778 781 private void initSections() 782 { 783 if (!_sectionRangeFound) 784 { 785 int[] point = findRange(_sections, _sectionStart, _start, _end); 786 _sectionStart = point[0]; 787 _sectionEnd = point[1]; 788 _sectionRangeFound = true; 789 } 790 } 791 792 802 private int[] findRange(List rpl, int min, int start, int end) 803 { 804 int x = min; 805 PropertyNode node = (PropertyNode)rpl.get(x); 806 while(node.getEnd() <= start && x < rpl.size()-1) 807 { 808 x++; 809 node = (PropertyNode)rpl.get(x); 810 } 811 812 int y = x; 813 node = (PropertyNode)rpl.get(y); 814 while(node.getEnd() < end && y < rpl.size()-1) 815 { 816 y++; 817 node = (PropertyNode)rpl.get(y); 818 } 819 return new int[]{x, y + 1}; 820 } 821 822 825 private void reset() 826 { 827 _textRangeFound = false; 828 _charRangeFound = false; 829 _parRangeFound = false; 830 _sectionRangeFound = false; 831 } 832 833 837 private void adjustForInsert(int length) 838 { 839 _end += length; 840 reset(); 841 Range parent = (Range)_parent.get(); 842 if (parent != null) 843 { 844 parent.adjustForInsert(length); 845 } 846 } 847 848 } 849 | Popular Tags |