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