Package erjang

Source Code of erjang.CharCollector$DecodingException

/**
* This file is part of Erjang - A JVM-based Erlang VM
*
* Copyright (c) 2010 by Trifork
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/

package erjang;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.CharBuffer;
import java.nio.ByteBuffer;

/** Used by the unicode BIFs characters_to_binary/2 and characters_to_list/2.
*/
public class CharCollector {
  public static ByteBuffer EMPTY = ByteBuffer.wrap(new byte[0]);
  public static int BUF_SIZE = 20486;

  CharsetDecoder decoder;
  CharBuffer buffer;
  Appendable output;
  boolean dirtyDecoder = false;

  public CharCollector(Charset charset, Appendable output) {
    buffer = CharBuffer.allocate(BUF_SIZE);
    this.output = output;
    this.decoder = charset.newDecoder();
    this.decoder.reset();
  }

  public ESeq addInteger(int value, ESeq rest) throws IOException, DecodingException {
   
    if (rest != ERT.NIL) {
      return rest.cons(ERT.box(value));
    }

    if (dirtyDecoder)
      try { flushDecoder(); }
      catch (PartialDecodingException e) {
        // Incomplete binary was followed by an integer...
        // Convert exception.
        throw new DecodingException();
      }
    char c = (char)value;
    if (c != value || !Character.isDefined(value)) fail(new DecodingException());

    if (! buffer.hasRemaining())
      flushBuffer(); /* Or write to output directly?   Provided that we
              * flush the buffer when we do the decoder. */
    buffer.put(c);
   
    return rest;
  }

  /** Add a byte array, interpreted as a list of integers.
   *  Equivalent to (but faster than) calling add(int) for each of
   *  the elements.
   * @return
   @throws PartialDecodingException if these integers follow an
   *  incomplete binary.
   */
  public ESeq addIntegers(byte[] data, int offset, int length, ESeq rest) throws IOException, PartialDecodingException {
   
    if (rest != ERT.NIL) {
      return rest.cons(EBinary.make(data, offset, length, 0));
    }
   
    if (length==0) return rest;
    if (dirtyDecoder) flushDecoder();
    while (length > 0) {
      int free = buffer.remaining();
      while (length > 0 && free > 0) {
        char c = (char)(data[offset] & 0xFF);
        buffer.put(c);
        offset++; length--; free--; // Could be smarter.
      }
      if (free==0) flushBuffer();
    }
    return rest;
  }

  /** Add a byte array, interpreted as a binary to be decoded.
   * @param rest TODO
   * @return TODO*/
  public ESeq addBinary(byte[] data, int offset, int length, ESeq rest) throws IOException, PartialDecodingException {
    if (rest != ERT.NIL) {
      return rest.cons(EBinary.make(data, offset, length, 0));
    }
    return addBinary(ByteBuffer.wrap(data, offset, length), false, rest);
  }

  public ESeq addBinary(ByteBuffer data, boolean endOfInput, ESeq rest)
    throws IOException, PartialDecodingException
  {
    if (rest != ERT.NIL) {
      return rest.cons(EBinary.make(data));
    }
   
    CoderResult res;
    do {
      res = decoder.decode(data, buffer, endOfInput);
      if (!handle(res))
        fail(new PartialDecodingException(data.position()));
    } while (res == CoderResult.OVERFLOW);
   
    if (data.hasRemaining()) {
      if (!endOfInput) {
        decoder.decode(ByteBuffer.wrap(new byte[0]), buffer, true);
        // flush the decoder ...
        // decoder.flush(buffer);
      }
      return rest.cons(EBinary.make(data));
    }
    // The decoder may have left some data. Save that in some fashion...
    dirtyDecoder = true;
    return rest;
  }

  protected boolean handle(CoderResult res) throws IOException {
    if (res == CoderResult.UNDERFLOW) {
      return true;
    } else if (res == CoderResult.OVERFLOW) {
      flushBuffer();
      return true;
    } else return false;
  }

  public void end() throws IOException, PartialDecodingException {
    flushDecoder();
    flushBuffer();
  }

  protected void fail(DecodingException e) throws DecodingException, IOException {
    flushBuffer();
    throw e;
  }
  protected void fail(PartialDecodingException e) throws PartialDecodingException, IOException {
    flushBuffer();
    throw e;
  }

  protected void flushDecoder() throws IOException,PartialDecodingException {
    addBinary(EMPTY, true, ERT.NIL);
    decoder.flush(buffer);
    decoder.reset();
    dirtyDecoder = false;
  }

  protected void flushBuffer() throws IOException {
    buffer.flip();
    output.append(buffer);
  }

  @SuppressWarnings("serial")
  public static class DecodingException extends Exception { }

  @SuppressWarnings("serial")
  public static class PartialDecodingException extends Exception {
    public final int inputPos;
    public PartialDecodingException(int inputPos) {
      this.inputPos = inputPos;
    }
  }

   @SuppressWarnings("serial")
  public static class InvalidElementException extends Exception { }

  @SuppressWarnings("serial")
  public static class CollectingException extends Exception {
    public final EObject restOfInput;
    public CollectingException(EObject restOfInput) {
      this.restOfInput = restOfInput;
    }
  }

  /**
   * @param data
   * @param off
   * @param length
   * @throws PartialDecodingException
   * @throws IOException
   */
  public ESeq addIntegers(char[] data, int offset, int length, ESeq rest) throws IOException, PartialDecodingException {
    if (length==0) return rest;
    if (dirtyDecoder) flushDecoder();
    while (length > 0) {
      int free = buffer.remaining();
      while (length > 0 && free > 0) {
        char c = (char)(data[offset] & 0xFFFF);
        buffer.put(c);
        offset++; length--; free--; // Could be smarter.
      }
      if (free==0) flushBuffer();
    }
    return rest;
  }

}
TOP

Related Classes of erjang.CharCollector$DecodingException

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.