JNA помечено объединение карт - PullRequest
1 голос
/ 06 апреля 2019

Как отобразить следующую структуру "tagged union" на JNA?Эта структура используется libvterm ( ссылка на исходный код ).

/**
 * Tagged union storing either an RGB color or an index into a colour palette
 */
typedef union {
  /**
   * Tag indicating which union member is actually valid. This variable
   * coincides with the `type` member of the `rgb` and the `indexed` struct
   * in memory. */
  uint8_t type;

  struct {
    uint8_t type;
    uint8_t red, green, blue;
  } rgb;

  struct {
    uint8_t type;
    uint8_t idx;
  } indexed;
} VTermColor;

1 Ответ

2 голосов
/ 07 апреля 2019

Хотя существует много отображений, которые будут работать (любая 32-битная структура с правильными методами, используемыми для извлечения значений), канонический способ отобразить это напрямую - использовать класс JNA Union . Союз будет иметь три элемента; либо byte, либо структуру RGB, которую вы можете определить (для внутреннего класса Union это нормально), либо структуру Indexed, которую вы определите (опять же, внутренний класс).

Union выделит достаточно памяти на собственной стороне для самого большого элемента (32-битного), и с учетом опций структуры вам гарантировано, что первые 8 бит результирующей 32-битной памяти на стороне C будут содержать поле type; на основании этого значения вы будете знать, что содержится в оставшихся 24 битах.

Если вы посмотрите на исходный код класса VNAant JNA , который отображает объединенный тег VARIANT , вы увидите, что это реализовано в несколько более сложном масштабе. Класс _VARIANT содержит эти пять элементов, аналогично трем элементам в вашем союзе:

        public VARTYPE vt;
        public short wReserved1;
        public short wReserved2;
        public short wReserved3;
        public __VARIANT __variant;

Для Союза допустимо только одно значение __variant. В этом случае тип задается здесь:

   public void setVarType(short vt) {
        this._variant.vt = new VARTYPE(vt);
   }

В более общем смысле вы можете посмотреть на внешний класс VARIANT, который использует метод Union class setType(), чтобы определить, существует ли даже допустимое значение: он устанавливает строку, соответствующую активному полю (в данном случае "_variant" ), который устанавливается в конструкторе. (Вы также можете установить использование класса вместо String.)

В вашем случае вы захотите выполнить инициализацию на основе значения типа, поэтому вы начнете с type в качестве значения по умолчанию, прочитаете его значение и затем переключитесь.

Вы можете определить свой союз следующим образом:

public class VTermColor extends Union {
    public class RGB extends Structure {
        public byte type;
        public byte red;
        public byte green;
        public byte blue;
    }

    public class Indexed extends Structure {
        public byte type;
        public byte idx;
    }

    public byte type;
    public RGB rgb;
    public Indexed indexed;

    public VTermColor() {
        // initialize knowing only the type, read its value
        this.setType("type");
        this.read();

        // switch union based on type, re-read
        if ((this.type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_RGB) {
            this.setType("rgb");
        } else {
            this.setType("indexed");
        }
        this.read();
    }

    public VTermColor(Pointer p) {
        super(p);
        // same remaining code as above
    }
}

Возможно, вы захотите создать несколько других методов получения, чтобы проверять значение type перед возвратом соответствующих полей.

Как упоминалось в начале, любая 32-битная структура данных будет работать. Несколько хакерская альтернатива (жертвуя удобочитаемостью и безопасностью типов для намного меньшего количества кода) может просто всегда использовать 4-байтовую структуру RGB, как определено выше. Метод получения для type всегда будет работать, в то время как методы получения для red, green и blue будут работать, если они действительны, в противном случае вы можете создать метод получения для idx, который просто читает значение red .

...