Tensorflowsharp从入门到放弃(二)——这次有个手写数字识别

接上文,源代码是控制台的:所有输出Console.WriteLine(*);这样的代码一致改为this.textBox1.Text +="\r\n"+ string.Format(*);

这次又更新了四课内容,其中手写数字识别卡住了一会,主要原因是网上 TF#的MNIST手写数字识别代码太多太乱,此处补上最新版的(也是原作者的代码)供后人学习。


        /// <summary>
        /// 06 线性回归(没实现)
        /// </summary>
        private void button6_Click(object sender, EventArgs e)
        {
            // 创建所需数据
            var xList = new List<double>();
            var yList = new List<double>();
            var ran = new Random();
            for (var i = 0; i < 10; i++)
            {
                var num = ran.NextDouble();
                var noise = ran.NextDouble();
                xList.Add(num);
                yList.Add(num * 3 + 4 + noise); // y = 3 * x + 4
            }
            var xData = xList.ToArray();
            var yData = yList.ToArray();
            var learning_rate = 0.01;

            // 创建图
            var g = new TFGraph();

            // 创建占位符
            var x = g.Placeholder(TFDataType.Double, new TFShape(xData.Length));
            var y = g.Placeholder(TFDataType.Double, new TFShape(yData.Length));

            // 权重和偏置
            var W = g.VariableV2(TFShape.Scalar, TFDataType.Double, operName: "weight");
            var b = g.VariableV2(TFShape.Scalar, TFDataType.Double, operName: "bias");

            var initW = g.Assign(W, g.Const(ran.NextDouble()));
            var initb = g.Assign(b, g.Const(ran.NextDouble()));

            var output = g.Add(g.Mul(x, W), b);

            // 损失
            var loss = g.ReduceSum(g.Abs(g.Sub(output, y)));
            var grad = g.AddGradients(new TFOutput[] { loss }, new TFOutput[] { W, b });
            var optimize = new[]
            {
                g.AssignSub(W, g.Mul(grad[0], g.Const(learning_rate))).Operation,
                g.AssignSub(b, g.Mul(grad[1], g.Const(learning_rate))).Operation
            };

            // 创建会话
            var sess = new TFSession(g);

            // 变量初始化
            sess.GetRunner().AddTarget(initW.Operation, initb.Operation).Run();

            // 进行训练拟合
            for (var i = 0; i < 1000; i++)
            {
                var result = sess.GetRunner()
                    .AddInput(x, xData)
                    .AddInput(y, yData)
                    .AddTarget(optimize)
                    .Fetch(loss, W, b).Run();

                this.textBox1.Text = string.Format("loss: {0} W:{1} b:{2}", result[0].GetValue(), result[1].GetValue(), result[2].GetValue());
               
            }
        }

        /// <summary>
        /// 07 手写数字识别
        /// </summary>
        private void button7_Click(object sender, EventArgs e)
        {
            // 加载手写数字资源
            var mnist = Mnist.Load();

            // 训练次数和测试次数
            var trainCount = 5000;
            var testCount = 200;

            // 获取训练图片、训练图片标签、测试图片、测试图片标签
            float[,] trainingImages, trainingLabels, testImages, testLabels;
            mnist.GetTrainReader().NextBatch(trainCount, out trainingImages, out trainingLabels);
            mnist.GetTestReader().NextBatch(testCount, out testImages, out testLabels);
            //mnist.GetTrainReader().NextBatch(trainCount);
            //mnist.GetTestReader().NextBatch(testCount);


            // 创建图
            var g = new TFGraph();

            // 训练图片占位符和训练标签占位符
            var trainingInput = g.Placeholder(TFDataType.Float, new TFShape(-1, 784)); // 不定数量的像素为24*24的图片
            var xte = g.Placeholder(TFDataType.Float, new TFShape(784));

            // 创建计算误差和预测的图
            var distance = g.ReduceSum(g.Abs(g.Add(trainingInput, g.Neg(xte))), axis: g.Const(1));
            var pred = g.ArgMin(distance, g.Const(0));

            // 创建会话
            var sess = new TFSession(g);

            // 精度
            var accuracy = 0.0f;

            // 进行迭代训练,并且每次都输出预测值
            for (int i = 0; i < testCount; i++)
            {
                var runner = sess.GetRunner();

                // 计算并且获取误差和预测值
                var result = runner.
                    Fetch(pred).
                    Fetch(distance).
                    AddInput(trainingInput, trainingImages).
                    AddInput(xte, Extract(testImages, i)).Run();
                var r = result[0].GetValue();
                var tr = result[1].GetValue();

                var nn_index = (int)(long)result[0].GetValue();

                this.textBox1.Text += string.Format($"训练次数 {i}: 预测: { ArgMax(trainingLabels, nn_index) } 真实值: { ArgMax(testLabels, i)} (nn_index= { nn_index })");
                if (ArgMax(trainingLabels, nn_index) == ArgMax(testLabels, i))
                    accuracy += 1f / testImages.Length;
            }

            // 精确度
            this.textBox1.Text += string.Format("精度:" + accuracy);
        }

        /// <summary>
        /// 获取矩阵array中idx行的最大值
        /// </summary>
        /// <param name="array"></param>
        /// <param name="idx"></param>
        /// <returns></returns>
        static int ArgMax(float[,] array, int idx)
        {
            float max = -1;
            int maxIdx = -1;
            var len = array.GetLength(1);
            for (int i = 0; i < len; i++)
                if (array[idx, i] > max)
                {
                    maxIdx = i;
                    max = array[idx, i];
                }
            return maxIdx;
        }

        /// <summary>
        /// 获取矩阵array中的index行(即获取n*n图片数组中的第n张)
        /// </summary>
        /// <param name="array"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        static public float[] Extract(float[,] array, int index)
        {
            var n = array.GetLength(1);
            var ret = new float[n];

            for (int i = 0; i < n; i++)
                ret[i] = array[index, i];
            return ret;
        }

        /// <summary>
        /// 08 张量的使用
        /// </summary>
        private void button8_Click(object sender, EventArgs e)
        {
            // 整数张量
            var tensor = new TFTensor(1);
            this.textBox1.Text +="\r\n"+ string.Format("Value:" + tensor.GetValue());

            // 矩阵张量
            tensor = new TFTensor(new int[,]
            {
                { 1, 2, 3 },
                { 4, 5, 6 },
            });
            this.textBox1.Text += "\r\n" + string.Format("TensorType: {0}", tensor.TensorType.ToString());
            this.textBox1.Text += "\r\n" + string.Format("NumDims: " + tensor.NumDims);
            this.textBox1.Text += "\r\n" + string.Format("Shape", string.Join(",", tensor.Shape));
            for (var i = 0; i < tensor.NumDims; i++)
            {
                var dim = tensor.GetTensorDimension(i);
                this.textBox1.Text += "\r\n" + string.Format("DimIndex: {0}, Dim: {1}", i, dim);
            }

            // 创建图
            var g = new TFGraph();

            // 创建字符串张量
            tensor = new TFTensor("Hello, world!".Select(o => (sbyte)o).ToArray());
            var hello = g.Const(tensor);

            // 创建会话
            var sess = new TFSession(g);

            // 进行计算
            var result = sess.GetRunner().Run(hello).GetValue();

            // 输出计算结果
            this.textBox1.Text += "\r\n" + string.Format(string.Join("", ((sbyte[])result).Select(o => (char)o)));
        }

