Manifest.cs 4.2 KB
Newer Older
1 2 3
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
4 5 6 7 8

using System.Collections.Generic;
using System.IO;
using System.Linq;

9
namespace Microsoft.NET.HostModel.Bundle
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
{
    /// <summary>
    ///  BundleManifest is a description of the contents of a bundle file.
    ///  This class handles creation and consumption of bundle-manifests.
    ///  
    ///  Here is the description of the Bundle Layout:
    ///  _______________________________________________
    ///  AppHost 
    ///
    ///
    /// ------------Embedded Files ---------------------
    /// The embedded files including the app, its
    /// configuration files, dependencies, and 
    /// possibly the runtime.
    /// 
    /// 
    /// 
    /// 
    /// 
    /// 
    ///
    /// ------------ Manifest Header -------------
    ///     MajorVersion
    ///     MinorVersion
    ///     NumEmbeddedFiles
35
    ///     ExtractionID
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
    ///     
    /// - - - - - - Manifest Entries - - - - - - - - - - -
    ///     Series of FileEntries (for each embedded file)
    ///     [File Type, Name, Offset, Size information]
    ///     
    ///     
    /// 
    /// - - - - - - Manifest Footer - - - - - - - - - - -
    ///   Manifest header offset
    ///   Bundle Signature
    /// _________________________________________________
    /// </summary>
    public class Manifest
    {
        public const string Signature = ".NetCoreBundle";
        public const uint MajorVersion = 0;
        public const uint MinorVersion = 1;
        public const char DirectorySeparatorChar = '/';

55 56 57 58 59 60
        // Bundle ID is a string that is used to uniquely 
        // identify this bundle. It is choosen to be compatible
        // with path-names so that the AppHost can use it in
        // extraction path.
        string BundleID;

61 62 63 64 65
        public List<FileEntry> Files;

        public Manifest()
        {
            Files = new List<FileEntry>();
66
            BundleID = Path.GetRandomFileName();
67 68
        }

69
        public long Write(BinaryWriter writer)
70 71 72 73 74 75 76
        {
            long startOffset = writer.BaseStream.Position;

            // Write the manifest header
            writer.Write(MajorVersion);
            writer.Write(MinorVersion);
            writer.Write(Files.Count());
77
            writer.Write(BundleID);
78 79 80 81 82 83 84 85 86 87 88

            // Write the manifest entries
            foreach (FileEntry entry in Files)
            {
                entry.Write(writer);
            }

            // Write the manifest footer
            writer.Write(startOffset);
            writer.Write(Signature);

89
            return startOffset;
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
        }

        public static Manifest Read(BinaryReader reader)
        {
            Manifest manifest = new Manifest();

            // Read the manifest footer

            // signatureSize is one byte longer, for the length encoding.
            long signatureSize = Signature.Length + 1;
            reader.BaseStream.Position = reader.BaseStream.Length - signatureSize;
            string signature = reader.ReadString();
            if (!signature.Equals(Signature))
            {
                throw new BundleException("Invalid Bundle");
            }

            // The manifest header offset resides just behind the signature.
            reader.BaseStream.Position = reader.BaseStream.Length - signatureSize - sizeof(long);
            long headerOffset = reader.ReadInt64();

            // Read the manifest header
            reader.BaseStream.Position = headerOffset;
            uint majorVersion = reader.ReadUInt32();
            uint minorVersion = reader.ReadUInt32();
115 116
            int fileCount = reader.ReadInt32();
            manifest.BundleID = reader.ReadString(); // Bundle ID
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133

            if (majorVersion != MajorVersion || minorVersion != MinorVersion)
            {
                throw new BundleException("Extraction failed: Invalid Version");
            }

            // Read the manifest entries
            for (long i = 0; i < fileCount; i++)
            {
                manifest.Files.Add(FileEntry.Read(reader));
            }

            return manifest;
        }
    }
}