using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.IO; namespace Cosmos.Compiler.Assembler { public class DataMember : BaseAssemblerElement, IComparable { public const string IllegalIdentifierChars = "&.,+$<>{}-`\'/\\ ()[]*!="; public static string GetStaticFieldName( FieldInfo aField ) { return FilterStringForIncorrectChars( "static_field__" + MethodInfoLabelGenerator.GetFullName( aField.DeclaringType ) + "." + aField.Name ); } public static string FilterStringForIncorrectChars( string aName ) { string xTempResult = aName; foreach( char c in IllegalIdentifierChars ) { xTempResult = xTempResult.Replace( c, '_' ); } return String.Intern( xTempResult ); } public DataMember( string aName, Stream aData ) { Name = aName; RawDefaultValue = new byte[ aData.Length ]; aData.Read( RawDefaultValue, 0, RawDefaultValue.Length ); } public bool IsComment { get; set; } public byte[] RawDefaultValue { get; set; } public uint Alignment { get; set; } private object[] UntypedDefaultValue; public DataMember( string aName, params object[] aDefaultValue ) { Name = aName; UntypedDefaultValue = aDefaultValue; } public DataMember( string aName, byte[] aDefaultValue ) { Name = aName; RawDefaultValue = aDefaultValue; //UntypedDefaultValue = aDefaultValue; } public DataMember( string aName, short[] aDefaultValue ) { Name = aName; RawDefaultValue = new byte[ aDefaultValue.Length * 2 ]; for( int i = 0; i < aDefaultValue.Length; i++ ) { Array.Copy( BitConverter.GetBytes( aDefaultValue[ i ] ), 0, RawDefaultValue, i * 2, 2 ); } //UntypedDefaultValue = aDefaultValue; } public DataMember( string aName, params ushort[] aDefaultValue ) { Name = aName; RawDefaultValue = new byte[ aDefaultValue.Length * 2 ]; for( int i = 0; i < aDefaultValue.Length; i++ ) { Array.Copy( BitConverter.GetBytes( aDefaultValue[ i ] ), 0, RawDefaultValue, i * 2, 2 ); } //UntypedDefaultValue = aDefaultValue; } public DataMember( string aName, params uint[] aDefaultValue ) { Name = aName; //RawDefaultValue = new byte[aDefaultValue.Length * 4]; //for (int i = 0; i < aDefaultValue.Length; i++) { // Array.Copy(BitConverter.GetBytes(aDefaultValue[i]), 0, // RawDefaultValue, i * 4, 4); //} UntypedDefaultValue = aDefaultValue.Cast().ToArray(); } public DataMember( string aName, params int[] aDefaultValue ) { Name = aName; //RawDefaultValue = new byte[aDefaultValue.Length * 4]; //for (int i = 0; i < aDefaultValue.Length; i++) { // Array.Copy(BitConverter.GetBytes(aDefaultValue[i]), 0, // RawDefaultValue, i * 4, 4); //} UntypedDefaultValue = aDefaultValue.Cast().ToArray(); } public string Name { get; private set; } public override void WriteText( Assembler aAssembler, TextWriter aOutput ) { if( RawDefaultValue != null ) { if( RawDefaultValue.Length == 0 ) { aOutput.Write( Name ); aOutput.Write( ":" ); return; } if( ( from item in RawDefaultValue group item by item into i select i ).Count() > 1 || RawDefaultValue.Length < 250 ) { if( IsGlobal ) { aOutput.Write( "global " ); aOutput.WriteLine( Name ); } aOutput.Write( Name ); aOutput.Write( " db " ); for( int i = 0; i < ( RawDefaultValue.Length - 1 ); i++ ) { aOutput.Write( RawDefaultValue[ i ] ); aOutput.Write( ", " ); } aOutput.Write( RawDefaultValue.Last() ); } else { //aOutputWriter.WriteLine("TIMES 0x50000 db 0"); aOutput.Write( "global " ); aOutput.WriteLine( Name ); aOutput.Write( Name ); aOutput.Write( ": TIMES " ); aOutput.Write( RawDefaultValue.Length ); aOutput.Write( " db " ); aOutput.Write( RawDefaultValue[ 0 ] ); } return; } if( UntypedDefaultValue != null ) { StringBuilder xSB = new StringBuilder(); if( IsGlobal ) { aOutput.Write( "global " ); aOutput.WriteLine( Name ); } aOutput.Write( Name ); aOutput.Write( " dd " ); Func xGetTextForItem = delegate( object aItem ) { var xElementRef = aItem as ElementReference; if( xElementRef == null ) { return ( aItem ?? 0 ).ToString(); } else { if( xElementRef.Offset == 0 ) { return xElementRef.Name; } return xElementRef.Name + " + " + xElementRef.Offset; } }; for( int i = 0; i < ( UntypedDefaultValue.Length - 1 ); i++ ) { aOutput.Write( xGetTextForItem( UntypedDefaultValue[ i ] ) ); aOutput.Write( ", " ); } aOutput.Write( xGetTextForItem( UntypedDefaultValue.Last() ) ); return; } throw new Exception( "Situation unsupported!" ); } public int CompareTo( DataMember other ) { return String.Compare( Name, other.Name ); } public bool IsGlobal { get; set; } public override ulong? ActualAddress { get { // TODO: for now, we dont have any data alignment return StartAddress; } } public override void UpdateAddress( Assembler aAssembler, ref ulong xAddress ) { if( Alignment > 0 ) { if( xAddress % Alignment != 0 ) { xAddress += Alignment - ( xAddress % Alignment ); } } base.UpdateAddress( aAssembler, ref xAddress ); if( RawDefaultValue != null ) { xAddress += ( ulong )RawDefaultValue.LongLength; } if( UntypedDefaultValue != null ) { // TODO: what to do with 64bit target platforms? right now we only support 32bit xAddress += ( ulong )( UntypedDefaultValue.LongLength * 4 ); } } public override bool IsComplete( Assembler aAssembler ) { if( UntypedDefaultValue != null && UntypedDefaultValue.LongLength > 0 ) { foreach( var xReference in ( from item in UntypedDefaultValue let xRef = item as ElementReference where xRef != null select xRef ) ) { var xRef = aAssembler.TryResolveReference( xReference ); if( xRef == null ) { return false; } else if( !xRef.IsComplete( aAssembler ) ) { return false; } } } return true; } public override byte[] GetData( Assembler aAssembler ) { if( UntypedDefaultValue != null && UntypedDefaultValue.LongLength > 0 ) { var xBuff = ( byte[] )Array.CreateInstance( typeof( byte ), UntypedDefaultValue.LongLength * 4 ); for( int i = 0; i < UntypedDefaultValue.Length; i++ ) { var xRef = UntypedDefaultValue[ i ] as ElementReference; byte[] xTemp; if( xRef != null ) { var xTheRef = aAssembler.TryResolveReference( xRef ); if( xTheRef == null ) { throw new Exception( "Reference not found!" ); } if( !xTheRef.ActualAddress.HasValue ) { Console.Write( "" ); } xTemp = BitConverter.GetBytes( xTheRef.ActualAddress.Value ); } else { if( UntypedDefaultValue[ i ] is int ) { xTemp = BitConverter.GetBytes( ( int )UntypedDefaultValue[ i ] ); } else { if( UntypedDefaultValue[ i ] is uint ) { xTemp = BitConverter.GetBytes( ( uint )UntypedDefaultValue[ i ] ); } else { throw new Exception( "Invalid value inside UntypedDefaultValue" ); } } } Array.Copy( xTemp, 0, xBuff, i * 4, 4 ); } return xBuff; } return RawDefaultValue; } public override void WriteData( Assembler aAssembler, Stream aOutput ) { if( UntypedDefaultValue != null && UntypedDefaultValue.LongLength > 0 ) { //var xBuff = (byte[])Array.CreateInstance(typeof(byte), UntypedDefaultValue.LongLength * 4); for( int i = 0; i < UntypedDefaultValue.Length; i++ ) { var xRef = UntypedDefaultValue[ i ] as ElementReference; //byte[] xTemp; if( xRef != null ) { var xTheRef = aAssembler.TryResolveReference( xRef ); if( xTheRef == null ) { throw new Exception( "Reference not found!" ); } if( !xTheRef.ActualAddress.HasValue ) { Console.Write( "" ); } aOutput.Write( BitConverter.GetBytes( xTheRef.ActualAddress.Value ), 0, 4 ); //xTemp = BitConverter.GetBytes(); } else { if( UntypedDefaultValue[ i ] is int ) { aOutput.Write( BitConverter.GetBytes( ( int )UntypedDefaultValue[ i ] ), 0, 4 ); //xTemp = BitConverter.GetBytes((int)UntypedDefaultValue[i]); } else { if( UntypedDefaultValue[ i ] is uint ) { aOutput.Write( BitConverter.GetBytes( ( uint )UntypedDefaultValue[ i ] ), 0, 4 ); //xTemp = BitConverter.GetBytes((uint)UntypedDefaultValue[i]); } else { throw new Exception( "Invalid value inside UntypedDefaultValue" ); } } } //Array.Copy(xTemp, 0, xBuff, i * 4, 4); } } else { aOutput.Write( RawDefaultValue, 0, RawDefaultValue.Length ); } } } }