Пример #1
0
 /// <summary>
 /// Writes a single record to the file, returning the number of bytes written
 /// </summary>
 /// <param name="record"></param>
 public int WriteRecord(StdfRecord record)
 {
     if (record == null)
     {
         throw new ArgumentNullException("record");
     }
     if (_Endian == Endian.Unknown)
     {
         //we must be able to infer the endianness based on the first record
         if (record.GetType() == typeof(StartOfStreamRecord))
         {
             var sos = (StartOfStreamRecord)record;
             _Endian = sos.Endian;
             return(0);
         }
         else if (record.GetType() == typeof(Far))
         {
             InferEndianFromFar((Far)record);
         }
         if (_Endian == Endian.Unknown)
         {
             throw new InvalidOperationException(Resources.CannotInferEndianness);
         }
     }
     if (record.IsWritable)
     {
         var writer = new LinqToStdf.BinaryWriter(_Stream, _Endian, false);
         var ur     = ConverterFactory.Unconvert(record, _Endian);
         writer.WriteHeader(new RecordHeader((ushort)ur.Content.Length, ur.RecordType));
         _Stream.Write(ur.Content, 0, ur.Content.Length);
         return(ur.Content.Length + 4);
     }
     return(0);
 }
Пример #2
0
 /// <summary>
 /// <para>
 /// This is a helper function used by the LCG code
 /// to simplify the process of ensuring that the provided
 /// target record is suitable for conversion.
 /// </para>
 /// <para>
 /// Throws InvalidRecordConversionException if the conversion cannot succeed.
 /// </para>
 /// </summary>
 /// <param name="record">The record that is the target for conversion</param>
 /// <exception cref="InvalidRecordConversionException"/>
 public void EnsureConvertibleTo(StdfRecord record)
 {
     if (!RecordType.Equals(record.RecordType))
     {
         throw new InvalidRecordConversionException();
     }
 }
Пример #3
0
 /// <summary>
 /// Converts a concrete record into an unknown record of the given endianness
 /// </summary>
 public UnknownRecord Unconvert(StdfRecord record, Endian endian)
 {
     return(GetUnconverter(record.GetType())(record, endian));
 }
