SignatureEncoder.java

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

import com.lucimber.dbus.type.DBusByte;
import com.lucimber.dbus.type.DBusSignature;
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;

/**
 * An encoder which encodes a signature to the D-Bus marshalling format using ByteBuffer.
 *
 * @see Encoder
 * @see DBusSignature
 */
public final class SignatureEncoder implements Encoder<DBusSignature, ByteBuffer> {

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

    private static final int NUL_TERMINATOR_LENGTH = 1;

    @Override
    public EncoderResult<ByteBuffer> encode(DBusSignature signature, int offset)
            throws EncoderException {
        Objects.requireNonNull(signature, "signature must not be null");

        try {
            String value = signature.toString();
            byte[] signatureBytes = value.getBytes(StandardCharsets.UTF_8);
            int length = signatureBytes.length;

            // Encode the length as a single byte
            DBusByte size = DBusByte.valueOf((byte) length);
            Encoder<DBusByte, ByteBuffer> byteEncoder = new ByteEncoder();
            EncoderResult<ByteBuffer> lengthResult = byteEncoder.encode(size, offset);
            ByteBuffer lengthBuffer = lengthResult.getBuffer();

            // Allocate the complete buffer
            int totalSize = lengthResult.getProducedBytes() + length + NUL_TERMINATOR_LENGTH;
            ByteBuffer buffer = ByteBuffer.allocate(totalSize);
            buffer.put(lengthBuffer);
            buffer.put(signatureBytes);
            buffer.put((byte) 0); // NUL terminator
            buffer.flip();

            EncoderResult<ByteBuffer> result = new EncoderResultImpl<>(totalSize, buffer);

            LOGGER.debug(
                    LoggerUtils.MARSHALLING,
                    "SIGNATURE: {}; Offset: {}; Padding: {}; Produced bytes: {};",
                    signature,
                    offset,
                    0,
                    totalSize);

            return result;
        } catch (Exception ex) {
            throw new EncoderException("Could not encode SIGNATURE.", ex);
        }
    }
}