SignatureDecoder.java

/*
 * SPDX-FileCopyrightText: 2023-2025 Lucimber UG
 * SPDX-License-Identifier: Apache-2.0
 */
package com.lucimber.dbus.codec.decoder;

import com.lucimber.dbus.type.DBusSignature;
import com.lucimber.dbus.type.Type;
import com.lucimber.dbus.util.LoggerUtils;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A decoder which unmarshals a signature from the byte stream format used by D-Bus.
 *
 * @see Decoder
 * @see DBusSignature
 */
public final class SignatureDecoder implements Decoder<ByteBuffer, DBusSignature> {

    private static final Logger LOGGER = LoggerFactory.getLogger(SignatureDecoder.class);

    @Override
    public DecoderResult<DBusSignature> decode(ByteBuffer buffer, int offset)
            throws DecoderException {
        Objects.requireNonNull(buffer, "buffer must not be null");

        try {
            int consumedBytes = 0;

            int padding = DecoderUtils.skipPadding(buffer, offset, Type.SIGNATURE);
            consumedBytes += padding;

            // Read 1-byte length prefix
            byte lenByte = buffer.get();
            consumedBytes += 1;
            int length = Byte.toUnsignedInt(lenByte);

            // Read `length` bytes of UTF-8 data
            byte[] bytes = new byte[length];
            buffer.get(bytes);
            consumedBytes += length;

            // Read 1-byte nul terminator (must be 0)
            byte nul = buffer.get();
            consumedBytes += 1;
            if (nul != 0) {
                throw new Exception("Expected nul-terminator after signature bytes.");
            }

            String sigStr = new String(bytes, StandardCharsets.UTF_8);
            DBusSignature signature = DBusSignature.valueOf(sigStr);
            DecoderResult<DBusSignature> result = new DecoderResultImpl<>(consumedBytes, signature);

            LOGGER.debug(
                    LoggerUtils.MARSHALLING,
                    "SIGNATURE: {}; Offset: {}; Padding: {}; Consumed bytes: {};",
                    signature,
                    offset,
                    padding,
                    consumedBytes);

            return result;
        } catch (Exception e) {
            throw new DecoderException("Could not decode SIGNATURE.", e);
        }
    }
}