1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/TypeSerializer.hxx>
21 #include <tools/vcompat.hxx>
22 #include <tools/fract.hxx>
23 #include <sal/log.hxx>
24 #include <comphelper/fileformat.h>
25 #include <vcl/gdimtf.hxx>
26 #include <vcl/dibtools.hxx>
28 TypeSerializer::TypeSerializer(SvStream
& rStream
)
29 : GenericTypeSerializer(rStream
)
33 void TypeSerializer::readGradient(Gradient
& rGradient
)
35 VersionCompatRead
aCompat(mrStream
);
37 sal_uInt16 nStyle
= 0;
40 sal_uInt16 nAngle
= 0;
41 sal_uInt16 nBorder
= 0;
42 sal_uInt16 nOffsetX
= 0;
43 sal_uInt16 nOffsetY
= 0;
44 sal_uInt16 nIntensityStart
= 0;
45 sal_uInt16 nIntensityEnd
= 0;
46 sal_uInt16 nStepCount
= 0;
48 mrStream
.ReadUInt16(nStyle
);
49 readColor(aStartColor
);
51 mrStream
.ReadUInt16(nAngle
);
52 mrStream
.ReadUInt16(nBorder
);
53 mrStream
.ReadUInt16(nOffsetX
);
54 mrStream
.ReadUInt16(nOffsetY
);
55 mrStream
.ReadUInt16(nIntensityStart
);
56 mrStream
.ReadUInt16(nIntensityEnd
);
57 mrStream
.ReadUInt16(nStepCount
);
59 rGradient
.SetStyle(static_cast<GradientStyle
>(nStyle
));
60 rGradient
.SetStartColor(aStartColor
);
61 rGradient
.SetEndColor(aEndColor
);
64 SAL_WARN("vcl", "angle out of range " << nAngle
);
67 rGradient
.SetAngle(Degree10(nAngle
));
68 rGradient
.SetBorder(nBorder
);
69 rGradient
.SetOfsX(nOffsetX
);
70 rGradient
.SetOfsY(nOffsetY
);
71 rGradient
.SetStartIntensity(nIntensityStart
);
72 rGradient
.SetEndIntensity(nIntensityEnd
);
73 rGradient
.SetSteps(nStepCount
);
76 void TypeSerializer::writeGradient(const Gradient
& rGradient
)
78 VersionCompatWrite
aCompat(mrStream
, 1);
80 mrStream
.WriteUInt16(static_cast<sal_uInt16
>(rGradient
.GetStyle()));
81 writeColor(rGradient
.GetStartColor());
82 writeColor(rGradient
.GetEndColor());
83 mrStream
.WriteUInt16(rGradient
.GetAngle().get());
84 mrStream
.WriteUInt16(rGradient
.GetBorder());
85 mrStream
.WriteUInt16(rGradient
.GetOfsX());
86 mrStream
.WriteUInt16(rGradient
.GetOfsY());
87 mrStream
.WriteUInt16(rGradient
.GetStartIntensity());
88 mrStream
.WriteUInt16(rGradient
.GetEndIntensity());
89 mrStream
.WriteUInt16(rGradient
.GetSteps());
92 void TypeSerializer::readGfxLink(GfxLink
& rGfxLink
)
95 sal_uInt32 nDataSize
= 0;
96 sal_uInt32 nUserId
= 0;
100 bool bMapAndSizeValid
= false;
103 VersionCompatRead
aCompat(mrStream
);
106 mrStream
.ReadUInt16(nType
);
107 mrStream
.ReadUInt32(nDataSize
);
108 mrStream
.ReadUInt32(nUserId
);
110 if (aCompat
.GetVersion() >= 2)
113 readMapMode(aMapMode
);
114 bMapAndSizeValid
= true;
118 auto nRemainingData
= mrStream
.remainingSize();
119 if (nDataSize
> nRemainingData
)
121 SAL_WARN("vcl", "graphic link stream is smaller than requested size");
122 nDataSize
= nRemainingData
;
125 std::unique_ptr
<sal_uInt8
[]> pBuffer(new sal_uInt8
[nDataSize
]);
126 mrStream
.ReadBytes(pBuffer
.get(), nDataSize
);
128 rGfxLink
= GfxLink(std::move(pBuffer
), nDataSize
, static_cast<GfxLinkType
>(nType
));
129 rGfxLink
.SetUserId(nUserId
);
131 if (bMapAndSizeValid
)
133 rGfxLink
.SetPrefSize(aSize
);
134 rGfxLink
.SetPrefMapMode(aMapMode
);
138 void TypeSerializer::writeGfxLink(const GfxLink
& rGfxLink
)
141 VersionCompatWrite
aCompat(mrStream
, 2);
144 mrStream
.WriteUInt16(sal_uInt16(rGfxLink
.GetType()));
145 mrStream
.WriteUInt32(rGfxLink
.GetDataSize());
146 mrStream
.WriteUInt32(rGfxLink
.GetUserId());
149 writeSize(rGfxLink
.GetPrefSize());
150 writeMapMode(rGfxLink
.GetPrefMapMode());
153 if (rGfxLink
.GetDataSize())
155 if (rGfxLink
.GetData())
156 mrStream
.WriteBytes(rGfxLink
.GetData(), rGfxLink
.GetDataSize());
162 #define NATIVE_FORMAT_50 COMPAT_FORMAT('N', 'A', 'T', '5')
164 } // end anonymous namespace
166 void TypeSerializer::readGraphic(Graphic
& rGraphic
)
168 if (mrStream
.GetError())
171 const sal_uLong nInitialStreamPosition
= mrStream
.Tell();
174 // if there is no more data, avoid further expensive
175 // reading which will create VDevs and other stuff, just to
177 if (mrStream
.remainingSize() < 4)
181 mrStream
.ReadUInt32(nType
);
183 if (NATIVE_FORMAT_50
== nType
)
188 // read compat info, destructor writes stuff into the header
190 VersionCompatRead
aCompat(mrStream
);
195 if (!mrStream
.GetError() && aLink
.LoadNative(aGraphic
))
197 if (aLink
.IsPrefMapModeValid())
198 aGraphic
.SetPrefMapMode(aLink
.GetPrefMapMode());
200 if (aLink
.IsPrefSizeValid())
201 aGraphic
.SetPrefSize(aLink
.GetPrefSize());
205 mrStream
.Seek(nInitialStreamPosition
);
206 mrStream
.SetError(ERRCODE_IO_WRONGFORMAT
);
213 const SvStreamEndian nOldFormat
= mrStream
.GetEndian();
215 mrStream
.SeekRel(-4);
216 mrStream
.SetEndian(SvStreamEndian::LITTLE
);
217 ReadDIBBitmapEx(aBitmapEx
, mrStream
);
219 if (!mrStream
.GetError())
221 sal_uInt32 nMagic1
= 0;
222 sal_uInt32 nMagic2
= 0;
223 if (mrStream
.remainingSize() >= 8)
225 sal_uInt64 nBeginPosition
= mrStream
.Tell();
226 mrStream
.ReadUInt32(nMagic1
);
227 mrStream
.ReadUInt32(nMagic2
);
228 mrStream
.Seek(nBeginPosition
);
230 if (!mrStream
.GetError())
232 if (nMagic1
== 0x5344414e && nMagic2
== 0x494d4931)
234 Animation aAnimation
;
235 ReadAnimation(mrStream
, aAnimation
);
237 // #108077# manually set loaded BmpEx to Animation
238 // (which skips loading its BmpEx if already done)
239 aAnimation
.SetBitmapEx(aBitmapEx
);
240 rGraphic
= Graphic(aAnimation
);
244 rGraphic
= Graphic(aBitmapEx
);
249 mrStream
.ResetError();
254 GDIMetaFile aMetaFile
;
256 mrStream
.Seek(nInitialStreamPosition
);
257 mrStream
.ResetError();
258 ReadGDIMetaFile(mrStream
, aMetaFile
);
260 if (!mrStream
.GetError())
262 rGraphic
= Graphic(aMetaFile
);
266 ErrCode nOriginalError
= mrStream
.GetErrorCode();
267 // try to stream in Svg defining data (length, byte array and evtl. path)
268 // See below (operator<<) for more information
270 mrStream
.Seek(nInitialStreamPosition
);
271 mrStream
.ResetError();
272 mrStream
.ReadUInt32(nMagic
);
274 if (constSvgMagic
== nMagic
|| constWmfMagic
== nMagic
|| constEmfMagic
== nMagic
275 || constPdfMagic
== nMagic
)
277 sal_uInt32 nLength
= 0;
278 mrStream
.ReadUInt32(nLength
);
282 auto rData
= std::make_unique
<std::vector
<sal_uInt8
>>(nLength
);
283 mrStream
.ReadBytes(rData
->data(), rData
->size());
284 BinaryDataContainer
aDataContainer(std::move(rData
));
286 if (!mrStream
.GetError())
288 VectorGraphicDataType
aDataType(VectorGraphicDataType::Svg
);
293 aDataType
= VectorGraphicDataType::Wmf
;
296 aDataType
= VectorGraphicDataType::Emf
;
299 aDataType
= VectorGraphicDataType::Pdf
;
303 auto aVectorGraphicDataPtr
304 = std::make_shared
<VectorGraphicData
>(aDataContainer
, aDataType
);
305 rGraphic
= Graphic(aVectorGraphicDataPtr
);
311 mrStream
.SetError(nOriginalError
);
314 mrStream
.Seek(nInitialStreamPosition
);
317 mrStream
.SetEndian(nOldFormat
);
321 void TypeSerializer::writeGraphic(const Graphic
& rGraphic
)
323 Graphic
aGraphic(rGraphic
);
325 if (!aGraphic
.makeAvailable())
328 auto pGfxLink
= aGraphic
.GetSharedGfxLink();
330 if (mrStream
.GetVersion() >= SOFFICE_FILEFORMAT_50
331 && (mrStream
.GetCompressMode() & SvStreamCompressFlags::NATIVE
) && pGfxLink
332 && pGfxLink
->IsNative())
335 mrStream
.WriteUInt32(NATIVE_FORMAT_50
);
337 // write compat info, destructor writes stuff into the header
339 VersionCompatWrite
aCompat(mrStream
, 1);
341 pGfxLink
->SetPrefMapMode(aGraphic
.GetPrefMapMode());
342 pGfxLink
->SetPrefSize(aGraphic
.GetPrefSize());
343 writeGfxLink(*pGfxLink
);
348 const SvStreamEndian nOldFormat
= mrStream
.GetEndian();
349 mrStream
.SetEndian(SvStreamEndian::LITTLE
);
351 switch (aGraphic
.GetType())
353 case GraphicType::NONE
:
354 case GraphicType::Default
:
357 case GraphicType::Bitmap
:
359 auto pVectorGraphicData
= aGraphic
.getVectorGraphicData();
360 if (pVectorGraphicData
)
362 // stream out Vector Graphic defining data (length, byte array and evtl. path)
363 // this is used e.g. in swapping out graphic data and in transporting it over UNO API
364 // as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be
365 // no problem to extend it; only used at runtime
366 switch (pVectorGraphicData
->getType())
368 case VectorGraphicDataType::Wmf
:
370 mrStream
.WriteUInt32(constWmfMagic
);
373 case VectorGraphicDataType::Emf
:
375 mrStream
.WriteUInt32(constEmfMagic
);
378 case VectorGraphicDataType::Svg
:
380 mrStream
.WriteUInt32(constSvgMagic
);
383 case VectorGraphicDataType::Pdf
:
385 mrStream
.WriteUInt32(constPdfMagic
);
390 sal_uInt32 nSize
= pVectorGraphicData
->getBinaryDataContainer().getSize();
391 mrStream
.WriteUInt32(nSize
);
392 mrStream
.WriteBytes(pVectorGraphicData
->getBinaryDataContainer().getData(),
394 // For backwards compatibility, used to serialize path
395 mrStream
.WriteUniOrByteString(u
"", mrStream
.GetStreamCharSet());
397 else if (aGraphic
.IsAnimated())
399 WriteAnimation(mrStream
, aGraphic
.GetAnimation());
403 WriteDIBBitmapEx(aGraphic
.GetBitmapEx(), mrStream
);
410 if (aGraphic
.IsSupportedGraphic())
411 WriteGDIMetaFile(mrStream
, rGraphic
.GetGDIMetaFile());
415 mrStream
.SetEndian(nOldFormat
);
419 void TypeSerializer::readMapMode(MapMode
& rMapMode
)
421 VersionCompatRead
aCompat(mrStream
);
422 sal_uInt16
nTmp16(0);
428 mrStream
.ReadUInt16(nTmp16
);
429 MapUnit eUnit
= static_cast<MapUnit
>(nTmp16
);
431 readFraction(aScaleX
);
432 readFraction(aScaleY
);
433 mrStream
.ReadCharAsBool(bSimple
);
436 rMapMode
= MapMode(eUnit
);
438 rMapMode
= MapMode(eUnit
, aOrigin
, aScaleX
, aScaleY
);
441 void TypeSerializer::writeMapMode(MapMode
const& rMapMode
)
443 VersionCompatWrite
aCompat(mrStream
, 1);
445 mrStream
.WriteUInt16(sal_uInt16(rMapMode
.GetMapUnit()));
446 writePoint(rMapMode
.GetOrigin());
447 writeFraction(rMapMode
.GetScaleX());
448 writeFraction(rMapMode
.GetScaleY());
449 mrStream
.WriteBool(rMapMode
.IsSimple());
452 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */