0

最初のビット(BigEndian)がPreonを使用して別のバイトが続いているかどうかを示す、可変長のバイトシーケンスをどのように解析しますか?

    byte[] bytecode = new byte[] {
            (byte) 0xf2, (byte) 0xbf, (byte) 0xbf, (byte) 0xbf, (byte) 0x50
    };

ノート

  • 次のビットが最終ペイロードで破棄されることを示す最初のビット
  • この投稿に使用されたPreonのバージョンは1.1でした

結果バイト(10進数)

{114、63、63、63、80}

すでに試しました

@BoundList + @Choices(条件付き)

Limbo exp langはメソッド呼び出しをサポートしていないため、ストリームの終わりを検出できません(前のブロックには符号1が必要で、現在のブロックは最後である必要があります。つまり、符号は0である必要があります)

@Ifを使用した再帰的アプローチ

public static class Entry {

    @BoundNumber(size = "1", byteOrder = ByteOrder.BigEndian)
    private byte hasNext;

    @BoundNumber(size = "7", byteOrder = ByteOrder.BigEndian)
    private byte payload;

    @If("hasNext > 0")
    @BoundNumber(size = "1", byteOrder = ByteOrder.BigEndian)
    private byte hasNext1;

    @If("hasNext > 0")
    @BoundNumber(size = "7", byteOrder = ByteOrder.BigEndian)
    private byte payload1;

    @If("hasNext1 > 0")
    @BoundObject
    private Entry nextEntry;

    @Override
    public String toString() {
        return hasNext > 0 ? String.valueOf(payload) : String.valueOf(payload)
                + ", " + String.valueOf(payload1);
    }

    //...
}

何らかの理由で、たとえば上記のように、Preonは、3つあるはずの場合でも、エントリの2つのインスタンス(親と子)のみを解析します。

ありがとう。

4

1 に答える 1

2

このために、実行したいことに応じて、独自のコーデックまたはコーデックデコレータを実装することをお勧めします。バイトのシーケンスを独自のバイト配列に格納するだけの場合は、独自のコーデックを作成してフレームワークに接続するのはかなり簡単です。

これはおそらくあなたが探しているものに近いコーデックの実装です:

VariableLengthByteArrayCodec:

package org.codehaus.preon.sample.varlength;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.codehaus.preon.Builder;
import org.codehaus.preon.Codec;
import org.codehaus.preon.CodecDescriptor;
import org.codehaus.preon.DecodingException;
import org.codehaus.preon.Resolver;
import org.codehaus.preon.buffer.BitBuffer;
import org.codehaus.preon.channel.BitChannel;
import org.codehaus.preon.el.Expression;

import nl.flotsam.pecia.Documenter;
import nl.flotsam.pecia.ParaContents;
import nl.flotsam.pecia.SimpleContents;

public class VariableLengthByteArrayCodec implements Codec<byte[]> {

    public byte[] decode(BitBuffer buffer, Resolver resolver, Builder builder) throws DecodingException {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        boolean cont = true;
        while (cont) {
            byte b = buffer.readAsByte(8);
            bout.write(b);
            cont = (b & (1 << 7)) > 0;
        }
        return bout.toByteArray();
    }

    public void encode(byte[] value, BitChannel channel, Resolver resolver) throws IOException {
        channel.write(value, 0, value.length - 1);
    }

    public Expression<Integer, Resolver> getSize() {
        return null;
    }

    public CodecDescriptor getCodecDescriptor() {
        return new CodecDescriptor() {

            public <C extends ParaContents<?>> Documenter<C> summary() {
                return new Documenter<C>() {
                    public void document(C target) {
                        target.document(reference(Adjective.A, true));
                        target.text(".");
                    }
                };
            }

            public <C extends ParaContents<?>> Documenter<C> reference(final Adjective adjective, final boolean startWithCapital) {
                return new Documenter<C>() {
                    public void document(C target) {
                        target.text(adjective.asTextPreferA(startWithCapital))
                                .text("variable length encoded byte array.");
                    }
                };
            }

            public <C extends SimpleContents<?>> Documenter<C> details(String bufferReference) {
                return new Documenter<C>() {
                    public void document(C target) {
                        target.para()
                                .text("The number of bytes is determined by the ")
                                .text("leading bit of the individual bytes; ")
                                .text("if the first bit of a byte is 1, then ")
                                .text("more bytes are expted to follow.");
                    }
                };

            }

            public boolean requiresDedicatedSection() {
                return false;
            }

            public String getTitle() {
                assert requiresDedicatedSection();
                return null;
            }
        };
    }

    public Class<?>[] getTypes() {
        return new Class<?>[] { Byte[].class };
    }

    public Class<?> getType() {
        return Byte[].class;
    }
}

VariableLengthByteArrayCodecFactory:

package org.codehaus.preon.sample.varlength;

import java.lang.reflect.AnnotatedElement;
import org.codehaus.preon.Codec;
import org.codehaus.preon.CodecFactory;
import org.codehaus.preon.ResolverContext;

public class VariableLengthByteArrayCodecFactory implements CodecFactory {

    public <T> Codec<T> create(AnnotatedElement metadata, Class<T> type, ResolverContext context) {
        if (metadata != null && metadata.isAnnotationPresent(VarLengthEncoded.class) && type == byte[].class) {
            return (Codec<T>) new VariableLengthByteArrayCodec();
        } else {
            return null;
        }
    }

}

VarLengthEncoded:

package org.codehaus.preon.sample.varlength;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface VarLengthEncoded {
}

そして最後に、これはあなたがそれをどのように使うかです:

public static class SomeHolder {

    @VarLengthEncoded byte[] value;

    public byte[] getValue() {
        return value;
    }

}

...
Codec<SomeHolder> codec = Codecs.create(SomeHolder.class, new VariableLengthByteArrayCodecFactory());
SomeHolder holder = Codecs.decode(codec, (byte) 0xff, (byte) 0x0f);
assertThat(holder.getValue(), is(not(nullValue())));
assertThat(holder.getValue().length, is(2));
assertThat(holder.getValue()[0], is((byte) 0xff));
assertThat(holder.getValue()[1], is((byte) 0x0f));

これはかなりのコードのように見えるかもしれませんが、注意深くチェックすると、@ VarLengthEncodedアノテーションを使用してクラスのドキュメントを生成するときはいつでも、ほとんどのコードが実際に適切な説明が生成されていることを確認していることがわかります。ドキュメントをまったく気にしない場合は、デフォルトのCodecDescriptorを返すだけです。

したがって、この答えの本質は次のとおりです。Preon自体に実装を提供すると、フレームワークが過負荷になる場合が確かにあります。これは、フレームワークがデフォルトで提供するすべてのものに依存する必要があるという意味ではありません。これは、独自の拡張機能をプラグインする必要があることを意味します。

于 2011-02-13T13:18:10.967 に答える