Ferramenta de Estruturas

Geral

A ferramenta de Estruturas permite a análise e edição de sequências de 'bytes' com base na definição de estruturas criadas pelo usuário, as quais poderão ser compostas por listas, uniões, tipos primitivos e enumerados.

Ela tem uma janela de configuração própria, que poderá ser acessada com o botão Configurações. Existem várias opções que poderão ser configuradas, como o estilo (decimal, hexadecimal ou binário) no qual são apresentados os valores. Além disso, é possível escolher as definições de estruturas que são carregadas e quais são apresentadas na janela.

As estruturas são definidas nos arquivos de Definição de Estruturas do Okteta (baseados em XML, com a extensão .osd). Além disso, um arquivo .desktop contém os metadados sobre esse arquivo de descrição de estruturas, como o autor, o site e a licença.

Atualmente, não existe nenhum suporte incorporado para criar ou editar as definições das estruturas, assim elas deverão ser criadas manualmente, como se encontra descrito nas seções a seguir.

Instalar as definições das estruturas

Instalar através do KNewStuff

A forma mais simples de instalar novas definições de estruturas é usar o suporte incorporado do KNewStuff no Okteta. Para instalar uma estrutura existente, abra a janela de configuração da ferramenta de Estruturas. Aí, selecione a página de Gerenciamento de estruturas e pressione no botão Obter estruturas novas.... A janela que aparecerá permite-lhe então instalar ou desinstalar estruturas.

Instalar as definições das estruturas manualmente

A ferramenta de Estruturas procura pelas descrições de estruturas na subpasta okteta/structures/ da pasta pessoal do usuário para os dados dos aplicativos (descubra-a com o comando qtpaths --paths LocalGenericoDeDados). Talvez você precise criar essa pasta, caso ainda não tenha nenhuma definição de estrutura instalada.

Existem dois arquivos para cada definição de estrutura. Um arquivo para a definição em si e um arquivo .desktop para os metadados (autor, versão, etc).

Nessa pasta, existe uma subpasta para cada definição de estruturas, a qual contém tanto o arquivo .desktop como o .osd ou o main.jspara essa definição.

Por exemplo, com a pasta de dados dos aplicativos qtpaths --paths LocalGenericoDeDados e com uma definição de estrutura chamada EstruturaExemplo, existe a pasta okteta/structures/EstruturaExemplo, que contém um arquivo EstruturaExemplo.desktop e um arquivo EstruturaExemplo.osd.

Usar as estruturas recém instaladas

Após ter instalado uma nova definição de estruturas, você poderá ter que reiniciar o Okteta antes de poder usá-lo. Após ter reiniciado o Okteta, abra a janela de configurações da ferramenta de Estruturas. Nela, selecione a página de Gerenciamento das estruturas e certifique-se que a definição da estrutura relevante é assinalada. Depois, mude para a página Estruturas e certifique-se de que o elemento desejado está listado no lado direito.

Compartilhar definições de estruturas

Para as estruturas comuns, você poderá não ter que criar você mesmo uma definição, mas sim reutilizar uma definição já existente de locais como o store.kde.org.

Você poderá também querer compartilhar você mesmo uma definição. Para fazer isso, crie um pacote de arquivos (por exemplo, um pacote compactado do tar, .tar.gz) contendo apenas a subpasta com o arquivo .desktop e o arquivo de definição da estrutura. No exemplo da última seção, seria a subpasta EstruturaExemplo com todo o seu conteúdo. Usando este formato para compartilhar definições de estruturas será possível instalá-las no Okteta e não irá exigir uma instalação manual.

Criar definições de estruturas

Nota

Existe um guia mais atualizado, mas não completo, sobre a criação de definições de estruturas na Wiki do KDE UserBase.

Existem duas maneiras diferentes de criar definições de estrutura. A primeira é escrever a definição em XML e a outra é usar JavaScript. A abordagem com JavaScript permite-lhe criar estruturas mais complexas com funcionalidades como, por exemplo, validação da estrutura. Usar XML oferece menos recursos, mas se uma estrutura estática é tudo que você precisa, pode ser a abordagem mais fácil. Se você precisar de uma estrutura dinâmica, ou seja, onde as dimensões de uma matriz dependem de outros valores na estrutura ou o layout da estrutura é diferente quando o valor de algum membro se altera, então você terá que escrever a definição da estrutura em JavaScript. Não há exceções a esta regra. Se você tiver uma matriz cujo comprimento deve ser exatamente o mesmo de acordo com outro valor na estrutura, então você pode usar XML. Mas se for algo como comprimento - 1 deve-se usar JavaScript.

Formato do arquivo XML da definição da estrutura

Nota

Existe um guia mais atualizado, mas não completo, sobre a criação de definições de estruturas na Wiki do KDE UserBase.

O arquivo XML .osd possui um elemento raiz: <data> sem atributos. Dentro deste elemento deve existir um dos seguintes elementos:

<primitive>

