chiark / gitweb /
configure.ac: Replace with a new version.
[catacomb] / key-fetch.c
1 /* -*-c-*-
2  *
3  * $Id$
4  *
5  * Higher-level key unpacking
6  *
7  * (c) 2000 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------*
11  *
12  * This file is part of Catacomb.
13  *
14  * Catacomb is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU Library General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  *
19  * Catacomb is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU Library General Public
25  * License along with Catacomb; if not, write to the Free
26  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27  * MA 02111-1307, USA.
28  */
29
30 /*----- Header files ------------------------------------------------------*/
31
32 #include <mLib/dstr.h>
33
34 #include "key.h"
35 #include "key-data.h"
36
37 /*----- Main code ---------------------------------------------------------*/
38
39 /* --- @key_fetchinit@ --- *
40  *
41  * Arguments:   @const key_fetchdef *kf@ = pointer to base definition
42  *              @key_packstruct *kps@ = pointer to destination packing def
43  *              @void *p@ = pointer to destination block
44  *
45  * Returns:     Pointer to packing definition.
46  *
47  * Use:         Initializes a packing definition (@key_packdef@ structure).
48  *              If @kps@ is null on entry, an appropriately sized block is
49  *              allocated automatically.  Otherwise it must be large enough.
50  */
51
52 static size_t kfcount(const key_fetchdef *kf)
53 {
54   size_t n = 1;
55   while (kf->name) {
56     n++;
57     if (kf->kf)
58       n += kfcount(kf->kf);
59     kf++;
60   }
61   return (n);
62 }
63
64 key_packdef *key_fetchinit(const key_fetchdef *kf,
65                            key_packstruct *kp, void *p)
66 {
67   size_t n = 1 + kfcount(kf);
68   key_packdef *kpd;
69   key_packstruct *kps;
70   char *cp = p;
71
72   /* --- If @kps@ is null, count the entries and allocate --- */
73
74   if (kp)
75     kp->name = 0;
76   else {
77     kp = xmalloc(n * sizeof(*kp));
78     kp->name = (char *)kp;
79   }
80
81   /* --- Fill in the top part --- */
82
83   kp->kp.e = KENC_STRUCT;
84   kp->kp.p = &kp[1];
85   kp->kp.kd = 0;
86   kpd = &kp->kp;
87
88   /* --- Initialize for the main loop --- */
89
90   kps = kp + n;
91   n = 0;
92   kp++;
93
94   /* --- Iterate over the entries in the table --- *
95    *
96    * The end of the target block is used as a stack to record where
97    * substructure is meant to occur.  The integer @n@ is the depth of the
98    * stack; @kps@ is a full descending stack pointer.  The @kp.p@ member of a
99    * stack element points back to an entry with substructure, the @kp.p@
100    * member of which refers to the @kf@ table for the substructure.
101    *
102    * This should all be about as clear as mud.
103    */
104
105   for (;;) {
106
107     /* --- Blat out a level's worth --- */
108
109     while (kf->name) {
110       kp->name = kf->name;
111       kp->kp.e = kf->e;
112       kp->kp.kd = 0;
113       if ((kf->e & KF_ENCMASK) != KENC_STRUCT)
114         kp->kp.p = cp + kf->off;
115       else {
116         (--kps)->kp.p = kp;
117         kp->kp.p = (void *)kf->kf;
118         n++;
119       }
120       kf++;
121       kp++;
122     }
123     (kp++)->name = 0;
124     if (!n)
125       break;
126
127     /* --- Pop an entry from the stack --- */
128
129     {
130       key_packstruct *kkp = (kps++)->kp.p;
131       kf = kkp->kp.p;
132       kkp->kp.p = kp;
133       n--;
134     }
135   }
136
137   /* --- We're done --- */
138
139   return (kpd);
140 }
141
142 /* --- @key_fetch@ --- *
143  *
144  * Arguments:   @key_packdef *kp@ = pointer to packing structure
145  *              @key *k@ = key file containing desired key
146  *
147  * Returns:     Error code, or zero.
148  *
149  * Use:         Fetches an unpacked key from a packed one.
150  */
151
152 int key_fetch(key_packdef *kp, key *k)
153 {
154   dstr d = DSTR_INIT;
155   int e;
156
157   key_fulltag(k, &d);
158   e = key_unpack(kp, k->k, &d);
159   dstr_destroy(&d);
160   return (e);
161 }
162
163 /* --- @key_fetchbyname@ --- *
164  *
165  * Arguments:   @key_packdef *kp@ = pointer to packing structure
166  *              @key_file *kf@ = key file containing desired key
167  *              @const char *tag@ = user's tag describing the key
168  *
169  * Returns:     Error code, or zero.
170  *
171  * Use:         Fetches a named key from a key file and unpacks it
172  *              conveniently.
173  */
174
175 int key_fetchbyname(key_packdef *kp, key_file *kf, const char *tag)
176 {
177   dstr d = DSTR_INIT;
178   key_data **kd;
179   int e;
180
181   if (key_qtag(kf, tag, &d, 0, &kd))
182     e = KERR_NOTFOUND;
183   else
184     e = key_unpack(kp, *kd, &d);
185   dstr_destroy(&d);
186   return (e);
187 }
188
189 /* --- @key_fetchdone@ --- *
190  *
191  * Arguments:   @key_packdef *kp@ = pointer to packing structure
192  *
193  * Returns:     ---
194  *
195  * Use:         Frees a packing structure.  If the structure was allocated by
196  *              @key_fetchinit@ then it is freed.
197  */
198
199 void key_fetchdone(key_packdef *kp)
200 {
201   key_packstruct *kps =
202     (key_packstruct *)(((char *)kp) - offsetof(key_packstruct, kp));
203   key_unpackdone(kp);
204   if (kps->name)
205     xfree(kps);
206 }
207
208 /*----- That's all, folks -------------------------------------------------*/