Інструмент структур

Загальне

За допомогою інструменту «Структури» можна аналізувати та редагувати масиви байтів на основі створених користувачем визначень структур, які можна побудувати з масивів, об’єднань, елементарних типів та переліків.

Інструмент має власне діалогове вікно параметрів, відкрити яке можна за допомогою натискання кнопки Параметри. Передбачено досить багато параметрів налаштування, зокрема стиль (десяткові, шістнадцяткові або двійкові), у якому буде показано значення. Крім того, можна визначити, які визначення структур буде завантажено і які структури буде показано.

Структури визначаються за допомогою файлів визначення структур Okteta (XML-файлах, з суфіксом назви .osd). Крім того, потрібен файл .desktop, що містить метадані щодо файла опису структури, зокрема відомості щодо автора, домашньої сторінки та умов ліцензування.

У поточній версії програми ще немає вбудованої підтримки створення або редагування визначень структур, отже все це слід робити вручну у спосіб, описаний у наступних розділах.

Встановлення визначень структур

Встановлення за допомогою KNewStuff

Найпростішим способом встановлення нових визначень структур є використання вбудованої підтримки KNewStuff у Okteta. Щоб встановити існуючу структуру, відкрийте діалогове вікно інструменту «Структури». Перейдіть на вкладку Керування структурами і натисніть кнопку Отримати нові структури.... За допомогою діалогового вікна, яке буде відкрито, ви зможете встановити або вилучити встановлені визначення структур.

Встановлення визначень структур вручну

Інструмент «Структури» шукає описи структур у підкаталозі okteta/structures/ каталогу даних програм користувача (визначити адресу цього каталогу можна за допомогою команди qtpaths --paths GenericDataLocation). Якщо ще не встановлено жодного визначення структури, можливо, вам доведеться створити відповідний підкаталог.

Дані кожного визначення структури має бути розподілено між двома файлами: один з файлів міститиме дані самого визначення, а інший файл, .desktop, зберігатиме метадані (дані щодо автора, версії тощо).

У цьому каталозі має бути підкаталог для кожного з визначень структури, у якому мають зберігатися обидва файла визначення: файл .desktop і файл .osd або main.js.

Наприклад, якщо каталогом даних програм є qtpaths --paths GenericDataLocation, а визначення структури має назву ExampleStructure, має бути каталог 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.

Формат файлів визначення структури XML

Примітка

Новіші, але трохи неповні настанови щодо створення визначень структур можна знайти у вікі користувачів 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, значення якого буде показано на панелі перегляду структури.

Зразок визначення структури мовами XML і JavaScript

Примітка

Новіші, але трохи неповні настанови щодо створення визначень структур можна знайти у вікі користувачів 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 для відповідного пункту структури. Можна вказати будь-яку піктограму, яку можна знайти у вікні, яке відкриває команда kdialog --geticon, або адресу файла піктограми

Призначення полів має бути очевидним, окрім поля X-KDE-PluginInfo-Name. Значення у цьому полі має збігатися з назвою каталогу, у якому зберігається файл, а також назвою файла .desktop. Під час створення структури XML назва файла .osd також має збігатися з вказаною назвою.

У нашому прикладі ми маємо каталог з назвою simplestruct, у якому зберігаються файл simplestruct.desktop. Якщо структура визначається у форматі XML, у каталозі також має зберігатися файл з назвою simplestruct.osd. Якщо використано підхід з визначенням JavaScript, матимемо файл з назвою main.js.

Просте визначення структури у форматі XML

Для початку ми створимо визначення дуже простої структури, що міститиме лише прості типи даних (один символ і одне 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

Щоб реалізувати наведену вище структуру мовою 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 змінено відповідним чином), та повторимо дії зі встановлення визначення структури.

Докладніші відомості

Декілька прикладів визначень структур можна знайти тут. Серед цих прикладів є файл заголовка для файлів PNG і заголовка файла ELF. Схема XML, яка описує структуру файла .osd, зберігається тут. Якщо вам потрібні якісь додаткові відомості, зверніться до автора за адресою