Mudanças entre as edições de "Compilador ASN1"
Linha 49: | Linha 49: | ||
A nova API foi denominada ASN1++, e pode ser obtida em: | A nova API foi denominada ASN1++, e pode ser obtida em: | ||
− | * [http://tele.sj.ifsc.edu.br/~msobral/ptc/asn1++.tgz API ASN1++] | + | * [http://tele.sj.ifsc.edu.br/~msobral/ptc/asn1++-v1.tgz API ASN1++] |
Linha 79: | Linha 79: | ||
BEGIN | BEGIN | ||
+ | Teste ::= ENUMERATED {um, dois, tres} | ||
+ | |||
Ativo ::= SEQUENCE { | Ativo ::= SEQUENCE { | ||
nome PrintableString (SIZE(1..16)), | nome PrintableString (SIZE(1..16)), | ||
codigo INTEGER, | codigo INTEGER, | ||
− | valor INTEGER, | + | valor SEQUENCE OF INTEGER, |
data NumericString(SIZE(8)), | data NumericString(SIZE(8)), | ||
− | horario NumericString (SIZE(6)) | + | horario NumericString (SIZE(6)), |
+ | cod Teste, | ||
+ | conteudo CHOICE { | ||
+ | ex Extra, | ||
+ | ot Outro, | ||
+ | mais PrintableString (SIZE(2..8)), | ||
+ | num INTEGER | ||
+ | } | ||
+ | } | ||
+ | |||
+ | Extra ::= SEQUENCE { | ||
+ | id INTEGER, | ||
+ | desc PrintableString | ||
+ | } | ||
+ | |||
+ | Outro ::= SEQUENCE { | ||
+ | id INTEGER, | ||
+ | valor INTEGER | ||
} | } | ||
END | END | ||
+ | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Linha 121: | Linha 141: | ||
{{collapse top|Programa de teste}} | {{collapse top|Programa de teste}} | ||
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
+ | #include <parser_ativo.h> | ||
#include <iostream> | #include <iostream> | ||
#include <fstream> | #include <fstream> | ||
− | |||
− | |||
− | |||
− | |||
using namespace std; | using namespace std; | ||
int main() { | int main() { | ||
− | + | TAtivo pkt; | |
− | |||
− | // | + | // definindo os valores de varios campos |
− | + | pkt.set_codigo(35123); | |
− | + | pkt.set_nome( "PETR3"); | |
− | + | pkt.set_data("30092015"); | |
− | + | pkt.set_horario("135812"); | |
− | |||
− | // | + | // este campo "cod" é do tipo enumerated "Teste" |
− | + | pkt.set_cod(Teste_um); | |
− | |||
− | // | + | // "valor" é um campo do tipo sequence of, e pode ser |
− | + | // definido usando um vector ... | |
− | + | vector<long> v; | |
+ | v.push_back(111); | ||
+ | v.push_back(222); | ||
+ | pkt.set_valor(v); | ||
− | // | + | // "conteudo" é um choice ... aqui se escolhe seu campo "ot" |
− | + | // que é do tipo TOutro (um sequence) | |
− | + | TAtivo::Choice_conteudo & con = pkt.get_conteudo(); | |
+ | TOutro ot = con.get_ot(); | ||
+ | ot.set_id(777); | ||
+ | ot.set_valor(999); | ||
// verifica se os valores contidos na estrutura de dados respeitam | // verifica se os valores contidos na estrutura de dados respeitam | ||
Linha 158: | Linha 178: | ||
// mostra a estrutura de dados na tela | // mostra a estrutura de dados na tela | ||
− | cout << "Estrutura de dados em memória (antes de codificação | + | cout << "Estrutura de dados em memória (antes de codificação XER):" << endl; |
pkt.show(); | pkt.show(); | ||
// cria o codificador | // cria o codificador | ||
ofstream out("pkt.data"); | ofstream out("pkt.data"); | ||
− | + | TAtivo::XerSerializer encoder(out); | |
// codifica a estrutura de dados | // codifica a estrutura de dados | ||
encoder.serialize(pkt); | encoder.serialize(pkt); | ||
out.close(); | out.close(); | ||
− | |||
// cria o decodificador | // cria o decodificador | ||
ifstream arq("pkt.data"); | ifstream arq("pkt.data"); | ||
− | + | TAtivo::XerDeserializer decoder(arq); | |
// tenta decodificar uma estrutura de dados | // tenta decodificar uma estrutura de dados | ||
− | + | TAtivo * other = decoder.deserialize(); | |
arq.close(); | arq.close(); | ||
Linha 181: | Linha 200: | ||
if (other) { | if (other) { | ||
− | cout << "Estrutura de dados obtida da decodificação | + | cout << "Estrutura de dados obtida da decodificação XER:" << endl; |
other->show(); | other->show(); | ||
} else cerr << "Erro: não consegui decodificar a estrutura de dados ..." << endl; | } else cerr << "Erro: não consegui decodificar a estrutura de dados ..." << endl; | ||
− | + | ||
+ | // devem-se destruir explicitamente as estruturas de dados obtidas | ||
+ | // do decodificador | ||
+ | delete other; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Linha 201: | Linha 223: | ||
<syntaxhighlight lang=bash> | <syntaxhighlight lang=bash> | ||
aluno@M2:~$ build/demo | aluno@M2:~$ build/demo | ||
− | Estrutura de dados em memória (antes de codificação | + | Estrutura de dados em memória (antes de codificação XER): |
Ativo ::= { | Ativo ::= { | ||
nome: PETR3 | nome: PETR3 | ||
codigo: 35123 | codigo: 35123 | ||
− | valor: | + | valor: valor ::= { |
+ | 111 | ||
+ | 222 | ||
+ | } | ||
data: 30092015 | data: 30092015 | ||
horario: 135812 | horario: 135812 | ||
+ | cod: 0 | ||
+ | conteudo: Outro ::= { | ||
+ | id: 777 | ||
+ | valor: 999 | ||
+ | } | ||
} | } | ||
− | Estrutura de dados obtida da decodificação | + | Estrutura de dados obtida da decodificação XER: |
Ativo ::= { | Ativo ::= { | ||
nome: PETR3 | nome: PETR3 | ||
codigo: 35123 | codigo: 35123 | ||
− | valor: | + | valor: valor ::= { |
+ | 111 | ||
+ | 222 | ||
+ | } | ||
data: 30092015 | data: 30092015 | ||
horario: 135812 | horario: 135812 | ||
+ | cod: 0 | ||
+ | conteudo: Outro ::= { | ||
+ | id: 777 | ||
+ | valor: 999 | ||
+ | } | ||
} | } | ||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Edição das 14h00min de 23 de novembro de 2015
O compilador ASN1 desenvolvido por Lev Walkin traduz as especificações ASN1 para linguagem C, além de prover uma biblioteca para codificação e decodificação. Ele é compatível com ASN.1 rev. 2002. Há duas formas de utilizá-lo:
- Obtendo seu código-fonte, e realizando sua compilação e instalação
- Acessando sua versão online
O resultado da compilação ASN1 é um conjunto de arquivos em código-fonte C, contendo a definição dos tipos de dados criados com ASN1 e as funções auxiliares para usar esses tipos de dados e realizar codificação e decodificação. Por exemplo, ao compilar esta especificação ASN1:
Exemplo DEFINITIONS ::=
BEGIN
Mensagem ::= SEQUENCE {
nome PrintableString,
cod INTEGER,
oid OBJECT IDENTIFIER,
flags BIT STRING,
ok BOOLEAN,
dados SET OF INTEGER
}
END
... são gerados estes arquivos:
asn_application.h +Compiler.Log Mensagem.h per_opentype.c
asn_codecs.h constraints.c module.asn1 per_opentype.h
asn_codecs_prim.c constraints.h NativeEnumerated.c per_support.c
asn_codecs_prim.h constr_SEQUENCE.c NativeEnumerated.h per_support.h
asn_internal.h constr_SEQUENCE.h NativeInteger.c VisibleString.c
asn_system.h constr_TYPE.c NativeInteger.h VisibleString.h
ber_decoder.c constr_TYPE.h OBJECT_IDENTIFIER.c xer_decoder.c
ber_decoder.h converter-sample.c OBJECT_IDENTIFIER.h xer_decoder.h
ber_tlv_length.c der_encoder.c OCTET_STRING.c xer_encoder.c
ber_tlv_length.h der_encoder.h OCTET_STRING.h xer_encoder.h
ber_tlv_tag.c INTEGER.c per_decoder.c xer_support.c
ber_tlv_tag.h INTEGER.h per_decoder.h xer_support.h
BIT_STRING.c Makefile.am.sample per_encoder.c
BIT_STRING.h Mensagem.c per_encoder.h
Dentre eles, os arquivos Mensagem.c e Mensagem.h contêm as declarações correspondentes à estrutura de dados Mensagem. Os demais arquivos incluem funções e declarações para o uso, codificação e decodificação de estruturas de dados especificadas via ASN1. Portanto, além de compilar uma especificação, é gerada uma API para usar as estruturas de dados criadas.
A API nativa gerada pelo compilador pode ser usada diretamente, porém ela apresenta limitações quanto ao uso dos tipos de dados básicos ASN1. Alguns tipos de dados, tais como OCTET STRING e suas variações, OBJECT IDENTIFIER e RELATIVE-OID, não estão acompanhados de funções na API para manipulá-los de forma prática. Em alguns casos é necessário criar algoritmos para acessar a estrutura interna desses tipos de dados, o que se torna repetitivo ao usá-los em programas e sujeito a erros. Além disso, as operações de codificação e decodificação também demandam uma quantidade razoável de código-fonte extra a ser escrito para poderem ser usadas. Por isso essa API gerada pelo compilador foi encapsulada em uma outra API C++, que oferece um conjunto de classes para sanar essas limitações.
API ASN1++
A nova API foi denominada ASN1++, e pode ser obtida em:
Após transferir o arquivo, descompacte-o em algum diretório. A API é composta destes arquivos, que estão no subdiretório asn1++:
- include: diretório com arquivos contendo declarações das classes que compõem a API.
- lib: diretório com bibliotecas estáticas contendo a implementação da API em 32 e 64 bits
- Makefile: script de compilação para ajudar a compilação de um projeto ASN1. Possibilita compilar a especificação ASN1 e também o projeto
- Makefile.build: script de compilação auxiliar
- demo.cc: um programa de demonstração do uso da API
- ativo.asn1: a especificação ASN.1 do programa de demonstração
Para utilizá-la basta copiar todos os arquivos nela contidos para o mesmo diretório onde está sua especificação ASN1. Caso deseje usar os scripts de compilação (recomendável), edite Makefile.build e modifique-o conforme ali indicado.
Exemplo de compilação
Um exemplo de estrutura de dados que descreve um ativo financeiro é usado para demonstrar o uso do compilador ASN.1 e a API ASN1++. Os passos a seguir são:
- Escrever a especificação da estrutura de dados em ASN.1
- Compilar a especificação com o compilador asn1c usando o script de compilação fornecido na API ASN1++
- Escrever um programa de teste, o qual deve explorar a API ASN1++
- Compilar o programa de teste
- Usar o programa de teste
Passo 1: escrever a especificação da estrutura de dados em ASN.1
Module-Exemplo DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
Teste ::= ENUMERATED {um, dois, tres}
Ativo ::= SEQUENCE {
nome PrintableString (SIZE(1..16)),
codigo INTEGER,
valor SEQUENCE OF INTEGER,
data NumericString(SIZE(8)),
horario NumericString (SIZE(6)),
cod Teste,
conteudo CHOICE {
ex Extra,
ot Outro,
mais PrintableString (SIZE(2..8)),
num INTEGER
}
}
Extra ::= SEQUENCE {
id INTEGER,
desc PrintableString
}
Outro ::= SEQUENCE {
id INTEGER,
valor INTEGER
}
END
Passo 2: compilar a especificação
Neste exemplo a especificação ASN1 deve estar em um arquivo chamado ativo.asn1. A compilação é feita usando-se o script de compilação Makefile.build, fornecido na API ASN1++. Esse arquivo Makefile.build deve ser editado de forma a definir estas variáveis:
MYOBJS=demo.o
# Modifique a variável PROG para o nome do programa executável a ser gerado.
# Neste exemplo, o programa se chamará "demo"
PROG=demo
# Substitua aqui o nome do seu arquivo com a especificação ASN1
ASN1SRC=ativo.asn1
Em seguida, deve-se realizar a compilação da especificação com este comando:
make build
Passo 3: escrever um programa de teste, o qual deve explorar a biblioteca de codificação gerada durante a compilação
O programa de teste deve-se chamar demo.cc. Ele cria uma estrutura de de dados Ativo, atribui valores aos membros dessa estrutura e mostra-a na tela. Em seguida, ele a codifica com DER e grava o resultado em um arquivo pkt.data. Ao final, decodifica o conteúdo desse arquivo, recuperando a estrutura de dados criada.
Programa de teste |
---|
#include <parser_ativo.h>
#include <iostream>
#include <fstream>
using namespace std;
int main() {
TAtivo pkt;
// definindo os valores de varios campos
pkt.set_codigo(35123);
pkt.set_nome( "PETR3");
pkt.set_data("30092015");
pkt.set_horario("135812");
// este campo "cod" é do tipo enumerated "Teste"
pkt.set_cod(Teste_um);
// "valor" é um campo do tipo sequence of, e pode ser
// definido usando um vector ...
vector<long> v;
v.push_back(111);
v.push_back(222);
pkt.set_valor(v);
// "conteudo" é um choice ... aqui se escolhe seu campo "ot"
// que é do tipo TOutro (um sequence)
TAtivo::Choice_conteudo & con = pkt.get_conteudo();
TOutro ot = con.get_ot();
ot.set_id(777);
ot.set_valor(999);
// verifica se os valores contidos na estrutura de dados respeitam
// a especificação
pkt.check_constraints();
// mostra a estrutura de dados na tela
cout << "Estrutura de dados em memória (antes de codificação XER):" << endl;
pkt.show();
// cria o codificador
ofstream out("pkt.data");
TAtivo::XerSerializer encoder(out);
// codifica a estrutura de dados
encoder.serialize(pkt);
out.close();
// cria o decodificador
ifstream arq("pkt.data");
TAtivo::XerDeserializer decoder(arq);
// tenta decodificar uma estrutura de dados
TAtivo * other = decoder.deserialize();
arq.close();
cout << endl;
if (other) {
cout << "Estrutura de dados obtida da decodificação XER:" << endl;
other->show();
} else cerr << "Erro: não consegui decodificar a estrutura de dados ..." << endl;
// devem-se destruir explicitamente as estruturas de dados obtidas
// do decodificador
delete other;
}
|
Passo 4: Compilar o programa de teste
make all
Passo 5: Usar o programa de teste
aluno@M2:~$ build/demo
Estrutura de dados em memória (antes de codificação XER):
Ativo ::= {
nome: PETR3
codigo: 35123
valor: valor ::= {
111
222
}
data: 30092015
horario: 135812
cod: 0
conteudo: Outro ::= {
id: 777
valor: 999
}
}
Estrutura de dados obtida da decodificação XER:
Ativo ::= {
nome: PETR3
codigo: 35123
valor: valor ::= {
111
222
}
data: 30092015
horario: 135812
cod: 0
conteudo: Outro ::= {
id: 777
valor: 999
}
}
Classes e classes template da API ASN1++
A API ASN1++ contém as seguintes classes e classes template:
- ASN1DataType<T>: classe para auxiliar o uso do tipo de dados ASN1 definido pelo usuário. Definida como template para suportar qualquer tipo de dados ASN1
- ASN1String: classe para auxiliar o acesso, conversão e modificação de strings ASN1
- ASN1BitString: classe para auxiliar o uso de BIT STRING
- ASN1Oid: classe para auxiliar o acesso e modificação de OBJECT IDENTIFIER
- ASN1RelativeOid: classe para auxiliar o acesso e modificação de RELATIVE OID (um caso especial de OID). Tem mesmas operações que ASN1Oid.
- ASN1Sequence<T>: classe para facilitar o uso de sequências ASN1 (SEQUENCE OF e SET OF). Definida como template pois o tipo do dado contido em sequências é genérico
- ASN1DERSerializer<T>: codificador DER. Codifica estruturas de dados e grava o resultado em um stream (ex: ofstream ou ostringstream)
- ASN1XERSerializer<T>: codificador XER. Codifica estruturas de dados e grava o resultado em um stream (ex: ofstream ou ostringstream)
- ASN1DERDeserializer<T>: decodificador DER. Decodifica octetos lidos de um stream (ex: ifstream ou istringstream) e gera uma estrutura de dados.
- ASN1XERDeserializer<T>: decodificador XER. Decodifica octetos lidos de um stream (ex: ifstream ou istringstream) e gera uma estrutura de dados.
ASN1DataType<T>
A classe ASN1DataType<T> encapsula uma estrutura de dados do tipo T, que deve ter sido gerada pelo compilador ASN1.
#include <asn1++/datatype.h>
Métodos:
- ASN1DataType(asn_TYPE_descriptor_t * desc): construtor da classe, o qual deve receber uma referência a um descritor do tipo de dados ASN1 (se o tipo de dados se chamar Mensagem, seu descritor se chama asn_DEF_Mensagem). O descritor é automaticamente declarado no código-fonte gerado pelo compilador ASN1. Este construtor cria automaticamente a estrutura de dados encapsulada de tipo T.
- ASN1DataType(asn_TYPE_descriptor_t * desc, T * apkt): este construtor difere do anterior apenas na possibilidade de passar como parâmetro uma estrutura de dados de tipo T já existente, para que seja encapsulada.
- T * get_data(): retorna uma referência para a estrutura de dados encapsulada
- asn_TYPE_descriptor_t * get_desc(): retorna uma referência ao descritor do tipo de dados ASN1
- void show(): mostra na saída padrão uma representação textual da estrutura de dados encapsulada
- void check_constraints(): verifica se os valores dos membros da estrutura de dados encapsulada respeitam as restrições declaradas na especificação ASN1.
ASN1DataType<Mensagem_t> pkt(&asn_DEF_Mensagem);
Mensagem_t * msg = pkt.get_data();
// modifica valores dos membros da estrutura de dados (não mostrado aqui)
// verifica se valores contidos na estrutura de dados respeitam as restrições
// da especificação ASN1
pkt.check_constraints();
// Mostra a estrutura de dados na tela
pkt.show();
ASN1String
A classe ASN1String encapsula uma referência a uma string ASN1 (OCTET_STRING_t *), e implementa operações para modificar e acessar essa string.
#include <asn1++/string.h>
Métodos:
- ASN1String(OCTET_STRING & astr): construtor da classe. O parâmetro astr deve ser um membro string de uma estrutura de dados ASN1.
- string str(): retorna uma string C++ com o conteúdo da string ASN1
- ASN1String & operator=(const char * s): possibilita atribuir uma string C à string ASN1
- ASN1String & operator=(const string * s): possibilita atribuir uma string C++ à string ASN1
- ASN1String & operator+=(const char * s): possibilita anexar uma string C à string ASN1
- ASN1String & operator+=(const string & s): possibilita anexar uma string C++ à string ASN1
Exemplo de uso:
ASN1DataType<Mensagem_t> pkt(&asn_DEF_Mensagem);
Mensagem_t * msg = pkt.get_data();
ASN1String name(msg->nome);
name = "CONTROL";
cout << "nome: " << name.str() << endl;
ASN1BitString
A classe ASN1BitString encapsula uma referência a uma string de bits ASN1 (BIT_STRING_t *), e implementa operações para modificar e acessar diretamente os bits.
#include <asn1++/bitstring.h>
Métodos:
- ASN1BitString(BIT_STRING_t & bs, int nbits): construtor da classe. O parâmetro bs deve ser um membro string de bits de uma estrutura de dados ASN1, e nbits deve informar qual seu comprimento em bits.
- void set(int pos): Ativa um bit na posição "pos"
- void reset(int pos): Desativa um bit na posição "pos"
- bool get(int pos): retorna o valor do bit na posição "pos"
- void clear(): desativa todos os bits
- void enable(): ativa todos os bits
Exemplo de uso:
ASN1DataType<Mensagem_t> pkt(&asn_DEF_Mensagem);
Mensagem_t * msg = pkt.get_data();
ASN1BitString flags(msg->flags, 12);
flags.enable();
flags.reset(2);
flags.reset(3);
ASN1Oid e ASN1RelativeOid
A classe ASN1Oid encapsula uma referência a um identificador de objeto ASN1 (OBJECT_IDENTIFIER_t *), e implementa operações para modificá-lo e acessá-lo. A classe ASN1RelativeOid estende ASN1Oid para encapsular identificadores relativos de objetos ASN1 (RELATIVE_OID_t *).
#include <asn1++/oid.h>
#include <asn1++/relative-oid.h>
Métodos de ASN1Oid:
- ASN1Oid(OBJECT_IDENTIFIER_t & oid): construtor da classe. O parâmetro oid deve ser um membro identificador de objeto de uma estrutura de dados ASN1.
- ASN1Oid(): construtor da classe. Cria automaticamente o valor OBJECT_IDENTIFIER_t encapsulado.
- ASN1Oid & operator=(const string & oid): possibilita a definição do OID por meio de uma string (ex: 1.3.6.4)
- ASN1Oid & operator+=(const ASN1Oid & other): concatena o OID referenciado por other (faz mais sentido que other seja um ASN1RelativeOid)
- ASN1Oid & operator+=(const string & other): concatena o OID representado pela string other
- iterator begin(): retorna um iterador para o início do OID
- iterator end(): retorna um iterador para o final do OID (após o último número do OID)
Métodos de ASN1RelativeOid:
- ASN1RelativeOid(OBJECT_IDENTIFIER_t & roid): construtor da classe ASN1RelativeOid. O parâmetro roid deve ser um membro identificador relativo de objeto de uma estrutura de dados ASN1.
- ASN1RelativeOid(): construtor da classe ASN1RelativeOid. Cria automaticamente o valor RELATIVE_OID_t encapsulado.
- ASN1RelativeOid & operator=(const string & oid): possibilita a definição do OID por meio de uma string (ex: 6.4)
Exemplo de uso:
ASN1DataType<Mensagem_t> pkt(&asn_DEF_Mensagem);
Mensagem_t * msg = pkt.get_data();
ASN1Oid oid(msg->oid);
oid = "1.3.6.4";
ASN1RelativeOid roid;
roid = "10.200";
oid += roid;
cout << "OID: " << oid.str() << endl;
ASN1Oid::iterator
O iterador da classe ASN1Oid possibilita o acesso sequencial dos números que constituem um OID. Ele possibilita também a modificação individual de qualquer um desses números.
A iteração é feita com semântica semelhante a iteradores da STL (ex: vector<T>::iterator, string::iterator, ...).
Para iniciar um iterador, deve-se usar o método ASN1Oid::begin().
O método ASN1Oid::end() retorna um iterador para o fim do OID, o que pode ser usado para testar a condição de fim de iteração.
Métodos de ASN1Oid::iterator
- iterator& operator++(): avança a iteração para o próximo número do OID
- iterator& operator++(int): avança a iteração para o próximo número do OID
- long& operator*(): retorna uma referência ao número atual do OID na iteração
- bool operator==(const iterator &it): compara se dois iteradores são iguais
- bool operator!=(const iterator &it): compara se dois iteradores são diferentes
Exemplo de uso:
ASN1DataType<Mensagem_t> pkt(&asn_DEF_Mensagem);
Mensagem_t * msg = pkt.get_data();
ASN1Oid oid(msg->oid);
oid = "1.3.6.4";
// mostra os números do OID na tela, separados por espaços
for (ASN1Oid::iterator it = oid.begin(); it != oid.end(); it++) {
cout << *it << " ";
}
ASN1Sequence<T>
Classe template para facilitar o uso de sequências ASN1 (SEQUENCE OF e SET OF). Possibilita acrescentar, remover e acessar valores de uma sequência.
#include <asn1++/sequence.h>
Métodos:
- ASN1Sequence(void * a_seq): construtor da classe. O parâmetro a_seq deve ser um ponteiro para uma sequência ASN1.
- void add(T val): adiciona o valor val à sequência
- T& get(int pos): obtém o valor na posição pos
- void do_empty(): esvazia a sequência
- void del(int pos): remove o dado na posição pos
- void del(int pos, bool do_free): remove o dado na posição pos e o destrói se do_free for verdadeiro
- int len(): retorna o comprimento da sequência
Exemplo de uso:
ASN1DataType<Mensagem_t> pkt(&asn_DEF_Mensagem);
Mensagem_t * msg = pkt.get_data();
ASN1Sequence<long> seq(&msg->dados);
seq.add(10);
seq.add(20);
cout << "seq[0]: " << seq.get(0) << endl;
ASN1Sequence<T>::iterator
A classe template ASN1Sequence<T> contém um iterador para facilitar o acesso e modificação dos dados de uma sequência. A interface e semântica desse iterador é idêntica a de ASN1Oid::iterator.
Exemplo de uso:
ASN1DataType<Mensagem_t> pkt(&asn_DEF_Mensagem);
Mensagem_t * msg = pkt.get_data();
ASN1Sequence<long> seq(&msg->dados);
seq.add(10);
seq.add(20);
for (ASN1Sequence<long>::iterator it = seq.begin(); it != seq.end(); it++) {
cout << "dado: " << *it << endl;
}
ASN1DERSerializer<T> e ASN1XERSerializer<T>
As classes template ASN1DERSerializer<T> e ASN1XERSerializer<T> implementam respectivamente os codificadores DER e XER para uma estrutura de dados ASN1 do tipo T.
#include <asn1++/codec.h>
Métodos:
- DERSerializer(asn_TYPE_descriptor_t * desc, ostream & arq): construtor da classe DERSerializer. O parâmetro desc corresponde ao descritor do tipo de dados ASN1 a ser codificado, e arq é um stream de saída onde será gravada a estrutura de dados codificada.
- XERSerializer(asn_TYPE_descriptor_t * desc, ostream & arq): construtor da classe XERSerializer. Segue mesma definição do construtor de DERSerializer. Cria um codificador BASIC-XER.
- XERSerializer(asn_TYPE_descriptor_t * desc, ostream & arq, xer_encoder_flags_e mode): construtor da classe XERSerializer. Segue mesma definição do construtor de DERSerializer. O parâmetro mode possibilita selecionar o modo de codificação:
- XER_F_BASIC: cria um codificador BASIC-XER.
- XER_F_CANONICAL: cria um codificador CXER (Canonical XER).
- ssize_t serialize(ASN1DataType<T> & pkt): codifica a estrutura de dados dada pelo parâmetro pkt.
Exemplo de uso:
ASN1DataType<Mensagem_t> pkt(&asn_DEF_Mensagem);
Mensagem_t * msg = pkt.get_data();
ASN1Oid oid(msg->oid);
oid = "1.3.6.4";
ASN1String nome(msg->nome);
nome = "CONTROL";
// cria um codificador DER que grava as estruturas codificadas na saída padrão
DERSerializer<Mensagem_t> encoder(&asn_DEF_Mensagem, cout);
encoder.serialize(pkt);
// cria um codificador XER que grava as estruturas codificadas na saída padrão
// usando BASIC-XER
XERSerializer<Mensagem_t> encoder(&asn_DEF_Mensagem, cout);
encoder.serialize(pkt);
// cria um codificador XER que grava as estruturas codificadas na saída padrão
// usando CXER (Canonical-XER)
XERSerializer<Mensagem_t> encoder(&asn_DEF_Mensagem, cout, XER_F_CANONICAL);
encoder.serialize(pkt);
ASN1DERDeserializer<T> e ASN1XERDeserializer<T>
As classes template ASN1DERDeserializer<T> e ASN1XERDeserializer<T> implementam respectivamente os decodificadores DER e XER para uma estrutura de dados ASN1 do tipo T.
#include <asn1++/codec.h>
Métodos:
- DERDeserializer(asn_TYPE_descriptor_t * desc, istream & arq): construtor da classe DERDeserializer. O parâmetro desc corresponde ao descritor do tipo de dados ASN1 a ser decodificado, e arq é um stream de entrada de onde serão decodificadas as estruturas de dados.
- XERDeserializer(asn_TYPE_descriptor_t * desc, ostream & arq): construtor da classe XERDeserializer. Segue mesma definição do construtor de DERDeserializer.
- ASN1DataType<T>* deserialize(): decodifica uma estrutura de dados, retornando um ponteiro para estrutura extraída. Se não conseguir decodificar, retorna NULL.
- ASN1DataType<T> * scan(): percorre a stream de entrada até conseguir decodificar uma estrututura de dados. Octetos lidos que não puderem ser decodificados são descartados. Se chegar ao fim da stream e não conseguir decodificar, retorna NULL.
Exemplo de uso:
ifstream arq("pacotes.data");
DERDeserializer<Mensagem_t> decoder(&asn_DEF_Mensagem, arq);
ASN1DataType<Mensagem_t> * pkt = decoder.decode();
if (pkt) pkt.show();
pkt = decoder.scan();
if (pkt) pkt.show();
Guia rápido para a biblioteca de codificação original
- Acesso a membros do tipo INTEGER e BOOLEAN: basta referenciá-los diretamente, como neste exemplo aplicado à estrutura de dados Ativo:
Ativo_t * pkt = (Ativo_t*)malloc(sizeof(Ativo_t)); pkt->codigo = 555;
- Conversão de string C para OCTET STRING:
int OCTET_STRING_fromString(OCTET_STRING_t *s, const char *str);
- Conversão de OCTET STRING para string C:
// "ptr" é do tipo OCTET_STRING_t * // "data" é do tipo char*, e deve ter capacidade >= ptr->size+1 memcpy(data, ptr->buf, ptr->size); data[ptr->size] = 0;
Para membros da estrutura de dados que forem SET OF ou SEQUENCE OF (i.e. listas de valores), usa-se esta definição de estrutura de dados como exemplo:
ASN.1 | Linguagem C |
---|---|
Ativo ::= SEQUENCE {
nome PrintableString (SIZE(1..16)),
codigo INTEGER,
valor SET OF INTEGER
}
|
/* Ativo */
typedef struct Ativo {
PrintableString_t nome;
long codigo;
struct valor {
A_SET_OF(long) list;
/* Context for parsing across buffer boundaries */
asn_struct_ctx_t _asn_ctx;
} valor;
/* Context for parsing across buffer boundaries */
asn_struct_ctx_t _asn_ctx;
} Ativo_t;
|
- Anexar um valor a uma SEQUENCE OF ou SET OF:
// "pkt" é do tipo Ativo_t* int * p; p = (int*)malloc(sizeof(int)); asn_set_add(&pkt->valor, p);
- Remover um valor de uma SEQUENCE OF ou SET OF:
// remove o valor na posição "0" da sequência // "valor" da estrutura de dados Ativo_t apontada por "pkt" // o último parâmetro informa se memória do dado removido deve ser liberada (0=não, 1=sim) asn_set_del(&pkt->valor, 0, 0);
- Esvazia uma SEQUENCE OF ou SET OF:
// remove todos os dados da sequência "valor" // liberando suas áreas de memória asn_set_empty(&pkt->valor);
- Acesso a um dado de uma SEQUENCE OF ou SET OF:
// n: posição acessada no vetor interno de dados da sequência // k: posição lógica do dado acessado (equivalente à usada em asn_set_del) int n, k; for (n=0, k=0; (k < pkt->valor.list.count) && (n < pkt->valor.list.size);) { if (pkt->valor.list.array[n] != NULL) { long * number = pkt->valor.list.array[n]; printf("valor[%d]=%d\n", k, *number); k++; } }
- Codificar com BER
- Codificar com DER
- Codificar com PER
- Codificar com XER