| 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 | |