/* hex-escape.c - Manage encoding and decoding of byte strings into path names * * Copyright (c) 2011 David Bremner * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/ . * * Author: David Bremner */ #include #include #include #include #include "error_util.h" #include "hex-escape.h" static const size_t default_buf_size = 1024; static const char *output_charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-_@=.:,"; static const int escape_char = '%'; static int is_output (char c) { return (strchr (output_charset, c) != NULL); } static int maybe_realloc (void *ctx, size_t needed, char **out, size_t *out_size) { if (*out_size < needed) { if (*out == NULL) *out = talloc_size (ctx, needed); else *out = talloc_realloc (ctx, *out, char, needed); if (*out == NULL) return 0; *out_size = needed; } return 1; } hex_status_t hex_encode (void *ctx, const char *in, char **out, size_t *out_size) { const unsigned char *p; char *q; size_t escape_count = 0; size_t len = 0; size_t needed; assert (ctx); assert (in); assert (out); assert (out_size); for (p = (unsigned char *) in; *p; p++) { escape_count += (!is_output (*p)); len++; } needed = len + escape_count * 2 + 1; if (*out == NULL) *out_size = 0; if (!maybe_realloc (ctx, needed, out, out_size)) return HEX_OUT_OF_MEMORY; q = *out; p = (unsigned char *) in; while (*p) { if (is_output (*p)) { *q++ = *p++; } else { sprintf (q, "%%%02x", *p++); q += 3; } } *q = '\0'; return HEX_SUCCESS; } hex_status_t hex_decode (void *ctx, const char *in, char **out, size_t * out_size) { char buf[3]; const char *p; unsigned char *q; size_t escape_count = 0; size_t needed = 0; assert (ctx); assert (in); assert (out); assert (out_size); size_t len = strlen (in); for (p = in; *p; p++) escape_count += (*p == escape_char); needed = len - escape_count * 2 + 1; if (!maybe_realloc (ctx, needed, out, out_size)) return HEX_OUT_OF_MEMORY; p = in; q = (unsigned char *) *out; buf[2] = 0; while (*p) { if (*p == escape_char) { char *endp; if (!isxdigit ((unsigned char) p[1]) || !isxdigit ((unsigned char) p[2])) return HEX_SYNTAX_ERROR; buf[0] = p[1]; buf[1] = p[2]; *q = strtoul (buf, &endp, 16); if (endp != buf + 2) return HEX_SYNTAX_ERROR; p += 3; q++; } else { *q++ = *p++; } } *q = '\0'; return HEX_SUCCESS; }