/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // /////////////////////////////////////////////////////////////////////////////// using System; using StringBuilder = System.Text.StringBuilder; using System; using System.Collections; using Microsoft.Singularity; using Microsoft.Singularity.Io; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Drivers; using Microsoft.Singularity.Directory; using Microsoft.Singularity.V1.Services; namespace Iso9660 { /// /// This class contains a number of static methods for marshalling, /// unmarshalling, and comparing byte arrays. /// public class ByteArray { private const int MIN = -1; private const int MAX = -2; /// /// Marshalls a byte array into a buffer starting at a pointer /// into the buffer, and advances the pointer accordingly. /// /// The byte array that is being marshalled. /// The buffer into which the integer is /// marshalled. /// /// The position in the buffer where the Handle /// starts.After completion, offset is the next position after the /// Handle. public static void Marshall(byte[] b, byte[] bytes, ref int offset) { if (b == Minimum) { Int.Marshall(MIN, bytes, ref offset); } else if (b == Maximum) { Int.Marshall(MAX, bytes, ref offset); } else { if (b != null) { Int.Marshall(b.Length, bytes, ref offset); Array.Copy(b, 0, bytes, offset, b.Length); offset += b.Length; } else { Int.Marshall(0, bytes, ref offset); } } } public static int Sizeof(byte[] b) { if (b == Minimum || b == Maximum) { return Int.Size; } if (b == null) { return Int.Size; } return Int.Size + b.Length; } /// /// Given a buffer and a pointer into it, unmarshalls a byte array /// from the buffer, advancing the pointer by 4 bytes. /// /// The buffer from which the byte array is /// unmarshalled. /// The position in the buffer where the Handle /// starts. /// After completion, offset is the next position after the Handle. /// /// The byte array that was unmarshalled. /// /// Note that our marshall and unmarshall routines are not symmetric /// I.e., We marshall a null string as a string of zero length. But /// unmarshalling a 0 length string does not result in a null string /// but in a string with zero length. /// I believe the B-Tree recovery procedures cannot deal with an /// unmarshalled string that is a null. public static byte[] Unmarshall(byte[] bytes, ref int offset) { int len = Int.Unmarshall(bytes, ref offset); if (len == MIN) { return Minimum; } else if (len == MAX) { return Maximum; } else { if (len < 0) { Console.WriteLine("ba len is negative " + len); system.panic("bad len"); } if (len == 0) { //Console.WriteLine("BA LEN is 0 "); } byte[] b = new byte[len]; try { Array.Copy(bytes, offset, b, 0, b.Length); offset += b.Length; return b; } catch (Exception) { Console.WriteLine("len = " + len + " b.Length " + b.Length + " offset: " + offset + " bytes.Length " + bytes.Length); throw; } } } /// /// Given a buffer and a pointer into it, unmarshalls the length of a /// byte array from the buffer, but does not advance the pointer. /// /// The buffer from which the byte array /// is unmarshalled. /// The position in the buffer where the Handle /// starts. After completion, offset is the next position after /// the Handle. /// The byte array that was unmarshalled. public static int UnmarshallLength(byte[] bytes, int offset) { int len = Int.Unmarshall(bytes, ref offset); return len < 0 ? 0 : len; } /// /// This constant identifies the minimum byte array, i.e. the byte /// array that, when compared (via Comparer.Compare) with any other /// byte array, is smaller. /// public static readonly byte[] Minimum = new byte[0]; /// /// This constant identifies the maximum byte array, i.e. the byte /// array that, when compared (via Comparer.Compare) with any other /// byte array, is larger. /// public static readonly byte[] Maximum = new byte[0]; public delegate int CompareTo(byte[] a, byte[] b); static public int LexicographicCompareTo(byte[] a, byte[] b) { int min = System.Math.Min(a.Length, b.Length); int i = 0; for (; i < min; i++) { if (a[i] < b[i]) return -1; if (a[i] > b[i]) return +1; } if (a.Length < b.Length) return -1; if (a.Length > b.Length) return +1; return 0; } /// /// Returns the string representation of a byte array. Returns /// "null" if the byte array is null, and "Maximum" if the byte /// array is identical to Maximum. /// /// /// public static string ToString(byte[] b) { if (b == Minimum) return "Minimum"; if (b == Maximum) return "Maximum"; if (b == null) return "null"; char[] c = new char[b.Length]; for (int i = 0; i < c.Length; i++) c[i] = (char)b[i]; return new string(c); } /// /// for debugging -- return a hex version of the array that can /// be printed on the console /// /// /// public static string ToLegibleString(byte[] b) { return ToLegibleString(new ByteContainer(b)); } public static string ToLegibleString(ByteContainer b) { byte[] temp = b.ConvertToArray(); StringBuilder legible = new StringBuilder(); for (int i = 0; i < temp.Length; i++) { legible.AppendFormat("{0:x2}", temp[i]); } return legible.ToString(); } public static string ToLegibleString(byte[] b, int off, int len) { return ToLegibleString(new ByteContainer(b), off, len); } public static string ToLegibleString(ByteContainer b, int off, int len) { byte[] temp = b.ConvertToArray(); system.Assert(len + off <= temp.Length); StringBuilder legible = new StringBuilder(); for (int i = off; i < off + len; i++) { legible.AppendFormat("{0:x2}", temp[i]); } return legible.ToString(); } public static string ToLegibleString(byte[] b, int len) { return ToLegibleString(new ByteContainer(b), len); } public static string ToLegibleString(ByteContainer b, int len) { byte[] temp = b.ConvertToArray(); system.Assert(len < temp.Length); StringBuilder legible = new StringBuilder(); for (int i = 0; i < len; i++) { legible.AppendFormat("{0:x2}", temp[i]); } return legible.ToString(); } public static byte[] ToByteArray(string s) { byte[] b = new byte[s.Length]; for (int i = 0; i < s.Length; i++) { b[i] = (byte)(s[i] & 0xff); } return b; } /// /// general purpose string-byte array transformation /// /// /// public static byte[] StringToByteArray(string s) { if (s == null) { return null; } byte[] b = new byte[s.Length]; for (int i = 0; i < s.Length; i++) { b[i] = (byte)(s[i] & 0xff); } return b; } public static string ToString(byte[] b, int count) { if (b == null) { return "null"; } int len; if (count < b.Length) { len = count; } else { len = b.Length; } char[] c = new char[len]; for (int i = 0; i < len; i++) { c[i] = (char)b[i]; } return new string(c); } public static string ToString(byte[] b, int off, int len) { char[] c = new char[len]; for (int i = 0; i < len; i++) { c[i] = (char)b[off+i]; } return new string(c); } public static ulong ToUlong(byte[] b, int off) { // little-endian ulong x = 0; for (int i = 0; i < 4; i++) { x <<= 8; x += b[off+i]; } return x; } public static ushort ToUshort(byte[] b, int off) { // little-endian ushort x = 0; for (int i = 0; i < 2; i++) { x <<= 8; x += b[off+i]; } return x; } public static int SizeofString(string s) { return Int.Size + s.Length; } public static void MarshallString(string s, byte[] bytes, ref int off){ Int.Marshall(s.Length, bytes, ref off); for(int i = 0; i < s.Length; i++) { bytes[off++] = (byte)(s[i] & 0xff); } } public static string UnmarshallString(byte[] bytes, ref int offset){ int len = Int.Unmarshall(bytes, ref offset); if (len <= 0 ) { Tracing.Log(Tracing.Debug,"bytes had a negative len="+len); return null; } char[] c = new char[len]; for (int i = 0; i < len; i++) { c[i] = (char)bytes[offset++]; } return new string(c); } public class Comparer { public readonly CompareTo RawCompareTo; public Comparer() { this.RawCompareTo = new CompareTo(LexicographicCompareTo); } public Comparer(CompareTo rawComp) { this.RawCompareTo = rawComp; } public int Compare(byte[] a, byte[] b) { if ((a == Minimum && b == Minimum) || (a == Maximum && b == Maximum)) { return 0; } else if (a == Minimum || b == Maximum) { return -1; } else if (b == Minimum || a == Maximum) { return +1; } else { return this.RawCompareTo(a, b); } } } } }