1 /*
   2  * Copyright 2008 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;
  27 
  28 import java.nio.Buffer;
  29 import java.nio.ByteBuffer;
  30 import java.nio.CharBuffer;
  31 import java.nio.charset.Charset;
  32 import java.nio.charset.CharsetDecoder;
  33 import java.nio.charset.CharsetEncoder;
  34 import java.nio.charset.CoderResult;
  35 import static sun.nio.cs.CharsetMapping.*;
  36 
  37 public class SingleByte
  38 {
  39     private static final CoderResult withResult(CoderResult cr,
  40                                                 Buffer src, int sp,
  41                                                 Buffer dst, int dp)
  42     {
  43         src.position(sp - src.arrayOffset());
  44         dst.position(dp - dst.arrayOffset());
  45         return cr;
  46     }
  47 
  48     public static class Decoder extends CharsetDecoder {
  49         private final char[] b2c;
  50 
  51         public Decoder(Charset cs, char[] b2c) {
  52             super(cs, 1.0f, 1.0f);
  53             this.b2c = b2c;
  54         }
  55 
  56         private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
  57             byte[] sa = src.array();
  58             int sp = src.arrayOffset() + src.position();
  59             int sl = src.arrayOffset() + src.limit();
  60 
  61             char[] da = dst.array();
  62             int dp = dst.arrayOffset() + dst.position();
  63             int dl = dst.arrayOffset() + dst.limit();
  64 
  65             CoderResult cr = CoderResult.UNDERFLOW;
  66             if ((dl - dp) < (sl - sp)) {
  67                 sl = sp + (dl - dp);
  68                 cr = CoderResult.OVERFLOW;
  69             }
  70 
  71             while (sp < sl) {
  72                 char c = decode(sa[sp]);
  73                 if (c == UNMAPPABLE_DECODING) {
  74                     return withResult(CoderResult.unmappableForLength(1),
  75                                src, sp, dst, dp);
  76                 }
  77                 da[dp++] = c;
  78                 sp++;
  79             }
  80             return withResult(cr, src, sp, dst, dp);
  81         }
  82 
  83         private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) {
  84             int mark = src.position();
  85             try {
  86                 while (src.hasRemaining()) {
  87                     char c = decode(src.get());
  88                     if (c == UNMAPPABLE_DECODING)
  89                         return CoderResult.unmappableForLength(1);
  90                     if (!dst.hasRemaining())
  91                         return CoderResult.OVERFLOW;
  92                     dst.put(c);
  93                     mark++;
  94                 }
  95                 return CoderResult.UNDERFLOW;
  96             } finally {
  97                 src.position(mark);
  98             }
  99         }
 100 
 101         protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
 102             if (src.hasArray() && dst.hasArray())
 103                 return decodeArrayLoop(src, dst);
 104             else
 105                 return decodeBufferLoop(src, dst);
 106         }
 107 
 108         private final char decode(int b) {
 109             return b2c[b + 128];
 110         }
 111     }
 112 
 113     public static class Encoder extends CharsetEncoder {
 114         private Surrogate.Parser sgp;
 115         private final char[] c2b;
 116         private final char[] c2bIndex;
 117 
 118         public Encoder(Charset cs, char[] c2b, char[] c2bIndex) {
 119             super(cs, 1.0f, 1.0f);
 120             this.c2b = c2b;
 121             this.c2bIndex = c2bIndex;
 122         }
 123 
 124         public boolean canEncode(char c) {
 125             return encode(c) != UNMAPPABLE_ENCODING;
 126         }
 127 
 128         private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
 129             char[] sa = src.array();
 130             int sp = src.arrayOffset() + src.position();
 131             int sl = src.arrayOffset() + src.limit();
 132 
 133             byte[] da = dst.array();
 134             int dp = dst.arrayOffset() + dst.position();
 135             int dl = dst.arrayOffset() + dst.limit();
 136 
 137             CoderResult cr = CoderResult.UNDERFLOW;
 138             if ((dl - dp) < (sl - sp)) {
 139                 sl = sp + (dl - dp);
 140                 cr = CoderResult.OVERFLOW;
 141             }
 142 
 143             while (sp < sl) {
 144                 char c = sa[sp];
 145                 int b = encode(c);
 146                 if (b == UNMAPPABLE_ENCODING) {
 147                     if (Surrogate.is(c)) {
 148                         if (sgp == null)
 149                             sgp = new Surrogate.Parser();
 150                         if (sgp.parse(c, sa, sp, sl) < 0)
 151                             return withResult(sgp.error(), src, sp, dst, dp);
 152                         return withResult(sgp.unmappableResult(), src, sp, dst, dp);
 153                     }
 154                     return withResult(CoderResult.unmappableForLength(1),
 155                                src, sp, dst, dp);
 156                 }
 157                 da[dp++] = (byte)b;
 158                 sp++;
 159             }
 160             return withResult(cr, src, sp, dst, dp);
 161         }
 162 
 163         private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
 164             int mark = src.position();
 165             try {
 166                 while (src.hasRemaining()) {
 167                     char c = src.get();
 168                     int b = encode(c);
 169                     if (b == UNMAPPABLE_ENCODING) {
 170                         if (Surrogate.is(c)) {
 171                             if (sgp == null)
 172                                 sgp = new Surrogate.Parser();
 173                             if (sgp.parse(c, src) < 0)
 174                                 return sgp.error();
 175                             return sgp.unmappableResult();
 176                         }
 177                         return CoderResult.unmappableForLength(1);
 178                     }
 179                     if (!dst.hasRemaining())
 180                         return CoderResult.OVERFLOW;
 181                     dst.put((byte)b);
 182                     mark++;
 183                 }
 184                 return CoderResult.UNDERFLOW;
 185             } finally {
 186                 src.position(mark);
 187             }
 188         }
 189 
 190         protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
 191             if (src.hasArray() && dst.hasArray())
 192                 return encodeArrayLoop(src, dst);
 193             else
 194                 return encodeBufferLoop(src, dst);
 195         }
 196 
 197         private final int encode(char ch) {
 198             char index = c2bIndex[ch >> 8];
 199             if (index == UNMAPPABLE_ENCODING)
 200                 return UNMAPPABLE_ENCODING;
 201             return c2b[index + (ch & 0xff)];
 202         }
 203     }
 204 
 205     // init the c2b and c2bIndex tables from b2c.
 206     public static void initC2B(char[] b2c, char[] c2bNR,
 207                                char[] c2b, char[] c2bIndex) {
 208         for (int i = 0; i < c2bIndex.length; i++)
 209             c2bIndex[i] = UNMAPPABLE_ENCODING;
 210         for (int i = 0; i < c2b.length; i++)
 211             c2b[i] = UNMAPPABLE_ENCODING;
 212         int off = 0;
 213         for (int i = 0; i < b2c.length; i++) {
 214             char c = b2c[i];
 215             if (c == UNMAPPABLE_DECODING)
 216                 continue;
 217             int index = (c >> 8);
 218             if (c2bIndex[index] == UNMAPPABLE_ENCODING) {
 219                 c2bIndex[index] = (char)off;
 220                 off += 0x100;
 221             }
 222             index = c2bIndex[index] + (c & 0xff);
 223             c2b[index] = (char)((i>=0x80)?(i-0x80):(i+0x80));
 224         }
 225         if (c2bNR != null) {
 226             // c-->b nr entries
 227             int i = 0;
 228             while (i < c2bNR.length) {
 229                 char b = c2bNR[i++];
 230                 char c = c2bNR[i++];
 231                 int index = (c >> 8);
 232                 if (c2bIndex[index] == UNMAPPABLE_ENCODING) {
 233                     c2bIndex[index] = (char)off;
 234                     off += 0x100;
 235                 }
 236                 index = c2bIndex[index] + (c & 0xff);
 237                 c2b[index] = b;
 238             }
 239         }
 240     }
 241 }