private static RecordInputStream ConvertToInputStream(DrawingRecord r) { byte[] data = r.Serialize(); using (MemoryStream ms = new MemoryStream(data)) { RecordInputStream rinp = new RecordInputStream(ms); rinp.NextRecord(); return rinp; } }
/// <summary> /// Returns the next available record, or null if /// this pass didn't return a record that's /// suitable for returning (eg was a continue record). /// </summary> /// <returns></returns> private Record GetNextRecord() { Record toReturn = null; if (in1.HasNextRecord) { // Grab our next record in1.NextRecord(); short sid = in1.Sid; // // for some reasons we have to make the workbook to be at least 4096 bytes // but if we have such workbook we Fill the end of it with zeros (many zeros) // // it Is not good: // if the Length( all zero records ) % 4 = 1 // e.g.: any zero record would be Readed as 4 bytes at once ( 2 - id and 2 - size ). // And the last 1 byte will be Readed WRONG ( the id must be 2 bytes ) // // So we should better to Check if the sid Is zero and not to Read more data // The zero sid shows us that rest of the stream data Is a fake to make workbook // certain size // if (sid == 0) return null; // If we had a last record, and this one // Isn't a continue record, then pass // it on to the listener if ((rec != null) && (sid != ContinueRecord.sid)) { // This last record ought to be returned toReturn = rec; } // If this record Isn't a continue record, // then build it up if (sid != ContinueRecord.sid) { //Console.WriteLine("creating "+sid); Record[] recs = RecordFactory.CreateRecord(in1); // We know that the multiple record situations // don't contain continue records, so just // pass those on to the listener now if (recs.Length > 1) { bonusRecords = new ArrayList(recs.Length - 1); for (int k = 0; k < (recs.Length - 1); k++) { bonusRecords.Add(recs[k]); } } // Regardless of the number we Created, always hold // onto the last record to be Processed on the next // loop, in case it has any continue records rec = recs[recs.Length - 1]; // Don't return it just yet though, as we probably have // a record from the last round to return } else { // Normally, ContinueRecords are handled internally // However, in a few cases, there Is a gap between a record at // its Continue, so we have to handle them specially // This logic Is much like in RecordFactory.CreateRecords() Record[] recs = RecordFactory.CreateRecord(in1); ContinueRecord crec = (ContinueRecord)recs[0]; if ((lastRec is ObjRecord) || (lastRec is TextObjectRecord)) { // You can have Obj records between a DrawingRecord // and its continue! lastDrawingRecord.ProcessContinueRecord(crec.Data); // Trigger them on the drawing record, now it's complete rec = lastDrawingRecord; } else if ((lastRec is DrawingGroupRecord)) { ((DrawingGroupRecord)lastRec).ProcessContinueRecord(crec.Data); // Trigger them on the drawing record, now it's complete rec = lastRec; } else { if (rec is UnknownRecord) { ;//silently skip records we don't know about } else { throw new RecordFormatException("Records should handle ContinueRecord internally. Should not see this exception"); } } } // Update our tracking of the last record lastRec = rec; if (rec is DrawingRecord) { lastDrawingRecord = (DrawingRecord)rec; } } else { // No more records hitEOS = true; } // If we've hit the end-of-stream, then // finish off the last record and be done if (hitEOS) { complete = true; // Return the last record if there was // one, otherwise null if (rec != null) { toReturn = rec; rec = null; } } return toReturn; }
/** * Serializes this aggregate to a byte array. Since this Is an aggregate * record it will effectively Serialize the aggregated records. * * @param offset The offset into the start of the array. * @param data The byte array to Serialize to. * @return The number of bytes Serialized. */ public override int Serialize(int offset, byte [] data) { ConvertUserModelToRecords(); // Determine buffer size IList records = EscherRecords; int size = GetEscherRecordSize(records); byte[] buffer = new byte[size]; // Serialize escher records into one big data structure and keep note of ending offsets. spEndingOffsets = new ArrayList(); shapes = new ArrayList(); int pos = 0; for (IEnumerator iterator = records.GetEnumerator(); iterator.MoveNext(); ) { EscherRecord e = (EscherRecord)iterator.Current; pos += e.Serialize(pos, buffer, new SerializationListener(ref spEndingOffsets,ref shapes)); } // todo: fix this shapes.Insert(0, null); spEndingOffsets.Insert(0, null); // Split escher records into Separate MSODRAWING and OBJ, TXO records. (We don't break on // the first one because it's the patriach). pos = offset; for (int i = 1; i < shapes.Count; i++) { int endOffset = (int)spEndingOffsets[i] - 1; int startOffset; if (i == 1) startOffset = 0; else startOffset = (int)spEndingOffsets[i - 1]; // Create and Write a new MSODRAWING record DrawingRecord drawing = new DrawingRecord(); byte[] drawingData = new byte[endOffset - startOffset + 1]; Array.Copy(buffer, startOffset, drawingData, 0, drawingData.Length); drawing.Data=drawingData; int temp = drawing.Serialize(pos, data); pos += temp; // Write the matching OBJ record Record obj = (Record)shapeToObj[shapes[i]]; temp = obj.Serialize(pos, data); pos += temp; } // Write records that need to be Serialized after all drawing Group records for (int i = 0; i < tailRec.Count; i++) { Record rec = (Record)tailRec[i]; pos += rec.Serialize(pos, data); } int bytesWritten = pos - offset; if (bytesWritten != RecordSize) throw new RecordFormatException(bytesWritten + " bytes written but RecordSize reports " + RecordSize); return bytesWritten; }
public override Object Clone() { DrawingRecord rec = new DrawingRecord(); rec.recordData = (byte[])recordData.Clone();// new byte[recordData.Length]; if (contd != null) { rec.contd = (byte[])contd.Clone(); } return rec; }
public DrawingRecordForBiffViewer(DrawingRecord r) : base(ConvertToInputStream(r)) { ConvertRawBytesToEscherRecords(); }