以下三个类文件放到自己工程下,网上很多MNIST.cs的代码有些版本不同,会有部分函数功能不同,目前最新如下:

MNIST.cs代码

//
// Code to download and load the MNIST data.
//

using System;
using System.IO;
using System.IO.Compression;
using Mono;
using TensorFlow;
using System.Linq;

namespace Learn.Mnist
{
    // Stores the per-image MNIST information we loaded from disk 
    //
    // We store the data in two formats, byte array (as it came in from disk), and float array
    // where each 0..255 value has been mapped to 0.0f..1.0f
    public struct MnistImage
    {
        public int Cols, Rows;
        public byte[] Data;
        public float[] DataFloat;

        public MnistImage(int cols, int rows, byte[] data)
        {
            Cols = cols;
            Rows = rows;
            Data = data;
            DataFloat = new float[data.Length];
            for (int i = 0; i < data.Length; i++)
            {
                DataFloat[i] = Data[i] / 255f;
            }
        }
    }

    // Helper class used to load and work with the Mnist data set
    public class Mnist
    {
        // 
        // The loaded results
        //
        public MnistImage[] TrainImages, TestImages, ValidationImages;
        public byte[] TrainLabels, TestLabels, ValidationLabels;
        public byte[,] OneHotTrainLabels, OneHotTestLabels, OneHotValidationLabels;

        public BatchReader GetTrainReader() => new BatchReader(TrainImages, TrainLabels, OneHotTrainLabels);
        public BatchReader GetTestReader() => new BatchReader(TestImages, TestLabels, OneHotTestLabels);
        public BatchReader GetValidationReader() => new BatchReader(ValidationImages, ValidationLabels, OneHotValidationLabels);

        public class BatchReader
        {
            int start = 0;
            MnistImage[] source;
            byte[] labels;
            byte[,] oneHotLabels;

            internal BatchReader(MnistImage[] source, byte[] labels, byte[,] oneHotLabels)
            {
                this.source = source;
                this.labels = labels;
                this.oneHotLabels = oneHotLabels;
            }

            public void NextBatch(int batchSize, out float[,] imageData, out float[,] labelData)
            {
                imageData = new float[batchSize, 784];
                labelData = new float[batchSize, 10];

                int p = 0;
                for (int item = 0; item < batchSize; item++)
                {
                    Buffer.BlockCopy(source[start + item].DataFloat, 0, imageData, p, 784 * sizeof(float));
                    p += 784 * sizeof(float);
                    for (var j = 0; j < 10; j++)
                        labelData[item, j] = oneHotLabels[item + start, j];
                }

                start += batchSize;
            }
        }

        int Read32(Stream s)
        {
            var x = new byte[4];
            s.Read(x, 0, 4);
            return DataConverter.BigEndian.GetInt32(x, 0);
        }

        MnistImage[] ExtractImages(Stream input, string file)
        {
            using (var gz = new GZipStream(input, CompressionMode.Decompress))
            {
                if (Read32(gz) != 2051)
                    throw new Exception("Invalid magic number found on the MNIST " + file);
                var count = Read32(gz);
                var rows = Read32(gz);
                var cols = Read32(gz);

                var result = new MnistImage[count];
                for (int i = 0; i < count; i++)
                {
                    var size = rows * cols;
                    var data = new byte[size];
                    gz.Read(data, 0, size);

                    result[i] = new MnistImage(cols, rows, data);
                }
                return result;
            }
        }


        byte[] ExtractLabels(Stream input, string file)
        {
            using (var gz = new GZipStream(input, CompressionMode.Decompress))
            {
                if (Read32(gz) != 2049)
                    throw new Exception("Invalid magic number found on the MNIST " + file);
                var count = Read32(gz);
                var labels = new byte[count];
                gz.Read(labels, 0, count);

                return labels;
            }
        }

        T[] Pick<T>(T[] source, int first, int last)
        {
            if (last == 0)
                last = source.Length;
            var count = last - first;
            var result = new T[count];
            Array.Copy(source, first, result, 0, count);
            return result;
        }

        // Turn the labels array that contains values 0..numClasses-1 into
        // a One-hot encoded array
        byte[,] OneHot(byte[] labels, int numClasses)
        {
            var oneHot = new byte[labels.Length, numClasses];
            for (int i = 0; i < labels.Length; i++)
            {
                oneHot[i, labels[i]] = 1;
            }
            return oneHot;
        }

        /// <summary>
        /// Reads the data sets.
        /// </summary>
        /// <param name="trainDir">Directory where the training data is downlaoded to.</param>
        /// <param name="numClasses">Number classes to use for one-hot encoding, or zero if this is not desired</param>
        /// <param name="validationSize">Validation size.</param>
        public void ReadDataSets(string trainDir, int numClasses = 10, int validationSize = 5000)
        {
            const string SourceUrl = "http://yann.lecun.com/exdb/mnist/";
            const string TrainImagesName = "train-images-idx3-ubyte.gz";
            const string TrainLabelsName = "train-labels-idx1-ubyte.gz";
            const string TestImagesName = "t10k-images-idx3-ubyte.gz";
            const string TestLabelsName = "t10k-labels-idx1-ubyte.gz";

            TrainImages = ExtractImages(Helper.MaybeDownload(SourceUrl, trainDir, TrainImagesName), TrainImagesName);
            TestImages = ExtractImages(Helper.MaybeDownload(SourceUrl, trainDir, TestImagesName), TestImagesName);
            TrainLabels = ExtractLabels(Helper.MaybeDownload(SourceUrl, trainDir, TrainLabelsName), TrainLabelsName);
            TestLabels = ExtractLabels(Helper.MaybeDownload(SourceUrl, trainDir, TestLabelsName), TestLabelsName);

            ValidationImages = Pick(TrainImages, 0, validationSize);
            ValidationLabels = Pick(TrainLabels, 0, validationSize);
            TrainImages = Pick(TrainImages, validationSize, 0);
            TrainLabels = Pick(TrainLabels, validationSize, 0);

            if (numClasses != -1)
            {
                OneHotTrainLabels = OneHot(TrainLabels, numClasses);
                OneHotValidationLabels = OneHot(ValidationLabels, numClasses);
                OneHotTestLabels = OneHot(TestLabels, numClasses);
            }
        }