Para criar tipos de dados primitivos, como por exemplo, int e float. Este elemento não aceita subelementos e pode ter os seguintes atributos:

type

O tipo deste tipo primitivo. Deve ser um dos seguintes:

  • char para caracteres ASCII de 8 bits

  • int8, int16, int32, int64 para inteiros com sinal com os tamanhos respectivos

  • uint8, uint16, uint32, uint64 para inteiros sem sinal com os tamanhos respectivos

  • bool8, bool16, bool32, bool64 para booleanos sem sinal (0 = falso, qualquer outro valor = verdadeiro) com o tamanho respectivo

  • float para números de vírgula flutuante IEEE754 de 32 bits

  • double para números de vírgula flutuante IEEE754 de 64 bits

<bitfield>

Para criar um campo de bits. Este elemento não aceita subelementos e pode ter os seguintes atributos:

width

O número de bits usado por este campo de bits. Deve ser entre 1 e 64.

type

O tipo deste campo de bits. Deve ser um dos seguintes:

  • unsigned para um campo de bits onde o valor será interpretada como um valor sem sinal (intervalo de 0 à 2width - 1)

  • signed para o campo de bits onde o valor será interpretado como um valor com sinal (intervalo de -2width - 1 à 2width - 1 - 1)

  • bool para um campo de bits onde o valor será interpretado como um valor booleano

Nota

Lembre-se sempre de adicionar um separador após um <bitfield>, uma vez que caso contrário o próximo elemento (exceto para textos e matrizes, que adicionam separadores automaticamente) iniciará no meio de um byte. Obviamente o separador não é necessário se você deseja este comportamento.

<enum>

Para criar um tipo primitivo, mas onde os valores são exibidos como membros de uma enumeração se possível. Este elemento não aceita subelementos (no entanto, você precisará de uma marca <enumDef> no arquivo para referenciá-lo). Ele tem os seguintes atributos:

enum

A enumeração subjacente para este valor. Deve corresponder ao atributo name de uma das marcas <enumDef> neste arquivo.

type

O tipo desta enumeração. Veja o atributo de tipo de <primitive>. A única diferença é que o Double e o Float não fazem sentido.

<flags>

Isto é o mesmo que <enum> com a única diferença sendo que os valores são representados como um bitwise-or de todos os valores da enumeração.

<struct>

Para criar uma estrutura. Todos os outros elementos (incluindo o <struct>) podem ser filhos deste e então serão parte da estrutura resultante

<union>

Para criar uma união. Basicamente, o mesmo que <struct> exceto pelo fato que todos os elementos filho iniciarão a partir do mesmo deslocamento. Útil para interpretar a mesma sequência de bytes de várias maneiras.

<array>

Para criar uma matriz. Este elemento aceita exatamente um filho (o tipo subjacente da matriz), que pode ser qualquer dos elementos, até mesmo a <array> em si. Ele possui os seguintes atributos:

length

O número de elementos nesta matriz como um número decimal. Alternativamente, ele pode também ser um texto que corresponde ao atributo nome de um elemento <primitive>, <enum> ou <flags> previamente definido. Então o comprimento será o valor deste elemento. Atualmente está limitado à 10000, porque matrizes maiores usariam muita memória e tornariam esta ferramenta muito lenta.

<string>

Para criar um texto em várias codificações. Por padrão, você obtém um texto terminado em NULL no estilo C. No entanto, diferentes tipos de texto podem ser criados com os seguintes atributos:

terminatedBy

Este atributo determina com que ponto de código unicode o texto é terminado. Deve ser um número hexadecimal (opcionalmente com um prefixo 0x). Quando a codificação for ASCII, somente valores até o 0x7f são significativos. Se isto, maxCharCount ou maxByteCount estão definidos, isto é considerado como 0 (texto no estilo C)

maxCharCount

O número máximo de caracteres que este texto pode ter. Se terminatedBy estiver definido então o que for atingido primeiro termina o texto. Isto é mutualmente exclusivo com o maxByteCount

maxByteCount

O número máximo de bytes que o texto pode ter. Se terminatedBy estiver definido também, então o que for atingido primeiro termina o texto. Isto é mutualmente exclusivo com maxCharCount. Com codificações como ASCII isto é o mesmo que maxCharCount.

type

A codificação do texto. Pode ser uma das seguintes:

  • ASCII

  • LATIN-1

  • UTF-8

  • UTF-16-LE ou UTF-16-BE. Se os sufixos -LE ou -BE não forem fornecidos, o little endian é considerado.

  • UTF-32-LE ou UTF-32-BE. Se os sufixos -LE ou -BE não forem fornecidos, o little endian é considerado.

Cada elemento também aceita um atributo name que é então visível na visão de estruturas.

Um exemplo de definição de estrutura em XML e JavaScript

Nota

Existe um guia mais atualizado, mas não completo, sobre a criação de definições de estruturas na Wiki do KDE UserBase.

O passos comum, compartilhado por ambas as abordagens

