1 7 8 10 package java.nio.charset; 11 12 import java.nio.Buffer ; 13 import java.nio.ByteBuffer ; 14 import java.nio.CharBuffer ; 15 import java.nio.BufferOverflowException ; 16 import java.nio.BufferUnderflowException ; 17 import java.lang.ref.WeakReference ; 18 import java.nio.charset.CoderMalfunctionError ; 20 21 118 119 public abstract class CharsetEncoder { 120 121 private final Charset charset; 122 private final float averageBytesPerChar; 123 private final float maxBytesPerChar; 124 125 private byte[] replacement; 126 private CodingErrorAction malformedInputAction 127 = CodingErrorAction.REPORT; 128 private CodingErrorAction unmappableCharacterAction 129 = CodingErrorAction.REPORT; 130 131 private static final int ST_RESET = 0; 134 private static final int ST_CODING = 1; 135 private static final int ST_END = 2; 136 private static final int ST_FLUSHED = 3; 137 138 private int state = ST_RESET; 139 140 private static String stateNames[] 141 = { "RESET", "CODING", "CODING_END", "FLUSHED" }; 142 143 144 164 protected 165 CharsetEncoder(Charset cs, 166 float averageBytesPerChar, 167 float maxBytesPerChar, 168 byte[] replacement) 169 { 170 this.charset = cs; 171 if (averageBytesPerChar <= 0.0f) 172 throw new IllegalArgumentException ("Non-positive " 173 + "averageBytesPerChar"); 174 if (maxBytesPerChar <= 0.0f) 175 throw new IllegalArgumentException ("Non-positive " 176 + "maxBytesPerChar"); 177 if (!Charset.atBugLevel("1.4")) { 178 if (averageBytesPerChar > maxBytesPerChar) 179 throw new IllegalArgumentException ("averageBytesPerChar" 180 + " exceeds " 181 + "maxBytesPerChar"); 182 } 183 this.replacement = replacement; 184 this.averageBytesPerChar = averageBytesPerChar; 185 this.maxBytesPerChar = maxBytesPerChar; 186 replaceWith(replacement); 187 } 188 189 205 protected CharsetEncoder(Charset cs, 206 float averageBytesPerChar, 207 float maxBytesPerChar) 208 { 209 this(cs, 210 averageBytesPerChar, maxBytesPerChar, 211 new byte[] { (byte)'?' }); 212 } 213 214 219 public final Charset charset() { 220 return charset; 221 } 222 223 229 public final byte[] replacement() { 230 return replacement; 231 } 232 233 258 public final CharsetEncoder replaceWith(byte[] newReplacement) { 259 if (newReplacement == null) 260 throw new IllegalArgumentException ("Null replacement"); 261 int len = newReplacement.length; 262 if (len == 0) 263 throw new IllegalArgumentException ("Empty replacement"); 264 if (len > maxBytesPerChar) 265 throw new IllegalArgumentException ("Replacement too long"); 266 267 if (!isLegalReplacement(newReplacement)) 268 throw new IllegalArgumentException ("Illegal replacement"); 269 270 this.replacement = newReplacement; 271 implReplaceWith(newReplacement); 272 return this; 273 } 274 275 284 protected void implReplaceWith(byte[] newReplacement) { 285 } 286 287 288 289 private WeakReference cachedDecoder = null; 290 291 307 public boolean isLegalReplacement(byte[] repl) { 308 WeakReference wr = cachedDecoder; 309 CharsetDecoder dec = null; 310 if ((wr == null) || ((dec = (CharsetDecoder )wr.get()) == null)) { 311 dec = charset().newDecoder(); 312 dec.onMalformedInput(CodingErrorAction.REPORT); 313 dec.onUnmappableCharacter(CodingErrorAction.REPORT); 314 cachedDecoder = new WeakReference (dec); 315 } else { 316 dec.reset(); 317 } 318 ByteBuffer bb = ByteBuffer.wrap(repl); 319 CharBuffer cb = CharBuffer.allocate((int)(bb.remaining() 322 * (double)dec.maxCharsPerByte())); 323 CoderResult cr = dec.decode(bb, cb, true); 324 return !cr.isError(); 325 } 326 327 328 329 334 public CodingErrorAction malformedInputAction() { 335 return malformedInputAction; 336 } 337 338 351 public final CharsetEncoder onMalformedInput(CodingErrorAction newAction) { 352 if (newAction == null) 353 throw new IllegalArgumentException ("Null action"); 354 malformedInputAction = newAction; 355 implOnMalformedInput(newAction); 356 return this; 357 } 358 359 366 protected void implOnMalformedInput(CodingErrorAction newAction) { } 367 368 375 public CodingErrorAction unmappableCharacterAction() { 376 return unmappableCharacterAction; 377 } 378 379 392 public final CharsetEncoder onUnmappableCharacter(CodingErrorAction 393 newAction) 394 { 395 if (newAction == null) 396 throw new IllegalArgumentException ("Null action"); 397 unmappableCharacterAction = newAction; 398 implOnUnmappableCharacter(newAction); 399 return this; 400 } 401 402 409 protected void implOnUnmappableCharacter(CodingErrorAction newAction) { } 410 411 419 public final float averageBytesPerChar() { 420 return averageBytesPerChar; 421 } 422 423 431 public final float maxBytesPerChar() { 432 return maxBytesPerChar; 433 } 434 435 531 public final CoderResult encode(CharBuffer in, ByteBuffer out, 532 boolean endOfInput) 533 { 534 int newState = endOfInput ? ST_END : ST_CODING; 535 if ((state != ST_RESET) && (state != ST_CODING) 536 && !(endOfInput && (state == ST_END))) 537 throwIllegalStateException(state, newState); 538 state = newState; 539 540 for (;;) { 541 542 CoderResult cr; 543 try { 544 cr = encodeLoop(in, out); 545 } catch (BufferUnderflowException x) { 546 throw new CoderMalfunctionError (x); 547 } catch (BufferOverflowException x) { 548 throw new CoderMalfunctionError (x); 549 } 550 551 if (cr.isOverflow()) 552 return cr; 553 554 if (cr.isUnderflow()) { 555 if (endOfInput && in.hasRemaining()) { 556 cr = CoderResult.malformedForLength(in.remaining()); 557 } else { 559 return cr; 560 } 561 } 562 563 CodingErrorAction action = null; 564 if (cr.isMalformed()) 565 action = malformedInputAction; 566 else if (cr.isUnmappable()) 567 action = unmappableCharacterAction; 568 else 569 assert false : cr.toString(); 570 571 if (action == CodingErrorAction.REPORT) 572 return cr; 573 574 if (action == CodingErrorAction.REPLACE) { 575 if (out.remaining() < replacement.length) 576 return CoderResult.OVERFLOW; 577 out.put(replacement); 578 } 579 580 if ((action == CodingErrorAction.IGNORE) 581 || (action == CodingErrorAction.REPLACE)) { 582 in.position(in.position() + cr.length()); 584 continue; 585 } 586 587 assert false; 588 } 589 590 } 591 592 628 public final CoderResult flush(ByteBuffer out) { 629 if (state != ST_END) 630 throwIllegalStateException(state, ST_FLUSHED); 631 state = ST_FLUSHED; 632 return implFlush(out); 633 } 634 635 649 protected CoderResult implFlush(ByteBuffer out) { 650 return CoderResult.UNDERFLOW; 651 } 652 653 663 public final CharsetEncoder reset() { 664 implReset(); 665 state = ST_RESET; 666 return this; 667 } 668 669 675 protected void implReset() { } 676 677 712 protected abstract CoderResult encodeLoop(CharBuffer in, 713 ByteBuffer out); 714 715 746 public final ByteBuffer encode(CharBuffer in) 747 throws CharacterCodingException 748 { 749 int n = (int)(in.remaining() * averageBytesPerChar()); 750 ByteBuffer out = ByteBuffer.allocate(n); 751 752 if (n == 0) 753 return out; 754 reset(); 755 for (;;) { 756 CoderResult cr; 757 if (in.hasRemaining()) 758 cr = encode(in, out, true); 759 else 760 cr = flush(out); 761 if (cr.isUnderflow()) 762 break; 763 if (cr.isOverflow()) { 764 n *= 2; 765 ByteBuffer o = ByteBuffer.allocate(n); 766 out.flip(); 767 o.put(out); 768 out = o; 769 continue; 770 } 771 cr.throwException(); 772 } 773 out.flip(); 774 return out; 775 } 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 private boolean canEncode(CharBuffer cb) { 856 if (state == ST_FLUSHED) 857 reset(); 858 else if (state != ST_RESET) 859 throwIllegalStateException(state, ST_CODING); 860 CodingErrorAction ma = malformedInputAction(); 861 CodingErrorAction ua = unmappableCharacterAction(); 862 try { 863 onMalformedInput(CodingErrorAction.REPORT); 864 onUnmappableCharacter(CodingErrorAction.REPORT); 865 encode(cb); 866 } catch (CharacterCodingException x) { 867 return false; 868 } finally { 869 onMalformedInput(ma); 870 onUnmappableCharacter(ua); 871 reset(); 872 } 873 return true; 874 } 875 876 899 public boolean canEncode(char c) { 900 CharBuffer cb = CharBuffer.allocate(1); 901 cb.put(c); 902 cb.flip(); 903 return canEncode(cb); 904 } 905 906 928 public boolean canEncode(CharSequence cs) { 929 CharBuffer cb; 930 if (cs instanceof CharBuffer ) 931 cb = ((CharBuffer )cs).duplicate(); 932 else 933 cb = CharBuffer.wrap(cs.toString()); 934 return canEncode(cb); 935 } 936 937 938 939 940 private void throwIllegalStateException(int from, int to) { 941 throw new IllegalStateException ("Current state = " + stateNames[from] 942 + ", new state = " + stateNames[to]); 943 } 944 945 } 946 | Popular Tags |