~ubuntu-branches/ubuntu/wily/afnix/wily

« back to all changes in this revision

Viewing changes to src/mod/itu/shl/AsnNode.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anibal Monsalve Salazar
  • Date: 2011-03-16 21:31:18 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20110316213118-gk4k3ez3e5d2huna
Tags: 2.0.0-1
* QA upload.
* New upstream release
* Debian source format is 3.0 (quilt)
* Fix debhelper-but-no-misc-depends
* Fix ancient-standards-version
* Fix package-contains-linda-override
* debhelper compatibility is 7
* Fix dh-clean-k-is-deprecated

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// ---------------------------------------------------------------------------
 
2
// - AsnNode.cpp                                                             -
 
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.                  -
 
7
// -                                                                         -
 
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
// ---------------------------------------------------------------------------
 
16
 
 
17
#include "Item.hpp"
 
18
#include "Vector.hpp"
 
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"
 
28
 
 
29
namespace afnix {
 
30
 
 
31
  // -------------------------------------------------------------------------
 
32
  // - private section                                                       -
 
33
  // -------------------------------------------------------------------------
 
34
  
 
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;
 
45
 
 
46
  // -------------------------------------------------------------------------
 
47
  // - private section                                                       -
 
48
  // -------------------------------------------------------------------------
 
49
 
 
50
  // this procedure maps a class type to a byte
 
51
  static t_byte asn_ncls_byte (const AsnNode::t_ncls ncls) {
 
52
    t_byte result = nilc;
 
53
    switch (ncls) {
 
54
    case AsnNode::CLS_UNIV:
 
55
      result = ASN_UNIV_CLS;
 
56
      break;
 
57
    case AsnNode::CLS_APPL:
 
58
      result = ASN_APPL_CLS;
 
59
      break;
 
60
    case AsnNode::CLS_CTXS:
 
61
      result = ASN_CTXS_CLS;
 
62
      break;
 
63
    case AsnNode::CLS_PRIV:
 
64
      result = ASN_PRIV_CLS;
 
65
      break;
 
66
    }
 
67
    return result;
 
68
  }
 
69
 
 
70
  // this procedure generates an identifier octet
 
71
  static t_byte asn_make_ido (const AsnNode::t_ncls ncls, const bool cstf,
 
72
                              const t_octa tagn) {
 
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
 
78
    if (tagn < 31) {
 
79
      ido |= (t_byte) tagn;
 
80
    } else {
 
81
      ido |= ASN_LTAG_BIN;
 
82
    }
 
83
    // here it is
 
84
    return ido;
 
85
  }
 
86
 
 
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) {
 
91
    // check for negative
 
92
    if (clen < 0) {
 
93
      throw Exception ("asn-error", "invalid negative content length");
 
94
    }
 
95
    // if we have a content length less than 128, then a single byte
 
96
    // is generated (i.e short form)
 
97
    if (clen < 128) {
 
98
      buf[0] = (t_byte) clen;
 
99
      return 1;
 
100
    }
 
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
 
103
    Relatif rlen = clen;
 
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
 
109
    return size + 1;
 
110
  }
 
111
 
 
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
 
117
    Buffer buf;
 
118
    // generate the identifier octet
 
119
    t_byte ido = asn_make_ido (ncls, cstf, tagn);
 
120
    // write the byte
 
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);
 
125
    }
 
126
    // write the content length
 
127
    if (iclf == false) {
 
128
      // write the content length
 
129
      t_byte cbuf[9];
 
130
      long size = asn_clen_byte (cbuf, clen);
 
131
      for (long i = 0; i < size; i++) buf.add ((char) cbuf[i]);
 
132
    } else {
 
133
      buf.add ((char) ASN_ILEN_BIN);
 
134
    }
 
135
    // here it is
 
136
    return buf;
 
137
  }
 
138
 
 
139
  // -------------------------------------------------------------------------
 
140
  // - protected section                                                     -
 
141
  // -------------------------------------------------------------------------
 
142
 
 
143
  // create an empty node
 
144
 
 
145
  AsnNode::AsnNode (void) {
 
146
    d_ncls = ASN_NCLS_DEF;
 
147
    d_cstf = ASN_CSTF_DEF;
 
148
    d_tagn = 0ULL;
 
149
    d_iclf = ASN_ICLF_DEF;
 
150
  }
 
151
 
 
152
  // create a primitive node by tag number
 
153
 
 
154
  AsnNode::AsnNode (const t_octa tagn) {
 
155
    d_ncls = ASN_NCLS_DEF;
 
156
    d_cstf = ASN_CSTF_DEF;
 
157
    d_tagn = tagn;
 
158
    d_iclf = ASN_ICLF_DEF;
 
159
  }
 
160
 
 
161
  // create a primitive node by tag number and flag
 
