1 57 58 package org.enhydra.apache.xerces.utils; 59 60 import org.enhydra.apache.xerces.readers.XMLEntityHandler; 61 62 public class UTF8DataChunk implements StringPool.StringProducer { 66 public static final int CHUNK_SHIFT = 14; public static final int CHUNK_SIZE = (1 << CHUNK_SHIFT); 71 public static final int CHUNK_MASK = CHUNK_SIZE - 1; 72 public static UTF8DataChunk createChunk(StringPool stringPool, UTF8DataChunk prev) { 76 77 synchronized (UTF8DataChunk.class) { 78 if (fgFreeChunks != null) { 79 UTF8DataChunk newChunk = fgFreeChunks; 80 fgFreeChunks = newChunk.fNextChunk; 81 newChunk.fNextChunk = null; 82 newChunk.init(stringPool, prev); 83 return newChunk; 84 } 85 } 86 UTF8DataChunk chunk = new UTF8DataChunk(stringPool, prev); 87 return chunk; 88 } 89 public final byte[] toByteArray() { 93 return fData; 94 } 95 public void setByteArray(byte[] data) { 99 fData = data; 100 } 101 public UTF8DataChunk nextChunk() { 105 return fNextChunk; 106 } 107 public boolean clearPreviousChunk() { 111 if (fPreviousChunk != null) { 112 fPreviousChunk.setNextChunk(null); 113 fPreviousChunk.removeRef(); 114 fPreviousChunk = null; 117 return true; 118 } 119 return fChunk == 0; 120 } 121 public void releaseChunk() { 125 removeRef(); 126 } 128 public void releaseString(int offset, int length) { 132 removeRef(); 133 } 134 public String toString(int offset, int length) { 138 139 synchronized (fgTempBufferLock) { 140 int outOffset = 0; 141 UTF8DataChunk dataChunk = this; 142 int endOffset = offset + length; 143 int index = offset & CHUNK_MASK; 144 byte[] data = fData; 145 boolean skiplf = false; 146 while (offset < endOffset) { 147 int b0 = data[index++] & 0xff; 148 offset++; 149 if (index == CHUNK_SIZE && offset < endOffset) { 150 dataChunk = dataChunk.fNextChunk; 151 data = dataChunk.fData; 152 index = 0; 153 } 154 if (b0 < 0x80) { 155 if (skiplf) { 156 skiplf = false; 157 if (b0 == 0x0A) 158 continue; 159 } 160 if (b0 == 0x0D) { 161 b0 = 0x0A; 162 skiplf = true; 163 } 164 try { 165 fgTempBuffer[outOffset] = (char)b0; 166 outOffset++; 167 } catch (NullPointerException ex) { 168 fgTempBuffer = new char[CHUNK_SIZE]; 169 fgTempBuffer[outOffset++] = (char)b0; 170 } catch (ArrayIndexOutOfBoundsException ex) { 171 char[] newBuffer = new char[outOffset * 2]; 172 System.arraycopy(fgTempBuffer, 0, newBuffer, 0, outOffset); 173 fgTempBuffer = newBuffer; 174 fgTempBuffer[outOffset++] = (char)b0; 175 } 176 continue; 177 } 178 int b1 = data[index++] & 0xff; 179 offset++; 180 if (index == CHUNK_SIZE && offset < endOffset) { 181 dataChunk = dataChunk.fNextChunk; 182 data = dataChunk.fData; 183 index = 0; 184 } 185 if ((0xe0 & b0) == 0xc0) { int ch = ((0x1f & b0)<<6) + (0x3f & b1); try { 188 fgTempBuffer[outOffset] = (char)ch; 189 outOffset++; 190 } catch (NullPointerException ex) { 191 fgTempBuffer = new char[CHUNK_SIZE]; 192 fgTempBuffer[outOffset++] = (char)ch; 193 } catch (ArrayIndexOutOfBoundsException ex) { 194 char[] newBuffer = new char[outOffset * 2]; 195 System.arraycopy(fgTempBuffer, 0, newBuffer, 0, outOffset); 196 fgTempBuffer = newBuffer; 197 fgTempBuffer[outOffset++] = (char)ch; 198 } 199 continue; 200 } 201 int b2 = data[index++] & 0xff; 202 offset++; 203 if (index == CHUNK_SIZE && offset < endOffset) { 204 dataChunk = dataChunk.fNextChunk; 205 data = dataChunk.fData; 206 index = 0; 207 } 208 if ((0xf0 & b0) == 0xe0) { int ch = ((0x0f & b0)<<12) + ((0x3f & b1)<<6) + (0x3f & b2); try { 211 fgTempBuffer[outOffset] = (char)ch; 212 outOffset++; 213 } catch (NullPointerException ex) { 214 fgTempBuffer = new char[CHUNK_SIZE]; 215 fgTempBuffer[outOffset++] = (char)ch; 216 } catch (ArrayIndexOutOfBoundsException ex) { 217 char[] newBuffer = new char[outOffset * 2]; 218 System.arraycopy(fgTempBuffer, 0, newBuffer, 0, outOffset); 219 fgTempBuffer = newBuffer; 220 fgTempBuffer[outOffset++] = (char)ch; 221 } 222 continue; 223 } 224 int b3 = data[index++] & 0xff; offset++; 226 if (index == CHUNK_SIZE && offset < endOffset) { 227 dataChunk = dataChunk.fNextChunk; 228 data = dataChunk.fData; 229 index = 0; 230 } 231 int ch = ((0x0f & b0)<<18) + ((0x3f & b1)<<12) + ((0x3f & b2)<<6) + (0x3f & b3); 232 if (ch < 0x10000) { 233 try { 234 fgTempBuffer[outOffset] = (char)ch; 235 outOffset++; 236 } catch (NullPointerException ex) { 237 fgTempBuffer = new char[CHUNK_SIZE]; 238 fgTempBuffer[outOffset++] = (char)ch; 239 } catch (ArrayIndexOutOfBoundsException ex) { 240 char[] newBuffer = new char[outOffset * 2]; 241 System.arraycopy(fgTempBuffer, 0, newBuffer, 0, outOffset); 242 fgTempBuffer = newBuffer; 243 fgTempBuffer[outOffset++] = (char)ch; 244 } 245 } else { 246 char ch1 = (char)(((ch-0x00010000)>>10)+0xd800); 247 char ch2 = (char)(((ch-0x00010000)&0x3ff)+0xdc00); 248 try { 249 fgTempBuffer[outOffset] = (char)ch1; 250 outOffset++; 251 } catch (NullPointerException ex) { 252 fgTempBuffer = new char[CHUNK_SIZE]; 253 fgTempBuffer[outOffset++] = (char)ch1; 254 } catch (ArrayIndexOutOfBoundsException ex) { 255 char[] newBuffer = new char[outOffset * 2]; 256 System.arraycopy(fgTempBuffer, 0, newBuffer, 0, outOffset); 257 fgTempBuffer = newBuffer; 258 fgTempBuffer[outOffset++] = (char)ch1; 259 } 260 try { 261 fgTempBuffer[outOffset] = (char)ch2; 262 outOffset++; 263 } catch (NullPointerException ex) { 264 fgTempBuffer = new char[CHUNK_SIZE]; 265 fgTempBuffer[outOffset++] = (char)ch2; 266 } catch (ArrayIndexOutOfBoundsException ex) { 267 char[] newBuffer = new char[outOffset * 2]; 268 System.arraycopy(fgTempBuffer, 0, newBuffer, 0, outOffset); 269 fgTempBuffer = newBuffer; 270 fgTempBuffer[outOffset++] = (char)ch2; 271 } 272 } 273 } 274 return new String (fgTempBuffer, 0, outOffset); 275 } 276 } 277 public boolean equalsString(int offset, int length, char[] strChars, int strOffset, int strLength) { 281 UTF8DataChunk dataChunk = this; 282 int endOffset = offset + length; 283 int index = offset & CHUNK_MASK; 284 byte[] data = fData; 285 boolean skiplf = false; 286 while (offset < endOffset) { 287 if (strLength-- == 0) 288 return false; 289 int b0 = data[index++] & 0xff; 290 offset++; 291 if (index == CHUNK_SIZE && offset < endOffset) { 292 dataChunk = dataChunk.fNextChunk; 293 data = dataChunk.fData; 294 index = 0; 295 } 296 if (b0 < 0x80) { 297 if (skiplf) { 298 skiplf = false; 299 if (b0 == 0x0A) 300 continue; 301 } 302 if (b0 == 0x0D) { 303 b0 = 0x0A; 304 skiplf = true; 305 } 306 if (b0 != strChars[strOffset++]) 307 return false; 308 continue; 309 } 310 int b1 = data[index++] & 0xff; 311 offset++; 312 if (index == CHUNK_SIZE && offset < endOffset) { 313 dataChunk = dataChunk.fNextChunk; 314 data = dataChunk.fData; 315 index = 0; 316 } 317 if ((0xe0 & b0) == 0xc0) { int ch = ((0x1f & b0)<<6) + (0x3f & b1); 319 if (ch != strChars[strOffset++]) 320 return false; 321 continue; 322 } 323 int b2 = data[index++] & 0xff; 324 offset++; 325 if (index == CHUNK_SIZE && offset < endOffset) { 326 dataChunk = dataChunk.fNextChunk; 327 data = dataChunk.fData; 328 index = 0; 329 } 330 if ((0xf0 & b0) == 0xe0) { int ch = ((0x0f & b0)<<12) + ((0x3f & b1)<<6) + (0x3f & b2); 332 if (ch != strChars[strOffset++]) 333 return false; 334 continue; 335 } 336 int b3 = data[index++] & 0xff; offset++; 338 if (index == CHUNK_SIZE && offset < endOffset) { 339 dataChunk = dataChunk.fNextChunk; 340 data = dataChunk.fData; 341 index = 0; 342 } 343 int ch = ((0x0f & b0)<<18) + ((0x3f & b1)<<12) 344 + ((0x3f & b2)<<6) + (0x3f & b3); 345 if (ch < 0x10000) { 346 if (ch != strChars[strOffset++]) 347 return false; 348 } else { 349 if ((((ch-0x00010000)>>10)+0xd800) != strChars[strOffset++]) 350 return false; 351 if (strLength-- == 0) 352 return false; 353 if ((((ch-0x00010000)&0x3ff)+0xdc00) != strChars[strOffset++]) 354 return false; 355 } 356 } 357 return (strLength == 0); 358 } 359 public int addString(int offset, int length) { 363 if (length == 0) 364 return StringPool.EMPTY_STRING; 365 int chunk = offset >> CHUNK_SHIFT; 366 if (chunk != fChunk) { 367 if (fPreviousChunk == null) 368 throw new RuntimeException (new ImplementationMessages().createMessage(null, ImplementationMessages.INT_PCN, 0, null)); 369 return fPreviousChunk.addString(offset, length); 370 } 371 int lastChunk = (offset + length - 1) >> CHUNK_SHIFT; 372 if (chunk == lastChunk) { 373 addRef(); 374 return fStringPool.addString(this, offset & CHUNK_MASK, length); 375 } 376 String str = toString(offset & CHUNK_MASK, length); 377 return fStringPool.addString(str); 378 } 379 public int addSymbol(int offset, int length, int hashcode) { 383 if (length == 0) 384 return StringPool.EMPTY_STRING; 385 int chunk = offset >> CHUNK_SHIFT; 386 if (chunk != fChunk) { 387 if (fPreviousChunk == null) 388 throw new RuntimeException (new ImplementationMessages().createMessage(null, ImplementationMessages.INT_PCN, 0, null)); 389 return fPreviousChunk.addSymbol(offset, length, hashcode); 390 } 391 int lastChunk = (offset + length - 1) >> CHUNK_SHIFT; 392 int index = offset & CHUNK_MASK; 393 if (chunk == lastChunk) { 394 if (hashcode == 0) { 395 hashcode = getHashcode(index, length); 396 } 397 int symbol = fStringPool.lookupSymbol(this, index, length, hashcode); 398 if (symbol == -1) { 399 String str = toString(index, length); 400 symbol = fStringPool.addNewSymbol(str, hashcode); 401 } 402 return symbol; 403 } 404 String str = toString(index, length); 405 return fStringPool.addSymbol(str); 406 } 407 public void append(XMLEntityHandler.CharBuffer charBuffer, int offset, int length) { 411 UTF8DataChunk dataChunk = chunkFor(offset); 415 int endOffset = offset + length; 416 int index = offset & CHUNK_MASK; 417 byte[] data = dataChunk.fData; 418 boolean skiplf = false; 419 while (offset < endOffset) { 420 int b0 = data[index++] & 0xff; 421 offset++; 422 if (index == CHUNK_SIZE && offset < endOffset) { 423 dataChunk = dataChunk.fNextChunk; 424 data = dataChunk.fData; 425 index = 0; 426 } 427 if (b0 < 0x80) { 428 if (skiplf) { 429 skiplf = false; 430 if (b0 == 0x0A) 431 continue; 432 } 433 if (b0 == 0x0D) { 434 b0 = 0x0A; 435 skiplf = true; 436 } 437 charBuffer.append((char)b0); 438 continue; 439 } 440 int b1 = data[index++] & 0xff; 441 offset++; 442 if (index == CHUNK_SIZE && offset < endOffset) { 443 dataChunk = dataChunk.fNextChunk; 444 data = dataChunk.fData; 445 index = 0; 446 } 447 if ((0xe0 & b0) == 0xc0) { int ch = ((0x1f & b0)<<6) + (0x3f & b1); 449 charBuffer.append((char)ch); continue; 451 } 452 int b2 = data[index++] & 0xff; 453 offset++; 454 if (index == CHUNK_SIZE && offset < endOffset) { 455 dataChunk = dataChunk.fNextChunk; 456 data = dataChunk.fData; 457 index = 0; 458 } 459 if ((0xf0 & b0) == 0xe0) { int ch = ((0x0f & b0)<<12) + ((0x3f & b1)<<6) + (0x3f & b2); 461 charBuffer.append((char)ch); continue; 463 } 464 int b3 = data[index++] & 0xff; offset++; 466 if (index == CHUNK_SIZE && offset < endOffset) { 467 dataChunk = dataChunk.fNextChunk; 468 data = dataChunk.fData; 469 index = 0; 470 } 471 int ch = ((0x0f & b0)<<18) + ((0x3f & b1)<<12) 472 + ((0x3f & b2)<<6) + (0x3f & b3); 473 if (ch < 0x10000) 474 charBuffer.append((char)ch); 475 else { 476 charBuffer.append((char)(((ch-0x00010000)>>10)+0xd800)); 477 charBuffer.append((char)(((ch-0x00010000)&0x3ff)+0xdc00)); 478 } 479 } 480 } 481 private int getHashcode(int index, int length) { 485 int endIndex = index + length; 486 int hashcode = 0; 487 byte[] data = fData; 488 while (index < endIndex) { 489 int b0 = data[index++] & 0xff; 490 if ((b0 & 0x80) == 0) { 491 hashcode = StringHasher.hashChar(hashcode, b0); 492 continue; 493 } 494 int b1 = data[index++] & 0xff; 495 if ((0xe0 & b0) == 0xc0) { int ch = ((0x1f & b0)<<6) + (0x3f & b1); hashcode = StringHasher.hashChar(hashcode, ch); 498 continue; 499 } 500 int b2 = data[index++] & 0xff; 501 if ((0xf0 & b0) == 0xe0) { int ch = ((0x0f & b0)<<12) + ((0x3f & b1)<<6) + (0x3f & b2); hashcode = StringHasher.hashChar(hashcode, ch); 504 continue; 505 } 506 int b3 = data[index++] & 0xff; int ch = ((0x0f & b0)<<18) + ((0x3f & b1)<<12) 508 + ((0x3f & b2)<<6) + (0x3f & b3); 509 if (ch < 0x10000) 510 hashcode = StringHasher.hashChar(hashcode, ch); 511 else { 512 hashcode = StringHasher.hashChar(hashcode, (int)(((ch-0x00010000)>>10)+0xd800)); 513 hashcode = StringHasher.hashChar(hashcode, (int)(((ch-0x00010000)&0x3ff)+0xdc00)); 514 } 515 } 516 return StringHasher.finishHash(hashcode); 517 } 518 private void init(StringPool stringPool, UTF8DataChunk prev) { 522 fStringPool = stringPool; 523 fRefCount = 1; 524 fChunk = prev == null ? 0 : prev.fChunk + 1; 525 fNextChunk = null; 526 fPreviousChunk = prev; 527 if (prev != null) { 528 prev.addRef(); 529 prev.setNextChunk(this); 530 prev.removeRef(); 531 } 532 } 533 private UTF8DataChunk(StringPool stringPool, UTF8DataChunk prev) { 537 init(stringPool, prev); 538 } 539 private final UTF8DataChunk chunkFor(int offset) { 543 if ((offset >> CHUNK_SHIFT) == fChunk) 544 return this; 545 return slowChunkFor(offset); 546 } 547 private UTF8DataChunk slowChunkFor(int offset) { 548 int firstChunk = offset >> CHUNK_SHIFT; 549 UTF8DataChunk dataChunk = this; 550 while (firstChunk != dataChunk.fChunk) 551 dataChunk = dataChunk.fPreviousChunk; 552 return dataChunk; 553 } 554 private final void addRef() { 558 fRefCount++; 559 } 561 private final void removeRef() { 565 fRefCount--; 566 if (fRefCount == 0) { 568 fStringPool = null; 570 fChunk = -1; 571 fPreviousChunk = null; 573 synchronized (UTF8DataChunk.class) { 574 577 fNextChunk = null; 578 fgFreeChunks = this; 579 } 580 } 581 } 582 private void setNextChunk(UTF8DataChunk nextChunk) { 586 if (nextChunk == null) { 587 if (fNextChunk != null) 588 fNextChunk.removeRef(); 589 } else if (fNextChunk == null) { 590 nextChunk.addRef(); 591 } else 592 throw new RuntimeException ("UTF8DataChunk::setNextChunk"); 593 fNextChunk = nextChunk; 594 } 595 private StringPool fStringPool; 599 private int fRefCount; 600 private int fChunk; 601 private byte[] fData = null; 602 private UTF8DataChunk fNextChunk; 603 private UTF8DataChunk fPreviousChunk; 604 private static UTF8DataChunk fgFreeChunks = null; 605 private static char[] fgTempBuffer = null; 606 private static Object fgTempBufferLock = new Object (); 607 } 608 | Popular Tags |