Пример #1
0
 private static void WriteString(Stream/*!*/ stream, FormatDirective directive, MutableString str)
 {
     // TODO (opt): unneccessary copy of byte[]
     byte[] bytes = str != null ? str.ToByteArray() : Utils.EmptyBytes;
     int dataLen;
     int paddedLen;
     if (directive.Count.HasValue) {
         paddedLen = directive.Count.Value;
         dataLen = Math.Min(bytes.Length, paddedLen);
     } else {
         paddedLen = bytes.Length;
         dataLen = bytes.Length;
     }
     stream.Write(bytes, 0, dataLen);
     if (paddedLen > dataLen) {
         byte fill = (directive.Directive == 'A') ? (byte)' ' : (byte)0;
         for (int j = 0; j < (paddedLen - dataLen); j++) {
             stream.WriteByte(fill);
         }
     }
     if (directive.Directive == 'Z' && !directive.Count.HasValue) {
         stream.WriteByte((byte)0);
     }
 }
Пример #2
0
        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);
            }
        }