blob: 63b39d0803f66ede8b796e43174a9f440274afc9 [file] [log] [blame]
Lev Walkin59b176e2005-11-26 11:25:14 +00001/*
2 * Copyright (c) 2005 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
5#include <asn_system.h>
6#include <per_support.h>
7
8/*
Lev Walkin60364882005-11-28 06:58:11 +00009 * Extract a small number of bits (<= 31) from the specified PER data pointer.
Lev Walkin59b176e2005-11-26 11:25:14 +000010 */
11int32_t
12per_get_few_bits(asn_per_data_t *pd, int nbits) {
13 size_t off; /* Next after last bit offset */
14 uint32_t accum;
Lev Walkin1d9e8dd2005-12-07 05:46:03 +000015 const uint8_t *buf;
Lev Walkin59b176e2005-11-26 11:25:14 +000016
17 if(nbits < 0 || pd->nboff + nbits > pd->nbits)
18 return -1;
Lev Walkin59b176e2005-11-26 11:25:14 +000019
20 /*
21 * Normalize position indicator.
22 */
23 if(pd->nboff >= 8) {
24 pd->buffer += (pd->nboff >> 3);
25 pd->nbits -= (pd->nboff & ~0x07);
26 pd->nboff &= 0x07;
27 }
28 off = (pd->nboff += nbits);
29 buf = pd->buffer;
30
31 /*
32 * Extract specified number of bits.
33 */
34 if(off <= 8)
Lev Walkin60364882005-11-28 06:58:11 +000035 accum = nbits ? (buf[0]) >> (8 - off) : 0;
Lev Walkin59b176e2005-11-26 11:25:14 +000036 else if(off <= 16)
37 accum = ((buf[0] << 8) + buf[1]) >> (16 - off);
38 else if(off <= 24)
39 accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off);
40 else if(off <= 31)
41 accum = ((buf[0] << 24) + (buf[1] << 16)
42 + (buf[2] << 8) + (buf[3])) >> (32 - off);
Lev Walkin60364882005-11-28 06:58:11 +000043 else if(nbits <= 31) {
44 asn_per_data_t tpd = *pd;
45 /* Here are we with our 31-bits limit plus 1..7 bits offset. */
46 tpd.nboff -= nbits;
47 accum = per_get_few_bits(&tpd, nbits - 24) << 24;
48 accum |= per_get_few_bits(&tpd, 24);
49 } else {
Lev Walkin59b176e2005-11-26 11:25:14 +000050 pd->nboff -= nbits; /* Oops, revert back */
51 return -1;
52 }
53
Lev Walkin60364882005-11-28 06:58:11 +000054 return (accum & (((uint32_t)1 << nbits) - 1));
Lev Walkin59b176e2005-11-26 11:25:14 +000055}
56
57/*
58 * Extract a large number of bits from the specified PER data pointer.
59 */
60int
61per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int alright, int nbits) {
62 int32_t value;
63
64 if(alright && (nbits & 7)) {
65 /* Perform right alignment of a first few bits */
66 value = per_get_few_bits(pd, nbits & 0x07);
67 if(value < 0) return -1;
68 *dst++ = value; /* value is already right-aligned */
69 nbits &= ~7;
70 }
71
72 while(nbits) {
73 if(nbits >= 24) {
74 value = per_get_few_bits(pd, 24);
75 if(value < 0) return -1;
76 *(dst++) = value >> 16;
77 *(dst++) = value >> 8;
78 *(dst++) = value;
79 nbits -= 24;
80 } else {
81 value = per_get_few_bits(pd, nbits);
82 if(value < 0) return -1;
83 if(nbits & 7) { /* implies alright */
84 value <<= 8 - (nbits & 7),
85 nbits += 8 - (nbits & 7);
86 if(nbits > 24)
87 *dst++ = value >> 24;
88 }
89 if(nbits > 16)
90 *dst++ = value >> 16;
91 if(nbits > 8)
92 *dst++ = value >> 8;
93 *dst++ = value;
94 break;
95 }
96 }
97
98 return 0;
99}
100
101/*
102 * Get the length "n" from the stream.
103 */
104ssize_t
105uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) {
106 ssize_t value;
107
108 *repeat = 0;
109
110 if(ebits >= 0) return per_get_few_bits(pd, ebits);
111
112 value = per_get_few_bits(pd, 8);
113 if(value < 0) return -1;
114 if((value & 128) == 0) /* #10.9.3.6 */
115 return (value & 0x7F);
116 if((value & 64) == 0) { /* #10.9.3.7 */
117 value = ((value & 63) << 8) | per_get_few_bits(pd, 8);
118 if(value < 0) return -1;
119 return value;
120 }
121 value &= 63; /* this is "m" from X.691, #10.9.3.8 */
122 if(value < 1 || value > 4)
123 return -1;
124 *repeat = 1;
125 return (16384 * value);
126}
127
128/*
129 * Get the normally small non-negative whole number.
130 * X.691, #10.6
131 */
132ssize_t
133uper_get_nsnnwn(asn_per_data_t *pd) {
134 ssize_t value;
135
136 value = per_get_few_bits(pd, 7);
137 if(value & 64) { /* implicit (value < 0) */
138 value &= 63;
139 value <<= 2;
140 value |= per_get_few_bits(pd, 2);
141 if(value & 128) /* implicit (value < 0) */
142 return -1;
143 if(value == 0)
144 return 0;
145 if(value >= 3)
146 return -1;
147 value = per_get_few_bits(pd, 8 * value);
148 return value;
149 }
150
151 return value;
152}