42 private: |
42 private: |
43 ostream& output; |
43 ostream& output; |
44 wstring_convert<codecvt_utf8<wchar_t>> convertor; // only UTF8String is supported |
44 wstring_convert<codecvt_utf8<wchar_t>> convertor; // only UTF8String is supported |
45 int sequenceLevel = 0; |
45 int sequenceLevel = 0; |
46 |
46 |
47 void xxx_indent() { |
47 enum TagClass : uint8_t { |
48 // FIXME: remove |
48 /** The type is native to ASN.1 */ |
49 for (int i = 0; i < sequenceLevel; i++) output << " "; |
49 Universal = 0, |
|
50 /** The type is only valid for one specific application */ |
|
51 Application = 1, |
|
52 /** Meaning of this type depends on the context (such as within a sequence, set or choice) */ |
|
53 ContextSpecific = 2, |
|
54 /** Defined in private specifications */ |
|
55 Private = 3, |
|
56 }; |
|
57 |
|
58 enum PC : uint8_t { |
|
59 /** The contents octets directly encode the element value. */ |
|
60 Primitive = 0, |
|
61 /** The contents octets contain 0, 1, or more element encodings. */ |
|
62 Constructed = 1, |
|
63 }; |
|
64 |
|
65 enum UniversalType : uint16_t { |
|
66 Boolean = 1, |
|
67 Integer = 2, |
|
68 OctetString = 4, |
|
69 Null = 5, |
|
70 ObjectIdentifier = 6, |
|
71 Real = 9, |
|
72 UTF8String = 12, |
|
73 RelativeObjectIdentifier = 13, |
|
74 Sequence = 16, |
|
75 }; |
|
76 |
|
77 void writeIdentifier(TagClass tagClass, PC pc, uint16_t tagNumber) { |
|
78 if (tagNumber > 30) throw cli::RelpipeCLIException(L"Tag numbers higher than 30 are currently unsupported.", cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // should not happen, error in the program // TODO: support tag numbers > 30 |
|
79 uint8_t tag = 0; |
|
80 tag |= tagClass << 6; |
|
81 tag |= pc << 5; |
|
82 tag |= tagNumber; |
|
83 output.put(tag); |
|
84 } |
|
85 |
|
86 /** |
|
87 * @param der |
|
88 * @param length |
|
89 */ |
|
90 template<typename N, typename = typename std::enable_if<std::is_unsigned<N>::value, N>::type> |
|
91 void writeLength(N length) { |
|
92 if (length < 128) { |
|
93 output.put(length); |
|
94 } else { |
|
95 for (int i = sizeof (N) - 1; i >= 0; i--) { |
|
96 uint8_t b = length >> (i * 8); |
|
97 if (b || i == 0) { |
|
98 output.put((i + 1) | 0x80); |
|
99 for (; i >= 0; i--) { |
|
100 b = length >> (i * 8); |
|
101 output.put(b); |
|
102 } |
|
103 break; |
|
104 } |
|
105 } |
|
106 } |
|
107 } |
|
108 |
|
109 static bool isLittleEndian() { |
|
110 int test = 1; |
|
111 return (*(char *) &test); |
|
112 } |
|
113 |
|
114 static bool isBigEndian() { |
|
115 return !isLittleEndian(); |
50 } |
116 } |
51 |
117 |
52 public: |
118 public: |
53 |
119 |
54 ASN1Writer(std::ostream& output) : output(output) { |
120 ASN1Writer(std::ostream& output) : output(output) { |
55 } |
121 } |
56 |
122 |
57 virtual ~ASN1Writer() { |
123 virtual ~ASN1Writer() { |
58 if (sequenceLevel) output << "Unable to close ASN1Writer because there are not ended sequences." << endl; // FIXME: better error handling |
|
59 output.flush(); |
124 output.flush(); |
60 } |
125 } |
61 |
126 |
|
127 /** |
|
128 * Just check whether all sequences are closed. If not, throws RelpipeCLIException. |
|
129 */ |
|
130 void end() { |
|
131 if (sequenceLevel) throw cli::RelpipeCLIException(L"Unable to close ASN1Writer because there are not ended sequences.", cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // should not happen, error in the program |
|
132 } |
|
133 |
62 void writeStartSequence() { |
134 void writeStartSequence() { |
63 xxx_indent(); |
|
64 output << "sequence start" << endl; |
|
65 |
|
66 sequenceLevel++; |
135 sequenceLevel++; |
|
136 output.put('\x30'); |
|
137 output.put('\x80'); |
67 } |
138 } |
68 |
139 |
69 void writeEndSequence() { |
140 void writeEndSequence() { |
70 if (sequenceLevel == 0) throw cli::RelpipeCLIException(L"Unable to writeEndSequence() if not sequence is currently started.", cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // should not happen, error in the program |
141 if (sequenceLevel == 0) throw cli::RelpipeCLIException(L"Unable to writeEndSequence() if not sequence is currently started.", cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // should not happen, error in the program |
71 |
|
72 sequenceLevel--; |
142 sequenceLevel--; |
73 |
143 output.put('\x00'); |
74 xxx_indent(); |
144 output.put('\x00'); |
75 output << "sequence end" << endl; |
|
76 } |
145 } |
77 |
146 |
78 void writeBoolean(const boolean_t& value) { |
147 void writeBoolean(const boolean_t& value) { |
79 xxx_indent(); |
148 output.put('\x01'); |
80 output << "boolean" << (value ? "true" : "false") << endl; |
149 output.put('\x01'); |
|
150 output.put(value ? '\xFF' : '\x00'); |
|
151 |
81 } |
152 } |
82 |
153 |
83 void writeInteger(const integer_t& value) { |
154 void writeInteger(const integer_t& value) { |
84 xxx_indent(); |
155 uint8_t* end = (uint8_t*) & value; |
85 output << "integer: " << value << endl; |
156 uint8_t* start = end + sizeof (value) - 1; |
|
157 uint8_t* current; |
|
158 int direction = -1; |
|
159 |
|
160 if (isBigEndian()) { |
|
161 std::swap(end, start); |
|
162 direction = -direction; |
|
163 } |
|
164 |
|
165 // move current pointer to the first valuable octet |
|
166 for (current = start; current != end; current += direction) { |
|
167 switch (*current) { |
|
168 case 0x00: if ((*(current + direction) & 0x80) == 0) continue; |
|
169 break; |
|
170 case 0xFF: if ((*(current + direction) & 0x80) != 0) continue; |
|
171 break; |
|
172 } |
|
173 break; |
|
174 } |
|
175 |
|
176 std::vector<char> v; |
|
177 writeIdentifier(TagClass::Universal, PC::Primitive, UniversalType::Integer); |
|
178 writeLength((size_t) (end > current ? end - current : current - end) + 1); |
|
179 for (end += direction; current != end; current += direction) output.put(*current); |
86 } |
180 } |
87 |
181 |
88 void writeString(const string_t& value) { |
182 void writeString(const string_t& value) { |
89 xxx_indent(); |
183 // TODO: empty string → null? |
90 output << "string: " << convertor.to_bytes(value) << endl; |
184 std::string bytes = convertor.to_bytes(value); |
|
185 writeIdentifier(TagClass::Universal, PC::Primitive, UniversalType::UTF8String); |
|
186 writeLength(bytes.length()); |
|
187 output << bytes; |
91 } |
188 } |
92 |
189 |
93 }; |
190 }; |
94 |
191 |
95 } |
192 } |