162
 
 
163
  AsnNode::AsnNode (const t_octa tagn, const bool cstf) {
 
164
    d_ncls = ASN_NCLS_DEF;
 
165
    d_cstf = cstf;
 
166
    d_tagn = tagn;
 
167
    d_iclf = ASN_ICLF_DEF;
 
168
  }
 
169
  
 
170
  // copy construct an asn node
 
171
 
 
172
  AsnNode::AsnNode (const AsnNode& that) {
 
173
    that.rdlock ();
 
174
    try {
 
175
      d_ncls = that.d_ncls;
 
176
      d_cstf = that.d_cstf;
 
177
      d_tagn = that.d_tagn;
 
178
      d_iclf = that.d_iclf;
 
179
      that.unlock ();
 
180
    } catch (...) {
 
181
      that.unlock ();
 
182
      throw;
 
183
    }
 
184
  }
 
185
 
 
186
  // assign an asn node to this one
 
187
 
 
188
  AsnNode& AsnNode::operator = (const AsnNode& that) {
 
189
    if (this == &that) return *this;
 
190
    wrlock ();
 
191
    that.rdlock ();
 
192
    try {
 
193
      d_ncls = that.d_ncls;
 
194
      d_cstf = that.d_cstf;
 
195
      d_tagn = that.d_tagn;
 
196
      d_iclf = that.d_iclf;
 
197
      unlock ();
 
198
      that.unlock ();
 
199
      return *this;
 
200
    } catch (...) {
 
201
      unlock ();
 
202
      that.unlock ();
 
203
      throw;
 
204
    }
 
205
  }
 
206
 
 
207
  // write the node header into a buffer
 
208
 
 
209
  void AsnNode::whead (const t_encr encr, Buffer& buf) const {
 
210
    rdlock ();
 
211
    try {
 
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
 
217
      buf.add (hbuf);
 
218
      // unlock and return
 
219
      unlock ();
 
220
    } catch (...) {
 
221
      unlock ();
 
222
      throw;
 
223
    }
 
224
  }
 
225
 
 
226
  // write the node header into an output stream
 
227
 
 
228
  void AsnNode::whead (const t_encr encr, OutputStream& os) const {
 
229
    rdlock ();
 
230
    try {
 
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 ());
 
237
      // unlock and return
 
238
      unlock ();
 
239
    } catch (...) {
 
240
      unlock ();
 
241
      throw;
 
242
    }
 
243
  }
 
244
 
 
245
  // write the node footer into a buffer
 
246
 
 
247
  void AsnNode::wfoot (const t_encr encr, Buffer& buf) const {
 
248
    rdlock ();
 
249
    try {
 
250
      // check for the icl flag
 
251
      if (d_iclf == true) {
 
252
        buf.add (nilc);
 
253
        buf.add (nilc);
 
254
      }
 
255
      unlock ();
 
256
    } catch (...) {
 
257
      unlock ();
 
258
      throw;
 
259
    }
 
260
  }
 
261
 
 
262
  // write the node footer into an output stream
 
263
  
 
264
  void AsnNode::wfoot (const t_encr encr, OutputStream& os) const {
 
265
    rdlock ();
 
266
    try {
 
267
      // check for the icl flag
 
268
      if (d_iclf == true) {
 
269
        os.write (nilc);
 
270
        os.write (nilc);
 
271
      }
 
272
      unlock ();
 
273
    } catch (...) {
 
274
      unlock ();
 
275
      throw;
 
276
    }
 
277
  }
 
278
 
 
279
  // -------------------------------------------------------------------------
 
280
  // - class section                                                         -
 
281
  // -------------------------------------------------------------------------
 
282
 
 
283
  // return the node class name
 
284
 
 
285
  String AsnNode::repr (void) const {
 
286
    return "AsnNode";
 
287
  }
 
288
 
 
289
  // reset this asn node
 
290
 
 
291
  void AsnNode::reset (void) {
 
292
    wrlock ();
 
293
    try {
 
294
      d_ncls = ASN_NCLS_DEF;
 
295
      d_cstf = ASN_CSTF_DEF;
 
296
      d_tagn = ASN_TAGN_DEF;
 
297
      d_iclf = ASN_ICLF_DEF;
 
298
      unlock ();
 
299
    } catch (...) {
 
300
      unlock ();
 
301
      throw;
 
302
    }
 
303
  }
 
304
 
 
305
  // get the asn node class
 
306
 
 
307
  AsnNode::t_ncls AsnNode::getcls (void) const {
 
308
    rdlock ();
 
309
    try {
 
310
      t_ncls result = d_ncls;
 
311
      unlock ();
 
312
      return result;
 
313
    } catch (...) {
 
314
      unlock ();
 
315
      throw;
 
316
    }
 
317
  }
 
318
 
 
319
  // return true if the node is primitive
 
