1 /* hex-escape.c - Manage encoding and decoding of byte strings into path names
3 * Copyright (c) 2011 David Bremner
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see http://www.gnu.org/licenses/ .
18 * Author: David Bremner <david@tethera.net>
25 #include "error_util.h"
26 #include "hex-escape.h"
28 static const size_t default_buf_size = 1024;
30 static const char *output_charset =
31 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-_@=.,";
33 static const char escape_char = '%';
38 return (strchr (output_charset, c) != NULL);
42 maybe_realloc (void *ctx, size_t needed, char **out, size_t *out_size)
44 if (*out_size < needed) {
47 *out = talloc_size (ctx, needed);
49 *out = talloc_realloc (ctx, *out, char, needed);
60 hex_encode (void *ctx, const char *in, char **out, size_t *out_size)
66 size_t needed = 1; /* for the NUL */
68 assert (ctx); assert (in); assert (out); assert (out_size);
70 for (p = in; *p; p++) {
71 needed += is_output (*p) ? 1 : 3;
77 if (!maybe_realloc (ctx, needed, out, out_size))
78 return HEX_OUT_OF_MEMORY;
87 sprintf (q, "%%%02x", (unsigned char)*p++);
96 /* Hex decode 'in' to 'out'.
98 * This must succeed for in == out to support hex_decode_inplace().
101 hex_decode_internal (const char *in, unsigned char *out)
106 if (*in == escape_char) {
109 /* This also handles unexpected end-of-string. */
110 if (!isxdigit ((unsigned char) in[1]) ||
111 !isxdigit ((unsigned char) in[2]))
112 return HEX_SYNTAX_ERROR;
118 *out = strtoul (buf, &endp, 16);
121 return HEX_SYNTAX_ERROR;
136 hex_decode_inplace (char *s)
138 /* A decoded string is never longer than the encoded one, so it is
139 * safe to decode a string onto itself. */
140 return hex_decode_internal (s, (unsigned char *) s);
144 hex_decode (void *ctx, const char *in, char **out, size_t * out_size)
147 size_t needed = 1; /* for the NUL */
149 assert (ctx); assert (in); assert (out); assert (out_size);
151 for (p = in; *p; p++)
152 if ((p[0] == escape_char) && isxdigit (p[1]) && isxdigit (p[2]))
157 if (!maybe_realloc (ctx, needed, out, out_size))
158 return HEX_OUT_OF_MEMORY;
160 return hex_decode_internal (in, (unsigned char *) *out);