///
/// class SimFile
/// Models the file format used with Record/Playback Simulator (Summer 2008)
///
/// 16 Mar 2009 - D.Bozarth - Sonoma State Engineering Science
///
#region Using directives
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Utility;
#endregion
namespace SimFile
{
public class SimFile
{
#region Constants
//
public const string VERSION_ID = "SimFile1.0";
public const int BUF_SIZE_DFLT = Utility.StreamProcessor.BufSizeDflt;
public enum SignalId { A, B, C, D, E, All = -1 };
public enum ComponentId { Real, Imag };
public enum ByteOffset { B0, B1, B2, B3, All= -1 };
public enum FileContent { All, FileHdr, SwpAll, SwpHdr, Data, SignalData, IntegerData };
public enum FileFormat { Binary, CsvByte, Csv, Xml };
//
public const int nFlagsSimData = 4;
public const int nInt16PerSample = 4;
public const int nComponentsPerSignal = 2;
public const int nSignalsPerSample = 5;
public const int nComponentsPerSample = nComponentsPerSignal * nSignalsPerSample;
public const int nBytesPerBool = sizeof( bool );
public const int nBytesPerInt16 = sizeof( Int16 );
public const int nBytesPerInt32 = sizeof( Int32 );
public const int nBytesPerSingle = sizeof( Single );
public const int nBytesPerComponent = nBytesPerSingle;
public const int nBytesPerSignal = nBytesPerComponent * nComponentsPerSignal;
public const int nBytesSignalPerSample = nBytesPerSignal * nSignalsPerSample;
public const int nBytesInt16PerSample = nBytesPerInt16 * nInt16PerSample;
public const int nBytesIntegerPerSample = nBytesInt16PerSample;
public const int nBytesPerSample = nBytesSignalPerSample + nBytesIntegerPerSample;
public const int nBytesExtraField = nFlagsSimData * nBytesPerBool + 3 * nBytesPerInt16;
public const int nBytesPerMapEntry = 2 * nBytesPerInt32;
// Note: Wherever the native implementation used size_t or long,
// .. here we use int32.
public const int nBytesSweepHdr
= sizeof(int)
+ sizeof(int)
+ sizeof(int)
+ sizeof(int)
+ (sizeof(bool) * nFlagsSimData)
+ sizeof(short)
+ sizeof(short)
+ sizeof(short)
+ sizeof(int)
+ sizeof(int)
;
public const int nBytesFileHdr
= sizeof(int)
+ sizeof(int)
+ (sizeof(bool) * nFlagsSimData)
+ sizeof(short)
+ sizeof(short)
+ sizeof(short)
+ sizeof(int)
+ sizeof(int)
;
//
#endregion Constants
#region Contained classes of class SimFile
//
public class Test
{
}
public struct Sample {
public Pair A; // 5 complex numbers {real, imag}.
public Pair B;
public Pair C;
public Pair D;
public Pair E;
public short one;
public short two;
public short three;
public short four;
public override string ToString() {
return "{" + A.First + ", " + A.Second + "} "
+ "{" + B.First + ", " + B.Second + "} "
+ "{" + C.First + ", " + C.Second + "} "
+ "{" + D.First + ", " + D.Second + "} "
+ "{" + E.First + ", " + E.Second + "} "
+ one + " " + two + " " + three + " " + four
;
}
} // struct Sample
public class Sweep : List
{
#region Methods of class Sweep
public Sweep() {
sweepHdrExtra = new byte[nBytesExtraField];
SweepIds = new List();
Locas = new List();
fileName = "";
fileDesc = "";
}
public Io.Result StreamWrite( Stream outStream, FileContent fc ) {
return StreamWrite( outStream, fc, 0, this.Count );
}
public Io.Result StreamWrite( Stream outStream, FileContent fc, int start, int count ) {
Io.Result rtn = Io.Result.NoAction;
if ( fc == FileContent.FileHdr ) return rtn;
if ( fc == FileContent.All || fc == FileContent.SwpAll || fc == FileContent.SwpHdr ) {
rtn = StreamWriteHdr( outStream );
if ( rtn == Io.Result.BadFormat ) {
string msg = "Sweep.StreamWrite(Stream,FileContent,int,int): 'Bad Format' signal from Sweep.StreamWriteHdr(Stream)";
throw new SimFileException( msg );
}
}
if ( fc != FileContent.SwpHdr ) {
StreamWriteData( outStream, fc, start, count );
rtn = Io.Result.OK;
}
return rtn;
} // method StreamWrite
public Io.Result StreamWriteHdr( Stream outStream ) {
// Prepare & write the fixed-length segment of the sweep header.
byte[] bufSweepHdr = new byte[ nBytesSweepHdr ];
int nDx = 0;
if ( nSamples < 0 || nSweepIds < 0 || nLocas < 0 ) return Io.Result.BadFormat;
ByteArrayConverter.SetInt( bufSweepHdr, ref nDx, nSamples );
ByteArrayConverter.SetInt( bufSweepHdr, ref nDx, acqNum ); // deprecated
ByteArrayConverter.SetInt( bufSweepHdr, ref nDx, nSweepIds );
ByteArrayConverter.SetInt( bufSweepHdr, ref nDx, nLocas );
// Set some data we don't care about.
Array.Copy( sweepHdrExtra, 0, bufSweepHdr, nDx, nBytesExtraField );
nDx += nBytesExtraField;
if ( nFileChars < 0 || nDescChars < 0 ) return Io.Result.BadFormat;
ByteArrayConverter.SetInt( bufSweepHdr, ref nDx, nFileChars );
ByteArrayConverter.SetInt( bufSweepHdr, ref nDx, nDescChars );
outStream.Write( bufSweepHdr, 0, nBytesSweepHdr );
// Prepare & write the variable-length segment of the sweep header.
int nBytesSweepAux = ByteSizeAux();
byte[] bufSweepAux = new byte[ nBytesSweepAux ];
nDx = 0;
for ( int i = 0; i < nSweepIds; ++i ) {
ByteArrayConverter.SetInt( bufSweepAux, ref nDx, SweepIds[i] );
}
for ( int i = 0; i < nLocas; ++i ) {
ByteArrayConverter.SetInt( bufSweepAux, ref nDx, Locas[i] );
}
ByteArrayConverter.SetString( bufSweepAux, ref nDx, fileName );
ByteArrayConverter.SetString( bufSweepAux, ref nDx, fileDesc );
outStream.Write( bufSweepAux, 0, nBytesSweepAux );
return Io.Result.OK;
} // method StreamWriteHdr
public void StreamWriteData( Stream outStream, FileContent fc ) {
StreamWriteData( outStream, fc, 0, this.Count );
}
public void StreamWriteData( Stream outStream, FileContent fc, int start, int count ) {
// Prepare and write the Sweep data.
// Review this part later. Not sure this index-changing is all good.
// .. Review this with all Stream Io methods.
int myStart = 0 < start ? start : 0;
int myCount = 0 < count ? count : 0;
myStart = myStart < this.Count ? myStart : this.Count;
myCount = myStart + myCount < this.Count ? myCount : this.Count;
int nBytesData = myCount;
int nDx = 0;
switch ( fc ) {
case FileContent.All :
case FileContent.SwpAll :
case FileContent.Data :
nBytesData *= nBytesPerSample; break;
case FileContent.SignalData :
nBytesData *= nBytesSignalPerSample; break;
case FileContent.IntegerData :
nBytesData *= nBytesIntegerPerSample; break;
default : return;
}
byte[] bufSweepData = new byte[nBytesData];
for ( int i = myStart; i < myCount; ++i ) {
Sample sample = this[i];
if ( fc != FileContent.IntegerData ) {
ByteArrayConverter.SetPairFloat( bufSweepData, ref nDx, sample.A );
ByteArrayConverter.SetPairFloat( bufSweepData, ref nDx, sample.B );
ByteArrayConverter.SetPairFloat( bufSweepData, ref nDx, sample.C );
ByteArrayConverter.SetPairFloat( bufSweepData, ref nDx, sample.D );
ByteArrayConverter.SetPairFloat( bufSweepData, ref nDx, sample.E );
}
if ( fc != FileContent.SignalData ) {
ByteArrayConverter.SetShort( bufSweepData, ref nDx, sample.one );
ByteArrayConverter.SetShort( bufSweepData, ref nDx, sample.two );
ByteArrayConverter.SetShort( bufSweepData, ref nDx, sample.three );
ByteArrayConverter.SetShort( bufSweepData, ref nDx, sample.four );
}
}
outStream.Write( bufSweepData, 0, nBytesData );
} // method StreamWriteData
public Io.Result StreamRead( Stream inStream, FileContent fc ) {
return StreamRead( inStream, fc, 0, this.Count );
}
/*
* Caller manages starting condition of the object.
* inStream underflow => return Io.Result.Underflow
* inStream overflow => return Io.Result.Overflow
* .. otherwise return IoResult.OK
*/
public Io.Result StreamRead( Stream inStream, FileContent fc, int start, int count ) {
Io.Result rtn = Io.Result.NoAction;
if ( fc == FileContent.FileHdr ) return rtn;
if ( fc == FileContent.All || fc == FileContent.SwpAll || fc == FileContent.SwpHdr ) {
rtn = StreamReadHdr( inStream );
switch ( rtn ) {
case Io.Result.BadFormat :
case Io.Result.Underflow :
string tag = Io.GetResultTag( rtn );
string msg = "Sweep.StreamRead(Stream,FileContent,int,int): '"+tag+"' signal from Sweep.StreamReadHdr";
throw new SimFileException( msg );
case Io.Result.Overflow :
// Leave the overflow signal active: Let data method modify, or let caller decide what to do.
case Io.Result.OK : break;
}
}
if ( fc != FileContent.SwpHdr ) {
rtn = StreamReadData( inStream, fc, start, count );
}
return rtn;
} // method StreamRead
public Io.Result StreamReadHdr( Stream inStream ) {
if ( inStream.Length - inStream.Position < nBytesSweepHdr ) return Io.Result.Underflow;
// Read & parse the fixed-length segment of the Sweep header.
int nDx = 0;
byte[] bufSweepHdr = new byte[nBytesSweepHdr];
Io.Result rtn = StreamProcessor.ReadByteStream(bufSweepHdr, 0, nBytesSweepHdr, inStream);
if ( rtn == Io.Result.BadIndex ) {
string msg = "Sweep.StreamReadHdr(Stream): 'Bad Index' signal from StreamProcessor.ReadByteStream";
throw new SimFileException( msg );
}
nSamples = ByteArrayConverter.GetInt( bufSweepHdr, ref nDx );
acqNum = ByteArrayConverter.GetInt( bufSweepHdr, ref nDx ); // deprecated
nSweepIds = ByteArrayConverter.GetInt( bufSweepHdr, ref nDx );
nLocas = ByteArrayConverter.GetInt( bufSweepHdr, ref nDx );
if ( nSamples < 0 || nSweepIds < 0 || nLocas < 0 ) return Io.Result.BadFormat;
// Get some data we don't care about but need to save.
for ( int i = 0; i < nBytesExtraField; ++i ) {
sweepHdrExtra[i] = bufSweepHdr[nDx + i];
}
nDx += nBytesExtraField;
nFileChars = ByteArrayConverter.GetInt( bufSweepHdr, ref nDx );
nDescChars = ByteArrayConverter.GetInt( bufSweepHdr, ref nDx );
if ( nFileChars < 0 || nDescChars < 0 ) return Io.Result.BadFormat;
int nBytesSweepAux = ByteSizeAux();
if ( inStream.Length - inStream.Position < nBytesSweepAux ) return Io.Result.Underflow;
// Read & parse the variable-length segment of the sweep header.
nDx = 0;
byte[] bufSweepAux = new byte[nBytesSweepAux];
rtn = StreamProcessor.ReadByteStream( bufSweepAux, 0, nBytesSweepAux, inStream );
if ( rtn == Io.Result.BadIndex ) {
string msg = "Sweep.StreamReadHdr(Stream): 'Bad Index' signal from StreamProcessor.ReadByteStream";
throw new SimFileException( msg );
}
for ( long i = 0; i < nSweepIds; ++i ) {
SweepIds.Add( ByteArrayConverter.GetInt( bufSweepAux, ref nDx ) );
}
for (int i = 0; i < nLocas; ++i) {
Locas.Add( ByteArrayConverter.GetInt( bufSweepAux, ref nDx ) );
}
fileName = ByteArrayConverter.GetString( bufSweepAux, ref nDx, nFileChars );
fileDesc = ByteArrayConverter.GetString( bufSweepAux, ref nDx, nDescChars );
if ( inStream.Position < inStream.Length ) return Io.Result.Overflow;
return Io.Result.OK;
} // method StreamReadHdr
public Io.Result StreamReadData( Stream inStream, FileContent fc ) {
return StreamReadData( inStream, fc, 0, this.Count );
}
public Io.Result StreamReadData( Stream inStream, FileContent fc, int start, int count ) {
if ( fc == FileContent.FileHdr || fc == FileContent.SwpHdr ) return Io.Result.NoAction;
int myStart = 0 < start ? start : 0;
int myCount = 0 < count ? count : 0;
myStart = myStart < this.Count ? myStart : this.Count;
int nBytesData = myCount;
switch ( fc ) {
case FileContent.All :
case FileContent.SwpAll :
case FileContent.Data :
nBytesData *= nBytesPerSample; break;
case FileContent.SignalData :
nBytesData *= nBytesSignalPerSample; break;
case FileContent.IntegerData :
nBytesData *= nBytesIntegerPerSample; break;
default : return 0;
}
if ( inStream.Length - inStream.Position < nBytesData ) return Io.Result.Underflow;
// Read and parse the Sweep data.
int nDx = 0;
byte[] bufSweepData = new byte[ nBytesData ];
Io.Result rtn = StreamProcessor.ReadByteStream( bufSweepData, 0, nBytesData, inStream );
if ( rtn == Io.Result.BadIndex ) {
string msg = "Sweep.StreamReadData(Stream,FileContent,int,int): 'Bad Index' signal from StreamProcessor.ReadByteStream";
throw new SimFileException( msg );
}
for ( int i = myStart; i < myCount; ++i ) {
Sample sample = i < this.Count ? this[i] : new Sample();
if ( fc != FileContent.IntegerData ) {
sample.A = ByteArrayConverter.GetPairFloat( bufSweepData, ref nDx );
sample.B = ByteArrayConverter.GetPairFloat( bufSweepData, ref nDx );
sample.C = ByteArrayConverter.GetPairFloat( bufSweepData, ref nDx );
sample.D = ByteArrayConverter.GetPairFloat( bufSweepData, ref nDx );
sample.E = ByteArrayConverter.GetPairFloat( bufSweepData, ref nDx );
}
if ( fc != FileContent.SignalData ) {
sample.one = ByteArrayConverter.GetShort( bufSweepData, ref nDx );
sample.two = ByteArrayConverter.GetShort( bufSweepData, ref nDx );
sample.three= ByteArrayConverter.GetShort( bufSweepData, ref nDx );
sample.four = ByteArrayConverter.GetShort( bufSweepData, ref nDx );
}
if ( i < this.Count ) {
this[i] = sample;
} else {
this.Add( sample );
}
}
if ( inStream.Position < inStream.Length ) return Io.Result.Overflow;
return Io.Result.OK;
} // method StreamReadData
private int ByteSize() {
return Count * nBytesPerSample + nBytesSweepHdr + ByteSizeAux();
}
private int ByteSizeAux() {
return ( nSweepIds + nLocas ) * sizeof( Int32 )
+ ( nFileChars + nDescChars ) * sizeof( char )
;
}
public override string ToString() {
int count = ((List) this).Count;
string rtn = " ";
rtn += nSamples.ToString() + ", ";
rtn += SweepIds.ToString() + ", ";
rtn += Locas.ToString() + ", ";
rtn += fileName + ", ";
rtn += fileDesc + " | ";
for( int i = 0; i < count; ++i ) {
rtn += ((List) this)[i].ToString();
if ( i + 1 < count ) {
rtn += " | ";
}
}
return rtn;
}
// method toString
#endregion Methods
#region Properties of class Sweep
//
public int NbrSamples { get { return nSamples; } set { nSamples = value; } }
public int NbrFileChars { get { return nFileChars; } }
public int NbrDescChars { get { return nDescChars; } }
public string FileName {
get { return fileName; }
set {
fileName = value;
nFileChars = fileName.Length;
}
}
public string FileDesc {
get { return fileDesc; }
set {
fileDesc = value;
nDescChars = fileDesc.Length;
}
}
//
#endregion
#region Data of class Sweep
// Fixed-length info
private int nSamples;
private int acqNum; // deprecated
private int nSweepIds;
private int nLocas;
private byte[] sweepHdrExtra;
private int nFileChars;
private int nDescChars;
// Variable-length info
private List SweepIds;
private List Locas;
private string fileName;
private string fileDesc;
//
#endregion
} // class Sweep
public class SimFileException : ApplicationException
{
public SimFileException( String message ) : base( message )
{}
public SimFileException( String message, Exception inner ) : base( message, inner )
{}
}
//
#endregion Contained classes
#region Methods of class SimFile
//
public SimFile( List sweepSet ) {
fileHdrExtra = new byte[nBytesExtraField];
Locas = new List();
fileName = "";
fileDesc = "";
mySweeps = sweepSet;
byteBlock = new List();
legacyFileVersion = 0;
}
public SimFile() {
fileHdrExtra = new byte[nBytesExtraField];
Locas = new List();
fileName = "";
fileDesc = "";
mySweeps = new List();
byteBlock = new List();
legacyFileVersion = 0;
}
/*
* All StreamWrite methods send data from a memory object, to an output stream.
*/
public Io.Result StreamWrite( Stream outStream, FileContent fc ) {
return StreamWrite( outStream, fc, 0, mySweeps.Count );
}
/*
* start, count represent sample units (not bytes !).
*/
public Io.Result StreamWrite( Stream outStream, FileContent fc, int start, int count ) {
Io.Result rtn = Io.Result.OK;
if ( fc == FileContent.FileHdr || fc == FileContent.All ) {
rtn = StreamWriteHdr( outStream );
if ( rtn == Io.Result.BadFormat ) {
string msg = "SimFile.StreamWrite(Stream,FileContent,int,int): 'Bad Format' signal from SimFile.StreamWriteHdr";
throw new SimFileException( msg );
}
}
if ( fc != FileContent.FileHdr ) {
rtn = StreamWriteData( outStream, fc, start, count );
}
return rtn;
} // method StreamWrite
public Io.Result StreamWriteHdr( Stream outStream ) {
// Prepare & write the fixed-length segment of the file header.
byte[] bufFileHdr = new byte[ nBytesFileHdr ];
int nDx = 0;
if ( nSweeps < 0 || nLocas < 0 ) return Io.Result.BadFormat;
ByteArrayConverter.SetInt( bufFileHdr, ref nDx, nSweeps );
ByteArrayConverter.SetInt( bufFileHdr, ref nDx, nLocas );
// Set some data we don't care about.
Array.Copy( fileHdrExtra, 0, bufFileHdr, nDx, nBytesExtraField );
nDx += nBytesExtraField;
if ( nFileChars < 0 || nDescChars < 0 ) return Io.Result.BadFormat;
ByteArrayConverter.SetInt( bufFileHdr, ref nDx, nFileChars );
ByteArrayConverter.SetInt( bufFileHdr, ref nDx, nDescChars );
outStream.Write( bufFileHdr, 0, nBytesFileHdr );
// Prepare & write the variable-length segment of the file header.
int nBytesFileAux = ByteSizeAux();
byte[] bufFileAux = new byte[nBytesFileAux];
nDx = 0;
for ( int i = 0; i < nLocas; ++i ) {
ByteArrayConverter.SetInt( bufFileAux, ref nDx, Locas[i] );
}
ByteArrayConverter.SetString( bufFileAux, ref nDx, fileName );
ByteArrayConverter.SetString( bufFileAux, ref nDx, fileDesc );
outStream.Write( bufFileAux, 0, nBytesFileAux );
return Io.Result.OK;
} // method StreamWriteHdr
public Io.Result StreamWriteData( Stream outStream, FileContent fc ) {
return StreamWriteData( outStream, fc, 0, mySweeps.Count );
}
/*
* start, count represent sample units (not bytes !).
*/
public Io.Result StreamWriteData( Stream outStream, FileContent fc, int start, int count ) {
Io.Result rtn = Io.Result.NoAction;
if ( fc == FileContent.FileHdr ) return rtn;
int myStart = 0 < start ? start : 0;
int myCount = 0 < count ? count : 0;
myStart = myStart < mySweeps.Count ? myStart : mySweeps.Count;
myCount = myStart + myCount < mySweeps.Count ? myCount : mySweeps.Count;
for ( int i = myStart; i < myCount; ++i ) {
rtn = mySweeps[i].StreamWrite( outStream, fc );
switch ( rtn ) {
case Io.Result.OK : break;
default :
string tag = Io.GetResultTag( rtn );
string msg = "SimFile.StreamWriteData(Stream,FileContent,int,int): '"+tag+"' signal from Sweep.StreamWrite";
throw new SimFileException( msg );
}
}
return rtn;
} // method StreamWriteData
/*
* All StreamRead methods send data from a stream, to an object in memory.
*/
public Io.Result StreamRead( Stream inStream, FileContent fc ) {
return StreamRead( inStream, fc, 0, mySweeps.Count );
}
/*
* start, count represent sample units (not bytes !).
*/
public Io.Result StreamRead( Stream inStream, FileContent fc, int start, int count ) {
Io.Result rtn = Io.Result.OK;
if ( fc == FileContent.FileHdr || fc == FileContent.All ) {
rtn = StreamReadHdr( inStream );
switch ( rtn ) {
case Io.Result.BadFormat :
case Io.Result.Underflow :
string tag = Io.GetResultTag( rtn );
string msg = "SimFile.StreamRead(Stream,FileContent,int,int): '"+tag+"' signal from SimFile.StreamReadHdr";
throw new SimFileException( msg );
case Io.Result.Overflow : // May still need to read Sweeps.
// Let the overflow be returned to the caller, or be modified by data read.
case Io.Result.OK : break;
}
}
if ( fc != FileContent.FileHdr ) {
rtn = StreamReadData( inStream, fc, start, count );
switch ( rtn ) {
case Io.Result.Overflow : // Supposed to be finished.
string tag = Io.GetResultTag( rtn );
string msg = "SimFile.StreamRead(Stream,FileContent,int,int): '"+tag+"' signal from SimFile.StreamReadData";
throw new SimFileException( msg );
case Io.Result.OK : break;
}
}
return rtn;
} // method StreamRead
public Io.Result StreamReadHdr( Stream inStream ) {
if ( inStream.Length - inStream.Position < nBytesFileHdr ) return Io.Result.Underflow;
// Read & parse the fixed-length segment of the file header.
int nDx = 0;
byte[] bufFileHdr = new byte[nBytesFileHdr];
Io.Result rtn = StreamProcessor.ReadByteStream( bufFileHdr, 0, nBytesFileHdr, inStream );
if ( rtn == Io.Result.BadIndex ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimFile.StreamReadHdr(Stream): '" + tag + "' signal from StreamProcessor.ReadByteStream";
throw new SimFileException( msg );
}
nSweeps = ByteArrayConverter.GetInt( bufFileHdr, ref nDx );
nLocas = ByteArrayConverter.GetInt( bufFileHdr, ref nDx );
if (nSweeps < 0 || nLocas < 0) return Io.Result.BadFormat;
// Get some data we don't care about but need to save.
for ( int i = 0; i < nBytesExtraField; ++i ) {
fileHdrExtra[i] = bufFileHdr[nDx + i];
}
nDx += nBytesExtraField;
nFileChars = ByteArrayConverter.GetInt( bufFileHdr, ref nDx );
nDescChars = ByteArrayConverter.GetInt( bufFileHdr, ref nDx );
if (nFileChars < 0 || nDescChars < 0) return Io.Result.BadFormat;
int nBytesFileAux = ByteSizeAux();
if ( inStream.Length - inStream.Position < nBytesFileAux ) return Io.Result.Underflow;
// Read & parse the variable-length segment of the sweep header.
nDx = 0;
byte[] bufFileAux = new byte[ nBytesFileAux ];
rtn = StreamProcessor.ReadByteStream( bufFileAux, 0, nBytesFileAux, inStream );
if ( rtn == Io.Result.BadIndex ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimFile.StreamReadHdr(Stream): '" + tag + "' signal from StreamProcessor.ReadByteStream";
throw new SimFileException( msg );
}
for ( int i = 0; i < nLocas; ++i ) {
Locas.Add( ByteArrayConverter.GetInt( bufFileAux, ref nDx ) );
}
fileName = ByteArrayConverter.GetString( bufFileAux, ref nDx, nFileChars );
fileDesc = ByteArrayConverter.GetString( bufFileAux, ref nDx, nDescChars );
if ( inStream.Position + 1 < inStream.Length ) return Io.Result.Overflow;
return Io.Result.OK;
} // method StreamReadHdr
public Io.Result StreamReadData( Stream inStream, FileContent fc ) {
return StreamReadData( inStream, fc, 0, mySweeps.Count );
}
/*
* Caller must manage the starting size of mySweeps, and the ending value of nSweeps.
* start, count represent sample units (not bytes !).
*/
public Io.Result StreamReadData( Stream inStream, FileContent fc, int start, int count ) {
Io.Result rtn = Io.Result.NoAction;
if ( fc == FileContent.FileHdr ) return rtn;
int myStart = 0 < start ? start : 0;
myStart = myStart < mySweeps.Count ? myStart : mySweeps.Count;
// Read and parse Sweep data from inStream.
// Note: requires that the sweep header was previously read in (so that NbrSamples is set).
for ( int i = myStart; i < count; ++i ) {
bool xFlg = false;
if ( i < mySweeps.Count ) {
// Modify existing Sweep object.
Sweep sweep = mySweeps[i];
rtn = sweep.StreamRead( inStream, fc, 0, sweep.NbrSamples );
switch ( rtn ) {
case Io.Result.Underflow : xFlg = true; break;
case Io.Result.Overflow :
if ( i + 1 < mySweeps.Count ) {
rtn = Io.Result.OK;
} else {
//return rtn; // Supposed to be finished.
xFlg = true; // Supposed to be finished.
}
break;
case Io.Result.NoAction : rtn = Io.Result.OK; break;
case Io.Result.OK : break;
}
if ( xFlg ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimFile.StreamReadData(Stream,FileContent,int,int): '"+tag+"' signal from Sweep.StreamRead";
throw new SimFileException( msg );
}
mySweeps[i] = sweep;
} else {
Sweep sweep = new Sweep();
rtn = sweep.StreamReadHdr( inStream );
switch ( rtn ) {
case Io.Result.BadFormat :
case Io.Result.Underflow : xFlg = true; break;
case Io.Result.Overflow :
if (( i + 1 < count ) || ( fc != FileContent.SwpHdr )) {
rtn = Io.Result.OK; // No problem, still have to read Sweeps.
} else {
xFlg = true; // Supposed to be finished.
}
break;
case Io.Result.OK : break;
}
if ( xFlg ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimFile.StreamReadData(Stream,FileContent,int,int): '"+tag+"' signal from Sweep.StreamReadHdr";
throw new SimFileException( msg );
}
rtn = sweep.StreamReadData( inStream, fc, 0, sweep.NbrSamples );
switch ( rtn ) {
case Io.Result.Underflow : xFlg = true; break;
case Io.Result.Overflow :
if ( i + 1 < count ) {
rtn = Io.Result.OK; // No problem, still have to read Sweeps.
} else {
xFlg = true; // Supposed to be finished.
}
break;
case Io.Result.NoAction : rtn = Io.Result.OK; break;
case Io.Result.OK : break;
}
if ( xFlg ) {
string tag = Io.GetResultTag( rtn );
string msg = "SimFile.StreamReadData(Stream,FileContent,int,int): '"+tag+"' signal from Sweep.StreamReadData";
throw new SimFileException( msg );
}
mySweeps.Add(sweep);
}
}
if ( inStream.Position < inStream.Length ) return Io.Result.Overflow;
return rtn;
} // method StreamReadData
public Io.Result FileWrite( string fileSpec ) {
File.Delete( fileSpec );
Io.Result rtn = Io.Result.OK;
FileStream outStream = File.OpenWrite( fileSpec );
try {
rtn = StreamWrite( outStream, FileContent.All );
} catch ( Exception ex ) {
string msg = "Caught in SimFile.FileWrite(string) call StreamWrite(Stream, FileContent)";
throw new SimFileException( msg, ex );
} finally {
outStream.Close();
}
return rtn;
} // method FileWrite
public Io.Result FileRead( string fileSpec ) {
mySweeps.Clear();
Io.Result rtn = Io.Result.OK;
FileStream inStream = File.OpenRead( fileSpec );
try {
rtn = StreamReadHdr( inStream );
switch ( rtn ) {
case Io.Result.BadFormat :
case Io.Result.Underflow :
string tag = Io.GetResultTag( rtn );
string msg = "SimFile.FileRead(string): '"+tag+"' signal from SimFile.StreamReadHdr";
throw new SimFileException( msg );
case Io.Result.Overflow : // No problem, still need to read Sweeps.
rtn = Io.Result.OK;
break;
case Io.Result.OK : break;
}
rtn = StreamReadData( inStream, FileContent.All, 0, nSweeps );
} catch ( Exception ex ) {
throw new SimFileException("Caught in SimFile.FileRead", ex);
} finally {
inStream.Close();
}
switch ( rtn ) {
case Io.Result.Overflow : // Supposed to be finished.
string tag = Io.GetResultTag( rtn );
string msg = "SimFile.FileRead(Stream,FileContent,int,int): '"+tag+"' signal from SimFile.StreamReadData";
throw new SimFileException( msg );
case Io.Result.OK :
default : break;
}
return rtn;
} // method FileRead
/*
* Populate the data member byteBlock, with object data corresponding to fc.
*/
public Io.Result LoadByteBlock( FileContent fc ) {
byteBlock.Clear();
MemoryStream memStream = new MemoryStream();
Io.Result rtn = Io.Result.OK;
try {
if ( fc == FileContent.FileHdr || fc == FileContent.All ) {
rtn = StreamWriteHdr( memStream );
if (rtn == Io.Result.BadFormat) {
string tag = Io.GetResultTag( rtn );
string msg = "SimFile.LoadByteBlock(FileContent): '"+tag+"' signal from SimFile.StreamWriteHdr";
throw new SimFileException( msg );
}
byteBlock.Add( memStream.ToArray() );
}
if ( fc != FileContent.FileHdr ) {
for ( int i = 0; i < mySweeps.Count; ++i ) {
memStream.SetLength( 0 );
rtn = mySweeps[i].StreamWrite( memStream, fc );
// rtn == OK unless exception was thrown in callee.
byteBlock.Add( memStream.ToArray() );
}
}
} catch ( Exception ex ) {
throw new SimFileException("Caught in SimFile.LoadByteBlock(FileContent)", ex);
} finally {
memStream.Close();
}
return rtn; // OK if no exception thrown.
} // method LoadByteBlock
/*
* This has been adapted to serve two different but similar applications.
* It reports the row and column size characteristics of byteBlock.
* The return value represents the #rows and the width of the widest row (greatest #cols).
* The two out values are to be interpreted as follows:
* wmin is the width of the narrowest row (least #cols).
* If extra is an empty array, then byteBlock is rectangular.
* .. Otherwise, extra has a number of elements equal to the #rows,
* .. .. and each element is the difference between wmin and the corresponding row's width.
* (wmin and extra may be used directly by SimZip.Compress to form a header for a jagged array component.)
*/
public Pair GetByteBlockScale( out int wmin, out int[] extra ) {
List eList = new List();
bool isJagged = false;
int height = byteBlock.Count;
int wmax = 0;
wmin = byteBlock[0].Length;
for ( int i = 0; i < height; ++i ) {
int len = byteBlock[i].Length;
if ( len < wmin ) wmin = len;
if ( wmax < len ) wmax = len;
}
for ( int i = 0; i < height; ++i ) {
int dif = byteBlock[i].Length - wmin;
if ( 0 < dif ) isJagged = true;
eList.Add(dif);
}
if ( isJagged ) {
extra = new int[ eList.Count ];
eList.CopyTo( extra );
} else {
extra = new int[0];
}
return new Pair( height, wmax );
} // method GetByteBlockScale
private int ByteSizeAux() {
return nLocas * sizeof(Int32)
+ (nFileChars + nDescChars) * sizeof(char)
;
}
public override string ToString() {
int count = mySweeps.Count;
string rtn = " ";
rtn += nSweeps.ToString() + ", ";
rtn += Locas.ToString() + ", ";
rtn += fileName + ", ";
rtn += fileDesc + ", ";
for (int i = 0; i < count; ++i) {
rtn += mySweeps[i].ToString();
if (i + 1 < count) rtn += " | ";
}
return rtn;
} // method ToString
//
#endregion Methods
#region Properties of class SimFile
//
public int LegacyFileVersion { get {return legacyFileVersion;} set {legacyFileVersion = value;} }
public int NbrSweeps { get {return nSweeps;} set {nSweeps = value;} }
//
#endregion
#region Data of class SimFile
// Memory-only data
private int legacyFileVersion;
// Fixed-length info
private int nSweeps;
private int nLocas;
private byte[] fileHdrExtra;
private int nFileChars;
private int nDescChars;
// Variable-length info
private List Locas;
private string fileName;
private string fileDesc;
// Sweep data
protected List mySweeps;
protected List byteBlock;
//
#endregion
} // class SimFile
} // namespace Compress