2013-04-12 00:47:50 +02:00
using System ;
using System.Collections.Generic ;
2013-04-21 22:04:06 +02:00
using System.Data ;
2013-04-12 00:47:50 +02:00
using System.IO ;
2013-11-09 16:30:59 +01:00
using System.Text ;
2021-04-25 18:31:05 +02:00
using Microsoft.Data.Sqlite ;
2013-04-12 00:47:50 +02:00
using ChanSort.Api ;
namespace ChanSort.Loader.Panasonic
{
2021-09-23 20:25:30 +02:00
internal enum ByteOrder { BigEndian , LittleEndian }
2022-11-29 18:21:52 +01:00
class SvlSerializer : SerializerBase
2013-04-12 00:47:50 +02:00
{
2023-06-03 10:38:11 +02:00
private readonly ChannelList avbtChannels = new ( SignalSource . AnalogT , "Analog Antenna" ) ;
private readonly ChannelList avbcChannels = new ( SignalSource . AnalogC , "Analog Cable" ) ;
private readonly ChannelList dvbtChannels = new ( SignalSource . DvbT , "DVB-T" ) ;
private readonly ChannelList dvbcChannels = new ( SignalSource . DvbC , "DVB-C" ) ;
private readonly ChannelList dvbsChannels = new ( SignalSource . DvbS , "DVB-S" ) ;
private readonly ChannelList antIpChannels = new ( SignalSource . IpAntenna , "Antenna>IP" ) ;
private readonly ChannelList cabIpChannels = new ( SignalSource . IpCable , "Cable>IP" ) ;
private readonly ChannelList satIpChannels = new ( SignalSource . IpSat , "SAT>IP" ) ;
private readonly ChannelList freesatChannels = new ( SignalSource . DvbS | SignalSource . Freesat , "Freesat" ) ;
2013-04-12 00:47:50 +02:00
2013-06-25 23:45:40 +02:00
private string workFile ;
private CypherMode cypherMode ;
2021-09-22 23:46:03 +02:00
private byte [ ] fileHeader = Array . Empty < byte > ( ) ;
2013-06-25 23:45:40 +02:00
private int dbSizeOffset ;
2021-09-23 20:25:30 +02:00
private ByteOrder headerByteOrder ;
2013-11-09 16:30:59 +01:00
private string charEncoding ;
2020-12-26 18:16:01 +01:00
private bool explicitUtf8 ;
private bool implicitUtf8 ;
2013-04-12 00:47:50 +02:00
2013-06-25 23:45:40 +02:00
enum CypherMode
{
None ,
HeaderAndChecksum ,
Encryption ,
Unknown
}
#region ctor ( )
2022-11-29 18:21:52 +01:00
public SvlSerializer ( string inputFile ) : base ( inputFile )
2013-04-12 00:47:50 +02:00
{
2015-06-13 18:37:59 +02:00
this . Features . ChannelNameEdit = ChannelNameEditMode . None ; // due to the chaos with binary data inside the "sname" string column, writing back a name has undesired side effects
2019-11-08 02:31:44 +01:00
this . Features . DeleteMode = DeleteMode . Physically ;
2019-11-24 20:00:48 +01:00
this . Features . CanSkipChannels = true ;
this . Features . CanLockChannels = true ;
this . Features . CanHideChannels = false ;
2015-01-14 21:38:01 +01:00
this . Features . CanHaveGaps = false ;
2015-11-21 19:34:30 +01:00
this . Features . EncryptedFlagEdit = true ;
2021-03-14 22:13:22 +01:00
this . Features . FavoritesMode = FavoritesMode . OrderedPerSource ;
2013-06-29 17:34:51 +02:00
this . DataRoot . AddChannelList ( this . avbtChannels ) ;
this . DataRoot . AddChannelList ( this . avbcChannels ) ;
2013-06-27 20:21:56 +02:00
this . DataRoot . AddChannelList ( this . dvbtChannels ) ;
this . DataRoot . AddChannelList ( this . dvbcChannels ) ;
this . DataRoot . AddChannelList ( this . dvbsChannels ) ;
2023-06-03 10:38:11 +02:00
this . DataRoot . AddChannelList ( this . antIpChannels ) ;
this . DataRoot . AddChannelList ( this . cabIpChannels ) ;
this . DataRoot . AddChannelList ( this . satIpChannels ) ;
2013-06-29 17:34:51 +02:00
this . DataRoot . AddChannelList ( this . freesatChannels ) ;
2019-02-05 19:30:47 +01:00
2019-02-10 15:56:03 +01:00
// hide columns for fields that don't exist in Panasonic channel list
2019-02-05 19:30:47 +01:00
foreach ( var list in this . DataRoot . ChannelLists )
{
2019-02-10 15:56:03 +01:00
list . VisibleColumnFieldNames . Remove ( "PcrPid" ) ;
2019-02-05 19:30:47 +01:00
list . VisibleColumnFieldNames . Remove ( "VideoPid" ) ;
list . VisibleColumnFieldNames . Remove ( "AudioPid" ) ;
}
2013-04-12 00:47:50 +02:00
}
2013-06-25 23:45:40 +02:00
#endregion
2013-04-12 00:47:50 +02:00
#region Load ( )
public override void Load ( )
{
2013-06-25 23:45:40 +02:00
this . workFile = this . GetUncypheredWorkFile ( ) ;
2013-04-12 00:47:50 +02:00
this . CreateDummySatellites ( ) ;
2025-06-05 18:35:10 +02:00
string channelConnString = $"Data Source=\" { this . workFile } \ ";Pooling=False" ;
2022-11-29 14:56:23 +01:00
using var conn = new SqliteConnection ( channelConnString ) ;
conn . Open ( ) ;
using var cmd = conn . CreateCommand ( ) ;
RepairCorruptedDatabaseImage ( cmd ) ;
InitCharacterEncoding ( cmd ) ;
2017-06-08 20:01:42 +02:00
2022-11-29 14:56:23 +01:00
cmd . CommandText = "SELECT count(1) FROM sqlite_master WHERE type = 'table' and name in ('SVL', 'TSL')" ;
if ( Convert . ToInt32 ( cmd . ExecuteScalar ( ) ) ! = 2 )
throw LoaderException . TryNext ( "File doesn't contain the expected TSL/SVL tables" ) ;
2017-06-08 20:01:42 +02:00
2022-11-29 14:56:23 +01:00
this . ReadChannels ( cmd ) ;
2013-04-12 00:47:50 +02:00
}
#endregion
2013-06-25 23:45:40 +02:00
#region GetUncypheredWorkFile ( )
private string GetUncypheredWorkFile ( )
{
this . cypherMode = this . GetCypherMode ( this . FileName ) ;
if ( cypherMode = = CypherMode . Unknown )
2022-11-29 14:56:23 +01:00
throw LoaderException . TryNext ( ERR_UnknownFormat ) ;
2013-06-25 23:45:40 +02:00
if ( cypherMode = = CypherMode . None )
return this . FileName ;
2023-12-12 19:07:57 +01:00
this . TempPath = Path . Combine ( Path . GetDirectoryName ( this . FileName ) ? ? "" , Path . GetFileNameWithoutExtension ( this . FileName ) + $"_decrypted_{DateTime.Now:yyMMdd-HHmmss}.db" ) ; //Path.GetTempFileName();
2019-11-08 19:35:59 +01:00
this . DeleteTempPath ( ) ;
2019-11-08 02:31:44 +01:00
2013-06-25 23:45:40 +02:00
if ( cypherMode = = CypherMode . Encryption )
2019-11-08 19:35:59 +01:00
this . CypherFile ( this . FileName , this . TempPath , false ) ;
2013-06-25 23:45:40 +02:00
else
2019-11-08 19:35:59 +01:00
this . RemoveHeader ( this . FileName , this . TempPath ) ;
return this . TempPath ;
2013-06-25 23:45:40 +02:00
}
#endregion
#region GetCypherMode ( )
private CypherMode GetCypherMode ( string file )
{
2022-11-29 22:00:16 +01:00
using var stream = File . OpenRead ( file ) ;
using var rdr = new BinaryReader ( stream ) ;
uint value = ( uint ) rdr . ReadInt32 ( ) ;
2023-10-22 21:43:46 +02:00
if ( value = = 0x694C5153 ) return CypherMode . None ; // "SQLi", already decrypted svl.db or svl.bin
if ( value = = 0x42445350 ) return CypherMode . HeaderAndChecksum ; // "PSDB" - svl.bin
if ( value = = 0xA07DCB50 ) return CypherMode . Encryption ; // svl.db
2022-11-29 22:00:16 +01:00
return CypherMode . Unknown ;
2013-06-25 23:45:40 +02:00
}
#endregion
2013-04-12 00:47:50 +02:00
#region CypherFile ( )
/// <summary>
/// XOR-based cypher which can be used to alternately crypt/decrypt data
/// </summary>
2013-06-28 15:10:14 +02:00
private void CypherFile ( string input , string output , bool encrypt )
2013-04-12 00:47:50 +02:00
{
byte [ ] fileContent = File . ReadAllBytes ( input ) ;
2013-06-29 16:44:47 +02:00
if ( ! encrypt & & this . CalcChecksum ( fileContent , fileContent . Length ) ! = 0 )
2022-11-29 14:56:23 +01:00
throw LoaderException . Fail ( "Checksum validation failed" ) ;
2013-06-29 16:44:47 +02:00
2013-04-12 00:47:50 +02:00
int chiffre = 0x0388 ;
int step = 0 ;
2013-06-29 16:44:47 +02:00
for ( int i = 0 ; i < fileContent . Length - 4 ; i + + )
2013-04-12 00:47:50 +02:00
{
byte b = fileContent [ i ] ;
2013-06-28 15:10:14 +02:00
byte n = ( byte ) ( b ^ ( chiffre > > 8 ) ) ;
fileContent [ i ] = n ;
2013-04-12 00:47:50 +02:00
if ( + + step < 256 )
2013-06-28 15:10:14 +02:00
chiffre + = ( encrypt ? n : b ) + 0x96A3 ;
2013-04-12 00:47:50 +02:00
else
{
chiffre = 0x0388 ;
step = 0 ;
}
}
2013-06-29 16:44:47 +02:00
if ( encrypt )
this . UpdateChecksum ( fileContent ) ;
2013-04-12 00:47:50 +02:00
File . WriteAllBytes ( output , fileContent ) ;
}
#endregion
2013-06-25 23:45:40 +02:00
#region RemoveHeader ( )
private void RemoveHeader ( string inputFile , string outputFile )
{
var data = File . ReadAllBytes ( inputFile ) ;
2013-06-29 16:44:47 +02:00
if ( this . CalcChecksum ( data , data . Length ) ! = 0 )
2022-11-29 14:56:23 +01:00
throw LoaderException . Fail ( "Checksum validation failed" ) ;
2013-06-25 23:45:40 +02:00
2013-07-19 17:27:02 +02:00
int offset ;
2021-09-23 20:25:30 +02:00
if ( ! this . ValidateFileSize ( data , ByteOrder . BigEndian , out offset ) & &
! this . ValidateFileSize ( data , ByteOrder . LittleEndian , out offset ) )
2022-11-29 14:56:23 +01:00
throw LoaderException . Fail ( "File size validation failed" ) ;
2013-06-25 23:45:40 +02:00
using ( var stream = new FileStream ( outputFile , FileMode . Create , FileAccess . Write ) )
2022-11-29 18:21:52 +01:00
stream . Write ( data , offset , data . Length - offset - 4 ) ;
2013-06-25 23:45:40 +02:00
this . fileHeader = new byte [ offset ] ;
Array . Copy ( data , 0 , this . fileHeader , 0 , offset ) ;
}
#endregion
2013-07-19 17:27:02 +02:00
#region ValidateFileSize ( )
2021-09-23 20:25:30 +02:00
private bool ValidateFileSize ( byte [ ] data , ByteOrder byteOrder , out int offset )
2013-07-19 17:27:02 +02:00
{
2021-09-23 20:25:30 +02:00
this . headerByteOrder = byteOrder ;
offset = 30 + Tools . GetInt16 ( data , 28 , byteOrder = = ByteOrder . LittleEndian ) ;
2013-07-19 17:27:02 +02:00
if ( offset > = data . Length ) return false ;
this . dbSizeOffset = offset ;
2021-09-23 20:25:30 +02:00
int dbSize = Tools . GetInt32 ( data , offset , byteOrder = = ByteOrder . LittleEndian ) ;
2013-07-19 17:27:02 +02:00
offset + = 4 ;
return data . Length = = offset + dbSize + 4 ;
}
#endregion
2013-06-29 16:44:47 +02:00
#region CalcChecksum ( )
2019-07-20 02:08:51 +02:00
2013-06-29 16:44:47 +02:00
private uint CalcChecksum ( byte [ ] data , int length )
2013-06-25 23:45:40 +02:00
{
2019-07-20 02:08:51 +02:00
return Crc32 . Normal . CalcCrc32 ( data , 0 , length ) ;
2013-06-25 23:45:40 +02:00
}
2019-07-20 02:08:51 +02:00
2013-06-25 23:45:40 +02:00
#endregion
2013-04-12 00:47:50 +02:00
#region CreateDummySatellites ( )
private void CreateDummySatellites ( )
{
for ( int i = 1 ; i < = 4 ; i + + )
{
var sat = new Satellite ( i ) ;
sat . Name = "LNB " + i ;
sat . OrbitalPosition = i . ToString ( ) ;
this . DataRoot . Satellites . Add ( i , sat ) ;
}
}
#endregion
2013-11-09 16:30:59 +01:00
#region InitCharacterEncoding ( )
2021-04-25 18:31:05 +02:00
private void InitCharacterEncoding ( SqliteCommand cmd )
2013-11-09 16:30:59 +01:00
{
2013-11-24 13:30:20 +01:00
cmd . CommandText = "PRAGMA encoding" ;
this . charEncoding = cmd . ExecuteScalar ( ) as string ;
}
#endregion
#region RepairCorruptedDatabaseImage ( )
2021-04-25 18:31:05 +02:00
private void RepairCorruptedDatabaseImage ( SqliteCommand cmd )
2013-11-24 13:30:20 +01:00
{
cmd . CommandText = "REINDEX" ;
cmd . ExecuteNonQuery ( ) ;
2013-11-09 16:30:59 +01:00
}
#endregion
2013-04-12 00:47:50 +02:00
#region ReadChannels ( )
2021-04-25 18:31:05 +02:00
private void ReadChannels ( SqliteCommand cmd )
2013-04-12 00:47:50 +02:00
{
string [ ] fieldNames = { "rowid" , "major_channel" , "physical_ch" , "sname" , "freq" , "skip" , "running_status" , "free_CA_mode" , "child_lock" ,
2023-06-03 10:38:11 +02:00
"profile1index" , "profile2index" , "profile3index" , "profile4index" , "stype" , "onid" , "tsid" , "sid" , "ntype" , "ya_svcid" , "delivery" , "delivery_type" } ;
2013-04-12 00:47:50 +02:00
2013-06-25 23:45:40 +02:00
const string sql = @ "
2013-11-20 02:42:47 +01:00
select s . rowid , s . major_channel , s . physical_ch , cast ( s . sname as blob ) , t . freq , s . skip , s . running_status , s . free_CA_mode , s . child_lock ,
2023-06-03 10:38:11 +02:00
profile1index , profile2index , profile3index , profile4index , s . stype , s . onid , s . tsid , s . svcid , s . ntype , s . ya_svcid , delivery , ifnull ( t . delivery_type , 0 )
2013-06-25 23:45:40 +02:00
from SVL s
2023-12-18 17:03:05 +01:00
left outer join TSL t on s . ntype = t . ntype and s . physical_ch = t . physical_ch and s . tsid = t . tsid and s . onid = t . onid
2013-06-25 23:45:40 +02:00
order by s . ntype , major_channel
";
2013-04-12 00:47:50 +02:00
var fields = this . GetFieldMap ( fieldNames ) ;
cmd . CommandText = sql ;
2020-12-26 18:16:01 +01:00
this . implicitUtf8 = true ;
2013-04-12 00:47:50 +02:00
using ( var r = cmd . ExecuteReader ( ) )
{
while ( r . Read ( ) )
{
2020-12-26 16:51:33 +01:00
var channel = new DbChannel ( r , fields , this . DataRoot , this . DefaultEncoding ) ;
2013-04-12 00:47:50 +02:00
if ( ! channel . IsDeleted )
{
2020-12-26 16:51:33 +01:00
if ( channel . RawName . Length > 0 & & channel . RawName [ 0 ] = = 0x15 ) // if there is a channel with a 0x15 encoding ID (UTF-8), we can allow editing channels
2020-12-26 18:16:01 +01:00
this . explicitUtf8 = true ;
if ( channel . NonAscii ) // if all channels with non-ascii characters are valid UTF-8 strings, we can allow editing too
this . implicitUtf8 & = channel . ValidUtf8 ;
2013-04-12 00:47:50 +02:00
var channelList = this . DataRoot . GetChannelList ( channel . SignalSource ) ;
2019-08-29 16:57:20 +02:00
this . DataRoot . AddChannel ( channelList , channel ) ;
2013-04-12 00:47:50 +02:00
}
}
}
2020-12-26 18:16:01 +01:00
if ( this . explicitUtf8 | | this . implicitUtf8 )
this . Features . ChannelNameEdit = ChannelNameEditMode . All ;
2013-04-12 00:47:50 +02:00
}
#endregion
#region GetFieldMap ( )
private IDictionary < string , int > GetFieldMap ( string [ ] fieldNames )
{
Dictionary < string , int > field = new Dictionary < string , int > ( ) ;
for ( int i = 0 ; i < fieldNames . Length ; i + + )
field [ fieldNames [ i ] ] = i ;
return field ;
}
#endregion
2013-11-20 02:42:47 +01:00
#region DefaultEncoding
public override Encoding DefaultEncoding
{
get { return base . DefaultEncoding ; }
set
{
base . DefaultEncoding = value ;
foreach ( var list in this . DataRoot . ChannelLists )
{
foreach ( var channel in list . Channels )
channel . ChangeEncoding ( value ) ;
}
}
}
#endregion
2013-04-12 00:47:50 +02:00
2013-06-25 23:45:40 +02:00
2013-04-21 22:04:06 +02:00
#region Save ( )
2022-11-29 22:00:16 +01:00
public override void Save ( )
2013-04-12 00:47:50 +02:00
{
2025-06-05 18:35:10 +02:00
string channelConnString = $"Data Source=\" { this . workFile } \ ";Pooling=False" ;
2022-11-29 22:00:16 +01:00
using ( var conn = new SqliteConnection ( channelConnString ) )
2013-04-21 22:04:06 +02:00
{
conn . Open ( ) ;
2021-05-01 11:41:33 +02:00
using var trans = conn . BeginTransaction ( ) ;
using var cmd = conn . CreateCommand ( ) ;
2022-11-29 18:21:52 +01:00
cmd . Transaction = trans ;
2021-05-01 11:41:33 +02:00
this . WriteChannels ( cmd , this . avbtChannels ) ;
this . WriteChannels ( cmd , this . avbcChannels ) ;
this . WriteChannels ( cmd , this . dvbtChannels ) ;
this . WriteChannels ( cmd , this . dvbcChannels ) ;
this . WriteChannels ( cmd , this . dvbsChannels ) ;
2023-06-03 10:38:11 +02:00
this . WriteChannels ( cmd , this . antIpChannels ) ;
this . WriteChannels ( cmd , this . cabIpChannels ) ;
this . WriteChannels ( cmd , this . satIpChannels ) ;
2021-05-01 11:41:33 +02:00
this . WriteChannels ( cmd , this . freesatChannels ) ;
trans . Commit ( ) ;
cmd . Transaction = null ;
this . RepairCorruptedDatabaseImage ( cmd ) ;
2013-04-21 22:04:06 +02:00
}
2013-06-25 23:45:40 +02:00
this . WriteCypheredFile ( ) ;
2013-04-21 22:04:06 +02:00
}
#endregion
#region WriteChannels ( )
2021-04-25 18:31:05 +02:00
private void WriteChannels ( SqliteCommand cmd , ChannelList channelList )
2013-04-21 22:04:06 +02:00
{
2021-09-22 23:46:03 +02:00
if ( channelList . Channels . Count = = 0 )
return ;
2023-06-03 10:38:11 +02:00
cmd . CommandText = "update SVL set major_channel=@progNr, sname=@sname, profile1index=@fav1, profile2index=@fav2, profile3index=@fav3, profile4index=@fav4, " +
"child_lock=@lock, skip=@skip, free_CA_mode=@encr where rowid=@rowid" ;
2013-06-25 23:45:40 +02:00
cmd . Parameters . Clear ( ) ;
2021-04-25 18:31:05 +02:00
cmd . Parameters . Add ( "@rowid" , SqliteType . Integer ) ;
cmd . Parameters . Add ( "@progNr" , SqliteType . Integer ) ;
2021-09-22 23:46:03 +02:00
cmd . Parameters . Add ( "@sname" , this . implicitUtf8 ? SqliteType . Text : SqliteType . Blob ) ; // must use "TEXT" when possible to preserve collation / case-insensitive sorting for the TV
2021-04-25 18:31:05 +02:00
cmd . Parameters . Add ( "@fav1" , SqliteType . Integer ) ;
cmd . Parameters . Add ( "@fav2" , SqliteType . Integer ) ;
cmd . Parameters . Add ( "@fav3" , SqliteType . Integer ) ;
cmd . Parameters . Add ( "@fav4" , SqliteType . Integer ) ;
cmd . Parameters . Add ( "@lock" , SqliteType . Integer ) ;
cmd . Parameters . Add ( "@skip" , SqliteType . Integer ) ;
2023-06-03 10:38:11 +02:00
cmd . Parameters . Add ( "@encr" , SqliteType . Integer ) ;
2013-04-21 22:04:06 +02:00
cmd . Prepare ( ) ;
2013-11-23 15:09:20 +01:00
foreach ( ChannelInfo channelInfo in channelList . Channels )
2013-04-21 22:04:06 +02:00
{
2013-11-23 15:09:20 +01:00
var channel = channelInfo as DbChannel ;
if ( channel = = null ) // skip reference list proxy channels
continue ;
2019-11-08 02:31:44 +01:00
if ( channel . IsDeleted & & channel . OldProgramNr > = 0 )
2013-06-25 23:45:40 +02:00
continue ;
2020-12-26 18:16:01 +01:00
channel . UpdateRawData ( this . explicitUtf8 , this . implicitUtf8 ) ;
2013-04-21 22:04:06 +02:00
cmd . Parameters [ "@rowid" ] . Value = channel . RecordIndex ;
2013-06-27 20:21:56 +02:00
cmd . Parameters [ "@progNr" ] . Value = channel . NewProgramNr ;
2021-09-22 23:46:03 +02:00
cmd . Parameters [ "@sname" ] . Value = this . implicitUtf8 ? channel . Name : channel . RawName ; // must use a string when possible to preserve collation / case-insensitive sorting for the TV
2013-06-25 23:45:40 +02:00
for ( int fav = 0 ; fav < 4 ; fav + + )
2021-03-13 18:11:30 +01:00
cmd . Parameters [ "@fav" + ( fav + 1 ) ] . Value = Math . Max ( 0 , channel . GetPosition ( fav + 1 ) ) ;
2013-06-25 23:45:40 +02:00
cmd . Parameters [ "@lock" ] . Value = channel . Lock ;
2013-04-21 22:04:06 +02:00
cmd . Parameters [ "@skip" ] . Value = channel . Skip ;
2023-06-03 10:38:11 +02:00
cmd . Parameters [ "@encr" ] . Value = channel . Encrypted ;
2013-04-21 22:04:06 +02:00
cmd . ExecuteNonQuery ( ) ;
}
2013-06-25 23:45:40 +02:00
// delete unassigned channels
cmd . CommandText = "delete from SVL where rowid=@rowid" ;
cmd . Parameters . Clear ( ) ;
2021-04-25 18:31:05 +02:00
cmd . Parameters . Add ( new SqliteParameter ( "@rowid" , DbType . Int32 ) ) ;
2013-06-28 10:13:12 +02:00
foreach ( ChannelInfo channel in channelList . Channels )
2013-06-25 23:45:40 +02:00
{
2019-11-08 02:31:44 +01:00
if ( channel . IsDeleted & & channel . OldProgramNr > = 0 )
2013-06-29 12:10:13 +02:00
{
cmd . Parameters [ "@rowid" ] . Value = channel . RecordIndex ;
cmd . ExecuteNonQuery ( ) ;
}
2013-06-25 23:45:40 +02:00
}
2023-06-03 10:38:11 +02:00
// remove unassigned/deleted transponders from TSL table
// add. info: only digital transponders should be deleted as import
// generates error when no analog transponders are found
cmd . CommandText = "delete from TSL where onid<>0 and physical_ch not in (select physical_ch from SVL where physical_ch is not null)" ;
cmd . Parameters . Clear ( ) ;
cmd . ExecuteNonQuery ( ) ;
2013-06-25 23:45:40 +02:00
}
#endregion
#region WriteCypheredFile ( )
private void WriteCypheredFile ( )
{
switch ( this . cypherMode )
{
case CypherMode . None :
break ;
case CypherMode . Encryption :
2013-06-28 15:10:14 +02:00
this . CypherFile ( this . workFile , this . FileName , true ) ;
2013-06-25 23:45:40 +02:00
break ;
case CypherMode . HeaderAndChecksum :
this . WriteFileWithHeaderAndChecksum ( ) ;
break ;
}
2013-04-12 00:47:50 +02:00
}
2013-04-21 22:04:06 +02:00
#endregion
2013-06-25 23:45:40 +02:00
#region WriteFileWithHeaderAndChecksum ( )
private void WriteFileWithHeaderAndChecksum ( )
{
long workFileSize = new FileInfo ( this . workFile ) . Length ;
byte [ ] data = new byte [ this . fileHeader . Length + workFileSize + 4 ] ;
Array . Copy ( fileHeader , data , fileHeader . Length ) ;
using ( var stream = new FileStream ( this . workFile , FileMode . Open , FileAccess . Read ) )
stream . Read ( data , fileHeader . Length , ( int ) workFileSize ) ;
2021-09-23 20:25:30 +02:00
Tools . SetInt32 ( data , this . dbSizeOffset , ( int ) workFileSize , this . headerByteOrder = = ByteOrder . LittleEndian ) ;
2013-06-29 16:44:47 +02:00
this . UpdateChecksum ( data ) ;
2013-06-25 23:45:40 +02:00
using ( var stream = new FileStream ( this . FileName , FileMode . Create , FileAccess . Write ) )
stream . Write ( data , 0 , data . Length ) ;
}
2013-06-29 16:44:47 +02:00
#endregion
2013-06-25 23:45:40 +02:00
2013-06-29 16:44:47 +02:00
#region UpdateChecksum ( )
private void UpdateChecksum ( byte [ ] data )
{
uint checksum = this . CalcChecksum ( data , data . Length - 4 ) ;
data [ data . Length - 1 ] = ( byte ) ( checksum & 0xFF ) ;
data [ data . Length - 2 ] = ( byte ) ( ( checksum > > 8 ) & 0xFF ) ;
data [ data . Length - 3 ] = ( byte ) ( ( checksum > > 16 ) & 0xFF ) ;
data [ data . Length - 4 ] = ( byte ) ( ( checksum > > 24 ) & 0xFF ) ;
}
2013-06-25 23:45:40 +02:00
#endregion
2013-11-09 16:30:59 +01:00
2013-11-20 02:42:47 +01:00
#region GetFileInformation ( )
2013-11-09 16:30:59 +01:00
public override string GetFileInformation ( )
{
StringBuilder sb = new StringBuilder ( ) ;
sb . Append ( base . GetFileInformation ( ) ) ;
sb . Append ( "Content type: " ) ;
switch ( this . GetCypherMode ( this . FileName ) )
{
case CypherMode . None : sb . AppendLine ( "unencrypted SQLite database" ) ; break ;
case CypherMode . Encryption : sb . AppendLine ( "encrypted SQLite database" ) ; break ;
case CypherMode . HeaderAndChecksum :
sb . AppendLine ( "embedded SQLite database" ) ;
2021-09-23 20:25:30 +02:00
sb . Append ( "Header byte order: " ) . AppendLine ( this . headerByteOrder . ToString ( ) ) ;
2013-11-09 16:30:59 +01:00
break ;
}
sb . Append ( "Character encoding: " ) . AppendLine ( this . charEncoding ) ;
return sb . ToString ( ) ;
}
2013-11-20 02:42:47 +01:00
#endregion
2013-04-12 00:47:50 +02:00
}
}