        public static Mnist Load()
        {
            var x = new Mnist();
            x.ReadDataSets(Environment.CurrentDirectory + "\\tmp");
            return x;
        }
    }
}

DataConverter.cs文件

//
// Authors:
//   Miguel de Icaza ([email protected])
//
// See the following url for documentation:
//     http://www.mono-project.com/Mono_DataConvert
//
// Compilation Options:
//     MONO_DATACONVERTER_PUBLIC:
//         Makes the class public instead of the default internal.
//
//     MONO_DATACONVERTER_STATIC_METHODS:     
//         Exposes the public static methods.
//
// TODO:
//   Support for "DoubleWordsAreSwapped" for ARM devices
//
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#define MONO_DATACONVERTER_PUBLIC
using System;
using System.Collections;
using System.Text;
using System.Collections.Generic;

#pragma warning disable 3021

namespace Mono
{

#if MONO_DATACONVERTER_PUBLIC
    public
#endif
    unsafe abstract class DataConverter
    {

        // Disables the warning: CLS compliance checking will not be performed on
        //  `XXXX' because it is not visible from outside this assembly
#pragma warning disable 3019
        static readonly DataConverter SwapConv = new SwapConverter();
        static readonly DataConverter CopyConv = new CopyConverter();

        public static readonly bool IsLittleEndian = BitConverter.IsLittleEndian;

        public abstract double GetDouble(byte[] data, int index);
        public abstract float GetFloat(byte[] data, int index);
        public abstract long GetInt64(byte[] data, int index);
        public abstract int GetInt32(byte[] data, int index);

        public abstract short GetInt16(byte[] data, int index);

        [CLSCompliant(false)]
        public abstract uint GetUInt32(byte[] data, int index);
        [CLSCompliant(false)]
        public abstract ushort GetUInt16(byte[] data, int index);
        [CLSCompliant(false)]
        public abstract ulong GetUInt64(byte[] data, int index);

        public abstract void PutBytes(byte[] dest, int destIdx, double value);
        public abstract void PutBytes(byte[] dest, int destIdx, float value);
        public abstract void PutBytes(byte[] dest, int destIdx, int value);
        public abstract void PutBytes(byte[] dest, int destIdx, long value);
        public abstract void PutBytes(byte[] dest, int destIdx, short value);

        [CLSCompliant(false)]
        public abstract void PutBytes(byte[] dest, int destIdx, ushort value);
        [CLSCompliant(false)]
        public abstract void PutBytes(byte[] dest, int destIdx, uint value);
        [CLSCompliant(false)]
        public abstract void PutBytes(byte[] dest, int destIdx, ulong value);

        public byte[] GetBytes(double value)
        {
            byte[] ret = new byte[8];
            PutBytes(ret, 0, value);
            return ret;
        }

        public byte[] GetBytes(float value)
        {
            byte[] ret = new byte[4];
            PutBytes(ret, 0, value);
            return ret;
        }

        public byte[] GetBytes(int value)
        {
            byte[] ret = new byte[4];
            PutBytes(ret, 0, value);
            return ret;
        }

        public byte[] GetBytes(long value)
        {
            byte[] ret = new byte[8];
            PutBytes(ret, 0, value);
            return ret;
        }

        public byte[] GetBytes(short value)
        {
            byte[] ret = new byte[2];
            PutBytes(ret, 0, value);
            return ret;
        }

        [CLSCompliant(false)]
        public byte[] GetBytes(ushort value)
        {
            byte[] ret = new byte[2];
            PutBytes(ret, 0, value);
            return ret;
        }

        [CLSCompliant(false)]
        public byte[] GetBytes(uint value)
        {
            byte[] ret = new byte[4];
            PutBytes(ret, 0, value);
            return ret;
        }

        [CLSCompliant(false)]
        public byte[] GetBytes(ulong value)
        {
            byte[] ret = new byte[8];
            PutBytes(ret, 0, value);
            return ret;
        }

        static public DataConverter LittleEndian
        {
            get
            {
                return BitConverter.IsLittleEndian ? CopyConv : SwapConv;
            }
        }

        static public DataConverter BigEndian
        {
            get
            {
                return BitConverter.IsLittleEndian ? SwapConv : CopyConv;
            }
        }

        static public DataConverter Native
        {
            get
            {
                return CopyConv;
            }
        }

        static int Align(int current, int align)
        {
            return ((current + align - 1) / align) * align;
        }

        class PackContext
        {
            // Buffer
            public byte[] buffer;
            int next;

            public string description;
            public int i; // position in the description
            public DataConverter conv;
            public int repeat;

            //
            // if align == -1, auto align to the size of the byte array
            // if align == 0, do not do alignment
            // Any other values aligns to that particular size
            //
            public int align;

            public void Add(byte[] group)
            {
                //Console.WriteLine ("Adding {0} bytes to {1} (next={2}", group.Length,
                // buffer == null ? "null" : buffer.Length.ToString (), next);

                if (buffer == null)
                {
                    buffer = group;
                    next = group.Length;
                    return;
                }
                if (align != 0)
                {
                    if (align == -1)
                        next = Align(next, group.Length);
                    else
                        next = Align(next, align);
                    align = 0;
                }

                if (next + group.Length > buffer.Length)
                {
                    byte[] nb = new byte[System.Math.Max(next, 16) * 2 + group.Length];
                    Array.Copy(buffer, nb, buffer.Length);
                    Array.Copy(group, 0, nb, next, group.Length);
                    next = next + group.Length;
                    buffer = nb;
                }
                else
                {
                    Array.Copy(group, 0, buffer, next, group.Length);
                    next += group.Length;
                }
            }