Nosso arquivo de metadados se parece com isto:

        [Desktop Entry]
        Icon=arrow-up❶
        Type=Service
        ServiceTypes=KPluginInfo

        Name=Estrutura simples de teste
        Comment=Uma estrutura de teste simples contendo apenas dois itens

        X-KDE-PluginInfo-Author=Alex Richardson
        X-KDE-PluginInfo-Email=foo.bar@email.org
        X-KDE-PluginInfo-Name=estruturasimples
        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
        

O ícone exibido no Okteta para esta estrutura. Pode ser qualquer coisa encontrada na execução do kdialog --geticon ou o caminho para um ícone

Estes campos devem parecer bem auto-explicativos, exceto pelo X-KDE-PluginInfo-Name. O valor deste campo deve corresponder ao nome da pasta que contém o arquivo bem como o nome do arquivo .desktop. Ao cria as definições de estrutura em XML o nome do arquivo .osd deve também corresponder ao nome.

Neste exemplo, teríamos uma pasta chamada estruturasimples que contém os arquivos estruturasimples.desktop. Ao definir as estruturas em XML, a pasta iria conter também um arquivo chamado estruturasimples.osd. Se usarmos o JavaScript, iríamos ter um arquivo chamado main.js em alternativa.

Uma definição de estrutura XML simples

Para começar, vamos criar uma definição para uma estrutura de testes muito simples, contendo apenas tipos de dados primitivos (um caractere, um inteiro de 32 bits com sinal e um campo de bits). Isto poderia ser uma expresso em C/C++ como:

          struct simple {
            char aChar;
            int anInt;
            bool bitFlag :1;
            unsigned padding :7;
          };
          

O primeiro passo é escrever o arquivo .osd de acordo com o formato de arquivo definido na seção anterior. Nós o chamaremos de estruturasimples.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>
          

que é bastante similar a uma definição em C/C++.

Agora crie uma pasta estruturasimples dentro da pasta de instalação da estrutura (veja como instalar manualmente definições de estruturas) e copie os dois arquivos para esta pasta. Agora você pode reiniciar o Okteta, para poder usar a nova estrutura.

Uma estrutura simples em JavaScript

Para implementar a estrutura acima em JavaScript, crie um arquivo chamado main.js em vez de estruturasimples.osd e altere o 'X-KDE-PluginInfo-Category=structure' para 'X-KDE-PluginInfo-Category=structure/js'. O conteúdo desse arquivo deverá ser:

        function init() {
          var estrutura = struct({
            caracter : char(),
            inteiro : int32(),
            opcaoBit : bitfield("bool", 1),
            preenchimento : bitfield("unsigned", 7),
          })
          return estrutura;
        }
        

A estrutura apresentada pelo Okteta é sempre o valor devolvido pela função init.

As seguintes funções poderão ser invocadas para criar um tipo primitivo:

  • char()

  • int8(), int16(), int32() ou int64()

  • uint8(), uint16(), uint32() ou uint64()

  • bool8(), bool16(), bool32() ou bool64()

  • float()

  • double()

A função 'bitfield' recebe dois parâmetros, sendo o primeiro um texto que consiste em bool, signed ou unsigned. O segundo parâmetro é um inteiro que define o tamanho em 'bits'.

Estruturas mais complexas

A seguir, iremos criar uma estrutura mais complexa, que irá se chamar "complexa" e salvá-la num arquivo complexa.osd. Esta estrutura irá conter duas listas (uma de tamanho fixo e outra com o tamanho determinado durante a execução), assim como uma estrutura encadeada e uma união.


          <?xml version="1.0" encoding="UTF-8"?>
          <data>
            <struct name="complexa">
              <primitive name="tamanho" type="UInt8" />
              <union name="umaUniao">
                <array name="quatroBytes" length="4">
                  <primitive type="Int8" />
                </array>
              </union>
              <struct name="encadeado">
                <array name="texto" length="tamanho"> <!-- referencia o campo 'tamanho' acima -->
                  <primitive type="Char" />
                </array>
              </struct>
            </struct>
          </data>
          

Isto irá corresponder ao seguinte, em pseudo-C/C++

struct complexa {
            uint8_t tamanho;
            union umaUniao {
              int8_t quatroBytes[4];
            };
            struct encadeado {
              char texto[tamanho] //C++ não válido por referenciar o valor de 'tamanho'
            };
          };
          

Nota

Obviamente, você só poderá ter campos de referência de listas de tamanho dinâmico antes da lista.

A seguir, será criado o arquivo complexo.desktop, como foi feito no exemplo anterior (certifique-se de que define o X-KDE-PluginInfo-Name corretamente) e faça o mesmo para instalar ambos os arquivos.

Mais informações

Alguns exemplos de definições de estruturas poderão ser encontrados no repositório Git. Isso inclui, por exemplo, o cabeçalho dos arquivos PNG e ELF. Um esquema em XML que descreve a estrutura do arquivo .osd pode ser encontrado aqui. Se precisar de mais informações, sinta-se à vontade em contactar-me através do e-mail