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

com.github.davidmoten.rx.internal.operators.TransformerDecode Maven / Gradle / Ivy

package com.github.davidmoten.rx.internal.operators;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;

import com.github.davidmoten.rx.Transformers;

import rx.Observable.Transformer;
import rx.Subscriber;
import rx.functions.Func0;
import rx.functions.Func2;
import rx.functions.Func3;

public final class TransformerDecode {

    public static Transformer decode(final CharsetDecoder decoder) {
        Func0 initialState = new Func0() {

            @Override
            public ByteBuffer call() {
                return null;
            }
        };
        Func3, ByteBuffer> transition = new Func3, ByteBuffer>() {

            @Override
            public ByteBuffer call(ByteBuffer last, byte[] next, Subscriber o) {
                Result result = process(next, last, false, decoder, o);
                return result.leftOver;
            }
        };
        Func2, Boolean> completion = new Func2, Boolean>() {

            @Override
            public Boolean call(ByteBuffer last, Subscriber subscriber) {
                return process(null, last, true, decoder, subscriber).canEmitFurther;
            }
        };

        return Transformers.stateMachine(initialState, transition, completion);
    }

    private static final class Result {
        final ByteBuffer leftOver;
        final boolean canEmitFurther;

        Result(ByteBuffer leftOver, boolean canEmitFurther) {
            this.leftOver = leftOver;
            this.canEmitFurther = canEmitFurther;
        }

    }

    public static Result process(byte[] next, ByteBuffer last, boolean endOfInput,
            CharsetDecoder decoder, Subscriber o) {
        if (o.isUnsubscribed())
            return new Result(null, false);

        ByteBuffer bb;
        if (last != null) {
            if (next != null) {
                // merge leftover in front of the next bytes
                bb = ByteBuffer.allocate(last.remaining() + next.length);
                bb.put(last);
                bb.put(next);
                bb.flip();
            } else { // next == null
                bb = last;
            }
        } else { // last == null
            if (next != null) {
                bb = ByteBuffer.wrap(next);
            } else { // next == null
                return new Result(null, true);
            }
        }

        CharBuffer cb = CharBuffer.allocate((int) (bb.limit() * decoder.averageCharsPerByte()));
        CoderResult cr = decoder.decode(bb, cb, endOfInput);
        cb.flip();

        if (cr.isError()) {
            try {
                cr.throwException();
            } catch (CharacterCodingException e) {
                o.onError(e);
                return new Result(null, false);
            }
        }

        ByteBuffer leftOver;
        if (bb.remaining() > 0) {
            leftOver = bb;
        } else {
            leftOver = null;
        }

        String string = cb.toString();
        if (!string.isEmpty())
            o.onNext(string);

        return new Result(leftOver, true);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy