BASE641


点击(此处)折叠或打开

  1. import java.math.BigInteger;
  2. import java.util.Arrays;


  3. public class SanyiDecode extends SanyiCodec {

  4.     private static final int BITS_PER_ENCODED_BYTE = 6;
  5.     private static final int BYTES_PER_UNENCODED_BLOCK = 3;
  6.     private static final int BYTES_PER_ENCODED_BLOCK = 4;

  7.     static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};

  8.     private static final byte[] STANDARD_ENCODE_TABLE = {
  9.             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  10.             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
  11.             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  12.             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
  13.             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
  14.     };

  15.     private static final byte[] URL_SAFE_ENCODE_TABLE = {
  16.             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  17.             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
  18.             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  19.             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
  20.             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
  21.     };

  22.     private static final byte[] DECODE_TABLE = {
  23.             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  24.             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  25.             -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54,
  26.             55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
  27.             5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
  28.             24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
  29.             35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
  30.     };

  31.     private static final int MASK_6BITS = 0x3f;

  32.     private final byte[] encodeTable;

  33.     private final byte[] decodeTable = DECODE_TABLE;
  34.     private final byte[] lineSeparator;

  35.     private final int decodeSize;

  36.     private final int encodeSize;

  37.     public SanyiDecode() {
  38.         this(0);
  39.     }

  40.     public SanyiDecode(final boolean urlSafe) {
  41.         this(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe);
  42.     }
  43.     public SanyiDecode(final int lineLength) {
  44.         this(lineLength, CHUNK_SEPARATOR);
  45.     }

  46.     public SanyiDecode(final int lineLength, final byte[] lineSeparator) {
  47.         this(lineLength, lineSeparator, false);
  48.     }

  49.     public SanyiDecode(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) {
  50.         super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK,
  51.                 lineLength,
  52.                 lineSeparator == null ? 0 : lineSeparator.length);
  53.         
  54.         if (lineSeparator != null) {
  55.             if (containsAlphabetOrPad(lineSeparator)) {
  56.                 final String sep = StringUtils.newStringUtf8(lineSeparator);
  57.                 throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]");
  58.             }
  59.             if (lineLength > 0){ // null line-sep forces no chunking rather than throwing IAE
  60.                 this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length;
  61.                 this.lineSeparator = new byte[lineSeparator.length];
  62.                 System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
  63.             } else {
  64.                 this.encodeSize = BYTES_PER_ENCODED_BLOCK;
  65.                 this.lineSeparator = null;
  66.             }
  67.         } else {
  68.             this.encodeSize = BYTES_PER_ENCODED_BLOCK;
  69.             this.lineSeparator = null;
  70.         }
  71.         this.decodeSize = this.encodeSize - 1;
  72.         this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
  73.     }

  74.     public boolean isUrlSafe() {
  75.         return this.encodeTable == URL_SAFE_ENCODE_TABLE;
  76.     }

  77.     @Override
  78.     void decry(final byte[] in, int inPos, final int inAvail, final Context context) {
  79.         if (context.eof) {
  80.             return;
  81.         }
  82.         if (inAvail < 0) {
  83.             context.eof = true;
  84.         }
  85.         for (int i = 0; i < inAvail; i++) {
  86.             final byte[] buffer = ensureBufferSize(decodeSize, context);
  87.             final byte b = in[inPos++];
  88.             if (b == pad) {
  89.                 // We're done.
  90.                 context.eof = true;
  91.                 break;
  92.             } else {
  93.                 if (b >= 0 && b < DECODE_TABLE.length) {
  94.                     final int result = DECODE_TABLE[b];
  95.                     if (result >= 0) {
  96.                         context.modulus = (context.modulus+1) % BYTES_PER_ENCODED_BLOCK;
  97.                         context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result;
  98.                         if (context.modulus == 0) {
  99.                             buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 16) & MASK_8BITS);
  100.                             buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
  101.                             buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS);
  102.                         }
  103.                     }
  104.                 }
  105.             }
  106.         }

  107.         if (context.eof && context.modulus != 0) {
  108.             final byte[] buffer = ensureBufferSize(decodeSize, context);

  109.           
  110.             switch (context.modulus) {
  111. // case 0 : // impossible, as excluded above
  112.                 case 1 : // 6 bits - ignore entirely
  113.                     // TODO not currently tested; perhaps it is impossible?
  114.                     break;
  115.                 case 2 : // 12 bits = 8 + 4
  116.                     context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits
  117.                     buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
  118.                     break;
  119.                 case 3 : // 18 bits = 8 + 8 + 2
  120.                     context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits
  121.                     buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
  122.                     buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
  123.                     break;
  124.                 default:
  125.                     throw new IllegalStateException("Impossible modulus "+context.modulus);
  126.             }
  127.         }
  128.     }


  129.     public static byte[] decryData(final String dataString) {
  130.         return new SanyiDecode().decode(dataString);
  131.     }

  132.     public static byte[] decryData(final byte[] data) {
  133.         return new SanyiDecode().decode(data);
  134.     }

  135.     public static BigInteger decryInteger(final byte[] pArray) {
  136.         return new BigInteger(1, decryData(pArray));
  137.     }

  138.     @Override
  139.     protected boolean isInAlphabet(final byte octet) {
  140.         return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
  141.     }

  142. }


  143. abstract class SanyiCodec {

  144.     static class Context {

  145.         int ibitWorkArea;

  146.         long lbitWorkArea;

  147.         byte[] buffer;

  148.         int pos;

  149.         int readPos;

  150.         boolean eof;

  151.         int currentLinePos;

  152.         int modulus;

  153.         Context() {
  154.         }

  155.  
  156.         @SuppressWarnings("boxing") // OK to ignore boxing here
  157.         @Override
  158.         public String toString() {
  159.             return String.format("%s[buffer=%s, currentLinePos=%s, eof=%s, ibitWorkArea=%s, lbitWorkArea=%s, " +
  160.                     "modulus=%s, pos=%s, readPos=%s]", this.getClass().getSimpleName(), Arrays.toString(buffer),
  161.                     currentLinePos, eof, ibitWorkArea, lbitWorkArea, modulus, pos, readPos);
  162.         }
  163.     }

  164.  
  165.     static final int EOF = -1;

  166.     public static final int MIME_CHUNK_SIZE = 76;

  167.     public static final int PEM_CHUNK_SIZE = 64;

  168.     private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2;

  169.   
  170.     private static final int DEFAULT_BUFFER_SIZE = 8192;

  171.  
  172.     protected static final int MASK_8BITS = 0xff;

  173.  
  174.     protected static final byte PAD_DEFAULT = '='; // Allow static access to default

  175.  
  176.     @Deprecated
  177.     protected final byte PAD = PAD_DEFAULT; // instance variable just in case it needs to vary later

  178.     protected final byte pad; // instance variable just in case it needs to vary later

  179.     private final int unencodedBlockSize;

  180.     private final int encodedBlockSize;

  181.  
  182.     protected final int lineLength;

  183.  
  184.     private final int chunkSeparatorLength;

  185.   
  186.     protected SanyiCodec(final int unencodedBlockSize, final int encodedBlockSize,
  187.                          final int lineLength, final int chunkSeparatorLength) {
  188.         this(unencodedBlockSize, encodedBlockSize, lineLength, chunkSeparatorLength, PAD_DEFAULT);
  189.     }

  190.     protected SanyiCodec(final int unencodedBlockSize, final int encodedBlockSize,
  191.                          final int lineLength, final int chunkSeparatorLength, final byte pad) {
  192.         this.unencodedBlockSize = unencodedBlockSize;
  193.         this.encodedBlockSize = encodedBlockSize;
  194.         final boolean useChunking = lineLength > 0 && chunkSeparatorLength > 0;
  195.         this.lineLength = useChunking ? (lineLength / encodedBlockSize) * encodedBlockSize : 0;
  196.         this.chunkSeparatorLength = chunkSeparatorLength;

  197.         this.pad = pad;
  198.     }

  199.    
  200.     boolean hasData(final Context context) { // package protected for access from I/O streams
  201.         return context.buffer != null;
  202.     }

  203.    
  204.     int available(final Context context) { // package protected for access from I/O streams
  205.         return context.buffer != null ? context.pos - context.readPos : 0;
  206.     }

  207.    
  208.     protected int getDefaultBufferSize() {
  209.         return DEFAULT_BUFFER_SIZE;
  210.     }

  211.     
  212.     private byte[] resizeBuffer(final Context context) {
  213.         if (context.buffer == null) {
  214.             context.buffer = new byte[getDefaultBufferSize()];
  215.             context.pos = 0;
  216.             context.readPos = 0;
  217.         } else {
  218.             final byte[] b = new byte[context.buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR];
  219.             System.arraycopy(context.buffer, 0, b, 0, context.buffer.length);
  220.             context.buffer = b;
  221.         }
  222.         return context.buffer;
  223.     }

  224.     
  225.     protected byte[] ensureBufferSize(final int size, final Context context){
  226.         if ((context.buffer == null) || (context.buffer.length < context.pos + size)){
  227.             return resizeBuffer(context);
  228.         }
  229.         return context.buffer;
  230.     }

  231.    
  232.     int readResults(final byte[] b, final int bPos, final int bAvail, final Context context) {
  233.         if (context.buffer != null) {
  234.             final int len = Math.min(available(context), bAvail);
  235.             System.arraycopy(context.buffer, context.readPos, b, bPos, len);
  236.             context.readPos += len;
  237.             if (context.readPos >= context.pos) {
  238.                 context.buffer = null; // so hasData() will return false, and this method can return -1
  239.             }
  240.             return len;
  241.         }
  242.         return context.eof ? EOF : 0;
  243.     }

  244.     
  245.     protected static boolean isWhiteSpace(final byte byteToCheck) {
  246.         switch (byteToCheck) {
  247.             case ' ' :
  248.             case '\n' :
  249.             case '\r' :
  250.             case '\t' :
  251.                 return true;
  252.             default :
  253.                 return false;
  254.         }
  255.     }

  256.    
  257.     public Object decode(final Object obj) throws SanyiDecoderException {
  258.         if (obj instanceof byte[]) {
  259.             return decode((byte[]) obj);
  260.         } else if (obj instanceof String) {
  261.             return decode((String) obj);
  262.         } else {
  263.             throw new SanyiDecoderException("Parameter supplied to Base-N decode is not a byte[] or a String");
  264.         }
  265.     }

  266.   
  267.     public byte[] decode(final String pArray) {
  268.         return decode(StringUtils.getBytesUtf8(pArray));
  269.     }

  270.    
  271.     
  272.     public byte[] decode(final byte[] pArray) {
  273.         if (pArray == null || pArray.length == 0) {
  274.             return pArray;
  275.         }
  276.         final Context context = new Context();
  277.         decry(pArray, 0, pArray.length, context);
  278.         decry(pArray, 0, EOF, context); // Notify decoder of EOF.
  279.         final byte[] result = new byte[context.pos];
  280.         readResults(result, 0, result.length, context);
  281.         return result;
  282.     }

  283.     abstract void decry(byte[] pArray, int i, int length, Context context);

  284.     protected abstract boolean isInAlphabet(byte value);

  285.    
  286.     public boolean isInAlphabet(final byte[] arrayOctet, final boolean allowWSPad) {
  287.         for (int i = 0; i < arrayOctet.length; i++) {
  288.             if (!isInAlphabet(arrayOctet[i]) &&
  289.                     (!allowWSPad || (arrayOctet[i] != pad) && !isWhiteSpace(arrayOctet[i]))) {
  290.                 return false;
  291.             }
  292.         }
  293.         return true;
  294.     }

  295.    
  296.     public boolean isInAlphabet(final String basen) {
  297.         return isInAlphabet(StringUtils.getBytesUtf8(basen), true);
  298.     }

  299.   
  300.     protected boolean containsAlphabetOrPad(final byte[] arrayOctet) {
  301.         if (arrayOctet == null) {
  302.             return false;
  303.         }
  304.         for (final byte element : arrayOctet) {
  305.             if (pad == element || isInAlphabet(element)) {
  306.                 return true;
  307.             }
  308.         }
  309.         return false;
  310.     }

  311.     
  312.     public long getEncodedLength(final byte[] pArray) {
  313.         long len = ((pArray.length + unencodedBlockSize-1) / unencodedBlockSize) * (long) encodedBlockSize;
  314.         if (lineLength > 0) { // We're using chunking
  315.             len += ((len + lineLength-1) / lineLength) * chunkSeparatorLength;
  316.         }
  317.         return len;
  318.     }
  319. }


  320. class SanyiDecoderException extends Exception {

  321.     private static final long serialVersionUID = 1L;


  322.     public SanyiDecoderException() {
  323.         super();
  324.     }

  325.  
  326.     public SanyiDecoderException(String message) {
  327.         super(message);
  328.     }


  329.     public SanyiDecoderException(String message, Throwable cause) {
  330.         super(message, cause);
  331.     }

  332.  
  333.     public SanyiDecoderException(Throwable cause) {
  334.         super(cause);
  335.     }
  336. }

  337. class SanyiCode32 extends SanyiCodec {

  338.     private static final int BITS_PER_ENCODED_BYTE = 5;
  339.     private static final int BYTES_PER_ENCODED_BLOCK = 8;
  340.     private static final int BYTES_PER_UNENCODED_BLOCK = 5;

  341.     private static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};

  342.    
  343.     private static final byte[] DECODE_TABLE = {
  344.          // 0 1 2 3 4 5 6 7 8 9 A B C D E F
  345.             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f
  346.             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f
  347.             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 20-2f
  348.             -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, // 30-3f 2-7
  349.             -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40-4f A-N
  350.             15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 50-5a O-Z
  351.     };

  352.     
  353.     private static final byte[] ENCODE_TABLE = {
  354.             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  355.             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
  356.             '2', '3', '4', '5', '6', '7',
  357.     };

  358.     private static final byte[] HEX_DECODE_TABLE = {
  359.          // 0 1 2 3 4 5 6 7 8 9 A B C D E F
  360.             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f
  361.             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f
  362.             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 20-2f
  363.              0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 30-3f 2-7
  364.             -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 40-4f A-N
  365.             25, 26, 27, 28, 29, 30, 31, 32, // 50-57 O-V
  366.     };

  367.     
  368.     private static final byte[] HEX_ENCODE_TABLE = {
  369.             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  370.             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  371.             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  372.     };

  373.   
  374.     private static final int MASK_5BITS = 0x1f;

  375.     
  376.     private final int decodeSize;

  377.    
  378.     private final byte[] decodeTable;

  379.   
  380.     private final int encodeSize;

  381.    
  382.     private final byte[] encodeTable;

  383.    
  384.     private final byte[] lineSeparator;

  385.    
  386.     public SanyiCode32() {
  387.         this(false);
  388.     }

  389.    
  390.     public SanyiCode32(final byte pad) {
  391.         this(false, pad);
  392.     }

  393.    
  394.     public SanyiCode32(final boolean useHex) {
  395.         this(0, null, useHex, PAD_DEFAULT);
  396.     }

  397.     
  398.     public SanyiCode32(final boolean useHex, final byte pad) {
  399.         this(0, null, useHex, pad);
  400.     }

  401.    
  402.     public SanyiCode32(final int lineLength) {
  403.         this(lineLength, CHUNK_SEPARATOR);
  404.     }

  405.     public SanyiCode32(final int lineLength, final byte[] lineSeparator) {
  406.         this(lineLength, lineSeparator, false, PAD_DEFAULT);
  407.     }

  408.     
  409.     public SanyiCode32(final int lineLength, final byte[] lineSeparator, final boolean useHex) {
  410.         this(lineLength, lineSeparator, useHex, PAD_DEFAULT);
  411.     }

  412.     
  413.     public SanyiCode32(final int lineLength, final byte[] lineSeparator, final boolean useHex, final byte pad) {
  414.         super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength,
  415.                 lineSeparator == null ? 0 : lineSeparator.length, pad);
  416.         if (useHex) {
  417.             this.encodeTable = HEX_ENCODE_TABLE;
  418.             this.decodeTable = HEX_DECODE_TABLE;
  419.         } else {
  420.             this.encodeTable = ENCODE_TABLE;
  421.             this.decodeTable = DECODE_TABLE;
  422.         }
  423.         if (lineLength > 0) {
  424.             if (lineSeparator == null) {
  425.                 throw new IllegalArgumentException("lineLength " + lineLength + " > 0, but lineSeparator is null");
  426.             }
  427.             // Must be done after initializing the tables
  428.             if (containsAlphabetOrPad(lineSeparator)) {
  429.                 final String sep = StringUtils.newStringUtf8(lineSeparator);
  430.                 throw new IllegalArgumentException("lineSeparator must not contain Base32 characters: [" + sep + "]");
  431.             }
  432.             this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length;
  433.             this.lineSeparator = new byte[lineSeparator.length];
  434.             System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
  435.         } else {
  436.             this.encodeSize = BYTES_PER_ENCODED_BLOCK;
  437.             this.lineSeparator = null;
  438.         }
  439.         this.decodeSize = this.encodeSize - 1;

  440.         if (isInAlphabet(pad) || isWhiteSpace(pad)) {
  441.             throw new IllegalArgumentException("pad must not be in alphabet or whitespace");
  442.         }
  443.     }

  444.   
  445.     @Override
  446.     void decry(final byte[] in, int inPos, final int inAvail, final Context context) {
  447.         // package protected for access from I/O streams

  448.         if (context.eof) {
  449.             return;
  450.         }
  451.         if (inAvail < 0) {
  452.             context.eof = true;
  453.         }
  454.         for (int i = 0; i < inAvail; i++) {
  455.             final byte b = in[inPos++];
  456.             if (b == pad) {
  457.                 // We're done.
  458.                 context.eof = true;
  459.                 break;
  460.             } else {
  461.                 final byte[] buffer = ensureBufferSize(decodeSize, context);
  462.                 if (b >= 0 && b < this.decodeTable.length) {
  463.                     final int result = this.decodeTable[b];
  464.                     if (result >= 0) {
  465.                         context.modulus = (context.modulus+1) % BYTES_PER_ENCODED_BLOCK;
  466.                         // collect decoded bytes
  467.                         context.lbitWorkArea = (context.lbitWorkArea << BITS_PER_ENCODED_BYTE) + result;
  468.                         if (context.modulus == 0) { // we can output the 5 bytes
  469.                             buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 32) & MASK_8BITS);
  470.                             buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 24) & MASK_8BITS);
  471.                             buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 16) & MASK_8BITS);
  472.                             buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 8) & MASK_8BITS);
  473.                             buffer[context.pos++] = (byte) (context.lbitWorkArea & MASK_8BITS);
  474.                         }
  475.                     }
  476.                 }
  477.             }
  478.         }

  479.         if (context.eof && context.modulus >= 2) { // if modulus < 2, nothing to do
  480.             final byte[] buffer = ensureBufferSize(decodeSize, context);

  481.             // we ignore partial bytes, i.e. only multiples of 8 count
  482.             switch (context.modulus) {
  483.                 case 2 : // 10 bits, drop 2 and output one byte
  484.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 2) & MASK_8BITS);
  485.                     break;
  486.                 case 3 : // 15 bits, drop 7 and output 1 byte
  487.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 7) & MASK_8BITS);
  488.                     break;
  489.                 case 4 : // 20 bits = 2*8 + 4
  490.                     context.lbitWorkArea = context.lbitWorkArea >> 4; // drop 4 bits
  491.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 8) & MASK_8BITS);
  492.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea) & MASK_8BITS);
  493.                     break;
  494.                 case 5 : // 25bits = 3*8 + 1
  495.                     context.lbitWorkArea = context.lbitWorkArea >> 1;
  496.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 16) & MASK_8BITS);
  497.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 8) & MASK_8BITS);
  498.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea) & MASK_8BITS);
  499.                     break;
  500.                 case 6 : // 30bits = 3*8 + 6
  501.                     context.lbitWorkArea = context.lbitWorkArea >> 6;
  502.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 16) & MASK_8BITS);
  503.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 8) & MASK_8BITS);
  504.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea) & MASK_8BITS);
  505.                     break;
  506.                 case 7 : // 35 = 4*8 +3
  507.                     context.lbitWorkArea = context.lbitWorkArea >> 3;
  508.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 24) & MASK_8BITS);
  509.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 16) & MASK_8BITS);
  510.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea >> 8) & MASK_8BITS);
  511.                     buffer[context.pos++] = (byte) ((context.lbitWorkArea) & MASK_8BITS);
  512.                     break;
  513.                 default:
  514.                     // modulus can be 0-7, and we excluded 0,1 already
  515.                     throw new IllegalStateException("Impossible modulus "+context.modulus);
  516.             }
  517.         }
  518.     }


  519.     @Override
  520.     public boolean isInAlphabet(final byte octet) {
  521.         return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
  522.     }
  523. }


  524. class SanyiCode64 extends SanyiCodec {

  525.     private static final int BITS_PER_ENCODED_BYTE = 6;
  526.     private static final int BYTES_PER_UNENCODED_BLOCK = 3;
  527.     private static final int BYTES_PER_ENCODED_BLOCK = 4;

  528.    
  529.     static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};

  530.     
  531.     private static final byte[] STANDARD_ENCODE_TABLE = {
  532.             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  533.             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
  534.             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  535.             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
  536.             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
  537.     };

  538.     
  539.     private static final byte[] URL_SAFE_ENCODE_TABLE = {
  540.             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  541.             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
  542.             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  543.             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
  544.             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
  545.     };

  546.     private static final byte[] DECODE_TABLE = {
  547.             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  548.             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  549.             -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54,
  550.             55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
  551.             5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
  552.             24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
  553.             35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
  554.     };

  555.     
  556.     private static final int MASK_6BITS = 0x3f;

  557.    
  558.     private final byte[] encodeTable;

  559.     
  560.     private final byte[] decodeTable = DECODE_TABLE;

  561.    
  562.     private final byte[] lineSeparator;

  563.   
  564.     private final int decodeSize;

  565.    
  566.     private final int encodeSize;

  567.     
  568.     public SanyiCode64() {
  569.         this(0);
  570.     }

  571.    
  572.     public SanyiCode64(final boolean urlSafe) {
  573.         this(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe);
  574.     }

  575.     
  576.     public SanyiCode64(final int lineLength) {
  577.         this(lineLength, CHUNK_SEPARATOR);
  578.     }

  579.     
  580.     public SanyiCode64(final int lineLength, final byte[] lineSeparator) {
  581.         this(lineLength, lineSeparator, false);
  582.     }

  583.     
  584.     public SanyiCode64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) {
  585.         super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK,
  586.                 lineLength,
  587.                 lineSeparator == null ? 0 : lineSeparator.length);
  588.         // TODO could be simplified if there is no requirement to reject invalid line sep when length <=0
  589.         // @see test case Base64Test.testConstructors()
  590.         if (lineSeparator != null) {
  591.             if (containsAlphabetOrPad(lineSeparator)) {
  592.                 final String sep = StringUtils.newStringUtf8(lineSeparator);
  593.                 throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]");
  594.             }
  595.             if (lineLength > 0){ // null line-sep forces no chunking rather than throwing IAE
  596.                 this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length;
  597.                 this.lineSeparator = new byte[lineSeparator.length];
  598.                 System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
  599.             } else {
  600.                 this.encodeSize = BYTES_PER_ENCODED_BLOCK;
  601.                 this.lineSeparator = null;
  602.             }
  603.         } else {
  604.             this.encodeSize = BYTES_PER_ENCODED_BLOCK;
  605.             this.lineSeparator = null;
  606.         }
  607.         this.decodeSize = this.encodeSize - 1;
  608.         this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
  609.     }

  610.     
  611.     public boolean isUrlSafe() {
  612.         return this.encodeTable == URL_SAFE_ENCODE_TABLE;
  613.     }

  614.   
  615.     @Override
  616.     void decry(final byte[] in, int inPos, final int inAvail, final Context context) {
  617.         if (context.eof) {
  618.             return;
  619.         }
  620.         if (inAvail < 0) {
  621.             context.eof = true;
  622.         }
  623.         for (int i = 0; i < inAvail; i++) {
  624.             final byte[] buffer = ensureBufferSize(decodeSize, context);
  625.             final byte b = in[inPos++];
  626.             if (b == pad) {
  627.                 // We're done.
  628.                 context.eof = true;
  629.                 break;
  630.             } else {
  631.                 if (b >= 0 && b < DECODE_TABLE.length) {
  632.                     final int result = DECODE_TABLE[b];
  633.                     if (result >= 0) {
  634.                         context.modulus = (context.modulus+1) % BYTES_PER_ENCODED_BLOCK;
  635.                         context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result;
  636.                         if (context.modulus == 0) {
  637.                             buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 16) & MASK_8BITS);
  638.                             buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
  639.                             buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS);
  640.                         }
  641.                     }
  642.                 }
  643.             }
  644.         }

  645.         // Two forms of EOF as far as base64 decoder is concerned: actual
  646.         // EOF (-1) and first time '=' character is encountered in stream.
  647.         // This approach makes the '=' padding characters completely optional.
  648.         if (context.eof && context.modulus != 0) {
  649.             final byte[] buffer = ensureBufferSize(decodeSize, context);

  650.             // We have some spare bits remaining
  651.             // Output all whole multiples of 8 bits and ignore the rest
  652.             switch (context.modulus) {
  653. // case 0 : // impossible, as excluded above
  654.                 case 1 : // 6 bits - ignore entirely
  655.                     // TODO not currently tested; perhaps it is impossible?
  656.                     break;
  657.                 case 2 : // 12 bits = 8 + 4
  658.                     context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits
  659.                     buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
  660.                     break;
  661.                 case 3 : // 18 bits = 8 + 8 + 2
  662.                     context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits
  663.                     buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
  664.                     buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
  665.                     break;
  666.                 default:
  667.                     throw new IllegalStateException("Impossible modulus "+context.modulus);
  668.             }
  669.         }
  670.     }

  671.     
  672.     @Deprecated
  673.     public static boolean isArrayByteBase64(final byte[] arrayOctet) {
  674.         return isCode(arrayOctet);
  675.     }

  676.    
  677.     public static boolean isCode(final byte octet) {
  678.         return octet == PAD_DEFAULT || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1);
  679.     }

  680.     
  681.     public static boolean isCode(final String base64) {
  682.         return isCode(StringUtils.getBytesUtf8(base64));
  683.     }

  684.    
  685.     public static boolean isCode(final byte[] arrayOctet) {
  686.         for (int i = 0; i < arrayOctet.length; i++) {
  687.             if (!isCode(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) {
  688.                 return false;
  689.             }
  690.         }
  691.         return true;
  692.     }

  693.     public static byte[] decryData(final String dataring) {
  694.         return new SanyiCode64().decode(dataring);
  695.     }

  696.    
  697.     public static byte[] decryData(final byte[] data) {
  698.         return new SanyiCode64().decode(data);
  699.     }

  700.     public static BigInteger decryInteger(final byte[] pArray) {
  701.         return new BigInteger(1, decryData(pArray));
  702.     }

  703.     static byte[] toIntegerBytes(final BigInteger bigInt) {
  704.         int bitlen = bigInt.bitLength();
  705.         // round bitlen
  706.         bitlen = ((bitlen + 7) >> 3) << 3;
  707.         final byte[] bigBytes = bigInt.toByteArray();

  708.         if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) {
  709.             return bigBytes;
  710.         }
  711.         // set up params for copying everything but sign bit
  712.         int startSrc = 0;
  713.         int len = bigBytes.length;

  714.         // if bigInt is exactly byte-aligned, just skip signbit in copy
  715.         if ((bigInt.bitLength() % 8) == 0) {
  716.             startSrc = 1;
  717.             len--;
  718.         }
  719.         final int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec
  720.         final byte[] resizedBytes = new byte[bitlen / 8];
  721.         System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len);
  722.         return resizedBytes;
  723.     }

  724.     
  725.     @Override
  726.     protected boolean isInAlphabet(final byte octet) {
  727.         return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
  728.     }

  729. }

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31347383/viewspace-2122413/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/31347383/viewspace-2122413/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值