r8302: import mini HEIMDAL into the tree
[kai/samba.git] / source4 / heimdal / lib / asn1 / gen_encode.c
1 /*
2  * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 #include "gen_locl.h"
35
36 RCSID("$Id: gen_encode.c,v 1.15 2005/05/29 14:23:01 lha Exp $");
37
38 static void
39 encode_primitive (const char *typename, const char *name)
40 {
41     fprintf (codefile,
42              "e = encode_%s(p, len, %s, &l);\n"
43              "BACK;\n",
44              typename,
45              name);
46 }
47
48 static void
49 encode_type (const char *name, const Type *t)
50 {
51     switch (t->type) {
52     case TType:
53 #if 0
54         encode_type (name, t->symbol->type);
55 #endif
56         fprintf (codefile,
57                  "e = encode_%s(p, len, %s, &l);\n"
58                  "BACK;\n",
59                  t->symbol->gen_name, name);
60         break;
61     case TInteger:
62         if(t->members == NULL)
63             encode_primitive ("integer", name);
64         else {
65             char *s;
66             asprintf(&s, "(const int*)%s", name);
67             if(s == NULL)
68                 errx(1, "out of memory");
69             encode_primitive ("integer", s);
70             free(s);
71         }
72         break;
73     case TUInteger:
74         encode_primitive ("unsigned", name);
75         break;
76     case TOctetString:
77         encode_primitive ("octet_string", name);
78         break;
79     case TOID :
80         encode_primitive ("oid", name);
81         break;
82     case TBitString: {
83         Member *m;
84         int pos;
85         int rest;
86         int tag = -1;
87
88         if (t->members == NULL)
89             break;
90
91         fprintf (codefile, "{\n"
92                  "unsigned char c = 0;\n");
93         pos = t->members->prev->val;
94         /* fix for buggy MIT (and OSF?) code */
95         if (pos > 31)
96             abort ();
97         /*
98          * It seems that if we do not always set pos to 31 here, the MIT
99          * code will do the wrong thing.
100          *
101          * I hate ASN.1 (and DER), but I hate it even more when everybody
102          * has to screw it up differently.
103          */
104         pos = 31;
105         rest = 7 - (pos % 8);
106
107         for (m = t->members->prev; m && tag != m->val; m = m->prev) {
108             while (m->val / 8 < pos / 8) {
109                 fprintf (codefile,
110                          "*p-- = c; len--; ret++;\n"
111                          "c = 0;\n");
112                 pos -= 8;
113             }
114             fprintf (codefile,
115                      "if(%s->%s) c |= 1<<%d;\n", name, m->gen_name,
116                      7 - m->val % 8);
117
118             if (tag == -1)
119                 tag = m->val;
120         }
121
122         fprintf (codefile, 
123                  "*p-- = c;\n"
124                  "*p-- = %d;\n"
125                  "len -= 2;\n"
126                  "ret += 2;\n"
127                  "}\n\n"
128                  "e = der_put_length_and_tag (p, len, ret, ASN1_C_UNIV, PRIM,"
129                  "UT_BitString, &l);\n"
130                  "BACK;\n",
131                  rest);
132         break;
133     }
134     case TEnumerated : {
135         encode_primitive ("enumerated", name);
136         break;
137     }
138     case TSequence: {
139         Member *m;
140         int tag = -1;
141         int oldret_counter = unique_get_next();
142
143         if (t->members == NULL)
144             break;
145
146         for (m = t->members->prev; m && tag != m->val; m = m->prev) {
147             char *s;
148
149             asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name);
150             if (m->optional)
151                 fprintf (codefile,
152                          "if(%s)\n",
153                          s);
154 #if 1
155             fprintf (codefile, "{\n"
156                      "int oldret%d = ret;\n"
157                      "ret = 0;\n",
158                      oldret_counter);
159 #endif
160             encode_type (s, m->type);
161             fprintf (codefile,
162                      "e = der_put_length_and_tag (p, len, ret, ASN1_C_CONTEXT, CONS, "
163                      "%d, &l);\n"
164                      "BACK;\n",
165                      m->val);
166 #if 1
167             fprintf (codefile,
168                      "ret += oldret%d;\n"
169                      "}\n",
170                      oldret_counter);
171 #endif
172             if (tag == -1)
173                 tag = m->val;
174             free (s);
175         }
176         fprintf (codefile,
177                  "e = der_put_length_and_tag (p, len, ret, ASN1_C_UNIV, CONS, UT_Sequence, &l);\n"
178                  "BACK;\n");
179         break;
180     }
181     case TSequenceOf: {
182         int oldret_counter = unique_get_next();
183         char *n;
184
185         fprintf (codefile,
186                  "for(i = (%s)->len - 1; i >= 0; --i) {\n"
187 #if 1
188                  "int oldret%d = ret;\n"
189                  "ret = 0;\n",
190 #else
191                  ,
192 #endif
193                  name, oldret_counter);
194         asprintf (&n, "&(%s)->val[i]", name);
195         encode_type (n, t->subtype);
196         fprintf (codefile,
197 #if 1
198                  "ret += oldret%d;\n"
199 #endif
200                  "}\n"
201                  "e = der_put_length_and_tag (p, len, ret, ASN1_C_UNIV, CONS, UT_Sequence, &l);\n"
202                  "BACK;\n"
203 #if 1
204                  , oldret_counter
205 #endif
206             );
207         free (n);
208         break;
209     }
210     case TGeneralizedTime:
211         encode_primitive ("generalized_time", name);
212         break;
213     case TGeneralString:
214         encode_primitive ("general_string", name);
215         break;
216     case TUTF8String:
217         encode_primitive ("utf8string", name);
218         break;
219     case TNull:
220         fprintf (codefile,
221                  "e = encode_nulltype(p, len, &l);\n"
222                  "BACK;\n");
223         break;
224     case TApplication:
225         encode_type (name, t->subtype);
226         fprintf (codefile,
227                  "e = der_put_length_and_tag (p, len, ret, ASN1_C_APPL, CONS, %d, &l);\n"
228                  "BACK;\n",
229                  t->application);
230         break;
231     case TBoolean:
232         encode_primitive ("boolean", name);
233         break;
234     default:
235         abort ();
236     }
237 }
238
239 void
240 generate_type_encode (const Symbol *s)
241 {
242   fprintf (headerfile,
243            "int    "
244            "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n",
245            s->gen_name, s->gen_name);
246
247   fprintf (codefile, "#define BACK if (e) return e; p -= l; len -= l; ret += l\n\n");
248
249
250   fprintf (codefile, "int\n"
251            "encode_%s(unsigned char *p, size_t len,"
252            " const %s *data, size_t *size)\n"
253            "{\n",
254            s->gen_name, s->gen_name);
255
256   switch (s->type->type) {
257   case TInteger:
258   case TUInteger:
259   case TBoolean:
260   case TOctetString:
261   case TGeneralizedTime:
262   case TGeneralString:
263   case TUTF8String:
264   case TNull:
265   case TBitString:
266   case TEnumerated:
267   case TOID:
268   case TSequence:
269   case TSequenceOf:
270   case TApplication:
271   case TType:
272     fprintf (codefile,
273              "size_t ret = 0;\n"
274              "size_t l;\n"
275              "int i, e;\n\n");
276     fprintf(codefile, "i = 0;\n"); /* hack to avoid `unused variable' */
277     
278       encode_type("data", s->type);
279
280     fprintf (codefile, "*size = ret;\n"
281              "return 0;\n");
282     break;
283   default:
284     abort ();
285   }
286   fprintf (codefile, "}\n\n");
287 }