using System; using System.Collections.Generic; using System.Text; using System.Collections; namespace FastReport.Export.BIFF8 { class BIFF8_ShapeProp { UInt16 complex; UInt32 union; Byte[] data; // UInt32 Id; internal UInt32 ReadProperty(StreamHelper stream) { complex = stream.ReadUshort(); union = stream.ReadUint(); if ((complex & 0x8000) == 0) { return 6; } else { return 6 + union; } } internal void ReadPayload(StreamHelper stream) { if ((complex & 0x8000) != 0) { data = stream.ReadBytes((int)union); } } internal void WriteProperty(StreamHelper stream) { stream.WriteUshort(complex); stream.WriteUint(union); } internal void WritePayload(StreamHelper stream) { if ((complex & 0x8000) != 0) { stream.WriteBytes(data); } } public BIFF8_ShapeProp() { } public BIFF8_ShapeProp(UInt16 Complex, UInt32 Union) { this.complex = Complex; this.union = Union; } public BIFF8_ShapeProp(UInt16 Complex, UInt32 Union, Byte[] Data) { this.complex = Complex; this.union = Union; this.data = Data; } public BIFF8_ShapeProp(UInt16 Complex, string value) { this.complex = (ushort)(Complex | 0xc000); data = new byte[value.Length * 2 + 2]; int i = 0; foreach (char ch in value) { data[i++] = (byte)ch; data[i++] = (byte)((ushort)ch >> 8); } data[i++] = 0; data[i] = 0; this.union = (uint)(this.data.Length); } } class BIFF8_ExcelDrawing { // msofbtSp UInt32 spid; UInt32 grfPersistent; // msofbtClientAnchor UInt16 unknown; UInt16 left_col; UInt16 left_off; UInt16 top_row; UInt16 top_off; UInt16 right_col; UInt16 right_off; UInt16 bottom_row; UInt16 bottom_off; // ftCmo: Common object data UInt16 objectType; UInt16 objectID; UInt16 optionFlags; // ftCf: Clipboard format UInt16 ftCf; // ftPioGrbit: Picture option flags UInt16 ftPioGrbit; ArrayList prop_list = new ArrayList(); UInt32 first_shape_id = 1024; /// /// Related to DRAWING group. Used once /// UInt32 csp; // The number of shapes in this drawing UInt32 spidCur; // The last MSOSPID given to an SP in this DG internal long total_spgr_size_position; internal long total_dg_size_position; private void ReadSpgrContainer(StreamHelper stream, uint dg_record_size) { while (dg_record_size > 0) { UInt16 _packed_data = stream.ReadUshort(); UInt16 _fbt = stream.ReadUshort(); UInt32 _total_record_size = stream.ReadUint(); if (_fbt != 0xf004) throw new Exception("Group container format error"); ReadSpContainer(stream, _total_record_size); dg_record_size -= _total_record_size + 8; } } private void ReadDgContainer(StreamHelper stream, UInt32 container_size) { while (container_size > 0) { UInt16 dg_packed_data = stream.ReadUshort(); UInt16 dg_fbt = stream.ReadUshort(); UInt32 dg_record_size = stream.ReadUint(); switch (dg_fbt) { case 0xf008: // msofbtDg csp = stream.ReadUint(); // The number of shapes in this drawing spidCur = stream.ReadUint(); // The last MSOSPID given to an SP in this DG break; case 0xf003: // msofbtSpgrContainer dg_record_size = container_size - 8; ReadSpgrContainer(stream, dg_record_size); break; } container_size -= dg_record_size + 8; } } private void ReadSpContainer(StreamHelper stream, UInt32 container_size) { while (container_size > 0) { UInt16 sp_packed_data = stream.ReadUshort(); UInt16 sp_fbt = stream.ReadUshort(); UInt32 sp_record_size = stream.ReadUint(); switch (sp_fbt) { case 0xf009: // msofbtSpgr UInt32 x = stream.ReadUint(); UInt32 y = stream.ReadUint(); UInt32 dx = stream.ReadUint(); UInt32 dy = stream.ReadUint(); break; case 0xf00a: // msofbtSp spid = stream.ReadUint(); grfPersistent = stream.ReadUint(); break; case 0xf00b: // msofbtOPT UInt32 local_size = sp_record_size; while (local_size > 0) { BIFF8_ShapeProp prop = new BIFF8_ShapeProp(); UInt32 prop_size = prop.ReadProperty(stream); prop_list.Add(prop); local_size -= prop_size; } foreach (BIFF8_ShapeProp prop in prop_list) { prop.ReadPayload(stream); } break; case 0xf010: // msofbtClientAnchor unknown = stream.ReadUshort(); left_col = stream.ReadUshort(); left_off = stream.ReadUshort(); top_row = stream.ReadUshort(); top_off = stream.ReadUshort(); right_col = stream.ReadUshort(); right_off = stream.ReadUshort(); bottom_row = stream.ReadUshort(); bottom_off = stream.ReadUshort(); break; case 0xf011: // msofbtClientData stream.SkipBytes((int)sp_record_size); break; default: throw new Exception("Sp container format error"); } container_size -= sp_record_size + 8; } } internal void Read(StreamHelper stream, UInt32 record_size) { UInt16 packed_data = stream.ReadUshort(); UInt16 fbt = stream.ReadUshort(); UInt32 total_record_size = stream.ReadUint(); record_size -= 8; switch (fbt) { case 0xf002: // DgContainer ReadDgContainer(stream, record_size); break; case 0xf004: // SpContainer ReadSpContainer(stream, record_size); break; default: throw new Exception("Drawing structure error"); } } internal void Read_GraphicsObject(StreamHelper stream, UInt32 RecordSize) { for (UInt16 sub_size = (UInt16)RecordSize; sub_size > 0;) { UInt16 SubRecordID = stream.ReadUshort(); UInt16 SubRecordSize = stream.ReadUshort(); switch (SubRecordID) { case 0x0015: // ftCmo: Common object data objectType = stream.ReadUshort(); objectID = stream.ReadUshort(); optionFlags = stream.ReadUshort(); stream.SkipBytes(12); break; case 0x0007: // ftCf: Clipboard format ftCf = stream.ReadUshort(); break; case 0x0008: // ftPioGrbit: Picture option flags ftPioGrbit = stream.ReadUshort(); break; case 0x0000: // ftEnd: The ftEnd file type marks the end of an OBJ record. if (SubRecordSize != 0) { throw new Exception("Bad forrmat of ftEnd record"); } break; default: throw new Exception("Unknown subrecord type in 005dh record"); } sub_size -= (ushort)(SubRecordSize + sizeof(UInt16) + sizeof(UInt16)); } } internal void Write_GraphicsObject(StreamHelper stream) { stream.WriteUshort(0x005d); // GOBJ stream.WriteUshort(38); stream.WriteUshort(0x0015); // GOBJ::ftCmo stream.WriteUshort(18); stream.WriteUshort(objectType); stream.WriteUshort(objectID); stream.WriteUshort(optionFlags); stream.SkipBytes(12); stream.WriteUshort(0x0007); // GOBJ::ftCf stream.WriteUshort(2); stream.WriteUshort(ftCf); stream.WriteUshort(0x0008); // GOBJ::ftPioGrbit stream.WriteUshort(2); stream.WriteUshort(ftPioGrbit); stream.WriteUshort(0x0000); // GOBJ::ftEnd stream.WriteUshort(0); } private void WriteSpOptions(StreamHelper stream) { stream.WriteUshort(0x00b3); stream.WriteUshort(0xf00b); long opt_size_position = stream.Position; stream.WriteUint(0x0000); foreach (BIFF8_ShapeProp prop in prop_list) prop.WriteProperty(stream); foreach (BIFF8_ShapeProp prop in prop_list) prop.WritePayload(stream); // Fix options size long curr_position = stream.Position; stream.Position = opt_size_position; opt_size_position = curr_position - opt_size_position - sizeof(UInt32); stream.WriteUint((ushort)opt_size_position); stream.Position = curr_position; } private uint Write_SpContainer(StreamHelper stream) { stream.WriteUshort(0x000f); stream.WriteUshort(0xf004); // SpContainer long container_size_position = stream.Position; stream.WriteUint(0x0000); // SP stream.WriteUshort(0x04b2); stream.WriteUshort(0xf00a); stream.WriteUint(0x0008); stream.WriteUint(spid); stream.WriteUint(grfPersistent); // OPT WriteSpOptions(stream); // ClientAnchor stream.WriteUshort(0x0000); stream.WriteUshort(0xf010); stream.WriteUint(0x0012); stream.WriteUshort(unknown); stream.WriteUshort(left_col); stream.WriteUshort(left_off); stream.WriteUshort(top_row); stream.WriteUshort(top_off); stream.WriteUshort(right_col); stream.WriteUshort(right_off); stream.WriteUshort(bottom_row); stream.WriteUshort(bottom_off); // ClientData stream.WriteUshort(0x0000); stream.WriteUshort(0xf011); stream.WriteUint(0x0000); long curr_position = stream.Position; stream.Position = container_size_position; container_size_position = curr_position - container_size_position - sizeof(UInt32); stream.WriteUint((ushort)container_size_position); stream.Position = curr_position; return (uint)(container_size_position + 8); } private uint Write_SpgrContainer(StreamHelper stream) { stream.WriteUshort(0x000f); // SPGR stream.WriteUshort(0xf003); total_spgr_size_position = stream.Position; stream.WriteUint(0x0000); stream.WriteUshort(0x000f); // SpContainer stream.WriteUshort(0xf004); stream.WriteUint(0x0028); stream.WriteUshort(0x0001); // msofbtSpgr stream.WriteUshort(0xf009); stream.WriteUint(0x0010); stream.WriteUint(0); // x stream.WriteUint(0); // y stream.WriteUint(0); // dx stream.WriteUint(0); // dy // SP stream.WriteUshort(0x0002); stream.WriteUshort(0xf00a); stream.WriteUint(0x0008); stream.WriteUint(first_shape_id /*1024*/); // First shape ID 1024 stream.WriteUint(5); // Bitfield for root record. uint container_size = Write_SpContainer(stream); return container_size + 48; } internal uint Write(StreamHelper stream, bool drawing_group) { uint multiple_sp_size = 0; stream.WriteUshort(0x00ec); // DRAWING long drawing_size_position = stream.Position; stream.WriteUshort(0x0000); if (drawing_group) { // DG container stream.WriteUshort(0x000f); stream.WriteUshort(0xf002); total_dg_size_position = stream.Position; stream.WriteUint(0x0000); // DG stream.WriteUshort(0x0010); stream.WriteUshort(0xf008); // DG stream.WriteUint(0x0008); stream.WriteUint(csp + 1); // The number of shapes in this drawing stream.WriteUint(spidCur); // The last MSOSPID given to an SP in this DG multiple_sp_size += Write_SpgrContainer(stream); } else { multiple_sp_size += Write_SpContainer(stream); } long curr_position = stream.Position; stream.Position = drawing_size_position; drawing_size_position = curr_position - drawing_size_position - sizeof(UInt16); stream.WriteUshort((ushort)drawing_size_position); stream.Position = curr_position; return multiple_sp_size; } internal void AddPicureToSheet( FastReport.Export.ExportIEMObject Obj, int index, int x, int y, int dx, int dy) { this.csp = (uint)(index + 1); this.spidCur = this.csp + first_shape_id; this.unknown = 2; this.left_col = (ushort)x; this.left_off = 0; this.top_row = (ushort)y; this.top_off = 0; this.right_col = (ushort)(x + dx); this.right_off = 0; this.bottom_row = (ushort)(y + dy); this.bottom_off = 0; this.right_off = 3; // 256; this.bottom_off = 3; // 205; this.spid = spidCur; this.grfPersistent = 0xa00; // ftCmo: Common object data this.objectType = 0x0008; this.objectID = (ushort)csp; // 0x002a; this.optionFlags = 0x6011; this.ftCf = 0xffff; this.ftPioGrbit = 0x0001; prop_list.Add(new BIFF8_ShapeProp(127, 0x01fb0080)); // fLockAgainstGrouping prop_list.Add(new BIFF8_ShapeProp(191, 0x00040004)); // fFitTextToShape prop_list.Add(new BIFF8_ShapeProp(260 | 0x4000, csp)); // fFitTextToShape prop_list.Add(new BIFF8_ShapeProp(261, "pib" + csp.ToString() + ".png")); // pibName prop_list.Add(new BIFF8_ShapeProp(319, 0x00060000)); // pictureActive prop_list.Add(new BIFF8_ShapeProp(447, 0x00110000)); // fNoFillHitTest prop_list.Add(new BIFF8_ShapeProp(511, 0x00180010)); // fNoLineDrawDash prop_list.Add(new BIFF8_ShapeProp(831, 0x00180010)); // fBackground prop_list.Add(new BIFF8_ShapeProp(896, "pic" + csp.ToString())); // wzName prop_list.Add(new BIFF8_ShapeProp(897, "")); // wzDescription is empty prop_list.Add(new BIFF8_ShapeProp(959, 0x00020000)); // ?? } internal BIFF8_ExcelDrawing() { } } }