            public byte[] Get()
            {
                if (buffer == null)
                    return new byte[0];

                if (buffer.Length != next)
                {
                    byte[] b = new byte[next];
                    Array.Copy(buffer, b, next);
                    return b;
                }
                return buffer;
            }
        }

        //
        // Format includes:
        // Control:
        //   ^    Switch to big endian encoding
        //   _    Switch to little endian encoding
        //   %    Switch to host (native) encoding
        //   !    aligns the next data type to its natural boundary (for strings this is 4).
        //
        // Types:
        //   s    Int16
        //   S    UInt16
        //   i    Int32
        //   I    UInt32
        //   l    Int64
        //   L    UInt64
        //   f    float
        //   d    double
        //   b    byte
        //   c    1-byte signed character
        //   C    1-byte unsigned character
        //   z8   string encoded as UTF8 with 1-byte null terminator
        //   z6   string encoded as UTF16 with 2-byte null terminator
        //   z7   string encoded as UTF7 with 1-byte null terminator
        //   zb   string encoded as BigEndianUnicode with 2-byte null terminator
        //   z3   string encoded as UTF32 with 4-byte null terminator
        //   z4   string encoded as UTF32 big endian with 4-byte null terminator
        //   $8   string encoded as UTF8
        //   $6   string encoded as UTF16
        //   $7   string encoded as UTF7
        //   $b   string encoded as BigEndianUnicode
        //   $3   string encoded as UTF32
        //   $4   string encoded as UTF-32 big endian encoding
        //   x    null byte
        //
        // Repeats, these are prefixes:
        //   N    a number between 1 and 9, indicates a repeat count (process N items
        //        with the following datatype
        //   [N]  For numbers larger than 9, use brackets, for example [20]
        //   *    Repeat the next data type until the arguments are exhausted
        //
        static public byte[] Pack(string description, params object[] args)
        {
            int argn = 0;
            PackContext b = new PackContext();
            b.conv = CopyConv;
            b.description = description;

            for (b.i = 0; b.i < description.Length;)
            {
                object oarg;

                if (argn < args.Length)
                    oarg = args[argn];
                else
                {
                    if (b.repeat != 0)
                        break;

                    oarg = null;
                }

                int save = b.i;

                if (PackOne(b, oarg))
                {
                    argn++;
                    if (b.repeat > 0)
                    {
                        if (--b.repeat > 0)
                            b.i = save;
                        else
                            b.i++;
                    }
                    else
                        b.i++;
                }
                else
                    b.i++;
            }
            return b.Get();
        }

        static public byte[] PackEnumerable(string description, IEnumerable args)
        {
            PackContext b = new PackContext();
            b.conv = CopyConv;
            b.description = description;

            IEnumerator enumerator = args.GetEnumerator();
            bool ok = enumerator.MoveNext();

            for (b.i = 0; b.i < description.Length;)
            {
                object oarg;

                if (ok)
                    oarg = enumerator.Current;
                else
                {
                    if (b.repeat != 0)
                        break;
                    oarg = null;
                }

                int save = b.i;

                if (PackOne(b, oarg))
                {
                    ok = enumerator.MoveNext();
                    if (b.repeat > 0)
                    {
                        if (--b.repeat > 0)
                            b.i = save;
                        else
                            b.i++;
                    }
                    else
                        b.i++;
                }
                else
                    b.i++;
            }
            return b.Get();
        }

        //
        // Packs one datum `oarg' into the buffer `b', using the string format
        // in `description' at position `i'
        //
        // Returns: true if we must pick the next object from the list
        //
        static bool PackOne(PackContext b, object oarg)
        {
            int n;

            switch (b.description[b.i])
            {
                case '^':
                    b.conv = BigEndian;
                    return false;
                case '_':
                    b.conv = LittleEndian;
                    return false;
                case '%':
                    b.conv = Native;
                    return false;

                case '!':
                    b.align = -1;
                    return false;

                case 'x':
                    b.Add(new byte[] { 0 });
                    return false;

                // Type Conversions
                case 'i':
                    b.Add(b.conv.GetBytes(Convert.ToInt32(oarg)));
                    break;

                case 'I':
                    b.Add(b.conv.GetBytes(Convert.ToUInt32(oarg)));
                    break;

                case 's':
                    b.Add(b.conv.GetBytes(Convert.ToInt16(oarg)));
                    break;

                case 'S':
                    b.Add(b.conv.GetBytes(Convert.ToUInt16(oarg)));
                    break;

                case 'l':
                    b.Add(b.conv.GetBytes(Convert.ToInt64(oarg)));
                    break;

                case 'L':
                    b.Add(b.conv.GetBytes(Convert.ToUInt64(oarg)));
                    break;

                case 'f':
                    b.Add(b.conv.GetBytes(Convert.ToSingle(oarg)));
                    break;

                case 'd':
                    b.Add(b.conv.GetBytes(Convert.ToDouble(oarg)));
                    break;

                case 'b':
                    b.Add(new byte[] { Convert.ToByte(oarg) });
                    break;

                case 'c':
                    b.Add(new byte[] { (byte)(Convert.ToSByte(oarg)) });
                    break;

                case 'C':
                    b.Add(new byte[] { Convert.ToByte(oarg) });
                    break;

                // Repeat acount;
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                    b.repeat = ((short)b.description[b.i]) - ((short)'0');
                    return false;

                case '*':
                    b.repeat = Int32.MaxValue;
                    return false;

                case '[':
                    int count = -1, j;

                    for (j = b.i + 1; j < b.description.Length; j++)
                    {
                        if (b.description[j] == ']')
                            break;
                        n = ((short)b.description[j]) - ((short)'0');
                        if (n >= 0 && n <= 9)
                        {
                            if (count == -1)
                                count = n;
                            else
                                count = count * 10 + n;
                        }
                    }
                    if (count == -1)
                        throw new ArgumentException("invalid size specification");
                    b.i = j;
                    b.repeat = count;
                    return false;

                case '$':
                case 'z':
                    bool add_null = b.description[b.i] == 'z';
                    b.i++;
                    if (b.i >= b.description.Length)
                        throw new ArgumentException("$ description needs a type specified", "description");
                    char d = b.description[b.i];
                    Encoding e;

                    switch (d)
                    {
                        case '8':
                            e = Encoding.UTF8;
                            n = 1;
                            break;
                        case '6':
                            e = Encoding.Unicode;
                            n = 2;
                            break;
                        case '7':
#if PCL
					e = Encoding.GetEncoding ("utf-7");
#else
                            e = Encoding.UTF7;
#endif
                            n = 1;
                            break;
                        case 'b':
                            e = Encoding.BigEndianUnicode;
                            n = 2;
                            break;
                        case '3':
#if PCL
					e = Encoding.GetEncoding ("utf-32");
#else
                            e = Encoding.GetEncoding(12000);
#endif
                            n = 4;
                            break;
                        case '4':
#if PCL
					e = Encoding.GetEncoding ("utf-32BE");
#else
                            e = Encoding.GetEncoding(12001);
#endif
                            n = 4;
                            break;

                        default:
                            throw new ArgumentException("Invalid format for $ specifier", "description");
                    }
                    if (b.align == -1)
                        b.align = 4;
                    b.Add(e.GetBytes(Convert.ToString(oarg)));
                    if (add_null)
                        b.Add(new byte[n]);
                    break;
                default:
                    throw new ArgumentException(String.Format("invalid format specified `{0}'",
                                            b.description[b.i]));
            }
            return true;
        }

