1 /*
2 Copyright (c) 2019, 2020 MariaDB
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
16
17 #include "mariadb.h"
18
19 #include "sql_class.h"
20 #include "sql_type_string.h"
21
22
23 uchar *
pack(uchar * to,const uchar * from,uint max_length) const24 StringPack::pack(uchar *to, const uchar *from, uint max_length) const
25 {
26 size_t length= MY_MIN(m_octet_length, max_length);
27 size_t local_char_length= char_length();
28 DBUG_PRINT("debug", ("length: %zu ", length));
29
30 if (length > local_char_length)
31 local_char_length= charset()->charpos(from, from + length,
32 local_char_length);
33 set_if_smaller(length, local_char_length);
34
35 /*
36 TODO: change charset interface to add a new function that does
37 the following or add a flag to lengthsp to do it itself
38 (this is for not packing padding adding bytes in BINARY
39 fields).
40 */
41 if (mbmaxlen() == 1)
42 {
43 while (length && from[length-1] == charset()->pad_char)
44 length --;
45 }
46 else
47 length= charset()->lengthsp((const char*) from, length);
48
49 // Length always stored little-endian
50 *to++= (uchar) length;
51 if (m_octet_length > 255)
52 *to++= (uchar) (length >> 8);
53
54 // Store the actual bytes of the string
55 memcpy(to, from, length);
56 return to+length;
57 }
58
59
60 const uchar *
unpack(uchar * to,const uchar * from,const uchar * from_end,uint param_data) const61 StringPack::unpack(uchar *to, const uchar *from, const uchar *from_end,
62 uint param_data) const
63 {
64 uint from_length, length;
65
66 /*
67 Compute the declared length of the field on the master. This is
68 used to decide if one or two bytes should be read as length.
69 */
70 if (param_data)
71 from_length= (((param_data >> 4) & 0x300) ^ 0x300) + (param_data & 0x00ff);
72 else
73 from_length= m_octet_length;
74
75 DBUG_PRINT("debug",
76 ("param_data: 0x%x, field_length: %u, from_length: %u",
77 param_data, m_octet_length, from_length));
78 /*
79 Compute the actual length of the data by reading one or two bits
80 (depending on the declared field length on the master).
81 */
82 if (from_length > 255)
83 {
84 if (from + 2 > from_end)
85 return 0;
86 length= uint2korr(from);
87 from+= 2;
88 }
89 else
90 {
91 if (from + 1 > from_end)
92 return 0;
93 length= (uint) *from++;
94 }
95 if (from + length > from_end || length > m_octet_length)
96 return 0;
97
98 memcpy(to, from, length);
99 // Pad the string with the pad character of the fields charset
100 charset()->fill((char*) to + length,
101 m_octet_length - length,
102 charset()->pad_char);
103 return from+length;
104 }
105