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 utilizador, as quais poderão ser compostas por listas, uniões, tipos primitivos e enumerados.

Tem uma janela de configuração própria, que poderá ser acedida com o botão Configuração. 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. Para 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 ficheiros de Definição de Estruturas do Okteta (baseados em XML, com a extensão .osd). Para além disso, um ficheiro .desktop contém os meta-dados acerca desse ficheiro de descrição de estruturas, como o autor, a página Web e a licença.

De momento, não existe nenhum suporte incorporado para criar ou editar as definições das estruturas, pelo que estas deverão ser criadas manualmente, como se encontra descrito nas secções seguintes.

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í, seleccione a página de Gestão de Estruturas e carregue no botão Obter Estruturas Novas.... A janela que aparecerá permite-lhe então instalar ou desinstalar estruturas.

Instalar manualmente as definições das estruturas

A ferramenta de Estruturas procura pelas descrições de estruturas na sub-pasta okteta/structures/ da pasta do utilizador para os dados das aplicações (descubra-a com o comando qtpaths --path GenericDataLocation). Poderá ter de criar esta pasta, caso não existam ainda nenhumas definições de estruturas instaladas.

Existem dois ficheiros para cada definição da estrutura: Um ficheiro para a definição em si e um ficheiro .desktop para os meta-dados (autor, versão, etc.).

Nessa sub-pasta, existe uma sub-pasta própria para cada definição de estruturas, a qual contém tanto o ficheiro .desktop como o .osd ou o main.js para essa definição.

Por exemplo, com a pasta de dados das aplicações qtpaths --paths GenericDataLocation e com uma definição de estrutura chamada EstruturaExemplo, existe a pasta okteta/structures/EstruturaExemplo, que contém um ficheiro EstruturaExemplo.desktop e um ficheiro EstruturaExemplo.osd.

Usar as estruturas acabadas de instalar

Se tiver instalado uma nova definição de estruturas, poderá ter de reiniciar o Okteta e abrir a janela de configuração da ferramenta de Estruturas. Aí, seleccione a página de Gestão das Estruturas e certifique-se que a definição da estrutura relevante é assinalada. Depois, mude para a página Estruturas e certifique-se que o elemento desejado está listado no lado direito.

Partilhar definições de estruturas

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

Poderá também querer partilhar você mesmo uma definição. Para o fazer, crie um pacote de ficheiros (isto é, um pacote tar.gz ou .tgz) contendo apenas a sub-pasta com o ficheiro .desktop e o ficheiro de definição da estrutura. No exemplo da última secção, seria a sub-pasta EstruturaExemplo com todo o seu conteúdo. Se usar este formato para partilhar as definições de estruturas, permite a instalação das mesmas dentro do Okteta sem qualquer instalação manual.

Criar definições de estruturas

Nota

Poderá encontrar um guia mais actualizado, mas não completo, sobre a criação de definições de estruturas na Wiki de Base de Utilizadores do KDE.

Existem duas formas diferentes de criar definições de estruturas. O primeiro é criar a definição em XML e o outro é usando o JavaScript. A abordagem do JavaScript permite-lhe criar estruturas mais complexas com funcionalidades como p.ex. a validação da estrutura. A utilização do XML dá-lhe menos funcionalidades, mas se tudo o que precisar for uma estrutura estática, esta poderá ser a abordagem mais simples. Se necessitar de uma estrutura dinâmica, i.e., onde os tamanhos das listas dependem de outros valores na estrutura ou se a disposição da estrutura for diferente quando algum valor-membro mudar, então terá de criar a definição da estrutura em JavaScript. Existe uma excepção a essa regra: se tiver uma lista cujo tamanho é suposto ser exactamente igual a outro valor na estrutura, então poderá usar o XML. Contudo, se existir algo do tipo tamanho - 1, terá então de ser em JavaScript.

Formato do ficheiro XML de definição de estruturas

Nota

Poderá encontrar um guia mais actualizado, mas não completo, sobre a criação de definições de estruturas na Wiki de Base de Utilizadores do KDE.

O ficheiro XML .osd tem um elemento de raiz: o <data> sem quaisquer atributos. Dentro deste elemento, deverá existir um dos seguintes elementos:

<primitive>

Para criar um tipo de dados primitivo como isto é o int e float. Este elemento não aceita sub-elementos e poderá ter os seguintes atributos:

