Enhanced SIM for E2AP v1 for TS UC
[sim/e2-interface.git] / e2sim / e2apv1sim / src / ASN1 / asn / buffer.hpp
1 #pragma once
2 /******************************************************************************
3 *
4 *   Copyright (c) 2019 AT&T Intellectual Property.
5 *   Copyright (c) 2018-2019 Nokia.
6 *
7 *   Licensed under the Apache License, Version 2.0 (the "License");
8 *   you may not use this file except in compliance with the License.
9 *   You may obtain a copy of the License at
10 *
11 *       http://www.apache.org/licenses/LICENSE-2.0
12 *
13 *   Unless required by applicable law or agreed to in writing, software
14 *   distributed under the License is distributed on an "AS IS" BASIS,
15 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 *   See the License for the specific language governing permissions and
17 *   limitations under the License.
18 *
19 *******************************************************************************/
20
21 // Standard Includes: ANSI C/C++, MSA, and Third-Party Libraries
22 #include <cstring>
23
24 // Local Includes: Application specific classes, functions, and libraries
25 #include "asn/error_context.hpp"
26 #include "value_traits.hpp"
27
28 //#define CODEC_BIT_TRACE_ENABLE
29 #ifdef CODEC_BIT_TRACE_ENABLE
30         #define CODEC_BIT_TRACE(FMT, args...) printf("%s[%u]:" FMT "\n", std::strrchr(__FILE__, '/') + 1, __LINE__, ##args)
31 #else
32         #define CODEC_BIT_TRACE(...)
33 #endif
34
35 namespace asn {
36
37 template <class IE, class VALUE, bool LSB>
38 struct bit_accessor;
39
40 template <bool LSB>
41 struct bit_accessor_cross_byte;
42
43 template <typename PTR>
44 class buffer
45 {
46 public:
47         typedef PTR pointer;
48
49         explicit buffer(error_context& err)
50                 : m_errCtx(err)
51         {}
52
53         void reset(pointer data, u32 size)
54         {
55                 m_start         = data;
56                 m_end           = m_start + size;
57                 m_current   = m_start;
58                 m_shift     = 0;
59         }
60
61         u32 getOffset() const          { return begin() - m_start; }
62
63         u32 getBytesLeft() const       { return end() - begin(); }
64         u32 getBytesUsed() const       { return getOffset() + (get_shift() ? 1 : 0); }
65
66         u8 get_shift() const           { return m_shift; }
67         void reset_shift()             { m_shift = 0; }
68         void byte_align()              { if (get_shift()) { m_shift = 0; ++m_current; } }
69
70         pointer advance(u32 delta)     { pointer p = begin(); m_current += delta; return p; }
71
72         pointer begin() const          { return m_current; }
73
74         void set_begin(pointer ptr, u8 bit_shift)
75         {
76                 if (m_start <= ptr && ptr <= end())
77                 {
78                         m_current = ptr;
79                         m_shift = bit_shift;
80                 }
81         }
82
83         pointer end() const            { return m_end; }
84         void set_end(pointer v)        { m_end = v; }
85
86         bool checkAlignment(char const* name, u8 const mask = 0xFF)
87         {
88                 if (0 == (get_shift() & mask)) return true;
89                 m_errCtx.alignmentError(name, get_shift());
90                 return false;
91         }
92
93         bool checkBytesLeft(char const* name, u32 const num_bytes)
94         {
95                 if (getBytesLeft() >= num_bytes) return true;
96                 m_errCtx.lengthErrorBytes(name, getBytesLeft(), num_bytes);
97                 return false;
98         }
99
100         bool checkBitsLeft(char const* name, u32 const num_bits)
101         {
102                 if (getBitsLeft() >= num_bits) return true;
103                 m_errCtx.lengthErrorBits(name, getBitsLeft(), num_bits);
104                 return false;
105         }
106
107         bool checkBytesAndAlignment(char const* name, u32 const num_bytes, u8 const mask = 0xFF)
108         {
109                 if (getBytesLeft() >= num_bytes)
110                 {
111                         if (0 == (get_shift() & mask)) return true;
112                         m_errCtx.alignmentError(name, get_shift());
113                 }
114                 else
115                 {
116                         m_errCtx.lengthErrorBytes(name, getBytesLeft(), num_bytes);
117                 }
118                 return false;
119         }
120
121         pointer getBytes(char const* name, u32 num_bytes)
122         {
123                 if (checkBytesAndAlignment(name, num_bytes))
124                 {
125                         return advance(num_bytes);
126                 }
127                 return nullptr;
128         }
129
130         //NOTE! num_bytes should be set to minimal number of bytes expected
131         pointer getBytes(char const* name, u32 max_requested, u32& num_bytes)
132         {
133                 if (checkAlignment(name))
134                 {
135                         u32 const left = getBytesLeft();
136                         if (left >= num_bytes)
137                         {
138                                 num_bytes = (left > max_requested) ? max_requested : left;
139                                 return advance(num_bytes);
140                         }
141
142                         m_errCtx.lengthErrorBytes(name, getBytesLeft(), num_bytes);
143                 }
144                 return nullptr;
145         }
146
147         bool putByte(char const* name, u8 byte)
148         {
149                 if (checkBytesAndAlignment(name, 1))
150                 {
151                         begin()[0] = byte;
152                         ++m_current;
153                         return true;
154                 }
155                 return false;
156         }
157
158         bool putBytes(char const* name, void const* in, u32 num_bytes)
159         {
160                 if (checkBytesAndAlignment(name, num_bytes))
161                 {
162                         std::memcpy(begin(), in, num_bytes);
163                         m_current += num_bytes;
164                         return true;
165                 }
166                 return false;
167         }
168         
169         bool checkAlignment(u8 const mask = 0xFF)
170         {
171                 if (0 == (get_shift() & mask)) return true;
172                 m_errCtx.alignmentError(get_shift());
173                 return false;
174         }
175
176         bool checkBytesLeft(u32 const num_bytes)
177         {
178                 if (getBytesLeft() >= num_bytes) return true;
179                 m_errCtx.lengthErrorBytes(getBytesLeft(), num_bytes);
180                 return false;
181         }
182
183         bool checkBitsLeft(u32 const num_bits)
184         {
185                 if (getBitsLeft() >= num_bits) return true;
186                 m_errCtx.lengthErrorBits(getBitsLeft(), num_bits);
187                 return false;
188         }
189
190         bool checkBytesAndAlignment(u32 const num_bytes, u8 const mask = 0xFF)
191         {
192                 if (getBytesLeft() >= num_bytes)
193                 {
194                         if (0 == (get_shift() & mask)) return true;
195                         m_errCtx.alignmentError(get_shift());
196                 }
197                 else
198                 {
199                         m_errCtx.lengthErrorBytes(getBytesLeft(), num_bytes);
200                 }
201                 return false;
202         }
203
204         pointer getBytes(u32 num_bytes)
205         {
206                 if (checkBytesAndAlignment(num_bytes))
207                 {
208                         return advance(num_bytes);
209                 }
210                 return nullptr;
211         }
212
213         //NOTE! num_bytes should be set to minimal number of bytes expected
214         pointer getBytes(u32 max_requested, u32& num_bytes)
215         {
216                 if (checkAlignment())
217                 {
218                         u32 const left = getBytesLeft();
219                         if (left >= num_bytes)
220                         {
221                                 num_bytes = (left > max_requested) ? max_requested : left;
222                                 return advance(num_bytes);
223                         }
224
225                         m_errCtx.lengthErrorBytes(getBytesLeft(), num_bytes);
226                 }
227                 return nullptr;
228         }
229
230         bool putByte(u8 byte)
231         {
232                 if (checkBytesAndAlignment(1))
233                 {
234                         begin()[0] = byte;
235                         ++m_current;
236                         return true;
237                 }
238                 return false;
239         }
240
241         bool putBytes(void const* in, u32 num_bytes)
242         {
243                 if (num_bytes)
244                 {
245                         if(checkBytesAndAlignment(num_bytes))
246                         {
247                                 std::memcpy(begin(), in, num_bytes);
248                                 m_current += num_bytes;
249                         }
250                         else
251                                 return false;
252                 }
253                 return true;
254         }
255
256         char const* toString() const
257         {
258                 static char sz[64];
259                 u8 const* p = begin();
260                 snprintf(sz, sizeof(sz), "%02X %02X %02X %02X [%02X]=%p@%u..%p -%u bits: +%u bytes", p[-4], p[-3], p[-2], p[-1], p[0], p
261                         , getOffset(), end(), get_shift(), getBytesLeft());
262                 return sz;
263         }
264
265 private:
266         template <class IE, class VALUE, bool LSB>
267         friend class bit_accessor;
268         
269         template <bool LSB>
270         friend struct bit_accessor_cross_byte;
271
272         template <typename U>
273         void push_u8(U value)          { *m_current++ = static_cast<u8>(value); }
274         template <typename U>
275         void put_u8(U value)           { m_current[0] = static_cast<u8>(value); }
276
277 //khxm68: TODO: won't compile without it. WTF?!
278 #pragma GCC diagnostic push
279 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
280         u8 get_u8() const              { return m_current[0]; }
281 #pragma GCC diagnostic pop
282         u8 extract_u8(u8 value, u8 mask, u8 shift) const
283                 { return (get_u8() & ~(mask << shift)) | ((value & mask) << shift); }
284
285         u16 get_u16() const            { return (static_cast<u16>(m_current[0]) << 8) | m_current[1]; }
286         u16 extract_u16(u16 value, u16 mask, u16 shift) const
287                 { return (get_u16() & ~(mask << shift)) | ((value & mask) << shift); }
288
289         u32 get_u24() const            { return (static_cast<u32>(m_current[0]) << 16) | (static_cast<u32>(m_current[1]) << 8) | m_current[2]; }
290         u32 extract_u24(u32 value, u32 mask, u32 shift) const
291                 { return (get_u24() & ~(mask << shift)) | ((value & mask) << shift); }
292
293         u32 get_u32() const            { return (static_cast<u32>(m_current[0]) << 24) | (static_cast<u32>(m_current[1]) << 16) | (static_cast<u32>(m_current[2]) << 8) | m_current[3]; }
294         u32 extract_u32(u32 value, u32 mask, u32 shift) const
295                 { return (get_u32() & ~(mask << shift)) | ((value & mask) << shift); }
296
297         u32 getBitsLeft() const        { return begin() == end() ? 0 : (getBytesLeft()*8 - get_shift()); }
298
299         void bit_advance(u8 num_bits)
300         {
301                 m_shift += num_bits;
302                 if (get_shift() > 7)
303                 {
304                         reset_shift();
305                         m_current++;
306                 }
307         }
308
309         pointer  m_current;
310         pointer  m_end;
311         pointer  m_start;
312         u8       m_shift;
313         error_context& m_errCtx;
314 };
315
316 template <class IE>     //LSB 1..7 bits
317 struct bit_accessor<IE, stdex::value::_8, true>
318 {
319         static_assert(IE::length::value > 0 && IE::length::value < 8, "something wrong with traits!");
320
321         static void put(u8 value, buffer<u8*>& buf)
322         {
323                 u8 const mask = static_cast<u8>((1u << IE::length::value) - 1);
324                 u8 const shift = buf.get_shift();
325                 u8 const data = buf.extract_u8(value, mask, shift);
326                 buf.put_u8(data);
327
328                 CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%02X(%02X) mask=%04X: %s", shift, buf.get_shift()
329                         , IE::length::value, data, value, mask, buf.toString());
330
331                 buf.bit_advance(IE::length::value);
332         }
333
334         static u8 get(buffer<u8 const*>& buf)
335         {
336                 u8 const mask = static_cast<u8>((1u << IE::length::value) - 1);
337                 u8 const shift = buf.get_shift();
338                 u8 const data = (buf.get_u8() >> shift) & mask;
339
340                 CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%02X mask=%02X: %s", shift, buf.get_shift()
341                         , IE::length::value, data, mask, buf.toString());
342
343                 buf.bit_advance(IE::length::value);
344                 return data;
345         }
346 };
347
348 template <class IE>     //LSB 9..15 bits
349 struct bit_accessor<IE, stdex::value::_16, true>
350 {
351         static_assert(IE::length::value > 8 && IE::length::value < 16, "something wrong with traits!");
352
353         static void put(u16 value, buffer<u8*>& buf)
354         {
355                 u16 const mask = static_cast<u16>((1u << IE::length::value) - 1);
356                 u16 const shift = buf.get_shift();
357                 u16 const data = buf.extract_u16(value, mask, shift);
358                 buf.push_u8(data >> 8);
359                 buf.put_u8(data);
360
361                 CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%04X(%04X) mask=%04X: %s", shift, buf.get_shift()
362                         , IE::length::value, data, value, mask, buf.toString());
363
364                 buf.bit_advance(IE::length::value - 8);
365         }
366
367         static u16 get(buffer<u8 const*>& buf)
368         {
369                 u16 const mask = static_cast<u16>((1u << IE::length::value) - 1);
370                 u16 const shift = buf.get_shift();
371                 u16 const data = (buf.get_u16() >> shift) & mask;
372                 buf.m_current += 1;
373
374                 CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%04X mask=%04X: %s", shift, buf.get_shift()
375                         , IE::length::value, data, mask, buf.toString());
376
377                 buf.bit_advance(IE::length::value - 8);
378                 return data;
379         }
380 };
381
382 template <class IE>     //LSB 17..24 bits
383 struct bit_accessor<IE, stdex::value::_24, true>
384 {
385         static_assert(IE::length::value > 16 && IE::length::value <= 24, "something wrong with traits!");
386
387         static void put(u32 value, buffer<u8*>& buf)
388         {
389                 u32 const mask = static_cast<u32>((1u << IE::length::value) - 1);
390                 u32 const shift = buf.get_shift();
391                 u32 const data = buf.extract_u24(value, mask, shift);
392
393                 buf.push_u8(data >> 16);
394                 buf.push_u8(data >> 8);
395                 buf.put_u8(data);
396
397                 CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%06X(%06X) mask=%06X: %s", shift, buf.get_shift()
398                         , IE::length::value, data, value, mask, buf.toString());
399
400                 buf.bit_advance(IE::length::value - 16);
401         }
402
403         static u32 get(buffer<u8 const*>& buf)
404         {
405                 u32 const mask = static_cast<u32>((1u << IE::length::value) - 1);
406                 u32 const shift = buf.get_shift();
407                 u32 const data = (buf.get_u24() >> shift) & mask;
408                 buf.m_current += 2;
409
410                 CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%06X mask=%06X: %s", shift, buf.get_shift()
411                         , IE::length::value, data, mask, buf.toString());
412
413                 buf.bit_advance(IE::length::value - 16);
414                 return data;
415         }
416 };
417
418 template <class IE>     //LSB 25..31 bits
419 struct bit_accessor<IE, stdex::value::_32, true>
420 {
421         static_assert(IE::length::value > 24 && IE::length::value < 32, "something wrong with traits!");
422
423         static void put(u32 value, buffer<u8*>& buf)
424         {
425                 u32 const mask = static_cast<u32>((1u << IE::length::value) - 1);
426                 u32 const shift = buf.get_shift();
427                 u32 const data = buf.extract_u32(value, mask, shift);
428
429                 buf.push_u8(data >> 24);
430                 buf.push_u8(data >> 16);
431                 buf.push_u8(data >> 8);
432                 buf.put_u8(data);
433
434                 CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%08X(%08X) mask=%08X: %s", shift, buf.get_shift()
435                         , IE::length::value, data, value, mask, buf.toString());
436
437                 buf.bit_advance(IE::length::value - 24);
438         }
439
440         static u32 get(buffer<u8 const*>& buf)
441         {
442                 u32 const mask = static_cast<u32>((1u << IE::length::value) - 1);
443                 u32 const shift = buf.get_shift();
444                 u32 const data = (buf.get_u32() >> shift) & mask;
445                 buf.m_current += 3;
446
447                 CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%08X mask=%08X: %s", shift, buf.get_shift()
448                         , IE::length::value, data, mask, buf.toString());
449
450                 buf.bit_advance(IE::length::value - 24);
451                 return data;
452         }
453 };
454
455
456 template <class IE>     //MSB 1..7 bits
457 struct bit_accessor<IE, stdex::value::_8, false>
458 {
459         static_assert(IE::length::value > 0 && IE::length::value < 8, "something wrong with traits!");
460
461         static void put(u8 value, buffer<u8*>& buf)
462         {
463                 u8 const mask = static_cast<u8>((1u << IE::length::value) - 1);
464                 u8 const shift = 8 - buf.get_shift() - IE::length::value;
465                 u8 const data = buf.extract_u8(value, mask, shift);
466                 buf.put_u8(data);
467
468                 CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%02X(%02X) mask=%04X: %s", shift, buf.get_shift()
469                         , IE::length::value, data, value, mask, buf.toString());
470
471                 buf.bit_advance(IE::length::value);
472         }
473
474         static u8 get(buffer<u8 const*>& buf)
475         {
476                 u8 const mask = static_cast<u8>((1u << IE::length::value) - 1);
477                 u8 const shift = 8 - buf.get_shift() - IE::length::value;
478                 u8 const data = (buf.get_u8() >> shift) & mask;
479
480                 CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%02X mask=%02X: %s", shift, buf.get_shift()
481                         , IE::length::value, data, mask, buf.toString());
482
483                 buf.bit_advance(IE::length::value);
484                 return data;
485         }
486 };
487
488 template <class IE>     //MSB 9..15 bits
489 struct bit_accessor<IE, stdex::value::_16, false>
490 {
491         static_assert(IE::length::value > 8 && IE::length::value < 16, "something wrong with traits!");
492
493         static void put(u16 value, buffer<u8*>& buf)
494         {
495                 u16 const mask = static_cast<u16>((1u << IE::length::value) - 1);
496                 u16 const shift = 16 - buf.get_shift() - IE::length::value;
497                 u16 const data = buf.extract_u16(value, mask, shift);
498
499                 buf.push_u8(data >> 8);
500                 buf.put_u8(data);
501
502                 CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%04X(%04X) mask=%04X: %s", shift, buf.get_shift()
503                         , IE::length::value, data, value, mask, buf.toString());
504
505                 buf.bit_advance(IE::length::value - 8);
506         }
507
508         static u16 get(buffer<u8 const*>& buf)
509         {
510                 u16 const mask = static_cast<u16>((1u << IE::length::value) - 1);
511                 u16 const shift = 16 - buf.get_shift() - IE::length::value;
512                 u16 const data = (buf.get_u16() >> shift) & mask;
513                 buf.m_current += 1;
514
515                 CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%04X mask=%04X: %s", shift, buf.get_shift()
516                         , IE::length::value, data, mask, buf.toString());
517
518                 buf.bit_advance(IE::length::value - 8);
519                 return data;
520         }
521 };
522
523
524 template <class IE>     //MSB 17..24 bits
525 struct bit_accessor<IE, stdex::value::_24, false>
526 {
527         static_assert(IE::length::value > 16 && IE::length::value <= 24, "something wrong with traits!");
528
529         static void put(u32 value, buffer<u8*>& buf)
530         {
531                 u32 const mask = static_cast<u32>((1u << IE::length::value) - 1);
532                 u32 const shift = 24 - buf.get_shift() - IE::length::value;
533                 u32 const data = buf.extract_u24(value, mask, shift);
534
535                 buf.push_u8(data >> 16);
536                 buf.push_u8(data >> 8);
537                 buf.put_u8(data);
538
539                 CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%06X(%06X) mask=%06X: %s", shift, buf.get_shift()
540                         , IE::length::value, data, value, mask, buf.toString());
541
542                 buf.bit_advance(IE::length::value - 16);
543         }
544
545         static u32 get(buffer<u8 const*>& buf)
546         {
547                 u32 const mask = static_cast<u32>((1u << IE::length::value) - 1);
548                 u32 const shift = 24 - buf.get_shift() - IE::length::value;
549                 u32 const data = (buf.get_u24() >> shift) & mask;
550                 buf.m_current += 2;
551
552                 CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%06X mask=%06X: %s", shift, buf.get_shift()
553                         , IE::length::value, data, mask, buf.toString());
554
555                 buf.bit_advance(IE::length::value - 16);
556                 return data;
557         }
558 };
559
560 template <class IE>     //MSB 25..31 bits
561 struct bit_accessor<IE, stdex::value::_32, false>
562 {
563         static_assert(IE::length::value > 24 && IE::length::value < 32, "something wrong with traits!");
564
565         static void put(u32 value, buffer<u8*>& buf)
566         {
567                 u32 const mask = static_cast<u32>((1u << IE::length::value) - 1);
568                 u32 const shift = 32 - buf.get_shift() - IE::length::value;
569                 u32 const data = buf.extract_u32(value, mask, shift);
570
571                 buf.push_u8(data >> 24);
572                 buf.push_u8(data >> 16);
573                 buf.push_u8(data >> 8);
574                 buf.put_u8(data);
575
576                 CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%08X(%08X) mask=%08X: %s", shift, buf.get_shift()
577                         , IE::length::value, data, value, mask, buf.toString());
578
579                 buf.bit_advance(IE::length::value - 24);
580         }
581
582         static u32 get(buffer<u8 const*>& buf)
583         {
584                 u32 const mask = static_cast<u32>((1u << IE::length::value) - 1);
585                 u32 const shift = 32 - buf.get_shift() - IE::length::value;
586                 u32 const data = (buf.get_u32() >> shift) & mask;
587                 buf.m_current += 3;
588
589                 CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%08X mask=%08X: %s", shift, buf.get_shift()
590                         , IE::length::value, data, mask, buf.toString());
591
592                 buf.bit_advance(IE::length::value - 24);
593                 return data;
594         }
595 };
596
597 /********************************************************************************
598 bit_accessor_cross_byte
599 *********************************************************************************/
600 template<>
601 struct bit_accessor_cross_byte<false> //MSB
602 {
603         static bool put(u8 value, u8 length, buffer<u8*>& buf)
604         {
605                 u8 spare = 8 - buf.get_shift();
606
607                 if (spare < length)
608                 {
609                         length -= spare;
610                         u8 chunk = value >> length;
611                         u8 const mask = static_cast<u8>((1u << spare) - 1);
612                         u8 data = buf.extract_u8(chunk, mask, 0);
613                         buf.put_u8(data);
614
615                         buf.bit_advance(spare);
616                 }
617                 if (buf.checkBytesLeft(1))
618                 {
619                         u8 const mask = static_cast<u8>((1u << length) - 1);
620                         u8 const shift = 8 - buf.get_shift() - length;
621                         u8 data = buf.extract_u8(value, mask, shift);
622                         buf.put_u8(data);
623
624                         buf.bit_advance(length);
625
626                         return true;
627                 }
628                 return false;
629         }
630
631         static u8 get(u8 length, buffer<u8 const*>& buf)
632         {
633                 u8 rval {0};
634                 u8 const mask = static_cast<u8>((1u << length) - 1);
635                 u8 const spare = 8 - buf.get_shift();
636                 if (spare < length)
637                 {
638                         length -= spare;
639                         rval = buf.get_u8() << length;
640                         buf.bit_advance(spare);
641                 }
642                 if (length && buf.checkBytesLeft(1))
643                 {
644                         u8 val = buf.get_u8();
645                         val = val >> (8 - length - buf.get_shift());
646                         rval |= val;
647                         rval &= mask;
648                         buf.bit_advance(length);
649                 }
650                 return rval;
651         }
652
653         static void padByte(buffer<u8*>& buf)
654         {
655                 if (buf.get_shift())
656                 {
657                         u8 mask = static_cast<u8>((1u << buf.get_shift()) - 1);
658                         mask = mask << (8 - buf.get_shift());
659                         buf.begin()[0] &= mask;
660                         buf.bit_advance(8 - buf.get_shift());
661                 }
662         }
663
664         static void padByte(buffer<u8 const*>& buf)
665         {
666                 if(buf.get_shift())
667                         buf.bit_advance(8 - buf.get_shift());
668         }
669
670         static bool put(const u8* in, size_t len, buffer<u8*>& buf, u8 trail_bitsqty)
671         {
672                 if (len)
673                 {
674                         if (trail_bitsqty)
675                         {
676                                 buf.putBytes(in, len - 1);
677                                 u8 last_byte = in[len - 1];
678                                 last_byte = last_byte >> (8 - trail_bitsqty);
679                                 return put(last_byte, trail_bitsqty, buf);
680                         }
681                         buf.putBytes(in, len);
682                 }
683                 return true;
684         }
685 };
686
687 }       //end: namespace asn
688
689