320
 
 
321
  bool AsnNode::isprm (void) const {
 
322
    rdlock ();
 
323
    try {
 
324
      bool result = !d_cstf;
 
325
      unlock ();
 
326
      return result;
 
327
    } catch (...) {
 
328
      unlock ();
 
329
      throw;
 
330
    }
 
331
  }
 
332
 
 
333
  // return true if the node is constructed
 
334
 
 
335
  bool AsnNode::iscst (void) const {
 
336
    rdlock ();
 
337
    try {
 
338
      bool result = d_cstf;
 
339
      unlock ();
 
340
      return result;
 
341
    } catch (...) {
 
342
      unlock ();
 
343
      throw;
 
344
    }
 
345
  }
 
346
 
 
347
  // return true if the icl flag is set
 
348
 
 
349
  bool AsnNode::isicl (void) const {
 
350
    rdlock ();
 
351
    try {
 
352
      bool result = d_iclf;
 
353
      unlock ();
 
354
      return result;
 
355
    } catch (...) {
 
356
      unlock ();
 
357
      throw;
 
358
    }
 
359
  }
 
360
 
 
361
  // get the node tag number
 
362
 
 
363
  t_octa AsnNode::gettagn (void) const {
 
364
    rdlock ();
 
365
    try {
 
366
      t_octa result = d_tagn;
 
367
      unlock ();
 
368
      return result;
 
369
    } catch (...) {
 
370
      unlock ();
 
371
      throw;
 
372
    }
 
373
  }
 
374
 
 
375
  // get the node content length
 
376
 
 
377
  t_long AsnNode::getclen (void) const {
 
378
    rdlock ();
 
379
    try {
 
380
      t_long result = d_iclf ? 0 : getclen (ASN_BER);
 
381
      // unlock and return
 
382
      unlock ();
 
383
      return result;
 
384
    } catch (...) {
 
385
      unlock ();
 
386
      throw;
 
387
    }
 
388
  }
 
389
 
 
390
  // get the node length
 
391
 
 
392
  t_long AsnNode::length (void) const {
 
393
    rdlock ();
 
394
    try {
 
395
      t_long result = length (ASN_BER);
 
396
      // unlock and return
 
397
      unlock ();
 
398
      return result;
 
399
    } catch (...) {
 
400
      unlock ();
 
401
      throw;
 
402
    }
 
403
  }
 
404
 
 
405
  // get the node length
 
406
 
 
407
  t_long AsnNode::length (const t_encr encr) const {
 
408
    rdlock ();
 
409
    try {
 
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
 
417
      result += clen;
 
418
      // eventually add the icl value
 
419
      if (d_iclf == true) result += ASN_ASNB_LEN;
 
420
      // unlock and return
 
421
      unlock ();
 
422
      return result;
 
423
    } catch (...) {
 
424
      unlock ();
 
425
      throw;
 
426
    }
 
427
  }
 
428
 
 
429
  // write a node into a buffer in ber mode
 
430
 
 
431
  void AsnNode::write (Buffer& buf) const {
 
432
    rdlock ();
 
433
    try {
 
434
      write (ASN_BER, buf);
 
435
      // unlock and return
 
436
      unlock ();
 
437
    } catch (...) {
 
438
      unlock ();
 
439
      throw;
 
440
    }
 
441
  }
 
442
 
 
443
  // write a node into a buffer by encoding rule
 
444
 
 
445
  void AsnNode::write (const t_encr encr, Buffer& buf) const {
 
446
    rdlock ();
 
447
    try {
 
448
      // write the header
 
449
      whead (encr, buf);
 
450
      // write the body
 
451
      wbody (encr, buf);
 
452
      // write the footer
 
453
      wfoot (encr, buf);
 
454
      // unlock and return
 
455
      unlock ();
 
456
    } catch (...) {
 
457
      unlock ();
 
458
      throw;
 
459
    }
 
460
  }
 
461
 
 
462
 // write a node into an output stream in ber mode
 
463
 
 
464
  void AsnNode::write (OutputStream& os) const {
 
465
    rdlock ();
 
466
    try {
 
467
      write (ASN_BER, os);
 
468
      unlock ();
 
469
    } catch (...) {
 
470
      unlock ();
 
471
      throw;
 
472
    }
 
473
  }
 
474
 
 
475
  // write a node into an output stream by encoding rule
 
476
 
 
477
  void AsnNode::write (const t_encr encr, OutputStream& os) const {
 
478
    rdlock ();
 
479
    try {
 
480
      // write the header
 
481
      whead (encr, os);
 
482
      // write the body
 
483
      wbody (encr, os);
 
484
      // write the footer
 
485
      wfoot (encr, os);
 
486
      // unlock and return
 
487
      unlock ();
 
488
    } catch (...) {
 
489
      unlock ();
 
490
      throw;
 
491
    }
 
492
  }
 
493
 
 
494
  // -------------------------------------------------------------------------
 
495
  // - object section                                                        -
 
496
  // -------------------------------------------------------------------------
 
497
 
 
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");
 
507
 
 
508
  // the quark zone
 
509
  static const long QUARK_ZONE_LENGTH = 7;
 
510
  static QuarkZone  zone (QUARK_ZONE_LENGTH);
 
511
 
 
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");
 
521
 
 
522
  // map an asn node type to an item
 
523
  static inline Item* type_to_item (const AsnNode::t_ncls type) {
 
524
    switch (type) {
 
525
    case AsnNode::CLS_UNIV:
 
526
      return new Item (QUARK_ASNNODE, QUARK_ASNUNIV);
 
527
      break;
 
528
    case AsnNode::CLS_APPL:
 
529
      return new Item (QUARK_ASNNODE, QUARK_ASNAPPL);
 
530
      break;
 
531
    case AsnNode::CLS_CTXS:
 
532
      return new Item (QUARK_ASNNODE, QUARK_ASNCTXS);
 
533
      break;
 
534
    case AsnNode::CLS_PRIV:
 
535
      return new Item (QUARK_ASNNODE, QUARK_ASNPRIV);
 
536
      break;
 
537
    }
 
538
    // we should never be here
 
539
    return nilp;
 
540
  }
 
541
 
 
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");
 
553
  }
 
554
 
 
555
  // evaluate an object data member
 
556
  
 
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));
 
574
  }
 
575
 
 
576
  // return true if the given quark is defined
 
577
 
 
578
  bool AsnNode::isquark (const long quark, const bool hflg) const {
 
579
    rdlock ();
 
580
    if (zone.exists (quark) == true) {
 
581
      unlock ();
 
582
      return true;
 
583
    }
 
584
    bool result = hflg ? Object::isquark (quark, hflg) : false;
 
585
    unlock ();
 
586
    return result;
 
587
  }
 
588
 
 
589
  // apply this object with a set of arguments and a quark
 
590
 
 
591
  Object* AsnNode::apply (Runnable* robj, Nameset* nset, const long quark,
 
592
                          Vector* argv) {
 
593
    // get the number of arguments
 
594
    long argc = (argv == nilp) ? 0 : argv->length ();
 
595
 
 
596
    // check for 0 argument
 
597
    if (argc == 0) {
 
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) {
 
605
        reset ();
 
606
        return nilp;
 
607
      }
 
608
      if (quark == QUARK_WRITE) {
 
609
        OutputStream* os = (robj == nilp) ? nilp : robj->getos ();
 
610
        if (os == nilp) return nilp;
 
611
        write (*os);
 
612
        return nilp;
 
613
      }
 
614
    }
 
615
    // check for 1 argument
 
616
    if (argc == 1) {
 
617
      if (quark == QUARK_WRITE) {
 
618
        Object* obj = argv->get (0);
 
619
        // check for an output stream
 
620
        OutputStream* os = dynamic_cast <OutputStream*> (obj);
 
621
        if (os != nilp) {
 
622
          write (*os);
 
623
          return nilp;
 
624
        }
 
625
        // check for a buffer
 
626
        Buffer* buf = dynamic_cast <Buffer*> (obj);
 
627
        if (buf != nilp) {
 
628
          write (*buf);
 
629
          return nilp;
 
630
        }
 
631
        throw Exception ("type-error", "invalid object with write",
 
632
                         Object::repr (obj));
 
633
      }
 
634
    }
 
635
    // check for 2 arguments
 
636
    if (argc == 2) {
 
637
      if (quark == QUARK_WRITE) {
 
638
        Object* obj = argv->get (0);
 
639
        // check for an item type
 
640
        Item* iobj = dynamic_cast <Item*> (obj);
 
641
        if (iobj == nilp) {
 
642
          throw Exception ("type-error", "invalid object with write",
 
643
                           Object::repr (obj));
 
644
        }
 
645
        AsnNode::t_encr encr = item_to_encr (*iobj);
 
646
        // get secondary object
 
647
        obj = argv->get (1);
 
648
        // check for an output stream
 
649
        OutputStream* os = dynamic_cast <OutputStream*> (obj);
 
650
        if (os != nilp) {
 
651
          write (encr, *os);
 
652
          return nilp;
 
653
        }
 
654
        // check for a buffer
 
655
        Buffer* buf = dynamic_cast <Buffer*> (obj);
 
656
        if (buf != nilp) {
 
657
          write (encr, *buf);
 
658
          return nilp;
 
659
        }
 
660
        throw Exception ("type-error", "invalid object with write",
 
661
                         Object::repr (obj));
 
662
      }
 
663
    }
 
664
    // call the object method
 
665
    return Object::apply (robj, nset, quark, argv);
 
666
  }
 
667
}