1 16 19 package org.apache.xml.utils; 20 21 52 public class FastStringBuffer 53 { 54 static final int DEBUG_FORCE_INIT_BITS=0; 56 57 static boolean DEBUG_FORCE_FIXED_CHUNKSIZE=true; 64 65 71 public static final int SUPPRESS_LEADING_WS=0x01; 72 73 77 public static final int SUPPRESS_TRAILING_WS=0x02; 78 79 84 public static final int SUPPRESS_BOTH 85 = SUPPRESS_LEADING_WS | SUPPRESS_TRAILING_WS; 86 87 91 private static final int CARRY_WS=0x04; 92 93 99 int m_chunkBits = 15; 100 101 106 int m_maxChunkBits = 15; 107 108 116 int m_rebundleBits = 2; 117 118 123 int m_chunkSize; 125 130 int m_chunkMask; 132 140 char[][] m_array; 141 142 151 int m_lastChunk = 0; 152 153 160 int m_firstFree = 0; 161 162 169 FastStringBuffer m_innerFSB = null; 170 171 193 public FastStringBuffer(int initChunkBits, int maxChunkBits, 194 int rebundleBits) 195 { 196 if(DEBUG_FORCE_INIT_BITS!=0) initChunkBits=DEBUG_FORCE_INIT_BITS; 197 198 if(DEBUG_FORCE_FIXED_CHUNKSIZE) maxChunkBits=initChunkBits; 206 208 m_array = new char[16][]; 209 210 if (initChunkBits > maxChunkBits) 212 initChunkBits = maxChunkBits; 213 214 m_chunkBits = initChunkBits; 215 m_maxChunkBits = maxChunkBits; 216 m_rebundleBits = rebundleBits; 217 m_chunkSize = 1 << (initChunkBits); 218 m_chunkMask = m_chunkSize - 1; 219 m_array[0] = new char[m_chunkSize]; 220 } 221 222 228 public FastStringBuffer(int initChunkBits, int maxChunkBits) 229 { 230 this(initChunkBits, maxChunkBits, 2); 231 } 232 233 244 public FastStringBuffer(int initChunkBits) 245 { 246 this(initChunkBits, 15, 2); 247 } 248 249 252 public FastStringBuffer() 253 { 254 255 this(10, 15, 2); 261 } 262 263 268 public final int size() 269 { 270 return (m_lastChunk << m_chunkBits) + m_firstFree; 271 } 272 273 278 public final int length() 279 { 280 return (m_lastChunk << m_chunkBits) + m_firstFree; 281 } 282 283 288 public final void reset() 289 { 290 291 m_lastChunk = 0; 292 m_firstFree = 0; 293 294 FastStringBuffer innermost = this; 296 297 while (innermost.m_innerFSB != null) 298 { 299 innermost = innermost.m_innerFSB; 300 } 301 302 m_chunkBits = innermost.m_chunkBits; 303 m_chunkSize = innermost.m_chunkSize; 304 m_chunkMask = innermost.m_chunkMask; 305 306 m_innerFSB = null; 308 m_array = new char[16][0]; 309 m_array[0] = new char[m_chunkSize]; 310 } 311 312 324 public final void setLength(int l) 325 { 326 m_lastChunk = l >>> m_chunkBits; 327 328 if (m_lastChunk == 0 && m_innerFSB != null) 329 { 330 m_innerFSB.setLength(l, this); 332 } 333 else 334 { 335 m_firstFree = l & m_chunkMask; 336 337 if(m_firstFree==0 && m_lastChunk>0) 343 { 344 --m_lastChunk; 345 m_firstFree=m_chunkSize; 346 } 347 } 348 } 349 350 357 private final void setLength(int l, FastStringBuffer rootFSB) 358 { 359 360 m_lastChunk = l >>> m_chunkBits; 361 362 if (m_lastChunk == 0 && m_innerFSB != null) 363 { 364 m_innerFSB.setLength(l, rootFSB); 365 } 366 else 367 { 368 369 rootFSB.m_chunkBits = m_chunkBits; 372 rootFSB.m_maxChunkBits = m_maxChunkBits; 373 rootFSB.m_rebundleBits = m_rebundleBits; 374 rootFSB.m_chunkSize = m_chunkSize; 375 rootFSB.m_chunkMask = m_chunkMask; 376 rootFSB.m_array = m_array; 377 rootFSB.m_innerFSB = m_innerFSB; 378 rootFSB.m_lastChunk = m_lastChunk; 379 380 rootFSB.m_firstFree = l & m_chunkMask; 382 } 383 } 384 385 398 public final String toString() 399 { 400 401 int length = (m_lastChunk << m_chunkBits) + m_firstFree; 402 403 return getString(new StringBuffer (length), 0, 0, length).toString(); 404 } 405 406 416 public final void append(char value) 417 { 418 419 char[] chunk; 420 421 boolean lastchunk = (m_lastChunk + 1 == m_array.length); 424 425 if (m_firstFree < m_chunkSize) chunk = m_array[m_lastChunk]; 427 else 428 { 429 430 int i = m_array.length; 432 433 if (m_lastChunk + 1 == i) 434 { 435 char[][] newarray = new char[i + 16][]; 436 437 System.arraycopy(m_array, 0, newarray, 0, i); 438 439 m_array = newarray; 440 } 441 442 chunk = m_array[++m_lastChunk]; 444 445 if (chunk == null) 446 { 447 448 if (m_lastChunk == 1 << m_rebundleBits 450 && m_chunkBits < m_maxChunkBits) 451 { 452 453 m_innerFSB = new FastStringBuffer(this); 456 } 457 458 chunk = m_array[m_lastChunk] = new char[m_chunkSize]; 460 } 461 462 m_firstFree = 0; 463 } 464 465 chunk[m_firstFree++] = value; 467 } 468 469 478 public final void append(String value) 479 { 480 481 if (value == null) 482 return; 483 int strlen = value.length(); 484 485 if (0 == strlen) 486 return; 487 488 int copyfrom = 0; 489 char[] chunk = m_array[m_lastChunk]; 490 int available = m_chunkSize - m_firstFree; 491 492 while (strlen > 0) 494 { 495 496 if (available > strlen) 498 available = strlen; 499 500 value.getChars(copyfrom, copyfrom + available, m_array[m_lastChunk], 501 m_firstFree); 502 503 strlen -= available; 504 copyfrom += available; 505 506 if (strlen > 0) 508 { 509 510 int i = m_array.length; 512 513 if (m_lastChunk + 1 == i) 514 { 515 char[][] newarray = new char[i + 16][]; 516 517 System.arraycopy(m_array, 0, newarray, 0, i); 518 519 m_array = newarray; 520 } 521 522 chunk = m_array[++m_lastChunk]; 524 525 if (chunk == null) 526 { 527 528 if (m_lastChunk == 1 << m_rebundleBits 530 && m_chunkBits < m_maxChunkBits) 531 { 532 533 m_innerFSB = new FastStringBuffer(this); 536 } 537 538 chunk = m_array[m_lastChunk] = new char[m_chunkSize]; 540 } 541 542 available = m_chunkSize; 543 m_firstFree = 0; 544 } 545 } 546 547 m_firstFree += available; 549 } 550 551 560 public final void append(StringBuffer value) 561 { 562 563 if (value == null) 564 return; 565 int strlen = value.length(); 566 567 if (0 == strlen) 568 return; 569 570 int copyfrom = 0; 571 char[] chunk = m_array[m_lastChunk]; 572 int available = m_chunkSize - m_firstFree; 573 574 while (strlen > 0) 576 { 577 578 if (available > strlen) 580 available = strlen; 581 582 value.getChars(copyfrom, copyfrom + available, m_array[m_lastChunk], 583 m_firstFree); 584 585 strlen -= available; 586 copyfrom += available; 587 588 if (strlen > 0) 590 { 591 592 int i = m_array.length; 594 595 if (m_lastChunk + 1 == i) 596 { 597 char[][] newarray = new char[i + 16][]; 598 599 System.arraycopy(m_array, 0, newarray, 0, i); 600 601 m_array = newarray; 602 } 603 604 chunk = m_array[++m_lastChunk]; 606 607 if (chunk == null) 608 { 609 610 if (m_lastChunk == 1 << m_rebundleBits 612 && m_chunkBits < m_maxChunkBits) 613 { 614 615 m_innerFSB = new FastStringBuffer(this); 618 } 619 620 chunk = m_array[m_lastChunk] = new char[m_chunkSize]; 622 } 623 624 available = m_chunkSize; 625 m_firstFree = 0; 626 } 627 } 628 629 m_firstFree += available; 631 } 632 633 645 public final void append(char[] chars, int start, int length) 646 { 647 648 int strlen = length; 649 650 if (0 == strlen) 651 return; 652 653 int copyfrom = start; 654 char[] chunk = m_array[m_lastChunk]; 655 int available = m_chunkSize - m_firstFree; 656 657 while (strlen > 0) 659 { 660 661 if (available > strlen) 663 available = strlen; 664 665 System.arraycopy(chars, copyfrom, m_array[m_lastChunk], m_firstFree, 666 available); 667 668 strlen -= available; 669 copyfrom += available; 670 671 if (strlen > 0) 673 { 674 675 int i = m_array.length; 677 678 if (m_lastChunk + 1 == i) 679 { 680 char[][] newarray = new char[i + 16][]; 681 682 System.arraycopy(m_array, 0, newarray, 0, i); 683 684 m_array = newarray; 685 } 686 687 chunk = m_array[++m_lastChunk]; 689 690 if (chunk == null) 691 { 692 693 if (m_lastChunk == 1 << m_rebundleBits 695 && m_chunkBits < m_maxChunkBits) 696 { 697 698 m_innerFSB = new FastStringBuffer(this); 701 } 702 703 chunk = m_array[m_lastChunk] = new char[m_chunkSize]; 705 } 706 707 available = m_chunkSize; 708 m_firstFree = 0; 709 } 710 } 711 712 m_firstFree += available; 714 } 715 716 726 public final void append(FastStringBuffer value) 727 { 728 729 if (value == null) 734 return; 735 int strlen = value.length(); 736 737 if (0 == strlen) 738 return; 739 740 int copyfrom = 0; 741 char[] chunk = m_array[m_lastChunk]; 742 int available = m_chunkSize - m_firstFree; 743 744 while (strlen > 0) 746 { 747 748 if (available > strlen) 750 available = strlen; 751 752 int sourcechunk = (copyfrom + value.m_chunkSize - 1) 753 >>> value.m_chunkBits; 754 int sourcecolumn = copyfrom & value.m_chunkMask; 755 int runlength = value.m_chunkSize - sourcecolumn; 756 757 if (runlength > available) 758 runlength = available; 759 760 System.arraycopy(value.m_array[sourcechunk], sourcecolumn, 761 m_array[m_lastChunk], m_firstFree, runlength); 762 763 if (runlength != available) 764 System.arraycopy(value.m_array[sourcechunk + 1], 0, 765 m_array[m_lastChunk], m_firstFree + runlength, 766 available - runlength); 767 768 strlen -= available; 769 copyfrom += available; 770 771 if (strlen > 0) 773 { 774 775 int i = m_array.length; 777 778 if (m_lastChunk + 1 == i) 779 { 780 char[][] newarray = new char[i + 16][]; 781 782 System.arraycopy(m_array, 0, newarray, 0, i); 783 784 m_array = newarray; 785 } 786 787 chunk = m_array[++m_lastChunk]; 789 790 if (chunk == null) 791 { 792 793 if (m_lastChunk == 1 << m_rebundleBits 795 && m_chunkBits < m_maxChunkBits) 796 { 797 798 m_innerFSB = new FastStringBuffer(this); 801 } 802 803 chunk = m_array[m_lastChunk] = new char[m_chunkSize]; 805 } 806 807 available = m_chunkSize; 808 m_firstFree = 0; 809 } 810 } 811 812 m_firstFree += available; 814 } 815 816 825 public boolean isWhitespace(int start, int length) 826 { 827 828 int sourcechunk = start >>> m_chunkBits; 829 int sourcecolumn = start & m_chunkMask; 830 int available = m_chunkSize - sourcecolumn; 831 boolean chunkOK; 832 833 while (length > 0) 834 { 835 int runlength = (length <= available) ? length : available; 836 837 if (sourcechunk == 0 && m_innerFSB != null) 838 chunkOK = m_innerFSB.isWhitespace(sourcecolumn, runlength); 839 else 840 chunkOK = org.apache.xml.utils.XMLCharacterRecognizer.isWhiteSpace( 841 m_array[sourcechunk], sourcecolumn, runlength); 842 843 if (!chunkOK) 844 return false; 845 846 length -= runlength; 847 848 ++sourcechunk; 849 850 sourcecolumn = 0; 851 available = m_chunkSize; 852 } 853 854 return true; 855 } 856 857 863 public String getString(int start, int length) 864 { 865 int startColumn = start & m_chunkMask; 866 int startChunk = start >>> m_chunkBits; 867 if (startColumn + length < m_chunkMask && m_innerFSB == null) { 868 return getOneChunkString(startChunk, startColumn, length); 869 } 870 return getString(new StringBuffer (length), startChunk, startColumn, 871 length).toString(); 872 } 873 874 protected String getOneChunkString(int startChunk, int startColumn, 875 int length) { 876 return new String (m_array[startChunk], startColumn, length); 877 } 878 879 885 StringBuffer getString(StringBuffer sb, int start, int length) 886 { 887 return getString(sb, start >>> m_chunkBits, start & m_chunkMask, length); 888 } 889 890 914 StringBuffer getString(StringBuffer sb, int startChunk, int startColumn, 915 int length) 916 { 917 918 int stop = (startChunk << m_chunkBits) + startColumn + length; 919 int stopChunk = stop >>> m_chunkBits; 920 int stopColumn = stop & m_chunkMask; 921 922 for (int i = startChunk; i < stopChunk; ++i) 925 { 926 if (i == 0 && m_innerFSB != null) 927 m_innerFSB.getString(sb, startColumn, m_chunkSize - startColumn); 928 else 929 sb.append(m_array[i], startColumn, m_chunkSize - startColumn); 930 931 startColumn = 0; } 933 934 if (stopChunk == 0 && m_innerFSB != null) 935 m_innerFSB.getString(sb, startColumn, stopColumn - startColumn); 936 else if (stopColumn > startColumn) 937 sb.append(m_array[stopChunk], startColumn, stopColumn - startColumn); 938 939 return sb; 940 } 941 942 949 public char charAt(int pos) 950 { 951 int startChunk = pos >>> m_chunkBits; 952 953 if (startChunk == 0 && m_innerFSB != null) 954 return m_innerFSB.charAt(pos & m_chunkMask); 955 else 956 return m_array[startChunk][pos & m_chunkMask]; 957 } 958 959 978 public void sendSAXcharacters( 979 org.xml.sax.ContentHandler ch, int start, int length) 980 throws org.xml.sax.SAXException 981 { 982 983 int startChunk = start >>> m_chunkBits; 984 int startColumn = start & m_chunkMask; 985 if (startColumn + length < m_chunkMask && m_innerFSB == null) { 986 ch.characters(m_array[startChunk], startColumn, length); 987 return; 988 } 989 990 int stop = start + length; 991 int stopChunk = stop >>> m_chunkBits; 992 int stopColumn = stop & m_chunkMask; 993 994 for (int i = startChunk; i < stopChunk; ++i) 995 { 996 if (i == 0 && m_innerFSB != null) 997 m_innerFSB.sendSAXcharacters(ch, startColumn, 998 m_chunkSize - startColumn); 999 else 1000 ch.characters(m_array[i], startColumn, m_chunkSize - startColumn); 1001 1002 startColumn = 0; } 1004 1005 if (stopChunk == 0 && m_innerFSB != null) 1007 m_innerFSB.sendSAXcharacters(ch, startColumn, stopColumn - startColumn); 1008 else if (stopColumn > startColumn) 1009 { 1010 ch.characters(m_array[stopChunk], startColumn, 1011 stopColumn - startColumn); 1012 } 1013 } 1014 1015 1038 public int sendNormalizedSAXcharacters( 1039 org.xml.sax.ContentHandler ch, int start, int length) 1040 throws org.xml.sax.SAXException 1041 { 1042 int stateForNextChunk=SUPPRESS_LEADING_WS; 1047 1048 int stop = start + length; 1049 int startChunk = start >>> m_chunkBits; 1050 int startColumn = start & m_chunkMask; 1051 int stopChunk = stop >>> m_chunkBits; 1052 int stopColumn = stop & m_chunkMask; 1053 1054 for (int i = startChunk; i < stopChunk; ++i) 1055 { 1056 if (i == 0 && m_innerFSB != null) 1057 stateForNextChunk= 1058 m_innerFSB.sendNormalizedSAXcharacters(ch, startColumn, 1059 m_chunkSize - startColumn); 1060 else 1061 stateForNextChunk= 1062 sendNormalizedSAXcharacters(m_array[i], startColumn, 1063 m_chunkSize - startColumn, 1064 ch,stateForNextChunk); 1065 1066 startColumn = 0; } 1068 1069 if (stopChunk == 0 && m_innerFSB != null) 1071 stateForNextChunk= m_innerFSB.sendNormalizedSAXcharacters(ch, startColumn, stopColumn - startColumn); 1073 else if (stopColumn > startColumn) 1074 { 1075 stateForNextChunk= sendNormalizedSAXcharacters(m_array[stopChunk], 1077 startColumn, stopColumn - startColumn, 1078 ch, stateForNextChunk | SUPPRESS_TRAILING_WS); 1079 } 1080 return stateForNextChunk; 1081 } 1082 1083 static final char[] SINGLE_SPACE = {' '}; 1084 1085 1128 static int sendNormalizedSAXcharacters(char ch[], 1129 int start, int length, 1130 org.xml.sax.ContentHandler handler, 1131 int edgeTreatmentFlags) 1132 throws org.xml.sax.SAXException 1133 { 1134 boolean processingLeadingWhitespace = 1135 ((edgeTreatmentFlags & SUPPRESS_LEADING_WS) != 0); 1136 boolean seenWhitespace = ((edgeTreatmentFlags & CARRY_WS) != 0); 1137 boolean suppressTrailingWhitespace = 1138 ((edgeTreatmentFlags & SUPPRESS_TRAILING_WS) != 0); 1139 int currPos = start; 1140 int limit = start+length; 1141 1142 if (processingLeadingWhitespace) { 1144 for (; currPos < limit 1145 && XMLCharacterRecognizer.isWhiteSpace(ch[currPos]); 1146 currPos++) { } 1147 1148 if (currPos == limit) { 1151 return edgeTreatmentFlags; 1152 } 1153 } 1154 1155 while (currPos < limit) { 1157 int startNonWhitespace = currPos; 1158 1159 for (; currPos < limit 1161 && !XMLCharacterRecognizer.isWhiteSpace(ch[currPos]); 1162 currPos++) { } 1163 1164 if (startNonWhitespace != currPos) { 1167 if (seenWhitespace) { 1168 handler.characters(SINGLE_SPACE, 0, 1); 1169 seenWhitespace = false; 1170 } 1171 handler.characters(ch, startNonWhitespace, 1172 currPos - startNonWhitespace); 1173 } 1174 1175 int startWhitespace = currPos; 1176 1177 for (; currPos < limit 1179 && XMLCharacterRecognizer.isWhiteSpace(ch[currPos]); 1180 currPos++) { } 1181 1182 if (startWhitespace != currPos) { 1183 seenWhitespace = true; 1184 } 1185 } 1186 1187 return (seenWhitespace ? CARRY_WS : 0) 1188 | (edgeTreatmentFlags & SUPPRESS_TRAILING_WS); 1189 } 1190 1191 1201 public static void sendNormalizedSAXcharacters(char ch[], 1202 int start, int length, 1203 org.xml.sax.ContentHandler handler) 1204 throws org.xml.sax.SAXException 1205 { 1206 sendNormalizedSAXcharacters(ch, start, length, 1207 handler, SUPPRESS_BOTH); 1208 } 1209 1210 1222 public void sendSAXComment( 1223 org.xml.sax.ext.LexicalHandler ch, int start, int length) 1224 throws org.xml.sax.SAXException 1225 { 1226 1227 String comment = getString(start, length); 1229 ch.comment(comment.toCharArray(), 0, length); 1230 } 1231 1232 1253 private void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) 1254 { 1255 } 1257 1258 1266 private FastStringBuffer(FastStringBuffer source) 1267 { 1268 1269 m_chunkBits = source.m_chunkBits; 1271 m_maxChunkBits = source.m_maxChunkBits; 1272 m_rebundleBits = source.m_rebundleBits; 1273 m_chunkSize = source.m_chunkSize; 1274 m_chunkMask = source.m_chunkMask; 1275 m_array = source.m_array; 1276 m_innerFSB = source.m_innerFSB; 1277 1278 m_lastChunk = source.m_lastChunk - 1; 1281 m_firstFree = source.m_chunkSize; 1282 1283 source.m_array = new char[16][]; 1285 source.m_innerFSB = this; 1286 1287 source.m_lastChunk = 1; 1291 source.m_firstFree = 0; 1292 source.m_chunkBits += m_rebundleBits; 1293 source.m_chunkSize = 1 << (source.m_chunkBits); 1294 source.m_chunkMask = source.m_chunkSize - 1; 1295 } 1296} 1297 | Popular Tags |