All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ome.codecs.Base64Codec Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * Image encoding and decoding routines.
 * %%
 * Copyright (C) 2005 - 2017 Open Microscopy Environment:
 *   - Board of Regents of the University of Wisconsin-Madison
 *   - Glencoe Software, Inc.
 *   - University of Dundee
 * %%
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * #L%
 */

package ome.codecs;

import java.io.IOException;

import loci.common.RandomAccessInputStream;
import ome.codecs.CodecException;

/**
 * Implements encoding (compress) and decoding (decompress) methods
 * for Base64.  This code was adapted from the Jakarta Commons Codec source,
 * http://jakarta.apache.org/commons
 *
 * @author Melissa Linkert melissa at glencoesoftware.com
 */
public class Base64Codec extends BaseCodec {

  // Base64 alphabet and codes

  private static final byte PAD = (byte) '=';

  private static byte[] base64Alphabet = new byte[255];
  private static byte[] lookupBase64Alphabet = new byte[255];

  static {
    for (int i=0; i<255; i++) {
      base64Alphabet[i] = (byte) -1;
    }
    for (int i = 'Z'; i >= 'A'; i--) {
      base64Alphabet[i] = (byte) (i - 'A');
      lookupBase64Alphabet[i - 'A'] = (byte) i;
    }
    for (int i = 'z'; i >= 'a'; i--) {
      base64Alphabet[i] = (byte) (i - 'a' + 26);
      lookupBase64Alphabet[i - 'a' + 26] = (byte) i;
    }
    for (int i = '9'; i >= '0'; i--) {
      base64Alphabet[i] = (byte) (i - '0' + 52);
      lookupBase64Alphabet[i - '0' + 52] = (byte) i;
    }

    base64Alphabet['+'] = 62;
    base64Alphabet['/'] = 63;

    lookupBase64Alphabet[62] = (byte) '+';
    lookupBase64Alphabet[63] = (byte) '/';
  }

  /* @see Codec#compress(byte[], CodecOptions) */
  @Override
  public byte[] compress(byte[] input, CodecOptions options)
    throws CodecException
  {
    if (input == null || input.length == 0) return null;
    int dataBits = input.length * 8;
    int fewerThan24 = dataBits % 24;
    int numTriples = dataBits / 24;
    ByteVector encoded = new ByteVector();

    byte k, l, b1, b2, b3;

    int dataIndex = 0;

    for (int i=0; i> 2) :
        (byte) ((b1) >> 2 ^ 0xc0);
      byte v2 = ((b2 & -128) == 0) ? (byte) (b2 >> 4) :
        (byte) ((b2) >> 4 ^ 0xf0);
      byte v3 = ((b3 & -128) == 0) ? (byte) (b3 >> 6) :
        (byte) ((b3) >> 6 ^ 0xfc);

      encoded.add(lookupBase64Alphabet[v1]);
      encoded.add(lookupBase64Alphabet[v2 | (k << 4)]);
      encoded.add(lookupBase64Alphabet[(l << 2) | v3]);
      encoded.add(lookupBase64Alphabet[b3 & 0x3f]);
    }

    dataIndex = numTriples * 3;

    if (fewerThan24 == 8) {
      b1 = input[dataIndex];
      k = (byte) (b1 & 0x03);
      byte v = ((b1 & -128) == 0) ? (byte) (b1 >> 2) :
        (byte) ((b1) >> 2 ^ 0xc0);
      encoded.add(lookupBase64Alphabet[v]);
      encoded.add(lookupBase64Alphabet[k << 4]);
      encoded.add(PAD);
      encoded.add(PAD);
    }
    else if (fewerThan24 == 16) {
      b1 = input[dataIndex];
      b2 = input[dataIndex + 1];
      l = (byte) (b2 & 0x0f);
      k = (byte) (b1 & 0x03);

      byte v1 = ((b1 & -128) == 0) ? (byte) (b1 >> 2) :
        (byte) ((b1) >> 2 ^ 0xc0);
      byte v2 = ((b2 & -128) == 0) ? (byte) (b2 >> 4) :
        (byte) ((b2) >> 4 ^ 0xf0);

      encoded.add(lookupBase64Alphabet[v1]);
      encoded.add(lookupBase64Alphabet[v2 | (k << 4)]);
      encoded.add(lookupBase64Alphabet[l << 2]);
      encoded.add(PAD);
    }

    return encoded.toByteArray();
  }

  /* @see Codec#decompress(RandomAccessInputStream, CodecOptions) */
  @Override
  public byte[] decompress(RandomAccessInputStream in, CodecOptions options)
    throws CodecException, IOException
  {
    if (in == null)
      throw new IllegalArgumentException("No data to decompress.");
    if (in.length() == 0) return new byte[0];

    byte b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;

    ByteVector decodedData = new ByteVector();

    byte[] block = new byte[8192];
    int nRead = in.read(block);
    int p = 0;
    byte b1 = base64Alphabet[block[p++]];
    byte b2 = base64Alphabet[block[p++]];

    while (b1 != -1 && b2 != -1 &&
      (in.getFilePointer() - nRead + p < in.length()))
    {
      marker0 = block[p++];
      marker1 = block[p++];

      if (p == block.length) {
        nRead = in.read(block);
        p = 0;
      }

      decodedData.add((byte) (b1 << 2 | b2 >> 4));
      if (marker0 != PAD && marker1 != PAD) {
        b3 = base64Alphabet[marker0];
        b4 = base64Alphabet[marker1];

        decodedData.add((byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)));
        decodedData.add((byte) (b3 << 6 | b4));
      }
      else if (marker0 != PAD && marker1 == PAD) {
        b3 = base64Alphabet[marker0];

        decodedData.add((byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)));
      }
      if (p >= nRead && in.getFilePointer() >= in.length()) break;
      b1 = base64Alphabet[block[p++]];
      b2 = base64Alphabet[block[p++]];
    }
    return decodedData.toByteArray();
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy