JNA标签联合映射

时间:2019-04-06 13:16:39

标签: java jna

如何将以下“标记的联合”结构映射到JNA? libvtermlink to source code)使用此结构。

/**
 * 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 个答案:

答案 0 :(得分:2)

尽管有许多可用的映射(使用正确的方法来获取值的任何32位结构),但直接映射此映射的规范方法是使用JNA的Union类。联盟将包含三个要素;您可以定义的byte或结构RGB(可以使用Union的内部类),也可以定义的结构Indexed(同样可以是内部类) 。

Union将在本机侧为最大的元素(32位)分配足够的内存,并且在给定结构选项的情况下,您可以确保得到的32位C端的前8位内存将包含type字段;根据该值,您将知道剩余的24位中包含什么。

如果您查看映射source code of JNA's Variant classtagged union VARIANT,您会发现它的实现稍微复杂一些。 _VARIANT类包含这五个元素,类似于并集中的3个元素:

        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类setType()方法来确定是否还有一个有效值:它设置了一个与活动字段相对应的字符串(在此在构造函数中设置的大小写"_variant")。 (您也可以使用类而不是字符串进行设置。)

在您的情况下,您将需要基于类型值进行初始化,因此将以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
    }
}

您可能想创建其他一些getter方法,以在返回适当的字段之前检查type值。

如开头所述,任何32位数据结构都可以使用。有点骇人听闻的选择(以更少的代码牺牲了可读性和类型安全性)可以始终使用上面定义的4字节RGB结构。 type的吸气剂将始终有效,而redgreenblue的吸气剂将在有效时起作用,否则,您可以为{{1}创建吸气剂}只会读取idx的值。