        static bool Prepare(byte[] buffer, ref int idx, int size, ref bool align)
        {
            if (align)
            {
                idx = Align(idx, size);
                align = false;
            }
            if (idx + size > buffer.Length)
            {
                idx = buffer.Length;
                return false;
            }
            return true;
        }

        static public IList Unpack(string description, byte[] buffer, int startIndex)
        {
            DataConverter conv = CopyConv;
            var result = new List<object>();
            int idx = startIndex;
            bool align = false;
            int repeat = 0, n;

            for (int i = 0; i < description.Length && idx < buffer.Length;)
            {
                int save = i;

                switch (description[i])
                {
                    case '^':
                        conv = BigEndian;
                        break;
                    case '_':
                        conv = LittleEndian;
                        break;
                    case '%':
                        conv = Native;
                        break;
                    case 'x':
                        idx++;
                        break;

                    case '!':
                        align = true;
                        break;

                    // Type Conversions
                    case 'i':
                        if (Prepare(buffer, ref idx, 4, ref align))
                        {
                            result.Add(conv.GetInt32(buffer, idx));
                            idx += 4;
                        }
                        break;

                    case 'I':
                        if (Prepare(buffer, ref idx, 4, ref align))
                        {
                            result.Add(conv.GetUInt32(buffer, idx));
                            idx += 4;
                        }
                        break;

                    case 's':
                        if (Prepare(buffer, ref idx, 2, ref align))
                        {
                            result.Add(conv.GetInt16(buffer, idx));
                            idx += 2;
                        }
                        break;

                    case 'S':
                        if (Prepare(buffer, ref idx, 2, ref align))
                        {
                            result.Add(conv.GetUInt16(buffer, idx));
                            idx += 2;
                        }
                        break;

                    case 'l':
                        if (Prepare(buffer, ref idx, 8, ref align))
                        {
                            result.Add(conv.GetInt64(buffer, idx));
                            idx += 8;
                        }
                        break;

                    case 'L':
                        if (Prepare(buffer, ref idx, 8, ref align))
                        {
                            result.Add(conv.GetUInt64(buffer, idx));
                            idx += 8;
                        }
                        break;

                    case 'f':
                        if (Prepare(buffer, ref idx, 4, ref align))
                        {
                            result.Add(conv.GetFloat(buffer, idx));
                            idx += 4;
                        }
                        break;

                    case 'd':
                        if (Prepare(buffer, ref idx, 8, ref align))
                        {
                            result.Add(conv.GetDouble(buffer, idx));
                            idx += 8;
                        }
                        break;

                    case 'b':
                        if (Prepare(buffer, ref idx, 1, ref align))
                        {
                            result.Add(buffer[idx]);
                            idx++;
                        }
                        break;

                    case 'c':
                    case 'C':
                        if (Prepare(buffer, ref idx, 1, ref align))
                        {
                            char c;

                            if (description[i] == 'c')
                                c = ((char)((sbyte)buffer[idx]));
                            else
                                c = ((char)((byte)buffer[idx]));

                            result.Add(c);
                            idx++;
                        }
                        break;

                    // Repeat acount;
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        repeat = ((short)description[i]) - ((short)'0');
                        save = i + 1;
                        break;

                    case '*':
                        repeat = Int32.MaxValue;
                        break;

                    case '[':
                        int count = -1, j;

                        for (j = i + 1; j < description.Length; j++)
                        {
                            if (description[j] == ']')
                                break;
                            n = ((short)description[j]) - ((short)'0');
                            if (n >= 0 && n <= 9)
                            {
                                if (count == -1)
                                    count = n;
                                else
                                    count = count * 10 + n;
                            }
                        }
                        if (count == -1)
                            throw new ArgumentException("invalid size specification");
                        i = j;
                        save = i + 1;
                        repeat = count;
                        break;

                    case '$':
                    case 'z':
                        // bool with_null = description [i] == 'z';
                        i++;
                        if (i >= description.Length)
                            throw new ArgumentException("$ description needs a type specified", "description");
                        char d = description[i];
                        Encoding e;
                        if (align)
                        {
                            idx = Align(idx, 4);
                            align = false;
                        }
                        if (idx >= buffer.Length)
                            break;

                        switch (d)
                        {
                            case '8':
                                e = Encoding.UTF8;
                                n = 1;
                                break;
                            case '6':
                                e = Encoding.Unicode;
                                n = 2;
                                break;
                            case '7':
#if PCL
						e = Encoding.GetEncoding ("utf-7");
#else
                                e = Encoding.UTF7;
#endif
                                n = 1;
                                break;
                            case 'b':
                                e = Encoding.BigEndianUnicode;
                                n = 2;
                                break;
                            case '3':
#if PCL
						e = Encoding.GetEncoding ("utf-32");
#else
                                e = Encoding.GetEncoding(12000);
#endif
                                n = 4;
                                break;
                            case '4':
#if PCL
						e = Encoding.GetEncoding ("utf-32BE");
#else
                                e = Encoding.GetEncoding(12001);
#endif
                                n = 4;
                                break;

                            default:
                                throw new ArgumentException("Invalid format for $ specifier", "description");
                        }
                        int k = idx;
                        switch (n)
                        {
                            case 1:
                                for (; k < buffer.Length && buffer[k] != 0; k++)
                                    ;
                                result.Add(e.GetChars(buffer, idx, k - idx));
                                if (k == buffer.Length)
                                    idx = k;
                                else
                                    idx = k + 1;
                                break;

                            case 2:
                                for (; k < buffer.Length; k++)
                                {
                                    if (k + 1 == buffer.Length)
                                    {
                                        k++;
                                        break;
                                    }
                                    if (buffer[k] == 0 && buffer[k + 1] == 0)
                                        break;
                                }
                                result.Add(e.GetChars(buffer, idx, k - idx));
                                if (k == buffer.Length)
                                    idx = k;
                                else
                                    idx = k + 2;
                                break;

                            case 4:
                                for (; k < buffer.Length; k++)
                                {
                                    if (k + 3 >= buffer.Length)
                                    {
                                        k = buffer.Length;
                                        break;
                                    }
                                    if (buffer[k] == 0 && buffer[k + 1] == 0 && buffer[k + 2] == 0 && buffer[k + 3] == 0)
                                        break;
                                }
                                result.Add(e.GetChars(buffer, idx, k - idx));
                                if (k == buffer.Length)
                                    idx = k;
                                else
                                    idx = k + 4;
                                break;
                        }
                        break;
                    default:
                        throw new ArgumentException(String.Format("invalid format specified `{0}'",
                                                description[i]));
                }

                if (repeat > 0)
                {
                    if (--repeat > 0)
                        i = save;
                }
                else
                    i++;
            }
            return result;
        }

