1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /*******************************************************************//** |
21 | @file include/ut0mem.ic |
22 | Memory primitives |
23 | |
24 | Created 5/30/1994 Heikki Tuuri |
25 | ************************************************************************/ |
26 | |
27 | #include "ut0byte.h" |
28 | #include "mach0data.h" |
29 | |
30 | /** Wrapper for memcpy(3). Copy memory area when the source and |
31 | target are not overlapping. |
32 | @param[in,out] dest copy to |
33 | @param[in] src copy from |
34 | @param[in] n number of bytes to copy |
35 | @return dest */ |
36 | UNIV_INLINE |
37 | void* |
38 | ut_memcpy(void* dest, const void* src, ulint n) |
39 | { |
40 | return(memcpy(dest, src, n)); |
41 | } |
42 | |
43 | /** Wrapper for memmove(3). Copy memory area when the source and |
44 | target are overlapping. |
45 | @param[in,out] dest Move to |
46 | @param[in] src Move from |
47 | @param[in] n number of bytes to move |
48 | @return dest */ |
49 | UNIV_INLINE |
50 | void* |
51 | ut_memmove(void* dest, const void* src, ulint n) |
52 | { |
53 | return(memmove(dest, src, n)); |
54 | } |
55 | |
56 | /** Wrapper for memcmp(3). Compare memory areas. |
57 | @param[in] str1 first memory block to compare |
58 | @param[in] str2 second memory block to compare |
59 | @param[in] n number of bytes to compare |
60 | @return negative, 0, or positive if str1 is smaller, equal, |
61 | or greater than str2, respectively. */ |
62 | UNIV_INLINE |
63 | int |
64 | ut_memcmp(const void* str1, const void* str2, ulint n) |
65 | { |
66 | return(memcmp(str1, str2, n)); |
67 | } |
68 | |
69 | /** Wrapper for strcpy(3). Copy a NUL-terminated string. |
70 | @param[in,out] dest Destination to copy to |
71 | @param[in] src Source to copy from |
72 | @return dest */ |
73 | UNIV_INLINE |
74 | char* |
75 | ut_strcpy(char* dest, const char* src) |
76 | { |
77 | return(strcpy(dest, src)); |
78 | } |
79 | |
80 | /** Wrapper for strlen(3). Determine the length of a NUL-terminated string. |
81 | @param[in] str string |
82 | @return length of the string in bytes, excluding the terminating NUL */ |
83 | UNIV_INLINE |
84 | ulint |
85 | ut_strlen(const char* str) |
86 | { |
87 | return(strlen(str)); |
88 | } |
89 | |
90 | /** Wrapper for strcmp(3). Compare NUL-terminated strings. |
91 | @param[in] str1 first string to compare |
92 | @param[in] str2 second string to compare |
93 | @return negative, 0, or positive if str1 is smaller, equal, |
94 | or greater than str2, respectively. */ |
95 | UNIV_INLINE |
96 | int |
97 | ut_strcmp(const char* str1, const char* str2) |
98 | { |
99 | return(strcmp(str1, str2)); |
100 | } |
101 | |
102 | /**********************************************************************//** |
103 | Converts a raw binary data to a NUL-terminated hex string. The output is |
104 | truncated if there is not enough space in "hex", make sure "hex_size" is at |
105 | least (2 * raw_size + 1) if you do not want this to happen. Returns the |
106 | actual number of characters written to "hex" (including the NUL). |
107 | @return number of chars written */ |
108 | UNIV_INLINE |
109 | ulint |
110 | ut_raw_to_hex( |
111 | /*==========*/ |
112 | const void* raw, /*!< in: raw data */ |
113 | ulint raw_size, /*!< in: "raw" length in bytes */ |
114 | char* hex, /*!< out: hex string */ |
115 | ulint hex_size) /*!< in: "hex" size in bytes */ |
116 | { |
117 | |
118 | #ifdef WORDS_BIGENDIAN |
119 | |
120 | #define MK_UINT16(a, b) (((uint16) (a)) << 8 | (uint16) (b)) |
121 | |
122 | #define UINT16_GET_A(u) ((char) ((u) >> 8)) |
123 | #define UINT16_GET_B(u) ((char) ((u) & 0xFF)) |
124 | |
125 | #else /* WORDS_BIGENDIAN */ |
126 | |
127 | #define MK_UINT16(a, b) (((uint16) (b)) << 8 | (uint16) (a)) |
128 | |
129 | #define UINT16_GET_A(u) ((char) ((u) & 0xFF)) |
130 | #define UINT16_GET_B(u) ((char) ((u) >> 8)) |
131 | |
132 | #endif /* WORDS_BIGENDIAN */ |
133 | |
134 | #define MK_ALL_UINT16_WITH_A(a) \ |
135 | MK_UINT16(a, '0'), \ |
136 | MK_UINT16(a, '1'), \ |
137 | MK_UINT16(a, '2'), \ |
138 | MK_UINT16(a, '3'), \ |
139 | MK_UINT16(a, '4'), \ |
140 | MK_UINT16(a, '5'), \ |
141 | MK_UINT16(a, '6'), \ |
142 | MK_UINT16(a, '7'), \ |
143 | MK_UINT16(a, '8'), \ |
144 | MK_UINT16(a, '9'), \ |
145 | MK_UINT16(a, 'A'), \ |
146 | MK_UINT16(a, 'B'), \ |
147 | MK_UINT16(a, 'C'), \ |
148 | MK_UINT16(a, 'D'), \ |
149 | MK_UINT16(a, 'E'), \ |
150 | MK_UINT16(a, 'F') |
151 | |
152 | static const uint16 hex_map[256] = { |
153 | MK_ALL_UINT16_WITH_A('0'), |
154 | MK_ALL_UINT16_WITH_A('1'), |
155 | MK_ALL_UINT16_WITH_A('2'), |
156 | MK_ALL_UINT16_WITH_A('3'), |
157 | MK_ALL_UINT16_WITH_A('4'), |
158 | MK_ALL_UINT16_WITH_A('5'), |
159 | MK_ALL_UINT16_WITH_A('6'), |
160 | MK_ALL_UINT16_WITH_A('7'), |
161 | MK_ALL_UINT16_WITH_A('8'), |
162 | MK_ALL_UINT16_WITH_A('9'), |
163 | MK_ALL_UINT16_WITH_A('A'), |
164 | MK_ALL_UINT16_WITH_A('B'), |
165 | MK_ALL_UINT16_WITH_A('C'), |
166 | MK_ALL_UINT16_WITH_A('D'), |
167 | MK_ALL_UINT16_WITH_A('E'), |
168 | MK_ALL_UINT16_WITH_A('F') |
169 | }; |
170 | const unsigned char* rawc; |
171 | ulint read_bytes; |
172 | ulint write_bytes; |
173 | ulint i; |
174 | |
175 | rawc = (const unsigned char*) raw; |
176 | |
177 | if (hex_size == 0) { |
178 | |
179 | return(0); |
180 | } |
181 | |
182 | if (hex_size <= 2 * raw_size) { |
183 | |
184 | read_bytes = hex_size / 2; |
185 | write_bytes = hex_size; |
186 | } else { |
187 | |
188 | read_bytes = raw_size; |
189 | write_bytes = 2 * raw_size + 1; |
190 | } |
191 | |
192 | #define LOOP_READ_BYTES(ASSIGN) \ |
193 | for (i = 0; i < read_bytes; i++) { \ |
194 | ASSIGN; \ |
195 | hex += 2; \ |
196 | rawc++; \ |
197 | } |
198 | |
199 | if (ut_align_offset(hex, 2) == 0) { |
200 | |
201 | LOOP_READ_BYTES( |
202 | *(uint16*) hex = hex_map[*rawc] |
203 | ); |
204 | } else { |
205 | |
206 | LOOP_READ_BYTES( |
207 | *hex = UINT16_GET_A(hex_map[*rawc]); |
208 | *(hex + 1) = UINT16_GET_B(hex_map[*rawc]) |
209 | ); |
210 | } |
211 | |
212 | if (hex_size <= 2 * raw_size && hex_size % 2 == 0) { |
213 | |
214 | hex--; |
215 | } |
216 | |
217 | *hex = '\0'; |
218 | |
219 | return(write_bytes); |
220 | } |
221 | |
222 | /*******************************************************************//** |
223 | Adds single quotes to the start and end of string and escapes any quotes |
224 | by doubling them. Returns the number of bytes that were written to "buf" |
225 | (including the terminating NUL). If buf_size is too small then the |
226 | trailing bytes from "str" are discarded. |
227 | @return number of bytes that were written */ |
228 | UNIV_INLINE |
229 | ulint |
230 | ut_str_sql_format( |
231 | /*==============*/ |
232 | const char* str, /*!< in: string */ |
233 | ulint str_len, /*!< in: string length in bytes */ |
234 | char* buf, /*!< out: output buffer */ |
235 | ulint buf_size) /*!< in: output buffer size |
236 | in bytes */ |
237 | { |
238 | ulint str_i; |
239 | ulint buf_i; |
240 | |
241 | buf_i = 0; |
242 | |
243 | switch (buf_size) { |
244 | case 3: |
245 | |
246 | if (str_len == 0) { |
247 | |
248 | buf[buf_i] = '\''; |
249 | buf_i++; |
250 | buf[buf_i] = '\''; |
251 | buf_i++; |
252 | } |
253 | /* FALLTHROUGH */ |
254 | case 2: |
255 | case 1: |
256 | |
257 | buf[buf_i] = '\0'; |
258 | buf_i++; |
259 | /* FALLTHROUGH */ |
260 | case 0: |
261 | |
262 | return(buf_i); |
263 | } |
264 | |
265 | /* buf_size >= 4 */ |
266 | |
267 | buf[0] = '\''; |
268 | buf_i = 1; |
269 | |
270 | for (str_i = 0; str_i < str_len; str_i++) { |
271 | |
272 | char ch; |
273 | |
274 | if (buf_size - buf_i == 2) { |
275 | |
276 | break; |
277 | } |
278 | |
279 | ch = str[str_i]; |
280 | |
281 | switch (ch) { |
282 | case '\0': |
283 | |
284 | if (buf_size - buf_i < 4) { |
285 | |
286 | goto func_exit; |
287 | } |
288 | buf[buf_i] = '\\'; |
289 | buf_i++; |
290 | buf[buf_i] = '0'; |
291 | buf_i++; |
292 | break; |
293 | case '\'': |
294 | case '\\': |
295 | |
296 | if (buf_size - buf_i < 4) { |
297 | |
298 | goto func_exit; |
299 | } |
300 | buf[buf_i] = ch; |
301 | buf_i++; |
302 | /* FALLTHROUGH */ |
303 | default: |
304 | |
305 | buf[buf_i] = ch; |
306 | buf_i++; |
307 | } |
308 | } |
309 | |
310 | func_exit: |
311 | |
312 | buf[buf_i] = '\''; |
313 | buf_i++; |
314 | buf[buf_i] = '\0'; |
315 | buf_i++; |
316 | |
317 | return(buf_i); |
318 | } |
319 | |