/src/util-linux/lib/mangle.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Functions for \oct encoding used in mtab/fstab/swaps/etc. |
3 | | * |
4 | | * No copyright is claimed. This code is in the public domain; do with |
5 | | * it what you wish. |
6 | | * |
7 | | * Written by Karel Zak <kzak@redhat.com> [2010] |
8 | | */ |
9 | | #include <stdio.h> |
10 | | #include <stdlib.h> |
11 | | #include <string.h> |
12 | | #include <ctype.h> |
13 | | |
14 | | #include "mangle.h" |
15 | | #include "c.h" |
16 | | |
17 | 5.12M | #define isoctal(a) (((a) & ~7) == '0') |
18 | | |
19 | 0 | #define from_hex(c) (isdigit(c) ? c - '0' : tolower(c) - 'a' + 10) |
20 | | |
21 | 0 | #define is_unwanted_char(x) (strchr(" \t\n\\", (unsigned int) x) != NULL) |
22 | | |
23 | | |
24 | | char *mangle(const char *s) |
25 | 0 | { |
26 | 0 | char *ss, *sp; |
27 | |
|
28 | 0 | if (!s) |
29 | 0 | return NULL; |
30 | | |
31 | 0 | ss = sp = malloc(4 * strlen(s) + 1); |
32 | 0 | if (!sp) |
33 | 0 | return NULL; |
34 | 0 | while(1) { |
35 | 0 | if (!*s) { |
36 | 0 | *sp = '\0'; |
37 | 0 | break; |
38 | 0 | } |
39 | 0 | if (is_unwanted_char(*s)) { |
40 | 0 | *sp++ = '\\'; |
41 | 0 | *sp++ = '0' + ((*s & 0300) >> 6); |
42 | 0 | *sp++ = '0' + ((*s & 070) >> 3); |
43 | 0 | *sp++ = '0' + (*s & 07); |
44 | 0 | } else |
45 | 0 | *sp++ = *s; |
46 | 0 | s++; |
47 | 0 | } |
48 | 0 | return ss; |
49 | 0 | } |
50 | | |
51 | | |
52 | | void unmangle_to_buffer(const char *s, char *buf, size_t len) |
53 | 212k | { |
54 | 212k | size_t sz = 0; |
55 | | |
56 | 212k | if (!s) |
57 | 0 | return; |
58 | | |
59 | 2.62M | while(*s && sz < len - 1) { |
60 | 2.41M | if (*s == '\\' && sz + 3 < len - 1 && isoctal(s[1]) && |
61 | 2.41M | isoctal(s[2]) && isoctal(s[3])) { |
62 | | |
63 | 478 | *buf++ = 64*(s[1] & 7) + 8*(s[2] & 7) + (s[3] & 7); |
64 | 478 | s += 4; |
65 | 478 | sz += 4; |
66 | 2.41M | } else { |
67 | 2.41M | *buf++ = *s++; |
68 | 2.41M | sz++; |
69 | 2.41M | } |
70 | 2.41M | } |
71 | 212k | *buf = '\0'; |
72 | 212k | } |
73 | | |
74 | | size_t unhexmangle_to_buffer(const char *s, char *buf, size_t len) |
75 | 0 | { |
76 | 0 | size_t sz = 0; |
77 | 0 | const char *buf0 = buf; |
78 | |
|
79 | 0 | if (!s) |
80 | 0 | return 0; |
81 | | |
82 | 0 | while(*s && sz < len - 1) { |
83 | 0 | if (*s == '\\' && sz + 3 < len - 1 && s[1] == 'x' && |
84 | 0 | isxdigit(s[2]) && isxdigit(s[3])) { |
85 | |
|
86 | 0 | *buf++ = from_hex(s[2]) << 4 | from_hex(s[3]); |
87 | 0 | s += 4; |
88 | 0 | sz += 4; |
89 | 0 | } else { |
90 | 0 | *buf++ = *s++; |
91 | 0 | sz++; |
92 | 0 | } |
93 | 0 | } |
94 | 0 | *buf = '\0'; |
95 | 0 | return buf - buf0 + 1; |
96 | 0 | } |
97 | | |
98 | | size_t unescape_to_buffer(const char *s, const char *wanted, char *buf, size_t len) |
99 | 0 | { |
100 | 0 | size_t sz = 0; |
101 | 0 | const char *buf0 = buf; |
102 | |
|
103 | 0 | while (*s && sz < len - 1) { |
104 | 0 | if (*s == '\\' && sz + 1 < len - 1 && strchr(wanted, s[1])) { |
105 | 0 | *buf++ = s[1]; |
106 | 0 | s += 2; |
107 | 0 | sz += 2; |
108 | 0 | } else { |
109 | 0 | *buf++ = *s++;; |
110 | 0 | sz++; |
111 | 0 | } |
112 | 0 | } |
113 | 0 | *buf = '\0'; |
114 | 0 | return buf - buf0 + 1; |
115 | 0 | } |
116 | | |
117 | | static inline const char *skip_nonspaces(const char *s) |
118 | 256k | { |
119 | 2.67M | while (s && *s && !(*s == ' ' || *s == '\t')) |
120 | 2.41M | s++; |
121 | 256k | return s; |
122 | 256k | } |
123 | | |
124 | | /* |
125 | | * Returns mallocated buffer or NULL in case of error. |
126 | | */ |
127 | | char *unmangle(const char *s, const char **end) |
128 | 256k | { |
129 | 256k | char *buf; |
130 | 256k | const char *e; |
131 | 256k | size_t sz; |
132 | | |
133 | 256k | if (!s) |
134 | 0 | return NULL; |
135 | | |
136 | 256k | e = skip_nonspaces(s); |
137 | 256k | sz = e - s + 1; |
138 | | |
139 | 256k | if (end) |
140 | 256k | *end = e; |
141 | 256k | if (e == s) |
142 | 44.3k | return NULL; /* empty string */ |
143 | | |
144 | 212k | buf = malloc(sz); |
145 | 212k | if (!buf) |
146 | 0 | return NULL; |
147 | | |
148 | 212k | unmangle_to_buffer(s, buf, sz); |
149 | 212k | return buf; |
150 | 212k | } |
151 | | |
152 | | #ifdef TEST_PROGRAM_MANGLE |
153 | | #include <errno.h> |
154 | | int main(int argc, char *argv[]) |
155 | | { |
156 | | char *p = NULL; |
157 | | if (argc < 3) { |
158 | | fprintf(stderr, "usage: %s --mangle|unmangle|unescape <string>\n", |
159 | | program_invocation_short_name); |
160 | | return EXIT_FAILURE; |
161 | | } |
162 | | |
163 | | if (!strcmp(argv[1], "--mangle")) { |
164 | | p = mangle(argv[2]); |
165 | | printf("mangled: '%s'\n", p); |
166 | | free(p); |
167 | | } |
168 | | |
169 | | else if (!strcmp(argv[1], "--unmangle")) { |
170 | | char *x = unmangle(argv[2], NULL); |
171 | | |
172 | | if (x) { |
173 | | printf("unmangled: '%s'\n", x); |
174 | | free(x); |
175 | | } |
176 | | |
177 | | x = strdup(argv[2]); |
178 | | if (x) { |
179 | | unmangle_to_buffer(x, x, strlen(x) + 1); |
180 | | |
181 | | printf("self-unmangled: '%s'\n", x); |
182 | | free(x); |
183 | | } |
184 | | } |
185 | | |
186 | | else if (!strcmp(argv[1], "--unescape")) { |
187 | | char *x = strdup(argv[2]); |
188 | | if (x) { |
189 | | unescape_to_buffer(x, ",\"", x, strlen(x) + 1); |
190 | | |
191 | | printf("self-unescaped: '%s'\n", x); |
192 | | free(x); |
193 | | } |
194 | | } |
195 | | |
196 | | return EXIT_SUCCESS; |
197 | | } |
198 | | #endif /* TEST_PROGRAM_MANGLE */ |