1
// ---------------------------------------------------------------------------
3
// - afnix:itu module - asn base node class implementation -
4
// ---------------------------------------------------------------------------
5
// - This program is free software; you can redistribute it and/or modify -
6
// - it provided that this copyright notice is kept intact. -
8
// - This program is distributed in the hope that it will be useful, but -
9
// - without any warranty; without even the implied warranty of -
10
// - merchantability or fitness for a particular purpose. In no event shall -
11
// - the copyright holder be liable for any direct, indirect, incidental or -
12
// - special damages arising in any way out of the use of this software. -
13
// ---------------------------------------------------------------------------
14
// - copyright (c) 1999-2011 amaury darsch -
15
// ---------------------------------------------------------------------------
19
#include "AsnNode.hpp"
20
#include "AsnNode.hxx"
21
#include "Boolean.hpp"
22
#include "Integer.hpp"
23
#include "Relatif.hpp"
24
#include "AsnUtils.hpp"
25
#include "Runnable.hpp"
26
#include "QuarkZone.hpp"
27
#include "Exception.hpp"
31
// -------------------------------------------------------------------------
32
// - private section -
33
// -------------------------------------------------------------------------
35
// the default node class
36
static const AsnNode::t_ncls ASN_NCLS_DEF = AsnNode::CLS_UNIV;
37
// the default primitive/constructed flag
38
static const bool ASN_CSTF_DEF = false;
39
// the default tag number
40
static const t_octa ASN_TAGN_DEF = 0x0000000000000000ULL;
41
// the default indefinite content length flag
42
static const bool ASN_ICLF_DEF = false;
43
// the end of content length
44
static const t_long ASN_ASNB_LEN = 2LL;
46
// -------------------------------------------------------------------------
47
// - private section -
48
// -------------------------------------------------------------------------
50
// this procedure maps a class type to a byte
51
static t_byte asn_ncls_byte (const AsnNode::t_ncls ncls) {
54
case AsnNode::CLS_UNIV:
55
result = ASN_UNIV_CLS;
57
case AsnNode::CLS_APPL:
58
result = ASN_APPL_CLS;
60
case AsnNode::CLS_CTXS:
61
result = ASN_CTXS_CLS;
63
case AsnNode::CLS_PRIV:
64
result = ASN_PRIV_CLS;
70
// this procedure generates an identifier octet
71
static t_byte asn_make_ido (const AsnNode::t_ncls ncls, const bool cstf,
73
// generate the identifier octet
74
t_byte ido = asn_ncls_byte (ncls);
75
// map the construted flag
76
if (cstf == true) ido |= ASN_CONS_CLS;
77
// check for max tag value
87
// this procedure write a definite length into a byte array - the byte
88
// array is in reverse order of writing and the minimal length is always
89
// generated as recommended in CER and DER encoding...
90
static long asn_clen_byte (t_byte buf[9], t_long clen) {
93
throw Exception ("asn-error", "invalid negative content length");
95
// if we have a content length less than 128, then a single byte
96
// is generated (i.e short form)
98
buf[0] = (t_byte) clen;
101
// here we have a content length bigger that 128 - the first buffer byte
102
// is the long form length byte followed by the encoded length
104
// fill the byte array at position 1
105
long size = rlen.toubuf (&buf[1], 8);
106
// long form byte length with msb set to 1
107
buf[0] = 0x80 | (t_byte) size;
108
// here is the total size
112
// this proceduire generates a buffer which represents the node header
113
static Buffer asn_head_buf (const AsnNode::t_ncls ncls,
114
const bool cstf, const t_octa tagn,
115
const bool iclf, const t_long clen) {
116
// create the result buffer
118
// generate the identifier octet
119
t_byte ido = asn_make_ido (ncls, cstf, tagn);
121
buf.add ((char) ido);
122
// check if we need to write a large tag
123
if ((ido & ASN_LTAG_BIN) == ASN_LTAG_BIN) {
124
AsnUtils::aidbuf (buf, tagn);
126
// write the content length
128
// write the content length
130
long size = asn_clen_byte (cbuf, clen);
131
for (long i = 0; i < size; i++) buf.add ((char) cbuf[i]);
133
buf.add ((char) ASN_ILEN_BIN);
139
// -------------------------------------------------------------------------
140
// - protected section -
141
// -------------------------------------------------------------------------
143
// create an empty node
145
AsnNode::AsnNode (void) {
146
d_ncls = ASN_NCLS_DEF;
147
d_cstf = ASN_CSTF_DEF;
149
d_iclf = ASN_ICLF_DEF;
152
// create a primitive node by tag number
154
AsnNode::AsnNode (const t_octa tagn) {
155
d_ncls = ASN_NCLS_DEF;
156
d_cstf = ASN_CSTF_DEF;
158
d_iclf = ASN_ICLF_DEF;
161
// create a primitive node by tag number and flag
163
AsnNode::AsnNode (const t_octa tagn, const bool cstf) {
164
d_ncls = ASN_NCLS_DEF;
167
d_iclf = ASN_ICLF_DEF;
170
// copy construct an asn node
172
AsnNode::AsnNode (const AsnNode& that) {
175
d_ncls = that.d_ncls;
176
d_cstf = that.d_cstf;
177
d_tagn = that.d_tagn;
178
d_iclf = that.d_iclf;
186
// assign an asn node to this one
188
AsnNode& AsnNode::operator = (const AsnNode& that) {
189
if (this == &that) return *this;
193
d_ncls = that.d_ncls;
194
d_cstf = that.d_cstf;
195
d_tagn = that.d_tagn;
196
d_iclf = that.d_iclf;
207
// write the node header into a buffer
209
void AsnNode::whead (const t_encr encr, Buffer& buf) const {
212
// get the content length for definite form
213
t_long clen = d_iclf ? 0 : getclen (encr);
214
// generate the head buffer
215
Buffer hbuf = asn_head_buf (d_ncls, d_cstf, d_tagn, d_iclf, clen);
216
// add the head buffer
226
// write the node header into an output stream
228
void AsnNode::whead (const t_encr encr, OutputStream& os) const {
231
// get the content length for definite form
232
t_long clen = d_iclf ? 0 : getclen (encr);
233
// generate the head buffer
234
Buffer hbuf = asn_head_buf (d_ncls, d_cstf, d_tagn, d_iclf, clen);
235
// write the header content
236
while (hbuf.empty () == false) os.write (hbuf.read ());
245
// write the node footer into a buffer
247
void AsnNode::wfoot (const t_encr encr, Buffer& buf) const {
250
// check for the icl flag
251
if (d_iclf == true) {
262
// write the node footer into an output stream
264
void AsnNode::wfoot (const t_encr encr, OutputStream& os) const {
267
// check for the icl flag
268
if (d_iclf == true) {
279
// -------------------------------------------------------------------------
281
// -------------------------------------------------------------------------
283
// return the node class name
285
String AsnNode::repr (void) const {
289
// reset this asn node
291
void AsnNode::reset (void) {
294
d_ncls = ASN_NCLS_DEF;
295
d_cstf = ASN_CSTF_DEF;
296
d_tagn = ASN_TAGN_DEF;
297
d_iclf = ASN_ICLF_DEF;
305
// get the asn node class
307
AsnNode::t_ncls AsnNode::getcls (void) const {
310
t_ncls result = d_ncls;
319
// return true if the node is primitive
321
bool AsnNode::isprm (void) const {
324
bool result = !d_cstf;
333
// return true if the node is constructed
335
bool AsnNode::iscst (void) const {
338
bool result = d_cstf;
347
// return true if the icl flag is set
349
bool AsnNode::isicl (void) const {
352
bool result = d_iclf;
361
// get the node tag number
363
t_octa AsnNode::gettagn (void) const {
366
t_octa result = d_tagn;
375
// get the node content length
377
t_long AsnNode::getclen (void) const {
380
t_long result = d_iclf ? 0 : getclen (ASN_BER);
390
// get the node length
392
t_long AsnNode::length (void) const {
395
t_long result = length (ASN_BER);
405
// get the node length
407
t_long AsnNode::length (const t_encr encr) const {
410
// get the content length
411
t_long clen = getclen (encr);
412
// generate the head buffer
413
Buffer hbuf = asn_head_buf (d_ncls, d_cstf, d_tagn, d_iclf, clen);
414
// get the header length
415
t_long result = hbuf.length ();
416
// add the content length
418
// eventually add the icl value
419
if (d_iclf == true) result += ASN_ASNB_LEN;
429
// write a node into a buffer in ber mode
431
void AsnNode::write (Buffer& buf) const {
434
write (ASN_BER, buf);
443
// write a node into a buffer by encoding rule
445
void AsnNode::write (const t_encr encr, Buffer& buf) const {
462
// write a node into an output stream in ber mode
464
void AsnNode::write (OutputStream& os) const {
475
// write a node into an output stream by encoding rule
477
void AsnNode::write (const t_encr encr, OutputStream& os) const {
494
// -------------------------------------------------------------------------
495
// - object section -
496
// -------------------------------------------------------------------------
498
// the object eval quarks
499
static const long QUARK_ASNBER = String::intern ("BER");
500
static const long QUARK_ASNDER = String::intern ("DER");
501
static const long QUARK_ASNCER = String::intern ("CER");
502
static const long QUARK_ASNUNIV = String::intern ("UNIVERSAL");
503
static const long QUARK_ASNAPPL = String::intern ("APPLICATION");
504
static const long QUARK_ASNCTXS = String::intern ("CONTEXT-SPECIFIC");
505
static const long QUARK_ASNPRIV = String::intern ("PRIVATE");
506
static const long QUARK_ASNNODE = String::intern ("AsnNode");
509
static const long QUARK_ZONE_LENGTH = 7;
510
static QuarkZone zone (QUARK_ZONE_LENGTH);
512
// the object supported quarks
513
static const long QUARK_RESET = zone.intern ("reset");
514
static const long QUARK_WRITE = zone.intern ("write");
515
static const long QUARK_LENGTH = zone.intern ("length");
516
static const long QUARK_GETCLS = zone.intern ("get-class");
517
static const long QUARK_ISPRMP = zone.intern ("primitive-p");
518
static const long QUARK_ISCSTP = zone.intern ("constructed-p");
519
static const long QUARK_GETTAGN = zone.intern ("get-tag-number");
520
static const long QUARK_GETCLEN = zone.intern ("get-content-length");
522
// map an asn node type to an item
523
static inline Item* type_to_item (const AsnNode::t_ncls type) {
525
case AsnNode::CLS_UNIV:
526
return new Item (QUARK_ASNNODE, QUARK_ASNUNIV);
528
case AsnNode::CLS_APPL:
529
return new Item (QUARK_ASNNODE, QUARK_ASNAPPL);
531
case AsnNode::CLS_CTXS:
532
return new Item (QUARK_ASNNODE, QUARK_ASNCTXS);
534
case AsnNode::CLS_PRIV:
535
return new Item (QUARK_ASNNODE, QUARK_ASNPRIV);
538
// we should never be here
542
// map an item to an encoding rule
543
static inline AsnNode::t_encr item_to_encr (const Item& item) {
544
// check for an asn node item
545
if (item.gettid () != QUARK_ASNNODE)
546
throw Exception ("item-error", "item is not an asn node item");
547
// map the item to the enumeration
548
long quark = item.getquark ();
549
if (quark == QUARK_ASNBER) return AsnNode::ASN_BER;
550
if (quark == QUARK_ASNDER) return AsnNode::ASN_DER;
551
if (quark == QUARK_ASNCER) return AsnNode::ASN_CER;
552
throw Exception ("item-error", "cannot map item to asn encoding rule");
555
// evaluate an object data member
557
Object* AsnNode::meval (Runnable* robj, Nameset* nset, const long quark) {
558
if (quark == QUARK_ASNBER)
559
return new Item (QUARK_ASNNODE, QUARK_ASNBER);
560
if (quark == QUARK_ASNDER)
561
return new Item (QUARK_ASNNODE, QUARK_ASNDER);
562
if (quark == QUARK_ASNCER)
563
return new Item (QUARK_ASNNODE, QUARK_ASNCER);
564
if (quark == QUARK_ASNUNIV)
565
return new Item (QUARK_ASNNODE, QUARK_ASNUNIV);
566
if (quark == QUARK_ASNAPPL)
567
return new Item (QUARK_ASNNODE, QUARK_ASNAPPL);
568
if (quark == QUARK_ASNCTXS)
569
return new Item (QUARK_ASNNODE, QUARK_ASNCTXS);
570
if (quark == QUARK_ASNPRIV)
571
return new Item (QUARK_ASNNODE, QUARK_ASNPRIV);
572
throw Exception ("eval-error", "cannot evaluate member",
573
String::qmap (quark));
576
// return true if the given quark is defined
578
bool AsnNode::isquark (const long quark, const bool hflg) const {
580
if (zone.exists (quark) == true) {
584
bool result = hflg ? Object::isquark (quark, hflg) : false;
589
// apply this object with a set of arguments and a quark
591
Object* AsnNode::apply (Runnable* robj, Nameset* nset, const long quark,
593
// get the number of arguments
594
long argc = (argv == nilp) ? 0 : argv->length ();
596
// check for 0 argument
598
if (quark == QUARK_GETCLS) return type_to_item (getcls ());
599
if (quark == QUARK_ISPRMP) return new Boolean (isprm ());
600
if (quark == QUARK_ISCSTP) return new Boolean (iscst ());
601
if (quark == QUARK_LENGTH) return new Integer (length ());
602
if (quark == QUARK_GETTAGN) return new Integer (gettagn ());
603
if (quark == QUARK_GETCLEN) return new Integer (getclen ());
604
if (quark == QUARK_RESET) {
608
if (quark == QUARK_WRITE) {
609
OutputStream* os = (robj == nilp) ? nilp : robj->getos ();
610
if (os == nilp) return nilp;
615
// check for 1 argument
617
if (quark == QUARK_WRITE) {
618
Object* obj = argv->get (0);
619
// check for an output stream
620
OutputStream* os = dynamic_cast <OutputStream*> (obj);
625
// check for a buffer
626
Buffer* buf = dynamic_cast <Buffer*> (obj);
631
throw Exception ("type-error", "invalid object with write",
635
// check for 2 arguments
637
if (quark == QUARK_WRITE) {
638
Object* obj = argv->get (0);
639
// check for an item type
640
Item* iobj = dynamic_cast <Item*> (obj);
642
throw Exception ("type-error", "invalid object with write",
645
AsnNode::t_encr encr = item_to_encr (*iobj);
646
// get secondary object
648
// check for an output stream
649
OutputStream* os = dynamic_cast <OutputStream*> (obj);
654
// check for a buffer
655
Buffer* buf = dynamic_cast <Buffer*> (obj);
660
throw Exception ("type-error", "invalid object with write",
664
// call the object method
665
return Object::apply (robj, nset, quark, argv);