+ add base64 encoding to deal with out of band byte arrays (for JRedis)
This commit is contained in:
@@ -0,0 +1,569 @@
|
||||
package org.springframework.data.keyvalue.redis.connection.jredis;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/** A very fast and memory efficient class to encode and decode to and from BASE64 in full accordance
|
||||
* with RFC 2045.<br><br>
|
||||
* On Windows XP sp1 with 1.4.2_04 and later ;), this encoder and decoder is about 10 times faster
|
||||
* on small arrays (10 - 1000 bytes) and 2-3 times as fast on larger arrays (10000 - 1000000 bytes)
|
||||
* compared to <code>sun.misc.Encoder()/Decoder()</code>.<br><br>
|
||||
*
|
||||
* On byte arrays the encoder is about 20% faster than Jakarta Commons Base64 Codec for encode and
|
||||
* about 50% faster for decoding large arrays. This implementation is about twice as fast on very small
|
||||
* arrays (< 30 bytes). If source/destination is a <code>String</code> this
|
||||
* version is about three times as fast due to the fact that the Commons Codec result has to be recoded
|
||||
* to a <code>String</code> from <code>byte[]</code>, which is very expensive.<br><br>
|
||||
*
|
||||
* This encode/decode algorithm doesn't create any temporary arrays as many other codecs do, it only
|
||||
* allocates the resulting array. This produces less garbage and it is possible to handle arrays twice
|
||||
* as large as algorithms that create a temporary array. (E.g. Jakarta Commons Codec). It is unknown
|
||||
* whether Sun's <code>sun.misc.Encoder()/Decoder()</code> produce temporary arrays but since performance
|
||||
* is quite low it probably does.<br><br>
|
||||
*
|
||||
* The encoder produces the same output as the Sun one except that the Sun's encoder appends
|
||||
* a trailing line separator if the last character isn't a pad. Unclear why but it only adds to the
|
||||
* length and is probably a side effect. Both are in conformance with RFC 2045 though.<br>
|
||||
* Commons codec seem to always att a trailing line separator.<br><br>
|
||||
*
|
||||
* <b>Note!</b>
|
||||
* The encode/decode method pairs (types) come in three versions with the <b>exact</b> same algorithm and
|
||||
* thus a lot of code redundancy. This is to not create any temporary arrays for transcoding to/from different
|
||||
* format types. The methods not used can simply be commented out.<br><br>
|
||||
*
|
||||
* There is also a "fast" version of all decode methods that works the same way as the normal ones, but
|
||||
* har a few demands on the decoded input. Normally though, these fast verions should be used if the source if
|
||||
* the input is known and it hasn't bee tampered with.<br><br>
|
||||
*
|
||||
* If you find the code useful or you find a bug, please send me a note at base64 @ miginfocom . com.
|
||||
*
|
||||
* Licence (BSD):
|
||||
* ==============
|
||||
*
|
||||
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
* Neither the name of the MiG InfoCom AB nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* @version 2.2
|
||||
* @author Mikael Grev
|
||||
* Date: 2004-aug-02
|
||||
* Time: 11:31:11
|
||||
*/
|
||||
|
||||
class Base64 {
|
||||
private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
|
||||
private static final int[] IA = new int[256];
|
||||
static {
|
||||
Arrays.fill(IA, -1);
|
||||
for (int i = 0, iS = CA.length; i < iS; i++)
|
||||
IA[CA[i]] = i;
|
||||
IA['='] = 0;
|
||||
}
|
||||
|
||||
// ****************************************************************************************
|
||||
// * char[] version
|
||||
// ****************************************************************************************
|
||||
|
||||
/** Encodes a raw byte array into a BASE64 <code>char[]</code> representation i accordance with RFC 2045.
|
||||
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
|
||||
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
|
||||
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
|
||||
* little faster.
|
||||
* @return A BASE64 encoded array. Never <code>null</code>.
|
||||
*/
|
||||
public final static char[] encodeToChar(byte[] sArr, boolean lineSep) {
|
||||
// Check special case
|
||||
int sLen = sArr != null ? sArr.length : 0;
|
||||
if (sLen == 0)
|
||||
return new char[0];
|
||||
|
||||
int eLen = (sLen / 3) * 3; // Length of even 24-bits.
|
||||
int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
|
||||
int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
|
||||
char[] dArr = new char[dLen];
|
||||
|
||||
// Encode even 24-bits
|
||||
for (int s = 0, d = 0, cc = 0; s < eLen;) {
|
||||
// Copy next three bytes into lower 24 bits of int, paying attension to sign.
|
||||
int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
|
||||
|
||||
// Encode the int into four chars
|
||||
dArr[d++] = CA[(i >>> 18) & 0x3f];
|
||||
dArr[d++] = CA[(i >>> 12) & 0x3f];
|
||||
dArr[d++] = CA[(i >>> 6) & 0x3f];
|
||||
dArr[d++] = CA[i & 0x3f];
|
||||
|
||||
// Add optional line separator
|
||||
if (lineSep && ++cc == 19 && d < dLen - 2) {
|
||||
dArr[d++] = '\r';
|
||||
dArr[d++] = '\n';
|
||||
cc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Pad and encode last bits if source isn't even 24 bits.
|
||||
int left = sLen - eLen; // 0 - 2.
|
||||
if (left > 0) {
|
||||
// Prepare the int
|
||||
int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
|
||||
|
||||
// Set last four chars
|
||||
dArr[dLen - 4] = CA[i >> 12];
|
||||
dArr[dLen - 3] = CA[(i >>> 6) & 0x3f];
|
||||
dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : '=';
|
||||
dArr[dLen - 1] = '=';
|
||||
}
|
||||
return dArr;
|
||||
}
|
||||
|
||||
/** Decodes a BASE64 encoded char array. All illegal characters will be ignored and can handle both arrays with
|
||||
* and without line separators.
|
||||
* @param sArr The source array. <code>null</code> or length 0 will return an empty array.
|
||||
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
|
||||
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
|
||||
*/
|
||||
public final static byte[] decode(char[] sArr) {
|
||||
// Check special case
|
||||
int sLen = sArr != null ? sArr.length : 0;
|
||||
if (sLen == 0)
|
||||
return new byte[0];
|
||||
|
||||
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
|
||||
// so we don't have to reallocate & copy it later.
|
||||
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
|
||||
for (int i = 0; i < sLen; i++)
|
||||
// If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
|
||||
if (IA[sArr[i]] < 0)
|
||||
sepCnt++;
|
||||
|
||||
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
|
||||
if ((sLen - sepCnt) % 4 != 0)
|
||||
return null;
|
||||
|
||||
int pad = 0;
|
||||
for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0;)
|
||||
if (sArr[i] == '=')
|
||||
pad++;
|
||||
|
||||
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
|
||||
|
||||
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
|
||||
|
||||
for (int s = 0, d = 0; d < len;) {
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = 0;
|
||||
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
|
||||
int c = IA[sArr[s++]];
|
||||
if (c >= 0)
|
||||
i |= c << (18 - j * 6);
|
||||
else
|
||||
j--;
|
||||
}
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
if (d < len) {
|
||||
dArr[d++] = (byte) (i >> 8);
|
||||
if (d < len)
|
||||
dArr[d++] = (byte) i;
|
||||
}
|
||||
}
|
||||
return dArr;
|
||||
}
|
||||
|
||||
/** Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as
|
||||
* fast as {@link #decode(char[])}. The preconditions are:<br>
|
||||
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
|
||||
* + Line separator must be "\r\n", as specified in RFC 2045
|
||||
* + The array must not contain illegal characters within the encoded string<br>
|
||||
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
|
||||
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
|
||||
* @return The decoded array of bytes. May be of length 0.
|
||||
*/
|
||||
public final static byte[] decodeFast(char[] sArr) {
|
||||
// Check special case
|
||||
int sLen = sArr.length;
|
||||
if (sLen == 0)
|
||||
return new byte[0];
|
||||
|
||||
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
|
||||
|
||||
// Trim illegal chars from start
|
||||
while (sIx < eIx && IA[sArr[sIx]] < 0)
|
||||
sIx++;
|
||||
|
||||
// Trim illegal chars from end
|
||||
while (eIx > 0 && IA[sArr[eIx]] < 0)
|
||||
eIx--;
|
||||
|
||||
// get the padding count (=) (0, 1 or 2)
|
||||
int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
|
||||
int cCnt = eIx - sIx + 1; // Content count including possible separators
|
||||
int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
|
||||
|
||||
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
|
||||
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
|
||||
|
||||
// Decode all but the last 0 - 2 bytes.
|
||||
int d = 0;
|
||||
for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
|
||||
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
dArr[d++] = (byte) (i >> 8);
|
||||
dArr[d++] = (byte) i;
|
||||
|
||||
// If line separator, jump over it.
|
||||
if (sepCnt > 0 && ++cc == 19) {
|
||||
sIx += 2;
|
||||
cc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (d < len) {
|
||||
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
|
||||
int i = 0;
|
||||
for (int j = 0; sIx <= eIx - pad; j++)
|
||||
i |= IA[sArr[sIx++]] << (18 - j * 6);
|
||||
|
||||
for (int r = 16; d < len; r -= 8)
|
||||
dArr[d++] = (byte) (i >> r);
|
||||
}
|
||||
|
||||
return dArr;
|
||||
}
|
||||
|
||||
// ****************************************************************************************
|
||||
// * byte[] version
|
||||
// ****************************************************************************************
|
||||
|
||||
/** Encodes a raw byte array into a BASE64 <code>byte[]</code> representation i accordance with RFC 2045.
|
||||
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
|
||||
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
|
||||
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
|
||||
* little faster.
|
||||
* @return A BASE64 encoded array. Never <code>null</code>.
|
||||
*/
|
||||
public final static byte[] encodeToByte(byte[] sArr, boolean lineSep) {
|
||||
// Check special case
|
||||
int sLen = sArr != null ? sArr.length : 0;
|
||||
if (sLen == 0)
|
||||
return new byte[0];
|
||||
|
||||
int eLen = (sLen / 3) * 3; // Length of even 24-bits.
|
||||
int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
|
||||
int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
|
||||
byte[] dArr = new byte[dLen];
|
||||
|
||||
// Encode even 24-bits
|
||||
for (int s = 0, d = 0, cc = 0; s < eLen;) {
|
||||
// Copy next three bytes into lower 24 bits of int, paying attension to sign.
|
||||
int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
|
||||
|
||||
// Encode the int into four chars
|
||||
dArr[d++] = (byte) CA[(i >>> 18) & 0x3f];
|
||||
dArr[d++] = (byte) CA[(i >>> 12) & 0x3f];
|
||||
dArr[d++] = (byte) CA[(i >>> 6) & 0x3f];
|
||||
dArr[d++] = (byte) CA[i & 0x3f];
|
||||
|
||||
// Add optional line separator
|
||||
if (lineSep && ++cc == 19 && d < dLen - 2) {
|
||||
dArr[d++] = '\r';
|
||||
dArr[d++] = '\n';
|
||||
cc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Pad and encode last bits if source isn't an even 24 bits.
|
||||
int left = sLen - eLen; // 0 - 2.
|
||||
if (left > 0) {
|
||||
// Prepare the int
|
||||
int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
|
||||
|
||||
// Set last four chars
|
||||
dArr[dLen - 4] = (byte) CA[i >> 12];
|
||||
dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f];
|
||||
dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '=';
|
||||
dArr[dLen - 1] = '=';
|
||||
}
|
||||
return dArr;
|
||||
}
|
||||
|
||||
/** Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
|
||||
* and without line separators.
|
||||
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
|
||||
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
|
||||
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
|
||||
*/
|
||||
public final static byte[] decode(byte[] sArr) {
|
||||
// Check special case
|
||||
int sLen = sArr.length;
|
||||
|
||||
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
|
||||
// so we don't have to reallocate & copy it later.
|
||||
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
|
||||
for (int i = 0; i < sLen; i++)
|
||||
// If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
|
||||
if (IA[sArr[i] & 0xff] < 0)
|
||||
sepCnt++;
|
||||
|
||||
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
|
||||
if ((sLen - sepCnt) % 4 != 0)
|
||||
return null;
|
||||
|
||||
int pad = 0;
|
||||
for (int i = sLen; i > 1 && IA[sArr[--i] & 0xff] <= 0;)
|
||||
if (sArr[i] == '=')
|
||||
pad++;
|
||||
|
||||
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
|
||||
|
||||
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
|
||||
|
||||
for (int s = 0, d = 0; d < len;) {
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = 0;
|
||||
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
|
||||
int c = IA[sArr[s++] & 0xff];
|
||||
if (c >= 0)
|
||||
i |= c << (18 - j * 6);
|
||||
else
|
||||
j--;
|
||||
}
|
||||
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
if (d < len) {
|
||||
dArr[d++] = (byte) (i >> 8);
|
||||
if (d < len)
|
||||
dArr[d++] = (byte) i;
|
||||
}
|
||||
}
|
||||
|
||||
return dArr;
|
||||
}
|
||||
|
||||
|
||||
/** Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as
|
||||
* fast as {@link #decode(byte[])}. The preconditions are:<br>
|
||||
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
|
||||
* + Line separator must be "\r\n", as specified in RFC 2045
|
||||
* + The array must not contain illegal characters within the encoded string<br>
|
||||
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
|
||||
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
|
||||
* @return The decoded array of bytes. May be of length 0.
|
||||
*/
|
||||
public final static byte[] decodeFast(byte[] sArr) {
|
||||
// Check special case
|
||||
int sLen = sArr.length;
|
||||
if (sLen == 0)
|
||||
return new byte[0];
|
||||
|
||||
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
|
||||
|
||||
// Trim illegal chars from start
|
||||
while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0)
|
||||
sIx++;
|
||||
|
||||
// Trim illegal chars from end
|
||||
while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0)
|
||||
eIx--;
|
||||
|
||||
// get the padding count (=) (0, 1 or 2)
|
||||
int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
|
||||
int cCnt = eIx - sIx + 1; // Content count including possible separators
|
||||
int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
|
||||
|
||||
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
|
||||
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
|
||||
|
||||
// Decode all but the last 0 - 2 bytes.
|
||||
int d = 0;
|
||||
for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
|
||||
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
dArr[d++] = (byte) (i >> 8);
|
||||
dArr[d++] = (byte) i;
|
||||
|
||||
// If line separator, jump over it.
|
||||
if (sepCnt > 0 && ++cc == 19) {
|
||||
sIx += 2;
|
||||
cc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (d < len) {
|
||||
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
|
||||
int i = 0;
|
||||
for (int j = 0; sIx <= eIx - pad; j++)
|
||||
i |= IA[sArr[sIx++]] << (18 - j * 6);
|
||||
|
||||
for (int r = 16; d < len; r -= 8)
|
||||
dArr[d++] = (byte) (i >> r);
|
||||
}
|
||||
|
||||
return dArr;
|
||||
}
|
||||
|
||||
// ****************************************************************************************
|
||||
// * String version
|
||||
// ****************************************************************************************
|
||||
|
||||
/** Encodes a raw byte array into a BASE64 <code>String</code> representation i accordance with RFC 2045.
|
||||
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
|
||||
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
|
||||
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
|
||||
* little faster.
|
||||
* @return A BASE64 encoded array. Never <code>null</code>.
|
||||
*/
|
||||
public final static String encodeToString(byte[] sArr, boolean lineSep) {
|
||||
// Reuse char[] since we can't create a String incrementally anyway and StringBuffer/Builder would be slower.
|
||||
return new String(encodeToChar(sArr, lineSep));
|
||||
}
|
||||
|
||||
/** Decodes a BASE64 encoded <code>String</code>. All illegal characters will be ignored and can handle both strings with
|
||||
* and without line separators.<br>
|
||||
* <b>Note!</b> It can be up to about 2x the speed to call <code>decode(str.toCharArray())</code> instead. That
|
||||
* will create a temporary array though. This version will use <code>str.charAt(i)</code> to iterate the string.
|
||||
* @param str The source string. <code>null</code> or length 0 will return an empty array.
|
||||
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
|
||||
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
|
||||
*/
|
||||
public final static byte[] decode(String str) {
|
||||
// Check special case
|
||||
int sLen = str != null ? str.length() : 0;
|
||||
if (sLen == 0)
|
||||
return new byte[0];
|
||||
|
||||
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
|
||||
// so we don't have to reallocate & copy it later.
|
||||
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
|
||||
for (int i = 0; i < sLen; i++)
|
||||
// If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
|
||||
if (IA[str.charAt(i)] < 0)
|
||||
sepCnt++;
|
||||
|
||||
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
|
||||
if ((sLen - sepCnt) % 4 != 0)
|
||||
return null;
|
||||
|
||||
// Count '=' at end
|
||||
int pad = 0;
|
||||
for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0;)
|
||||
if (str.charAt(i) == '=')
|
||||
pad++;
|
||||
|
||||
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
|
||||
|
||||
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
|
||||
|
||||
for (int s = 0, d = 0; d < len;) {
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = 0;
|
||||
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
|
||||
int c = IA[str.charAt(s++)];
|
||||
if (c >= 0)
|
||||
i |= c << (18 - j * 6);
|
||||
else
|
||||
j--;
|
||||
}
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
if (d < len) {
|
||||
dArr[d++] = (byte) (i >> 8);
|
||||
if (d < len)
|
||||
dArr[d++] = (byte) i;
|
||||
}
|
||||
}
|
||||
return dArr;
|
||||
}
|
||||
|
||||
/** Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as
|
||||
* fast as {@link #decode(String)}. The preconditions are:<br>
|
||||
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
|
||||
* + Line separator must be "\r\n", as specified in RFC 2045
|
||||
* + The array must not contain illegal characters within the encoded string<br>
|
||||
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
|
||||
* @param s The source string. Length 0 will return an empty array. <code>null</code> will throw an exception.
|
||||
* @return The decoded array of bytes. May be of length 0.
|
||||
*/
|
||||
public final static byte[] decodeFast(String s) {
|
||||
// Check special case
|
||||
int sLen = s.length();
|
||||
if (sLen == 0)
|
||||
return new byte[0];
|
||||
|
||||
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
|
||||
|
||||
// Trim illegal chars from start
|
||||
while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0)
|
||||
sIx++;
|
||||
|
||||
// Trim illegal chars from end
|
||||
while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0)
|
||||
eIx--;
|
||||
|
||||
// get the padding count (=) (0, 1 or 2)
|
||||
int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end.
|
||||
int cCnt = eIx - sIx + 1; // Content count including possible separators
|
||||
int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0;
|
||||
|
||||
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
|
||||
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
|
||||
|
||||
// Decode all but the last 0 - 2 bytes.
|
||||
int d = 0;
|
||||
for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6
|
||||
| IA[s.charAt(sIx++)];
|
||||
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
dArr[d++] = (byte) (i >> 8);
|
||||
dArr[d++] = (byte) i;
|
||||
|
||||
// If line separator, jump over it.
|
||||
if (sepCnt > 0 && ++cc == 19) {
|
||||
sIx += 2;
|
||||
cc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (d < len) {
|
||||
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
|
||||
int i = 0;
|
||||
for (int j = 0; sIx <= eIx - pad; j++)
|
||||
i |= IA[s.charAt(sIx++)] << (18 - j * 6);
|
||||
|
||||
for (int r = 16; d < len; r -= 8)
|
||||
dArr[d++] = (byte) (i >> r);
|
||||
}
|
||||
|
||||
return dArr;
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long del(byte[]... keys) {
|
||||
try {
|
||||
return jredis.del(JredisUtils.convertMultiple(charset, keys));
|
||||
return jredis.del(JredisUtils.decodeMultiple(keys));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -119,7 +119,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean exists(byte[] key) {
|
||||
try {
|
||||
return jredis.exists(JredisUtils.convert(charset, key));
|
||||
return jredis.exists(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -128,7 +128,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean expire(byte[] key, long seconds) {
|
||||
try {
|
||||
return jredis.expire(JredisUtils.convert(charset, key), (int) seconds);
|
||||
return jredis.expire(JredisUtils.decode(key), (int) seconds);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -137,7 +137,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean expireAt(byte[] key, long unixTime) {
|
||||
try {
|
||||
return jredis.expireat(JredisUtils.convert(charset, key), unixTime);
|
||||
return jredis.expireat(JredisUtils.decode(key), unixTime);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -146,7 +146,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Collection<byte[]> keys(byte[] pattern) {
|
||||
try {
|
||||
return JredisUtils.convert(charset, jredis.keys(JredisUtils.convert(charset, pattern)));
|
||||
return JredisUtils.convertCollection(jredis.keys(JredisUtils.decode(pattern)));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -165,7 +165,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public byte[] randomKey() {
|
||||
try {
|
||||
return JredisUtils.convert(charset, jredis.randomkey());
|
||||
return JredisUtils.encode(jredis.randomkey());
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -174,7 +174,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public void rename(byte[] oldName, byte[] newName) {
|
||||
try {
|
||||
jredis.rename(JredisUtils.convert(charset, oldName), JredisUtils.convert(charset, newName));
|
||||
jredis.rename(JredisUtils.decode(oldName), JredisUtils.decode(newName));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -183,7 +183,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean renameNX(byte[] oldName, byte[] newName) {
|
||||
try {
|
||||
return jredis.renamenx(JredisUtils.convert(charset, oldName), JredisUtils.convert(charset, newName));
|
||||
return jredis.renamenx(JredisUtils.decode(oldName), JredisUtils.decode(newName));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -197,7 +197,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long ttl(byte[] key) {
|
||||
try {
|
||||
return jredis.ttl(JredisUtils.convert(charset, key));
|
||||
return jredis.ttl(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -206,7 +206,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public DataType type(byte[] key) {
|
||||
try {
|
||||
return JredisUtils.convertDataType(jredis.type(JredisUtils.convert(charset, key)));
|
||||
return JredisUtils.convertDataType(jredis.type(JredisUtils.decode(key)));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -229,7 +229,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public byte[] get(byte[] key) {
|
||||
try {
|
||||
return jredis.get(JredisUtils.convert(charset, key));
|
||||
return jredis.get(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -238,7 +238,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public void set(byte[] key, byte[] value) {
|
||||
try {
|
||||
jredis.set(JredisUtils.convert(charset, key), value);
|
||||
jredis.set(JredisUtils.decode(key), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -247,7 +247,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public byte[] getSet(byte[] key, byte[] value) {
|
||||
try {
|
||||
return jredis.getset(JredisUtils.convert(charset, key), value);
|
||||
return jredis.getset(JredisUtils.decode(key), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -256,7 +256,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long append(byte[] key, byte[] value) {
|
||||
try {
|
||||
return jredis.append(JredisUtils.convert(charset, key), value);
|
||||
return jredis.append(JredisUtils.decode(key), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -265,7 +265,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public List<byte[]> mGet(byte[]... keys) {
|
||||
try {
|
||||
return jredis.mget(JredisUtils.convertMultiple(charset, keys));
|
||||
return jredis.mget(JredisUtils.decodeMultiple(keys));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -274,7 +274,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public void mSet(Map<byte[], byte[]> tuple) {
|
||||
try {
|
||||
jredis.mset(JredisUtils.convert(charset, tuple));
|
||||
jredis.mset(JredisUtils.decodeMap(tuple));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -283,7 +283,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public void mSetNX(Map<byte[], byte[]> tuple) {
|
||||
try {
|
||||
jredis.msetnx(JredisUtils.convert(charset, tuple));
|
||||
jredis.msetnx(JredisUtils.decodeMap(tuple));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -297,7 +297,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean setNX(byte[] key, byte[] value) {
|
||||
try {
|
||||
return jredis.setnx(JredisUtils.convert(charset, key), value);
|
||||
return jredis.setnx(JredisUtils.decode(key), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -306,7 +306,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public byte[] substr(byte[] key, long start, long end) {
|
||||
try {
|
||||
return jredis.substr(JredisUtils.convert(charset, key), (long) start, (long) end);
|
||||
return jredis.substr(JredisUtils.decode(key), (long) start, (long) end);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -315,7 +315,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long decr(byte[] key) {
|
||||
try {
|
||||
return jredis.decr(JredisUtils.convert(charset, key));
|
||||
return jredis.decr(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -324,7 +324,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long decrBy(byte[] key, long value) {
|
||||
try {
|
||||
return jredis.decrby(JredisUtils.convert(charset, key), (int) value);
|
||||
return jredis.decrby(JredisUtils.decode(key), (int) value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -333,7 +333,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long incr(byte[] key) {
|
||||
try {
|
||||
return jredis.incr(JredisUtils.convert(charset, key));
|
||||
return jredis.incr(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -342,7 +342,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long incrBy(byte[] key, long value) {
|
||||
try {
|
||||
return jredis.incrby(JredisUtils.convert(charset, key), (int) value);
|
||||
return jredis.incrby(JredisUtils.decode(key), (int) value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -365,7 +365,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public byte[] lIndex(byte[] key, long index) {
|
||||
try {
|
||||
return jredis.lindex(JredisUtils.convert(charset, key), (long) index);
|
||||
return jredis.lindex(JredisUtils.decode(key), (long) index);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -374,7 +374,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long lLen(byte[] key) {
|
||||
try {
|
||||
return jredis.llen(JredisUtils.convert(charset, key));
|
||||
return jredis.llen(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -383,7 +383,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public byte[] lPop(byte[] key) {
|
||||
try {
|
||||
return jredis.lpop(JredisUtils.convert(charset, key));
|
||||
return jredis.lpop(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -392,7 +392,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long lPush(byte[] key, byte[] value) {
|
||||
try {
|
||||
jredis.lpush(JredisUtils.convert(charset, key), value);
|
||||
jredis.lpush(JredisUtils.decode(key), value);
|
||||
return null;
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
@@ -402,7 +402,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public List<byte[]> lRange(byte[] key, long start, long end) {
|
||||
try {
|
||||
List<byte[]> lrange = jredis.lrange(JredisUtils.convert(charset, key), start, end);
|
||||
List<byte[]> lrange = jredis.lrange(JredisUtils.decode(key), start, end);
|
||||
|
||||
return lrange;
|
||||
} catch (RedisException ex) {
|
||||
@@ -413,7 +413,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long lRem(byte[] key, long count, byte[] value) {
|
||||
try {
|
||||
return jredis.lrem(JredisUtils.convert(charset, key), value, (int) count);
|
||||
return jredis.lrem(JredisUtils.decode(key), value, (int) count);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -422,7 +422,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public void lSet(byte[] key, long index, byte[] value) {
|
||||
try {
|
||||
jredis.lset(JredisUtils.convert(charset, key), index, value);
|
||||
jredis.lset(JredisUtils.decode(key), index, value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -431,7 +431,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public void lTrim(byte[] key, long start, long end) {
|
||||
try {
|
||||
jredis.ltrim(JredisUtils.convert(charset, key), start, end);
|
||||
jredis.ltrim(JredisUtils.decode(key), start, end);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -440,7 +440,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public byte[] rPop(byte[] key) {
|
||||
try {
|
||||
return jredis.rpop(JredisUtils.convert(charset, key));
|
||||
return jredis.rpop(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -449,7 +449,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) {
|
||||
try {
|
||||
return jredis.rpoplpush(JredisUtils.convert(charset, srcKey), JredisUtils.convert(charset, dstKey));
|
||||
return jredis.rpoplpush(JredisUtils.decode(srcKey), JredisUtils.decode(dstKey));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -458,7 +458,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long rPush(byte[] key, byte[] value) {
|
||||
try {
|
||||
jredis.rpush(JredisUtils.convert(charset, key), value);
|
||||
jredis.rpush(JredisUtils.decode(key), value);
|
||||
return null;
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
@@ -472,7 +472,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean sAdd(byte[] key, byte[] value) {
|
||||
try {
|
||||
return jredis.sadd(JredisUtils.convert(charset, key), value);
|
||||
return jredis.sadd(JredisUtils.decode(key), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -481,7 +481,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long sCard(byte[] key) {
|
||||
try {
|
||||
return jredis.scard(JredisUtils.convert(charset, key));
|
||||
return jredis.scard(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -489,11 +489,11 @@ public class JredisConnection implements RedisConnection {
|
||||
|
||||
@Override
|
||||
public Set<byte[]> sDiff(byte[]... keys) {
|
||||
String set1 = JredisUtils.convert(charset, keys[0]);
|
||||
String[] sets = JredisUtils.convertMultiple(charset, Arrays.copyOfRange(keys, 1, keys.length));
|
||||
String destKey = JredisUtils.decode(keys[0]);
|
||||
String[] sets = JredisUtils.decodeMultiple(Arrays.copyOfRange(keys, 1, keys.length));
|
||||
|
||||
try {
|
||||
List<byte[]> result = jredis.sdiff(set1, sets);
|
||||
List<byte[]> result = jredis.sdiff(destKey, sets);
|
||||
return new LinkedHashSet<byte[]>(result);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
@@ -502,11 +502,11 @@ public class JredisConnection implements RedisConnection {
|
||||
|
||||
@Override
|
||||
public void sDiffStore(byte[] destKey, byte[]... keys) {
|
||||
String set1 = JredisUtils.convert(charset, keys[0]);
|
||||
String[] sets = JredisUtils.convertMultiple(charset, Arrays.copyOfRange(keys, 1, keys.length));
|
||||
String destSet = JredisUtils.decode(destKey);
|
||||
String[] sets = JredisUtils.decodeMultiple(keys);
|
||||
|
||||
try {
|
||||
jredis.sdiffstore(set1, sets);
|
||||
jredis.sdiffstore(destSet, sets);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -514,8 +514,8 @@ public class JredisConnection implements RedisConnection {
|
||||
|
||||
@Override
|
||||
public Set<byte[]> sInter(byte[]... keys) {
|
||||
String set1 = JredisUtils.convert(charset, keys[0]);
|
||||
String[] sets = JredisUtils.convertMultiple(charset, Arrays.copyOfRange(keys, 1, keys.length));
|
||||
String set1 = JredisUtils.decode(keys[0]);
|
||||
String[] sets = JredisUtils.decodeMultiple(Arrays.copyOfRange(keys, 1, keys.length));
|
||||
|
||||
try {
|
||||
List<byte[]> result = jredis.sinter(set1, sets);
|
||||
@@ -527,11 +527,11 @@ public class JredisConnection implements RedisConnection {
|
||||
|
||||
@Override
|
||||
public void sInterStore(byte[] destKey, byte[]... keys) {
|
||||
String set1 = JredisUtils.convert(charset, keys[0]);
|
||||
String[] sets = JredisUtils.convertMultiple(charset, Arrays.copyOfRange(keys, 1, keys.length));
|
||||
String destSet = JredisUtils.decode(destKey);
|
||||
String[] sets = JredisUtils.decodeMultiple(keys);
|
||||
|
||||
try {
|
||||
jredis.sinterstore(set1, sets);
|
||||
jredis.sinterstore(destSet, sets);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -540,7 +540,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean sIsMember(byte[] key, byte[] value) {
|
||||
try {
|
||||
return jredis.sismember(JredisUtils.convert(charset, key), value);
|
||||
return jredis.sismember(JredisUtils.decode(key), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -549,7 +549,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Set<byte[]> sMembers(byte[] key) {
|
||||
try {
|
||||
return new LinkedHashSet<byte[]>(jredis.smembers(JredisUtils.convert(charset, key)));
|
||||
return new LinkedHashSet<byte[]>(jredis.smembers(JredisUtils.decode(key)));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -558,7 +558,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) {
|
||||
try {
|
||||
return jredis.smove(JredisUtils.convert(charset, srcKey), JredisUtils.convert(charset, destKey), value);
|
||||
return jredis.smove(JredisUtils.decode(srcKey), JredisUtils.decode(destKey), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -567,7 +567,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public byte[] sPop(byte[] key) {
|
||||
try {
|
||||
return jredis.spop(JredisUtils.convert(charset, key));
|
||||
return jredis.spop(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -576,7 +576,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public byte[] sRandMember(byte[] key) {
|
||||
try {
|
||||
return jredis.srandmember(JredisUtils.convert(charset, key));
|
||||
return jredis.srandmember(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -585,7 +585,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean sRem(byte[] key, byte[] value) {
|
||||
try {
|
||||
return jredis.srem(JredisUtils.convert(charset, key), value);
|
||||
return jredis.srem(JredisUtils.decode(key), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -593,8 +593,8 @@ public class JredisConnection implements RedisConnection {
|
||||
|
||||
@Override
|
||||
public Set<byte[]> sUnion(byte[]... keys) {
|
||||
String set1 = JredisUtils.convert(charset, keys[0]);
|
||||
String[] sets = JredisUtils.convertMultiple(charset, Arrays.copyOfRange(keys, 1, keys.length));
|
||||
String set1 = JredisUtils.decode(keys[0]);
|
||||
String[] sets = JredisUtils.decodeMultiple(Arrays.copyOfRange(keys, 1, keys.length));
|
||||
|
||||
try {
|
||||
return new LinkedHashSet<byte[]>(jredis.sunion(set1, sets));
|
||||
@@ -605,11 +605,11 @@ public class JredisConnection implements RedisConnection {
|
||||
|
||||
@Override
|
||||
public void sUnionStore(byte[] destKey, byte[]... keys) {
|
||||
String set1 = JredisUtils.convert(charset, keys[0]);
|
||||
String[] sets = JredisUtils.convertMultiple(charset, Arrays.copyOfRange(keys, 1, keys.length));
|
||||
String destSet = JredisUtils.decode(destKey);
|
||||
String[] sets = JredisUtils.decodeMultiple(keys);
|
||||
|
||||
try {
|
||||
jredis.sunionstore(set1, sets);
|
||||
jredis.sunionstore(destSet, sets);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -623,7 +623,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean zAdd(byte[] key, double score, byte[] value) {
|
||||
try {
|
||||
return jredis.zadd(JredisUtils.convert(charset, key), score, value);
|
||||
return jredis.zadd(JredisUtils.decode(key), score, value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -632,7 +632,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long zCard(byte[] key) {
|
||||
try {
|
||||
return jredis.zcard(JredisUtils.convert(charset, key));
|
||||
return jredis.zcard(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -641,7 +641,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long zCount(byte[] key, double min, double max) {
|
||||
try {
|
||||
return jredis.zcount(JredisUtils.convert(charset, key), min, max);
|
||||
return jredis.zcount(JredisUtils.decode(key), min, max);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -650,7 +650,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Double zIncrBy(byte[] key, double increment, byte[] value) {
|
||||
try {
|
||||
return jredis.zincrby(JredisUtils.convert(charset, key), increment, value);
|
||||
return jredis.zincrby(JredisUtils.decode(key), increment, value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -669,7 +669,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Set<byte[]> zRange(byte[] key, long start, long end) {
|
||||
try {
|
||||
return new LinkedHashSet<byte[]>(jredis.zrange(JredisUtils.convert(charset, key), (long) start, (long) end));
|
||||
return new LinkedHashSet<byte[]>(jredis.zrange(JredisUtils.decode(key), (long) start, (long) end));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -684,7 +684,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Set<byte[]> zRangeByScore(byte[] key, double min, double max) {
|
||||
try {
|
||||
return new LinkedHashSet<byte[]>(jredis.zrangebyscore(JredisUtils.convert(charset, key), min, max));
|
||||
return new LinkedHashSet<byte[]>(jredis.zrangebyscore(JredisUtils.decode(key), min, max));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -708,7 +708,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long zRank(byte[] key, byte[] value) {
|
||||
try {
|
||||
return jredis.zrank(JredisUtils.convert(charset, key), value);
|
||||
return jredis.zrank(JredisUtils.decode(key), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -717,7 +717,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean zRem(byte[] key, byte[] value) {
|
||||
try {
|
||||
return jredis.zrem(JredisUtils.convert(charset, key), value);
|
||||
return jredis.zrem(JredisUtils.decode(key), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -726,7 +726,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long zRemRange(byte[] key, long start, long end) {
|
||||
try {
|
||||
return jredis.zremrangebyrank(JredisUtils.convert(charset, key), start, end);
|
||||
return jredis.zremrangebyrank(JredisUtils.decode(key), start, end);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -735,7 +735,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long zRemRangeByScore(byte[] key, double min, double max) {
|
||||
try {
|
||||
return jredis.zremrangebyscore(JredisUtils.convert(charset, key), min, max);
|
||||
return jredis.zremrangebyscore(JredisUtils.decode(key), min, max);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -744,7 +744,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Set<byte[]> zRevRange(byte[] key, long start, long end) {
|
||||
try {
|
||||
return new LinkedHashSet<byte[]>(jredis.zrevrange(JredisUtils.convert(charset, key), start, end));
|
||||
return new LinkedHashSet<byte[]>(jredis.zrevrange(JredisUtils.decode(key), start, end));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -758,7 +758,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long zRevRank(byte[] key, byte[] value) {
|
||||
try {
|
||||
return jredis.zrevrank(JredisUtils.convert(charset, key), value);
|
||||
return jredis.zrevrank(JredisUtils.decode(key), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -767,7 +767,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Double zScore(byte[] key, byte[] value) {
|
||||
try {
|
||||
return jredis.zscore(JredisUtils.convert(charset, key), value);
|
||||
return jredis.zscore(JredisUtils.decode(key), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -791,7 +791,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean hDel(byte[] key, byte[] field) {
|
||||
try {
|
||||
return jredis.hdel(JredisUtils.convert(charset, key), JredisUtils.convert(charset, field));
|
||||
return jredis.hdel(JredisUtils.decode(key), JredisUtils.decode(field));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -800,7 +800,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean hExists(byte[] key, byte[] field) {
|
||||
try {
|
||||
return jredis.hexists(JredisUtils.convert(charset, key), JredisUtils.convert(charset, field));
|
||||
return jredis.hexists(JredisUtils.decode(key), JredisUtils.decode(field));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -809,7 +809,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public byte[] hGet(byte[] key, byte[] field) {
|
||||
try {
|
||||
return jredis.hget(JredisUtils.convert(charset, key), JredisUtils.convert(charset, field));
|
||||
return jredis.hget(JredisUtils.decode(key), JredisUtils.decode(field));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -818,7 +818,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Map<byte[], byte[]> hGetAll(byte[] key) {
|
||||
try {
|
||||
return JredisUtils.convertMap(charset, jredis.hgetall(JredisUtils.convert(charset, key)));
|
||||
return JredisUtils.encodeMap(jredis.hgetall(JredisUtils.decode(key)));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -832,8 +832,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Set<byte[]> hKeys(byte[] key) {
|
||||
try {
|
||||
return new LinkedHashSet<byte[]>(JredisUtils.convert(charset,
|
||||
jredis.hkeys(JredisUtils.convert(charset, key))));
|
||||
return new LinkedHashSet<byte[]>(JredisUtils.convertCollection(jredis.hkeys(JredisUtils.decode(key))));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -842,7 +841,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Long hLen(byte[] key) {
|
||||
try {
|
||||
return jredis.hlen(JredisUtils.convert(charset, key));
|
||||
return jredis.hlen(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -861,7 +860,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public Boolean hSet(byte[] key, byte[] field, byte[] value) {
|
||||
try {
|
||||
return jredis.hset(JredisUtils.convert(charset, key), JredisUtils.convert(charset, field), value);
|
||||
return jredis.hset(JredisUtils.decode(key), JredisUtils.decode(field), value);
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
@@ -875,7 +874,7 @@ public class JredisConnection implements RedisConnection {
|
||||
@Override
|
||||
public List<byte[]> hVals(byte[] key) {
|
||||
try {
|
||||
return jredis.hvals(JredisUtils.convert(charset, key));
|
||||
return jredis.hvals(JredisUtils.decode(key));
|
||||
} catch (RedisException ex) {
|
||||
throw JredisUtils.convertJredisAccessException(ex);
|
||||
}
|
||||
|
||||
@@ -16,11 +16,9 @@
|
||||
|
||||
package org.springframework.data.keyvalue.redis.connection.jredis;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jredis.RedisException;
|
||||
@@ -40,18 +38,6 @@ public abstract class JredisUtils {
|
||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
static String convert(Charset charset, byte[] bytes) {
|
||||
return new String(bytes, charset);
|
||||
}
|
||||
|
||||
static String[] convertMultiple(Charset charset, byte[]... bytes) {
|
||||
String[] result = new String[bytes.length];
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
result[i] = new String(bytes[i], charset);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static DataType convertDataType(RedisType type) {
|
||||
switch (type) {
|
||||
case NONE:
|
||||
@@ -71,31 +57,44 @@ public abstract class JredisUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
static Map<byte[], byte[]> convertMap(Charset charset, Map<String, byte[]> map) {
|
||||
Map<byte[], byte[]> result = new LinkedHashMap<byte[], byte[]>(map.size());
|
||||
for (Map.Entry<String, byte[]> entry : map.entrySet()) {
|
||||
result.put(entry.getKey().getBytes(charset), entry.getValue());
|
||||
static String decode(byte[] bytes) {
|
||||
return Base64.encodeToString(bytes, false);
|
||||
}
|
||||
|
||||
static String[] decodeMultiple(byte[]... bytes) {
|
||||
String[] result = new String[bytes.length];
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
result[i] = decode(bytes[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Collection<byte[]> convert(Charset charset, List<String> keys) {
|
||||
static byte[] encode(String string) {
|
||||
return Base64.decode(string);
|
||||
}
|
||||
|
||||
static Map<byte[], byte[]> encodeMap(Map<String, byte[]> map) {
|
||||
Map<byte[], byte[]> result = new LinkedHashMap<byte[], byte[]>(map.size());
|
||||
for (Map.Entry<String, byte[]> entry : map.entrySet()) {
|
||||
result.put(encode(entry.getKey()), entry.getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Collection<byte[]> convertCollection(Collection<String> keys) {
|
||||
Collection<byte[]> list = new ArrayList<byte[]>(keys.size());
|
||||
|
||||
for (String string : keys) {
|
||||
list.add(string.getBytes(charset));
|
||||
list.add(Base64.decode(string));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static byte[] convert(Charset charset, String string) {
|
||||
return string.getBytes(charset);
|
||||
}
|
||||
|
||||
static Map<String, byte[]> convert(Charset charset, Map<byte[], byte[]> tuple) {
|
||||
static Map<String, byte[]> decodeMap(Map<byte[], byte[]> tuple) {
|
||||
Map<String, byte[]> result = new LinkedHashMap<String, byte[]>(tuple.size());
|
||||
for (Map.Entry<byte[], byte[]> entry : tuple.entrySet()) {
|
||||
result.put(new String(entry.getKey(), charset), entry.getValue());
|
||||
result.put(decode(entry.getKey()), entry.getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user