1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 26 package sun.nio.cs.ext; 27 28 import java.nio.ByteBuffer; 29 import java.nio.CharBuffer; 30 import java.nio.charset.Charset; 31 import java.nio.charset.CharsetDecoder; 32 import java.nio.charset.CharsetEncoder; 33 import java.nio.charset.CoderResult; 34 import java.util.Arrays; 35 import sun.nio.cs.Surrogate; 36 import static sun.nio.cs.CharsetMapping.*; 37 38 /* 39 * Four types of "DoubleByte" charsets are implemented in this class 40 * (1)DoubleByte 41 * The "mostly widely used" multibyte charset, a combination of 42 * a singlebyte character set (usually the ASCII charset) and a 43 * doublebyte character set. The codepoint values of singlebyte 44 * and doublebyte don't overlap. Microsoft's multibyte charsets 45 * and IBM's "DBCS_ASCII" charsets, such as IBM1381, 942, 943, 46 * 948, 949 and 950 are such charsets. 47 * 48 * (2)DoubleByte_EBCDIC 49 * IBM EBCDIC Mix multibyte charset. Use SO and SI to shift (switch) 50 * in and out between the singlebyte character set and doublebyte 51 * character set. 52 * 53 * (3)DoubleByte_SIMPLE_EUC 54 * It's a "simple" form of EUC encoding scheme, only have the 55 * singlebyte character set G0 and one doublebyte character set 56 * G1 are defined, G2 (with SS2) and G3 (with SS3) are not used. 57 * So it is actually the same as the "typical" type (1) mentioned 58 * above, except it return "malformed" for the SS2 and SS3 when 59 * decoding. 60 * 61 * (4)DoubleByte ONLY 62 * A "pure" doublebyte only character set. From implementation 63 * point of view, this is the type (1) with "decodeSingle" always 64 * returns unmappable. 65 * 66 * For simplicity, all implementations share the same decoding and 67 * encoding data structure. 68 * 69 * Decoding: 70 * 71 * char[][] b2c; 72 * char[] b2cSB; 73 * int b2Min, b2Max 74 * 75 * public char decodeSingle(int b) { 76 * return b2cSB.[b]; 77 * } 78 * 79 * public char decodeDouble(int b1, int b2) { 80 * if (b2 < b2Min || b2 > b2Max) 81 * return UNMAPPABLE_DECODING; 82 * return b2c[b1][b2 - b2Min]; 83 * } 84 * 85 * (1)b2Min, b2Max are the corresponding min and max value of the 86 * low-half of the double-byte. 87 * (2)The high 8-bit/b1 of the double-byte are used to indexed into 88 * b2c array. 89 * 90 * Encoding: 91 * 92 * char[] c2b; 93 * char[] c2bIndex; 94 * 95 * public int encodeChar(char ch) { 96 * return c2b[c2bIndex[ch >> 8] + (ch & 0xff)]; 97 * } 98 * 99 */ 100 101 public class DoubleByte { 102 103 public final static char[] B2C_UNMAPPABLE; 104 static { 105 B2C_UNMAPPABLE = new char[0x100]; 106 Arrays.fill(B2C_UNMAPPABLE, (char)UNMAPPABLE_DECODING); 107 } 108 109 public static class Decoder extends CharsetDecoder { 110 final char[][] b2c; 111 final char[] b2cSB; 112 final int b2Min; 113 final int b2Max; 114 115 // for SimpleEUC override 116 protected CoderResult crMalformedOrUnderFlow(int b) { 117 return CoderResult.UNDERFLOW; 118 } 119 120 protected CoderResult crMalformedOrUnmappable(int b) { 121 return CoderResult.unmappableForLength(2); 122 } 123 124 Decoder(Charset cs, float avgcpb, float maxcpb, 125 char[][] b2c, char[] b2cSB, 126 int b2Min, int b2Max) { 127 super(cs, avgcpb, maxcpb); 128 this.b2c = b2c; 129 this.b2cSB = b2cSB; 130 this.b2Min = b2Min; 131 this.b2Max = b2Max; 132 } 133 134 Decoder(Charset cs, char[][] b2c, char[] b2cSB, int b2Min, int b2Max) { 135 this(cs, 0.5f, 1.0f, b2c, b2cSB, b2Min, b2Max); 136 } 137 138 protected CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) { 139 byte[] sa = src.array(); 140 int sp = src.arrayOffset() + src.position(); 141 int sl = src.arrayOffset() + src.limit(); 142 143 char[] da = dst.array(); 144 int dp = dst.arrayOffset() + dst.position(); 145 int dl = dst.arrayOffset() + dst.limit(); 146 147 try { 148 while (sp < sl && dp < dl) { 149 // inline the decodeSingle/Double() for better performance 150 int inSize = 1; 151 int b1 = sa[sp] & 0xff; 152 char c = b2cSB[b1]; 153 if (c == UNMAPPABLE_DECODING) { 154 if (sl - sp < 2) 155 return crMalformedOrUnderFlow(b1); 156 int b2 = sa[sp + 1] & 0xff; 157 if (b2 < b2Min || b2 > b2Max || 158 (c = b2c[b1][b2 - b2Min]) == UNMAPPABLE_DECODING) { 159 return crMalformedOrUnmappable(b1); 160 } 161 inSize++; 162 } 163 da[dp++] = c; 164 sp += inSize; 165 } 166 return (sp >= sl) ? CoderResult.UNDERFLOW 167 : CoderResult.OVERFLOW; 168 } finally { 169 src.position(sp - src.arrayOffset()); 170 dst.position(dp - dst.arrayOffset()); 171 } 172 } 173 174 protected CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) { 175 int mark = src.position(); 176 try { 177 while (src.hasRemaining() && dst.hasRemaining()) { 178 int b1 = src.get() & 0xff; 179 char c = b2cSB[b1]; 180 int inSize = 1; 181 if (c == UNMAPPABLE_DECODING) { 182 if (src.remaining() < 1) 183 return crMalformedOrUnderFlow(b1); 184 int b2 = src.get() & 0xff; 185 if (b2 < b2Min || b2 > b2Max || 186 (c = b2c[b1][b2 - b2Min]) == UNMAPPABLE_DECODING) 187 return crMalformedOrUnmappable(b1); 188 inSize++; 189 } 190 dst.put(c); 191 mark += inSize; 192 } 193 return src.hasRemaining()? CoderResult.OVERFLOW 194 : CoderResult.UNDERFLOW; 195 } finally { 196 src.position(mark); 197 } 198 } 199 200 protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) { 201 if (src.hasArray() && dst.hasArray()) 202 return decodeArrayLoop(src, dst); 203 else 204 return decodeBufferLoop(src, dst); 205 } 206 207 // decode loops are not using decodeSingle/Double() for performance 208 // reason. 209 public char decodeSingle(int b) { 210 return b2cSB[b]; 211 } 212 213 public char decodeDouble(int b1, int b2) { 214 if (b2 < b2Min || b2 > b2Max) 215 return UNMAPPABLE_DECODING; 216 return b2c[b1][b2 - b2Min]; 217 } 218 } 219 220 // IBM_EBCDIC_DBCS 221 public static class Decoder_EBCDIC extends Decoder { 222 private static final int SBCS = 0; 223 private static final int DBCS = 1; 224 private static final int SO = 0x0e; 225 private static final int SI = 0x0f; 226 private int currentState; 227 228 Decoder_EBCDIC(Charset cs, 229 char[][] b2c, char[] b2cSB, int b2Min, int b2Max) { 230 super(cs, b2c, b2cSB, b2Min, b2Max); 231 } 232 233 protected void implReset() { 234 currentState = SBCS; 235 } 236 237 // Check validity of dbcs ebcdic byte pair values 238 // 239 // First byte : 0x41 -- 0xFE 240 // Second byte: 0x41 -- 0xFE 241 // Doublebyte blank: 0x4040 242 // 243 // The validation implementation in "old" DBCS_IBM_EBCDIC and sun.io 244 // as 245 // if ((b1 != 0x40 || b2 != 0x40) && 246 // (b2 < 0x41 || b2 > 0xfe)) {...} 247 // is not correct/complete (range check for b1) 248 // 249 private static boolean isDoubleByte(int b1, int b2) { 250 return (0x41 <= b1 && b1 <= 0xfe && 0x41 <= b2 && b2 <= 0xfe) 251 || (b1 == 0x40 && b2 == 0x40); // DBCS-HOST SPACE 252 } 253 254 protected CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) { 255 byte[] sa = src.array(); 256 int sp = src.arrayOffset() + src.position(); 257 int sl = src.arrayOffset() + src.limit(); 258 char[] da = dst.array(); 259 int dp = dst.arrayOffset() + dst.position(); 260 int dl = dst.arrayOffset() + dst.limit(); 261 262 try { 263 // don't check dp/dl together here, it's possible to 264 // decdoe a SO/SI without space in output buffer. 265 while (sp < sl) { 266 int b1 = sa[sp] & 0xff; 267 int inSize = 1; 268 if (b1 == SO) { // Shift out 269 if (currentState != SBCS) 270 return CoderResult.malformedForLength(1); 271 else 272 currentState = DBCS; 273 } else if (b1 == SI) { 274 if (currentState != DBCS) 275 return CoderResult.malformedForLength(1); 276 else 277 currentState = SBCS; 278 } else { 279 char c = UNMAPPABLE_DECODING; 280 if (currentState == SBCS) { 281 c = b2cSB[b1]; 282 if (c == UNMAPPABLE_DECODING) 283 return CoderResult.unmappableForLength(1); 284 } else { 285 if (sl - sp < 2) 286 return CoderResult.UNDERFLOW; 287 int b2 = sa[sp + 1] & 0xff; 288 if (b2 < b2Min || b2 > b2Max || 289 (c = b2c[b1][b2 - b2Min]) == UNMAPPABLE_DECODING) { 290 if (!isDoubleByte(b1, b2)) 291 return CoderResult.malformedForLength(2); 292 return CoderResult.unmappableForLength(2); 293 } 294 inSize++; 295 } 296 if (dl - dp < 1) 297 return CoderResult.OVERFLOW; 298 299 da[dp++] = c; 300 } 301 sp += inSize; 302 } 303 return CoderResult.UNDERFLOW; 304 } finally { 305 src.position(sp - src.arrayOffset()); 306 dst.position(dp - dst.arrayOffset()); 307 } 308 } 309 310 protected CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) { 311 int mark = src.position(); 312 try { 313 while (src.hasRemaining()) { 314 int b1 = src.get() & 0xff; 315 int inSize = 1; 316 if (b1 == SO) { // Shift out 317 if (currentState != SBCS) 318 return CoderResult.malformedForLength(1); 319 else 320 currentState = DBCS; 321 } else if (b1 == SI) { 322 if (currentState != DBCS) 323 return CoderResult.malformedForLength(1); 324 else 325 currentState = SBCS; 326 } else { 327 char c = UNMAPPABLE_DECODING; 328 if (currentState == SBCS) { 329 c = b2cSB[b1]; 330 if (c == UNMAPPABLE_DECODING) 331 return CoderResult.unmappableForLength(1); 332 } else { 333 if (src.remaining() < 1) 334 return CoderResult.UNDERFLOW; 335 int b2 = src.get()&0xff; 336 if (b2 < b2Min || b2 > b2Max || 337 (c = b2c[b1][b2 - b2Min]) == UNMAPPABLE_DECODING) { 338 if (!isDoubleByte(b1, b2)) 339 return CoderResult.malformedForLength(2); 340 return CoderResult.unmappableForLength(2); 341 } 342 inSize++; 343 } 344 345 if (dst.remaining() < 1) 346 return CoderResult.OVERFLOW; 347 348 dst.put(c); 349 } 350 mark += inSize; 351 } 352 return CoderResult.UNDERFLOW; 353 } finally { 354 src.position(mark); 355 } 356 } 357 } 358 359 // EBCDIC_DBCS_ONLY 360 public static class Decoder_EBCDIC_DBCSONLY extends Decoder { 361 static final char[] b2cSB; 362 static { 363 b2cSB = new char[0x100]; 364 Arrays.fill(b2cSB, (char)UNMAPPABLE_DECODING); 365 } 366 Decoder_EBCDIC_DBCSONLY(Charset cs, char[][] b2c, int b2Min, int b2Max) { 367 super(cs, 0.5f, 1.0f, b2c, b2cSB, b2Min, b2Max); 368 } 369 } 370 371 // EUC_SIMPLE 372 // The only thing we need to "override" is to check SS2/SS3 and 373 // return "malformed" if found 374 public static class Decoder_EUC_SIM extends Decoder { 375 private final int SS2 = 0x8E; 376 private final int SS3 = 0x8F; 377 378 Decoder_EUC_SIM(Charset cs, 379 char[][] b2c, char[] b2cSB, int b2Min, int b2Max) { 380 super(cs, b2c, b2cSB, b2Min, b2Max); 381 } 382 383 // No support provided for G2/G3 for SimpleEUC 384 protected CoderResult crMalformedOrUnderFlow(int b) { 385 if (b == SS2 || b == SS3 ) 386 return CoderResult.malformedForLength(1); 387 return CoderResult.UNDERFLOW; 388 } 389 390 protected CoderResult crMalformedOrUnmappable(int b) { 391 if (b == SS2 || b == SS3 ) 392 return CoderResult.malformedForLength(1); 393 return CoderResult.unmappableForLength(2); 394 } 395 } 396 397 public static class Encoder extends CharsetEncoder { 398 final int MAX_SINGLEBYTE = 0xff; 399 private final char[] c2b; 400 private final char[] c2bIndex; 401 Surrogate.Parser sgp; 402 403 Encoder(Charset cs, char[] c2b, char[] c2bIndex) { 404 super(cs, 2.0f, 2.0f); 405 this.c2b = c2b; 406 this.c2bIndex = c2bIndex; 407 } 408 409 Encoder(Charset cs, float avg, float max, byte[] repl, char[] c2b, char[] c2bIndex) { 410 super(cs, avg, max, repl); 411 this.c2b = c2b; 412 this.c2bIndex = c2bIndex; 413 } 414 415 public boolean canEncode(char c) { 416 return encodeChar(c) != UNMAPPABLE_ENCODING; 417 } 418 419 Surrogate.Parser sgp() { 420 if (sgp == null) 421 sgp = new Surrogate.Parser(); 422 return sgp; 423 } 424 425 protected CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { 426 char[] sa = src.array(); 427 int sp = src.arrayOffset() + src.position(); 428 int sl = src.arrayOffset() + src.limit(); 429 430 byte[] da = dst.array(); 431 int dp = dst.arrayOffset() + dst.position(); 432 int dl = dst.arrayOffset() + dst.limit(); 433 434 try { 435 while (sp < sl) { 436 char c = sa[sp]; 437 int bb = encodeChar(c); 438 if (bb == UNMAPPABLE_ENCODING) { 439 if (Surrogate.is(c)) { 440 if (sgp().parse(c, sa, sp, sl) < 0) 441 return sgp.error(); 442 return sgp.unmappableResult(); 443 } 444 return CoderResult.unmappableForLength(1); 445 } 446 447 if (bb > MAX_SINGLEBYTE) { // DoubleByte 448 if (dl - dp < 2) 449 return CoderResult.OVERFLOW; 450 da[dp++] = (byte)(bb >> 8); 451 da[dp++] = (byte)bb; 452 } else { // SingleByte 453 if (dl - dp < 1) 454 return CoderResult.OVERFLOW; 455 da[dp++] = (byte)bb; 456 } 457 458 sp++; 459 } 460 return CoderResult.UNDERFLOW; 461 } finally { 462 src.position(sp - src.arrayOffset()); 463 dst.position(dp - dst.arrayOffset()); 464 } 465 } 466 467 protected CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) { 468 int mark = src.position(); 469 try { 470 while (src.hasRemaining()) { 471 char c = src.get(); 472 int bb = encodeChar(c); 473 if (bb == UNMAPPABLE_ENCODING) { 474 if (Surrogate.is(c)) { 475 if (sgp().parse(c, src) < 0) 476 return sgp.error(); 477 return sgp.unmappableResult(); 478 } 479 return CoderResult.unmappableForLength(1); 480 } 481 if (bb > MAX_SINGLEBYTE) { // DoubleByte 482 if (dst.remaining() < 2) 483 return CoderResult.OVERFLOW; 484 dst.put((byte)(bb >> 8)); 485 dst.put((byte)(bb)); 486 } else { 487 if (dst.remaining() < 1) 488 return CoderResult.OVERFLOW; 489 dst.put((byte)bb); 490 } 491 mark++; 492 } 493 return CoderResult.UNDERFLOW; 494 } finally { 495 src.position(mark); 496 } 497 } 498 499 protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { 500 if (src.hasArray() && dst.hasArray()) 501 return encodeArrayLoop(src, dst); 502 else 503 return encodeBufferLoop(src, dst); 504 } 505 506 public int encodeChar(char ch) { 507 return c2b[c2bIndex[ch >> 8] + (ch & 0xff)]; 508 } 509 510 // init the c2b and c2bIndex tables from b2c. 511 static void initC2B(String[] b2c, String b2cSB, String b2cNR, String c2bNR, 512 int b2Min, int b2Max, 513 char[] c2b, char[] c2bIndex) 514 { 515 Arrays.fill(c2b, (char)UNMAPPABLE_ENCODING); 516 int off = 0x100; 517 518 char[][] b2c_ca = new char[b2c.length][]; 519 char[] b2cSB_ca = null; 520 if (b2cSB != null) 521 b2cSB_ca = b2cSB.toCharArray(); 522 523 for (int i = 0; i < b2c.length; i++) { 524 if (b2c[i] == null) 525 continue; 526 b2c_ca[i] = b2c[i].toCharArray(); 527 } 528 529 if (b2cNR != null) { 530 int j = 0; 531 while (j < b2cNR.length()) { 532 char b = b2cNR.charAt(j++); 533 char c = b2cNR.charAt(j++); 534 if (b < 0x100 && b2cSB_ca != null) { 535 if (b2cSB_ca[b] == c) 536 b2cSB_ca[b] = UNMAPPABLE_DECODING; 537 } else { 538 if (b2c_ca[b >> 8][(b & 0xff) - b2Min] == c) 539 b2c_ca[b >> 8][(b & 0xff) - b2Min] = UNMAPPABLE_DECODING; 540 } 541 } 542 } 543 544 if (b2cSB_ca != null) { // SingleByte 545 for (int b = 0; b < b2cSB_ca.length; b++) { 546 char c = b2cSB_ca[b]; 547 if (c == UNMAPPABLE_DECODING) 548 continue; 549 int index = c2bIndex[c >> 8]; 550 if (index == 0) { 551 index = off; 552 off += 0x100; 553 c2bIndex[c >> 8] = (char)index; 554 } 555 c2b[index + (c & 0xff)] = (char)b; 556 } 557 } 558 559 for (int b1 = 0; b1 < b2c.length; b1++) { // DoubleByte 560 char[] db = b2c_ca[b1]; 561 if (db == null) 562 continue; 563 for (int b2 = b2Min; b2 <= b2Max; b2++) { 564 char c = db[b2 - b2Min]; 565 if (c == UNMAPPABLE_DECODING) 566 continue; 567 int index = c2bIndex[c >> 8]; 568 if (index == 0) { 569 index = off; 570 off += 0x100; 571 c2bIndex[c >> 8] = (char)index; 572 } 573 c2b[index + (c & 0xff)] = (char)((b1 << 8) | b2); 574 } 575 } 576 577 if (c2bNR != null) { 578 // add c->b only nr entries 579 for (int i = 0; i < c2bNR.length(); i += 2) { 580 char b = c2bNR.charAt(i); 581 char c = c2bNR.charAt(i + 1); 582 int index = (c >> 8); 583 if (c2bIndex[index] == 0) { 584 c2bIndex[index] = (char)off; 585 off += 0x100; 586 } 587 index = c2bIndex[index] + (c & 0xff); 588 c2b[index] = b; 589 } 590 } 591 } 592 } 593 594 // EBCDIC_DBCS_ONLY 595 public static class Encoder_EBCDIC_DBCSONLY extends Encoder { 596 Encoder_EBCDIC_DBCSONLY(Charset cs, byte[] repl, 597 char[] c2b, char[] c2bIndex) { 598 super(cs, 2.0f, 2.0f, repl, c2b, c2bIndex); 599 } 600 601 public int encodeChar(char ch) { 602 int bb = super.encodeChar(ch); 603 if (bb <= MAX_SINGLEBYTE) 604 return UNMAPPABLE_ENCODING; 605 return bb; 606 } 607 } 608 609 // for IBM_EBCDIC_DBCS 610 public static class Encoder_EBCDIC extends Encoder { 611 static final int SBCS = 0; 612 static final int DBCS = 1; 613 static final byte SO = 0x0e; 614 static final byte SI = 0x0f; 615 616 protected int currentState = SBCS; 617 618 Encoder_EBCDIC(Charset cs, char[] c2b, char[] c2bIndex) { 619 super(cs, 4.0f, 5.0f, new byte[] {(byte)0x6f}, c2b, c2bIndex); 620 } 621 622 protected void implReset() { 623 currentState = SBCS; 624 } 625 626 protected CoderResult implFlush(ByteBuffer out) { 627 if (currentState == DBCS) { 628 if (out.remaining() < 1) 629 return CoderResult.OVERFLOW; 630 out.put(SI); 631 } 632 implReset(); 633 return CoderResult.UNDERFLOW; 634 } 635 636 protected CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { 637 char[] sa = src.array(); 638 int sp = src.arrayOffset() + src.position(); 639 int sl = src.arrayOffset() + src.limit(); 640 byte[] da = dst.array(); 641 int dp = dst.arrayOffset() + dst.position(); 642 int dl = dst.arrayOffset() + dst.limit(); 643 644 try { 645 while (sp < sl) { 646 char c = sa[sp]; 647 int bb = encodeChar(c); 648 if (bb == UNMAPPABLE_ENCODING) { 649 if (Surrogate.is(c)) { 650 if (sgp().parse(c, sa, sp, sl) < 0) 651 return sgp.error(); 652 return sgp.unmappableResult(); 653 } 654 return CoderResult.unmappableForLength(1); 655 } 656 if (bb > MAX_SINGLEBYTE) { // DoubleByte 657 if (currentState == SBCS) { 658 if (dl - dp < 1) 659 return CoderResult.OVERFLOW; 660 currentState = DBCS; 661 da[dp++] = SO; 662 } 663 if (dl - dp < 2) 664 return CoderResult.OVERFLOW; 665 da[dp++] = (byte)(bb >> 8); 666 da[dp++] = (byte)bb; 667 } else { // SingleByte 668 if (currentState == DBCS) { 669 if (dl - dp < 1) 670 return CoderResult.OVERFLOW; 671 currentState = SBCS; 672 da[dp++] = SI; 673 } 674 if (dl - dp < 1) 675 return CoderResult.OVERFLOW; 676 da[dp++] = (byte)bb; 677 678 } 679 sp++; 680 } 681 return CoderResult.UNDERFLOW; 682 } finally { 683 src.position(sp - src.arrayOffset()); 684 dst.position(dp - dst.arrayOffset()); 685 } 686 } 687 688 protected CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) { 689 int mark = src.position(); 690 try { 691 while (src.hasRemaining()) { 692 char c = src.get(); 693 int bb = encodeChar(c); 694 if (bb == UNMAPPABLE_ENCODING) { 695 if (Surrogate.is(c)) { 696 if (sgp().parse(c, src) < 0) 697 return sgp.error(); 698 return sgp.unmappableResult(); 699 } 700 return CoderResult.unmappableForLength(1); 701 } 702 if (bb > MAX_SINGLEBYTE) { // DoubleByte 703 if (currentState == SBCS) { 704 if (dst.remaining() < 1) 705 return CoderResult.OVERFLOW; 706 currentState = DBCS; 707 dst.put(SO); 708 } 709 if (dst.remaining() < 2) 710 return CoderResult.OVERFLOW; 711 dst.put((byte)(bb >> 8)); 712 dst.put((byte)(bb)); 713 } else { // Single-byte 714 if (currentState == DBCS) { 715 if (dst.remaining() < 1) 716 return CoderResult.OVERFLOW; 717 currentState = SBCS; 718 dst.put(SI); 719 } 720 if (dst.remaining() < 1) 721 return CoderResult.OVERFLOW; 722 dst.put((byte)bb); 723 } 724 mark++; 725 } 726 return CoderResult.UNDERFLOW; 727 } finally { 728 src.position(mark); 729 } 730 } 731 } 732 733 // EUC_SIMPLE 734 public static class Encoder_EUC_SIM extends Encoder { 735 Encoder_EUC_SIM(Charset cs, char[] c2b, char[] c2bIndex) { 736 super(cs, c2b, c2bIndex); 737 } 738 } 739 }