C#: implemented a compression algorithm for the LZE/Le compression scheme. (although it appears to perform worse than the original compression algorithm, it should still work)

This commit is contained in:
barubary 2011-11-21 23:46:48 +00:00
parent 4302517e58
commit a30a7ac3e3
11 changed files with 412 additions and 37 deletions

View File

@ -7,24 +7,58 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoldenSunDD", "GoldenSunDD\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuminousArc", "LuminousArc\LuminousArc.csproj", "{4BD8DF5C-E971-45D1-B170-340D22DDB351}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tester", "Tester\Tester.csproj", "{A4FABF4B-59F2-4D4B-9012-FF177980EAB7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E6F419F9-D6B5-4BE7-99BB-97C48C927FF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E6F419F9-D6B5-4BE7-99BB-97C48C927FF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E6F419F9-D6B5-4BE7-99BB-97C48C927FF3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{E6F419F9-D6B5-4BE7-99BB-97C48C927FF3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{E6F419F9-D6B5-4BE7-99BB-97C48C927FF3}.Debug|x86.ActiveCfg = Debug|Any CPU
{E6F419F9-D6B5-4BE7-99BB-97C48C927FF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E6F419F9-D6B5-4BE7-99BB-97C48C927FF3}.Release|Any CPU.Build.0 = Release|Any CPU
{E6F419F9-D6B5-4BE7-99BB-97C48C927FF3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{E6F419F9-D6B5-4BE7-99BB-97C48C927FF3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{E6F419F9-D6B5-4BE7-99BB-97C48C927FF3}.Release|x86.ActiveCfg = Release|Any CPU
{8CE72663-0036-4A94-BD70-99AFE7CEEC0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8CE72663-0036-4A94-BD70-99AFE7CEEC0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8CE72663-0036-4A94-BD70-99AFE7CEEC0C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{8CE72663-0036-4A94-BD70-99AFE7CEEC0C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{8CE72663-0036-4A94-BD70-99AFE7CEEC0C}.Debug|x86.ActiveCfg = Debug|Any CPU
{8CE72663-0036-4A94-BD70-99AFE7CEEC0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8CE72663-0036-4A94-BD70-99AFE7CEEC0C}.Release|Any CPU.Build.0 = Release|Any CPU
{8CE72663-0036-4A94-BD70-99AFE7CEEC0C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{8CE72663-0036-4A94-BD70-99AFE7CEEC0C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{8CE72663-0036-4A94-BD70-99AFE7CEEC0C}.Release|x86.ActiveCfg = Release|Any CPU
{4BD8DF5C-E971-45D1-B170-340D22DDB351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4BD8DF5C-E971-45D1-B170-340D22DDB351}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4BD8DF5C-E971-45D1-B170-340D22DDB351}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{4BD8DF5C-E971-45D1-B170-340D22DDB351}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{4BD8DF5C-E971-45D1-B170-340D22DDB351}.Debug|x86.ActiveCfg = Debug|Any CPU
{4BD8DF5C-E971-45D1-B170-340D22DDB351}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4BD8DF5C-E971-45D1-B170-340D22DDB351}.Release|Any CPU.Build.0 = Release|Any CPU
{4BD8DF5C-E971-45D1-B170-340D22DDB351}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{4BD8DF5C-E971-45D1-B170-340D22DDB351}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{4BD8DF5C-E971-45D1-B170-340D22DDB351}.Release|x86.ActiveCfg = Release|Any CPU
{A4FABF4B-59F2-4D4B-9012-FF177980EAB7}.Debug|Any CPU.ActiveCfg = Debug|x86
{A4FABF4B-59F2-4D4B-9012-FF177980EAB7}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{A4FABF4B-59F2-4D4B-9012-FF177980EAB7}.Debug|Mixed Platforms.Build.0 = Debug|x86
{A4FABF4B-59F2-4D4B-9012-FF177980EAB7}.Debug|x86.ActiveCfg = Debug|x86
{A4FABF4B-59F2-4D4B-9012-FF177980EAB7}.Debug|x86.Build.0 = Debug|x86
{A4FABF4B-59F2-4D4B-9012-FF177980EAB7}.Release|Any CPU.ActiveCfg = Release|x86
{A4FABF4B-59F2-4D4B-9012-FF177980EAB7}.Release|Mixed Platforms.ActiveCfg = Release|x86
{A4FABF4B-59F2-4D4B-9012-FF177980EAB7}.Release|Mixed Platforms.Build.0 = Release|x86
{A4FABF4B-59F2-4D4B-9012-FF177980EAB7}.Release|x86.ActiveCfg = Release|x86
{A4FABF4B-59F2-4D4B-9012-FF177980EAB7}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -11,7 +11,7 @@ namespace DSDecmp
class NewestProgram
{
#if DEBUG
public static string PluginFolder = "../../../PluginDistro/Debug";
public static string PluginFolder = "./Plugins/Debug";
#else
public static string PluginFolder = "./Plugins";
#endif
@ -299,7 +299,6 @@ namespace DSDecmp
inputData = new byte[inStream.Length];
inStream.Read(inputData, 0, inputData.Length);
}
bool compressed = false;
#region try to compress
@ -315,7 +314,6 @@ namespace DSDecmp
{
outStr.WriteTo(output);
}
compressed = true;
if (format is CompositeFormat)
Console.Write((format as CompositeFormat).LastUsedCompressFormatString);
else
@ -323,24 +321,28 @@ namespace DSDecmp
Console.WriteLine("-compressed " + input + " to " + outputFile);
}
}
catch (Exception) { }
catch (Exception ex)
{
#region copy or print and continue
if (copyErrors)
{
Copy(input, outputFile);
}
else
{
Console.WriteLine("Could not " + format.ShortFormatString + "-compress " + input + ";");
Console.WriteLine(ex.Message);
#if DEBUG
Console.WriteLine(ex.StackTrace);
#endif
}
#endregion
}
}
#endregion
if (!compressed)
{
#region copy or print and continue
if (copyErrors)
{
Copy(input, outputFile);
}
else
Console.WriteLine("Could not " + format.ShortFormatString + "-compress " + input + ".");
#endregion
}
}
catch (FileNotFoundException)
{

View File

@ -14,19 +14,21 @@ namespace DSDecmp
/// starting at oldPtr. Takes O(inLength * oldLength) = O(n^2) time.
/// </summary>
/// <param name="newPtr">The start of the data that needs to be compressed.</param>
/// <param name="newLength">The number of bytes that still need to be compressed.</param>
/// <param name="newLength">The number of bytes that still need to be compressed.
/// (or: the maximum number of bytes that _may_ be compressed into one block)</param>
/// <param name="oldPtr">The start of the raw file.</param>
/// <param name="oldLength">The number of bytes already compressed.</param>
/// <param name="disp">The offset of the start of the longest block to refer to.</param>
/// <param name="minDisp">The minimum allowed value for 'disp'.</param>
/// <returns>The length of the longest sequence of bytes that can be copied from the already decompressed data.</returns>
public static unsafe int GetOccurrenceLength(byte* newPtr, int newLength, byte* oldPtr, int oldLength, out int disp)
public static unsafe int GetOccurrenceLength(byte* newPtr, int newLength, byte* oldPtr, int oldLength, out int disp, int minDisp = 1)
{
disp = 0;
if (newLength == 0)
return 0;
int maxLength = 0;
// try every possible 'disp' value (disp = oldLength - i)
for (int i = 0; i < oldLength - 1; i++)
for (int i = 0; i < oldLength - minDisp; i++)
{
// work from the start of the old data to the end, to mimic the original implementation's behaviour
// (and going from start to end or from end to start does not influence the compression ratio anyway)
@ -48,6 +50,10 @@ namespace DSDecmp
{
maxLength = currentLength;
disp = oldLength - i;
// if we cannot do better anyway, stop trying.
if (maxLength == newLength)
break;
}
}
return maxLength;

View File

@ -29,9 +29,15 @@ namespace GameFormats
public override bool SupportsCompression
{
get { return false; }
get { return true; }
}
private static bool lookAhead = false;
/// <summary>
/// Gets or sets if, when compressing using this format, the optimal compression scheme should be used.
/// </summary>
public static bool LookAhead { get { return lookAhead; } set { lookAhead = value; } }
/*
* An LZE / Le file consists of the following:
- A six byte header
@ -97,6 +103,10 @@ namespace GameFormats
}
#endregion
#region Method: Decompress(instream, inLength, outstream)
/// <summary>
/// Decompresses the given stream using the LZE/Le compression format.
/// </summary>
public override long Decompress(System.IO.Stream instream, long inLength, System.IO.Stream outstream)
{
long readBytes = 0;
@ -191,7 +201,7 @@ namespace GameFormats
}
#endregion
case 1:
#region 1 -> compact LZ10-like format
#region 1 -> compact LZ10/RLE-like format
{
#region Get length and displacement('disp') values from next byte
// there are < 2 bytes available when the end is at most 1 byte away
@ -268,6 +278,7 @@ namespace GameFormats
default:
throw new Exception("BUG: Mask is not 2 bits long!");
}
outstream.Flush();
}
@ -281,22 +292,206 @@ namespace GameFormats
return decompressedSize;
}
#endregion
private int MaskRsh(int value, int mask)
/// <summary>
/// Checks if the given aguments have the '-opt' option, which makes this format
/// compress using (near-)optimal compression instead of the original compression algorithm.
/// </summary>
public override int ParseCompressionOptions(string[] args)
{
int maskCopy = mask;
int masked = value & mask;
if (maskCopy == 0)
return masked;
while ((maskCopy & 1) == 0)
{
masked >>= 1;
maskCopy >>= 1;
}
return masked;
LookAhead = false;
if (args.Length > 0)
if (args[0] == "-opt")
{
LookAhead = true;
return 1;
}
return 0;
}
public override int Compress(System.IO.Stream instream, long inLength, System.IO.Stream outstream)
public unsafe override int Compress(System.IO.Stream instream, long inLength, System.IO.Stream outstream)
{
// block type 0: stores at most 3+0xF = 0x12 = 18 bytes (in 2 bytes)
// block type 1: stores at most 2+0x3F = 0x41 = 65 bytes (in 1 byte)
// block type 2: 1 raw byte
// block type 3: 3 raw bytes
if (LookAhead)
return CompressWithLA(instream, inLength, outstream);
// save the input data in an array to prevent having to go back and forth in a file
byte[] indata = new byte[inLength];
int numReadBytes = instream.Read(indata, 0, (int)inLength);
if (numReadBytes != inLength)
throw new StreamTooShortException();
// write the compression head first
outstream.WriteByte((byte)'L');
outstream.WriteByte((byte)'e');
outstream.WriteByte((byte)(inLength & 0xFF));
outstream.WriteByte((byte)((inLength >> 8) & 0xFF));
outstream.WriteByte((byte)((inLength >> 16) & 0xFF));
outstream.WriteByte((byte)((inLength >> 24) & 0xFF));
int compressedLength = 6;
fixed (byte* instart = &indata[0])
{
// we do need to buffer the output, as the first byte indicates which blocks are compressed.
// this version does not use a look-ahead, so we do not need to buffer more than 4 blocks at a time.
// (a block is at most 3 bytes long)
byte[] outbuffer = new byte[4 * 3 + 1];
outbuffer[0] = 0;
int bufferlength = 1, bufferedBlocks = 0;
int readBytes = 0;
int cacheByte = -1;
while (readBytes < inLength)
{
#region If 4 blocks are bufferd, write them and reset the buffer
// we can only buffer 4 blocks at a time.
if (bufferedBlocks == 4)
{
outstream.Write(outbuffer, 0, bufferlength);
compressedLength += bufferlength;
// reset the buffer
outbuffer[0] = 0;
bufferlength = 1;
bufferedBlocks = 0;
}
#endregion
// type 0: 3 <= len <= 18; 5 <= disp <= 0x1004
// type 1: 2 <= len <= 65; 1 <= disp <= 4
// type 2: 1 raw byte
// type 3: 3 raw bytes
// check if we can compress it using type 1 first (only 1 byte-long block)
int disp;
int oldLength = Math.Min(readBytes, 0x1004);
int length = LZUtil.GetOccurrenceLength(instart + readBytes, (int)Math.Min(inLength - readBytes, 65),
instart + readBytes - oldLength, oldLength, out disp, 1);
if (disp >= 1 && ((disp <= 4 && length >= 2) || (disp >= 5 && length >= 3)))
{
if (cacheByte >= 0)
{
// write a single raw byte block (the previous byte could not be the start of any compressed block)
outbuffer[bufferlength++] = (byte)(cacheByte & 0xFF);
outbuffer[0] |= (byte)(2 << (bufferedBlocks * 2));
cacheByte = -1;
bufferedBlocks++;
// the block set may be full; just retry this iteration.
continue;
}
if (disp >= 5)
{
#region compress using type 0
// type 0: store len/disp in 2 bytes:
// AB CD, with len = C + 3, disp = DAB + 5
// make sure we do not try to compress more than fits into the block
length = Math.Min(length, 0xF + 3);
readBytes += length;
outbuffer[bufferlength++] = (byte)((disp - 5) & 0xFF);
outbuffer[bufferlength] = (byte)(((disp - 5) >> 8) & 0xF);
outbuffer[bufferlength++] |= (byte)(((length - 3) & 0xF) << 4);
#endregion
}
else // 1 <= disp <= 4
{
#region compress using type 1
// type 1: store len/disp in 1 byte:
// ABCDEFGH, wih len = ABCDEF + 2, disp = GH + 1
readBytes += length;
outbuffer[bufferlength] = (byte)(((length - 2) << 2) & 0xFC);
outbuffer[bufferlength] |= (byte)((disp - 1) & 0x3);
bufferlength++;
outbuffer[0] |= (byte)(1 << (bufferedBlocks * 2));
#endregion
}
}
else
{
if (cacheByte < 0)
{
// first fail? remember byte, try to compress starting at next byte
cacheByte = *(instart + (readBytes++));
continue;
}
else
{
// 2 consecutive fails -> store 3 raw bytes (type 3) if possible.
if (inLength - readBytes >= 2)
{
outbuffer[bufferlength++] = (byte)(cacheByte & 0xFF);
outbuffer[bufferlength++] = *(instart + (readBytes++));
outbuffer[bufferlength++] = *(instart + (readBytes++));
outbuffer[0] |= (byte)(3 << (bufferedBlocks * 2));
cacheByte = -1;
}
else
{
// there are only two bytes remaining (incl. the cched byte)
// so write the cached byte first as single raw byte.
// keep the next/last byte as new cache, since the block buffer may be full.
outbuffer[bufferlength++] = (byte)(cacheByte & 0xFF);
outbuffer[0] |= (byte)(2 << (bufferedBlocks * 2));
cacheByte = *(instart + (readBytes++));
}
}
}
bufferedBlocks++;
}
// there may be one cache-byte left.
if (cacheByte >= 0)
{
// if the current set of blocks is full, empty it first
if (bufferedBlocks == 4)
{
#region empty block buffer
outstream.Write(outbuffer, 0, bufferlength);
compressedLength += bufferlength;
// reset the buffer
outbuffer[0] = 0;
bufferlength = 1;
bufferedBlocks = 0;
#endregion
}
outbuffer[bufferlength++] = (byte)(cacheByte & 0xFF);
cacheByte = -1;
outbuffer[0] |= (byte)(2 << (bufferedBlocks * 2));
bufferedBlocks++;
}
// copy any remaining blocks to the output
if (bufferedBlocks > 0)
{
outstream.Write(outbuffer, 0, bufferlength);
compressedLength += bufferlength;
}
}
return compressedLength;
}
private unsafe int CompressWithLA(Stream instream, long inLength, Stream outstream)
{
throw new NotImplementedException();
}

View File

@ -22,6 +22,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -30,6 +31,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />

View File

@ -211,16 +211,18 @@
Utility class for compression using LZ-like compression schemes.
</summary>
</member>
<member name="M:DSDecmp.LZUtil.GetOccurrenceLength(System.Byte*,System.Int32,System.Byte*,System.Int32,System.Int32@)">
<member name="M:DSDecmp.LZUtil.GetOccurrenceLength(System.Byte*,System.Int32,System.Byte*,System.Int32,System.Int32@,System.Int32)">
<summary>
Determine the maximum size of a LZ-compressed block starting at newPtr, using the already compressed data
starting at oldPtr. Takes O(inLength * oldLength) = O(n^2) time.
</summary>
<param name="newPtr">The start of the data that needs to be compressed.</param>
<param name="newLength">The number of bytes that still need to be compressed.</param>
<param name="newLength">The number of bytes that still need to be compressed.
(or: the maximum number of bytes that _may_ be compressed into one block)</param>
<param name="oldPtr">The start of the raw file.</param>
<param name="oldLength">The number of bytes already compressed.</param>
<param name="disp">The offset of the start of the longest block to refer to.</param>
<param name="minDisp">The minimum allowed value for 'disp'.</param>
<returns>The length of the longest sequence of bytes that can be copied from the already decompressed data.</returns>
</member>
<member name="T:DSDecmp.Formats.Nitro.NitroCFormat">

Binary file not shown.

Binary file not shown.

27
CSharp/Tester/Program.cs Normal file
View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GameFormats;
namespace Tester
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Start");
//new LuminousArc().Compress("D:/tile molester/DSLazy/NDS_UNPACK_LUMARC/test/atcbg_dec.imb", "D:/tile molester/DSLazy/NDS_UNPACK_LUMARC/test/atcbg_dec_cmp.imb");
//new LuminousArc().Decompress("D:/tile molester/DSLazy/NDS_UNPACK_LUMARC/test/atcbg_dec_cmp.imb", "D:/tile molester/DSLazy/NDS_UNPACK_LUMARC/test/atcbg_dec_cmp_dec.imb");
new LuminousArc().Compress("D:/tile molester/DSLazy/NDS_UNPACK_LUMARC/test/o_lmoji00_dec.bin", "D:/tile molester/DSLazy/NDS_UNPACK_LUMARC/test/o_lmoji00_dec_cmp.bin");
Console.WriteLine();
new LuminousArc().Decompress("D:/tile molester/DSLazy/NDS_UNPACK_LUMARC/test/o_lmoji00_dec_cmp.bin", "D:/tile molester/DSLazy/NDS_UNPACK_LUMARC/test/o_lmoji00_dec_cmp_dec.bin");
Console.WriteLine("Success?");
Console.ReadLine();
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Tester")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Tester")]
[assembly: AssemblyCopyright("Copyright © 2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("abe40de2-686c-4757-83ff-375f54a21490")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A4FABF4B-59F2-4D4B-9012-FF177980EAB7}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Tester</RootNamespace>
<AssemblyName>Tester</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DSDecmp\DSDecmp.csproj">
<Project>{E6F419F9-D6B5-4BE7-99BB-97C48C927FF3}</Project>
<Name>DSDecmp</Name>
</ProjectReference>
<ProjectReference Include="..\GoldenSunDD\GoldenSunDD.csproj">
<Project>{8CE72663-0036-4A94-BD70-99AFE7CEEC0C}</Project>
<Name>GoldenSunDD</Name>
</ProjectReference>
<ProjectReference Include="..\LuminousArc\LuminousArc.csproj">
<Project>{4BD8DF5C-E971-45D1-B170-340D22DDB351}</Project>
<Name>LuminousArc</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>