using System; using System.Collections.Generic; using System.IO; using Bloomberg.Message.Entities; using Bloomberg.Message.Utils; namespace Bloomberg.Message.Reader { public class DataInfoReader { private readonly DataReader _dataReader = new DataReader(); private static log4net.ILog _log = log4net.LogManager.GetLogger(typeof(DataInfoReader)); public List Read(Stream currentStream, string savePath, ref bool errorDetected) { var dataList = new List(); uint lastReadMarker = ReadingForDataInfoStartMarker(dataList, currentStream, ref errorDetected); if(lastReadMarker != MessageConstants.DataInfoStartMarker) { return dataList; } bool endOfDataList = false; do { if(lastReadMarker != MessageConstants.DataStartMarker && lastReadMarker != MessageConstants.DataInfoEndMarker) { lastReadMarker = ReadUpToDataStartMarkerOrDataInfoEndMarker(dataList, currentStream, ref errorDetected); } switch (lastReadMarker) { case MessageConstants.DataStartMarker: DataElement newDataElement = new DataElement(); try { _dataReader.Read(currentStream, savePath, ref newDataElement, ref errorDetected); lastReadMarker = ReadUpToDataEndMarker(dataList, currentStream, ref errorDetected); } catch (Exception e) { errorDetected = true; newDataElement.Error = $"DataInfoReader - Caught the following exception while reading: \r\n{e.Message}"; if (string.IsNullOrEmpty(newDataElement.Name)) { newDataElement.Name = "n/a"; } _log.Error("Error in DataInfoReader", e); lastReadMarker = 0; } dataList.Add(newDataElement); break; case MessageConstants.DataInfoEndMarker: //just continue endOfDataList = true; break; default: //no marker found. end parsing _log.Warn("DataInfoReader - Bad marker found " + MessageConstants.GetMarkerName(lastReadMarker)); endOfDataList = true; break; } } while (!endOfDataList); return dataList; } private uint ReadingForDataInfoStartMarker(List dataList, Stream currentStream, ref bool errorDetected) { while (true) { uint foundMarker; if (ReaderHelper.ScanForSpecificMarkerNoSeek(currentStream, out foundMarker, MessageConstants.DataInfoStartMarker)) { return foundMarker; } string foundMarkerName = MessageConstants.GetMarkerName(foundMarker); switch (foundMarker) { case MessageConstants.DataInfoStartMarker: //what we wanted, just keep going but log this and add error dataelement because it wasn't the first read that returned this constant MessageReader.LogErrorDataElement(ref errorDetected, $"Unrecognized data before marker {foundMarkerName}", dataList); return foundMarker; case MessageConstants.MessageEndMarker: //just end streaming return foundMarker; case MessageConstants.ReportStartMarker: case MessageConstants.ReportEndMarker: case MessageConstants.DataInfoEndMarker: case MessageConstants.VariableLengthStartMarker: case MessageConstants.VariableLengthEndMarker: case MessageConstants.DataEndMarker: case MessageConstants.AttributeStartMarker: case MessageConstants.AttributeEndMarker: case MessageConstants.MessageStartMarker: MessageReader.LogErrorDataElement(ref errorDetected, $"Unexpected marker found before DataInfoStartMarker: {foundMarkerName}", dataList); break; case MessageConstants.DataStartMarker: //next best thing, we can start a data element with this just rewind the stream a bit MessageReader.LogErrorDataElement(ref errorDetected, $"Unexpected marker found before DataInfoStartMarker: {foundMarkerName}. Continuing with parsing the message.", dataList); return foundMarker; default: MessageReader.LogErrorDataElement(ref errorDetected, "No recognizeable marker found and end of stream reached while looking for DataInfoStartMarker", dataList); return foundMarker; } } } private uint ReadUpToDataStartMarkerOrDataInfoEndMarker(List dataList, Stream currentStream, ref bool errorDetected) { while (true) { uint foundMarker; if (ReaderHelper.ScanForSpecificMarkersNoSeek(currentStream, out foundMarker, MessageConstants.DataStartMarker, MessageConstants.DataInfoEndMarker)) { return foundMarker; } string foundMarkerName = MessageConstants.GetMarkerName(foundMarker); switch (foundMarker) { case MessageConstants.DataStartMarker: //what we wanted, just keep going but log this and add error dataelement because it wasn't the first read that returned this constant MessageReader.LogErrorDataElement(ref errorDetected, $"Unrecognized data before marker {foundMarkerName}", dataList); return foundMarker; case MessageConstants.DataInfoEndMarker: //the end of data info marker is found MessageReader.LogErrorDataElement(ref errorDetected, $"Unrecognized data before marker {foundMarkerName}", dataList); return MessageConstants.DataInfoEndMarker; case MessageConstants.MessageEndMarker: //stop reading MessageReader.LogErrorDataElement(ref errorDetected, $"Unrecognized data before marker {foundMarkerName}", dataList); return MessageConstants.MessageEndMarker; case MessageConstants.DataInfoStartMarker: case MessageConstants.ReportStartMarker: case MessageConstants.ReportEndMarker: case MessageConstants.VariableLengthStartMarker: case MessageConstants.VariableLengthEndMarker: case MessageConstants.DataEndMarker: case MessageConstants.AttributeStartMarker: case MessageConstants.AttributeEndMarker: case MessageConstants.MessageStartMarker: MessageReader.LogErrorDataElement(ref errorDetected, $"Unexpected marker found before DataInfoStartMarker or DataInfoEndMarker: {foundMarkerName}", dataList); break; default: MessageReader.LogErrorDataElement(ref errorDetected, "No recognizeable marker found and end of stream reached while looking for DataInfoStartMarker or DataInfoEndMarker", dataList); return 0; } } } private uint ReadUpToDataEndMarker(List dataList, Stream currentStream, ref bool errorDetected) { while (true) { uint foundMarker; if (ReaderHelper.ScanForSpecificMarkerNoSeek(currentStream, out foundMarker, MessageConstants.DataEndMarker)) { return foundMarker; } string foundMarkerName = MessageConstants.GetMarkerName(foundMarker); switch (foundMarker) { case MessageConstants.DataStartMarker: //the DataEndMarker is missing but keep reading to parse the new DataElement. Just rewind a little so the next scan for DataStartMarker works MessageReader.LogErrorDataElement(ref errorDetected, $"Unexpected marker found before marker DataEndMarker: {foundMarkerName}", dataList); return foundMarker; case MessageConstants.DataEndMarker: //there was some data before the end of the expected DataElement serialization MessageReader.LogErrorDataElement(ref errorDetected, $"Unexpected data before marker DataEndMarker: {foundMarkerName}", dataList); return foundMarker; case MessageConstants.DataInfoStartMarker: case MessageConstants.MessageEndMarker: case MessageConstants.ReportStartMarker: case MessageConstants.ReportEndMarker: case MessageConstants.VariableLengthStartMarker: case MessageConstants.VariableLengthEndMarker: case MessageConstants.DataInfoEndMarker: case MessageConstants.AttributeStartMarker: case MessageConstants.AttributeEndMarker: case MessageConstants.MessageStartMarker: MessageReader.LogErrorDataElement(ref errorDetected, $"Unexpected marker found before DataEndMarker: {foundMarkerName}", dataList); break; default: MessageReader.LogErrorDataElement(ref errorDetected, "No recognizeable marker found or end of stream reached while looking for DataEndMarker", dataList); return foundMarker; } } } } }