type

O tipo primitivo em si. Deverá ser um dos seguintes:

  • char para um carácter ASCII a 8 bits

  • int8, int16, int32, int64 para um número inteiro com sinal do tamanho indicado

  • uint8, uint16, uint32, uint64 para um número inteiro sem sinal do tamanho indicado

  • bool8, bool16, bool32, bool64 para um valor boolean sem sinal (0 = falso, qualquer outro valor = verdadeiro) do tamanho indicado

  • float para um número de vírgula-flutuante IEEE754 a 32 bits

  • double para um número de vírgula-flutuante IEEE754 a 64 bits

<bitfield>

Para criar um campo de 'bits'. Este elemento não aceita sub-elementos e poderá ter os seguintes atributos:

width

O número de 'bits' usados por este campo de 'bits'. Deverá ser entre 1 e 64.

type

O tipo deste campo de 'bits'. Deverá ser um dos seguintes:

  • unsigned para um campo de 'bits' em que o valor será interpretado como um valor sem sinal (com uma gama de 0 a 2width - 1)

  • signed para um campo de 'bits' em que o valor será interpretado como um valor com sinal (com uma gama de -2width - 1 a 2width - 1 - 1)

  • bool para um campo de 'bits' em que o valor será interpretado como booleano

Nota

Lembre-se sempre de adicionar algum preenchimento a seguir a um <bitfield>, caso contrário o elemento seguinte (exceptuando as cadeias de caracteres e as listas, por adicionarem um preenchimento automático) irão começar a meio de um 'byte'. Obviamente, o preenchimento não é necessário se desejar este comportamento.

<enum>

Para criar um tipo primitivo, mas em que os valores sejam apresentados como membros de uma enumeração, se possível. Este elemento não aceita sub-elementos (contudo, poderá necessitar de uma marca <enumDef> no ficheiro para a referenciar). Tem os seguintes atributos:

enum

O tipo enumerado subjacente deste valor. Deverá corresponder ao atributo name de uma das marcas <enumDef> neste ficheiro.

type

O tipo deste valor enumerado. Veja o atributo 'type' de <primitive>. A única diferença é que o Double e o Float não fazem aqui sentido.

<flags>

Este é igual ao <enum>, com a única diferença em que os valores são representados como um OU-de-bits com todos os valores da enumeração.

<struct>

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

<union>

Para criar uma união. Basicamente, é igual ao <struct>, com a diferença que todos os elementos-filhos começam na mesma posição. Útil para interpretar a mesma sequência de 'bytes' de várias formas.

<array>

Para criar uma lista. Este elemento aceita exactamente um filho (o tipo inerente da lista), que poderá ser qualquer elemento, até mesmo o próprio <array>. Também tem os seguintes atributos:

length

O número de elementos desta lista, como um número decimal. Em alternativa, também poderá ser um texto que corresponda ao valor do atributo 'name' de um elemento <primitive>, <enum> ou <flags> previamente definido. Aí, o tamanho será o valor desse elemento. De momento, está limitado a 10000, porque as listas maiores irão usar demasiada memória e tornariam a ferramenta demasiado lenta.

<string>

Para criar uma cadeia de caracteres com várias codificações. Por omissão, irá obter uma cadeia de caracteres terminada em NULL, como no C. Contudo, poderá criar vários tipos de cadeias de caracteres com os seguintes atributos:

terminatedBy

Este atributo define qual o código Unicode com que termina o texto. Deverá ser um número hexadecimal (opcionalmente com um 0x inicial). Quando a codificação for a ASCII, só fazem sentido valores até 0x7f. Se nem este valor nem os valores de maxCharCount ou maxByteCount estiverem definidos, assume-se como sendo 0 (como no C).

maxCharCount

O número máximo de caracteres que esta cadeia de caracteres poderá ter. Se o terminatedBy também estiver definido, então o que ocorrer primeiro corresponderá ao fim do texto. Isto é mutuamente exclusivo com o maxByteCount

maxByteCount

O número máximo de 'bytes' que este texto poderá ter de tamanho. Se o terminatedBy também estiver definido, então o que ocorrer primeiro irá definir o fim do texto. Isto é mutuamente exclusivo com o maxCharCount. Com as codificações como a ASCII, este valor é igual ao de maxCharCount.

