fr.arakne.utils.encoding.Base64.ord(char)   C
last analyzed

Complexity

Conditions 10

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 10

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 15
c 1
b 0
f 0
dl 0
loc 21
ccs 10
cts 10
cp 1
crap 10
rs 5.9999

How to fix   Complexity   

Complexity

Complex classes like fr.arakne.utils.encoding.Base64.ord(char) often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*
2
 * This file is part of ArakneUtils.
3
 *
4
 * ArakneUtils is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * ArakneUtils is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public License
15
 * along with ArakneUtils.  If not, see <https://www.gnu.org/licenses/>.
16
 *
17
 * Copyright (c) 2017-2020 Vincent Quatrevieux
18
 */
19
20
package fr.arakne.utils.encoding;
21
22
import org.checkerframework.checker.index.qual.NonNegative;
23
import org.checkerframework.checker.index.qual.PolyLength;
24
import org.checkerframework.common.value.qual.IntRange;
25
import org.checkerframework.dataflow.qual.Pure;
26
import org.checkerframework.dataflow.qual.SideEffectFree;
27
28
/**
29
 * Utility class for Dofus Pseudo base 64
30
 */
31
public final class Base64 {
32 1
    private static final char[] CHARSET = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
33
        't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
34
        'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'};
35
36
    /**
37
     * Disable constructor
38
     */
39
    private Base64() {}
40
41
    /**
42
     * Get int value of base64 char
43
     *
44
     * Example:
45
     * <code>
46
     *     Base64.ord('d'); // 3
47
     *     Base64.ord(Base64.chr(3)) == 3;
48
     * </code>
49
     *
50
     * @param c Char to convert
51
     * @return The int value, between 0 and 63 included
52
     *
53
     * @throws IllegalArgumentException When a character outside the charset is given
54
     * @see Base64#ord(char) For perform the opposite operation
55
     * @see Base64#decode(String) For decode an int string
56
     */
57
    @Pure
58
    public static @IntRange(from = 0, to = 63) int ord(char c) {
59 1
        if (c >= 'a' && c <= 'z') {
60 1
            return c - 'a';
61
        }
62
63 1
        if (c >= 'A' && c <= 'Z') {
64 1
            return c - 'A' + 26;
65
        }
66
67 1
        if (c >= '0' && c <= '9') {
68 1
            return c - '0' + 52;
69
        }
70
71 1
        switch (c) {
72
            case '-':
73 1
                return 62;
74
            case '_':
75 1
                return 63;
76
            default:
77 1
                throw new IllegalArgumentException("Invalid char value");
78
        }
79
    }
80
81
    /**
82
     * Get the base 64 character for the value
83
     *
84
     * Example:
85
     * <code>
86
     *     Base64.chr(3); // 'd'
87
     *     Base64.chr(Base64.ord('B')) == 'B';
88
     * </code>
89
     *
90
     * @param value Value to encode. Must be in interval [0, 63]
91
     * @return Encoded value
92
     *
93
     * @see Base64#ord(char) For perform the opposite operation
94
     * @see Base64#encode(int, int) For encode a 32 bits integer to a string
95
     */
96
    @Pure
97
    public static char chr(@IntRange(from = 0, to = 63) int value) {
98 1
        return CHARSET[value];
99
    }
100
101
    /**
102
     * Get the base 64 character for the value,
103
     * but after applying a modulo on the value to ensure that the call will not fail
104
     *
105
     * @param value Value to encode.
106
     * @return Encoded value
107
     */
108
    @Pure
109
    public static char chrMod(@NonNegative int value) {
110 1
        return CHARSET[value % CHARSET.length];
111
    }
112
113
    /**
114
     * Encode an int value to pseudo base 64
115
     *
116
     * Example:
117
     * <code>
118
     *     Base64.encode(145, 2); // "cr"
119
     *     Base64.encode(2, 3); // "aac"
120
     * </code>
121
     *
122
     * @param value Value to encode
123
     * @param length The expected result length. Must be between 1 and 6 included
124
     *
125
     * @return The encoded value. The returned string length will be exactly the same as length parameter
126
     *
127
     * @throws IllegalArgumentException When the length parameter is invalid
128
     */
129
    @SideEffectFree
130
    public static String encode(int value, @IntRange(from = 1, to = 6) int length) {
131 1
        if (length < 1 || length > 6) {
132 1
            throw new IllegalArgumentException("Invalid length parameter : it must be in range [1-6]");
133
        }
134
135 1
        final char[] encoded = new char[length];
136
137 1
        for (int i = length - 1; i >= 0; --i) {
138 1
            encoded[i] = CHARSET[value & 63];
139 1
            value >>= 6;
140
        }
141
142 1
        return new String(encoded);
143
    }
144
145
    /**
146
     * Encode a byte array to Base64 string
147
     *
148
     * Example:
149
     * <code>
150
     *     Base64.encode(new byte[] {2, 31}); // "cF"
151
     * </code>
152
     *
153
     * @param data Data to encode
154
     *
155
     * @return The encoded value. The result length is the same as the data size
156
     *
157
     * @see Base64#toBytes(String) For the opposite operation
158
     */
159
    @SideEffectFree
160
    @SuppressWarnings("return") // Checker do not resolve the length
161
    public static @PolyLength String encode(@IntRange(from = 0, to = 63) byte @PolyLength [] data) {
162 1
        final char[] encoded = new char[data.length];
163
164 1
        for (int i = 0; i < data.length; ++i) {
165 1
            encoded[i] = chr(data[i]);
166
        }
167
168 1
        return new String(encoded);
169
    }
170
171
    /**
172
     * Decode pseudo base64 value to int
173
     *
174
     * Example:
175
     * <code>
176
     *     Base64.decode("c"); // 2
177
     *     Base64.decode("hk"); // 458
178
     * </code>
179
     *
180
     * @param encoded The encoded value
181
     * @return The decoded value
182
     *
183
     * @throws IllegalArgumentException When an invalid string is given
184
     */
185
    @Pure
186
    public static int decode(String encoded) {
187 1
        if (encoded.length() > 6) {
188 1
            throw new IllegalArgumentException("Invalid encoded string : too long");
189
        }
190
191 1
        int value = 0;
192
193 1
        for (int i = 0; i < encoded.length(); ++i) {
194 1
            value <<= 6;
195 1
            value += ord(encoded.charAt(i));
196
        }
197
198 1
        return value;
199
    }
200
201
    /**
202
     * Decode a Base 64 string to a byte array
203
     * Each byte will represents the {@link Base64#ord(char)} value of each characters
204
     *
205
     * Example:
206
     * <code>
207
     *     Base64.toBytes("cF"); // new byte[] {2, 31}
208
     * </code>
209
     *
210
     * @param encoded The encoded string
211
     *
212
     * @return The decode byte array. The array size will be the same as the string length
213
     */
214
    @SideEffectFree
215
    @SuppressWarnings("return") // Checker do not like polymorphism here
216
    public static byte @PolyLength [] toBytes(@PolyLength String encoded) {
217 1
        final byte[] decoded = new byte[encoded.length()];
218
219 1
        for (int i = 0; i < encoded.length(); ++i) {
220 1
            decoded[i] = (byte) Base64.ord(encoded.charAt(i));
221
        }
222
223 1
        return decoded;
224
    }
225
}
226