Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/***** BEGIN LICENSE BLOCK *****
* Version: EPL 2.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse Public
* License Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/epl-v20.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2002-2004 Jan Arne Petersen
* Copyright (C) 2002-2004 Anders Bengtsson
* Copyright (C) 2003-2004 Thomas E Enebo
* Copyright (C) 2004 Charles O Nutter
* Copyright (C) 2004 Stefan Matthias Aust
* Copyright (C) 2005 Derek Berner
* Copyright (C) 2006 Evan Buswell
* Copyright (C) 2007 Nick Sieger
* Copyright (C) 2009 Joseph LaFata
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the EPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the EPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.jruby.util;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.jcodings.specific.ASCIIEncoding;
import org.jcodings.specific.USASCIIEncoding;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.*;
import org.jruby.platform.Platform;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import static com.headius.backport9.buffer.Buffers.markBuffer;
import static com.headius.backport9.buffer.Buffers.positionBuffer;
import static org.jruby.util.TypeConverter.toFloat;
public class Pack {
private static final byte[] sSp10 = " ".getBytes();
private static final byte[] sNil10 = "\000\000\000\000\000\000\000\000\000\000".getBytes();
private static final int IS_STAR = -1;
private static final ASCIIEncoding ASCII = ASCIIEncoding.INSTANCE;
private static final USASCIIEncoding USASCII = USASCIIEncoding.INSTANCE;
private static final UTF8Encoding UTF8 = UTF8Encoding.INSTANCE;
/** Native pack type.
**/
private static final String NATIVE_CODES = "sSiIlLjJ";
private static final String MAPPED_CODES = "sSiIqQjJ";
private static final char BE = '>' + 127; // 189, bumped up to avoid collisions with LE
private static final char LE = '<'; // 60
private static final String ENDIANESS_CODES = new String(new char[] {
's' + BE, 'S' + BE/*n*/, 'i' + BE, 'I' + BE, 'l' + BE, 'L' + BE/*N*/, 'q' + BE, 'Q' + BE, 'j' + BE, 'J' + BE,
's' + LE, 'S' + LE/*v*/, 'i' + LE, 'I' + LE, 'l' + LE, 'L' + LE/*V*/, 'q' + LE, 'Q' + LE, 'j' + LE, 'J' + LE});
private static final String UNPACK_IGNORE_NULL_CODES = "cC";
private static final String PACK_IGNORE_NULL_CODES = "cCiIlLnNqQsSvV";
private static final String PACK_IGNORE_NULL_CODES_WITH_MODIFIERS = "lLsS";
/** Unpack modes
**/
private static final int UNPACK_ARRAY = 0;
private static final int UNPACK_BLOCK = 1;
private static final int UNPACK_1 = 2;
private static final String sTooFew = "too few arguments";
private static final byte[] uu_table;
private static final byte[] b64_table;
public static final byte[] sHexDigits;
public static final int[] b64_xtable = new int[256];
private static final Converter[] converters = new Converter[512];
private static long num2quad(IRubyObject arg) {
if (arg.isNil()) return 0L;
if (arg instanceof RubyBignum) {
BigInteger big = ((RubyBignum) arg).getValue();
return big.longValue();
}
return RubyNumeric.num2long(arg);
}
private static float obj2flt(Ruby runtime, IRubyObject o) {
return (float) toFloat(runtime, o).getDoubleValue();
}
private static double obj2dbl(Ruby runtime, IRubyObject o) {
return toFloat(runtime, o).getDoubleValue();
}
static {
uu_table =
ByteList.plain("`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_");
b64_table =
ByteList.plain("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
sHexDigits = ByteList.plain("0123456789abcdef0123456789ABCDEFx");
// b64_xtable for decoding Base 64
for (int i = 0; i < 256; i++) {
b64_xtable[i] = -1;
}
for (int i = 0; i < 64; i++) {
b64_xtable[(int)b64_table[i]] = i;
}
// single precision, little-endian
converters['e'] = new Converter(4) {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return RubyFloat.newFloat(runtime, decodeFloatLittleEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeFloatLittleEndian(result, obj2flt(runtime, o));
}
};
// single precision, big-endian
converters['g'] = new Converter(4) {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return RubyFloat.newFloat(runtime, decodeFloatBigEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeFloatBigEndian(result, obj2flt(runtime, o));
}
};
// single precision, native
Converter tmp = new Converter(4) {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return RubyFloat.newFloat(runtime,
Platform.BYTE_ORDER == Platform.BIG_ENDIAN ?
decodeFloatBigEndian(enc) : decodeFloatLittleEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result) {
if (Platform.BYTE_ORDER == Platform.BIG_ENDIAN) {
encodeFloatBigEndian(result, obj2flt(runtime, o));
} else {
encodeFloatLittleEndian(result, obj2flt(runtime, o));
}
}
};
converters['F'] = tmp; // single precision, native
converters['f'] = tmp; // single precision, native
// double precision, little-endian
converters['E'] = new Converter(8) {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return RubyFloat.newFloat(runtime, decodeDoubleLittleEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeDoubleLittleEndian(result, obj2dbl(runtime, o));
}
};
// double precision, big-endian
converters['G'] = new Converter(8) {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return RubyFloat.newFloat(runtime, decodeDoubleBigEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeDoubleBigEndian(result, obj2dbl(runtime, o));
}
};
// double precision, native
tmp = new Converter(8) {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
if (Platform.BYTE_ORDER == Platform.BIG_ENDIAN) {
return RubyFloat.newFloat(runtime, decodeDoubleBigEndian(enc));
} else {
return RubyFloat.newFloat(runtime, decodeDoubleLittleEndian(enc));
}
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeDoubleLittleEndian(result, obj2dbl(runtime, o));
}
};
converters['D'] = tmp; // double precision, native
converters['d'] = tmp; // double precision, native
// signed short, little-endian
tmp = new QuadConverter(2, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(decodeShortUnsignedLittleEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeShortLittleEndian(result, overflowQuad(num2quad(o)));
}
};
converters['v'] = tmp;
converters['S' + LE] = tmp;
// signed short, big-endian
tmp = new QuadConverter(2, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(decodeShortUnsignedBigEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result) {
encodeShortBigEndian(result, overflowQuad(num2quad(o)));
}
};
converters['n'] = tmp;
converters['S' + BE] = tmp;
// signed short, native
converters['s'] = new QuadConverter(2, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(Platform.BYTE_ORDER == Platform.BIG_ENDIAN ?
decodeShortBigEndian(enc) : decodeShortLittleEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result) {
encodeShortByByteOrder(result, overflowQuad(num2quad(o))); // XXX: 0xffff0000 on BE?
}
};
// unsigned short, native
converters['S'] = new QuadConverter(2, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(Platform.BYTE_ORDER == Platform.BIG_ENDIAN ?
decodeShortUnsignedBigEndian(enc) : decodeShortUnsignedLittleEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeShortByByteOrder(result, overflowQuad(num2quad(o)));
}
};
// signed short, little endian
converters['s' + LE] = new QuadConverter(2, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(decodeShortLittleEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result) {
encodeShortLittleEndian(result, overflowQuad(num2quad(o))); // XXX: 0xffff0000 on BE?
}
};
// signed short, big endian
converters['s' + BE] = new QuadConverter(2, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(decodeShortBigEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result) {
encodeShortBigEndian(result, overflowQuad(num2quad(o))); // XXX: 0xffff0000 on BE?
}
};
// signed char
converters['c'] = new Converter(1, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
int c = enc.get();
return runtime.newFixnum(c > (char) 127 ? c-256 : c);
}
public void encode(Ruby runtime, IRubyObject o, ByteList result) {
byte c = (byte) (num2quad(o) & 0xff);
result.append(c);
}
};
// unsigned char
converters['C'] = new Converter(1, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(enc.get() & 0xFF);
}
public void encode(Ruby runtime, IRubyObject o, ByteList result){
byte c = o == runtime.getNil() ? 0 : (byte) (num2quad(o) & 0xff);
result.append(c);
}
};
// unsigned long, little-endian
tmp = new Converter(4, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(decodeIntUnsignedLittleEndian(enc));
}
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeIntLittleEndian(result, (int) RubyNumeric.num2long(o));
}
};
converters['V'] = tmp;
converters['L' + LE] = tmp;
converters['I' + LE] = tmp;
// unsigned long, big-endian
tmp = new Converter(4, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(decodeIntUnsignedBigEndian(enc));
}
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeIntBigEndian(result, (int) RubyNumeric.num2long(o));
}
};
converters['N'] = tmp;
converters['L' + BE] = tmp;
converters['I' + BE] = tmp;
// unsigned int, native
tmp = new Converter(4, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
if (Platform.BYTE_ORDER == Platform.BIG_ENDIAN) {
return runtime.newFixnum(decodeIntUnsignedBigEndian(enc));
} else {
return runtime.newFixnum(decodeIntUnsignedLittleEndian(enc));
}
}
public void encode(Ruby runtime, IRubyObject o, ByteList result){
int s = o == runtime.getNil() ? 0 : (int) RubyNumeric.num2long(o);
packInt_i(result, s);
}
};
converters['I'] = tmp; // unsigned int, native
converters['L'] = tmp; // unsigned long, native
// int, native
tmp = new Converter(4, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
int value = unpackInt_i(enc);
return runtime.newFixnum(value);
}
public void encode(Ruby runtime, IRubyObject o, ByteList result){
int s = o == runtime.getNil() ? 0 : (int)RubyNumeric.num2long(o);
packInt_i(result, s);
}
};
converters['i'] = tmp; // int, native
converters['l'] = tmp; // long, native
// int, little endian
tmp = new Converter(4, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(decodeIntLittleEndian(enc));
}
public void encode(Ruby runtime, IRubyObject o, ByteList result){
int s = o == runtime.getNil() ? 0 : (int)RubyNumeric.num2long(o);
encodeIntLittleEndian(result, s);
}
};
converters['i' + LE] = tmp; // int, native
converters['l' + LE] = tmp; // long, native
// int, big endian
tmp = new Converter(4, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(decodeIntBigEndian(enc));
}
public void encode(Ruby runtime, IRubyObject o, ByteList result){
int s = o == runtime.getNil() ? 0 : (int)RubyNumeric.num2long(o);
encodeIntBigEndian(result, s);
}
};
converters['i' + BE] = tmp; // int, native
converters['l' + BE] = tmp; // long, native
// 64-bit number, native (as bignum)
tmp = new QuadConverter(8, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
long l = Platform.BYTE_ORDER == Platform.BIG_ENDIAN ? decodeLongBigEndian(enc) : decodeLongLittleEndian(enc);
return RubyBignum.bignorm(runtime,BigInteger.valueOf(l).and(new BigInteger("FFFFFFFFFFFFFFFF", 16)));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeLongByByteOrder(result, num2quad(o));
}
};
converters['Q'] = tmp;
converters['J'] = tmp;
// 64-bit number, little endian (as bignum)
tmp = new QuadConverter(8, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
long l = decodeLongLittleEndian(enc);
return RubyBignum.bignorm(runtime,BigInteger.valueOf(l).and(new BigInteger("FFFFFFFFFFFFFFFF", 16)));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeLongLittleEndian(result, num2quad(o));
}
};
converters['Q' + LE] = tmp;
converters['J' + LE] = tmp;
// 64-bit number, big endian (as bignum)
tmp = new QuadConverter(8, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
long l = decodeLongBigEndian(enc);
return RubyBignum.bignorm(runtime,BigInteger.valueOf(l).and(new BigInteger("FFFFFFFFFFFFFFFF", 16)));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeLongBigEndian(result, num2quad(o));
}
};
converters['Q' + BE] = tmp;
converters['J' + BE] = tmp;
// 64-bit number, native (as fixnum)
tmp = new QuadConverter(8, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(Platform.BYTE_ORDER == Platform.BIG_ENDIAN ?
decodeLongBigEndian(enc) : decodeLongLittleEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeLongByByteOrder(result, num2quad(o));
}
};
converters['q'] = tmp;
converters['j'] = tmp;
// 64-bit number, little-endian (as fixnum)
tmp = new QuadConverter(8, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(decodeLongLittleEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeLongLittleEndian(result, num2quad(o));
}
};
converters['q' + LE] = tmp;
converters['j' + LE] = tmp;
// 64-bit number, big-endian (as fixnum)
tmp = new QuadConverter(8, "Integer") {
public IRubyObject decode(Ruby runtime, ByteBuffer enc) {
return runtime.newFixnum(decodeLongBigEndian(enc));
}
@Override
public void encode(Ruby runtime, IRubyObject o, ByteList result){
encodeLongBigEndian(result, num2quad(o));
}
};
converters['q' + BE] = tmp;
converters['j' + BE] = tmp;
}
public static int unpackInt_i(ByteBuffer enc) {
int value;
if (Platform.BYTE_ORDER == Platform.BIG_ENDIAN) {
value = decodeIntBigEndian(enc);
} else {
value = decodeIntLittleEndian(enc);
}
return value;
}
public static ByteList packInt_i(ByteList result, int s) {
if (Platform.BYTE_ORDER == Platform.BIG_ENDIAN) {
encodeIntBigEndian(result, s);
} else {
encodeIntLittleEndian(result, s);
}
return result;
}
public static void encodeUM(Ruby runtime, ByteList lCurElemString, int occurrences, boolean ignoreStar, char type, ByteList result) {
if (occurrences == 0 && type == 'm' && !ignoreStar) {
encodes(runtime, result, lCurElemString.getUnsafeBytes(),
lCurElemString.getBegin(), lCurElemString.length(),
lCurElemString.length(), (byte) type, false);
return;
}
occurrences = occurrences <= 2 ? 45 : occurrences / 3 * 3;
if (lCurElemString.length() == 0) return;
byte[] charsToEncode = lCurElemString.getUnsafeBytes();
for (int i = 0; i < lCurElemString.length(); i += occurrences) {
encodes(runtime, result, charsToEncode,
i + lCurElemString.getBegin(), lCurElemString.length() - i,
occurrences, (byte)type, true);
}
}
/**
* encodes a String in base64 or its uuencode variant.
* appends the result of the encoding in a StringBuffer
* @param io2Append The StringBuffer which should receive the result
* @param charsToEncode The String to encode
* @param startIndex
* @param length The max number of characters to encode
* @param charCount
* @param encodingType the type of encoding required (this is the same type as used by the pack method)
* @param tailLf true if the traililng "\n" is needed
* @return the io2Append buffer
**/
private static ByteList encodes(Ruby runtime, ByteList io2Append,byte[] charsToEncode, int startIndex, int length, int charCount, byte encodingType, boolean tailLf) {
charCount = charCount < length ? charCount : length;
io2Append.ensure(charCount * 4 / 3 + 6);
int i = startIndex;
byte[] lTranslationTable = encodingType == 'u' ? uu_table : b64_table;
byte lPadding;
if (encodingType == 'u') {
if (charCount >= lTranslationTable.length) {
throw runtime.newArgumentError(charCount
+ " is not a correct value for the number of bytes per line in a u directive. Correct values range from 0 to "
+ lTranslationTable.length);
}
io2Append.append(lTranslationTable[charCount]);
lPadding = '`';
} else {
lPadding = '=';
}
while (charCount >= 3) {
byte lCurChar = charsToEncode[i++];
byte lNextChar = charsToEncode[i++];
byte lNextNextChar = charsToEncode[i++];
io2Append.append(lTranslationTable[077 & (lCurChar >>> 2)]);
io2Append.append(lTranslationTable[077 & (((lCurChar << 4) & 060) | ((lNextChar >>> 4) & 017))]);
io2Append.append(lTranslationTable[077 & (((lNextChar << 2) & 074) | ((lNextNextChar >>> 6) & 03))]);
io2Append.append(lTranslationTable[077 & lNextNextChar]);
charCount -= 3;
}
if (charCount == 2) {
byte lCurChar = charsToEncode[i++];
byte lNextChar = charsToEncode[i++];
io2Append.append(lTranslationTable[077 & (lCurChar >>> 2)]);
io2Append.append(lTranslationTable[077 & (((lCurChar << 4) & 060) | ((lNextChar >> 4) & 017))]);
io2Append.append(lTranslationTable[077 & (((lNextChar << 2) & 074) | (('\0' >> 6) & 03))]);
io2Append.append(lPadding);
} else if (charCount == 1) {
byte lCurChar = charsToEncode[i++];
io2Append.append(lTranslationTable[077 & (lCurChar >>> 2)]);
io2Append.append(lTranslationTable[077 & (((lCurChar << 4) & 060) | (('\0' >>> 4) & 017))]);
io2Append.append(lPadding);
io2Append.append(lPadding);
}
if (tailLf) {
io2Append.append('\n');
}
return io2Append;
}
public static RubyArray unpack(Ruby runtime, ByteList encodedString, ByteList formatString) {
return unpackWithBlock(runtime.getCurrentContext(), runtime, encodedString, formatString, Block.NULL_BLOCK);
}
/**
* @see Pack#unpackWithBlock(ThreadContext, Ruby, ByteList, ByteList, Block)
* @param context
* @param encoded
* @param formatString
* @return unpacked array
*/
public static RubyArray unpack(ThreadContext context, RubyString encoded, ByteList formatString) {
return unpackWithBlock(context, encoded, formatString, Block.NULL_BLOCK);
}
/**
* Decodes str (which may contain binary data) according to the format
* string, returning an array of each value extracted.
* The format string consists of a sequence of single-character directives.
* Each directive may be followed by a number, indicating the number of times to repeat with this directive. An asterisk (``*'') will use up all
* remaining elements.
* Note that if passed a block, this method will return null and instead yield results to the block.
* The directives sSiIlL may each be followed by an underscore (``_'') to use the underlying platform's native size for the specified type; otherwise, it uses a platform-independent consistent size.
* Spaces are ignored in the format string.
*
*