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

com.yahoo.slime.BinaryDecoder Maven / Gradle / Ivy

// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.slime;


import static com.yahoo.slime.BinaryFormat.decode_double;
import static com.yahoo.slime.BinaryFormat.decode_meta;
import static com.yahoo.slime.BinaryFormat.decode_type;
import static com.yahoo.slime.BinaryFormat.decode_zigzag;

final class BinaryDecoder {

    BufferedInput in;

    private final SlimeInserter slimeInserter = new SlimeInserter(null);
    private final ArrayInserter arrayInserter = new ArrayInserter(null);
    private final ObjectSymbolInserter objectInserter = new ObjectSymbolInserter(null, 0);

    public BinaryDecoder() {}

    public Slime decode(byte[] bytes) {
        return decode(bytes, 0, bytes.length);
    }
    public Slime decode(byte[] bytes, int offset, int length) {
        Slime slime = new Slime();
        in = new BufferedInput(bytes, offset, length);
        decodeSymbolTable(in, slime.symbolTable());
        decodeValue(slimeInserter.adjust(slime));
        if (in.failed()) {
            slime.wrap("partial_result");
            slime.get().setData("offending_input", in.getOffending());
            slime.get().setString("error_message", in.getErrorMessage());
        }
        return slime;
    }

    long read_bytes_le(int bytes) {
        long value = 0;
        int shift = 0;
        for (int i = 0; i < bytes; ++i) {
            long b = in.getByte();
            value |= (b & 0xff) << shift;
            shift += 8;
        }
        return value;
    }

    long read_bytes_be(int bytes) {
        long value = 0;
        int shift = 56;
        for (int i = 0; i < bytes; ++i) {
            long b = in.getByte();
            value |= (b & 0xff) << shift;
            shift -= 8;
        }
        return value;
    }

    Cursor decodeNIX(Inserter inserter) {
        return inserter.insertNIX();
    }

    Cursor decodeBOOL(Inserter inserter, int meta) {
        return inserter.insertBOOL(meta != 0);
    }

    Cursor decodeLONG(Inserter inserter, int meta) {
        long encoded = read_bytes_le(meta);
        return inserter.insertLONG(decode_zigzag(encoded));
    }

    Cursor decodeDOUBLE(Inserter inserter, int meta) {
        long encoded = read_bytes_be(meta);
        return inserter.insertDOUBLE(decode_double(encoded));
    }

    Cursor decodeSTRING(Inserter inserter, int meta) {
        int size = in.read_size(meta);
        byte[] image = in.getBytes(size);
        return inserter.insertSTRING(image);
    }

    Cursor decodeDATA(Inserter inserter, int meta) {
        int size = in.read_size(meta);
        byte[] image = in.getBytes(size);
        return inserter.insertDATA(image);
    }

    Cursor decodeARRAY(Inserter inserter, int meta) {
        Cursor cursor = inserter.insertARRAY();
        int size = in.read_size(meta);
        for (int i = 0; i < size; ++i) {
            decodeValue(arrayInserter.adjust(cursor));
        }
        return cursor;
    }

    Cursor decodeOBJECT(Inserter inserter, int meta) {
        Cursor cursor = inserter.insertOBJECT();
        int size = in.read_size(meta);
        for (int i = 0; i < size; ++i) {
            int symbol = in.read_cmpr_int();
            decodeValue(objectInserter.adjust(cursor, symbol));
        }
        return cursor;
    }

    Cursor decodeValue(Inserter inserter, Type type, int meta) {
        switch (type) {
        case NIX:     return decodeNIX(inserter);
        case BOOL:    return decodeBOOL(inserter, meta);
        case LONG:    return decodeLONG(inserter, meta);
        case DOUBLE:  return decodeDOUBLE(inserter, meta);
        case STRING:  return decodeSTRING(inserter, meta);
        case DATA:    return decodeDATA(inserter, meta);
        case ARRAY:   return decodeARRAY(inserter, meta);
        case OBJECT:  return decodeOBJECT(inserter, meta);
        }
        assert false : "should not be reached";
        return null;
    }

    void decodeValue(Inserter inserter) {
        byte b = in.getByte();
        Cursor cursor = decodeValue(inserter, decode_type(b), decode_meta(b));
        if (!cursor.valid()) {
            in.fail("failed to decode value");
        }
    }

    static void decodeSymbolTable(BufferedInput input, SymbolTable names) {
        int numSymbols = input.read_cmpr_int();
        final byte[] backing = input.getBacking();
        for (int i = 0; i < numSymbols; ++i) {
            int size = input.read_cmpr_int();
            int offset = input.getPosition();
            input.skip(size);
            int symbol = names.insert(Utf8Codec.decode(backing, offset, size));
            if (symbol != i) {
                input.fail("duplicate symbols in symbol table");
                return;
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy