2016-11-12 19:02:48 +03:00
using System ;
using System.Linq ;
using System.IO ;
using System.Windows.Forms ;
2016-12-31 15:56:10 +03:00
using System.Collections.Generic ;
2016-11-12 19:02:48 +03:00
2017-04-23 19:22:25 +03:00
using CsbEditor.Properties ;
using SonicAudioLib ;
2016-11-12 19:02:48 +03:00
using SonicAudioLib.CriMw ;
using SonicAudioLib.IO ;
2017-06-21 01:19:47 +03:00
using SonicAudioLib.Archives ;
2016-11-12 19:02:48 +03:00
using System.Globalization ;
namespace CsbEditor
{
class Program
{
static void Main ( string [ ] args )
{
2017-06-21 01:19:47 +03:00
Settings . Default . Save ( ) ;
2016-11-12 19:02:48 +03:00
if ( args . Length < 1 )
{
2017-04-23 19:22:25 +03:00
Console . WriteLine ( Resources . Description ) ;
2016-11-12 19:02:48 +03:00
Console . ReadLine ( ) ;
return ;
}
2016-12-31 15:56:10 +03:00
#if ! DEBUG
2016-11-12 19:02:48 +03:00
try
{
2016-12-31 15:56:10 +03:00
#endif
2016-11-12 19:02:48 +03:00
if ( args [ 0 ] . EndsWith ( ".csb" ) )
{
2017-04-23 19:22:25 +03:00
var extractor = new DataExtractor ( ) ;
extractor . ProgressChanged + = OnProgressChanged ;
extractor . BufferSize = Settings . Default . BufferSize ;
extractor . EnableThreading = Settings . Default . EnableThreading ;
extractor . MaxThreads = Settings . Default . MaxThreads ;
2016-11-12 19:02:48 +03:00
string baseDirectory = Path . GetDirectoryName ( args [ 0 ] ) ;
string outputDirectoryName = Path . Combine ( baseDirectory , Path . GetFileNameWithoutExtension ( args [ 0 ] ) ) ;
2016-12-31 15:56:10 +03:00
CriCpkArchive cpkArchive = null ;
string cpkPath = outputDirectoryName + ".cpk" ;
bool found = File . Exists ( cpkPath ) ;
2016-11-12 19:02:48 +03:00
using ( CriTableReader reader = CriTableReader . Create ( args [ 0 ] ) )
{
while ( reader . Read ( ) )
{
if ( reader . GetString ( "name" ) = = "SOUND_ELEMENT" )
{
2017-04-23 19:22:25 +03:00
long tablePosition = reader . GetPosition ( "utf" ) ;
2017-06-21 01:19:47 +03:00
using ( CriTableReader sdlReader = CriTableReader . Create ( reader . GetSubStream ( "utf" ) ) )
2016-11-12 19:02:48 +03:00
{
while ( sdlReader . Read ( ) )
{
2016-12-31 15:56:10 +03:00
if ( sdlReader . GetByte ( "fmt" ) ! = 0 )
2016-11-12 19:02:48 +03:00
{
2016-12-31 15:56:10 +03:00
throw new Exception ( "The given CSB file contains an audio file which is not an ADX. Only CSB files with ADXs are supported." ) ;
2016-11-12 19:02:48 +03:00
}
2016-12-31 15:56:10 +03:00
bool streaming = sdlReader . GetBoolean ( "stmflg" ) ;
if ( streaming & & ! found )
2016-11-12 19:02:48 +03:00
{
2016-12-31 15:56:10 +03:00
throw new Exception ( "Cannot find the external .CPK file for this .CSB file. Please ensure that the external .CPK file is stored in the directory where the .CPK file is." ) ;
}
else if ( streaming & & found & & cpkArchive = = null )
{
cpkArchive = new CriCpkArchive ( ) ;
2017-04-23 19:22:25 +03:00
cpkArchive . Load ( cpkPath , Settings . Default . BufferSize ) ;
2016-11-12 19:02:48 +03:00
}
string sdlName = sdlReader . GetString ( "name" ) ;
DirectoryInfo destinationPath = new DirectoryInfo ( Path . Combine ( outputDirectoryName , sdlName ) ) ;
destinationPath . Create ( ) ;
2016-12-31 15:56:10 +03:00
CriAaxArchive aaxArchive = new CriAaxArchive ( ) ;
if ( streaming )
2016-11-12 19:02:48 +03:00
{
2016-12-31 15:56:10 +03:00
CriCpkEntry cpkEntry = cpkArchive . GetByPath ( sdlName ) ;
2017-01-30 13:47:50 +03:00
if ( cpkEntry ! = null )
2016-11-12 19:02:48 +03:00
{
2017-01-30 13:47:50 +03:00
using ( Stream cpkSource = File . OpenRead ( cpkPath ) )
using ( Stream aaxSource = cpkEntry . Open ( cpkSource ) )
2016-11-12 19:02:48 +03:00
{
2017-01-30 13:47:50 +03:00
aaxArchive . Read ( aaxSource ) ;
foreach ( CriAaxEntry entry in aaxArchive )
2016-12-31 15:56:10 +03:00
{
2017-04-23 19:22:25 +03:00
extractor . Add ( cpkPath ,
Path . Combine ( destinationPath . FullName ,
entry . Flag = = CriAaxEntryFlag . Intro ? "Intro.adx" : "Loop.adx" ) ,
cpkEntry . Position + entry . Position , entry . Length ) ;
2016-12-31 15:56:10 +03:00
}
}
}
}
else
{
2017-04-23 19:22:25 +03:00
long aaxPosition = sdlReader . GetPosition ( "data" ) ;
2017-06-21 01:19:47 +03:00
using ( Stream aaxSource = sdlReader . GetSubStream ( "data" ) )
2016-12-31 15:56:10 +03:00
{
aaxArchive . Read ( aaxSource ) ;
foreach ( CriAaxEntry entry in aaxArchive )
{
2017-04-23 19:22:25 +03:00
extractor . Add ( args [ 0 ] ,
Path . Combine ( destinationPath . FullName ,
entry . Flag = = CriAaxEntryFlag . Intro ? "Intro.adx" : "Loop.adx" ) ,
tablePosition + aaxPosition + entry . Position , entry . Length ) ;
2016-11-12 19:02:48 +03:00
}
}
}
}
}
break ;
}
}
}
2017-04-23 19:22:25 +03:00
extractor . Run ( ) ;
2016-11-12 19:02:48 +03:00
}
else if ( File . GetAttributes ( args [ 0 ] ) . HasFlag ( FileAttributes . Directory ) )
{
string baseDirectory = Path . GetDirectoryName ( args [ 0 ] ) ;
string csbPath = args [ 0 ] + ".csb" ;
if ( ! File . Exists ( csbPath ) )
{
throw new Exception ( "Cannot find the .CSB file for this directory. Please ensure that the .CSB file is stored in the directory where this directory is." ) ;
}
2016-12-31 15:56:10 +03:00
CriCpkArchive cpkArchive = new CriCpkArchive ( ) ;
2017-04-23 19:22:25 +03:00
cpkArchive . ProgressChanged + = OnProgressChanged ;
2016-12-31 15:56:10 +03:00
2016-11-12 19:02:48 +03:00
CriTable csbFile = new CriTable ( ) ;
2017-04-23 19:22:25 +03:00
csbFile . Load ( csbPath , Settings . Default . BufferSize ) ;
2016-11-12 19:02:48 +03:00
2016-12-31 15:56:10 +03:00
CriRow soundElementRow = csbFile . Rows . First ( row = > ( string ) row [ "name" ] = = "SOUND_ELEMENT" ) ;
2016-11-12 19:02:48 +03:00
CriTable soundElementTable = new CriTable ( ) ;
soundElementTable . Load ( ( byte [ ] ) soundElementRow [ "utf" ] ) ;
2016-12-31 15:56:10 +03:00
List < FileInfo > junks = new List < FileInfo > ( ) ;
2016-11-12 19:02:48 +03:00
foreach ( CriRow sdlRow in soundElementTable . Rows )
{
string sdlName = ( string ) sdlRow [ "name" ] ;
DirectoryInfo sdlDirectory = new DirectoryInfo ( Path . Combine ( args [ 0 ] , sdlName ) ) ;
if ( ! sdlDirectory . Exists )
{
throw new Exception ( $"Cannot find sound element directory for replacement.\nPath attempt: {sdlDirectory.FullName}" ) ;
}
2016-12-31 15:56:10 +03:00
bool streaming = ( byte ) sdlRow [ "stmflg" ] ! = 0 ;
2016-11-12 19:02:48 +03:00
uint sampleRate = ( uint ) sdlRow [ "sfreq" ] ;
byte numberChannels = ( byte ) sdlRow [ "nch" ] ;
2016-12-31 15:56:10 +03:00
CriAaxArchive aaxArchive = new CriAaxArchive ( ) ;
foreach ( FileInfo file in sdlDirectory . GetFiles ( "*.adx" ) )
2016-11-12 19:02:48 +03:00
{
2016-12-31 15:56:10 +03:00
CriAaxEntry entry = new CriAaxEntry ( ) ;
if ( file . Name . ToLower ( CultureInfo . GetCultureInfo ( "en-US" ) ) = = "intro.adx" )
{
entry . Flag = CriAaxEntryFlag . Intro ;
entry . FilePath = file ;
aaxArchive . Add ( entry ) ;
ReadAdx ( file , out sampleRate , out numberChannels ) ;
}
else if ( file . Name . ToLower ( CultureInfo . GetCultureInfo ( "en-US" ) ) = = "loop.adx" )
{
entry . Flag = CriAaxEntryFlag . Loop ;
entry . FilePath = file ;
aaxArchive . Add ( entry ) ;
ReadAdx ( file , out sampleRate , out numberChannels ) ;
}
}
2016-11-12 19:02:48 +03:00
2016-12-31 15:56:10 +03:00
if ( streaming )
{
CriCpkEntry entry = new CriCpkEntry ( ) ;
2017-03-09 20:48:17 +03:00
entry . Name = Path . GetFileName ( sdlName ) ;
entry . DirectoryName = Path . GetDirectoryName ( sdlName ) ;
2016-12-31 15:56:10 +03:00
entry . Id = ( uint ) cpkArchive . Count ;
entry . FilePath = new FileInfo ( Path . GetTempFileName ( ) ) ;
junks . Add ( entry . FilePath ) ;
cpkArchive . Add ( entry ) ;
2017-04-23 19:22:25 +03:00
aaxArchive . Save ( entry . FilePath . FullName , Settings . Default . BufferSize ) ;
2016-12-31 15:56:10 +03:00
}
else
{
sdlRow [ "data" ] = aaxArchive . Save ( ) ;
2016-11-12 19:02:48 +03:00
}
sdlRow [ "sfreq" ] = sampleRate ;
sdlRow [ "nch" ] = numberChannels ;
}
soundElementTable . WriterSettings = CriTableWriterSettings . AdxSettings ;
soundElementRow [ "utf" ] = soundElementTable . Save ( ) ;
csbFile . WriterSettings = CriTableWriterSettings . AdxSettings ;
2017-04-23 19:22:25 +03:00
csbFile . Save ( args [ 0 ] + ".csb" , Settings . Default . BufferSize ) ;
2016-12-31 15:56:10 +03:00
if ( cpkArchive . Count > 0 )
{
2017-04-23 19:22:25 +03:00
cpkArchive . Save ( args [ 0 ] + ".cpk" , Settings . Default . BufferSize ) ;
2016-12-31 15:56:10 +03:00
}
foreach ( FileInfo junk in junks )
{
junk . Delete ( ) ;
}
2016-11-12 19:02:48 +03:00
}
2016-12-31 15:56:10 +03:00
#if ! DEBUG
2016-11-12 19:02:48 +03:00
}
catch ( Exception exception )
{
MessageBox . Show ( $"{exception.Message}" , "CSB Editor" , MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
}
2016-12-31 15:56:10 +03:00
#endif
2016-11-12 19:02:48 +03:00
}
static void ReadAdx ( FileInfo fileInfo , out uint sampleRate , out byte numberChannels )
{
using ( Stream source = fileInfo . OpenRead ( ) )
{
source . Seek ( 7 , SeekOrigin . Begin ) ;
2017-06-21 01:19:47 +03:00
numberChannels = DataStream . ReadByte ( source ) ;
sampleRate = DataStream . ReadUInt32BE ( source ) ;
2016-11-12 19:02:48 +03:00
}
}
2017-04-23 19:22:25 +03:00
private static string buffer = new string ( ' ' , 17 ) ;
private static void OnProgressChanged ( object sender , ProgressChangedEventArgs e )
{
int left = Console . CursorLeft ;
int top = Console . CursorTop ;
Console . Write ( buffer ) ;
Console . SetCursorPosition ( left , top ) ;
Console . WriteLine ( "Progress: {0}%" , e . Progress ) ;
Console . SetCursorPosition ( left , top ) ;
}
2016-11-12 19:02:48 +03:00
}
}