source: trunk/third/libsoup/libsoup/soup-misc.c @ 21108

Revision 21108, 9.3 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21107, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/*
3 * soup-misc.c: Miscellaneous functions
4
5 * Copyright (C) 2000-2003, Ximian, Inc.
6 */
7
8#include <ctype.h>
9#include <string.h>
10
11#include "soup-misc.h"
12
13/**
14 * soup_str_case_hash:
15 * @key: ASCII string to hash
16 *
17 * Hashes @key in a case-insensitive manner.
18 *
19 * Return value: the hash code.
20 **/
21guint
22soup_str_case_hash (gconstpointer key)
23{
24        const char *p = key;
25        guint h = g_ascii_toupper(*p);
26
27        if (h)
28                for (p += 1; *p != '\0'; p++)
29                        h = (h << 5) - h + g_ascii_toupper(*p);
30
31        return h;
32}
33
34/**
35 * soup_str_case_equal:
36 * @v1: an ASCII string
37 * @v2: another ASCII string
38 *
39 * Compares @v1 and @v2 in a case-insensitive manner
40 *
41 * Return value: %TRUE if they are equal (modulo case)
42 **/
43gboolean
44soup_str_case_equal (gconstpointer v1,
45                     gconstpointer v2)
46{
47        const char *string1 = v1;
48        const char *string2 = v2;
49
50        return g_ascii_strcasecmp (string1, string2) == 0;
51}
52
53/* Base64 utils (straight from camel-mime-utils.c) */
54#define d(x)
55
56static char *base64_alphabet =
57        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
58
59/*
60 * call this when finished encoding everything, to
61 * flush off the last little bit
62 */
63int
64soup_base64_encode_close (const guchar  *in,
65                          int            inlen,
66                          gboolean       break_lines,
67                          guchar        *out,
68                          int           *state,
69                          int           *save)
70{
71        int c1, c2;
72        unsigned char *outptr = out;
73
74        if (inlen > 0)
75                outptr += soup_base64_encode_step (in,
76                                                   inlen,
77                                                   break_lines,
78                                                   outptr,
79                                                   state,
80                                                   save);
81
82        c1 = ((unsigned char *) save) [1];
83        c2 = ((unsigned char *) save) [2];
84       
85        d(printf("mode = %d\nc1 = %c\nc2 = %c\n",
86                 (int)((char *) save) [0],
87                 (int)((char *) save) [1],
88                 (int)((char *) save) [2]));
89
90        switch (((char *) save) [0]) {
91        case 2:
92                outptr [2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ];
93                g_assert (outptr [2] != 0);
94                goto skip;
95        case 1:
96                outptr[2] = '=';
97        skip:
98                outptr [0] = base64_alphabet [ c1 >> 2 ];
99                outptr [1] = base64_alphabet [ c2 >> 4 | ( (c1&0x3) << 4 )];
100                outptr [3] = '=';
101                outptr += 4;
102                break;
103        }
104        if (break_lines)
105                *outptr++ = '\n';
106
107        *save = 0;
108        *state = 0;
109
110        return outptr-out;
111}
112
113/*
114 * performs an 'encode step', only encodes blocks of 3 characters to the
115 * output at a time, saves left-over state in state and save (initialise to
116 * 0 on first invocation).
117 */
118int
119soup_base64_encode_step (const guchar  *in,
120                         int            len,
121                         gboolean       break_lines,
122                         guchar        *out,
123                         int           *state,
124                         int           *save)
125{
126        register guchar *outptr;
127        register const guchar *inptr;
128
129        if (len <= 0)
130                return 0;
131
132        inptr = in;
133        outptr = out;
134
135        d (printf ("we have %d chars, and %d saved chars\n",
136                   len,
137                   ((char *) save) [0]));
138
139        if (len + ((char *) save) [0] > 2) {
140                const guchar *inend = in+len-2;
141                register int c1, c2, c3;
142                register int already;
143
144                already = *state;
145
146                switch (((char *) save) [0]) {
147                case 1: c1 = ((unsigned char *) save) [1]; goto skip1;
148                case 2: c1 = ((unsigned char *) save) [1];
149                        c2 = ((unsigned char *) save) [2]; goto skip2;
150                }
151               
152                /*
153                 * yes, we jump into the loop, no i'm not going to change it,
154                 * it's beautiful!
155                 */
156                while (inptr < inend) {
157                        c1 = *inptr++;
158                skip1:
159                        c2 = *inptr++;
160                skip2:
161                        c3 = *inptr++;
162                        *outptr++ = base64_alphabet [ c1 >> 2 ];
163                        *outptr++ = base64_alphabet [ c2 >> 4 |
164                                                      ((c1&0x3) << 4) ];
165                        *outptr++ = base64_alphabet [ ((c2 &0x0f) << 2) |
166                                                      (c3 >> 6) ];
167                        *outptr++ = base64_alphabet [ c3 & 0x3f ];
168                        /* this is a bit ugly ... */
169                        if (break_lines && (++already)>=19) {
170                                *outptr++='\n';
171                                already = 0;
172                        }
173                }
174
175                ((char *)save)[0] = 0;
176                len = 2-(inptr-inend);
177                *state = already;
178        }
179
180        d(printf("state = %d, len = %d\n",
181                 (int)((char *)save)[0],
182                 len));
183
184        if (len>0) {
185                register char *saveout;
186
187                /* points to the slot for the next char to save */
188                saveout = & (((char *)save)[1]) + ((char *)save)[0];
189
190                /* len can only be 0 1 or 2 */
191                switch(len) {
192                case 2: *saveout++ = *inptr++;
193                case 1: *saveout++ = *inptr++;
194                }
195                ((char *)save)[0]+=len;
196        }
197
198        d(printf("mode = %d\nc1 = %c\nc2 = %c\n",
199                 (int)((char *)save)[0],
200                 (int)((char *)save)[1],
201                 (int)((char *)save)[2]));
202
203        return outptr-out;
204}
205
206/**
207 * soup_base64_encode:
208 * @text: the binary data to encode.
209 * @len: the length of @text.
210 *
211 * Encode a sequence of binary data into it's Base-64 stringified
212 * representation.
213 *
214 * Return value: The Base-64 encoded string representing @text.
215 */
216char *
217soup_base64_encode (const char *text, int len)
218{
219        unsigned char *out;
220        int state = 0, outlen;
221        unsigned int save = 0;
222       
223        out = g_malloc (len * 4 / 3 + 5);
224        outlen = soup_base64_encode_close (text,
225                                           len,
226                                           FALSE,
227                                           out,
228                                           &state,
229                                           &save);
230        out[outlen] = '\0';
231        return (char *) out;
232}
233
234static unsigned char camel_mime_base64_rank[256] = {
235        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
236        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
237        255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
238         52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,  0,255,255,
239        255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
240         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
241        255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
242         41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,
243        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
244        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
245        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
246        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
247        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
248        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
249        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
250        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
251};
252
253/**
254 * base64_decode_step: decode a chunk of base64 encoded data
255 * @in: input stream
256 * @len: max length of data to decode
257 * @out: output stream
258 * @state: holds the number of bits that are stored in @save
259 * @save: leftover bits that have not yet been decoded
260 *
261 * Decodes a chunk of base64 encoded data
262 **/
263int
264soup_base64_decode_step (const guchar  *in,
265                         int            len,
266                         guchar        *out,
267                         int           *state,
268                         guint         *save)
269{
270        register const guchar *inptr;
271        register guchar *outptr;
272        const guchar *inend;
273        guchar c;
274        register unsigned int v;
275        int i;
276
277        inend = in+len;
278        outptr = out;
279
280        /* convert 4 base64 bytes to 3 normal bytes */
281        v=*save;
282        i=*state;
283        inptr = in;
284        while (inptr < inend) {
285                c = camel_mime_base64_rank [*inptr++];
286                if (c != 0xff) {
287                        v = (v<<6) | c;
288                        i++;
289                        if (i==4) {
290                                *outptr++ = v>>16;
291                                *outptr++ = v>>8;
292                                *outptr++ = v;
293                                i=0;
294                        }
295                }
296        }
297
298        *save = v;
299        *state = i;
300
301        /* quick scan back for '=' on the end somewhere */
302        /* fortunately we can drop 1 output char for each trailing = (upto 2) */
303        i=2;
304        while (inptr > in && i) {
305                inptr--;
306                if (camel_mime_base64_rank [*inptr] != 0xff) {
307                        if (*inptr == '=')
308                                outptr--;
309                        i--;
310                }
311        }
312
313        /* if i!= 0 then there is a truncation error! */
314        return outptr - out;
315}
316
317char *
318soup_base64_decode (const char   *text,
319                    int          *out_len)
320{
321        char *ret;
322        int inlen, state = 0, save = 0;
323
324        inlen = strlen (text);
325        ret = g_malloc0 (inlen);
326
327        *out_len = soup_base64_decode_step (text, inlen, ret, &state, &save);
328
329        return ret;
330}
331
332typedef struct {
333        gpointer instance;
334        guint    signal_id;
335} SoupSignalOnceData;
336
337static void
338signal_once_object_destroyed (gpointer ssod, GObject *ex_object)
339{
340        g_free (ssod);
341}
342
343static void
344signal_once_metamarshal (GClosure *closure, GValue *return_value,
345                         guint n_param_values, const GValue *param_values,
346                         gpointer invocation_hint, gpointer marshal_data)
347{
348        SoupSignalOnceData *ssod = marshal_data;
349
350        closure->marshal (closure, return_value, n_param_values,
351                          param_values, invocation_hint,
352                          ((GCClosure *)closure)->callback);
353
354        if (g_signal_handler_is_connected (ssod->instance, ssod->signal_id))
355                g_signal_handler_disconnect (ssod->instance, ssod->signal_id);
356        g_object_weak_unref (G_OBJECT (ssod->instance), signal_once_object_destroyed, ssod);
357        g_free (ssod);
358}
359
360/**
361 * soup_signal_connect_once:
362 * @instance: an object
363 * @detailed_signal: "signal-name" or "signal-name::detail" to connect to
364 * @c_handler: the #GCallback to connect
365 * @data: data to pass to @c_handler calls
366 *
367 * Connects a #GCallback function to a signal as with
368 * g_signal_connect(), but automatically removes the signal handler
369 * after its first invocation.
370 *
371 * Return value: the signal handler id
372 **/
373guint
374soup_signal_connect_once (gpointer instance, const char *detailed_signal,
375                          GCallback c_handler, gpointer data)
376{
377        SoupSignalOnceData *ssod;
378        GClosure *closure;
379
380        g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
381        g_return_val_if_fail (detailed_signal != NULL, 0);
382        g_return_val_if_fail (c_handler != NULL, 0);
383
384        ssod = g_new0 (SoupSignalOnceData, 1);
385        ssod->instance = instance;
386        g_object_weak_ref (G_OBJECT (instance), signal_once_object_destroyed, ssod);
387
388        closure = g_cclosure_new (c_handler, data, NULL);
389        g_closure_set_meta_marshal (closure, ssod, signal_once_metamarshal);
390
391        ssod->signal_id = g_signal_connect_closure (instance, detailed_signal,
392                                                    closure, FALSE);
393        return ssod->signal_id;
394}
Note: See TracBrowser for help on using the repository browser.