예제 #1
0
        /// <summary>
        /// Checks the basic validity of the header, assuming the stream is at least the given size.
        /// Returns false (and the out exception) on failure.
        /// </summary>
        public static bool TryValidate(ref ModelHeader header, long size, out Exception ex)
        {
            Contracts.Check(size >= 0);

            try
            {
                Contracts.CheckDecode(header.Signature == SignatureValue, "Wrong file type");
                Contracts.CheckDecode(header.VerReadable <= header.VerWritten, "Corrupt file header");
                Contracts.CheckDecode(header.VerReadable <= VerWrittenCur, "File is too new");
                Contracts.CheckDecode(header.VerWritten >= VerWeCanReadBack, "File is too old");

                // Currently the model always comes immediately after the header.
                Contracts.CheckDecode(header.FpModel == Size);
                Contracts.CheckDecode(header.FpModel + header.CbModel >= header.FpModel);

                if (header.FpStringTable == 0)
                {
                    // No strings.
                    Contracts.CheckDecode(header.CbStringTable == 0);
                    Contracts.CheckDecode(header.FpStringChars == 0);
                    Contracts.CheckDecode(header.CbStringChars == 0);
                    if (header.VerWritten < VerAssemblyNameSupported || header.FpAssemblyName == 0)
                    {
                        Contracts.CheckDecode(header.FpTail == header.FpModel + header.CbModel);
                    }
                }
                else
                {
                    // Currently the string table always comes immediately after the model block.
                    Contracts.CheckDecode(header.FpStringTable == header.FpModel + header.CbModel);
                    Contracts.CheckDecode(header.CbStringTable % sizeof(long) == 0);
                    Contracts.CheckDecode(header.CbStringTable / sizeof(long) < int.MaxValue);
                    Contracts.CheckDecode(header.FpStringTable + header.CbStringTable > header.FpStringTable);
                    Contracts.CheckDecode(header.FpStringChars == header.FpStringTable + header.CbStringTable);
                    Contracts.CheckDecode(header.CbStringChars % sizeof(char) == 0);
                    Contracts.CheckDecode(header.FpStringChars + header.CbStringChars >= header.FpStringChars);
                    if (header.VerWritten < VerAssemblyNameSupported || header.FpAssemblyName == 0)
                    {
                        Contracts.CheckDecode(header.FpTail == header.FpStringChars + header.CbStringChars);
                    }
                }

                if (header.VerWritten >= VerAssemblyNameSupported)
                {
                    if (header.FpAssemblyName == 0)
                    {
                        Contracts.CheckDecode(header.CbAssemblyName == 0);
                    }
                    else
                    {
                        // the assembly name always immediately after the string table, if there is one
                        if (header.FpStringTable == 0)
                        {
                            Contracts.CheckDecode(header.FpAssemblyName == header.FpModel + header.CbModel);
                        }
                        else
                        {
                            Contracts.CheckDecode(header.FpAssemblyName == header.FpStringChars + header.CbStringChars);
                        }
                        Contracts.CheckDecode(header.CbAssemblyName % sizeof(char) == 0);
                        Contracts.CheckDecode(header.FpTail == header.FpAssemblyName + header.CbAssemblyName);
                    }
                }

                Contracts.CheckDecode(header.FpLim == header.FpTail + sizeof(ulong));
                Contracts.CheckDecode(size == 0 || size >= header.FpLim);

                ex = null;
                return(true);
            }
            catch (Exception e)
            {
                ex = e;
                return(false);
            }
        }
