Stream 可变长度序列,第一位表示序列结束,前子
当第一位(BigEndian)指示是否有另一个字节在使用Preon时,如何解析可变长度的字节序列 示例Stream 可变长度序列,第一位表示序列结束,前子,stream,variable-length,preon,Stream,Variable Length,Preon,当第一位(BigEndian)指示是否有另一个字节在使用Preon时,如何解析可变长度的字节序列 示例 byte[] bytecode = new byte[] { (byte) 0xf2, (byte) 0xbf, (byte) 0xbf, (byte) 0xbf, (byte) 0x50 }; 注释 指示在最终有效负载中丢弃下一个的第一位 这篇文章使用的Preon版本是1.1 结果字节(十进制) {114,63,63,63,80} 已尝试过 @B
byte[] bytecode = new byte[] {
(byte) 0xf2, (byte) 0xbf, (byte) 0xbf, (byte) 0xbf, (byte) 0x50
};
注释
- 指示在最终有效负载中丢弃下一个的第一位
- 这篇文章使用的Preon版本是1.1
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将只解析条目的2个实例(父实例和子实例),即使应该有3个
谢谢。对于这一点,我建议根据您的需要实现您自己的编解码器或编解码器装饰器。如果您只想将字节序列存储在自己的字节数组中,那么创建自己的编解码器并将其与框架连接起来应该相当容易 下面是一个编解码器的实现,它可能与您正在寻找的内容非常接近: 可变长度字节码:
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;
}
}
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;
}
}
}
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));
公共静态类{
@VAR编码字节[]值;
公共字节[]getValue(){
返回值;
}
}
...
Codec Codec=Codecs.create(SomeHolder.class,新变量lengthByteArrayCodeFactory());
SomeHolder=codec.decode(编解码器,(字节)0xff,(字节)0x0f);
断言(holder.getValue(),不是(nullValue());
断言(holder.getValue().length为(2));
断言(holder.getValue()[0]为((字节)0xff));
断言(holder.getValue()[1]为((字节)0x0f));
这似乎是一段相当多的代码,但如果仔细检查,您会注意到大多数代码实际上是在确保每当您为带有@varcode注释的类生成文档时,都会生成正确的描述。如果您根本不关心文档,那么您可以简单地返回一个默认的CodecDescriptor
因此,我想,这个答案的本质是:在某些情况下,在Preon中提供实现本身会使框架过载。这并不意味着您应该依赖框架默认提供的一切。这只是意味着您应该插入自己的扩展。我没想到会有一个完美的编解码器实现,非常感谢!当我很容易得到文档时,我不介意额外的东西。