1 /*
   2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  * @(#)SingleByteEncoder.java   1.14 03/01/23
  28  */
  29 
  30 package com.sun.codemodel.internal.util;
  31 
  32 import java.nio.ByteBuffer;
  33 import java.nio.CharBuffer;
  34 import java.nio.charset.Charset;
  35 import java.nio.charset.CharsetEncoder;
  36 import java.nio.charset.CoderResult;
  37 
  38 import sun.nio.cs.Surrogate;
  39 
  40 
  41 abstract class SingleByteEncoder
  42     extends CharsetEncoder
  43 {
  44 
  45     private final short index1[];
  46     private final String index2;
  47     private final int mask1;
  48     private final int mask2;
  49     private final int shift;
  50 
  51     private final Surrogate.Parser sgp = new Surrogate.Parser();
  52 
  53     protected SingleByteEncoder(Charset cs,
  54                                 short[] index1, String index2,
  55                                 int mask1, int mask2, int shift)
  56     {
  57         super(cs, 1.0f, 1.0f);
  58         this.index1 = index1;
  59         this.index2 = index2;
  60         this.mask1 = mask1;
  61         this.mask2 = mask2;
  62         this.shift = shift;
  63     }
  64 
  65     public boolean canEncode(char c) {
  66         char testEncode;
  67         testEncode = index2.charAt(index1[(c & mask1) >> shift]
  68                                    + (c & mask2));
  69         if (testEncode == '\u0000')
  70             return false;
  71         else
  72             return true;
  73     }
  74 
  75     private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
  76         char[] sa = src.array();
  77         int sp = src.arrayOffset() + src.position();
  78         int sl = src.arrayOffset() + src.limit();
  79         sp = (sp <= sl ? sp : sl);
  80         byte[] da = dst.array();
  81         int dp = dst.arrayOffset() + dst.position();
  82         int dl = dst.arrayOffset() + dst.limit();
  83         dp = (dp <= dl ? dp : dl);
  84 
  85         try {
  86             while (sp < sl) {
  87                 char c = sa[sp];
  88                 if (Surrogate.is(c)) {
  89                     if (sgp.parse(c, sa, sp, sl) < 0)
  90                         return sgp.error();
  91                     return sgp.unmappableResult();
  92                 }
  93                 if (c >= '\uFFFE')
  94                     return CoderResult.unmappableForLength(1);
  95                 if (dl - dp < 1)
  96                     return CoderResult.OVERFLOW;
  97 
  98                 char e = index2.charAt(index1[(c & mask1) >> shift]
  99                                        + (c & mask2));
 100 
 101                 // If output byte is zero because input char is zero
 102                 // then character is mappable, o.w. fail
 103                 if (e == '\u0000' && c != '\u0000')
 104                     return CoderResult.unmappableForLength(1);
 105 
 106                 sp++;
 107                 da[dp++] = (byte)e;
 108             }
 109             return CoderResult.UNDERFLOW;
 110         } finally {
 111             src.position(sp - src.arrayOffset());
 112             dst.position(dp - dst.arrayOffset());
 113         }
 114     }
 115 
 116     private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
 117         int mark = src.position();
 118         try {
 119             while (src.hasRemaining()) {
 120                 char c = src.get();
 121                 if (Surrogate.is(c)) {
 122                     if (sgp.parse(c, src) < 0)
 123                         return sgp.error();
 124                     return sgp.unmappableResult();
 125                 }
 126                 if (c >= '\uFFFE')
 127                     return CoderResult.unmappableForLength(1);
 128                 if (!dst.hasRemaining())
 129                     return CoderResult.OVERFLOW;
 130 
 131                 char e = index2.charAt(index1[(c & mask1) >> shift]
 132                                        + (c & mask2));
 133 
 134                 // If output byte is zero because input char is zero
 135                 // then character is mappable, o.w. fail
 136                 if (e == '\u0000' && c != '\u0000')
 137                     return CoderResult.unmappableForLength(1);
 138 
 139                 mark++;
 140                 dst.put((byte)e);
 141             }
 142             return CoderResult.UNDERFLOW;
 143         } finally {
 144             src.position(mark);
 145         }
 146     }
 147 
 148     protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
 149         if (true && src.hasArray() && dst.hasArray())
 150             return encodeArrayLoop(src, dst);
 151         else
 152             return encodeBufferLoop(src, dst);
 153     }
 154 
 155     public byte encode(char inputChar) {
 156         return (byte)index2.charAt(index1[(inputChar & mask1) >> shift] +
 157                 (inputChar & mask2));
 158     }
 159 }