1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.util;
11
12 import java.nio.charset.StandardCharsets;
13 import java.text.MessageFormat;
14 import java.util.Arrays;
15
16 import org.eclipse.jgit.internal.JGitText;
17
18
19
20
21
22
23 public final class Base85 {
24
25 private static final byte[] ENCODE = ("0123456789"
26 + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
27 + "abcdefghijklmnopqrstuvwxyz"
28 + "!#$%&()*+-;<=>?@^_`{|}~")
29 .getBytes(StandardCharsets.US_ASCII);
30
31 private static final int[] DECODE = new int[256];
32
33 static {
34 Arrays.fill(DECODE, -1);
35 for (int i = 0; i < ENCODE.length; i++) {
36 DECODE[ENCODE[i]] = i;
37 }
38 }
39
40 private Base85() {
41
42 }
43
44
45
46
47
48
49
50
51
52
53 public static int encodedLength(int rawLength) {
54 return (rawLength + 3) / 4 * 5;
55 }
56
57
58
59
60
61
62
63
64 public static byte[] encode(byte[] data) {
65 return encode(data, 0, data.length);
66 }
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public static byte[] encode(byte[] data, int start, int length) {
81 byte[] result = new byte[encodedLength(length)];
82 int end = start + length;
83 int in = start;
84 int out = 0;
85 while (in < end) {
86
87 long accumulator = ((long) (data[in++] & 0xFF)) << 24;
88 if (in < end) {
89 accumulator |= (data[in++] & 0xFF) << 16;
90 if (in < end) {
91 accumulator |= (data[in++] & 0xFF) << 8;
92 if (in < end) {
93 accumulator |= (data[in++] & 0xFF);
94 }
95 }
96 }
97
98 for (int i = 4; i >= 0; i--) {
99 result[out + i] = ENCODE[(int) (accumulator % 85)];
100 accumulator /= 85;
101 }
102 out += 5;
103 }
104 return result;
105 }
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 public static byte[] decode(byte[] encoded, int expectedSize) {
122 return decode(encoded, 0, encoded.length, expectedSize);
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 public static byte[] decode(byte[] encoded, int start, int length,
145 int expectedSize) {
146 if (length % 5 != 0) {
147 throw new IllegalArgumentException(JGitText.get().base85length);
148 }
149 byte[] result = new byte[expectedSize];
150 int end = start + length;
151 int in = start;
152 int out = 0;
153 while (in < end && out < expectedSize) {
154
155 long accumulator = 0;
156 for (int i = 4; i >= 0; i--) {
157 int val = DECODE[encoded[in++] & 0xFF];
158 if (val < 0) {
159 throw new IllegalArgumentException(MessageFormat.format(
160 JGitText.get().base85invalidChar,
161 Integer.toHexString(encoded[in - 1] & 0xFF)));
162 }
163 accumulator = accumulator * 85 + val;
164 }
165 if (accumulator > 0xFFFF_FFFFL) {
166 throw new IllegalArgumentException(
167 MessageFormat.format(JGitText.get().base85overflow,
168 Long.toHexString(accumulator)));
169 }
170
171 result[out++] = (byte) (accumulator >>> 24);
172 if (out < expectedSize) {
173 result[out++] = (byte) (accumulator >>> 16);
174 if (out < expectedSize) {
175 result[out++] = (byte) (accumulator >>> 8);
176 if (out < expectedSize) {
177 result[out++] = (byte) accumulator;
178 }
179 }
180 }
181 }
182
183 if (in < end) {
184 throw new IllegalArgumentException(
185 MessageFormat.format(JGitText.get().base85tooLong,
186 Integer.valueOf(expectedSize)));
187 }
188 if (out < expectedSize) {
189 throw new IllegalArgumentException(
190 MessageFormat.format(JGitText.get().base85tooShort,
191 Integer.valueOf(expectedSize)));
192 }
193 return result;
194 }
195 }