///
/// class SimZip
/// Compression/Decompression code to be used with SimFile format.
///
/// 18 Mar 2009 - D.Bozarth - Sonoma State Engineering Science
///
#region Using directives
using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using Utility;
#endregion
namespace SimFile
{
public class SimZip : SimFile
{
#region Constants
//
#region Version1.0
//
public const int HDR_FLG_SIZE = 1;
public const int HDR_SEG_SIZE = HDR_FLG_SIZE + 1; // Applies only to current version! (use for write only)
//
#endregion
#region VersionAll
//
public const byte HDR_FLG_SEMA = 0xff;
public const byte HDR_FLG_DFLT = 0x00;
public const byte HFLG_HDRJ_F = 0xfe; // Header Flag AND-bit mask: (Sweep Headers not jagged)
public const byte HFLG_HDRJ_T = 0x01; // Header Flag OR-bit mask: (Sweep Headers jagged)
public const byte HFLG_DATJ_F = 0xfd; // Header Flag AND-bit mask: (Signal Data not jagged)
public const byte HFLG_DATJ_T = 0x02; // Header Flag OR-bit mask: (Signal Data jagged)
public const string COMPRESS_EXE = @"c:\lzma\lzma.exe";
public const string DECOMPRESS_EXE = @"c:\lzma\lzma.exe";
public const string VERSION_HDR_FILE = @"..\..\version.hdr.txt";
public const string DATA_SZ_HDR_FILE = @"..\..\data.sz.hdr.lzma";
public const string DATA_SZ_TMP_FILE = @"..\..\data.sz.hdr.txt";
public const string cmFile0 = @"..\..\fileHdr.lzma";
public const string cmFile1 = @"..\..\fileHdr.raw";
public const string cmFile2 = @"..\..\swphdr.final.lzma";
public const string cmFile3 = @"..\..\swphdr.final.raw";
public const string cmFile4 = @"..\..\short.final.lzma";
public const string cmFile5 = @"..\..\short.final.raw";
public const string cmFile6 = @"..\..\abcde3.nis.lzma";
public const string cmFile7 = @"..\..\abcde3.nis.raw";
public const string cmFile8 = @"..\..\abcde012.raw";
public enum VerSupport { v1_0, None = -1 };
public enum ZipContent { FileHdr, SwpHdr, IntegerData, Signal012, Signal3 };
//
#endregion
//
#endregion
#region Contained classes of class SimZip
//
public class SimZipTest
{
static int Main( string[] args ) {
Io.Result rtn = Io.Result.OK;
SimZip zp = new SimZip();
try {
if ( args[0] == "e" ) {
rtn = zp.Compress( args[1], args[2], false);
} else {
if ( args[0] == "d" ) {
rtn = zp.Decompress( args[1], args[2] );
} else {
Console.WriteLine( "Syntax: SimZip [e|d] inFilePath outFilePath" );
}
}
} catch ( Exception ex ) {
Console.WriteLine( ex.Message );
Console.WriteLine( ex.StackTrace );
}
return (int) rtn;
} // method Main
} // class SimZipTest
public class SimZipException : ApplicationException
{
public SimZipException( String message ) : base( message )
{}
public SimZipException( String message, Exception inner ) : base( message, inner )
{}
}
//
#endregion
#region Methods of class SimZip
/*
* Limitation: inFile should have (size < Int32.MaxValue).
* szChkFlg: false => Normal operation. true => (inFile < outFile => delete outFile, return NoAction).
* Assumption: All samples are well-formed, including complete Integer and Signal components.
* .. (Thus FileContent.IntegerData can be used to determine jagged arrays for Integer, Bt3, and Bt012.)
* Returns OK, or NoAction. Throws SimZipException.
*/
public Io.Result Compress( string inFile, string outFile, bool szChkFlg ) {
string[] cmFiles
= { VERSION_HDR_FILE, DATA_SZ_HDR_FILE, cmFile0, cmFile2, cmFile4, cmFile6, cmFile8 };
Io.Result rtn = FileRead( inFile ); // rtn == OK unless exception thrown.
FileStream fs = File.OpenRead( inFile );
long szIn;
try {
szIn = fs.Length;
} catch ( Exception ex ) {
throw new SimZipException( "Caught in SimZip.Compress(string,string,bool)" , ex );
} finally {
fs.Close();
}
bool hdrJg, datJg;
int[] szAry;
int[] bufSize = { BUF_SIZE_DFLT };
int[] empty = new int[0];
rtn = FindJaggedContent( FileContent.SwpHdr, out hdrJg, out szAry );
rtn = FindJaggedContent( FileContent.IntegerData,out datJg, out szAry );
// rtn == OK unless exception thrown
// Build the 'Header Flags' byte array that will be stored (uncompressed)
// .. following the Version Id string.
byte[] hdrFlgs = new byte[1];
hdrFlgs[0] = 0x00;
if ( hdrJg ) hdrFlgs[0] |= HFLG_HDRJ_T;
if ( datJg ) hdrFlgs[0] |= HFLG_DATJ_T;
WriteVersionHeader( VERSION_HDR_FILE, hdrFlgs );
WriteDataSizeHeader( DATA_SZ_HDR_FILE, DATA_SZ_TMP_FILE, szAry, nBytesInt16PerSample );
// Encode the file header.
rtn = UnpackFileComponent(
cmFile0, cmFile1, FileContent.FileHdr, StreamProcessor.TransformCopyStream, bufSize
); // rtn == OK unless exception was thrown
StreamProcessor.Transform delegateTransform;
int[] intAry;
// Encode the sweep headers.
if ( hdrJg ) {
delegateTransform = StreamProcessor.TransformCopyStream;
intAry = bufSize;
} else {
delegateTransform = StreamProcessor.TransformTranspose;
intAry = empty;
}
rtn = UnpackFileComponent(
cmFile2, cmFile3, FileContent.SwpHdr, delegateTransform, intAry
);
// Encode the integer data.
if ( datJg ) {
delegateTransform = SimZip.TransformIntegerDataJg;
} else {
delegateTransform = SimZip.TransformIntegerData;
}
rtn = UnpackFileComponent(
cmFile4, cmFile5, FileContent.IntegerData, delegateTransform, empty
);
// Encode byte 3 of the signal data.
if ( datJg ) {
delegateTransform = SimZip.TransformSignalBt3Jg;
} else {
delegateTransform = SimZip.TransformSignalBt3;
}
rtn = UnpackFileComponent(
cmFile6, cmFile7, FileContent.SignalData, delegateTransform, empty
);
// Encode bytes 0-2 of the signal data.
if ( datJg ) {
delegateTransform = SimZip.TransformSignalBt012Jg;
} else {
delegateTransform = SimZip.TransformSignalBt012;
}
rtn = UnpackFileComponent(
cmFile8, "", FileContent.SignalData, delegateTransform, empty
);
Utility.FileProcessor.Catenate( outFile, cmFiles, true );
foreach ( string file in cmFiles ) File.Delete( file );
long szOut;
fs = File.OpenRead( outFile );
try {
szOut = fs.Length;
} catch ( Exception ex ) {
throw new SimZipException("Caught in SimZip.Compress(string,string,bool)", ex);
} finally {
fs.Close();
}
if ( szChkFlg && (szIn < szOut) ) {
File.Delete( outFile );
rtn = Io.Result.NoAction;
}
return rtn;
} // method Compress
/*
* Limitation: All files must have size < Int32.MaxValue .. May not work with Int64-sized files.
* Attempts to detect file format errors and returns BadFormat. Otherwise returns OK.
* Method throws no exception and ignores any callee exception.
*/
public Io.Result Decompress( string inFile, string outFile ) {
string[] cmFiles = { DATA_SZ_HDR_FILE, cmFile0, cmFile2, cmFile4, cmFile6, cmFile8 };
string verId;
byte[] flags;
Io.Result rtn = ReadVersionHeader( inFile, out verId, out flags );
if ( rtn == Io.Result.BadFormat ) return rtn;
VerSupport ver = ValidateVersion( verId );
bool hdrJg = false;
bool datJg = false;
switch ( ver ) { // Address version-specific concerns here.
case VerSupport.v1_0 :
hdrJg = (flags[0] & HFLG_HDRJ_T) != 0x00; // bit true => expect uneven Sweep Headers
datJg = (flags[0] & HFLG_DATJ_T) != 0x00; // bit true => expect uneven Sweep Data
break;
case VerSupport.None :
default : return Io.Result.BadFormat;
}
// Total header length includes semaphore byte + header length int.
int preSize = verId.Length + flags.Length + 1 + sizeof( Int32 );
rtn = FileProcessor.CopyFileMinusPrefix(inFile, cmFile1, preSize, BUF_SIZE_DFLT);
if ( rtn == Io.Result.BadIndex ) return Io.Result.BadFormat;
FileProcessor.Decatenate( cmFile1, cmFiles );
int[] szAry;
rtn = ReadDataSizeHeader( DATA_SZ_HDR_FILE, DATA_SZ_TMP_FILE, out szAry );
if ( rtn == Io.Result.BadFormat ) return rtn;
int[] bufSize = { BUF_SIZE_DFLT };
int[] empty = new int[0];
// Decode the file header.
rtn = PackFileComponent(
cmFile0, cmFile1, ZipContent.FileHdr, empty, StreamProcessor.TransformCopyStream, bufSize
); // OK unless exception was thrown
StreamProcessor.Transform delegateTransform;
int[] pass;
int[] mySzAry = new int[ szAry.Length ];
Array.Copy( szAry, mySzAry, szAry.Length );
int[] hwPre = new int[2];
hwPre[0] = -1;
hwPre[1] = szAry[0];
// Decode the sweep headers.
if ( hdrJg ) {
delegateTransform = StreamProcessor.TransformCopyStream;
pass = bufSize;
} else {
delegateTransform = StreamProcessor.TransformTranspose;
pass = empty;
}
rtn = PackFileComponent( cmFile2, cmFile3, ZipContent.SwpHdr, hwPre, delegateTransform, pass );
Array.Copy( szAry, mySzAry, szAry.Length );
mySzAry[0] = szAry[1] * nBytesInt16PerSample;
mySzAry[1] = szAry[0];
// Decode the integer data.
if ( datJg ) {
delegateTransform = SimZip.InvTransformIntegerDataJg;
} else {
delegateTransform = SimZip.InvTransformIntegerData;
}
rtn = PackFileComponent( cmFile4, cmFile5, ZipContent.IntegerData, mySzAry, delegateTransform, empty );
Array.Copy( szAry, mySzAry, szAry.Length );
mySzAry[0] *= nComponentsPerSample;
// Decode byte 3 of the signal data.
if ( datJg ) {
delegateTransform = SimZip.InvTransformSignalBt3Jg;
} else {
delegateTransform = SimZip.InvTransformSignalBt3;
}
rtn = PackFileComponent( cmFile6, cmFile7, ZipContent.Signal3, mySzAry, delegateTransform, empty );
// Note: cmFile7 has been re-written as a temporary file, will be interleaved with bytes 0-2.
Array.Copy( szAry, mySzAry, szAry.Length );
mySzAry[1] *= 3 * nComponentsPerSample; // 3 of the 4 bytes of each Single precision numeric value.
// Decode bytes 0-2 of the signal data.
if ( datJg ) {
delegateTransform = SimZip.InvTransformSignalBt012Jg;
pass = empty;
} else {
delegateTransform = StreamProcessor.TransformCopyStream;
pass = bufSize;
}
rtn = PackFileComponent(
// Note: cmFile7 will be read from disk, but is not the decoding target.
cmFile8, cmFile7, ZipContent.Signal012, mySzAry, delegateTransform, pass
);
foreach (string file in cmFiles) File.Delete(file);
return FileWrite( outFile );
} // method Decompress
/*
* Accept SizeArray data.
* Build the "Data Size" byte array and store in a separate, compressed header file.
* Throws SimZipException.
*/
private void WriteDataSizeHeader( string outFile, string tmpFile, int[] szAry, int scale ) {
byte[] szBytes = new byte[szAry.Length * nBytesPerInt32];
for ( int i = 0; i < szAry.Length; ++i ) {
int next = szAry[i];
if ( 0 < i ) {
// Normalize the width values to represent #samples, not #bytes.
if ( 0 < next ) {
if ( 0 < next % scale ) {
throw new SimZipException( "Arithmetic error in WriteDataSizeHeader" );
}
next /= scale;
}
}
byte[] oneInt32 = BitConverter.GetBytes( next );
Array.Copy( oneInt32, 0, szBytes, i * nBytesPerInt32, nBytesPerInt32 );
}
FileStream tmpStream = File.OpenWrite( tmpFile );
try {
tmpStream.Write( szBytes, 0, szBytes.Length );
} catch ( Exception ex ) {
string msg = "Caught in SimZip.WriteDataSizeHeader(string,string,int[],int) call Stream.Write";
throw new SimZipException( msg, ex );
} finally {
tmpStream.Close();
}
RunCompress( tmpFile, outFile, false );
File.Delete( tmpFile );
} // method WriteDataSizeHeader
/*
* Read the "Data Size" byte array from a separate, compressed header file.
* Build and return SizeArray data.
* Returns OK or BadFormat. Throws SimZipException.
*/
private Io.Result ReadDataSizeHeader( string inFile, string tmpFile, out int[] szAry ) {
RunCompress( inFile, tmpFile, true );
// tmpFile now contains decompressed size data.
int bufSz;
int outSz;
byte[] buf;
FileStream tmpStream = File.OpenRead( tmpFile );
if ( 0 < tmpStream.Length % nBytesPerInt32 ) {
tmpStream.Close();
szAry = new int[0];
return Io.Result.BadFormat;
}
Io.Result rtn = Io.Result.OK;
try {
bufSz = (int) tmpStream.Length;
outSz = bufSz / nBytesPerInt32;
buf = new byte[ bufSz ];
szAry = new int[ outSz ];
rtn = StreamProcessor.ReadByteStream( buf, 0, bufSz, tmpStream );
} catch ( Exception ex ) {
string msg = "Caught in SimZip.ReadDataSizeHeader(string,string,int[],int)";
throw new SimZipException( msg, ex );
} finally {
tmpStream.Close();
File.Delete( tmpFile );
}
switch ( rtn ) {
case Io.Result.BadIndex :
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.ReadDataSizeHeader(string,string,int[]): '" +tag+ "' signal from StreamProcessor.ReadByteStream";
throw new SimZipException( msg );
case Io.Result.OK : break;
}
for ( int i = 0; i < outSz; ++i ) {
szAry[i] = BitConverter.ToInt32( buf, i * nBytesPerInt32 );
}
return Io.Result.OK;
}
/*
* flgBytes[ 0 ] : Flags byte
* flgBytes[ 1 .. 4]: Int32 #rows
* flgBytes[ 5 .. 8]: Int32 min row width in #samples
* flgBytes[ 9 .. n]: One integer per row, indicates #samples "over" min row width
*/
private void WriteVersionHeader( string outFile, byte[] flgBytes ) {
int idLen = VERSION_ID.Length;
byte[] toFile = new byte[ idLen + 1 + flgBytes.Length ];
for ( int i = 0; i < idLen; ++i ) {
toFile[i] = (byte) VERSION_ID[i];
}
toFile[ idLen ] = HDR_FLG_SEMA; // Mark end of Version Id.
for ( int i = 0; i < flgBytes.Length; ++i ) { // Add flag byte plus array size configuration.
toFile[idLen + 1 + i] = flgBytes[ i ];
}
File.Delete( outFile );
FileStream fs = File.OpenWrite( outFile );
try {
fs.Write( toFile, 0, toFile.Length );
} catch ( Exception ex ) {
throw new SimZipException("Caught in SimZip.WriteVersionHeader(string,byte) call Stream.Write(byte[],int,int)", ex);
} finally {
fs.Close();
}
} // method WriteVersionHeader
/*
* Will recognize in a variable number of flag bytes.
* Version 1.0, however, uses a single flag byte, so the size of flags should be 1 upon return.
* Returns OK, or BadFormat. Throws SimZipException.
*/
private Io.Result ReadVersionHeader( string inFile, out string verId, out byte[] flags ) {
verId = "";
flags = new byte[0];
char[] verChars = new char[0];
byte[] flgBytes = new byte[0];
Io.Result rtn = Io.Result.OK;
int nSz = sizeof( Int32 );
FileStream fs = File.OpenRead( inFile );
try {
byte[] szBytes = new byte[ nSz ];
fs.Read( szBytes, 0, nSz );
int toRead = BitConverter.ToInt32( szBytes, 0 );
// Protect against excessive read length from incorrectly formatted file.
toRead = GetNbrBytesToReadAsVersion( toRead );
byte[] hdrBytes = new byte[ toRead ];
int verSz = 0;
int flgSz = -1;
rtn = StreamProcessor.ReadByteStream( hdrBytes, 0, toRead, fs );
if ( rtn != Io.Result.BadIndex ) {
for ( int i = 0; i < toRead; ++i ) {
if ( flgSz < 0 ) {
if ( hdrBytes[i] != HDR_FLG_SEMA ) {
verSz += 1;
} else {
flgSz += 1;
}
} else {
flgSz += 1;
}
}
} else { // Parameters don't work; 'BadIndex' detected; verSz == 0.
flgSz += 1;
}
if ( verSz == 0 || flgSz < 0 ) {
rtn = Io.Result.BadFormat;
}
if ( rtn != Io.Result.BadFormat ) {
verChars = new char[ verSz ];
flgBytes = new byte[ flgSz ];
for ( int i = 0; i < verSz; ++i ) {
verChars[i] = (char) hdrBytes[i];
}
for ( int i = 0; i < flgSz; ++i ) {
flgBytes[i] = hdrBytes[verSz + 1 + i];
}
}
} catch ( Exception ex ) {
throw new SimZipException("Caught in SimZip.ReadVersionHeader(string,string,byte[])", ex);
} finally {
fs.Close();
}
if ( rtn != Io.Result.BadFormat ) {
verId = new string( verChars );
flags = flgBytes;
// Check integrity among total header bytes, bytes read, version id, and flags length.
if ( rtn == Io.Result.OK ) {
rtn = Io.Result.BadFormat;
for ( int i = 0; i < verSupported.Length; ++i ) {
if ( verId == verSupported[i] ) {
if ( flags.Length + 1 == flgSupported[i] ) {
rtn = Io.Result.OK;
break;
}
}
}
}
}
return rtn;
} // method ReadVersionHeader
/*
* Determine whether the string contains a valid Version Id.
*/
private VerSupport ValidateVersion( string verId ) {
for ( int i = 0; i < verSupported.Length; ++i ) {
if ( verSupported[i] == verId ) return (VerSupport) i;
}
return VerSupport.None;
}
/*
* Return the lesser of:
* (a) the input value, or
* (b) the maximum string length from the collection of supported Version Id strings.
* (Purpose is to limit the number of bytes the caller will later read from a bad-format file.)
*/
private int GetNbrBytesToReadAsVersion( int tryMe ) {
int max = 0;
if ( tryMe < 0 ) tryMe = Int32.MaxValue;
for ( int i = 0; i < verSupported.Length; ++i ) {
string s = verSupported[i];
int flgSz = flgSupported[i];
int test = s.Length + flgSz;
if ( max < test ) max = test;
}
return max < tryMe ? max : tryMe;
} // method GetNbrBytesToReadAsVersion
/*
* Inspects the tmp array formed (in the expected way) from a SimFile object queried with fc.
* Post: If the tmp array is rectangular, then isJag == false. Otherwise, isJag == true.
* .. szAry has the following structure by position k, describing the tmp array:
* .. .. 0 : #rows
* .. .. 1 : min #cols over all rows
* .. .. 2->(n-1) : (#cols in row# (k-2)) - szAry[1] .. note this represents "excess #cols"
* .. Note that (isJag == true) <=> (szAry.Length == 2 + szAry[0])
* .. Note that (isJag == false) <=> (szAry.Length == 2)
* Note that the content of szAry controls just about everything else in this package!
* Returns OK. Throws SimZipException.
*/
private Io.Result FindJaggedContent( FileContent fc, out bool isJag, out int[] szAry ) {
isJag = false;
Io.Result rtn = Io.Result.OK;
Stream memStream = new MemoryStream();
try {
rtn = UnpackFileComponent( memStream, fc, out szAry );
// rtn == OK unless exception thrown
} catch ( Exception ex ) {
throw new SimZipException("Caught in SimZip.FindJaggedContent(FileContent,bool) call UnpackFileComponent(Stream,FileContent,Pair)", ex);
} finally {
memStream.Close();
}
isJag = (2 < szAry.Length); // Detect jagged array.
return rtn;
} // method FindJaggedContent
/*
* Purpose is to adapt a standard configuration to various transform parameters.
* Throws SimZipException.
*/
private static void ScaleSzAryWidths( int[] szAry, double scale ) {
for ( int i = 1; i < szAry.Length; ++i ) {
double test = (double) szAry[i] * scale;
if ( Math.Floor( test ) != test ) {
string msg = "Arithmetic error in SimZip.ScaleSzAryWidths(int[],double)";
throw new SimZipException( msg );
}
szAry[i] = (int) test;
}
} // method ScaleSzAryWidths
/*
* Populate outFile with the transformed SimFile content specified by fc.
* If parameters is an empty array,
* .. then (internally built) szAry will be passed in to transform.
* .. Otherwise, parameters will be passed in to transform.
* If rawFile is an empty string, then outFile will not be compressed.
* .. Otherwise, outFile will be compressed, and rawFile will be deleted.
* Returns OK. Throws SimZipException.
*/
public Io.Result UnpackFileComponent
( string outFile, string rawFile, FileContent fc,
StreamProcessor.Transform transform, int[] parameters
){
int[] pass;
int[] szAry;
Stream rawStream;
Io.Result rtn = Io.Result.OK;
bool cmpFlg = (0 < rawFile.Length) ? true : false;
if ( cmpFlg ) {
File.Delete( rawFile );
rawStream = File.OpenWrite( rawFile );
} else {
rawStream = new MemoryStream();
}
try {
Stream memStream = new MemoryStream();
try {
rtn = UnpackFileComponent( memStream, fc, out szAry );
// rtn == OK unless exception thrown
pass = (parameters.Length == 0) ? szAry : parameters;
memStream.Position = 0;
rtn = transform( memStream, rawStream, pass );
} catch ( Exception ex ) {
string msg = "Caught in SimZip.UnpackFileComponent(string,string,FileContent,StreamProcessor.Transform,int[])";
throw new SimZipException( msg, ex );
} finally {
memStream.Close();
}
} catch ( Exception ex ) {
rawStream.Close();
string msg = "Caught in SimZip.UnpackFileComponent(string,string,FileContent,StreamProcessor.Transform,int[])";
throw new SimZipException( msg, ex );
}
switch ( rtn ) {
case Io.Result.Mismatch :
case Io.Result.Underflow :
case Io.Result.Overflow :
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.UnpackFileComponent(string,string,FileContent,StreamProcessor.Transform,int[]): '"+tag+"' signal from StreamProcessor.Transform";
throw new SimZipException( msg );
case Io.Result.OK : break;
}
if ( cmpFlg ) {
rawStream.Close();
File.Delete( outFile );
RunCompress( rawFile, outFile, false ); // Compress
File.Delete( rawFile );
} else {
rawStream.Position = 0;
FileStream outStream = File.OpenWrite( outFile );
try {
StreamProcessor.CopyStream( rawStream, outStream, BUF_SIZE_DFLT );
outStream.SetLength( rawStream.Length );
} catch ( Exception ex ) {
string msg = "Caught in SimZip.UnpackFileComponent(string,string,FileContent,StreamProcessor.Transform,int[]) call StreamProcessor.CopyStream(Stream,Stream,int)";
throw new SimZipException( msg, ex );
} finally {
outStream.Close();
rawStream.Close();
}
}
return rtn;
} // method UnpackFileComponent
/*
* Populate outStream with the native SimFile content specified by fc.
* Populate szAry with standard scale.
* Returns OK. Throws no exception, ignores any exception thrown by callee.
*/
public Io.Result UnpackFileComponent( Stream outStream, FileContent fc, out int[] szAry ) {
Io.Result rtn = LoadByteBlock( fc );
// rtn == OK unless exception thrown.
int wmin;
int[] extra;
Pair scale = GetByteBlockScale( out wmin, out extra );
szAry = new int[2 + extra.Length];
szAry[0] = scale.First; // height
szAry[1] = wmin; // min width
for ( int i = 0; i < extra.Length; ++i ) {
szAry[2 + i] = extra[i];
}
return StreamWrite( outStream, fc ); // OK unless exception thrown.
} // method UnpackFileComponent
/*
* Decompresses and interprets content of inFile according to zc and szAry.
* Transforms the content according to zc, and transParm (if nonempty) or szAry.
* Returns OK. Throws SimZipException.
*/
public Io.Result PackFileComponent (
string inFile, string rawFile, ZipContent zc, int[] szAry,
StreamProcessor.Transform transform, int[] transParm
){
FileContent fc;
switch ( zc ) {
case ZipContent.FileHdr : fc = FileContent.FileHdr; break;
case ZipContent.SwpHdr : fc = FileContent.SwpHdr; break;
case ZipContent.IntegerData : fc = FileContent.IntegerData; break;
case ZipContent.Signal3 : fc = FileContent.SignalData; break;
case ZipContent.Signal012 : fc = FileContent.SignalData; break;
default : return Io.Result.NoAction;
}
FileStream inStream;
FileStream s3Stream;
Io.Result rtn = Io.Result.OK;
MemoryStream rawStream = new MemoryStream();
try {
MemoryStream memStream = new MemoryStream();
try {
if ( 0 < rawFile.Length && zc != ZipContent.Signal012 ) { // Hokey patch using zc.
RunCompress( inFile, rawFile, true ); // Decompress
inStream = File.OpenRead( rawFile );
} else {
inStream = File.OpenRead( inFile );
}
try {
StreamProcessor.CopyStream( inStream, memStream, BUF_SIZE_DFLT );
if ( zc == ZipContent.SwpHdr ) {
szAry[0] = (int) ( memStream.Length / NbrSweeps );
}
} catch ( Exception ex ) {
string msg = "Caught in SimZip.PackFileComponent(string,string,ZipContent,int[],StreamProcessor.Transform,int[])";
throw new SimZipException( msg, ex );
} finally {
inStream.Close();
}
// szAry now enables transform based on zc.
memStream.Position = 0;
int[] pass;
pass = (0 < transParm.Length) ? transParm : szAry;
rtn = transform( memStream, rawStream, pass );
} catch ( Exception ex ) {
string msg = "Caught in SimZip.PackFileComponent(string,string,ZipContent,int[],StreamProcessor.Transform,int[])";
throw new SimZipException(msg, ex);
} finally {
memStream.Close();
}
switch ( rtn ) {
case Io.Result.BadFormat :
case Io.Result.Mismatch :
case Io.Result.Underflow :
case Io.Result.Overflow :
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.PackFileComponent(string,string,ZipContent,int[],StreamProcessor.Transform,int[]): '" + tag + "' signal from StreamProcessor.Transform";
throw new SimZipException( msg );
case Io.Result.OK : break;
}
rawStream.Position = 0;
switch ( zc ) {
case ZipContent.Signal3 :
File.Delete( rawFile );
s3Stream = File.OpenWrite( rawFile );
try {
StreamProcessor.CopyStream( rawStream, s3Stream, BUF_SIZE_DFLT );
} catch ( Exception ex ) {
string msg = "Caught in SimZip.PackFileComponent(string,string,ZipContent,int[],StreamProcessor.Transform,int[]) call StreamProcessor.CopyStream(Stream,Stream,int)";
throw new SimZipException(msg, ex);
} finally {
s3Stream.Close();
}
break;
case ZipContent.Signal012 :
MemoryStream s012Stream = new MemoryStream();
try {
s3Stream = File.OpenRead( rawFile );
try {
StreamProcessor.CopyStream( rawStream, s012Stream, BUF_SIZE_DFLT );
rawStream.SetLength(0);
s012Stream.Position = 0;
Stream[] mergeThese = { s012Stream, s3Stream };
int[] counts = { 3, 1 };
StreamProcessor.MergeStreams( rawStream, mergeThese, counts );
} catch ( Exception ex ) {
string msg = "Caught in SimZip.PackFileComponent(string,string,ZipContent,Pair,StreamProcessor.Transform,int[])";
throw new SimZipException( msg, ex );
} finally {
s3Stream.Close();
}
} catch ( Exception ex ) {
string msg = "Caught in SimZip.PackFileComponent(string,string,ZipContent,Pair,StreamProcessor.Transform,int[])";
throw new SimZipException(msg, ex);
} finally {
s012Stream.Close();
}
rawStream.Position = 0;
rtn = StreamRead( rawStream, fc );
break;
default : // Not processing a signal component.
rtn = StreamRead( rawStream, fc, 0, NbrSweeps );
break;
}
} catch ( Exception ex ) {
string msg = "Caught in SimZip.PackFileComponent(string,string,ZipContent,Pair,StreamProcessor.Transform,int[])";
throw new SimZipException(msg, ex);
} finally {
rawStream.Close();
}
if ( rtn != Io.Result.OK ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.PackFileComponent(string,string,ZipContent,int[],StreamProcessor.Transform,int[]): '" + tag + "' signal from SimFile.StreamRead";
throw new SimZipException( msg );
}
if ( 0 < rawFile.Length && zc != ZipContent.Signal3 ) File.Delete( rawFile );
return rtn;
} // method PackFileComponent
/*
* decoFlg: false => compress, true = decompress
*/
public void RunCompress( string inFile, string outFile, bool decoFlg ) {
File.Delete( outFile );
Process p = new Process();
p.StartInfo.FileName = COMPRESS_EXE;
p.StartInfo.Arguments = BuildCompressArgs( inFile, outFile, decoFlg );
p.Start();
while ( ! p.HasExited )
{}
}
/*
* Used by RunCompress.
*/
private string BuildCompressArgs( string file1, string file2, bool decoFlg ) {
string code = decoFlg ? "d " : "e ";
string rtn;
/**/
rtn = code + file1 + " " + file2;
/**/
/*
// apply command-line switch(es)
string sw = "-pb4 -lp2";
rtn = code + file1 + " " + file2 + " " + sw;
*/
return rtn;
}
/*
* Pre: hw contains the height, width of the superarray.
* inStream.Length == h * w
* h equals NbrSweeps.
* (nBytesIntegerPerSample * nComponentsPerSample) divides w.
* Post: outStream is transformed from inStream, for optimal dictionary compression.
* Implements the Matlab function sig = transpose([s1 s2 s3 s4 s5 s6 s7 s8])
* .. where s1 is the segregation of all "1 of 8" bytes of inStream,
* .. s2 is the segregation of all "2 of 8" bytes of inStream, etc.
* (This is a performance bottleneck because of several calls to PickPeriodicValues.)
* Returns OK, or Mismatch. Throws SimZipException.
*/
public static Io.Result TransformIntegerData( Stream inStream, Stream outStream, int[] hw ) {
int h = hw[0];
int w = hw[1];
int cMod = nBytesIntegerPerSample;
int pRem = w % cMod;
if ( pRem != 0 ) return Io.Result.Mismatch;
byte[,] buf = new byte[h, w];
Io.Result rtn = StreamProcessor.StreamToArray2D( inStream, buf );
switch ( rtn ) {
case Io.Result.Underflow :
case Io.Result.Overflow :
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.TransformIntegerData(Stream,Stream,int[]): '"+tag+"' signal from StreamProcessor.StreamToArray2D";
throw new SimZipException( msg );
case Io.Result.OK : break;
}
int pSz = w / cMod;
int[] rNdx = {0};
int rMod = 0;
byte[,] mat = new byte[h, w];
int[] cNdx = new int[1];
for ( int i = 0; i < cMod; ++i ) {
cNdx[0] = i;
byte[,] pick = ByteArrayManipulator.PickPeriodicValues( buf, rNdx, rMod, cNdx, cMod );
ByteArrayManipulator.CopyArrayByColumn( mat, 0, i * pSz, pick );
}
buf = ByteArrayManipulator.Transpose( mat );
StreamProcessor.Array2DToStream( outStream, buf );
return rtn;
} // method TransformIntegerData
/*
* Version of TransformIntegerData, for jagged arrays.
* Returns OK. Throws SimZipException.
*/
public static Io.Result TransformIntegerDataJg( Stream inStream, Stream outStream, int[] szAry ) {
StreamProcessor.Transform delegateTransform = SimZip.TransformIntegerData;
int[] pick = new int[0];
int from = 0;
Io.Result rtn
= TransformJaggedFileComponent(inStream, outStream, delegateTransform, szAry, pick, from);
if ( rtn != Io.Result.OK ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.TransformIntegerDataJg(Stream,Stream,int[]): '"+tag+"' signal from SimZip.TransformJaggedFileComponent";
throw new SimZipException( msg );
}
return rtn;
} // method TransformIntegerDataJg
/*
* Pre: inStream.Length == h * w
* h equals NbrSweeps.
* nComponentsPerSample divides w.
* Post: outStream is transformed from inStream, for optimal compression.
* Implements the Matlab function sig = [ar3; ai3; br3; bi3; cr3; ci3; dr3; di3; er3; ei3]
* .. where ar3 is the segregation of all "4 of 4" bytes of the A Real component of inStream,
* .. bi3 is the segregation of all "4 of 4" bytes of the B Imaginary component of inStream, etc.
* Returns OK, or Mismatch. Throws SimZipException.*
*/
public static Io.Result TransformSignalBt3( Stream inStream, Stream outStream, int[] hw ) {
int h = hw[0];
int w = hw[1];
int cMod = nBytesPerComponent;
int pRem = w % cMod;
if ( pRem != 0 ) return Io.Result.Mismatch;
byte[,] buf = new byte[h, w];
Io.Result rtn = StreamProcessor.StreamToArray2D( inStream, buf );
switch ( rtn ) {
case Io.Result.Underflow :
case Io.Result.Overflow :
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.TransformSignalBt3(Stream,Stream,int[]): '"+tag+"' signal from StreamProcessor.StreamToArray2D";
throw new SimZipException( msg );
case Io.Result.OK : break;
}
// Isolate byte# 3 --> bt3.
int[] rNdx = {0};
int rMod = 0;
int[] cNdx = new int[1];
cNdx[0] = 3;
byte[,] bt3 = ByteArrayManipulator.PickPeriodicValues( buf, rNdx, rMod, cNdx, cMod );
// Transform bt3.
cMod = nComponentsPerSample;
int b = bt3.GetLength(1);
pRem = b % cMod;
if ( pRem != 0 ) return Io.Result.Mismatch;
int pSz = b / cMod;
int a = bt3.GetLength(0);
byte[,] mat = new byte[a * cMod, pSz];
for ( int i = 0; i < cMod; ++i ) {
cNdx[0] = i;
byte[,] pick = ByteArrayManipulator.PickPeriodicValues( bt3, rNdx, rMod, cNdx, cMod );
ByteArrayManipulator.CopyArrayByColumn( mat, i * a, 0, pick );
}
StreamProcessor.Array2DToStream( outStream, mat );
return rtn;
} // method TransformSignalBt3
/*
* Version of TransformSignalBt3, for jagged arrays.
* Returns OK. Throws SimZipException.
*/
public static Io.Result TransformSignalBt3Jg( Stream inStream, Stream outStream, int[] szAry ) {
StreamProcessor.Transform delegateTransform = SimZip.TransformSignalBt3;
int[] pick = { 3 };
int from = 4;
Io.Result rtn
= TransformJaggedFileComponent(inStream, outStream, delegateTransform, szAry, pick, from);
if ( rtn != Io.Result.OK ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.TransformSignalBt3Jg(Stream,Stream,int[]): '"+tag+"' signal from SimZip.TransformJaggedFileComponent";
throw new SimZipException( msg );
}
return rtn;
} // method TransformSignalBt3Jg
/*
* All this does is to isolate the first 3 bytes of each Int32 in the signal component.
* No transformation is done on the isolated bytes.
* Returns OK, or Mismatch. Throws SimZipException.
*/
public static Io.Result TransformSignalBt012( Stream inStream, Stream outStream, int[] hw ) {
int h = hw[0];
int w = hw[1];
int cMod = nBytesPerComponent;
int pRem = w % cMod;
if ( pRem != 0 ) return Io.Result.Mismatch;
byte[,] buf = new byte[h, w];
Io.Result rtn = StreamProcessor.StreamToArray2D( inStream, buf );
switch ( rtn ) {
case Io.Result.Underflow :
case Io.Result.Overflow :
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.TransformSignalBt012(Stream,Stream,int[]): '"+tag+"' signal from StreamProcessor.StreamToArray2D";
throw new SimZipException( msg );
case Io.Result.OK : break;
}
// Isolate byte#s 0,1,2 --> bt012.
int[] rNdx = {0};
int rMod = 0;
int[] cNdx = {0, 1, 2};
byte[,] bt012 = ByteArrayManipulator.PickPeriodicValues( buf, rNdx, rMod, cNdx, cMod );
StreamProcessor.Array2DToStream( outStream, bt012 );
return rtn;
} // method TransformSignalBt012
/*
* Version of TransformSignalBt012, for jagged arrays.
* Returns OK. Throws SimZipException.
*/
public static Io.Result TransformSignalBt012Jg( Stream inStream, Stream outStream, int[] szAry ) {
StreamProcessor.Transform delegateTransform = SimZip.TransformSignalBt012;
int[] pick = { 0, 1, 2 };
int from = 4;
Io.Result rtn
= TransformJaggedFileComponent(inStream, outStream, delegateTransform, szAry, pick, from);
if ( rtn != Io.Result.OK ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.TransformSignalBt012Jg(Stream,Stream,int[]): '"+tag+"' signal from SimZip.TransformJaggedFileComponent";
throw new SimZipException( msg );
}
return rtn;
} // method TransformSignalBt012Jg
/*
* Adapt a jagged file component to a rectangular transform in the following manner:
* .. Form a new rectangular array using the minimum row width from szAry[1].
* .. Collect the excess bytes in a temporary stream.
* .. Transform the rectangular array in the standard manner, and stream the transformed bytes.
* .. Append the excess bytes to the stream.
* pick and from are set by the caller, and may assist with further separation
* .. of components from a composite input stream; e.g., SignalData -> SignalBt012 + SignalBt3
* Returns Mismatch, Underflow, NoAction, or OK. Throws SimZipException.
*/
public static Io.Result TransformJaggedFileComponent
( Stream inStream,
Stream outStream,
StreamProcessor.Transform transformRectangular,
int[] szAry,
int[] pick,
int from
){
if ( szAry.Length < 3 ) return Io.Result.NoAction;
int height = szAry[0];
int wmin = szAry[1];
int lim = szAry.Length - 2;
int[] extra = new int[ lim ];
int i;
for ( i = 0; i < lim; ++i ) {
extra[i] = szAry[2 + i];
}
i = 0;
int j = 0;
inStream.Position = 0;
Io.Result rtn = Io.Result.OK;
byte[,] reduced = new byte[height, wmin];
MemoryStream spilled = new MemoryStream();
try {
// Separate the rectangular portion from the spillover portion of the data.
while ( inStream.Position < inStream.Length ) {
int next;
if ( j == wmin ) {
lim = extra[i];
if ( 0 < lim ) {
byte[,] spill = new byte[1, lim];
int[] zero = { 0 };
for ( int k = 0; k < lim; ++k ) {
next = inStream.ReadByte();
if ( next == -1 ) {
spilled.Close();
return Io.Result.Underflow;
}
spill[0, k] = (byte) next;
}
byte[,] mySpill;
if ( from != 0 ) {
mySpill = ByteArrayManipulator.PickPeriodicValues( spill, zero, 0, pick, from );
} else {
mySpill = spill;
}
for ( int k = 0; k < mySpill.GetLength( 1 ); ++k ) {
spilled.WriteByte( mySpill[0, k] );
}
}
i += 1;
j = 0;
} else {
next = inStream.ReadByte();
if ( next == -1 ) {
spilled.Close();
return Io.Result.Underflow;
}
reduced[i, j] = (byte) next;
j += 1;
}
}
if ( !(i == height && j == 0) && !(i + 1 == height && j == wmin)) {
spilled.Close();
return Io.Result.Mismatch;
}
spilled.Position = 0;
// The key (szAry) and the spillover portion are ready for outStream.
MemoryStream rectOut = new MemoryStream();
MemoryStream rectIn = new MemoryStream();
try {
try {
for ( i = 0; i < height; ++i ) {
for ( j = 0; j < wmin; ++j ) {
rectIn.WriteByte( reduced[i, j] );
}
}
rectIn.Position = 0;
int[] hw = { height, wmin };
rtn = transformRectangular( rectIn, rectOut, hw );
} catch ( Exception ex ) {
string msg = "Caught in SimZip.TransformJaggedFileComponent(Stream,Stream,StreamProcessor.Transform(Stream,Stream,int[]),int[])";
throw new SimZipException( msg, ex );
} finally {
rectIn.Close();
}
if ( rtn == Io.Result.OK ) {
rectOut.Position = 0;
// The transformed rectangular portion (rectOut) is ready for outStream.
outStream.Position = 0;
byte[] oneInt32 = new byte[ nBytesPerInt32 ];
// Write everything to outStream.
while ( rectOut.Position < rectOut.Length ) {
byte next = (byte) rectOut.ReadByte();
outStream.WriteByte( next );
}
}
} catch ( Exception ex ) {
string msg = "Caught in SimZip.TransformJaggedFileComponent(Stream,Stream,StreamProcessor.Transform(Stream,Stream,int[]),int[])";
throw new SimZipException( msg, ex );
} finally {
rectOut.Close();
}
if ( rtn == Io.Result.OK ) {
while ( spilled.Position < spilled.Length ) {
byte next = (byte) spilled.ReadByte();
outStream.WriteByte( next );
}
}
} catch ( Exception ex ) {
string msg = "Caught in SimZip.TransformJaggedFileComponent(Stream,Stream,StreamProcessor.Transform(Stream,Stream,int[]),int[])";
throw new SimZipException( msg, ex );
} finally {
spilled.Close();
}
if ( rtn != Io.Result.OK ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.TransformJaggedFileComponent(Stream,Stream,StreamProcessor.Transform,int[],int[],int): '" + tag + "' signal from StreamProcessor.Transform";
throw new SimZipException( msg );
}
return rtn;
} // method TransformJaggedFileComponent
/*
* Pre: inStream.Length matches h * w.
* (nBytesIntegerPerSample * nComponentsPerSample) divides h.
* w equals NbrSweeps
* Post: outStream is suitable for ReadStreamData( FileComponent.IntegerData )
* This is the inverse transform of TransformIntegerData.
* Returns Mismatch, or OK. Throws SimZipException.
*/
public static Io.Result InvTransformIntegerData( Stream inStream, Stream outStream, int[] hw ) {
int h = hw[0];
int w = hw[1];
byte[,] mat = new byte[h, w];
Io.Result rtn = StreamProcessor.StreamToArray2D( inStream, mat );
switch ( rtn ) {
case Io.Result.Underflow :
case Io.Result.Overflow :
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.InvTransformIntegerData(Stream,Stream,int[]): '"+tag+"' signal from StreamProcessor.StreamToArray2D";
throw new SimZipException( msg );
case Io.Result.OK : break;
}
byte[,] tam = ByteArrayManipulator.Transpose( mat );
int cMod = h;
int pRem = h % nBytesIntegerPerSample;
if ( pRem != 0 ) return Io.Result.Mismatch;
int pSz = h / nBytesIntegerPerSample;
int[] rNdx = {0};
int rMod = 0;
int[] cNdx = new int[pSz];
Stream[] sAry = new Stream[ nBytesIntegerPerSample ];
int[] counts = new int[ nBytesIntegerPerSample ];
try {
for ( int i = 0; i < nBytesIntegerPerSample; ++i ) {
for ( int j = 0; j < pSz; ++j ) cNdx[j] = i * pSz + j;
counts[i] = 1;
MemoryStream memStream = new MemoryStream();
byte[,] pick = ByteArrayManipulator.PickPeriodicValues( tam, rNdx, rMod, cNdx, cMod );
StreamProcessor.Array2DToStream( memStream, pick );
memStream.Position = 0;
sAry[i] = memStream;
}
StreamProcessor.MergeStreams( outStream, sAry, counts );
} catch ( Exception ex ) {
string msg = "Caught in SimZip.InvTransformIntegerData(Stream,Stream,int[])";
throw new SimZipException( msg, ex );
} finally {
foreach ( Stream s in sAry ) s.Close();
}
return rtn;
} // method InvTransformIntegerData
/*
* Version of InvTransformIntegerData, for jagged arrays.
* Returns OK, or BadFormat. Throws SimZipException.
*/
public static Io.Result InvTransformIntegerDataJg( Stream inStream, Stream outStream, int[] szAry ) {
if ( szAry[0] % nBytesInt16PerSample != 0 ) return Io.Result.BadFormat;
int[] hw = new int[2];
hw[0] = szAry[0];
hw[1] = szAry[1];
szAry[0] = szAry[1];
szAry[1] = hw[0] / nBytesInt16PerSample;
ScaleSzAryWidths( szAry, (double) nBytesInt16PerSample );
Io.Result rtn
= InvTransformJaggedFileComponent(inStream, outStream, InvTransformIntegerData, szAry, hw);
if ( rtn != Io.Result.OK ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.InvTransformIntegerDataJg(Stream,Stream,int[]): '"+tag+"' signal from SimZip.InvTransformJaggedFileComponent";
throw new SimZipException( msg );
}
return rtn;
} // method InvTransformIntegerDataJg
/*
* Pre: inStream.Length matches h * w.
* (NbrSweeps * nComponentsPerSample) divides h.
* Post: outStream is suitable for further multiplexing with SignalBt012.
* This is "not exactly" the inverse transform of TransformSignalBt3.
* (The forward transform takes a composite stream as input.
* The inverse transform supplies a pure stream as output.)
* Returns Mismatch, or OK. Throws SimZipException.
*/
public static Io.Result InvTransformSignalBt3( Stream inStream, Stream outStream, int[] hw ) {
int h = hw[0];
int w = hw[1];
byte[,] mat = new byte[h, w];
Io.Result rtn = StreamProcessor.StreamToArray2D( inStream, mat );
switch ( rtn ) {
case Io.Result.Underflow :
case Io.Result.Overflow :
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.InvTransformSignalBt3(Stream,Stream,int[]): '"+tag+"' signal from StreamProcessor.StreamToArray2D";
throw new SimZipException( msg );
case Io.Result.OK : break;
}
int rMod = h;
int pRem = h % nComponentsPerSample;
if ( pRem != 0 ) return Io.Result.Mismatch;
int pSz = h / nComponentsPerSample;
int[] cNdx = {0};
int cMod = 0;
int[] rNdx = new int[ pSz ];
Stream[] sAry = new Stream[ nComponentsPerSample ];
int[] counts = new int[ nComponentsPerSample ];
try {
for ( int i = 0; i < nComponentsPerSample; ++i ) {
for ( int j = 0; j < pSz; ++j ) rNdx[j] = i * pSz + j;
counts[i] = 1;
byte[,] pick = ByteArrayManipulator.PickPeriodicValues( mat, rNdx, rMod, cNdx, cMod );
MemoryStream memStream = new MemoryStream();
StreamProcessor.Array2DToStream( memStream, pick );
memStream.Position = 0;
sAry[i] = memStream;
}
StreamProcessor.MergeStreams( outStream, sAry, counts );
} catch ( Exception ex ) {
string msg = "Caught in SimZip.InvTransformSignalBt3(Stream,Stream,int[])";
throw new SimZipException( msg, ex );
} finally {
foreach ( Stream s in sAry ) s.Close();
}
return rtn;
} // method InvTransformSignalBt3
/*
* Version of InvTransformSignalBt3, for jagged arrays.
* Returns OK, or BadFormat. Throws SimZipException.
*/
public static Io.Result InvTransformSignalBt3Jg( Stream inStream, Stream outStream, int[] szAry ) {
if ( szAry[0] % nComponentsPerSample != 0 ) return Io.Result.BadFormat;
int[] hw = new int[2];
hw[0] = szAry[0];
hw[1] = szAry[1];
szAry[0] /= nComponentsPerSample;
ScaleSzAryWidths( szAry, (double) nComponentsPerSample );
Io.Result rtn
= InvTransformJaggedFileComponent(inStream, outStream, InvTransformSignalBt3, szAry, hw);
if ( rtn != Io.Result.OK ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.InvTransformSignalBt3Jg(Stream,Stream,int[]): '"+tag+"' signal from SimZip.InvTransformJaggedFileComponent";
throw new SimZipException( msg );
}
return rtn;
} // method InvTransformSignalBt3Jg
/*
* "Not quite" the inverse of TransformSignalBt012, for jagged arrays.
* Returns OK, or BadFormat. Throws SimZipException.
*/
public static Io.Result InvTransformSignalBt012Jg( Stream inStream, Stream outStream, int[] szAry ) {
if ( szAry[1] % (3 * nComponentsPerSample) != 0 ) return Io.Result.BadFormat;
szAry[1] /= (3 * nComponentsPerSample);
int[] empty = new int[0];
ScaleSzAryWidths( szAry, (double) 3 * nComponentsPerSample );
StreamProcessor.Transform delegateTransform = StreamProcessor.TransformCopyStream;
Io.Result rtn
= InvTransformJaggedFileComponent(inStream, outStream, delegateTransform, szAry, empty);
if ( rtn != Io.Result.OK ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimZip.InvTransformSignalBt012Jg(Stream,Stream,int[]): '"+tag+"' signal from SimZip.InvTransformJaggedFileComponent";
throw new SimZipException( msg );
}
return rtn;
} // method InvTransformSignalBt012Jg
/*
* Adapt a rectangular transform to a jagged-array file component in the following manner:
* .. Use szAry, hwPre to separate the rectangular component from the excess bytes.
* .. Transform the rectangular array in the standard manner..
* .. Multiplex the rectangular rows with any corresponding excess bytes.
* Returns Underflow, Overflow, or OK. Throws SimZipException.
*/
public static Io.Result InvTransformJaggedFileComponent
( Stream inStream,
Stream outStream,
StreamProcessor.Transform invTransformRectangular,
int[] szAry,
int[] hwPre
){
string msg;
int h;
int w;
int[] pass;
if ( 1 < hwPre.Length ) {
h = hwPre[0];
w = hwPre[1];
pass = new int[2];
pass[0] = h;
pass[1] = w;
} else {
h = szAry[0];
w = szAry[1];
pass = new int[0];
}
// Separate the rectangular skew array from the spillover.
inStream.Position = 0;
byte[] buf = new byte[h * w];
Io.Result rtn = StreamProcessor.ReadByteStream( buf, 0, buf.Length, inStream );
switch ( rtn ) {
case Io.Result.Underflow :
case Io.Result.Overflow :
string tag = Io.GetResultTag( rtn );
msg = "SimZip.InvTransformJaggedFileComponent(Stream,Stream,StreamProcessor.Transform,int[],int[]): '"+tag+"' signal from StreamProcessor.StreamToArray2D";
throw new SimZipException( msg );
case Io.Result.OK : break;
}
// inStream.Position now points to the first byte of spillover.
MemoryStream rectStream = new MemoryStream();
try {
MemoryStream skewStream = new MemoryStream();
skewStream.Write( buf, 0, h * w );
skewStream.Position = 0;
try {
rtn = invTransformRectangular( skewStream, rectStream, pass );
} catch ( Exception ex ) {
msg = "Caught in SimZip.InvTransformJaggedFileComponent(Stream,Stream,StreamProcessor.Transform,int[],int[])";
throw new SimZipException( msg, ex );
} finally {
skewStream.Close();
}
switch ( rtn ) {
case Io.Result.Mismatch :
rectStream.Close();
string tag = Io.GetResultTag( rtn );
msg = "SimZip.InvTransformJaggedFileComponent(Stream,Stream,StreamProcessor.Transform,int[],int[]): '" + tag + "' signal from StreamProcessor.Transform";
throw new SimZipException( msg );
case Io.Result.OK : break;
}
// rectStream now holds the rectangular portion of the decompressed file component.
h = szAry[0];
w = szAry[1];
rectStream.Position = 0;
outStream.Position = 0;
// Write the output.
for ( int i = 0; i < h; ++i ) {
for ( int j = 0; j < w; ++j ) {
int next = rectStream.ReadByte();
if ( next < 0 ) {
rectStream.Close();
return Io.Result.Underflow;
}
outStream.WriteByte( (byte) next );
}
// Append any spillover bytes to the end of each row.
if ( 2 + i < szAry.Length ) {
int lim = szAry[2 + i];
for ( int j = 0; j < lim; ++j ) {
int next = inStream.ReadByte();
if ( next < 0 ) {
rectStream.Close();
return Io.Result.Underflow;
}
outStream.WriteByte( (byte) next );
}
}
}
if ((rectStream.Position < rectStream.Length) || (inStream.Position < inStream.Length)) {
rtn = Io.Result.Overflow;
}
} catch ( Exception ex ) {
msg = "Caught in SimZip.InvTransformJaggedFileComponent(Stream,Stream,StreamProcessor.Transform,int[],int[])";
throw new SimZipException( msg, ex );
} finally {
rectStream.Close();
}
return rtn;
} // method InvTransformJaggedFileComponent
//
#endregion
#region Data of class SimZip
// Versioning info - The two arrays are correspondingly indexed.
private string[] verSupported = { "SimFile1.0" }; // valid Version Id's
private int[] flgSupported = { 2 }; // byte-length of flag segment (includes semaphore)
//
#endregion
//
} // class SimZip
} // namespace SimFile