2009-04-19 18:07:22 +00:00
#region = = = = = = = = = = = = = = = = = = Copyright ( c ) 2007 Pascal vd Heiden
/ *
* Copyright ( c ) 2007 Pascal vd Heiden , www . codeimp . com
* This program is released under GNU General Public License
*
* This program 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 .
*
* /
#endregion
#region = = = = = = = = = = = = = = = = = = Namespaces
2014-02-26 14:11:06 +00:00
using System ;
2009-04-19 18:07:22 +00:00
using System.Collections.Generic ;
using System.IO ;
#endregion
namespace CodeImp.DoomBuilder.ZDoom
{
public sealed class DecorateParser : ZDTextParser
{
#region = = = = = = = = = = = = = = = = = = Delegates
public delegate void IncludeDelegate ( DecorateParser parser , string includefile ) ;
public IncludeDelegate OnInclude ;
#endregion
#region = = = = = = = = = = = = = = = = = = Constants
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
// These are actors we want to keep
private Dictionary < string , ActorStructure > actors ;
// These are all parsed actors, also those from other games
private Dictionary < string , ActorStructure > archivedactors ;
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
2009-08-15 08:41:43 +00:00
/// <summary>
/// All actors that are supported by the current game.
/// </summary>
2009-04-19 18:07:22 +00:00
public ICollection < ActorStructure > Actors { get { return actors . Values ; } }
2009-08-15 08:41:43 +00:00
/// <summary>
/// All actors defined in the loaded DECORATE structures. This includes actors not supported in the current game.
/// </summary>
public ICollection < ActorStructure > AllActors { get { return archivedactors . Values ; } }
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Disposer
// Constructor
public DecorateParser ( )
{
// Syntax
2013-09-11 09:47:53 +00:00
whitespace = "\n \t\r\u00A0" ; //mxd. non-breaking space is also space :)
2009-08-15 08:41:43 +00:00
specialtokens = ":{}+-\n;," ;
2009-04-19 18:07:22 +00:00
// Initialize
2014-02-26 14:11:06 +00:00
actors = new Dictionary < string , ActorStructure > ( StringComparer . Ordinal ) ;
archivedactors = new Dictionary < string , ActorStructure > ( StringComparer . Ordinal ) ;
2009-04-19 18:07:22 +00:00
}
2010-08-19 15:06:15 +00:00
// Disposer
public void Dispose ( )
{
foreach ( KeyValuePair < string , ActorStructure > a in archivedactors )
a . Value . Dispose ( ) ;
actors = null ;
archivedactors = null ;
}
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Parsing
// This parses the given decorate stream
// Returns false on errors
2014-10-23 12:48:31 +00:00
public override bool Parse ( Stream stream , string sourcefilename , bool clearerrors )
2009-04-19 18:07:22 +00:00
{
2014-10-23 12:48:31 +00:00
base . Parse ( stream , sourcefilename , clearerrors ) ;
2009-04-19 18:07:22 +00:00
// Keep local data
Stream localstream = datastream ;
string localsourcename = sourcename ;
BinaryReader localreader = datareader ;
// Continue until at the end of the stream
while ( SkipWhitespace ( true ) )
{
// Read a token
string objdeclaration = ReadToken ( ) ;
if ( objdeclaration ! = null )
{
objdeclaration = objdeclaration . ToLowerInvariant ( ) ;
if ( objdeclaration = = "actor" )
{
// Read actor structure
ActorStructure actor = new ActorStructure ( this ) ;
if ( this . HasError ) break ;
// Add the actor
archivedactors [ actor . ClassName . ToLowerInvariant ( ) ] = actor ;
if ( actor . CheckActorSupported ( ) )
actors [ actor . ClassName . ToLowerInvariant ( ) ] = actor ;
// Replace an actor?
if ( actor . ReplacesClass ! = null )
{
if ( GetArchivedActorByName ( actor . ReplacesClass ) ! = null )
archivedactors [ actor . ReplacesClass . ToLowerInvariant ( ) ] = actor ;
else
General . ErrorLogger . Add ( ErrorType . Warning , "Unable to find the DECORATE class '" + actor . ReplacesClass + "' to replace, while parsing '" + actor . ClassName + "'" ) ;
if ( actor . CheckActorSupported ( ) )
{
if ( GetActorByName ( actor . ReplacesClass ) ! = null )
actors [ actor . ReplacesClass . ToLowerInvariant ( ) ] = actor ;
}
}
}
else if ( objdeclaration = = "#include" )
{
// Include a file
SkipWhitespace ( true ) ;
string filename = ReadToken ( ) ;
if ( ! string . IsNullOrEmpty ( filename ) )
{
// Strip the quotes
filename = filename . Replace ( "\"" , "" ) ;
// Callback to parse this file now
if ( OnInclude ! = null ) OnInclude ( this , filename ) ;
// Set our buffers back to continue parsing
datastream = localstream ;
datareader = localreader ;
sourcename = localsourcename ;
if ( HasError ) break ;
}
else
{
ReportError ( "Expected file name to include" ) ;
break ;
}
}
else if ( ( objdeclaration = = "const" ) | | ( objdeclaration = = "native" ) )
{
// We don't need this, ignore up to the first next ;
while ( SkipWhitespace ( true ) )
{
string t = ReadToken ( ) ;
if ( ( t = = ";" ) | | ( t = = null ) ) break ;
}
}
2015-03-05 08:51:12 +00:00
else if ( objdeclaration = = "$gzdb_skip" ) //mxd
{
break ;
}
2009-04-19 18:07:22 +00:00
else
{
// Unknown structure!
// Best we can do now is just find the first { and then
// follow the scopes until the matching } is found
string token2 ;
do
{
if ( ! SkipWhitespace ( true ) ) break ;
token2 = ReadToken ( ) ;
if ( token2 = = null ) break ;
}
while ( token2 ! = "{" ) ;
int scopelevel = 1 ;
do
{
if ( ! SkipWhitespace ( true ) ) break ;
token2 = ReadToken ( ) ;
if ( token2 = = null ) break ;
if ( token2 = = "{" ) scopelevel + + ;
if ( token2 = = "}" ) scopelevel - - ;
}
while ( scopelevel > 0 ) ;
}
}
}
// Return true when no errors occurred
return ( ErrorDescription = = null ) ;
}
#endregion
#region = = = = = = = = = = = = = = = = = = Methods
2009-08-15 08:41:43 +00:00
/// <summary>
/// This returns a supported actor by name. Returns null when no supported actor with the specified name can be found. This operation is of O(1) complexity.
/// </summary>
2009-04-19 18:07:22 +00:00
public ActorStructure GetActorByName ( string name )
{
name = name . ToLowerInvariant ( ) ;
if ( actors . ContainsKey ( name ) )
return actors [ name ] ;
else
return null ;
}
2009-08-15 08:41:43 +00:00
/// <summary>
/// This returns a supported actor by DoomEdNum. Returns null when no supported actor with the specified name can be found. Please note that this operation is of O(n) complexity!
/// </summary>
public ActorStructure GetActorByDoomEdNum ( int doomednum )
{
ICollection < ActorStructure > collection = actors . Values ;
foreach ( ActorStructure a in collection )
{
if ( a . DoomEdNum = = doomednum )
return a ;
}
return null ;
}
2009-04-19 18:07:22 +00:00
// This returns an actor by name
// Returns null when actor cannot be found
internal ActorStructure GetArchivedActorByName ( string name )
{
name = name . ToLowerInvariant ( ) ;
2015-03-17 12:28:42 +00:00
return ( archivedactors . ContainsKey ( name ) ? archivedactors [ name ] : null ) ;
2009-04-19 18:07:22 +00:00
}
#endregion
}
}