GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/utils/base64.cpp Lines: 21 92 22.8 %
Date: 2017-11-29 Branches: 5 39 12.8 %

Line Branch Exec Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | PHP HTML Embedded Scripting Language Version 3.0                     |
4
   +----------------------------------------------------------------------+
5
   | Copyright (c) 1997-2000 PHP Development Team (See Credits file)      |
6
   +----------------------------------------------------------------------+
7
   | This program is free software; you can redistribute it and/or modify |
8
   | it under the terms of one of the following licenses:                 |
9
   |                                                                      |
10
   |  A) the GNU General Public License as published by the Free Software |
11
   |     Foundation; either version 2 of the License, or (at your option) |
12
   |     any later version.                                               |
13
   |                                                                      |
14
   |  B) the PHP License as published by the PHP Development Team and     |
15
   |     included in the distribution in the file: LICENSE                |
16
   |                                                                      |
17
   | This program is distributed in the hope that it will be useful,      |
18
   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
19
   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
20
   | GNU General Public License for more details.                         |
21
   |                                                                      |
22
   | You should have received a copy of both licenses referred to here.   |
23
   | If you did not, or have any questions about PHP licensing, please    |
24
   | contact [email protected]                                                |
25
   +----------------------------------------------------------------------+
26
   | Author: Jim Winstead ([email protected])                                  |
27
   +----------------------------------------------------------------------+
28
   */
29
30
#include "utils/base64.h"
31
32
#include "utils/cast.h"
33
34
#include "debug.h"
35
36
static char base64_table[] =
37
{
38
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
39
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
40
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
41
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
42
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
43
};
44
static const char base64_pad = '=';
45
46
unsigned char *php3_base64_encode(const unsigned char *restrict const string,
47
                                  int length,
48
                                  int *restrict const ret_length)
49
{
50
    if (string == nullptr)
51
        return nullptr;
52
    const unsigned char *current = string;
53
    int i = 0;
54
    unsigned char *const result = static_cast<unsigned char *>(
55
        calloc(CAST_SIZE((length + 3 - length % 3) * 4 / 3 + 1)
56
        * sizeof(unsigned char), 1));
57
    if (result == nullptr)
58
        return nullptr;
59
60
    while (length > 2)
61
    { /* keep going until we have less than 24 bits */
62
        result[i++] = base64_table[current[0] >> 2];
63
        result[i++] = base64_table[((current[0] & 0x03)
64
                      << 4) + (current[1] >> 4)];
65
        result[i++] = base64_table[((current[1] & 0x0f)
66
                      << 2) + (current[2] >> 6)];
67
        result[i++] = base64_table[current[2] & 0x3f];
68
69
        current += 3;
70
        length -= 3; /* we just handle 3 octets of data */
71
    }
72
73
    /* now deal with the tail end of things */
74
    if (length != 0)
75
    {
76
        result[i++] = base64_table[current[0] >> 2];
77
        if (length > 1)
78
        {
79
            result[i++] = base64_table[((current[0] & 0x03) << 4)
80
                          + (current[1] >> 4)];
81
            result[i++] = base64_table[(current[1] & 0x0f) << 2];
82
            result[i++] = base64_pad;
83
        }
84
        else
85
        {
86
            result[i++] = base64_table[(current[0] & 0x03) << 4];
87
            result[i++] = base64_pad;
88
            result[i++] = base64_pad;
89
        }
90
    }
91
    if (ret_length != nullptr)
92
    {
93
        *ret_length = i;
94
    }
95
    result[i] = '\0';
96
    return result;
97
}
98
99
/* as above, but backwards. :) */
100
4
unsigned char *php3_base64_decode(const unsigned char *restrict const string,
101
                                  const int length,
102
                                  int *restrict const ret_length)
103
{
104
4
    const unsigned char *current = string;
105
4
    int ch, i = 0, j = 0, k;
106
107
    unsigned char *result = static_cast<unsigned char *>(
108
4
        calloc(length + 1, 1));
109
110
4
    if (result == nullptr)
111
        return nullptr;
112
113
    /* run through the whole string, converting as we go */
114
4
    while ((ch = *current++) != '\0')
115
    {
116
        if (ch == base64_pad)
117
            break;
118
119
        /* When Base64 gets POSTed, all pluses are interpreted as spaces.
120
           This line changes them back.  It's not exactly the Base64 spec,
121
           but it is completely compatible with it (the spec says that
122
           spaces are invalid).  This will also save many people considerable
123
           headache.  - Turadg Aleahmad <[email protected]>
124
           */
125
126
        if (ch == ' ') ch = '+';
127
128
        const char *const chp = strchr(base64_table, ch);
129
        if (chp == nullptr)
130
            continue;
131
        ch = CAST_S32(chp - base64_table);
132
133
        switch (i % 4)
134
        {
135
            case 0:
136
                result[j] = CAST_U8(ch << 2U);
137
                break;
138
            case 1:
139
                result[j++] |= CAST_U8(ch >> 4U);
140
                result[j] = CAST_U8((ch & 0x0f) << 4U);
141
                break;
142
            case 2:
143
                result[j++] |= CAST_U8(ch >>2U);
144
                result[j] = CAST_U8((ch & 0x03) << 6U);
145
                break;
146
            case 3:
147
                result[j++] |= CAST_U8(ch);
148
                break;
149
            default:
150
                break;
151
        }
152
        i++;
153
    }
154
155
4
    k = j;
156
    /* mop things up if we ended on a boundary */
157
4
    if (ch == base64_pad)
158
    {
159
        switch (i % 4)
160
        {
161
            case 0:
162
            case 1:
163
                free(result);
164
                return nullptr;
165
            case 2:
166
                k++;
167
                // copy from 3. is it should be here?
168
                result[k++] = 0;
169
                break;
170
            case 3:
171
                result[k++] = 0;
172
                break;
173
            default:
174
                break;
175
        }
176
    }
177
4
    if (ret_length != nullptr)
178
    {
179
4
        *ret_length = j;
180
    }
181
4
    result[k] = '\0';
182
4
    return result;
183
}
184
185
std::string encodeBase64String(std::string value)
186
{
187
    int sz = 0;
188
    const unsigned char *const str = reinterpret_cast<unsigned char*>(
189
        const_cast<char*>(value.c_str()));
190
    unsigned char *const buf = php3_base64_encode(
191
        str, CAST_S32(value.size()), &sz);
192
    if (buf == nullptr)
193
        return std::string();
194
195
    value = std::string(reinterpret_cast<char*>(buf), sz);
196
    free(buf);
197
    return value;
198
}
199
200
4
std::string decodeBase64String(std::string value)
201
{
202
4
    int sz = 0;
203
    const unsigned char *const str = reinterpret_cast<unsigned char*>(
204
4
        const_cast<char*>(value.c_str()));
205
4
    unsigned char *const buf = php3_base64_decode(
206
8
        str, CAST_S32(value.size()), &sz);
207
208
4
    if (buf != nullptr)
209
16
        value = std::string(reinterpret_cast<char*>(buf), sz);
210
    else
211
        value.clear();
212
4
    free(buf);
213
4
    return value;
214
}