ac90f3c8fe9ed9602d8688031c46a7986179f676
[pintos-anon] / src / lib / backdoor.c
1 #include "backdoor.h"
2 #include <stdbool.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 static void
7 marshal_int32 (int32_t value, void (*out) (uint8_t, void *aux), void *aux) 
8 {
9   out ((value >> 24) & 0xff, aux);
10   out ((value >> 16) & 0xff, aux);
11   out ((value >> 8) & 0xff, aux);
12   out (value & 0xff, aux);
13 }
14
15 static void
16 marshal_bytes (const void *buffer, size_t cnt,
17                void (*out) (uint8_t, void *aux), void *aux) 
18 {
19   const uint8_t *p = buffer;
20   size_t i;
21
22   for (i = 0; i < cnt; i++)
23     out (p[i], aux);
24 }
25
26 enum backdoor_error
27 backdoor_vmarshal (const char *types, va_list args,
28                    void (*out) (uint8_t, void *aux), void *aux) 
29 {
30   const char *p = types;
31
32   for (;;) 
33     {
34       /* Find next type character. */
35       while (*p == ' ')
36         p++;
37       if (*p == '\0')
38         return BACKDOOR_OK;
39       
40       out (*p, aux);
41       switch (*p++) 
42         {
43         case 's':
44           if (*p == '\'') 
45             {
46               const char *end = strchr (++p, '\'');
47               marshal_int32 (end - p, out, aux);
48               marshal_bytes (p, end - p, out, aux);
49               p = end + 1;
50             }
51           else
52             {
53               const char *s = va_arg (args, const char *);
54               marshal_int32 (strlen (s), out, aux);
55               marshal_bytes (s, strlen (s), out, aux);
56             }
57           break;
58
59         case 'i':
60           marshal_int32 (va_arg (args, int32_t), out, aux);
61           break;
62
63         case 'B':
64           {
65             const void *buffer = va_arg (args, const void *);
66             size_t size = va_arg (args, size_t);
67             marshal_int32 (size, out, aux);
68             marshal_bytes (buffer, size, out, aux);
69           }
70           break;
71
72         case 'b':
73           marshal_int32 (va_arg (args, int), out, aux);
74           break;
75
76         default:
77           return BACKDOOR_BAD_TYPE;
78         }
79     }
80 }
81
82 static bool
83 unmarshal_int32 (int32_t *value, 
84                  bool (*in) (uint8_t *, void *aux), void *aux) 
85 {
86   int32_t tmp;
87   int i;
88
89   tmp = 0;
90   for (i = 0; i < 4; i++) 
91     {
92       uint8_t b;
93       if (!in (&b, aux))
94         return false;
95
96       tmp = (tmp << 8) | b;
97     }
98   *value = tmp;
99   return true;
100 }
101
102 static bool
103 unmarshal_bytes (void *buffer, size_t cnt,
104                  bool (*in) (uint8_t *, void *aux), void *aux) 
105 {
106   uint8_t *p = buffer;
107   size_t i;
108
109   for (i = 0; i < cnt; i++) 
110     if (!in (&p[i], aux))
111       return false;
112   return true;
113 }
114
115 enum backdoor_error
116 backdoor_vunmarshal (const char *types, va_list args,
117                      bool (*in) (uint8_t *, void *aux), void *aux) 
118 {
119   const char *p = types;
120
121   for (;;) 
122     {
123       uint8_t c;
124       
125       /* Find next type character. */
126       while (*p == ' ')
127         p++;
128       if (*p == '\0')
129         return BACKDOOR_OK;
130
131       /* Check type character in input. */
132       if (!in (&c, aux))
133         return BACKDOOR_UNEXPECTED_EOF;
134       if (c != *p++)
135         return BACKDOOR_TYPE_MISMATCH;
136
137       switch (c) 
138         {
139         case 's': 
140           {
141             int32_t length;
142             
143             if (!unmarshal_int32 (&length, in, aux))
144               return BACKDOOR_UNEXPECTED_EOF;
145             if (length < 0)
146               return BACKDOOR_NEGATIVE_SIZE;
147             if (*p == '\'')
148               {
149                 const char *end = strchr (++p, '\'');
150                 if (length != end - p)
151                   return BACKDOOR_STRING_MISMATCH;
152                 while (p < end) 
153                   {
154                     uint8_t q;
155                     if (!in (&q, aux))
156                       return BACKDOOR_UNEXPECTED_EOF;
157                     if (q != *p++)
158                       return BACKDOOR_STRING_MISMATCH; 
159                   }
160                 p++;
161               }
162             else
163               {
164                 char *s = malloc (length + 1);
165                 if (s == NULL)
166                   return BACKDOOR_NOMEM;
167                 if (!unmarshal_bytes (s, length, in, aux)) 
168                   {
169                     free (s);
170                     return BACKDOOR_UNEXPECTED_EOF;
171                   }
172                 s[length] = '\0';
173                 *va_arg (args, char **) = s;
174               }
175           }
176           break;
177
178         case 'i':
179           if (!unmarshal_int32 (va_arg (args, int32_t *), in, aux))
180             return BACKDOOR_UNEXPECTED_EOF;
181           break;
182
183         case 'B':
184           {
185             int32_t size;
186             void *buffer;
187
188             if (!unmarshal_int32 (&size, in, aux))
189               return BACKDOOR_UNEXPECTED_EOF;
190             if (size < 0)
191               return BACKDOOR_NEGATIVE_SIZE;
192             buffer = malloc (size);
193             if (size > 0 && buffer == NULL)
194               return BACKDOOR_NOMEM;
195             if (!unmarshal_bytes (buffer, size, in, aux))
196               {
197                 free (buffer);
198                 return BACKDOOR_UNEXPECTED_EOF;
199               }
200             *va_arg (args, size_t *) = size;
201             *va_arg (args, void **) = buffer;
202           }
203           break;
204
205         case 'b':
206           {
207             int32_t b;
208             if (!unmarshal_int32 (&b, in, aux))
209               return BACKDOOR_UNEXPECTED_EOF;
210             *va_arg (args, bool *) = b;
211           }
212           break;
213
214         default:
215           return BACKDOOR_BAD_TYPE;
216         }
217     }
218 }