2012-08-29 19:02:13 +00:00
#region Using Statements
using System ;
using System.Collections.Generic ;
2012-10-18 11:11:59 +00:00
using System.ComponentModel ;
2012-08-29 19:02:13 +00:00
using System.IO ;
using System.Text ;
2015-04-08 14:50:03 +02:00
using System.Linq ;
2012-08-29 19:02:13 +00:00
using System.Xml ;
using ANX.Framework.NonXNA.Development ;
2015-04-08 14:50:03 +02:00
using System.Runtime.Versioning ;
using ANX.Framework.Content.Pipeline.Tasks.References ;
using ANX.Framework.Graphics ;
2012-08-29 19:02:13 +00:00
#endregion
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license
namespace ANX.Framework.Content.Pipeline.Tasks
{
2012-08-30 22:02:16 +00:00
//comment by author: if you find any mistakes in my language, go fix them ;-)
2015-04-08 14:50:03 +02:00
[Serializable]
2012-08-29 19:02:13 +00:00
public class ContentProject
{
2015-04-08 14:50:03 +02:00
public const string XmlNamespace = "https://anxframework.codeplex.com/AnxContentProject.xsd" ;
2012-08-29 19:02:13 +00:00
#region Properties
/// <summary>
/// Name of the Content Project
/// </summary>
public String Name { get ; set ; }
/// <summary>
/// Major version of the project format
/// </summary>
2012-10-18 11:11:59 +00:00
[Browsable(false)]
2015-04-08 14:50:03 +02:00
public int VersionMajor { get { return 1 ; } }
2012-08-29 19:02:13 +00:00
/// <summary>
/// Minor version of the project format.
/// Used to keep backwards compatibility
/// </summary>
2012-10-18 11:11:59 +00:00
[Browsable(false)]
2015-04-08 14:50:03 +02:00
public int VersionMinor { get { return 3 ; } } //before you commit your changes, please increase this value by one (and if you added stuff, please check the version before you read anything out of a file).
//And update the project template files, if necessary.
2012-08-29 19:02:13 +00:00
/// <summary>
/// A list containing all build items of this project
/// </summary>
public List < BuildItem > BuildItems { get ; private set ; }
2012-08-30 22:02:16 +00:00
/// <summary>
2015-04-08 14:50:03 +02:00
/// A list containing all configurations of this project.
2012-08-30 22:02:16 +00:00
/// </summary>
2015-04-08 14:50:03 +02:00
public ConfigurationCollection Configurations { get ; private set ; }
2012-08-30 22:02:16 +00:00
2012-08-29 19:02:13 +00:00
/// <summary>
/// List which holds Assemblies that contain custom importers/processors
/// </summary>
2015-04-08 14:50:03 +02:00
public List < Reference > References { get ; private set ; }
2012-08-29 19:02:13 +00:00
/// <summary>
/// Name of the tool that generated the resulting file. Might be useful for tracking down
/// bugs in that particular application.
/// </summary>
public String Creator { get ; set ; }
#endregion
/// <summary>
/// Initializes a new instance of a <see cref="ContentProject"/>
/// </summary>
/// <param name="name">Name of the project</param>
public ContentProject ( String name )
{
Name = name ;
2015-04-08 14:50:03 +02:00
Configurations = new ConfigurationCollection ( ) ;
2012-08-29 19:02:13 +00:00
BuildItems = new List < BuildItem > ( ) ;
2015-04-08 14:50:03 +02:00
References = new List < Reference > ( ) ;
2012-08-29 19:02:13 +00:00
}
#region Save
/// <summary>
/// Saves the project into a file. Should be a .cproj extension.
/// </summary>
/// <param name="path">The path to save the project</param>
public void Save ( string path )
{
2012-10-27 06:47:35 +00:00
//TODO: check file extension and throw exception when wrong (or silently change it?)
2012-08-29 19:02:13 +00:00
if ( ! Directory . Exists ( Path . GetDirectoryName ( path ) ) )
Directory . CreateDirectory ( Path . GetDirectoryName ( path ) ) ;
2015-04-08 14:50:03 +02:00
//Write only in memory first, to make sure we don't lose the file if something went wrong while saving.
using ( var stream = new MemoryStream ( ) )
2012-08-29 19:02:13 +00:00
{
2015-04-08 14:50:03 +02:00
XmlWriter writer = XmlTextWriter . Create ( stream , new XmlWriterSettings ( ) { Encoding = Encoding . UTF8 , Indent = true , NewLineHandling = NewLineHandling . Entitize , CloseOutput = false } ) ;
writer . WriteStartDocument ( ) ;
// <ContentProject Version="4.0">
writer . WriteStartElement ( "ContentProject" , XmlNamespace ) ;
writer . WriteStartAttribute ( "Version" ) ;
writer . WriteValue ( VersionMajor + "." + VersionMinor ) ;
2012-08-29 19:02:13 +00:00
writer . WriteEndAttribute ( ) ;
2015-04-08 14:50:03 +02:00
writer . WriteStartAttribute ( "Creator" ) ;
writer . WriteValue ( Creator ) ;
2012-08-29 19:02:13 +00:00
writer . WriteEndAttribute ( ) ;
2015-04-08 14:50:03 +02:00
//<ProjectName>Name</ProjectName>
writer . WriteStartElement ( "ProjectName" ) ;
writer . WriteValue ( Name ) ;
2012-08-29 19:02:13 +00:00
writer . WriteEndElement ( ) ;
2015-04-08 14:50:03 +02:00
writer . WriteStartElement ( "Configurations" ) ;
foreach ( var config in Configurations )
2012-08-29 19:02:13 +00:00
{
2015-04-08 14:50:03 +02:00
//<Configuration Name="Debug" Platform="Windows">
writer . WriteStartElement ( "Configuration" ) ;
2012-08-29 19:02:13 +00:00
writer . WriteStartAttribute ( "Name" ) ;
2015-04-08 14:50:03 +02:00
writer . WriteString ( config . Name ) ;
2012-08-29 19:02:13 +00:00
writer . WriteEndAttribute ( ) ;
2015-04-08 14:50:03 +02:00
writer . WriteStartAttribute ( "Platform" ) ;
writer . WriteValue ( config . Platform . ToString ( ) ) ;
writer . WriteEndAttribute ( ) ;
//<Profile>Reach</Profile>
writer . WriteStartElement ( "Profile" ) ;
writer . WriteValue ( config . Profile . ToString ( ) ) ;
writer . WriteEndElement ( ) ;
//<OutputPath>A:\Somewhere</OutputPath>
writer . WriteStartElement ( "OutputPath" ) ;
writer . WriteValue ( config . OutputDirectory ) ;
writer . WriteEndElement ( ) ;
//<CompressContent>False</CompressContent>
writer . WriteStartElement ( "CompressContent" ) ;
writer . WriteValue ( config . CompressContent ) ;
writer . WriteEndElement ( ) ;
2012-08-29 19:02:13 +00:00
writer . WriteEndElement ( ) ;
}
writer . WriteEndElement ( ) ;
2015-04-08 14:50:03 +02:00
//<References IncludeDir="B:\Pipeline">
// <Reference>ANX.Framework.Content.Pipeline.SomewhatImporter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=blah, ProcessorArch=MSIL</Reference>
//</References>
writer . WriteStartElement ( "References" ) ;
foreach ( var reference in References )
{
if ( reference is GACReference )
writer . WriteStartElement ( "AssemblyCacheReference" ) ;
else if ( reference is AssemblyReference )
writer . WriteStartElement ( "AssemblyReference" ) ;
else if ( reference is ProjectReference )
writer . WriteStartElement ( "ProjectReference" ) ;
reference . Write ( writer ) ;
writer . WriteEndElement ( ) ;
}
2012-09-01 16:30:35 +00:00
writer . WriteEndElement ( ) ;
2012-08-29 19:02:13 +00:00
2015-04-08 14:50:03 +02:00
//<BuildItems>
// <BuildItem AssetName="Content/MyPicture" OutputFilename="Content/MyPicture.xnb" Importer="TextureImporter" Processor="TextureProcessor">
// <SourceFile>A:\MyPicture.png</SourceFile>
// <ProcessorParams>
// <Parameter Name="DoThis">True</Parameter>
// <ProcessorParams>
// </BuildItem>
//</BuildItems>
writer . WriteStartElement ( "BuildItems" ) ;
foreach ( var buildItem in BuildItems )
{
writer . WriteStartElement ( "BuildItem" ) ;
writer . WriteStartAttribute ( "AssetName" ) ;
writer . WriteValue ( buildItem . AssetName ) ;
writer . WriteEndAttribute ( ) ;
writer . WriteStartAttribute ( "Importer" ) ;
writer . WriteValue ( buildItem . ImporterName ) ;
writer . WriteEndAttribute ( ) ;
writer . WriteStartAttribute ( "Processor" ) ;
writer . WriteValue ( buildItem . ProcessorName ) ;
writer . WriteEndAttribute ( ) ;
writer . WriteStartElement ( "SourceFile" ) ;
writer . WriteValue ( buildItem . SourceFilename ) ;
writer . WriteEndElement ( ) ;
writer . WriteStartElement ( "ProcessorParams" ) ;
foreach ( var pair in buildItem . ProcessorParameters )
{
writer . WriteStartElement ( "Parameter" ) ;
writer . WriteStartAttribute ( "Name" ) ;
writer . WriteValue ( pair . Key ) ;
writer . WriteEndAttribute ( ) ;
2015-11-04 23:38:46 +01:00
writer . WriteValue ( TypeDescriptor . GetConverter ( pair . Value ) . ConvertToInvariantString ( pair . Value ) ) ;
2015-04-08 14:50:03 +02:00
writer . WriteEndElement ( ) ;
}
writer . WriteEndElement ( ) ;
writer . WriteEndElement ( ) ;
}
writer . WriteEndElement ( ) ;
writer . Flush ( ) ;
writer . Close ( ) ;
using ( FileStream file = new FileStream ( path , FileMode . OpenOrCreate ) )
{
file . Position = 0 ;
file . SetLength ( 0 ) ;
stream . WriteTo ( file ) ;
file . Flush ( ) ;
}
}
2012-08-29 19:02:13 +00:00
}
#endregion
#region Load
public static ContentProject Load ( string path )
{
2012-08-30 22:02:16 +00:00
if ( ! File . Exists ( path ) )
throw new FileNotFoundException ( "The content project you tried to load does not exist: " , path ) ;
2015-04-08 14:50:03 +02:00
BuildItem lastBuildItem = null ;
2012-08-30 22:02:16 +00:00
var reader = XmlTextReader . Create ( path ) ;
ContentProject project = null ;
String creator = null ;
2015-04-08 14:50:03 +02:00
Configuration currentConfig = new Configuration ( "Debug" , TargetPlatform . Windows ) ;
2012-08-30 22:02:16 +00:00
int versionMajor = 0 ;
int versionMinor = 0 ;
while ( ! reader . EOF )
{
var readerName = reader . Name ;
switch ( readerName )
{
case "ProjectName" :
project = new ContentProject ( reader . ReadElementContentAsString ( ) ) ;
break ;
case "ContentProject" :
reader . MoveToAttribute ( "Version" ) ;
if ( reader . NodeType = = XmlNodeType . Attribute )
{
versionMajor = Convert . ToInt32 ( reader . ReadContentAsString ( ) . Split ( '.' ) [ 0 ] ) ;
versionMinor = Convert . ToInt32 ( reader . ReadContentAsString ( ) . Split ( '.' ) [ 1 ] ) ;
}
break ;
case "Creator" :
if ( reader . NodeType = = XmlNodeType . Attribute )
creator = reader . ReadContentAsString ( ) ;
break ;
2015-04-08 14:50:03 +02:00
//<Configurations>
2012-08-30 22:02:16 +00:00
case "Configuration" :
if ( reader . NodeType = = XmlNodeType . Element )
2015-04-08 14:50:03 +02:00
if ( versionMajor = = 1 )
2012-09-09 15:44:49 +00:00
{
2015-04-08 14:50:03 +02:00
string name ;
string platform ;
if ( versionMinor < 3 )
2012-09-09 15:44:49 +00:00
{
2015-04-08 14:50:03 +02:00
name = reader . ReadElementContentAsString ( ) ;
platform = "Windows" ; //With the current struct, we just can't load the platform the old way because Configuration is written before Platform.
2012-09-09 15:44:49 +00:00
}
2015-04-08 14:50:03 +02:00
else
{
name = reader . GetAttribute ( "Name" ) ;
platform = reader . GetAttribute ( "Platform" ) ;
}
if ( ! currentConfig . IsEmpty )
{
project . Configurations . Add ( currentConfig ) ;
}
currentConfig = new Configuration ( name , ( TargetPlatform ) Enum . Parse ( typeof ( TargetPlatform ) , platform , true ) ) ;
2012-09-09 15:44:49 +00:00
}
break ;
2015-04-08 14:50:03 +02:00
case "Profile" :
2012-08-30 22:02:16 +00:00
if ( reader . NodeType = = XmlNodeType . Element )
{
2015-04-08 14:50:03 +02:00
if ( versionMinor < 2 )
currentConfig . Profile = GraphicsProfile . Reach ;
else
2012-08-30 22:02:16 +00:00
{
2015-04-08 14:50:03 +02:00
string text = reader . ReadElementContentAsString ( ) ;
if ( ! string . IsNullOrWhiteSpace ( text ) )
2012-08-30 22:02:16 +00:00
{
2015-04-08 14:50:03 +02:00
currentConfig . Profile = ( GraphicsProfile ) Enum . Parse ( typeof ( GraphicsProfile ) , text , true ) ;
2012-08-30 22:02:16 +00:00
}
2013-02-09 12:01:51 +00:00
else
2015-04-08 14:50:03 +02:00
currentConfig . Profile = GraphicsProfile . HiDef ;
2012-08-30 22:02:16 +00:00
}
}
break ;
case "OutputPath" :
if ( reader . NodeType = = XmlNodeType . Element )
if ( versionMajor = = 1 & & versionMinor > = 0 )
2015-04-08 14:50:03 +02:00
currentConfig . OutputDirectory = reader . ReadElementContentAsString ( ) ;
2012-08-30 22:02:16 +00:00
break ;
2015-04-08 14:50:03 +02:00
case "CompressContent" :
2012-08-30 22:02:16 +00:00
if ( reader . NodeType = = XmlNodeType . Element )
2015-04-08 14:50:03 +02:00
if ( versionMajor = = 1 & & versionMinor > = 3 )
currentConfig . CompressContent = reader . ReadElementContentAsBoolean ( ) ;
2012-08-30 22:02:16 +00:00
break ;
2015-04-08 14:50:03 +02:00
//</Configurations>
//<References>
case "Reference" :
2012-08-30 22:02:16 +00:00
if ( reader . NodeType = = XmlNodeType . Element )
2015-04-08 14:50:03 +02:00
if ( versionMajor = = 1 )
{
//From version 1.3 onwards, references are divided into different types depending on the element name.
if ( versionMinor < 3 )
{
project . References . Add ( new AssemblyReference ( ) { AssemblyPath = reader . ReadElementContentAsString ( ) } ) ;
}
}
2012-08-30 22:02:16 +00:00
break ;
2015-04-08 14:50:03 +02:00
case "AssemblyReference" :
if ( reader . NodeType = = XmlNodeType . Element )
if ( versionMajor = = 1 & & versionMinor > = 3 )
{
Reference reference = new AssemblyReference ( ) ;
reference . Load ( reader ) ;
project . References . Add ( reference ) ;
}
2012-08-30 22:02:16 +00:00
break ;
2015-04-08 14:50:03 +02:00
case "ProjectReference" :
2012-08-30 22:02:16 +00:00
if ( reader . NodeType = = XmlNodeType . Element )
2015-04-08 14:50:03 +02:00
if ( versionMajor = = 1 & & versionMinor > = 3 )
{
Reference reference = new ProjectReference ( ) ;
reference . Load ( reader ) ;
project . References . Add ( reference ) ;
}
2012-08-30 22:02:16 +00:00
break ;
2015-04-08 14:50:03 +02:00
case "AssemblyCacheReference" :
if ( reader . NodeType = = XmlNodeType . Element )
if ( versionMajor = = 1 & & versionMinor > = 3 )
{
Reference reference = new GACReference ( ) ;
reference . Load ( reader ) ;
project . References . Add ( reference ) ;
}
break ;
//</References>
2012-08-30 22:02:16 +00:00
case "BuildItem" :
if ( versionMajor = = 1 & & versionMinor > = 0 )
{
2012-09-01 16:30:35 +00:00
if ( reader . NodeType ! = XmlNodeType . Element )
break ;
2012-08-30 22:02:16 +00:00
var buildItem = new BuildItem ( ) ;
lastBuildItem = buildItem ;
2012-09-01 16:30:35 +00:00
reader . MoveToFirstAttribute ( ) ;
while ( reader . NodeType = = XmlNodeType . Attribute )
2012-08-30 22:02:16 +00:00
{
switch ( reader . Name )
{
case "AssetName" :
buildItem . AssetName = reader . ReadContentAsString ( ) ;
2012-09-01 16:30:35 +00:00
reader . MoveToNextAttribute ( ) ;
2012-08-30 22:02:16 +00:00
break ;
case "Importer" :
buildItem . ImporterName = reader . ReadContentAsString ( ) ;
2012-09-01 16:30:35 +00:00
reader . MoveToNextAttribute ( ) ;
2012-08-30 22:02:16 +00:00
break ;
case "Processor" :
buildItem . ProcessorName = reader . ReadContentAsString ( ) ;
2012-09-01 16:30:35 +00:00
if ( buildItem . AssetName = = null )
reader . MoveToNextAttribute ( ) ;
else
reader . Read ( ) ;
break ;
2015-04-08 14:50:03 +02:00
default :
2012-09-01 16:30:35 +00:00
reader . Read ( ) ;
2012-08-30 22:02:16 +00:00
break ;
}
}
project . BuildItems . Add ( buildItem ) ;
}
break ;
case "SourceFile" :
if ( versionMajor = = 1 & & versionMinor > = 0 )
{
if ( reader . NodeType = = XmlNodeType . Element )
lastBuildItem . SourceFilename = reader . ReadElementContentAsString ( ) ;
}
break ;
2012-10-27 06:47:35 +00:00
case "Parameter" :
2012-08-30 22:02:16 +00:00
if ( versionMajor = = 1 & & versionMinor > = 0 )
{
string key ;
object value ;
reader . MoveToNextAttribute ( ) ;
key = reader . ReadContentAsString ( ) ;
reader . MoveToContent ( ) ;
value = reader . ReadElementContentAsObject ( ) ;
lastBuildItem . ProcessorParameters . Add ( key , value ) ;
}
break ;
}
reader . Read ( ) ;
}
reader . Close ( ) ;
2015-04-08 14:50:03 +02:00
project . Configurations . Add ( currentConfig ) ;
2012-08-29 19:02:13 +00:00
return project ;
}
#endregion
}
}