350 lines
12 KiB
C#
350 lines
12 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// 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
|
||
|
{
|
||
|
|
||
|
/// <summary>
|
||
|
/// This class contains a number of static methods for marshalling,
|
||
|
/// unmarshalling, and comparing byte arrays.
|
||
|
/// </summary>
|
||
|
public class ByteArray {
|
||
|
private const int MIN = -1;
|
||
|
private const int MAX = -2;
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// Marshalls a byte array into a buffer starting at a pointer
|
||
|
/// into the buffer, and advances the pointer accordingly.
|
||
|
/// </summary>
|
||
|
/// <param name="b">The byte array that is being marshalled.</param>
|
||
|
/// <param name="bytes">The buffer into which the integer is
|
||
|
/// marshalled.
|
||
|
/// </param>
|
||
|
/// <param name="offset">The position in the buffer where the Handle
|
||
|
/// starts.After completion, offset is the next position after the
|
||
|
/// Handle.</param>
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Given a buffer and a pointer into it, unmarshalls a byte array
|
||
|
/// from the buffer, advancing the pointer by 4 bytes.
|
||
|
/// </summary>
|
||
|
/// <param name="bytes">The buffer from which the byte array is
|
||
|
/// unmarshalled.</param>
|
||
|
/// <param name="offset">The position in the buffer where the Handle
|
||
|
/// starts.
|
||
|
/// After completion, offset is the next position after the Handle.
|
||
|
/// </param>
|
||
|
/// <returns>The byte array that was unmarshalled.</returns>
|
||
|
///
|
||
|
/// 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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Given a buffer and a pointer into it, unmarshalls the length of a
|
||
|
/// byte array from the buffer, but does not advance the pointer.
|
||
|
/// </summary>
|
||
|
/// <param name="bytes">The buffer from which the byte array
|
||
|
/// is unmarshalled.</param>
|
||
|
/// <param name="offset">The position in the buffer where the Handle
|
||
|
/// starts. After completion, offset is the next position after
|
||
|
/// the Handle.</param>
|
||
|
/// <returns>The byte array that was unmarshalled.</returns>
|
||
|
|
||
|
public static int UnmarshallLength(byte[] bytes, int offset) {
|
||
|
int len = Int.Unmarshall(bytes, ref offset);
|
||
|
return len < 0 ? 0 : len;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 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.
|
||
|
/// </summary>
|
||
|
public static readonly byte[] Minimum = new byte[0];
|
||
|
|
||
|
/// <summary>
|
||
|
/// 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.
|
||
|
/// </summary>
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 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.
|
||
|
/// </summary>
|
||
|
/// <param name="b"></param>
|
||
|
/// <returns></returns>
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// for debugging -- return a hex version of the array that can
|
||
|
/// be printed on the console
|
||
|
/// </summary>
|
||
|
/// <param name="s"></param>
|
||
|
/// <returns></returns>
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// general purpose string-byte array transformation
|
||
|
/// </summary>
|
||
|
/// <param name="s"></param>
|
||
|
/// <returns></returns>
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|