BIFF8_MSODrawingGroup.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. using System.Collections;
  6. namespace FastReport.Export.BIFF8
  7. {
  8. internal class BIFF8_MSODrawingRecord
  9. {
  10. Byte btWin32;
  11. Byte btMacOS;
  12. Byte[] uid;
  13. UInt16 tag;
  14. UInt32 size;
  15. UInt32 ref_count;
  16. UInt32 file_offset;
  17. Byte usage;
  18. Byte cbName;
  19. UInt16 picture_type;
  20. UInt16 blip_packed;
  21. // Byte[] UID0;
  22. Byte[] pic;
  23. Byte image_tag;
  24. ushort packed_options;
  25. internal void AddReference() { ref_count++; }
  26. internal void Read(StreamHelper stream, ushort packed_options)
  27. {
  28. btWin32 = (Byte)stream.ReadByte();
  29. btMacOS = (Byte)stream.ReadByte();
  30. uid = stream.ReadBytes(16);
  31. tag = stream.ReadUshort();
  32. size = stream.ReadUint();
  33. ref_count = stream.ReadUint();
  34. file_offset = stream.ReadUint();
  35. usage = (Byte)stream.ReadByte();
  36. cbName = (Byte)stream.ReadByte();
  37. stream.SkipBytes(2);
  38. this.packed_options = packed_options;
  39. }
  40. internal void Read_Picture(StreamHelper stream, UInt16 blip_packed, UInt16 type, int picture_size)
  41. {
  42. // picture_size = (int)blip_record_size - 17;
  43. Byte[] UID0;
  44. UID0 = stream.ReadBytes(16);
  45. //// Byte[] UID1 = ReadBytes(16);
  46. image_tag = (Byte)stream.ReadByte();
  47. pic = stream.ReadBytes(picture_size);
  48. this.picture_type = type;
  49. this.blip_packed = blip_packed;
  50. //FileStream f = new FileStream(@"C:\Users\alman\Documents\pict.png", FileMode.Create);
  51. //f.Write(pic, 0, pic.Length);
  52. //f.Close();
  53. }
  54. internal uint Write_Picture(StreamHelper stream)
  55. {
  56. uint payload_size = (uint)(uid.Length + 1 + pic.Length);
  57. stream.WriteUshort(this.blip_packed); // 0x6e00
  58. stream.WriteUshort(this.picture_type); // PNG = 0xf01e
  59. stream.WriteUint(payload_size);
  60. stream.WriteBytes(uid);
  61. //// stream.WriteBytes(UID1);
  62. stream.WriteByte(image_tag);
  63. stream.WriteBytes(pic);
  64. //FileStream f = new FileStream(@"C:\Users\alman\Documents\pict.png", FileMode.Create);
  65. //f.Write(pic, 0, pic.Length);
  66. //f.Close();
  67. return payload_size + 8;
  68. }
  69. internal void Write(StreamHelper stream)
  70. {
  71. stream.WriteUshort(packed_options); // 0x0052
  72. stream.WriteUshort(0xf007); // BSE
  73. long bse_size_position = stream.Position;
  74. stream.WriteUint(0x0000);
  75. stream.WriteByte(btWin32);
  76. stream.WriteByte(btMacOS);
  77. stream.WriteBytes(uid);
  78. stream.WriteUshort(tag);
  79. stream.WriteUint(size);
  80. stream.WriteUint(ref_count);
  81. stream.WriteUint(file_offset);
  82. stream.WriteByte(usage);
  83. stream.WriteByte(cbName);
  84. stream.SkipBytes(2);
  85. uint blip_size = Write_Picture(stream);
  86. long current_position = stream.Position;
  87. blip_size += 36;
  88. stream.Position = bse_size_position;
  89. stream.WriteUint((UInt32)blip_size);
  90. stream.Position = current_position;
  91. }
  92. internal void LoadPicture(FastReport.Export.ExportIEMObject Obj, int index)
  93. {
  94. btWin32 = 6; // PNG
  95. btMacOS = 6; // PNG
  96. uid = new byte[16];
  97. tag = 0xff;
  98. size = (uint)(8 + 16 + 1 + Obj.PictureStream.Length);
  99. ref_count = 1;
  100. file_offset = 0;
  101. usage = 0;
  102. cbName = 0;
  103. pic = new byte[Obj.PictureStream.Length];
  104. Obj.PictureStream.Position = 0;
  105. Obj.PictureStream.Read(pic, 0, (int)Obj.PictureStream.Length);
  106. // Take midddle bytes as hash
  107. int idx = pic.Length / 2;
  108. for (int i = 0; i < 16; i++)
  109. uid[i] = pic[i + idx];
  110. uid[0] = (byte)index;
  111. uid[15] = (byte)(index >> 4);
  112. picture_type = 0xf01e;
  113. blip_packed = 0x6e00;
  114. image_tag = 0xff;
  115. packed_options = 0x62;
  116. }
  117. }
  118. class BIFF8_MSODrawingGroup : ArrayList
  119. {
  120. UInt32 mso_spid;
  121. UInt32 cidcl;
  122. UInt32 cspSaved;
  123. UInt32 cdgSaved;
  124. ArrayList prop_list = new ArrayList();
  125. UInt32 fillColor;
  126. UInt32 lineColor;
  127. UInt32 shadowColor;
  128. UInt32 threeDColor;
  129. private void Read_BstoreContainer(StreamHelper stream, UInt32 loop_record_size)
  130. {
  131. BIFF8_MSODrawingRecord local_record = new BIFF8_MSODrawingRecord();
  132. while (loop_record_size > 0)
  133. {
  134. UInt16 blip_packed_data = stream.ReadUshort();
  135. UInt16 blip_fbt = stream.ReadUshort();
  136. UInt32 blip_record_size = stream.ReadUint();
  137. // Get BLIP data
  138. switch (blip_fbt)
  139. {
  140. case 0xf007: // msofbtBSE
  141. local_record = new BIFF8_MSODrawingRecord();
  142. local_record.Read(stream, blip_packed_data);
  143. this.Add(local_record);
  144. loop_record_size -= 36 /*blip_record_size*/;
  145. break;
  146. case 0xf01e: // PNG
  147. case 0xf01d: // JPEG
  148. local_record.Read_Picture(stream, blip_packed_data, blip_fbt, (int)blip_record_size - 17);
  149. loop_record_size -= blip_record_size;
  150. break;
  151. default:
  152. throw new Exception("BLIP not parsed yet");
  153. }
  154. loop_record_size -= 8; //HEADER SIZE
  155. }
  156. }
  157. internal int Read(StreamHelper stream, int RecordSize)
  158. {
  159. long stored_position = stream.Position;
  160. UInt16 packed_data = stream.ReadUshort();
  161. UInt16 fbt = stream.ReadUshort();
  162. UInt32 total_record_size = stream.ReadUint();
  163. RecordSize -= sizeof(UInt16) + sizeof(UInt16) + sizeof(UInt32);
  164. if (RecordSize > total_record_size)
  165. {
  166. throw new Exception("MSODRAWINGGROUP: Data layout error");
  167. }
  168. if (RecordSize < total_record_size)
  169. {
  170. StreamHelper virtual_stream = new StreamHelper();
  171. int tail = (int)total_record_size;
  172. do
  173. {
  174. byte[] record = stream.ReadBytes(RecordSize);
  175. virtual_stream.WriteBytes(record);
  176. //stream.Position += RecordSize;
  177. tail -= RecordSize;
  178. if (tail == 0) break;
  179. UInt16 RecordID = stream.ReadUshort();
  180. if (RecordID != 0x0003c && RecordID != 0x000eb) // CONTINUE record
  181. {
  182. throw new Exception("MSODRAWINGGROUP: Data layout error");
  183. }
  184. RecordSize = stream.ReadUshort();
  185. }
  186. while (tail > 0);
  187. RecordSize = (int)(stream.Position - stored_position);
  188. stream = virtual_stream;
  189. stream.Position = 0;
  190. }
  191. else
  192. {
  193. RecordSize += sizeof(UInt16) + sizeof(UInt16) + sizeof(UInt32);
  194. }
  195. while (total_record_size > 0)
  196. {
  197. UInt16 dgg_packed_data = stream.ReadUshort();
  198. UInt16 dgg_fbt = stream.ReadUshort();
  199. UInt32 dgg_record_size = stream.ReadUint();
  200. long shift = stream.Position - stored_position;
  201. switch (dgg_fbt)
  202. {
  203. case 0xf001: // msofbtBstoreContainer
  204. this.Read_BstoreContainer(stream, dgg_record_size);
  205. break;
  206. case 0xf006: // msofbtDgg
  207. mso_spid = stream.ReadUint();
  208. cidcl = stream.ReadUint();
  209. cspSaved = stream.ReadUint();
  210. cdgSaved = stream.ReadUint();
  211. for (int cid_idx = 1; cid_idx < cidcl; cid_idx++)
  212. {
  213. UInt32 dgid = stream.ReadUint();
  214. UInt32 cspidCur = stream.ReadUint();
  215. }
  216. break;
  217. case 0xf00b: // msofbtOPT
  218. UInt32 local_size = dgg_record_size;
  219. while (local_size > 0)
  220. {
  221. BIFF8_ShapeProp prop = new BIFF8_ShapeProp();
  222. UInt32 prop_size = prop.ReadProperty(stream);
  223. prop_list.Add(prop);
  224. local_size -= prop_size;
  225. }
  226. foreach (BIFF8_ShapeProp prop in prop_list)
  227. {
  228. prop.ReadPayload(stream);
  229. }
  230. break;
  231. case 0xf11e: // msofbtSplitMenuColors
  232. fillColor = stream.ReadUint();
  233. lineColor = stream.ReadUint();
  234. shadowColor = stream.ReadUint();
  235. threeDColor = stream.ReadUint();
  236. break;
  237. default:
  238. stream.SkipBytes((int)dgg_record_size);
  239. break;
  240. }
  241. total_record_size -= 8 + dgg_record_size;
  242. }
  243. return RecordSize;
  244. }
  245. internal void Write(StreamHelper stream)
  246. {
  247. StreamHelper helper_stream = new StreamHelper();
  248. this.mso_spid = 1026;
  249. this.cidcl = 2;
  250. this.cspSaved = 2;
  251. this.cdgSaved = (uint)this.Count;
  252. prop_list.Add(new BIFF8_ShapeProp(191, 0x00080008));
  253. prop_list.Add(new BIFF8_ShapeProp(385, 0x08000041));
  254. prop_list.Add(new BIFF8_ShapeProp(448, 0x08000040));
  255. helper_stream.WriteUshort(0x000f);
  256. helper_stream.WriteUshort(0xf000); // msofbtDggContainer
  257. long dgg_container_size_position = helper_stream.Position;
  258. helper_stream.WriteUint(0); // fix me
  259. helper_stream.WriteUshort(0x0000);
  260. helper_stream.WriteUshort(0xf006); // msofbtDgg
  261. uint dgg_record_size = 16 + (cidcl - 1) * 8;
  262. helper_stream.WriteUint(dgg_record_size); // dgg_record_size
  263. helper_stream.WriteUint(mso_spid);
  264. helper_stream.WriteUint(cidcl);
  265. helper_stream.WriteUint(cspSaved);
  266. helper_stream.WriteUint(cdgSaved);
  267. for (int cid_idx = 1; cid_idx < cidcl; cid_idx++)
  268. {
  269. UInt32 dgid = 1; // fix me
  270. UInt32 cspidCur = 2; // fix me
  271. helper_stream.WriteUint(dgid);
  272. helper_stream.WriteUint(cspidCur);
  273. }
  274. helper_stream.WriteUshort((ushort)(0x000f | (this.Count << 4)));
  275. helper_stream.WriteUshort(0xf001); // msofbtBstoreContainer
  276. long bstore_size_position = helper_stream.Position;
  277. helper_stream.WriteUint(0x0000);
  278. foreach (BIFF8_MSODrawingRecord record in this)
  279. {
  280. record.Write(helper_stream);
  281. }
  282. long current_stream_position = helper_stream.Position;
  283. helper_stream.Position = bstore_size_position;
  284. bstore_size_position = current_stream_position - bstore_size_position - 4;
  285. helper_stream.WriteUint((uint)bstore_size_position);
  286. helper_stream.Position = current_stream_position;
  287. helper_stream.WriteUshort(0x0033);
  288. helper_stream.WriteUshort(0xf00b); // msofbtOPT
  289. long opt_size_position = helper_stream.Position;
  290. helper_stream.WriteUint(0x0000);
  291. foreach (BIFF8_ShapeProp prop in prop_list) prop.WriteProperty(helper_stream);
  292. foreach (BIFF8_ShapeProp prop in prop_list) prop.WritePayload(helper_stream);
  293. // Fix options size
  294. long curr_position = helper_stream.Position;
  295. helper_stream.Position = opt_size_position;
  296. opt_size_position = curr_position - opt_size_position - sizeof(UInt32);
  297. helper_stream.WriteUint((ushort)opt_size_position);
  298. helper_stream.Position = curr_position;
  299. // skip SplitMenuColors
  300. helper_stream.WriteUshort(0x0040);
  301. helper_stream.WriteUshort(0xf11e); // msofbtSplitMenuColors
  302. helper_stream.WriteUint(16);
  303. helper_stream.WriteUint(fillColor);
  304. helper_stream.WriteUint(lineColor);
  305. helper_stream.WriteUint(shadowColor);
  306. helper_stream.WriteUint(threeDColor);
  307. long last_byte_position = helper_stream.Position;
  308. helper_stream.Position = dgg_container_size_position;
  309. dgg_container_size_position = last_byte_position - dgg_container_size_position - 4;
  310. helper_stream.WriteUint((uint)dgg_container_size_position);
  311. helper_stream.Position = 0;
  312. // Split huge temporary stream into records
  313. int iteration_trick = 0;
  314. int tail_size = (int)helper_stream.Length;
  315. ushort chunk_size;
  316. while (tail_size > 0)
  317. {
  318. ushort item_type = (ushort)((iteration_trick < 2) ? 0x00eb : 0x003c);
  319. stream.WriteUshort(item_type); // MSODRAWINGGROUP : CONTINUE
  320. chunk_size = (ushort)((tail_size <= 8224) ? tail_size : 8224);
  321. stream.WriteUshort(chunk_size);
  322. byte[] pictures = helper_stream.ReadBytes(chunk_size);
  323. stream.WriteBytes(pictures);
  324. tail_size -= chunk_size;
  325. iteration_trick++;
  326. }
  327. helper_stream.Dispose();
  328. helper_stream = null;
  329. }
  330. }
  331. }