context: /**
   * Copyright (c) 2014 James King [metapyziks@gmail.com]
   *
   * This file is part of TorchGame.
   * 
   * TorchGame is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   * 
   * TorchGame is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   * GNU General Public License for more details.
   * 
   * You should have received a copy of the GNU General Public License
   * along with TorchGame. If not, see <http://www.gnu.org/licenses/>.
   */
  
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.IO;
  using System.Security.Cryptography;
  using System.Drawing;
  using System.Reflection;
  
  using ICSharpCode.SharpZipLib.BZip2;
  
  namespace ResourceLib
  {
      public enum ArchiveDest : byte
      {
          Server = 1,
          Client = 2,
          Shared = 3
      }
  
      internal class Archive
      {
          private struct ResourceInfo
          {
              public String FilePath;
              public String CurPath;
              public String FileName;
              public String Extension;
              public RManager Manager;
          }
  
          public const ushort ArchiverVersion = 0x0000;
  
          internal static Archive CreateFromDirectory( String directoryPath )
          {
              if ( directoryPath.EndsWith( "\\" ) || directoryPath.EndsWith( "/" ) )
                  directoryPath = directoryPath.Substring( 0, directoryPath.Length - 1 );
  
              if ( !File.Exists( directoryPath + "\\info.txt" ) )
                  throw new Exception( "info.txt not present!" );
  
              Archive archive = new Archive();
  
              archive.LoadPropertiesFromInfoFile( directoryPath + "\\info.txt" );
  
              foreach ( String str in archive.myReferences )
              {
                  String reference = str.Trim();
  
                  if ( reference.Length == 0 )
                      continue;
  
                  int arch = Res.LoadArchive( reference + ".rsa" );
                  Res.MountArchive( arch );
              }
  
              List<ResourceInfo> resources = new List<ResourceInfo>();
  
              ExploreDirectory( resources, directoryPath, "" );
  
              resources = resources.OrderBy( x => x.Manager.Priority ).ToList();
  
              foreach ( ResourceInfo info in resources )
              {
                  Dictionary<String, Object> dict = archive.myDictionaries[ info.Manager.ValueType ];
  
                  FileStream stream = new FileStream( info.FilePath, FileMode.Open, FileAccess.Read );
                  ResourceItem[] items = info.Manager.LoadFromFile( info.CurPath, info.FileName, info.Extension, stream );
                  stream.Close();
  
                  foreach ( ResourceItem item in items )
                      dict.Add( item.Key, item.Value );
              }
  
              return archive;
          }
  
          private static void ExploreDirectory( List<ResourceInfo> resources, String directoryPath, String curPath )
          {
              foreach ( String file in Directory.EnumerateFiles( directoryPath ) )
              {
                  if ( file.Split( '\\' ).Last().Split( '.' ).Length != 2 )
                      continue;
  
                  string fileName = file.Split( '\\' ).Last().Split( '.' )[ 0 ];
                  string extension = file.Split( '\\' ).Last().Split( '.' )[ 1 ].ToLower();
  
                  if ( curPath == "" && fileName == "info" && extension == "txt" )
                      continue;
  
                  RManager manager = Res.GetManager( extension );
  
                  resources.Add( new ResourceInfo { FilePath = file, CurPath = curPath, FileName = fileName, Extension = extension, Manager = manager } );
              }
  
              foreach ( String dir in Directory.EnumerateDirectories( directoryPath ) )
                  ExploreDirectory( resources, dir, curPath + dir.Split( '\\' ).Last() + "_" );
          }
  
          private String myName;
          private String myVersion;
          private String myAuthor;
          private String myAuthorEmail;
          private String myAuthorWebsite;
          private String myDescription;
          private String myHash;
          private ArchiveDest myDest;
          private String myFilePath;
          private String[] myReferences;
  
          private Dictionary<Type,Dictionary<String,Object>> myDictionaries;
  
          internal String Name
          {
              get
              {
                  return myName;
              }
          }
  
          internal String Version
          {
              get
              {
                  return myVersion;
              }
          }
  
          internal String Author
          {
              get
              {
                  return myAuthor;
              }
          }
  
          internal String AuthorEmail
          {
              get
              {
                  return myAuthorEmail;
              }
          }
  
          internal String AuthorWebsite
          {
              get
              {
                  return myAuthorWebsite;
              }
          }
  
          internal String Description
          {
              get
              {
                  return myDescription;
              }
          }
  
          internal String Hash
          {
              get
              {
                  return myHash;
              }
          }
  
          internal ArchiveDest Destination
          {
              get
              {
                  return myDest;
              }
          }
  
          internal String FilePath
          {
              get
              {
                  return myFilePath;
              }
          }
  
          internal Dictionary<Type, Dictionary<String, Object>> Dictionaries
          {
              get
              {
                  return myDictionaries;
              }
          }
  
          private Archive()
          {
              myDictionaries = new Dictionary<Type, Dictionary<string, object>>();
  
              foreach( RManager manager in Res.Managers )
                  myDictionaries.Add( manager.ValueType, new Dictionary<String, Object>() );
  
              myName = "Untitled";
              myAuthor = "Unknown";
              myAuthorEmail = "None given";
              myAuthorWebsite = "None given";
              myDescription = "None given";
              myVersion = "1.0";
              myDest = ArchiveDest.Shared;
          }
  
          internal Archive( String filePath, bool unpackData = true )
              : this()
          {
              myFilePath = filePath;
  
              ushort archiverVersion;
              byte[] bytes;
              byte[] hash;
  
              using ( FileStream fstr = new FileStream( filePath, FileMode.Open, FileAccess.Read ) )
              {
                  using ( BinaryReader bstr = new BinaryReader( fstr ) )
                  {
                      archiverVersion = bstr.ReadUInt16();
                      myName = bstr.ReadString();
                      myAuthor = bstr.ReadString();
                      myVersion = bstr.ReadString();
                      myAuthorWebsite = bstr.ReadString();
                      myAuthorEmail = bstr.ReadString();
                      myDescription = bstr.ReadString();
                      myDest = (ArchiveDest) bstr.ReadByte();
  
  
gt:                     int len = bstr.ReadInt32();