예제 #2
0
        /// <summary>
        /// Checks the validity of the header, reads the string table, etc.
        /// </summary>
        public static bool TryValidate(ref ModelHeader header, BinaryReader reader, long fpMin, out string[] strings, out string loaderAssemblyName, out Exception ex)
        {
            Contracts.CheckValue(reader, nameof(reader));
            Contracts.Check(fpMin >= 0);

            if (!TryValidate(ref header, reader.BaseStream.Length - fpMin, out ex))
            {
                strings            = null;
                loaderAssemblyName = null;
                return(false);
            }

            try
            {
                long fpOrig = reader.FpCur();

                StringBuilder sb = null;
                if (header.FpStringTable == 0)
                {
                    // No strings.
                    strings = null;

                    if (header.VerWritten < VerAssemblyNameSupported)
                    {
                        // Before VerAssemblyNameSupported, if there were no strings in the model,
                        // validation ended here. Specifically the FpTail checks below were skipped.
                        // There are earlier versions of models that don't have strings, and 'reader' is
                        // not at FpTail at this point.
                        // Preserve the previous behavior by returning early here.
                        loaderAssemblyName = null;
                        ex = null;
                        return(true);
                    }
                }
                else
                {
                    reader.Seek(header.FpStringTable + fpMin);
                    Contracts.Assert(reader.FpCur() == header.FpStringTable + fpMin);

                    long cstr = header.CbStringTable / sizeof(long);
                    Contracts.Assert(cstr < int.MaxValue);
                    long[] offsets = reader.ReadLongArray((int)cstr);
                    Contracts.Assert(header.FpStringChars == reader.FpCur() - fpMin);
                    Contracts.CheckDecode(offsets[cstr - 1] == header.CbStringChars);

                    strings = new string[cstr];
                    long offset = 0;
                    sb = new StringBuilder();
                    for (int i = 0; i < offsets.Length; i++)
                    {
                        Contracts.CheckDecode(header.FpStringChars + offset == reader.FpCur() - fpMin);

                        long offsetPrev = offset;
                        offset = offsets[i];
                        Contracts.CheckDecode(offsetPrev <= offset & offset <= header.CbStringChars);
                        Contracts.CheckDecode(offset % sizeof(char) == 0);
                        long cch = (offset - offsetPrev) / sizeof(char);
                        Contracts.CheckDecode(cch < int.MaxValue);

                        sb.Clear();
                        for (long ich = 0; ich < cch; ich++)
                        {
                            sb.Append((char)reader.ReadUInt16());
                        }
                        strings[i] = sb.ToString();
                    }
                    Contracts.CheckDecode(offset == header.CbStringChars);
                    Contracts.CheckDecode(header.FpStringChars + header.CbStringChars == reader.FpCur() - fpMin);
                }

                if (header.VerWritten >= VerAssemblyNameSupported && header.FpAssemblyName != 0)
                {
                    reader.Seek(header.FpAssemblyName + fpMin);
                    int assemblyNameLength = (int)header.CbAssemblyName / sizeof(char);

                    sb = sb != null?sb.Clear() : new StringBuilder(assemblyNameLength);

                    for (long ich = 0; ich < assemblyNameLength; ich++)
                    {
                        sb.Append((char)reader.ReadUInt16());
                    }

                    loaderAssemblyName = sb.ToString();
                }
                else
                {
                    loaderAssemblyName = null;
                }

                Contracts.CheckDecode(header.FpTail == reader.FpCur() - fpMin);

                ulong tail = reader.ReadUInt64();
                Contracts.CheckDecode(tail == TailSignatureValue, "Corrupt model file tail");

                ex = null;

                reader.Seek(fpOrig);
                return(true);
            }
            catch (Exception e)
            {
                strings            = null;
                loaderAssemblyName = null;
                ex = e;
                return(false);
            }
        }
        protected LoadableClassAttributeBase(string summary, Type instType, Type loaderType, Type argType, Type[] sigTypes, string userName, params string[] loadNames)
        {
            Contracts.CheckValueOrNull(summary);
            Contracts.CheckValue(instType, nameof(instType));
            Contracts.CheckValue(loaderType, nameof(loaderType));
            Contracts.CheckNonEmpty(sigTypes, nameof(sigTypes));

            if (Utils.Size(loadNames) == 0)
            {
                loadNames = new string[] { userName }
            }
            ;

            if (loadNames.Any(s => string.IsNullOrWhiteSpace(s)))
            {
                throw Contracts.ExceptEmpty(nameof(loadNames), "LoadableClass loadName parameter can't be empty");
            }

            var sigType = sigTypes[0];

            Contracts.CheckValue(sigType, nameof(sigTypes));
            Type[] types;
            Contracts.CheckParam(sigType.BaseType == typeof(System.MulticastDelegate), nameof(sigTypes), "LoadableClass signature type must be a delegate type");

            var meth = sigType.GetMethod("Invoke");

            Contracts.CheckParam(meth != null, nameof(sigTypes), "LoadableClass signature type must be a delegate type");
            Contracts.CheckParam(meth.ReturnType == typeof(void), nameof(sigTypes), "LoadableClass signature type must be a delegate type with void return");

            var parms     = meth.GetParameters();
            int itypeBase = 0;

            if (argType != null)
            {
                types = new Type[1 + parms.Length];
                types[itypeBase++] = argType;
            }
            else if (parms.Length > 0)
            {
                types = new Type[parms.Length];
            }
            else
            {
                types = Type.EmptyTypes;
            }

            for (int itype = 0; itype < parms.Length; itype++)
            {
                var parm = parms[itype];
                if ((parm.Attributes & (ParameterAttributes.Out | ParameterAttributes.Retval)) != 0)
                {
                    throw Contracts.Except("Invalid signature parameter attributes");
                }
                types[itypeBase + itype] = parm.ParameterType;
            }

            for (int i = 1; i < sigTypes.Length; i++)
            {
                sigType = sigTypes[i];
                Contracts.CheckValue(sigType, nameof(sigTypes));

                Contracts.Check(sigType.BaseType == typeof(System.MulticastDelegate), "LoadableClass signature type must be a delegate type");

                meth = sigType.GetMethod("Invoke");
                Contracts.CheckParam(meth != null, nameof(sigTypes), "LoadableClass signature type must be a delegate type");
                Contracts.CheckParam(meth.ReturnType == typeof(void), nameof(sigTypes), "LoadableClass signature type must be a delegate type with void return");
                parms = meth.GetParameters();
                Contracts.CheckParam(parms.Length + itypeBase == types.Length, nameof(sigTypes), "LoadableClass signatures must have the same number of parameters");
                for (int itype = 0; itype < parms.Length; itype++)
                {
                    var parm = parms[itype];
                    if ((parm.Attributes & (ParameterAttributes.Out | ParameterAttributes.Retval)) != 0)
                    {
                        throw Contracts.ExceptParam(nameof(sigTypes), "Invalid signature parameter attributes");
                    }
                    Contracts.CheckParam(types[itypeBase + itype] == parm.ParameterType, nameof(sigTypes),
                                         "LoadableClass signatures must have the same set of parameters");
                }
            }

            InstanceType = instType;
            LoaderType   = loaderType;
            ArgType      = argType;
            SigTypes     = sigTypes;
            CtorTypes    = types;
            Summary      = summary;
            UserName     = userName;
            LoadNames    = loadNames;
        }
    }