В языке IDL поддерживаются как примитивные, так и составные типы данных. Набор поддерживаемых составных типов включает объединения, структуры, массивы и последовательности.
Примитивные типы
В языке IDL поддерживаются следующие примитивные типы:
SInt8, SInt16, SInt32, SInt64 – знаковое целое число.UInt8, UInt16, UInt32, UInt64 –беззнаковое целое число.UIntSize – беззнаковое целое число для представления размера объекта в байтах.Диапазон значений зависит от аппаратной платформы (аналогично типу size_t в языке C).
UIntPtr – беззнаковое целое число для представления адреса объекта.Диапазон значений зависит от аппаратной платформы (аналогично типу uintptr_t в языке C).
Handle – значение, двоичное представление которого состоит из нескольких полей, включая поле дескриптора и поле маски прав дескриптора.Дескриптор может идентифицировать любой ресурс.
handle<<имя интерфейса>> – значение, двоичное представление которого состоит из нескольких полей, включая поле callable-дескриптора и поле маски прав callable-дескриптора.Callable-дескриптор идентифицирует одновременно IPC-канал до сервера и службу этого сервера с заданным интерфейсом. Компилятор nk-psl-gen-c проверяет, что заданный интерфейс определен в одном из IDL-файлов, пути к которым заданы при вызове компилятора. В случае отсутствия определения работа компилятора завершится с ошибкой.
bytes<<максимальный размер в байтах>> – байтовый буфер, содержащий не более заданного числа байт.string<<максимальный размер в байтах>> – строковый буфер, представляющий собой байтовый буфер, фактический максимальный размер которого на единицу больше заданного из-за наличия дополнительного байта для терминирующего нуля.Символы в строковом буфере должны иметь кодировку UTF-8. В строковый буфер можно поместить строку нулевого размера без терминирующего нуля, что отражает отсутствие данных или пустую строку. Строка ненулевого размера должна завершаться терминирующим нулем. (В случае использования кодировки, отличной от UTF-8, или отсутствия терминирующего нуля в строке ненулевого размера модуль безопасности Kaspersky Security Module запретит передачу строкового буфера.)
Целочисленные литералы можно указывать в десятичном, шестнадцатеричном (например, 0x2f, 0X2f, 0x2F, 0X2F) или восьмеричном (например, 0O123, 0o123) представлении.
С помощью ключевого слова const можно определять именованные целочисленные константы, задавая их значения целочисленными литералами или целочисленными выражениями.
Примеры определений именованных целочисленных констант:
const UInt32 DeviceNameMax = 0o100;
const UInt32 HandleTypeUserLast = 0x0001FFFF;
const UInt32 MaxLogMessageSize = (2 << 3) ** 2;
const UInt32 MaxLogMessageCount = 100;
const UIntSize MaxLen = (MaxLogMessageSize + 4) * MaxLogMessageCount;
Именованные целочисленные константы можно использовать, чтобы избежать проблемы "магических чисел". К примеру, если в IDL-описании определены именованные целочисленные константы для кодов возврата интерфейсного метода, то при описании политики можно интерпретировать эти коды без дополнительных сведений. Также именованные целочисленные константы и целочисленные выражения могут применяться в определениях байтовых и строковых буферов, а также составных типов, чтобы задать размер данных или число элементов данных.
Конструкции bytes<<размер в байтах>>, string<<размер в байтах>> и handle<<имя интерфейса>> используются в определениях составных типов, сигнатурах интерфейсных методов и при создании псевдонимов типов, так как сами по себе они определяют анонимные типы (типы без имени).
Объединения
Объединение позволяет хранить данные разных типов в одной области памяти. В IPC-сообщении объединение снабжается дополнительным полем tag, позволяющим определить, какой именно член объединения используется.
Для определения объединения используется следующая конструкция:
union <имя типа> {
<тип члена> <имя члена>;
...
}
Пример определения объединения:
union ExitInfo {
UInt32 code;
ExceptionInfo exc;
}
Структуры
Для определения структуры используется следующая конструкция:
struct <имя типа> {
<тип поля> <имя поля>;
...
}
Пример определения структуры:
struct SessionEvqParams {
UInt32 count;
UInt32 align;
UInt32 size;
}
Массивы
Для определения массива используется следующая конструкция:
array<<тип элементов>, <число элементов>>
Эта конструкция используется в определениях других составных типов, сигнатурах интерфейсных методов и при создании псевдонимов типов, так как сама по себе она определяет анонимный тип.
Тип Handle и handle<<имя интерфейса>> можно использовать в качестве типа элементов массива, если этот массив не входит в другой составной тип данных. При этом суммарное число дескрипторов в IPC-сообщении не может превышать 255.
Последовательности
Последовательность представляет собой массив, содержащий не более заданного числа элементов заданного типа. Для определения последовательности используется следующая конструкция:
sequence<<тип элементов>, <максимальное число элементов>>
Эта конструкция используется в определениях других составных типов, сигнатурах интерфейсных методов и при создании псевдонимов типов, так как сама по себе она определяет анонимный тип.
Тип Handle и handle<<имя интерфейса>> нельзя использовать в качестве типа элементов последовательности.
Типы переменного и фиксированного размера
Типы bytes, string и sequence являются типами переменного размера, то есть при определении этих типов задается максимальное число элементов, а фактически может использоваться меньше, в том числе ноль. Данные типов bytes, string и sequence хранятся в арене IPC-сообщений. Остальные типы являются типами фиксированного размера. Данные типов фиксированного размера хранятся в фиксированной части IPC-сообщений.
Типы на основе составных типов
На основе составных типов могут быть определены другие составные типы. При этом определение массива или последовательности может быть вложено в определение другого типа.
Пример определения структуры с вложенными определениями массива и последовательности:
const UInt32 MessageSize = 64;
struct BazInfo {
array<UInt8, 100> a;
sequence<sequence<UInt32, MessageSize>, ((2 << 2) + 2 ** 2) * MessageSize> b;
string<100> c;
bytes<4096> d;
UIntSize e;
handle<embedder.DeviceManager> f;
}
Определение объединения или структуры не может быть вложено в определение другого типа. Однако в определение типа могут быть включены уже определенные объединения и структуры. Это выполняется посредством указания в определении типа имен включаемых типов.
Пример определения структуры, включающей объединение и структуру:
union foo {
UInt32 value1;
UInt8 value2;
}
struct bar {
UIntPtr a;
UInt8 b;
}
struct BazInfo {
foo x;
bar y;
}
Создание псевдонимов типов
Псевдонимы типов используются для повышения удобства работы с типами. Псевдонимы типов могут применяться, например, для того, чтобы задать типам с абстрактными именами мнемонические имена. Также назначение псевдонимов для анонимных типов позволяет получить именованные типы.
Для создания псевдонима типа используется следующая конструкция:
typedef <тип> <псевдоним типа>
Пример создания мнемонических псевдонимов:
typedef UInt64 ApplicationId;
typedef Handle PortHandle;
Пример создания псевдонима определению массива:
typedef array<UInt8, 4> IP4;
Пример создания псевдонима определению последовательности:
const UInt32 MaxDevices = 8;
struct Device {
string<32> DeviceName;
UInt8 DeviceID;
}
typedef sequence<Device, MaxDevices> Devices;
Пример создания псевдонима определению объединения:
union foo {
UInt32 value1;
UInt8 value2;
}
typedef foo bar;
Определение анонимных типов в сигнатурах интерфейсных методов
Анонимные типы могут быть определены в сигнатурах интерфейсных методов.
Пример определения последовательности в сигнатуре интерфейсного метода:
const UInt8 DeviceCount = 8;
interface {
Poll(in UInt32 timeout,
out sequence<UInt32, DeviceCount / 2> report,
out UInt32 count,
out UInt32 rc);
}
В начало