https://qiita.com/gnagaoka/items/1a1c862b9def660abb77
Es gibt N Strukturen. Die Anzahl der Sequenzen wird kurz vor Zubya geschrieben und nach dem Lesen die Struktur für diese Anzahl gelesen. Mit anderen Worten, die internen Werte sind ein Array, daher sieht es wie folgt aus.
public class LIST<T extends DataTypeInterface> extends SingleDataType<ArrayList<T>> {
/**
*Loop-Stop-Urteil
*/
private BiPredicate<Integer,Integer> isNext;
/**
*Fabrik 2
*/
private IntFunction<T> factory;
/**
* constructor
* @param Fabrik Fabrik
* @param isNext Gibt an, ob zum nächsten Element gewechselt werden soll
*/
public LIST( IntFunction<T> factory,
BiPredicate<Integer,Integer> isNext){
this.factory = factory;
this.isNext = isNext;
this.set(new ArrayList<>());
}
/**
*Geben Sie die Größe des Objekts zurück
*
* @Bytegröße des Rückgabeobjekts
*/
@Override
public Integer getSize() {
return this.get().stream().mapToInt(DataTypeInterface::getSize).sum();
}
/**
* 1.Notieren Sie die aktuelle Versatzposition des Puffers<br>
* 2.Ermitteln Sie die Anzahl der Scans<br>
* 3.Nur die Anzahl der Scans 4,Prozess 5<br>
* 4.Führen Sie preDecompile aus, um eine Instanz zu erstellen<br>
* 5.Führen Sie die Dekompilierungsmethode der Instanz aus<br>
* <br>
** Untergeordnete Elemente, die nicht dekompiliert werden konnten, werden übersprungen<br>
* <br>
* @param buf buffer
*/
@Override
public void decompile(ByteBuffer buf){
this.setOffset(buf.position());
Integer index = 0;
Integer length = 0;
while (this.isNext.test(index, length)) {
try {
T s = this.factory.apply(index);
s.decompile(buf);
this.get().add(s);
} catch (LISTSkipException e) {
continue;
} catch (LISTStopException e) {
break;
} finally {
index++;
length = buf.position() - this.getOffset();
}
}
}
/**
* 1.Notieren Sie die aktuelle Versatzposition des Puffers<br>
* 2.Führen Sie die Kompilierungsmethode für alle untergeordneten Elemente aus<br>
* <br>
** Untergeordnete Elemente, die nicht kompiliert werden konnten, werden übersprungen
*
* @param buf buffer
*/
@Override
public void compile(ByteBuffer buf) throws IllegalStateException,IllegalArgumentException {
this.setOffset(buf.position());
for(T s : this.get()){
try {
s.compile(buf);
} catch (LISTSkipException e) {
continue;
} catch (LISTStopException e) {
break;
}
}
}
/*
advanced method
*/
/**
*Holen Sie sich das erste Element des Arrays
* @erstes Element zurückgeben
*/
public T first(){
return this.get(0);
}
/**
*Holen Sie sich das zweite Element des Arrays
* @letztes Element zurückgeben
*/
public T second(){
return this.get(1);
}
/**
*Holen Sie sich das letzte Element des Arrays
* @letztes Element zurückgeben
*/
public T last(){
return this.get().get(this.get().size() - 1);
}
/**
*Fügen Sie das letzte Element des Arrays hinzu
* @letztes Element zurückgeben
*/
public T push(){
return this.get(this.get().size());
}
/**
*Interner Wert[index]Bekommen.
*
* @param index index
* @Indexwert zurückgeben
*/
public T get(Integer index) {
T x;
try {
x = this.get().get(index);
}catch (IndexOutOfBoundsException e){
x = this.factory.apply(index);
/*Füllen Sie bis zum Index*/
while((this.get().size()) < (index+1)){
x = this.factory.apply(this.get().size());
this.get().add(x);
}
}
return x;
}
}
Die Punkte sind isNext und factory. Wenn Sie diese verwenden, können Sie sich auf andere Gefühle beziehen, die Lambda für die Anzahl der Sequenzen verwenden. Die Verwendung ist wie folgt.
@PROPERTY(order = 5)
public USHORT numHoge= new USHORT();
@PROPERTY(order = 6)
public LIST<HogeObject> items = new LIST<>(
(i) -> new HogeObject(),
(i,len) -> this.numHoge.get() > i
);
Es ist durchaus möglich, dass zuerst der Versatzwert für die Struktur definiert wird und dann die Struktur gelesen wird, nachdem zum Versatzziel gewechselt wurde. Der Offset ist oft nicht vom Anfang der Binärdatei, sondern vom Anfang ihrer eigenen Struktur. Es ist so.
public class OFFSETW<T extends DataTypeInterface> extends CompositeDataType {
/**
*Verweis auf Offset
*/
protected NumericDataType offset;
/**
*Verweis auf Bytelänge
*/
protected NumericDataType lengthW;
/**
*Verweis auf Prüfsumme
*/
protected NumericDataType checkSum;
/**
*Verweis auf Basisversatz
*/
protected DataTypeInterface baseObject;
/*
structure
*/
/**
*Verweis auf Referenzobjekt
*/
@PROPERTY(order = 1)
public T reference;
/*
structure method
*/
/**
* constructor<br>
*Definieren Sie ein Referenzobjekt, das vom Basisobjekt versetzt ist
*
* @param offset offset
* @param baseObject Basisobjekt
* @param reference Referenzobjekt
*/
public OFFSETW(NumericDataType offset,DataTypeInterface baseObject,T reference) {
this.offset = offset;
this.reference = reference;
this.baseObject = baseObject;
}
/**
* constructor<br>
*Definieren Sie ein Referenzobjekt, das vom Basisobjekt versetzt ist
*
* @param buf buffer
* @param offset offset
* @param baseObject Basisobjekt
* @param reference Referenzobjekt
*/
public OFFSETW(ByteBuffer buf , NumericDataType offset,DataTypeInterface baseObject,T reference) {
this.offset = offset;
this.reference = reference;
this.baseObject = baseObject;
this.decompile(buf);
}
/**
* constructor
*Definieren Sie ein Referenzobjekt, das vom Basisobjekt versetzt ist<br>
* <br>
** Dieser Konstruktor ist etwas Besonderes und die Bytelänge des Zielreferenzobjekts wird auf den angegebenen Speicherort festgelegt.<br>
*Verknüpfung Es berechnet auch eine Prüfsumme aus dieser Bytezeichenfolge und verknüpft sie mit dem angegebenen Speicherort.<br>
*Dies ist besonders nützlich für cmap-Untertabellen und Schriftarten.<br>
*
* ToDO:Es ist zu überlegen, ob es sich um eine andere Klasse handelt
*
* @param offset offset
* @param baseObject Basisobjekt
* @param reference Referenzobjekt
* @Parameter Länge Byte Länge Objekt
* @param checkSum Prüfsummenobjekt
*/
public OFFSETW(NumericDataType offset,
NumericDataType length,
NumericDataType checkSum,
DataTypeInterface baseObject,
T reference
) {
this.offset = offset;
this.reference = reference;
this.baseObject = baseObject;
this.lengthW = length;
this.checkSum = checkSum;
}
/**
*Konvertiert ein Objekt in einen Bytepuffer.<br>
*Es wird nur die Offsetwertkonvertierung durchgeführt.<br>
*Da der Offset unbekannt ist, wird 0 geschrieben.<br>
*Der Versatz, in den der Versatzwert geschrieben wird, wird aufgezeichnet.<br>
*
* @param buf buffer
*/
@Override
public void compile(ByteBuffer buf) {
this.setOffset(buf.position());
Integer offset = buf.position();
buf.position(this.offset.getOffset());
this.offset.setNumber(offset - baseObject.getOffset());
this.offset.compile(buf);
buf.position(offset);
this.reference.compile(buf);
/*Machen Sie es teilbar durch 4*/
offset = buf.position();
Long length = offset.longValue() - this.getOffset();
/*Unteilbar*/
Long mod = length % 4;
if(mod > 0){
/*padding*/
for(Integer j = 0; j< (4-mod) ; j++){
buf.put((byte)0);
}
}
/*Offset-Update*/
offset = buf.position();
/*Wenn das Schreiben der Bytelänge angegeben ist*/
if(this.lengthW != null){
buf.position(this.lengthW.getOffset());
this.lengthW.setNumber(length);
this.lengthW.compile(buf);
buf.position(offset);
}
}
/*
advanced method
*/
/**
*Holen Sie sich untergeordnete Elemente
*
* @untergeordnetes Element zurückgeben
*/
@Override
public T get() {
return this.reference;
}
/**
*Konvertiert einen Bytepuffer in ein Objekt.<br>
*Konvertiert einen Bytepuffer in ein Objekt.<br>
*Das Versatzziel wird gleichzeitig mit dem Lesen des Versatzwerts dekompiliert.<br>
*Zu diesem Zeitpunkt können Sie auch den Basisversatz zum Versatzwert hinzufügen.<br>
*Auf 0 setzen, wenn der Basisversatz nicht vorhanden ist.<br>
*
* @param buf buffer
*/
@Override
public void decompile(ByteBuffer buf){
/**
*Offset ist 0 ist null
*/
if(this.offset.get().intValue() == 0){
return ;
}
/**
*Merken Sie sich den aktuellen Offset
*/
Integer old_offset = buf.position();
/**
*Versatzziel aufzeichnen
*/
this.setOffset(this.baseObject.getOffset() + this.offset.get().intValue());
/**
*Fliegen Sie zum versetzten Ziel
*/
buf.position(this.getOffset());
/**
*dekompilieren
*/
this.reference.decompile(buf);
/**
*Versatz rückgängig machen
*/
buf.position(old_offset);
}
}
Es ist einfach (^ ω ^).
@PROPERTY(order = 1)
public USHORT gesoOffset = new USHORT();
// ...
//Schreiben Sie es in den Rücken
@PROPERTY(order = 23)
public OFFSETW<Geso> geso= new OFFSETW<>(
this.gesoOffset,
this,
new Geso()
);
Wenn Sie es zusammen mit LIST verwenden, können Sie lesen, dass Offset ein Array ist.
@PROPERTY(order = 1)
public USHORT hogeCount = new USHORT()
@PROPERTY(order = 2)
public LIST<HogeRecord> hogeRecords= new LIST<>(
(i) -> new HogeRecord(this),
(i,len) -> this.hogeCount.get() > i
);
@PROPERTY(order = 3)
public LIST<OFFSETW<HogeHoge>> scripts = new LIST<>(
(i) -> new OFFSETW<>(
this.hogeRecords.get().get(i).offset,
this,
new HogeHoge()
),
(i,len) -> this.hogeCount.get() > i
);
Zu solchen Zeiten gibt es auch eine Lesung.
public class R<Z extends DataTypeInterface> extends CompositeDataType {
/**
*Dekompilierung definieren
* buf → (new,decompile) → instance
*/
public Function<ByteBuffer, Z> decompiler;
/**
*Kompilierung definieren
* buf,Z → (compile) →
*/
public BiConsumer<ByteBuffer, Z> compiler;
/**
* factory
* → (new) → instance
*/
protected Supplier<Z> factory;
/**
*Wirksamkeit|Ungültiges Urteil
*/
public Supplier<Boolean> enable;
/**
*Inhalt
*/
public Z content;
/**
* constructor
* <p>
*Aktivieren Sie, ob dieses Objekt aktiviert oder deaktiviert werden soll
*Bitte übergeben Sie den Lambda-Ausdruck.
*
* @param compiler Funktion, die zur Kompilierungszeit ausgeführt wird
* @Funktion zum Zeitpunkt der Dekompilierung des Parameterdekompilierers ausgeführt
* @param enable True:Wirksamkeit,False:Ungültig
*/
public R(
Function<ByteBuffer, Z> decompiler,
BiConsumer<ByteBuffer, Z> compiler,
Supplier<Boolean> enable) {
this.decompiler = decompiler;
this.compiler = compiler;
this.enable = enable;
}
/**
* constructor
* <p>
*Aktivieren Sie, ob dieses Objekt aktiviert oder deaktiviert werden soll
*Bitte übergeben Sie den Lambda-Ausdruck.
*
* @param Factory Instanziierung//ToDO:Ich möchte es für die Generierung von Generika ändern ...
* @param enable True:Wirksamkeit,False:Ungültig
*/
public R(
Supplier<Z> factory,
Supplier<Boolean> enable) {
this.factory= factory;
this.enable = enable;
}
/**
* getter
*
* @Inhalt zurückgeben
*/
public Z get() {
if(this.content == null){
this.content = this.factory.get();
}
return this.content;
}
@Override
public void decompile(ByteBuffer buf) {
this.setOffset(buf.position());
if (this.enable.get()) {
if(this.decompiler != null ){
this.content = this.decompiler.apply(buf);
}else{
this.content = this.factory.get();
this.content.decompile(buf);
}
}
}
@Override
public void compile(ByteBuffer buf) {
this.setOffset(buf.position());
if (this.enable.get()) {
if(this.compiler != null ){
this.compiler.accept(buf,this.content);
}else{
this.content.compile(buf);
}
}
}
@Override
public Object exports() {
if (this.enable.get()) {
return this.content.exports();
} else {
return null;
}
}
}
Es kann verwendet werden, wenn die Datenstruktur je nach Formatnummer unterschiedlich ist.
@PROPERTY(order = 1)
public USHORT formatNum = new USHORT();
@PROPERTY(order = 2)
public R<GesoGesoFormat1> gesogesoFormat1= new R<>(
()-> new GesoGesoFormat1(this),
()-> this.formatNum.get() == 1
);
@PROPERTY(order = 2)
public R<GesoGesoFormat2> gesogesoFormat2= new R<>(
()-> new GesoGesoFormat2(this),
()-> this.formatNum.get() == 2
);
Durch die Kombination von LIST, R und OFFSET können auch komplexe Datenstrukturen strukturell geschrieben werden.
Ende
Recommended Posts