public static object OpenIO([NotNull]BlockParam/*!*/ block, RubyClass/*!*/ self, [Optional]MutableString initialString, [Optional]MutableString mode) { MutableStringStream stream = new MutableStringStream(initialString ?? MutableString.CreateBinary()); string ioMode = (mode != null) ? mode.ConvertToString() : "rb+"; RubyIO io = new StringIO(self.Context, stream, ioMode); object result; block.Yield(io, out result); if (!io.Closed) { io.Close(); } return result; }
public static RubyArray/*!*/ Unpack(RubyContext/*!*/ context, MutableString/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ format) { RubyArray result = new RubyArray(1 + self.Length / 2); using (MutableStringStream stream = new MutableStringStream(self)) { BinaryReader reader = new BinaryReader(stream); foreach (ArrayOps.FormatDirective directive in ArrayOps.FormatDirective.Enumerate(format.ToString())) { int count, maxCount; byte[] buffer; MutableString str; int nilCount = 0; switch (directive.Directive) { case '@': stream.Position = directive.Count.HasValue ? directive.Count.Value : stream.Position; break; case 'A': case 'a': maxCount = (int)(stream.Length - stream.Position); count = directive.Count.HasValue ? directive.Count.Value : maxCount; if (count > maxCount) { count = maxCount; } buffer = reader.ReadBytes(count); str = MutableString.CreateBinary(buffer); if (directive.Directive == 'A') { // TODO: efficiency? for (int pos = count - 1; pos >= 0; pos--) { if (buffer[pos] != 0 && buffer[pos] != 0x20) { break; } str.Remove(pos, 1); } } result.Add(str); break; case 'Z': maxCount = (int)(stream.Length - stream.Position); count = directive.Count.HasValue ? directive.Count.Value : maxCount; if (count > maxCount) { count = maxCount; } buffer = reader.ReadBytes(count); str = MutableString.CreateBinary(buffer); for (int pos = 0; pos < count; pos++) { if (buffer[pos] == 0) { str.Remove(pos, count - pos); break; } } result.Add(str); break; case 'c': count = CalculateCounts(stream, directive.Count, sizeof(sbyte), out nilCount); for (int j = 0; j < count; j++) { result.Add((int)reader.ReadSByte()); } break; case 'C': count = CalculateCounts(stream, directive.Count, sizeof(byte), out nilCount); for (int j = 0; j < count; j++) { result.Add((int)reader.ReadByte()); } break; case 'i': case 'l': count = CalculateCounts(stream, directive.Count, sizeof(int), out nilCount); for (int j = 0; j < count; j++) { result.Add((int)reader.ReadInt32()); } break; case 'I': case 'L': count = CalculateCounts(stream, directive.Count, sizeof(uint), out nilCount); for (int j = 0; j < count; j++) { unchecked { result.Add((int)reader.ReadUInt32()); } } break; case 'm': // TODO: Recognize "==" as end of base 64 encoding int len = (int)(stream.Length - stream.Position); char[] base64 = reader.ReadChars(len); byte[] data = Convert.FromBase64CharArray(base64, 0, len); result.Add(MutableString.CreateBinary(data)); break; case 's': count = CalculateCounts(stream, directive.Count, sizeof(short), out nilCount); for (int j = 0; j < count; j++) { result.Add((int)reader.ReadInt16()); } break; case 'S': count = CalculateCounts(stream, directive.Count, sizeof(ushort), out nilCount); for (int j = 0; j < count; j++) { result.Add((int)reader.ReadUInt16()); } break; case 'U': maxCount = (int)(stream.Length - stream.Position); count = directive.Count.HasValue ? directive.Count.Value : maxCount; int readCount = directive.Count.HasValue ? Encoding.UTF8.GetMaxByteCount(count) : count; if (readCount > maxCount) { readCount = maxCount; } long startPosition = stream.Position; char[] charData = Encoding.UTF8.GetChars(reader.ReadBytes(readCount)); if (charData.Length > count) { int actualCount = Encoding.UTF8.GetByteCount(charData, 0, count); stream.Position = startPosition + actualCount; } else if (charData.Length < count) { count = charData.Length; } for (int j = 0; j < count; j++) { result.Add((int)charData[j]); } break; case 'X': int len3 = directive.Count.HasValue ? directive.Count.Value : 0; if (len3 > stream.Position) { throw RubyExceptions.CreateArgumentError("X outside of string"); } stream.Position -= len3; break; case 'x': int len4 = directive.Count.HasValue ? directive.Count.Value : 0; stream.Position += len4; break; case 'h': case 'H': maxCount = (int)(stream.Length - stream.Position) * 2; result.Add(ToHex(reader, Math.Min(directive.Count ?? maxCount, maxCount), directive.Directive == 'h')); break; default: throw RubyExceptions.CreateArgumentError( String.Format("Unknown format directive '{0}'", directive.Directive)); } for (int i = 0; i < nilCount; i++) { result.Add(null); } } } return result; }
public static MutableString/*!*/ Pack( ConversionStorage<IntegerValue>/*!*/ integerConversion, ConversionStorage<MutableString>/*!*/ stringCast, RubyContext/*!*/ context, RubyArray/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ format) { using (MutableStringStream stream = new MutableStringStream()) { BinaryWriter writer = new BinaryWriter(stream); int i = 0; foreach (FormatDirective directive in FormatDirective.Enumerate(format.ConvertToString())) { int remaining = (self.Count - i); int count = directive.Count.HasValue ? directive.Count.Value : remaining; if (count > remaining) { count = remaining; } MutableString str; switch (directive.Directive) { case '@': count = 0; stream.Position = directive.Count.HasValue ? directive.Count.Value : 1; break; case 'A': case 'a': case 'Z': count = 1; str = Protocols.CastToString(stringCast, self[i]); char[] cstr = (str == null) ? new char[0] : str.ToString().ToCharArray(); int dataLen; int paddedLen; if (directive.Count.HasValue) { paddedLen = directive.Count.Value; dataLen = Math.Min(cstr.Length, paddedLen); } else { paddedLen = cstr.Length; dataLen = cstr.Length; } writer.Write(cstr, 0, dataLen); if (paddedLen > dataLen) { byte fill = (directive.Directive == 'A') ? (byte)' ' : (byte)0; for (int j = 0; j < (paddedLen - dataLen); j++) { writer.Write(fill); } } if (directive.Directive == 'Z' && !directive.Count.HasValue) { writer.Write((byte)0); } break; case 'Q': case 'q': for (int j = 0; j < count; j++) { writer.Write(Protocols.CastToUInt64Unchecked(integerConversion, self[i + j])); } break; case 'l': case 'i': for (int j = 0; j < count; j++) { writer.Write(unchecked((int)Protocols.CastToUInt32Unchecked(integerConversion, self[i + j]))); } break; case 'L': case 'I': for (int j = 0; j < count; j++) { writer.Write(Protocols.CastToUInt32Unchecked(integerConversion, self[i + j])); } break; case 'N': // unsigned 4-byte big-endian WriteUInt32(integerConversion, writer, self, i, count, BitConverter.IsLittleEndian); break; case 'n': // unsigned 2-byte big-endian WriteUInt16(integerConversion, writer, self, i, count, BitConverter.IsLittleEndian); break; case 'V': // unsigned 4-byte little-endian WriteUInt32(integerConversion, writer, self, i, count, !BitConverter.IsLittleEndian); break; case 'v': // unsigned 2-byte little-endian WriteUInt16(integerConversion, writer, self, i, count, !BitConverter.IsLittleEndian); break; case 's': for (int j = 0; j < count; j++) { writer.Write(unchecked((short)Protocols.CastToUInt32Unchecked(integerConversion, self[i + j]))); } break; case 'S': for (int j = 0; j < count; j++) { writer.Write(unchecked((ushort)Protocols.CastToUInt32Unchecked(integerConversion, self[i + j]))); } break; case 'c': for (int j = 0; j < count; j++) { writer.Write(unchecked((sbyte)Protocols.CastToUInt32Unchecked(integerConversion, self[i + j]))); } break; case 'C': for (int j = 0; j < count; j++) { writer.Write(unchecked((byte)Protocols.CastToUInt32Unchecked(integerConversion, self[i + j]))); } break; case 'm': count = 1; str = Protocols.CastToString(stringCast, self[i]); char[] base64 = Convert.ToBase64String(str.ToByteArray()).ToCharArray(); for (int j = 0; j < base64.Length; j += 60) { int len = base64.Length - j; if (len > 60) { len = 60; } writer.Write(base64, j, len); writer.Write('\n'); } break; case 'U': char[] buffer = new char[count]; for (int j = 0; j < count; j++) { buffer[j] = unchecked((char)Protocols.CastToUInt32Unchecked(integerConversion, self[i + j])); } writer.Write(Encoding.UTF8.GetBytes(buffer)); break; case 'X': count = 0; int len3 = directive.Count.HasValue ? directive.Count.Value : 0; if (len3 > stream.Position) { throw RubyExceptions.CreateArgumentError("X outside of string"); } stream.Position -= len3; break; case 'x': count = 0; int len4 = directive.Count.HasValue ? directive.Count.Value : 0; for (int j = 0; j < len4; j++) { writer.Write((byte)0); } break; case 'h': case 'H': // MRI skips null, unlike in "m" directive: if (self[i] != null) { str = Protocols.CastToString(stringCast, self[i]); FromHex(writer, str, directive.Count ?? str.GetByteCount(), directive.Directive == 'h'); } break; default: throw RubyExceptions.CreateArgumentError( String.Format("Unknown format directive '{0}'", directive.Directive)); } i += count; if (i >= self.Count) { break; } } stream.SetLength(stream.Position); return stream.String; } }
/*!*/ public static MutableString Pack( ConversionStorage<IntegerValue>/*!*/ integerConversion, ConversionStorage<double>/*!*/ floatConversion, ConversionStorage<MutableString>/*!*/ stringCast, ConversionStorage<MutableString>/*!*/ tosConversion, RubyArray/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ format) { // TODO: encodings using (MutableStringStream stream = new MutableStringStream()) { int i = 0; foreach (FormatDirective directive in FormatDirective.Enumerate(format.ConvertToString())) { int count = directive.Count ?? self.Count - i; MutableString str; switch (directive.Directive) { case '@': count = 0; stream.SetLength(stream.Position = directive.Count.HasValue ? directive.Count.Value : 1); break; case 'A': case 'a': case 'Z': count = 1; WriteString(stream, directive, ToMutableString(stringCast, stream, GetPackArg(self, i))); break; case 'B': case 'b': count = 1; WriteBits( stream, directive.Count, directive.Directive == 'b', str = GetPackArg(self, i) != null ? ToMutableString(stringCast, stream, GetPackArg(self, i)) : MutableString.FrozenEmpty ); break; case 'c': case 'C': for (int j = 0; j < count; j++) { stream.WriteByte(unchecked((byte)Protocols.CastToUInt32Unchecked(integerConversion, GetPackArg(self, i + j)))); } break; case 'd': // 8-byte native-endian case 'D': WriteDouble(floatConversion, stream, self, i, count, false); break; case 'e': // 4-byte little-endian WriteSingle(floatConversion, stream, self, i, count, !BitConverter.IsLittleEndian); break; case 'E': // 8-byte little-endian WriteDouble(floatConversion, stream, self, i, count, !BitConverter.IsLittleEndian); break; case 'f': // 4-byte native-endian case 'F': WriteSingle(floatConversion, stream, self, i, count, false); break; case 'g': // 4-byte big-endian WriteSingle(floatConversion, stream, self, i, count, BitConverter.IsLittleEndian); break; case 'G': // 8-byte big-endian WriteDouble(floatConversion, stream, self, i, count, BitConverter.IsLittleEndian); break; case 'h': case 'H': // MRI skips null, unlike in "m" directive: if (GetPackArg(self, i) != null) { str = ToMutableString(stringCast, stream, GetPackArg(self, i)); FromHex(stream, str, directive.Count ?? str.GetByteCount(), directive.Directive == 'h'); } count = 1; break; case 'Q': case 'q': // (un)signed 8-byte native-endian WriteUInt64(integerConversion, stream, self, i, count, false); break; case 'l': case 'i': case 'L': case 'I': // (un)signed 4-byte native-endian WriteUInt32(integerConversion, stream, self, i, count, false); break; case 'N': // (un)signed 4-byte big-endian WriteUInt32(integerConversion, stream, self, i, count, BitConverter.IsLittleEndian); break; case 'n': // (un)signed 2-byte big-endian WriteUInt16(integerConversion, stream, self, i, count, BitConverter.IsLittleEndian); break; case 'V': // (un)signed 4-byte little-endian WriteUInt32(integerConversion, stream, self, i, count, !BitConverter.IsLittleEndian); break; case 'v': // (un)signed 2-byte little-endian WriteUInt16(integerConversion, stream, self, i, count, !BitConverter.IsLittleEndian); break; case 's': // (un)signed 2-byte native-endian case 'S': WriteUInt16(integerConversion, stream, self, i, count, false); break; case 'm': // Base64 if (GetPackArg(self, i) == null) { throw RubyExceptions.CreateTypeConversionError("nil", "String"); } WriteBase64(stream, ToMutableString(stringCast, stream, GetPackArg(self, i)), (directive.Count.HasValue && directive.Count.Value > 2) ? directive.Count.Value : 45 ); count = 1; break; case 'M': // quoted-printable, MIME encoding count = 1; if (GetPackArg(self, i) != null) { var site = tosConversion.GetSite(ConvertToSAction.Make(tosConversion.Context)); MutableString s = site.Target(site, GetPackArg(self, i)); stream.String.TaintBy(s); WritePrintedQuotable(stream, s, (directive.Count.HasValue && directive.Count.Value >= 2) ? directive.Count.Value : 72 ); } break; case 'u': // UU-encoded if (GetPackArg(self, i) == null) { throw RubyExceptions.CreateTypeConversionError("nil", "String"); } RubyEncoder.EncodeUU(ToMutableString(stringCast, stream, GetPackArg(self, i)).ToByteArray(), (directive.Count.HasValue && directive.Count.Value > 2) ? directive.Count.Value : 45, stream ); count = 1; break; case 'w': // BER-encoded for (int j = 0; j < count; j++) { WriteBer(stream, Protocols.CastToInteger(integerConversion, GetPackArg(self, i + j))); } break; case 'U': // UTF8 code point for (int j = 0; j < count; j++) { RubyEncoder.WriteUtf8CodePoint(stream, Protocols.CastToInteger(integerConversion, GetPackArg(self, i + j)).ToInt32()); } break; case 'X': count = 0; int len3 = directive.Count.HasValue ? directive.Count.Value : 0; if (len3 > stream.Position) { throw RubyExceptions.CreateArgumentError("X outside of string"); } stream.String.Write((int)stream.Position - len3, 0, len3); stream.Position -= len3; break; case 'x': count = 0; int len4 = directive.Count.HasValue ? directive.Count.Value : 0; stream.String.Write((int)stream.Position, 0, len4); stream.Position += len4; break; default: count = 0; break; } i += count; } stream.SetLength(stream.Position); return stream.String.TaintBy(format); } }
private static MutableString ToMutableString(ConversionStorage<MutableString>/*!*/ stringCast, MutableStringStream/*!*/ stream, object value) { var site = stringCast.GetSite(ConvertToStrAction.Make(stringCast.Context)); var result = site.Target(site, value); if (result != null) { stream.String.TaintBy(result); } return result; }
/*!*/ private static MutableString ReadUU(MutableString/*!*/ data, ref int position) { var input = new MutableStringStream(data); var output = new MutableStringStream(); input.Position = position; ReadUU(input, output); position = (int)input.Position; output.Dispose(); return output.String; }
public static MutableString /*!*/ Pack(RubyContext /*!*/ context, RubyArray /*!*/ self, [DefaultProtocol, NotNull] MutableString /*!*/ format) { using (MutableStringStream stream = new MutableStringStream()) { BinaryWriter writer = new BinaryWriter(stream); int i = 0; foreach (FormatDirective directive in FormatDirective.Enumerate(format.ConvertToString())) { int remaining = (self.Count - i); int count = directive.Count.HasValue ? directive.Count.Value : remaining; if (count > remaining) { count = remaining; } MutableString str; switch (directive.Directive) { case '@': count = 0; stream.Position = directive.Count.HasValue ? directive.Count.Value : 1; break; case 'A': case 'a': case 'Z': count = 1; char[] cstr = Protocols.CastToString(context, self[i]).ToString().ToCharArray(); int len1 = directive.Count.HasValue ? directive.Count.Value : cstr.Length; int len2 = (len1 > cstr.Length) ? cstr.Length : len1; writer.Write(cstr, 0, len2); if (len1 > len2) { byte fill = (directive.Directive == 'A') ? (byte)' ' : (byte)0; for (int j = 0; j < (len1 - len2); j++) { writer.Write(fill); } } if (directive.Directive == 'Z' && !directive.Count.HasValue) { writer.Write((byte)0); } break; case 'Q': case 'q': for (int j = 0; j < count; j++) { writer.Write(Protocols.CastToUInt64Unchecked(context, self[i + j])); } break; case 'l': case 'i': for (int j = 0; j < count; j++) { writer.Write(unchecked ((int)Protocols.CastToUInt32Unchecked(context, self[i + j]))); } break; case 'L': case 'I': for (int j = 0; j < count; j++) { writer.Write(Protocols.CastToUInt32Unchecked(context, self[i + j])); } break; case 'N': // unsigned 4-byte big-endian WriteUInt32(writer, self, context, i, count, BitConverter.IsLittleEndian); break; case 'n': // unsigned 2-byte big-endian WriteUInt16(writer, self, context, i, count, BitConverter.IsLittleEndian); break; case 'V': // unsigned 4-byte little-endian WriteUInt32(writer, self, context, i, count, !BitConverter.IsLittleEndian); break; case 'v': // unsigned 2-byte little-endian WriteUInt16(writer, self, context, i, count, !BitConverter.IsLittleEndian); break; case 's': for (int j = 0; j < count; j++) { writer.Write(unchecked ((short)Protocols.CastToUInt32Unchecked(context, self[i + j]))); } break; case 'S': for (int j = 0; j < count; j++) { writer.Write(unchecked ((ushort)Protocols.CastToUInt32Unchecked(context, self[i + j]))); } break; case 'c': for (int j = 0; j < count; j++) { writer.Write(unchecked ((sbyte)Protocols.CastToUInt32Unchecked(context, self[i + j]))); } break; case 'C': for (int j = 0; j < count; j++) { writer.Write(unchecked ((byte)Protocols.CastToUInt32Unchecked(context, self[i + j]))); } break; case 'm': count = 1; str = Protocols.CastToString(context, self[i]); char[] base64 = Convert.ToBase64String(str.ToByteArray()).ToCharArray(); for (int j = 0; j < base64.Length; j += 60) { int len = base64.Length - j; if (len > 60) { len = 60; } writer.Write(base64, j, len); writer.Write('\n'); } break; case 'U': char[] buffer = new char[count]; for (int j = 0; j < count; j++) { buffer[j] = unchecked ((char)Protocols.CastToUInt32Unchecked(context, self[i + j])); } writer.Write(Encoding.UTF8.GetBytes(buffer)); break; case 'X': count = 0; int len3 = directive.Count.HasValue ? directive.Count.Value : 0; if (len3 > stream.Position) { throw RubyExceptions.CreateArgumentError("X outside of string"); } stream.Position -= len3; break; case 'x': count = 0; int len4 = directive.Count.HasValue ? directive.Count.Value : 0; for (int j = 0; j < len4; j++) { writer.Write((byte)0); } break; case 'h': case 'H': // MRI skips null, unlike in "m" directive: if (self[i] != null) { str = Protocols.CastToString(context, self[i]); FromHex(writer, str, directive.Count ?? str.GetByteCount(), directive.Directive == 'h'); } break; default: throw RubyExceptions.CreateArgumentError( String.Format("Unknown format directive '{0}'", directive.Directive)); } i += count; if (i >= self.Count) { break; } } stream.SetLength(stream.Position); return(stream.String); } }
private static MutableString ToMutableString(ConversionStorage<MutableString>/*!*/ stringCast, MutableStringStream/*!*/ stream, object value) { var result = Protocols.CastToString(stringCast, value); if (result != null) { stream.String.TaintBy(result); } return result; }
public static RubyIO CreateIO(RubyClass/*!*/ self, [Optional]MutableString initialString, [Optional]MutableString mode) { MutableStringStream stream = new MutableStringStream(initialString ?? MutableString.CreateBinary()); string ioMode = (mode != null) ? mode.ConvertToString() : "rb+"; return new StringIO(self.Context, stream, ioMode); }
protected StringIO(RubyContext/*!*/ context, MutableStringStream/*!*/ stream, string/*!*/ mode) : base(context, stream, mode) { }
public static RubyArray/*!*/ Unpack(RubyContext/*!*/ context, MutableString/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ format) { RubyArray result = new RubyArray(1 + self.Length / 2); using (MutableStringStream stream = new MutableStringStream(self)) { BinaryReader reader = new BinaryReader(stream); foreach (ArrayOps.FormatDirective directive in ArrayOps.FormatDirective.Enumerate(format.ToString())) { int count, maxCount; byte[] buffer; MutableString str; int nilCount = 0; switch (directive.Directive) { case '@': if (directive.Count.HasValue) { if (directive.Count.Value > stream.Length) { throw RubyExceptions.CreateArgumentError("@ outside of string"); } stream.Position = directive.Count.Value > 0 ? directive.Count.Value : 0; } else { stream.Position = stream.Length; } break; case 'A': case 'a': maxCount = (int)(stream.Length - stream.Position); count = directive.Count.HasValue ? directive.Count.Value : maxCount; if (count > maxCount) { count = maxCount; } buffer = reader.ReadBytes(count); str = MutableString.CreateBinary(buffer); if (directive.Directive == 'A') { // TODO: efficiency? for (int pos = count - 1; pos >= 0; pos--) { if (buffer[pos] != 0 && buffer[pos] != 0x20) { break; } str.Remove(pos, 1); } } result.Add(str); break; case 'B': case 'b': if (stream.Length - stream.Position != 0) { count = directive.Count.HasValue ? directive.Count.Value : (int)(stream.Length - stream.Position) * 8; buffer = reader.ReadBytes((int)Math.Ceiling((double)count / 8)); if (count > buffer.Length * 8) { count = buffer.Length * 8; } str = MutableString.CreateBinary(count); if ((directive.Directive == 'B' && BitConverter.IsLittleEndian) || (directive.Directive == 'b' && !BitConverter.IsLittleEndian)) { for (int i = 0; i < buffer.Length; i++) { byte b = buffer[i]; int r = (b >> 4) | ((b & 0x0F) << 4); r = ((r & 0xCC) >> 2) | ((r & 0x33) << 2); r = ((r & 0xAA) >> 1) | ((r & 0x55) << 1); buffer[i] = (byte)r; } } for (int b = 0, i = 0; b < count; b++) { if (b == 8) { i++; b = 0; count -= 8; } str.Append(((buffer[i] & (1 << b)) != 0 ? '1' : '0')); } } else { str = MutableString.CreateEmpty(); } result.Add(str); break; case 'Z': maxCount = (int)(stream.Length - stream.Position); count = directive.Count.HasValue ? directive.Count.Value : maxCount; if (count > maxCount) { count = maxCount; } buffer = reader.ReadBytes(count); str = MutableString.CreateBinary(buffer); for (int pos = 0; pos < count; pos++) { if (buffer[pos] == 0) { str.Remove(pos, count - pos); if (!directive.Count.HasValue) { stream.Seek(pos - count + 1, SeekOrigin.End); } break; } } result.Add(str); break; case 'c': count = CalculateCounts(stream, directive.Count, sizeof(sbyte), out nilCount); for (int j = 0; j < count; j++) { result.Add((int)reader.ReadSByte()); } break; case 'C': count = CalculateCounts(stream, directive.Count, sizeof(byte), out nilCount); for (int j = 0; j < count; j++) { result.Add((int)reader.ReadByte()); } break; case 'i': case 'l': count = CalculateCounts(stream, directive.Count, sizeof(int), out nilCount); for (int j = 0; j < count; j++) { result.Add((int)reader.ReadInt32()); } break; case 'I': case 'L': count = CalculateCounts(stream, directive.Count, sizeof(uint), out nilCount); for (int j = 0; j < count; j++) { uint value = reader.ReadUInt32(); if (value <= Int32.MaxValue) { result.Add((int)value); } else { result.Add((BigInteger)value); } } break; case 'v': count = CalculateCounts(stream, directive.Count, sizeof(ushort), out nilCount); for (int j = 0; j < count; j++) { ushort value = reader.ReadUInt16(); if (!BitConverter.IsLittleEndian) { value = (ushort)(0x00FF & (value >> 8) | 0xFF00 & (value << 8)); } result.Add((int)value); } break; case 'V': count = CalculateCounts(stream, directive.Count, sizeof(uint), out nilCount); for (int j = 0; j < count; j++) { uint value = reader.ReadUInt32(); if (!BitConverter.IsLittleEndian) { value = (0x000000FF & (value >> 24) | 0x0000FF00 & (value >> 8) | 0x00FF0000 & (value << 8) | 0xFF000000 & (value << 24)); } if (value <= Int32.MaxValue) { result.Add((int)value); } else { result.Add((BigInteger)value); } } break; case 'q': count = CalculateCounts(stream, directive.Count, sizeof(long), out nilCount); for (int j = 0; j < count; j++) { long value = reader.ReadInt64(); if (!BitConverter.IsLittleEndian) { ulong uvalue = (ulong)value; uvalue = (0x00000000000000FF & (uvalue >> 56)) | (0x000000000000FF00 & (uvalue >> 40)) | (0x0000000000FF0000 & (uvalue >> 24)) | (0x00000000FF000000 & (uvalue >> 8)) | (0x000000FF00000000 & (uvalue << 8)) | (0x0000FF0000000000 & (uvalue << 24)) | (0x00FF000000000000 & (uvalue << 40)) | (0xFF00000000000000 & (uvalue << 56)); value = (long)uvalue; } if (value <= Int32.MaxValue && value >= Int32.MinValue) { result.Add((int)value); } else { result.Add((BigInteger)value); } } break; case 'Q': count = CalculateCounts(stream, directive.Count, sizeof(ulong), out nilCount); nilCount = 0; for (int j = 0; j < count; j++) { ulong value = reader.ReadUInt64(); if (!BitConverter.IsLittleEndian) { value = (0x00000000000000FF & (value >> 56)) | (0x000000000000FF00 & (value >> 40)) | (0x0000000000FF0000 & (value >> 24)) | (0x00000000FF000000 & (value >> 8)) | (0x000000FF00000000 & (value << 8)) | (0x0000FF0000000000 & (value << 24)) | (0x00FF000000000000 & (value << 40)) | (0xFF00000000000000 & (value << 56)); } if (value <= Int32.MaxValue) { result.Add((int)value); } else { result.Add((BigInteger)value); } } break; case 'm': // TODO: Recognize "==" as end of base 64 encoding int len = (int)(stream.Length - stream.Position); char[] base64 = reader.ReadChars(len); byte[] data = Convert.FromBase64CharArray(base64, 0, len); result.Add(MutableString.CreateBinary(data)); break; case 's': count = CalculateCounts(stream, directive.Count, sizeof(short), out nilCount); for (int j = 0; j < count; j++) { result.Add((int)reader.ReadInt16()); } break; case 'S': count = CalculateCounts(stream, directive.Count, sizeof(ushort), out nilCount); for (int j = 0; j < count; j++) { result.Add((int)reader.ReadUInt16()); } break; case 'U': maxCount = (int)(stream.Length - stream.Position); count = directive.Count.HasValue ? directive.Count.Value : maxCount; int readCount = directive.Count.HasValue ? Encoding.UTF8.GetMaxByteCount(count) : count; if (readCount > maxCount) { readCount = maxCount; } long startPosition = stream.Position; char[] charData = Encoding.UTF8.GetChars(reader.ReadBytes(readCount)); if (charData.Length > count) { int actualCount = Encoding.UTF8.GetByteCount(charData, 0, count); stream.Position = startPosition + actualCount; } else if (charData.Length < count) { count = charData.Length; } for (int j = 0; j < count; j++) { result.Add((int)charData[j]); } break; case 'X': int len3 = directive.Count.HasValue ? directive.Count.Value : 0; if (len3 > stream.Position) { throw RubyExceptions.CreateArgumentError("X outside of string"); } stream.Position -= len3; break; case 'x': int len4 = directive.Count.HasValue ? directive.Count.Value : 0; stream.Position += len4; break; case 'h': case 'H': maxCount = (int)(stream.Length - stream.Position) * 2; result.Add(ToHex(reader, Math.Min(directive.Count ?? maxCount, maxCount), directive.Directive == 'h')); break; default: throw RubyExceptions.CreateArgumentError( String.Format("Unknown format directive '{0}'", directive.Directive)); } for (int i = 0; i < nilCount; i++) { result.Add(null); } } } return result; }