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