KasperskyOS Community Edition 1.2

Типы данных в языке IDL

В языке IDL поддерживаются как примитивные, так и составные типы данных. Набор поддерживаемых составных типов включает объединения, структуры, массивы и последовательности.

Примитивные типы

В языке IDL поддерживаются следующие примитивные типы:

  • SInt8, SInt16, SInt32, SInt64 – знаковое целое число.
  • UInt8, UInt16, UInt32, UInt64 –беззнаковое целое число.
  • Handle – значение, двоичное представление которого состоит из нескольких полей, включая поле дескриптора и поле маски прав дескриптора.
  • bytes<<размер в байтах>> – байтовый буфер, представляющий собой область памяти с размером, не превышающим заданного числа байт.
  • string<<размер в байтах>> – строковый буфер, представляющий собой байтовый буфер, последний байт которого является терминирующим нулем. Максимальный размер строкового буфера на единицу больше заданного из-за наличия дополнительного байта с терминирующим нулем.

Целочисленные литералы можно указывать в десятичном, шестнадцатеричном (например, 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 UInt64 MaxLen = (MaxLogMessageSize + 4) * MaxLogMessageCount;

Именованные целочисленные константы можно использовать, чтобы избежать проблемы "магических чисел". К примеру, если в IDL-описании определены именованные целочисленные константы для кодов возврата интерфейсного метода, то при описании политики можно интерпретировать эти коды без дополнительных сведений. Также именованные целочисленные константы и целочисленные выражения могут применяться в определениях байтовых и строковых буферов, а также составных типов, чтобы задать размер данных или число элементов данных.

Конструкции bytes<<размер в байтах>> и string<<размер в байтах>> используются в определениях составных типов, сигнатурах интерфейсных методов и при создании псевдонимов типов, так как сами по себе они определяют анонимные типы (типы без имени).

Объединения

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

Для определения объединения используется следующая конструкция:

union <имя типа> { <тип члена> <имя члена>; [...] }

Пример определения объединения:

union ExitInfo { UInt32 code; ExceptionInfo exc; }

Структуры

Для определения структуры используется следующая конструкция:

struct <имя типа> { <тип поля> <имя поля>; [...] }

Пример определения структуры:

struct SessionEvqParams { UInt32 count; UInt32 align; UInt32 size; }

Массивы

Для определения массива используется следующая конструкция:

array<<тип элементов, число элементов>>

Эта конструкция используется в определениях других составных типов, сигнатурах интерфейсных методов и при создании псевдонимов типов, так как сама по себе она определяет анонимный тип.

Тип Handle можно использовать в качестве типа элементов массива, если этот массив не входит в другой составной тип данных. При этом суммарное число дескрипторов в IPC-сообщении не может превышать 255.

Последовательности

Последовательность представляет собой массив переменного размера. При определении последовательности указывается максимальное число ее элементов.

Для определения последовательности используется следующая конструкция:

sequence<<тип элементов, число элементов>>

Эта конструкция используется в определениях других составных типов, сигнатурах интерфейсных методов и при создании псевдонимов типов, так как сама по себе она определяет анонимный тип.

Тип 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; UInt64 e; }

Определение объединения или структуры не может быть вложено в определение другого типа. Однако в определение типа могут быть включены уже определенные объединения и структуры. Это выполняется посредством указания в определении типа имен включаемых типов.

Пример определения структуры, включающей объединение и структуру:

union foo { UInt32 value1; UInt8 value2; } struct bar { UInt32 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); }