        internal void Check(byte[] dest, int destIdx, int size)
        {
            if (dest == null)
                throw new ArgumentNullException("dest");
            if (destIdx < 0 || destIdx > dest.Length - size)
                throw new ArgumentException("destIdx");
        }

        class CopyConverter : DataConverter
        {
            public override double GetDouble(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 8)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");
                double ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 8; i++)
                    b[i] = data[index + i];

                return ret;
            }

            public override ulong GetUInt64(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 8)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                ulong ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 8; i++)
                    b[i] = data[index + i];

                return ret;
            }

            public override long GetInt64(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 8)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                long ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 8; i++)
                    b[i] = data[index + i];

                return ret;
            }

            public override float GetFloat(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 4)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                float ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 4; i++)
                    b[i] = data[index + i];

                return ret;
            }

            public override int GetInt32(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 4)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                int ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 4; i++)
                    b[i] = data[index + i];

                return ret;
            }

            public override uint GetUInt32(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 4)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                uint ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 4; i++)
                    b[i] = data[index + i];

                return ret;
            }

            public override short GetInt16(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 2)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                short ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 2; i++)
                    b[i] = data[index + i];

                return ret;
            }

            public override ushort GetUInt16(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 2)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                ushort ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 2; i++)
                    b[i] = data[index + i];

                return ret;
            }

            public override void PutBytes(byte[] dest, int destIdx, double value)
            {
                Check(dest, destIdx, 8);
                fixed (byte* target = &dest[destIdx])
                {
                    long* source = (long*)&value;

                    *((long*)target) = *source;
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, float value)
            {
                Check(dest, destIdx, 4);
                fixed (byte* target = &dest[destIdx])
                {
                    uint* source = (uint*)&value;

                    *((uint*)target) = *source;
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, int value)
            {
                Check(dest, destIdx, 4);
                fixed (byte* target = &dest[destIdx])
                {
                    uint* source = (uint*)&value;

                    *((uint*)target) = *source;
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, uint value)
            {
                Check(dest, destIdx, 4);
                fixed (byte* target = &dest[destIdx])
                {
                    uint* source = (uint*)&value;

                    *((uint*)target) = *source;
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, long value)
            {
                Check(dest, destIdx, 8);
                fixed (byte* target = &dest[destIdx])
                {
                    long* source = (long*)&value;

                    *((long*)target) = *source;
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, ulong value)
            {
                Check(dest, destIdx, 8);
                fixed (byte* target = &dest[destIdx])
                {
                    ulong* source = (ulong*)&value;

                    *((ulong*)target) = *source;
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, short value)
            {
                Check(dest, destIdx, 2);
                fixed (byte* target = &dest[destIdx])
                {
                    ushort* source = (ushort*)&value;

                    *((ushort*)target) = *source;
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, ushort value)
            {
                Check(dest, destIdx, 2);
                fixed (byte* target = &dest[destIdx])
                {
                    ushort* source = (ushort*)&value;

                    *((ushort*)target) = *source;
                }
            }
        }

        class SwapConverter : DataConverter
        {
            public override double GetDouble(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 8)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                double ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 8; i++)
                    b[7 - i] = data[index + i];

                return ret;
            }

            public override ulong GetUInt64(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 8)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                ulong ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 8; i++)
                    b[7 - i] = data[index + i];

                return ret;
            }

            public override long GetInt64(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 8)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                long ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 8; i++)
                    b[7 - i] = data[index + i];

                return ret;
            }

            public override float GetFloat(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 4)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                float ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 4; i++)
                    b[3 - i] = data[index + i];

                return ret;
            }

            public override int GetInt32(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 4)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                int ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 4; i++)
                    b[3 - i] = data[index + i];

                return ret;
            }

            public override uint GetUInt32(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 4)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                uint ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 4; i++)
                    b[3 - i] = data[index + i];

                return ret;
            }

            public override short GetInt16(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 2)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                short ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 2; i++)
                    b[1 - i] = data[index + i];

                return ret;
            }

            public override ushort GetUInt16(byte[] data, int index)
            {
                if (data == null)
                    throw new ArgumentNullException("data");
                if (data.Length - index < 2)
                    throw new ArgumentException("index");
                if (index < 0)
                    throw new ArgumentException("index");

                ushort ret;
                byte* b = (byte*)&ret;

                for (int i = 0; i < 2; i++)
                    b[1 - i] = data[index + i];

                return ret;
            }

            public override void PutBytes(byte[] dest, int destIdx, double value)
            {
                Check(dest, destIdx, 8);

                fixed (byte* target = &dest[destIdx])
                {
                    byte* source = (byte*)&value;

                    for (int i = 0; i < 8; i++)
                        target[i] = source[7 - i];
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, float value)
            {
                Check(dest, destIdx, 4);

                fixed (byte* target = &dest[destIdx])
                {
                    byte* source = (byte*)&value;

                    for (int i = 0; i < 4; i++)
                        target[i] = source[3 - i];
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, int value)
            {
                Check(dest, destIdx, 4);

                fixed (byte* target = &dest[destIdx])
                {
                    byte* source = (byte*)&value;

                    for (int i = 0; i < 4; i++)
                        target[i] = source[3 - i];
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, uint value)
            {
                Check(dest, destIdx, 4);

                fixed (byte* target = &dest[destIdx])
                {
                    byte* source = (byte*)&value;

                    for (int i = 0; i < 4; i++)
                        target[i] = source[3 - i];
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, long value)
            {
                Check(dest, destIdx, 8);

                fixed (byte* target = &dest[destIdx])
                {
                    byte* source = (byte*)&value;

                    for (int i = 0; i < 8; i++)
                        target[i] = source[7 - i];
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, ulong value)
            {
                Check(dest, destIdx, 8);

                fixed (byte* target = &dest[destIdx])
                {
                    byte* source = (byte*)&value;

                    for (int i = 0; i < 8; i++)
                        target[i] = source[7 - i];
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, short value)
            {
                Check(dest, destIdx, 2);

                fixed (byte* target = &dest[destIdx])
                {
                    byte* source = (byte*)&value;

                    for (int i = 0; i < 2; i++)
                        target[i] = source[1 - i];
                }
            }

            public override void PutBytes(byte[] dest, int destIdx, ushort value)
            {
                Check(dest, destIdx, 2);

                fixed (byte* target = &dest[destIdx])
                {
                    byte* source = (byte*)&value;

                    for (int i = 0; i < 2; i++)
                        target[i] = source[1 - i];
                }
            }
        }

#if MONO_DATACONVERTER_STATIC_METHODS
		static unsafe void PutBytesLE (byte *dest, byte *src, int count)
		{
			int i = 0;
			
			if (BitConverter.IsLittleEndian){
				for (; i < count; i++)
					*dest++ = *src++;
			} else {
				dest += count;
				for (; i < count; i++)
					*(--dest) = *src++;
			}
		}

		static unsafe void PutBytesBE (byte *dest, byte *src, int count)
		{
			int i = 0;
			
			if (BitConverter.IsLittleEndian){
				dest += count;
				for (; i < count; i++)
					*(--dest) = *src++;
			} else {
				for (; i < count; i++)
					*dest++ = *src++;
			}
		}

		static unsafe void PutBytesNative (byte *dest, byte *src, int count)
		{
			int i = 0;
			
			for (; i < count; i++)
				dest [i-count] = *src++;
		}
		
		static public unsafe double DoubleFromLE (byte[] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 8)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			double ret;
			fixed (byte *src = &data[index]){
				PutBytesLE ((byte *) &ret, src, 8);
			}
			return ret;
		}

		static public unsafe float FloatFromLE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 4)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			float ret;
			fixed (byte *src = &data[index]){
				PutBytesLE ((byte *) &ret, src, 4);
			}
			return ret;
		}

		static public unsafe long Int64FromLE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 8)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			long ret;
			fixed (byte *src = &data[index]){
				PutBytesLE ((byte *) &ret, src, 8);
			}
			return ret;
		}
		
		static public unsafe ulong UInt64FromLE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 8)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			ulong ret;
			fixed (byte *src = &data[index]){
				PutBytesLE ((byte *) &ret, src, 8);
			}
			return ret;
		}

		static public unsafe int Int32FromLE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 4)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			int ret;
			fixed (byte *src = &data[index]){
				PutBytesLE ((byte *) &ret, src, 4);
			}
			return ret;
		}
		
		static public unsafe uint UInt32FromLE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 4)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			uint ret;
			fixed (byte *src = &data[index]){
				PutBytesLE ((byte *) &ret, src, 4);
			}
			return ret;
		}

		static public unsafe short Int16FromLE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 2)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");

			short ret;
			fixed (byte *src = &data[index]){
				PutBytesLE ((byte *) &ret, src, 2);
			}
			return ret;
		}
		
		static public unsafe ushort UInt16FromLE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 2)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			ushort ret;
			fixed (byte *src = &data[index]){
				PutBytesLE ((byte *) &ret, src, 2);
			}
			return ret;
		}

		static public unsafe double DoubleFromBE (byte[] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 8)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			double ret;
			fixed (byte *src = &data[index]){
				PutBytesBE ((byte *) &ret, src, 8);
			}
			return ret;
		}

		static public unsafe float FloatFromBE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 4)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			float ret;
			fixed (byte *src = &data[index]){
				PutBytesBE ((byte *) &ret, src, 4);
			}
			return ret;
		}

		static public unsafe long Int64FromBE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 8)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			long ret;
			fixed (byte *src = &data[index]){
				PutBytesBE ((byte *) &ret, src, 8);
			}
			return ret;
		}
		
		static public unsafe ulong UInt64FromBE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 8)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			ulong ret;
			fixed (byte *src = &data[index]){
				PutBytesBE ((byte *) &ret, src, 8);
			}
			return ret;
		}

		static public unsafe int Int32FromBE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 4)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			int ret;
			fixed (byte *src = &data[index]){
				PutBytesBE ((byte *) &ret, src, 4);
			}
			return ret;
		}
		
		static public unsafe uint UInt32FromBE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 4)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			uint ret;
			fixed (byte *src = &data[index]){
				PutBytesBE ((byte *) &ret, src, 4);
			}
			return ret;
		}

		static public unsafe short Int16FromBE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 2)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");

			short ret;
			fixed (byte *src = &data[index]){
				PutBytesBE ((byte *) &ret, src, 2);
			}
			return ret;
		}
		
		static public unsafe ushort UInt16FromBE (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 2)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			ushort ret;
			fixed (byte *src = &data[index]){
				PutBytesBE ((byte *) &ret, src, 2);
			}
			return ret;
		}

		static public unsafe double DoubleFromNative (byte[] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 8)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			double ret;
			fixed (byte *src = &data[index]){
				PutBytesNative ((byte *) &ret, src, 8);
			}
			return ret;
		}

		static public unsafe float FloatFromNative (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 4)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			float ret;
			fixed (byte *src = &data[index]){
				PutBytesNative ((byte *) &ret, src, 4);
			}
			return ret;
		}

		static public unsafe long Int64FromNative (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 8)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			long ret;
			fixed (byte *src = &data[index]){
				PutBytesNative ((byte *) &ret, src, 8);
			}
			return ret;
		}
		
		static public unsafe ulong UInt64FromNative (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 8)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			ulong ret;
			fixed (byte *src = &data[index]){
				PutBytesNative ((byte *) &ret, src, 8);
			}
			return ret;
		}

		static public unsafe int Int32FromNative (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 4)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			int ret;
			fixed (byte *src = &data[index]){
				PutBytesNative ((byte *) &ret, src, 4);
			}
			return ret;
		}
		
		static public unsafe uint UInt32FromNative (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 4)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			uint ret;
			fixed (byte *src = &data[index]){
				PutBytesNative ((byte *) &ret, src, 4);
			}
			return ret;
		}

		static public unsafe short Int16FromNative (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 2)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");

			short ret;
			fixed (byte *src = &data[index]){
				PutBytesNative ((byte *) &ret, src, 2);
			}
			return ret;
		}
		
		static public unsafe ushort UInt16FromNative (byte [] data, int index)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			if (data.Length - index < 2)
				throw new ArgumentException ("index");
			if (index < 0)
				throw new ArgumentException ("index");
			
			ushort ret;
			fixed (byte *src = &data[index]){
				PutBytesNative ((byte *) &ret, src, 2);
			}
			return ret;
		}

                unsafe static byte[] GetBytesPtr (byte *ptr, int count)
                {
                        byte [] ret = new byte [count];

                        for (int i = 0; i < count; i++) {
                                ret [i] = ptr [i];
                        }

                        return ret;
                }

                unsafe static byte[] GetBytesSwap (bool swap, byte *ptr, int count)
                {
                        byte [] ret = new byte [count];

			if (swap){
				int t = count-1;
				for (int i = 0; i < count; i++) {
					ret [t-i] = ptr [i];
				}
			} else {
				for (int i = 0; i < count; i++) {
					ret [i] = ptr [i];
				}
			}
                        return ret;
                }
		
                unsafe public static byte[] GetBytesNative (bool value)
                {
                        return GetBytesPtr ((byte *) &value, 1);
                }

                unsafe public static byte[] GetBytesNative (char value)
                {
                        return GetBytesPtr ((byte *) &value, 2);
                }

                unsafe public static byte[] GetBytesNative (short value)
                {
                        return GetBytesPtr ((byte *) &value, 2);
                }

                unsafe public static byte[] GetBytesNative (int value)
                {
                        return GetBytesPtr ((byte *) &value, 4);
                }

                unsafe public static byte[] GetBytesNative (long value)
                {
                        return GetBytesPtr ((byte *) &value, 8);
                }

                [CLSCompliant (false)]
                unsafe public static byte[] GetBytesNative (ushort value)
                {
                        return GetBytesPtr ((byte *) &value, 2);
                }

                [CLSCompliant (false)]
                unsafe public static byte[] GetBytesNative (uint value)
                {
                        return GetBytesPtr ((byte *) &value, 4);
                }

                [CLSCompliant (false)]
                unsafe public static byte[] GetBytesNative (ulong value)
                {
                        return GetBytesPtr ((byte *) &value, 8);
                }

                unsafe public static byte[] GetBytesNative (float value)
                {
                        return GetBytesPtr ((byte *) &value, 4);
                }

                unsafe public static byte[] GetBytesNative (double value)
                {
			return GetBytesPtr ((byte *) &value, 8);
                }

                unsafe public static byte[] GetBytesLE (bool value)
                {
                        return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 1);
                }

                unsafe public static byte[] GetBytesLE (char value)
                {
                        return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 2);
                }

                unsafe public static byte[] GetBytesLE (short value)
                {
                        return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 2);
                }

                unsafe public static byte[] GetBytesLE (int value)
                {
                        return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 4);
                }

                unsafe public static byte[] GetBytesLE (long value)
                {
                        return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 8);
                }

                [CLSCompliant (false)]
                unsafe public static byte[] GetBytesLE (ushort value)
                {
                        return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 2);
                }

                [CLSCompliant (false)]
                unsafe public static byte[] GetBytesLE (uint value)
                {
                        return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 4);
                }

                [CLSCompliant (false)]
                unsafe public static byte[] GetBytesLE (ulong value)
                {
                        return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 8);
                }

                unsafe public static byte[] GetBytesLE (float value)
                {
                        return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 4);
                }

                unsafe public static byte[] GetBytesLE (double value)
                {
			return GetBytesSwap (!BitConverter.IsLittleEndian, (byte *) &value, 8);
                }
		
                unsafe public static byte[] GetBytesBE (bool value)
                {
                        return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 1);
                }

                unsafe public static byte[] GetBytesBE (char value)
                {
                        return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 2);
                }

                unsafe public static byte[] GetBytesBE (short value)
                {
                        return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 2);
                }

                unsafe public static byte[] GetBytesBE (int value)
                {
                        return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 4);
                }

                unsafe public static byte[] GetBytesBE (long value)
                {
                        return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 8);
                }

                [CLSCompliant (false)]
                unsafe public static byte[] GetBytesBE (ushort value)
                {
                        return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 2);
                }

                [CLSCompliant (false)]
                unsafe public static byte[] GetBytesBE (uint value)
                {
                        return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 4);
                }

                [CLSCompliant (false)]
                unsafe public static byte[] GetBytesBE (ulong value)
                {
                        return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 8);
                }

                unsafe public static byte[] GetBytesBE (float value)
                {
                        return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 4);
                }

                unsafe public static byte[] GetBytesBE (double value)
                {
			return GetBytesSwap (BitConverter.IsLittleEndian, (byte *) &value, 8);
                }
#endif

    }
}

help.cs

using System;
using System.IO;
using System.Net;

namespace Learn
{
    public class Helper
    {
        public static Stream MaybeDownload(string urlBase, string trainDir, string file)
        {
            if (!Directory.Exists(trainDir))
                Directory.CreateDirectory(trainDir);
            var target = Path.Combine(trainDir, file);
            if (!File.Exists(target))
            {
                var wc = new WebClient();
                wc.DownloadFile(urlBase + file, target);
            }
            return File.OpenRead(target);
        }
    }
}

初开博客,目的合作 交流,QQ:273651820.。

猜你喜欢

转载自blog.csdn.net/qq_26996385/article/details/83618369