https://qiita.com/gnagaoka/items/1a1c862b9def660abb77
Il existe N structures. Le nombre de séquences est écrit peu de temps avant Zubya, et après l'avoir lu, lisez la structure de ce nombre. En d'autres termes, les valeurs internes sont un tableau, donc cela ressemble à ce qui suit.
public class LIST<T extends DataTypeInterface> extends SingleDataType<ArrayList<T>> {
/**
*Jugement d'arrêt de boucle
*/
private BiPredicate<Integer,Integer> isNext;
/**
*Usine 2
*/
private IntFunction<T> factory;
/**
* constructor
* @usine d'usine param
* @param isNext S'il faut passer à l'élément suivant
*/
public LIST( IntFunction<T> factory,
BiPredicate<Integer,Integer> isNext){
this.factory = factory;
this.isNext = isNext;
this.set(new ArrayList<>());
}
/**
*Renvoie la taille de l'objet
*
* @Taille d'octet de l'objet de retour
*/
@Override
public Integer getSize() {
return this.get().stream().mapToInt(DataTypeInterface::getSize).sum();
}
/**
* 1.Enregistrer la position de décalage actuelle du tampon<br>
* 2.Obtenez le nombre de scans<br>
* 3.Seul le nombre de scans 4,Processus 5<br>
* 4.Effectuer une pré-décompilation pour créer une instance<br>
* 5.Exécuter la méthode de décompilation de l'instance<br>
* <br>
** Les éléments enfants qui n'ont pas pu être décompilés sont ignorés<br>
* <br>
* @tampon de param buf
*/
@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.Enregistrer la position de décalage actuelle du tampon<br>
* 2.Exécuter la méthode de compilation sur tous les éléments enfants<br>
* <br>
** Les éléments enfants qui n'ont pas pu être compilés sont ignorés
*
* @tampon de param buf
*/
@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
*/
/**
*Récupère le premier élément du tableau
* @retourne le premier élément
*/
public T first(){
return this.get(0);
}
/**
*Récupère le deuxième élément du tableau
* @return Dernier élément
*/
public T second(){
return this.get(1);
}
/**
*Récupère le dernier élément du tableau
* @return Dernier élément
*/
public T last(){
return this.get().get(this.get().size() - 1);
}
/**
*Ajouter le dernier élément du tableau
* @return Dernier élément
*/
public T push(){
return this.get(this.get().size());
}
/**
*Valeur interne[index]Obtenir.
*
* @index d'index de paramètre
* @valeur d'index de retour
*/
public T get(Integer index) {
T x;
try {
x = this.get().get(index);
}catch (IndexOutOfBoundsException e){
x = this.factory.apply(index);
/*Remplissez pour indexer*/
while((this.get().size()) < (index+1)){
x = this.factory.apply(this.get().size());
this.get().add(x);
}
}
return x;
}
}
Les points sont isNext et factory. En les utilisant, vous pouvez vous référer à d'autres sensations en utilisant lambda pour le nombre de séquences. L'utilisation est la suivante.
@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
);
Il est tout à fait possible que la valeur de décalage de la structure soit définie en premier, puis que la structure soit lue après le déplacement vers la destination de décalage. Le décalage provient souvent du début de sa propre structure, et non du début du binaire. C'est comme ça.
public class OFFSETW<T extends DataTypeInterface> extends CompositeDataType {
/**
*Référence au décalage
*/
protected NumericDataType offset;
/**
*Référence à la longueur d'octet
*/
protected NumericDataType lengthW;
/**
*Référence à la somme de contrôle
*/
protected NumericDataType checkSum;
/**
*Référence au décalage de base
*/
protected DataTypeInterface baseObject;
/*
structure
*/
/**
*Référence à l'objet de référence
*/
@PROPERTY(order = 1)
public T reference;
/*
structure method
*/
/**
* constructor<br>
*Définir un objet de référence qui est décalé par rapport à l'objet de base
*
* @offset de paramétrage
* @param baseObject Objet de base
* @référence param Objet de référence
*/
public OFFSETW(NumericDataType offset,DataTypeInterface baseObject,T reference) {
this.offset = offset;
this.reference = reference;
this.baseObject = baseObject;
}
/**
* constructor<br>
*Définir un objet de référence qui est décalé par rapport à l'objet de base
*
* @tampon de param buf
* @offset de paramétrage
* @param baseObject Objet de base
* @référence param Objet de référence
*/
public OFFSETW(ByteBuffer buf , NumericDataType offset,DataTypeInterface baseObject,T reference) {
this.offset = offset;
this.reference = reference;
this.baseObject = baseObject;
this.decompile(buf);
}
/**
* constructor
*Définir un objet de référence qui est décalé par rapport à l'objet de base<br>
* <br>
** Ce constructeur est un peu spécial et la longueur d'octet de l'objet de référence cible est définie à l'emplacement spécifié.<br>
*Lien Il calcule également une somme de contrôle à partir de cette chaîne d'octets et la lie à l'emplacement spécifié.<br>
*Ceci est particulièrement utile pour les sous-tables cmap et les tables de polices.<br>
*
* ToDO:Il faut se demander s'il faut en faire une classe différente
*
* @offset de paramétrage
* @param baseObject Objet de base
* @référence param Objet de référence
* @objet de longueur d'octet de longueur de paramètre
* @param checkSum Objet Checksum
*/
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;
}
/**
*Convertit un objet en tampon d'octets.<br>
*Seule la conversion de la valeur de décalage est effectuée.<br>
*Le décalage étant inconnu, 0 est écrit.<br>
*Le décalage sur lequel la valeur de décalage est écrite est enregistré.<br>
*
* @tampon de param buf
*/
@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);
/*Rendez-le divisible par 4*/
offset = buf.position();
Long length = offset.longValue() - this.getOffset();
/*Indivisible*/
Long mod = length % 4;
if(mod > 0){
/*padding*/
for(Integer j = 0; j< (4-mod) ; j++){
buf.put((byte)0);
}
}
/*Mise à jour de l'offset*/
offset = buf.position();
/*Lorsque l'écriture de longueur d'octet est spécifiée*/
if(this.lengthW != null){
buf.position(this.lengthW.getOffset());
this.lengthW.setNumber(length);
this.lengthW.compile(buf);
buf.position(offset);
}
}
/*
advanced method
*/
/**
*Obtenir des éléments enfants
*
* @retourner l'élément enfant
*/
@Override
public T get() {
return this.reference;
}
/**
*Convertit un tampon d'octets en objet.<br>
*Convertit un tampon d'octets en objet.<br>
*La destination de décalage est décompilée en même temps que la valeur de décalage est lue.<br>
*À ce moment-là, vous pouvez également ajouter le décalage de base à la valeur de décalage.<br>
*Mis à 0 si le décalage de base n'existe pas.<br>
*
* @tampon de param buf
*/
@Override
public void decompile(ByteBuffer buf){
/**
*offset est 0 est nul
*/
if(this.offset.get().intValue() == 0){
return ;
}
/**
*Souvenez-vous du décalage actuel
*/
Integer old_offset = buf.position();
/**
*Enregistrer la destination du décalage
*/
this.setOffset(this.baseObject.getOffset() + this.offset.get().intValue());
/**
*Volez vers la destination offset
*/
buf.position(this.getOffset());
/**
*décompiler
*/
this.reference.decompile(buf);
/**
*Annuler le décalage
*/
buf.position(old_offset);
}
}
C'est facile (^ ω ^).
@PROPERTY(order = 1)
public USHORT gesoOffset = new USHORT();
// ...
//Ecrivez-le au dos
@PROPERTY(order = 23)
public OFFSETW<Geso> geso= new OFFSETW<>(
this.gesoOffset,
this,
new Geso()
);
En l'utilisant avec LIST, vous pouvez lire que Offset est un tableau.
@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
);
Il y a aussi une lecture à de tels moments.
public class R<Z extends DataTypeInterface> extends CompositeDataType {
/**
*Définir la décompilation
* buf → (new,decompile) → instance
*/
public Function<ByteBuffer, Z> decompiler;
/**
*Définir la compilation
* buf,Z → (compile) →
*/
public BiConsumer<ByteBuffer, Z> compiler;
/**
* factory
* → (new) → instance
*/
protected Supplier<Z> factory;
/**
*Efficacité|Jugement invalide
*/
public Supplier<Boolean> enable;
/**
*Contenu
*/
public Z content;
/**
* constructor
* <p>
*permettre d'activer ou de désactiver cet objet
*Veuillez transmettre l'expression lambda.
*
* @param compilateur Fonction exécutée au moment de la compilation
* @Fonction exécutée au moment du décompilateur de param decomile
* @param enable True:Efficacité,False:Invalide
*/
public R(
Function<ByteBuffer, Z> decompiler,
BiConsumer<ByteBuffer, Z> compiler,
Supplier<Boolean> enable) {
this.decompiler = decompiler;
this.compiler = compiler;
this.enable = enable;
}
/**
* constructor
* <p>
*enable pour activer ou désactiver cet objet
*Veuillez transmettre l'expression lambda.
*
* @instanciation d'usine de param//ToDO:Je veux le changer pour la génération des génériques ...
* @param enable True:Efficacité,False:Invalide
*/
public R(
Supplier<Z> factory,
Supplier<Boolean> enable) {
this.factory= factory;
this.enable = enable;
}
/**
* getter
*
* @retourner le contenu
*/
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;
}
}
}
Il peut être utilisé lorsque la structure des données diffère en fonction du numéro de format.
@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
);
En combinant LIST, R et OFFSET, même des structures de données complexes peuvent être écrites structurellement.
fin
Recommended Posts