LibreOffice Module sw (master)  1
htmlreqifreader.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include "htmlreqifreader.hxx"
11 
14 #include <rtl/strbuf.hxx>
15 #include <sot/storage.hxx>
16 #include <svtools/parrtf.hxx>
17 #include <svtools/rtfkeywd.hxx>
18 #include <svtools/rtftoken.h>
19 #include <tools/stream.hxx>
21 #include <vcl/cvtgrf.hxx>
22 #include <ndole.hxx>
23 
24 namespace
25 {
27 class ReqIfRtfReader : public SvRTFParser
28 {
29 public:
30  ReqIfRtfReader(SvStream& rStream);
31  void NextToken(int nToken) override;
32  bool WriteObjectData(SvStream& rOLE);
33 
34 private:
35  bool m_bInObjData = false;
36  OStringBuffer m_aHex;
37 };
38 
39 ReqIfRtfReader::ReqIfRtfReader(SvStream& rStream)
40  : SvRTFParser(rStream)
41 {
42 }
43 
44 void ReqIfRtfReader::NextToken(int nToken)
45 {
46  switch (nToken)
47  {
48  case '}':
49  m_bInObjData = false;
50  break;
51  case RTF_TEXTTOKEN:
52  if (m_bInObjData)
53  m_aHex.append(OUStringToOString(aToken, RTL_TEXTENCODING_ASCII_US));
54  break;
55  case RTF_OBJDATA:
56  m_bInObjData = true;
57  break;
58  }
59 }
60 
61 bool ReqIfRtfReader::WriteObjectData(SvStream& rOLE)
62 {
63  return msfilter::rtfutil::ExtractOLE2FromObjdata(m_aHex.makeStringAndClear(), rOLE);
64 }
65 
67 OString ExtractOLEClassName(const tools::SvRef<SotStorage>& xStorage)
68 {
69  OString aRet;
70 
71  SotStorageStream* pCompObj = xStorage->OpenSotStream("\1CompObj");
72  if (!pCompObj)
73  return aRet;
74 
75  pCompObj->Seek(0);
76  pCompObj->SeekRel(28); // Header
77  if (!pCompObj->good())
78  return aRet;
79 
80  sal_uInt32 nData;
81  pCompObj->ReadUInt32(nData); // AnsiUserType
82  pCompObj->SeekRel(nData);
83  if (!pCompObj->good())
84  return aRet;
85 
86  pCompObj->ReadUInt32(nData); // AnsiClipboardFormat
87  pCompObj->SeekRel(nData);
88  if (!pCompObj->good())
89  return aRet;
90 
91  pCompObj->ReadUInt32(nData); // Reserved1
92  return read_uInt8s_ToOString(*pCompObj, nData);
93 }
94 
96 bool ParseOLE2Presentation(SvStream& rOle2, sal_uInt32& nWidth, sal_uInt32& nHeight,
97  SvStream& rPresentationData)
98 {
99  // See [MS-OLEDS] 2.3.4, OLEPresentationStream
100  rOle2.Seek(0);
101  tools::SvRef<SotStorage> pStorage = new SotStorage(rOle2);
102  tools::SvRef<SotStorageStream> xOle2Presentation
103  = pStorage->OpenSotStream("\002OlePres000", StreamMode::STD_READ);
104 
105  // Read AnsiClipboardFormat.
106  sal_uInt32 nMarkerOrLength = 0;
107  xOle2Presentation->ReadUInt32(nMarkerOrLength);
108  if (nMarkerOrLength != 0xffffffff)
109  // FormatOrAnsiString is not present
110  return false;
111  sal_uInt32 nFormatOrAnsiLength = 0;
112  xOle2Presentation->ReadUInt32(nFormatOrAnsiLength);
113  if (nFormatOrAnsiLength != 0x00000003) // CF_METAFILEPICT
114  return false;
115 
116  // Read TargetDeviceSize.
117  sal_uInt32 nTargetDeviceSize = 0;
118  xOle2Presentation->ReadUInt32(nTargetDeviceSize);
119  if (nTargetDeviceSize != 0x00000004)
120  // TargetDevice is present
121  return false;
122 
123  sal_uInt32 nAspect = 0;
124  xOle2Presentation->ReadUInt32(nAspect);
125  sal_uInt32 nLindex = 0;
126  xOle2Presentation->ReadUInt32(nLindex);
127  sal_uInt32 nAdvf = 0;
128  xOle2Presentation->ReadUInt32(nAdvf);
129  sal_uInt32 nReserved1 = 0;
130  xOle2Presentation->ReadUInt32(nReserved1);
131  xOle2Presentation->ReadUInt32(nWidth);
132  xOle2Presentation->ReadUInt32(nHeight);
133  sal_uInt32 nSize = 0;
134  xOle2Presentation->ReadUInt32(nSize);
135 
136  // Read Data.
137  if (nSize > xOle2Presentation->remainingSize())
138  return false;
139  std::vector<char> aBuffer(nSize);
140  xOle2Presentation->ReadBytes(aBuffer.data(), aBuffer.size());
141  rPresentationData.WriteBytes(aBuffer.data(), aBuffer.size());
142 
143  return true;
144 }
145 
147 OString InsertOLE1Header(SvStream& rOle2, SvStream& rOle1, sal_uInt32& nWidth, sal_uInt32& nHeight)
148 {
149  rOle2.Seek(0);
150  tools::SvRef<SotStorage> xStorage(new SotStorage(rOle2));
151  if (xStorage->GetError() != ERRCODE_NONE)
152  return OString();
153 
154  OString aClassName = ExtractOLEClassName(xStorage);
155 
156  // Write ObjectHeader, see [MS-OLEDS] 2.2.4.
157  rOle1.Seek(0);
158  // OLEVersion.
159  rOle1.WriteUInt32(0x00000501);
160 
161  // FormatID is EmbeddedObject.
162  rOle1.WriteUInt32(0x00000002);
163 
164  // ClassName
165  rOle1.WriteUInt32(aClassName.getLength());
166  if (!aClassName.isEmpty())
167  {
168  rOle1.WriteOString(aClassName);
169  // Null terminated pascal string.
170  rOle1.WriteChar(0);
171  }
172 
173  // TopicName.
174  rOle1.WriteUInt32(0);
175 
176  // ItemName.
177  rOle1.WriteUInt32(0);
178 
179  // NativeDataSize
180  rOle1.WriteUInt32(rOle2.TellEnd());
181 
182  // Write the actual native data.
183  rOle2.Seek(0);
184  rOle1.WriteStream(rOle2);
185 
186  // Write Presentation.
187  SvMemoryStream aPresentationData;
188  if (ParseOLE2Presentation(rOle2, nWidth, nHeight, aPresentationData))
189  {
190  // OLEVersion.
191  rOle1.WriteUInt32(0x00000501);
192  // FormatID: constant means the ClassName field is present.
193  rOle1.WriteUInt32(0x00000005);
194  // ClassName: null terminated pascal string.
195  OString aPresentationClassName("METAFILEPICT");
196  rOle1.WriteUInt32(aPresentationClassName.getLength() + 1);
197  rOle1.WriteOString(aPresentationClassName);
198  rOle1.WriteChar(0);
199  // Width.
200  rOle1.WriteUInt32(nWidth);
201  // Height.
202  rOle1.WriteUInt32(nHeight * -1);
203  // PresentationDataSize
204  sal_uInt32 nPresentationData = aPresentationData.Tell();
205  rOle1.WriteUInt32(8 + nPresentationData);
206  // Reserved1-4.
207  rOle1.WriteUInt16(0x0008);
208  rOle1.WriteUInt16(0x31b1);
209  rOle1.WriteUInt16(0x1dd9);
210  rOle1.WriteUInt16(0x0000);
211  aPresentationData.Seek(0);
212  rOle1.WriteStream(aPresentationData, nPresentationData);
213  }
214 
215  return aClassName;
216 }
217 
219 void WrapOleGraphicInRtf(SvStream& rRtf, const SwOLENode& rOLENode, const Graphic& rGraphic)
220 {
221  // Start result.
222  rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_RESULT);
223 
224  // Start pict.
225  rRtf.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_PICT);
226 
227  rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_WMETAFILE "8");
228  Size aSize(rOLENode.GetTwipSize());
229  rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICW);
230  rRtf.WriteCharPtr(OString::number(aSize.getWidth()).getStr());
231  rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICH);
232  rRtf.WriteCharPtr(OString::number(aSize.getHeight()).getStr());
233  rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICWGOAL);
234  rRtf.WriteCharPtr(OString::number(aSize.getWidth()).getStr());
235  rRtf.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
236  rRtf.WriteCharPtr(OString::number(aSize.getHeight()).getStr());
237  SvMemoryStream aGraphicStream;
238  if (GraphicConverter::Export(aGraphicStream, rGraphic, ConvertDataFormat::WMF) == ERRCODE_NONE)
239  {
240  auto pGraphicAry = static_cast<const sal_uInt8*>(aGraphicStream.GetData());
241  sal_uInt64 nSize = aGraphicStream.TellEnd();
242  msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nSize);
243  rRtf.WriteCharPtr(SAL_NEWLINE_STRING);
244  msfilter::rtfutil::WriteHex(pGraphicAry, nSize, &rRtf);
245  }
246 
247  // End pict.
248  rRtf.WriteCharPtr("}");
249 
250  // End result.
251  rRtf.WriteCharPtr("}");
252 }
253 }
254 
255 namespace SwReqIfReader
256 {
257 bool ExtractOleFromRtf(SvStream& rRtf, SvStream& rOle, bool& bOwnFormat)
258 {
259  // Add missing header/footer.
260  SvMemoryStream aRtf;
261  aRtf.WriteOString("{\\rtf1");
262  aRtf.WriteStream(rRtf);
263  aRtf.WriteOString("}");
264  aRtf.Seek(0);
265 
266  // Read the RTF markup.
267  tools::SvRef<ReqIfRtfReader> xReader(new ReqIfRtfReader(aRtf));
268  SvParserState eState = xReader->CallParser();
269  if (eState == SvParserState::Error)
270  return false;
271 
272  // Write the OLE2 data.
273  if (!xReader->WriteObjectData(rOle))
274  return false;
275 
276  tools::SvRef<SotStorage> pStorage = new SotStorage(rOle);
277  OUString aFilterName = SvxMSDffManager::GetFilterNameFromClassID(pStorage->GetClassName());
278  bOwnFormat = !aFilterName.isEmpty();
279  if (!bOwnFormat)
280  {
281  // Real OLE2 data, we're done.
282  rOle.Seek(0);
283  return true;
284  }
285 
286  // ODF-in-OLE2 case, extract actual data.
287  SvMemoryStream aMemory;
288  SvxMSDffManager::ExtractOwnStream(*pStorage, aMemory);
289  rOle.Seek(0);
290  aMemory.Seek(0);
291  rOle.WriteStream(aMemory);
292  // Stream length is current position + 1.
293  rOle.SetStreamSize(aMemory.GetSize() + 1);
294  rOle.Seek(0);
295  return true;
296 }
297 
298 bool WrapOleInRtf(SvStream& rOle2, SvStream& rRtf, SwOLENode& rOLENode)
299 {
300  sal_uInt64 nPos = rOle2.Tell();
301  comphelper::ScopeGuard g([&rOle2, nPos] { rOle2.Seek(nPos); });
302 
303  // Write OLE1 header, then the RTF wrapper.
304  SvMemoryStream aOLE1;
305  sal_uInt32 nWidth = 0;
306  sal_uInt32 nHeight = 0;
307  OString aClassName = InsertOLE1Header(rOle2, aOLE1, nWidth, nHeight);
308 
309  // Start object.
312 
313  // Start objclass.
315  rRtf.WriteOString(aClassName);
316  // End objclass.
317  rRtf.WriteCharPtr("}");
318 
319  // Object size.
321  rRtf.WriteCharPtr(OString::number(nWidth).getStr());
323  rRtf.WriteCharPtr(OString::number(nHeight).getStr());
324 
325  // Start objdata.
326  rRtf.WriteCharPtr(
328  msfilter::rtfutil::WriteHex(static_cast<const sal_uInt8*>(aOLE1.GetData()), aOLE1.GetSize(),
329  &rRtf);
330  // End objdata.
331  rRtf.WriteCharPtr("}");
332 
333  if (const Graphic* pGraphic = rOLENode.GetGraphic())
334  WrapOleGraphicInRtf(rRtf, rOLENode, *pGraphic);
335 
336  // End object.
337  rRtf.WriteCharPtr("}");
338 
339  return true;
340 }
341 
342 bool WrapGraphicInRtf(const Graphic& rGraphic, const Size& rLogicSize, SvStream& rRtf)
343 {
345 
346  GfxLink aLink = rGraphic.GetGfxLink();
347  const sal_uInt8* pGraphicAry = aLink.GetData();
348  sal_uInt64 nSize = aLink.GetDataSize();
349  OString aBlipType;
350  bool bIsWMF = false;
351  switch (aLink.GetType())
352  {
353  case GfxLinkType::NativeBmp:
354  aBlipType = OOO_STRING_SVTOOLS_RTF_WBITMAP;
355  break;
356  case GfxLinkType::NativeJpg:
358  break;
359  case GfxLinkType::NativePng:
360  aBlipType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
361  break;
362  case GfxLinkType::NativeWmf:
363  if (aLink.IsEMF())
364  aBlipType = OOO_STRING_SVTOOLS_RTF_EMFBLIP;
365  else
366  {
368  bIsWMF = true;
369  }
370  break;
371  default:
372  break;
373  }
374 
375  if (aBlipType.isEmpty())
376  return false;
377 
378  rRtf.WriteOString(aBlipType);
379 
380  Size aMapped(rGraphic.GetPrefSize());
382  rRtf.WriteOString(OString::number(aMapped.Width()));
384  rRtf.WriteOString(OString::number(aMapped.Height()));
385 
387  rRtf.WriteOString(OString::number(rLogicSize.Width()));
389  rRtf.WriteOString(OString::number(rLogicSize.Height()));
390 
391  if (bIsWMF)
392  {
393  rRtf.WriteOString(OString::number(8));
394  msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nSize);
395  }
397 
398  msfilter::rtfutil::WriteHex(pGraphicAry, nSize, &rRtf);
400 
401  // End pict.
402  rRtf.WriteCharPtr("}");
403  return true;
404 }
405 }
406 
407 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
long Width() const
bool SetStreamSize(sal_uInt64 nSize)
#define OOO_STRING_SVTOOLS_RTF_PNGBLIP
SvStream & WriteUInt16(sal_uInt16 nUInt16)
#define OOO_STRING_SVTOOLS_RTF_OBJH
long Height() const
bool WrapOleInRtf(SvStream &rOle2, SvStream &rRtf, SwOLENode &rOLENode)
Wraps an OLE2 container binary in an RTF fragment.
virtual sal_uInt64 TellEnd()
ErrCode GetError() const
bool ExtractOLE2FromObjdata(const OString &rObjdata, SvStream &rOle2)
#define OOO_STRING_SVTOOLS_RTF_PICT
sal_uInt64 Seek(sal_uInt64 nPos)
SvStream & WriteOString(const OString &rStr)
#define OOO_STRING_SVTOOLS_RTF_PICH
SvStream & WriteCharPtr(const char *pBuf)
SvParserState
virtual sal_uInt64 TellEnd() override
bool StripMetafileHeader(const sal_uInt8 *&rpGraphicAry, sal_uInt64 &rSize)
#define OOO_STRING_SVTOOLS_RTF_WBITMAP
#define OOO_STRING_SVTOOLS_RTF_OBJDATA
SvStream & WriteUInt32(sal_uInt32 nUInt32)
OString WriteHex(const sal_uInt8 *pData, sal_uInt32 nSize, SvStream *pStream=nullptr, sal_uInt32 nLimit=64)
static OUString GetFilterNameFromClassID(const SvGlobalName &aGlobName)
bool WrapGraphicInRtf(const Graphic &rGraphic, const Size &rLogicSize, SvStream &rRtf)
Wraps an image in an RTF fragment.
#define OOO_STRING_SVTOOLS_RTF_PICWGOAL
SvGlobalName GetClassName()
SotStorageStream * OpenSotStream(const OUString &rEleName, StreamMode=StreamMode::STD_READWRITE)
virtual void NextToken(int nToken)=0
const Graphic * GetGraphic()
Definition: ndole.cxx:242
sal_uInt64 GetSize()
std::size_t WriteBytes(const void *pData, std::size_t nSize)
#define OOO_STRING_SVTOOLS_RTF_EMFBLIP
GfxLink GetGfxLink() const
virtual Size GetTwipSize() const override
Definition: ndole.cxx:420
SvStream & WriteStream(SvStream &rStream)
#define OOO_STRING_SVTOOLS_RTF_PICW
Size GetPrefSize() const
#define OOO_STRING_SVTOOLS_RTF_OBJEMB
OString OUStringToOString(const OUString &str, ConnectionSettings const *settings)
static ErrCode Export(SvStream &rOStm, const Graphic &rGraphic, ConvertDataFormat nFormat)
#define OOO_STRING_SVTOOLS_RTF_IGNORE
#define ERRCODE_NONE
unsigned char sal_uInt8
#define OOO_STRING_SVTOOLS_RTF_OBJCLASS
bool ExtractOleFromRtf(SvStream &rRtf, SvStream &rOle, bool &bOwnFormat)
Extracts an OLE2 container binary from an RTF fragment.
sal_uInt64 Tell() const
#define OOO_STRING_SVTOOLS_RTF_PICHGOAL
RTF_OBJDATA
SvStream & WriteChar(char nChar)
#define OOO_STRING_SVTOOLS_RTF_WMETAFILE
sal_Int32 nPos
RTF_TEXTTOKEN
OString read_uInt8s_ToOString(SvStream &rStrm, std::size_t nLen)
#define OOO_STRING_SVTOOLS_RTF_OBJECT
#define OOO_STRING_SVTOOLS_RTF_OBJW
#define SAL_NEWLINE_STRING
const void * GetData()
#define OOO_STRING_SVTOOLS_RTF_JPEGBLIP
static void ExtractOwnStream(SotStorage &rSrcStg, SvMemoryStream &rMemStream)