type

A codificação desta cadeia de caracteres. Poderá ser um dos seguintes valores:

  • ASCII

  • LATIN-1

  • UTF-8

  • UTF-16-LE ou UTF-16-BE. Se nem o sufixo -LE nem o -BE forem indicados, assume-se o 'little endian'.

  • UTF-32-LE ou UTF-32-BE. Se nem o sufixo -LE nem o -BE forem indicados, assume-se o 'little endian'.

Todos os elementos aceitam também um atributo name que ficará visível na área de estruturas.

Uma definição de estrutura de exemplo tanto em XML como em JavaScript

Nota

Poderá encontrar um guia mais actualizado, mas não completo, sobre a criação de definições de estruturas na Wiki de Base de Utilizadores do KDE.

O passos comum, partilhado por ambas as abordagens

Os nossos meta-dados ficarão algo do género:

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

        Name=Estrutura de testes simples
        Comment=Uma estrutura muito simples de testes que só contém dois itens

        X-KDE-PluginInfo-Author=José Pires
        X-KDE-PluginInfo-Email=jose.pires@email.org
        X-KDE-PluginInfo-Name=estrutura-simples
        X-KDE-PluginInfo-Version=1.0
        X-KDE-PluginInfo-Website=http://www.plugin.org/
        X-KDE-PluginInfo-Category=structure
        X-KDE-PluginInfo-License=LGPL
        X-KDE-PluginInfo-EnabledByDefault=false
        

O ícone que aparece no Okteta para esta estrutura poderá ser qualquer coisa devolvida pela execução de kdialog --geticon ou a localização de um ícone

Estes campos deverão ser relativamente intuitivos, exceptuando o X-KDE-PluginInfo-Name. O valor deste campo deverá corresponder ao nome da pasta que contém o ficheiro, assim como o nome do ficheiro .desktop. Ao criar as definições de estruturas em XML, o nome do ficheiro .osd deverá também corresponder ao nome.

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

Uma definição de estrutura simples em XML

Para começar, iremos criar uma definição de uma estrutura de testes muito simples, contendo apenas tipos de dados integrais (um carácter, um inteiro com sinal de 32 bits e um campo de bits). Isto seria descrito em C/C++ como:

          struct simples {
            char umCaracter;
            int umInteiro;
            bool campoBits :1;
            unsigned preenchimento :7;
          };
          

O primeiro passo é criar o ficheiro .osd de acordo com o formato do ficheiro definido na secção anterior. Iremos chamar ao ficheiro estrutura-simples.osd:


          <?xml version="1.0" encoding="UTF-8"?>
          <data>
            <struct name="simple">
              <primitive name="umCaracter" type="Char"/>
              <primitive name="umInteiro" type="Int32"/>
              <bitfield name="campoBits" type="bool" width="1"/>
              <bitfield name="preenchimento" type="unsigned" width="7"/>
            </struct>
          </data>
          

, o que corresponderá de certa forma à definição em C/C++.

Agora crie uma sub-pasta estrutura-simples como descrito acima, copie os dois ficheiros para esta pasta e reinicie o Okteta, para poder usar a nova estrutura.

A estrutura simples em JavaScript

Para implementar a estrutura acima em JavaScript, crie um ficheiro chamado main.js em vez de simplestruct.osd e mude o texto 'X-KDE-PluginInfo-Category=structure' para 'X-KDE-PluginInfo-Category=structure'. O conteúdo desse ficheiro seria:

        function init() {
          var estrutura = struct({
            carácter : 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.

Poderá invocar as seguintes funções 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

De seguida, iremos criar uma estrutura mais complexa, que se irá chamar "complexa" e gravá-la num ficheiro 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, só poderá ter campos de referência de listas de tamanho dinâmico antes da lista.

Depois, será criado o ficheiro complexo.desktop, como foi feito no exemplo anterior (certifique-se que define o X-KDE-PluginInfo-Name correctamente) e faça o mesmo para instalar ambos os ficheiros.

Mais informações

Poderá encontrar alguns exemplos de definições de estruturas aqui. Isto inclui, por exemplo, o cabeçalho dos ficheiros PNG. Poderá encontrar um esquema em XML que descreve a estrutura do ficheiro .osd aqui. Se precisar de mais informações, sinta-se à vontade em contactar-me em