Пример #4
0
        IEnumerable <StdfRecord> InternalGetAllRecords()
        {
            //set this in case the last time we ended in seek mode
            _InSeekMode = false;
            using (IStdfStreamScope streamScope = _StreamManager.GetScope()) {
                try {
                    _Stream = new RewindableByteStream(streamScope.Stream);
                    //read the FAR to get endianness
                    var endian = Endian.Little;
                    var far    = new byte[6];
                    if (_Stream.Read(far, 6) < 6)
                    {
                        yield return(new StartOfStreamRecord {
                            Endian = Endian.Unknown, ExpectedLength = _Stream.Length
                        });

                        yield return(new FormatErrorRecord {
                            Message = Resources.FarReadError,
                            Recoverable = false
                        });

                        yield return(new EndOfStreamRecord());

                        yield break;
                    }
                    endian = far[4] < 2 ? Endian.Big : Endian.Little;
                    var stdfVersion = far[5];
                    var length      = (endian == Endian.Little ? far[0] : far[1]);
                    if (length != 2)
                    {
                        yield return(new StartOfStreamRecord {
                            Endian = endian, ExpectedLength = _Stream.Length
                        });

                        yield return(new FormatErrorRecord {
                            Message = Resources.FarLengthError,
                            Recoverable = false
                        });

                        yield return(new EndOfStreamRecord {
                            Offset = 2
                        });

                        yield break;
                    }
                    //validate record type
                    if (far[2] != 0)
                    {
                        yield return(new StartOfStreamRecord {
                            Endian = endian, ExpectedLength = _Stream.Length
                        });

                        yield return(new FormatErrorRecord {
                            Offset = 2,
                            Message = Resources.FarRecordTypeError,
                            Recoverable = false
                        });

                        yield return(new EndOfStreamRecord {
                            Offset = 6
                        });

                        yield break;
                    }
                    //validate record type
                    if (far[3] != 10)
                    {
                        yield return(new StartOfStreamRecord {
                            Endian = endian, ExpectedLength = _Stream.Length
                        });

                        yield return(new FormatErrorRecord {
                            Offset = 3,
                            Message = Resources.FarRecordSubTypeError,
                            Recoverable = false
                        });

                        yield return(new EndOfStreamRecord {
                            Offset = 3
                        });

                        yield break;
                    }
                    //OK we're satisfied, let's go
                    yield return(new StartOfStreamRecord()
                    {
                        Endian = endian, ExpectedLength = _Stream.Length
                    });

                    yield return(new LinqToStdf.Records.V4.Far()
                    {
                        CpuType = far[4], StdfVersion = far[5]
                    });

                    //flush the memory
                    _Stream.Flush();

                    //now we have the FAR out of the way, and we can blow through the rest.
                    while (true)
                    {
                        if (_InSeekMode)
                        {
                            _Stream.RewindAll();
                            int backup = -1;
                            //create the callback algorithms use to indicate the found something
                            void BackupCallback(int bytes)
                            {
                                backup = bytes;
                            }
                            var corruptOffset = _Stream.Offset;
                            //set up the seek algorithms and consume the sequence.
                            var algorithm = _SeekAlgorithm(_Stream.ReadAsByteSequence(), endian, BackupCallback);
                            algorithm.Count();
                            //when we get here, one of the algorithms has found the record stream,
                            //or we went to the end of the stream

                            var recoverable = false;
                            if (backup != -1)
                            {
                                //someone found where we need to be, backup the number of bytes they suggest
                                _Stream.Rewind(backup);
                                recoverable = true;
                            }
                            //spit out the corrupt data
                            yield return(new CorruptDataRecord()
                            {
                                CorruptData = _Stream.DumpDataToCurrentOffset(),
                                Offset = corruptOffset,
                                Recoverable = recoverable
                            });

                            //the data's gone out the door, so flush it
                            _Stream.Flush();
                            if (!recoverable)
                            {
                                //we got to the end without finding anything
                                //spit out a format error
                                yield return(new FormatErrorRecord()
                                {
                                    Message = Resources.EOFInSeekMode,
                                    Recoverable = false,
                                    Offset = _Stream.Offset
                                });

                                yield return(new EndOfStreamRecord()
                                {
                                    Offset = _Stream.Offset
                                });

                                yield break;
                            }
                            _InSeekMode = false;
                        }
                        var position = _Stream.Offset;
                        //read a record header
                        RecordHeader?header = _Stream.ReadHeader(endian);
                        //null means we hit EOS
                        if (header == null)
                        {
                            if (!_Stream.PastEndOfStream)
                            {
                                //Something's wrong. We know the offset is rewound
                                //to the begining of the header.  If there's still
                                //data, we're corrupt
                                yield return(new CorruptDataRecord()
                                {
                                    Offset = position,
                                    //TODO: leverage the data in the stream.
                                    //we know we've hit the end, so we can just dump
                                    //the remaining memoized data
                                    CorruptData = _Stream.DumpRemainingData(),
                                    Recoverable = false
                                });

                                yield return(new FormatErrorRecord()
                                {
                                    Message = Resources.EOFInHeader,
                                    Recoverable = false,
                                    Offset = position
                                });
                            }
                            yield return(new EndOfStreamRecord()
                            {
                                Offset = _Stream.Offset
                            });

                            yield break;
                        }
                        var contents = new byte[header.Value.Length];
                        int read     = _Stream.Read(contents, contents.Length);
                        if (read < contents.Length)
                        {
                            //rewind to the beginning of the record (read bytes + the header)
                            _Stream.Rewind(_Stream.Offset - position);
                            yield return(new CorruptDataRecord()
                            {
                                Offset = position,
                                CorruptData = _Stream.DumpRemainingData(),
                                Recoverable = false
                            });

                            yield return(new FormatErrorRecord()
                            {
                                Message = Resources.EOFInRecordContent,
                                Recoverable = false,
                                Offset = position
                            });
                        }
                        else
                        {
                            var ur = new UnknownRecord(header.Value.RecordType, contents, endian)
                            {
                                Offset = position
                            };
                            StdfRecord r = _ConverterFactory.Convert(ur);
                            if (r.GetType() != typeof(UnknownRecord))
                            {
                                //it converted, so update our last known position
                                //TODO: We should think about:
                                //* how to indicate corruption within the record boundaries
                                //* enabling filteres to set the last known offset (to allow valid unknown records to pass through)
                                //  * This could possible be done by allowing filters access to Flush or the dump functionality.
                                _Stream.Flush();
                            }
                            r.Offset = position;
                            yield return(r);
                        }
                    }
                }
                finally {
                    //set stream to null so we're not holding onto it
                    _Stream = null;
                }
            }
        }
Пример #5
0
 /// <summary>
 /// Returns the records that occur after the given record
 /// </summary>
 /// <param name="record">The "marker" record</param>
 /// <returns>All the records after the marker record</returns>
 static public IEnumerable <StdfRecord> After(this StdfRecord record)
 {
     return(record.StdfFile.GetRecords().SkipWhile(r => r.Offset <= record.Offset));
 }
Пример #6
0
 /// <summary>
 /// returns records that occur before the given record
 /// </summary>
 /// <param name="record">The "marker" record</param>
 /// <returns>All the records before the marker record</returns>
 static public IEnumerable <StdfRecord> Before(this StdfRecord record)
 {
     return(record.StdfFile.GetRecords().TakeWhile(r => r.Offset < record.Offset));
 }