
За допомогою інструменту «Структури» можна аналізувати та редагувати масиви байтів на основі створених користувачем визначень структур, які можна побудувати з масивів, об’єднань, елементарних типів та переліків.
Інструмент має власне діалогове вікно параметрів, відкрити яке можна за допомогою натискання кнопки . Передбачено досить багато параметрів налаштування, зокрема стиль (десяткові, шістнадцяткові або двійкові), у якому буде показано значення. Крім того, можна визначити, які визначення структур буде завантажено і які структури буде показано.
Структури визначаються за допомогою файлів визначення структур Okteta (XML-файлах, з суфіксом назви .osd
). Крім того, потрібен файл .desktop
, що містить метадані щодо файла опису структури, зокрема відомості щодо автора, домашньої сторінки та умов ліцензування.
У поточній версії програми ще немає вбудованої підтримки створення або редагування визначень структур, отже все це слід робити вручну у спосіб, описаний у наступних розділах.
Найпростішим способом встановлення нових визначень структур є використання вбудованої підтримки KNewStuff у Okteta. Щоб встановити існуючу структуру, відкрийте діалогове вікно інструменту «Структури». Перейдіть на вкладку Керування структурами і натисніть кнопку . За допомогою діалогового вікна, яке буде відкрито, ви зможете встановити або вилучити встановлені визначення структур.
Інструмент «Структури» шукає описи структур у підкаталозі okteta/structures/
каталогу даних програм користувача (визначити адресу цього каталогу можна за допомогою команди qtpaths
). Якщо ще не встановлено жодного визначення структури, можливо, вам доведеться створити відповідний підкаталог.--paths GenericDataLocation
Дані кожного визначення структури має бути розподілено між двома файлами: один з файлів міститиме дані самого визначення, а інший файл, .desktop
, зберігатиме метадані (дані щодо автора, версії тощо).
У цьому каталозі має бути підкаталог для кожного з визначень структури, у якому мають зберігатися обидва файла визначення: файл .desktop
і файл .osd
або main.js
.
Наприклад, якщо каталогом даних програм є
, а визначення структури має назву ExampleStructure, має бути каталог qtpaths
--paths GenericDataLocation
okteta/structures/ExampleStructure
, що міститиме файли ExampleStructure.desktop
і ExampleStructure.osd
.
Якщо ви встановили нове визначення структури створенням такого каталогу або редагуванням файлів у ньому, вам слід перезапустити Okteta, а потім відкрити діалогове вікно параметрів інструменту «Структури». Там слід перейти на вкладку Керування записами структур і переконатися, що відповідний пункт визначення структури позначено. Після цього перейдіть на вкладку Структури і переконайтеся, що бажаний пункт є у списку, розташованому у правій частині вікна.
Якщо потрібна вам структура є досить типовою, ви можете не створювати визначення власноруч, а скористатися готовим визначенням з якогось зі сховищ визначень, зокрема store.kde.org.
Крім того, ви і самі можете поділитися з іншими користувачами вашими визначеннями. Щоб зробити це, створіть файл архіву (наприклад, стиснутий zip архів tar, .tar.gz
), який міститиме лише підкаталог з файлом .desktop
і файлом визначення структури. Якщо скористатися нашим прикладом з попереднього розділу, ваш підкаталог має називатися ExampleStructure
. Якщо ви користуватиметеся саме цим форматом інші користувачі зможуть автоматично отримувати і встановлювати створені вами визначення.
Примітка
Новіші, але трохи неповні настанови щодо створення визначень структур можна знайти у вікі користувачів KDE.
Передбачено два різних способи створення визначень структури. Перший полягає у написанні визначення мовою XML, інший — мовою JavaScript. За допомогою JavaScript можна створювати складніші описи структур, зокрема з перевірками коректності структури. Використання XML звузить набір можливостей, але якщо вам потрібна лише статична структура, цей спосіб буде простішим. Якщо вам слід описати динамічну структуру, наприклад структуру, у якій довжини масивів залежатимуть від інших даних у структурі, або структуру, компонування якої змінюватиметься залежно від значень її компонентів, вам доведеться описувати структуру мовою JavaScript. Єдиним виключенням з цього правила є випадок, коли довжина масиву точно дорівнює іншому значенню структури. У цьому випадку ви можете скористатися XML, але якщо ви маєте для довжини щось подібне до значення - 1, доведеться користуватися JavaScript.
Примітка
Новіші, але трохи неповні настанови щодо створення визначень структур можна знайти у вікі користувачів KDE.
У файла XMLe .osd
є один кореневий теґ: <data> без жодних атрибутів. Всередині цього теґу має бути один з таких теґів:
- <primitive>
Для створення елементарних типів даних, наприклад int або float. Цей теґ не містить підтеґів і може мати такі атрибути:
- type
Тип цього елементарного типу. Має бути одним з таких значень:
char для 8-бітових символів ASCII
int8, int16, int32, int64 для цілих значень відповідного розміру зі знаком
uint8, uint16, uint32, uint64 для додатних цілих чисел відповідного розміру
bool8, bool16, bool32, bool64 для додатних булевих значень (0 = false, всі інші значення = true) відповідного розміру
float для 32-бітових дійсних значень стандарту IEEE754
double для 64-бітових дійсних значень стандарту IEEE754
- <bitfield>
Для створення бітового поля. Цей елемент не містить піделементів і може мати такі атрибути:
- width
Кількість бітів, використаних відповідним бітовим полем. Повинен мати значення від 1 до 64.
- type
Тип бітового поля. Має бути одним з таких записів:
unsigned для бітових полів, значення яких слід вважати додатним (зі значенням у діапазоні від 0 до 2width - 1)
signed для бітових полів, значення яких слід вважати значенням зі знаком (зі значенням від -2width - 1 до 2width - 1 - 1)
bool для бітових полів з булевим значенням
Примітка
Не забувайте додавати символи розриву рядка після <bitfield>, інакше наступний елемент (окрім рядків та масивів, там розрив буде додано автоматично) розпочнеться посередині байта. Звичайно ж, додавання розривів непотрібне, якщо саме така поведінка і є бажаною.
- <enum>
Для створення елементарного типу, значення якого буде, якщо це можливо, показано як нумерований список. Для цього теґу не передбачено підтеґів (але вам потрібен буде теґ <enumDef> у файлі для посилання). Має такі атрибути:
- enum
Нумерований список — основа цього значення. Маж збігатися зі значенням name одного з теґів <enumDef> у цьому файлі.
- type
Тип цього нумерованого списку. Див. атрибут type <primitive>. Єдиною відмінністю є те, що значення Double і Float у цьому випадку позбавлені сенсу.
- <flags>
Те саме, що і <enum>, єдиною відмінністю є те, що значення представлено як побітове «або» для всіх значень нумерованого списку.
- <struct>
Для створення структури. Всі інші теґи (зокрема <struct>) можуть бути дочірніми теґами такої структури, отже будуть частиною отриманої структури.
- <union>
Для створення об’єднання. В основному, те саме, що і <struct>, окрім того, що всі дочірні елементи будуть починатися з однаковим відступом. Корисно для представлення однієї послідовності байтів у різний спосіб.
- <array>
Для створення масиву. У цього теґу має бути один і лише один дочірній теґ (тип елемента масиву), який може визначати будь-який теґ, навіть теґ <array>. Також має такі атрибути:
- length
Кількість елементів у цьому масиві у форматі десяткового числа. Крім того, може мати значення, яке збігається з назвою атрибута попередньо визначеного теґу <primitive>, <enum> або <flags>. У такому разі значенням length вважатиметься значення відповідного теґу. У поточній версії значення обмежено числом 10000, оскільки більші значення призводять до надмірного споживання пам’яті і значно уповільнюють роботу програми.
- <string>
Для створення рядка у певному кодуванні. З атипових значень буде визначено рядок у стилі C, що завершується символом NULL. Інші типи рядків може бути створено за допомогою таких атрибутів:
- terminatedBy
Це атрибут визначає символ unicode, яким має завершуватися рядок. Символ слід вказувати у форматі шістнадцяткового номер у таблиці (з можливим додаванням префікса 0x). Якщо встановлено кодування ASCII, можна використовувати лише значення до 0x7f. Якщо не встановлено ні цього атрибута, ні атрибутів maxCharCount і maxByteCount, вважатиметься, що значенням є 0 (рядок у стилі C).
- maxCharCount
Максимальна кількість символів у рядку. Якщо встановлено також атрибут terminatedBy, рядок буде обірвано за виконання будь-якої з умов. Не можна визначати разом з атрибутом maxByteCount.
- maxByteCount
Максимальна кількість байтів у рядку. Якщо встановлено також атрибут terminatedBy, рядок буде обірвано за виконання будь-якої з умов. Не можна визначати разом з атрибутом maxCharCount. Для кодувань, подібних до ASCII, збігається з maxCharCount.
- type
Кодування цього рядка. Може приймати такі значення:
ASCII
LATIN-1
UTF-8
UTF-16-LE або UTF-16-BE. Якщо не вказано суфікса -LE або -BE, вважатиметься, що кодуванням є -LE (little endian).
UTF-32-LE або UTF-32-BE. Якщо не вказано суфікса -LE або -BE, вважатиметься, що кодуванням є -LE (little endian).
Кожен з елементів містить атрибут name, значення якого буде показано на панелі перегляду структури.
Примітка
Новіші, але трохи неповні настанови щодо створення визначень структур можна знайти у вікі користувачів KDE.
Наш файл метаданих буде таким:
[Desktop Entry] Icon=arrow-up❶ Type=Service ServiceTypes=KPluginInfo Name=Simple test structure Comment=A very simple test structure containing only two items X-KDE-PluginInfo-Author=Alex Richardson X-KDE-PluginInfo-Email=foo.bar@email.org X-KDE-PluginInfo-Name=simplestruct X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website=https://www.plugin.org/ X-KDE-PluginInfo-Category=structure X-KDE-PluginInfo-License=LGPL X-KDE-PluginInfo-EnabledByDefault=false
Піктограма, яку буде показано Okteta для відповідного пункту структури. Можна вказати будь-яку піктограму, яку можна знайти у вікні, яке відкриває команда |
Призначення полів має бути очевидним, окрім поля X-KDE-PluginInfo-Name
. Значення у цьому полі має збігатися з назвою каталогу, у якому зберігається файл, а також назвою файла .desktop
. Під час створення структури XML назва файла .osd
також має збігатися з вказаною назвою.
У нашому прикладі ми маємо каталог з назвою simplestruct
, у якому зберігаються файл simplestruct.desktop
. Якщо структура визначається у форматі XML, у каталозі також має зберігатися файл з назвою simplestruct.osd
. Якщо використано підхід з визначенням JavaScript, матимемо файл з назвою main.js
.
Для початку ми створимо визначення дуже простої структури, що міститиме лише прості типи даних (один символ і одне 32-бітове ціле число (int)). Цю структуру можна записати мовою C/C++ так:
struct simple { char aChar; int anInt; bool bitFlag :1; unsigned padding :7; };
Першим кроком буде створення файла .osd
, який ми назвемо simplestruct.osd
:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<struct name="simple">
<primitive name="aChar" type="Char"/>
<primitive name="anInt" type="Int32"/>
<bitfield name="bitFlag" type="bool" width="1"/>
<bitfield name="padding" type="unsigned" width="7"/>
</struct>
</data>
Цей файл дуже подібний до визначення структури у C/C++.
Тепер створимо підкаталог simplestruct
у каталозі встановлення структури (див. встановлення визначення структури вручну) і скопіюємо два файли до цього каталогу. Тепер можна перезапустити Okteta і спробувати скористатися новою структурою.
Щоб реалізувати наведену вище структуру мовою JavaScript, створіть файл з назвою main.js
замість simplestruct.osd
, і замініть X-KDE-PluginInfo-Category=structure на X-KDE-PluginInfo-Category=structure/js. У файлі мають міститися такі рядки:
function init() { var structure = struct({ aChar : char(), anInt : int32(), bitFlag : bitfield("bool", 1), padding : bitfield("unsigned", 7), }) return structure; }
Структура, показана у вікні Okteta, це завжди значення, яке повертає функція init
.
Для створення типу елемента може бути викликано такі функції:
char()
int8(), int16(), int32() or int64()
uint8(), uint16(), uint32() or uint64()
bool8(), bool16(), bool32() or bool64()
float()
double()
Функція bitfield отримує два параметри. Першим є рядок bool
, signed
або unsigned
. Другим параметром є ціле число, яке встановлює розмір типу у бітах.
Тепер ми створимо визначення складнішої структури, яке назвемо «complex» і збережемо у файлі з назвою complex.osd
. Ця структура міститиме два масиви (один фіксованої довжини і один, у якому довжина визначатиметься під час роботи програми), а також вкладену структуру і об’єднання (union).
<?xml version="1.0" encoding="UTF-8"?>
<data>
<struct name="complex">
<primitive name="size" type="UInt8" />
<union name="aUnion">
<array name="fourBytes" length="4">
<primitive type="Int8" />
</array>
</union>
<struct name="nested">
<array name="string" length="size"> <!-- references the field size above -->
<primitive type="Char" />
</array>
</struct>
</struct>
</data>
Така структура формально визначається у C/C++ так:
struct complex { uint8_t size; union aUnion { int8_t fourBytes[4]; }; struct nested { char string[size] //не відповідає стандартам C++, посилається на значення розмірності uint8 }; };
Примітка
Очевидно, поля посилань на масиви змінної (динамічної) довжини слід вказувати до самого масиву.
Далі, ми створимо файл complex.desktop
, як і у попередньому прикладі (переконайтеся, що значення X-KDE-PluginInfo-Name
змінено відповідним чином), та повторимо дії зі встановлення визначення структури.