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 https://www.gnu.org/licenses/ .
18 * Author: David Bremner <david@tethera.net>
25 #include "error_util.h"
26 #include "hex-escape.h"
28 static const char *output_charset =
29 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-_@=.,";
31 static const char escape_char = '%';
36 return (strchr (output_charset, c) != NULL);
40 maybe_realloc (void *ctx, size_t needed, char **out, size_t *out_size)
42 if (*out_size < needed) {
45 *out = talloc_size (ctx, needed);
47 *out = talloc_realloc (ctx, *out, char, needed);
58 hex_encode (void *ctx, const char *in, char **out, size_t *out_size)
64 size_t needed = 1; /* for the NUL */
66 assert (ctx); assert (in); assert (out); assert (out_size);
68 for (p = in; *p; p++) {
69 needed += is_output (*p) ? 1 : 3;
75 if (! maybe_realloc (ctx, needed, out, out_size))
76 return HEX_OUT_OF_MEMORY;
85 sprintf (q, "%%%02x", (unsigned char) *p++);
94 /* Hex decode 'in' to 'out'.
96 * This must succeed for in == out to support hex_decode_inplace().
99 hex_decode_internal (const char *in, unsigned char *out)
104 if (*in == escape_char) {
107 /* This also handles unexpected end-of-string. */
108 if (! isxdigit ((unsigned char) in[1]) ||
109 ! isxdigit ((unsigned char) in[2]))
110 return HEX_SYNTAX_ERROR;
116 *out = strtoul (buf, &endp, 16);
119 return HEX_SYNTAX_ERROR;
134 hex_decode_inplace (char *s)
136 /* A decoded string is never longer than the encoded one, so it is
137 * safe to decode a string onto itself. */
138 return hex_decode_internal (s, (unsigned char *) s);
142 hex_decode (void *ctx, const char *in, char **out, size_t *out_size)
145 size_t needed = 1; /* for the NUL */
147 assert (ctx); assert (in); assert (out); assert (out_size);
149 for (p = in; *p; p++)
150 if ((p[0] == escape_char) && isxdigit (p[1]) && isxdigit (p[2]))
155 if (! maybe_realloc (ctx, needed, out, out_size))
156 return HEX_OUT_OF_MEMORY;
158 return hex_decode_internal (in, (unsigned char *) *out);