office-gobmx/oox
Stephan Bergmann ae4a69d755 Avoid UBSan signed-integer-overflow
...during CppunitTest_sd_import_tests_smartart:

> oox/source/drawingml/diagram/diagramlayoutatoms.cxx:656:50: runtime error: signed integer overflow: 1924451 - -2147483647 cannot be represented in type 'int'
>  #0 in oox::drawingml::AlgAtom::layoutShape(std::shared_ptr<oox::drawingml::Shape> const&, std::__debug::vector<oox::drawingml::Constraint, std::allocator<oox::drawingml::Constraint> > const&, std::__debug::vector<oox::drawingml::Rule, std::allocator<oox::drawingml::Rule> > const&) at oox/source/drawingml/diagram/diagramlayoutatoms.cxx:656:50
>  #1 in oox::drawingml::ShapeLayoutingVisitor::visit(oox::drawingml::AlgAtom&) at oox/source/drawingml/diagram/layoutatomvisitors.cxx:202:19
>  #2 in oox::drawingml::AlgAtom::accept(oox::drawingml::LayoutAtomVisitor&) at oox/source/drawingml/diagram/diagramlayoutatoms.cxx:386:14
>  #3 in oox::drawingml::LayoutAtomVisitorBase::defaultVisit(oox::drawingml::LayoutAtom const&) at oox/source/drawingml/diagram/layoutatomvisitorbase.cxx:32:16
>  #4 in oox::drawingml::ShapeLayoutingVisitor::visit(oox::drawingml::LayoutNode&) at oox/source/drawingml/diagram/layoutatomvisitors.cxx:243:5
>  #5 in oox::drawingml::LayoutNode::accept(oox::drawingml::LayoutAtomVisitor&) at oox/source/drawingml/diagram/diagramlayoutatoms.cxx:1452:14
>  #6 in oox::drawingml::LayoutAtomVisitorBase::defaultVisit(oox::drawingml::LayoutAtom const&) at oox/source/drawingml/diagram/layoutatomvisitorbase.cxx:32:16
>  #7 in oox::drawingml::ShapeLayoutingVisitor::visit(oox::drawingml::LayoutNode&) at oox/source/drawingml/diagram/layoutatomvisitors.cxx:245:5
>  #8 in oox::drawingml::LayoutNode::accept(oox::drawingml::LayoutAtomVisitor&) at oox/source/drawingml/diagram/diagramlayoutatoms.cxx:1452:14
>  #9 in oox::drawingml::LayoutAtomVisitorBase::visit(oox::drawingml::ForEachAtom&) at oox/source/drawingml/diagram/layoutatomvisitorbase.cxx:98:20
>  #10 in oox::drawingml::ForEachAtom::accept(oox::drawingml::LayoutAtomVisitor&) at oox/source/drawingml/diagram/diagramlayoutatoms.cxx:167:14
>  #11 in oox::drawingml::LayoutAtomVisitorBase::defaultVisit(oox::drawingml::LayoutAtom const&) at oox/source/drawingml/diagram/layoutatomvisitorbase.cxx:32:16
>  #12 in oox::drawingml::ShapeLayoutingVisitor::visit(oox::drawingml::LayoutNode&) at oox/source/drawingml/diagram/layoutatomvisitors.cxx:245:5
>  #13 in oox::drawingml::LayoutNode::accept(oox::drawingml::LayoutAtomVisitor&) at oox/source/drawingml/diagram/diagramlayoutatoms.cxx:1452:14
>  #14 in oox::drawingml::Diagram::addTo(std::shared_ptr<oox::drawingml::Shape> const&) at oox/source/drawingml/diagram/diagram.cxx:122:30
>  #15 in oox::drawingml::loadDiagram(std::shared_ptr<oox::drawingml::Shape> const&, oox::core::XmlFilterBase&, rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, oox::core::Relations const&) at oox/source/drawingml/diagram/diagram.cxx:356:15
>  #16 in oox::drawingml::DiagramGraphicDataContext::onCreateContext(int, oox::AttributeList const&) at oox/source/drawingml/graphicshapecontext.cxx:252:9
>  #17 in non-virtual thunk to oox::drawingml::DiagramGraphicDataContext::onCreateContext(int, oox::AttributeList const&) at oox/source/drawingml/graphicshapecontext.cxx
>  #18 in oox::core::ContextHandler2Helper::implCreateChildContext(int, com::sun::uno::Reference<com::sun::xml::sax::XFastAttributeList> const&) at oox/source/core/contexthandler2.cxx:94:34
>  #19 in oox::core::ContextHandler2::createFastChildContext(int, com::sun::uno::Reference<com::sun::xml::sax::XFastAttributeList> const&) at oox/source/core/contexthandler2.cxx:191:12
>  #20 in non-virtual thunk to oox::core::ContextHandler2::createFastChildContext(int, com::sun::uno::Reference<com::sun::xml::sax::XFastAttributeList> const&) at oox/source/core/contexthandler2.cxx
>  #21 in (anonymous namespace)::Entity::startElement((anonymous namespace)::Event const*) at sax/source/fastparser/fastparser.cxx:432:44
>  #22 in sax_fastparser::FastSaxParserImpl::callbackStartElement(unsigned char const*, unsigned char const*, unsigned char const*, int, unsigned char const**, int, unsigned char const**) at sax/source/fastparser/fastparser.cxx:1246:21
>  #23 in (anonymous namespace)::call_callbackStartElement(void*, unsigned char const*, unsigned char const*, unsigned char const*, int, unsigned char const**, int, int, unsigned char const**) at sax/source/fastparser/fastparser.cxx:305:18
>  #24 in xmlParseStartTag2 at workdir/UnpackedTarball/libxml2/parser.c:9588:6
>  #25 in xmlParseTryOrFinish at workdir/UnpackedTarball/libxml2/parser.c:11378:14
>  #26 in xmlParseChunk__internal_alias at workdir/UnpackedTarball/libxml2/parser.c:12280:13
>  #27 in sax_fastparser::FastSaxParserImpl::parse() at sax/source/fastparser/fastparser.cxx:1046:21
>  #28 in sax_fastparser::FastSaxParserImpl::parseStream(com::sun::xml::sax::InputSource const&) at sax/source/fastparser/fastparser.cxx:866:9
>  #29 in sax_fastparser::FastSaxParser::parseStream(com::sun::xml::sax::InputSource const&) at sax/source/fastparser/fastparser.cxx:1369:13
>  #30 in oox::core::FastParser::parseStream(com::sun::xml::sax::InputSource const&, bool) at oox/source/core/fastparser.cxx:121:15
>  #31 in oox::core::FastParser::parseStream(com::sun::uno::Reference<com::sun::io::XInputStream> const&, rtl::OUString const&) at oox/source/core/fastparser.cxx:129:5
>  #32 in oox::core::XmlFilterBase::importFragment(rtl::Reference<oox::core::FragmentHandler> const&, oox::core::FastParser&) at oox/source/core/xmlfilterbase.cxx:402:21
>  #33 in oox::core::XmlFilterBase::importFragment(rtl::Reference<oox::core::FragmentHandler> const&) at oox/source/core/xmlfilterbase.cxx:331:12
>  #34 in oox::ppt::PresentationFragmentHandler::importSlide(rtl::Reference<oox::core::FragmentHandler> const&, std::shared_ptr<oox::ppt::SlidePersist> const&) at oox/source/ppt/presentationfragmenthandler.cxx:610:17
>  #35 in oox::ppt::PresentationFragmentHandler::importSlide(unsigned int, bool, bool) at oox/source/ppt/presentationfragmenthandler.cxx:348:13
>  #36 in oox::ppt::PresentationFragmentHandler::finalizeImport() at oox/source/ppt/presentationfragmenthandler.cxx:499:17
>  #37 in oox::core::FragmentHandler2::endDocument() at oox/source/core/fragmenthandler2.cxx:54:5
>  #38 in sax_fastparser::FastSaxParserImpl::parseStream(com::sun::xml::sax::InputSource const&) at sax/source/fastparser/fastparser.cxx:872:36
>  #39 in sax_fastparser::FastSaxParser::parseStream(com::sun::xml::sax::InputSource const&) at sax/source/fastparser/fastparser.cxx:1369:13
>  #40 in oox::core::FastParser::parseStream(com::sun::xml::sax::InputSource const&, bool) at oox/source/core/fastparser.cxx:121:15
>  #41 in oox::core::FastParser::parseStream(com::sun::uno::Reference<com::sun::io::XInputStream> const&, rtl::OUString const&) at oox/source/core/fastparser.cxx:129:5
>  #42 in oox::core::XmlFilterBase::importFragment(rtl::Reference<oox::core::FragmentHandler> const&, oox::core::FastParser&) at oox/source/core/xmlfilterbase.cxx:402:21
>  #43 in oox::core::XmlFilterBase::importFragment(rtl::Reference<oox::core::FragmentHandler> const&) at oox/source/core/xmlfilterbase.cxx:331:12
>  #44 in oox::ppt::PowerPointImport::importDocument() at oox/source/ppt/pptimport.cxx:145:17
>  #45 in oox::core::FilterBase::filter(com::sun::uno::Sequence<com::sun:🫘:PropertyValue> const&) at oox/source/core/filterbase.cxx:485:49
>  #46 in oox::ppt::PowerPointImport::filter(com::sun::uno::Sequence<com::sun:🫘:PropertyValue> const&) at oox/source/ppt/pptimport.cxx:223:24
>  #47 in SfxObjectShell::ImportFrom(SfxMedium&, com::sun::uno::Reference<com::sun::text::XTextRange> const&) at sfx2/source/doc/objstor.cxx:2251:34
>  #48 in sd::DrawDocShell::ImportFrom(SfxMedium&, com::sun::uno::Reference<com::sun::text::XTextRange> const&) at sd/source/ui/docshell/docshel4.cxx:399:39
>  #49 in SfxObjectShell::DoLoad(SfxMedium*) at sfx2/source/doc/objstor.cxx:738:23
>  #50 in SdModelTestBase::loadURL(rtl::OUString const&, int, std::shared_ptr<SfxAllItemSet>) at sd/qa/unit/sdmodeltestbase.hxx:181:30
>  #51 in SdImportTestSmartArt::testText() at sd/qa/unit/import-tests-smartart.cxx:250:37

As discussed on IRC:

> Jul 31 18:52:58 <vmiklos> sberg: yes, that looks reasonable, clearly the
>  expectation is that there is at least one element, in which case that
>  nVertMin grows from 0 and nVertMax shrinks from
>  std::numeric_limits<sal_Int32>::max()
> Jul 31 18:54:43 <vmiklos> sberg: sounds like i made that mistake in
>  acdde3c643, but recently i added a test that
>  now uncovered the problem :)

Change-Id: I0ee11dbab568af788f9e2786c3dca2c1a5e1ee08
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/99902
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2020-08-01 08:20:46 +02:00
..
documentation
inc tdf#133015 Fix duplicated row and column problem. 2020-07-24 09:47:05 +02:00
qa tdf#131175 oox chart import: fix char color of <dLbl>, inherited from <dLbls> 2020-07-15 10:53:17 +02:00
source Avoid UBSan signed-integer-overflow 2020-08-01 08:20:46 +02:00
util
AllLangMoTarget_oox.mk
CppunitTest_oox_crypto.mk
CppunitTest_oox_drawingml.mk
CppunitTest_oox_mathml.mk
CppunitTest_oox_shape.mk
CppunitTest_oox_tokenmap.mk
CppunitTest_oox_vba_compression.mk
CppunitTest_oox_vba_encryption.mk
CppunitTest_oox_vml.mk
CustomTarget_generated.mk
IwyuFilter_oox.yaml replace usage of blacklist with excludelist for IWYU 2020-07-10 02:03:40 +02:00
Library_oox.mk oox smartart: start parsing rule lists 2020-07-24 17:44:37 +02:00
Makefile
Module_oox.mk
Package_customshapes.mk
Package_generated.mk
README replace usage of blacklist with denylist 2020-07-10 01:34:54 +02:00
README.vars

Support for Office Open XML, the office XML-format designed by Microsoft.


== DrawingML Custom shapes and presets ==

Custom shapes are part of DrawingML and are different to binary ppt
and VML in older formats.
The import happens in oox/source/drawingml, where they are
imported as LO's enhanced custom shape's. see
offapi/com/sun/star/drawing/CustomShape.idl and
offapi/com/sun/star/drawing/EnhancedCustomShape*.idl
Check CustomShapeProperties::pushToPropSet() and see
how custom shape properties are converted.

Preset shapes are custom shapes whose guides and handles
have been defined in OOXML specification. By specifying
preset type and the adjustment values, the reset can
be taken from the shape definition.

example of drawingml preset:

         <a:prstGeom prst="star5">
           <a:avLst/>
         </a:prstGeom>

example of drawingml custom shape (equal to star5 preset):

   <avLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">
     <gd name="adj" fmla="val 19098" />
     <gd name="hf" fmla="val 105146" />
     <gd name="vf" fmla="val 110557" />
   </avLst>
   <gdLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">
     <gd name="a" fmla="pin 0 adj 50000" />
     <gd name="swd2" fmla="*/ wd2 hf 100000" />
     <gd name="shd2" fmla="*/ hd2 vf 100000" />
     <gd name="svc" fmla="*/ vc  vf 100000" />
     <gd name="dx1" fmla="cos swd2 1080000" />
     <gd name="dx2" fmla="cos swd2 18360000" />
     <gd name="dy1" fmla="sin shd2 1080000" />
     <gd name="dy2" fmla="sin shd2 18360000" />
     <gd name="x1" fmla="+- hc 0 dx1" />
     <gd name="x2" fmla="+- hc 0 dx2" />
     <gd name="x3" fmla="+- hc dx2 0" />
     <gd name="x4" fmla="+- hc dx1 0" />
     <gd name="y1" fmla="+- svc 0 dy1" />
     <gd name="y2" fmla="+- svc 0 dy2" />
     <gd name="iwd2" fmla="*/ swd2 a 50000" />
     <gd name="ihd2" fmla="*/ shd2 a 50000" />
     <gd name="sdx1" fmla="cos iwd2 20520000" />
     <gd name="sdx2" fmla="cos iwd2 3240000" />
     <gd name="sdy1" fmla="sin ihd2 3240000" />
     <gd name="sdy2" fmla="sin ihd2 20520000" />
     <gd name="sx1" fmla="+- hc 0 sdx1" />
     <gd name="sx2" fmla="+- hc 0 sdx2" />
     <gd name="sx3" fmla="+- hc sdx2 0" />
     <gd name="sx4" fmla="+- hc sdx1 0" />
     <gd name="sy1" fmla="+- svc 0 sdy1" />
     <gd name="sy2" fmla="+- svc 0 sdy2" />
     <gd name="sy3" fmla="+- svc ihd2 0" />
     <gd name="yAdj" fmla="+- svc 0 ihd2" />
   </gdLst>
   <ahLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">
     <ahXY gdRefY="adj" minY="0" maxY="50000">
       <pos x="hc" y="yAdj" />
     </ahXY>
   </ahLst>
   <cxnLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">
     <cxn ang="3cd4">
       <pos x="hc" y="t" />
     </cxn>
     <cxn ang="cd2">
       <pos x="x1" y="y1" />
     </cxn>
     <cxn ang="cd4">
       <pos x="x2" y="y2" />
     </cxn>
     <cxn ang="cd4">
       <pos x="x3" y="y2" />
     </cxn>
     <cxn ang="0">
       <pos x="x4" y="y1" />
     </cxn>
   </cxnLst>
   <rect l="sx1" t="sy1" r="sx4" b="sy3" xmlns="http://schemas.openxmlformats.org/drawingml/2006/main" />
   <pathLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">
     <path>
       <moveTo>
         <pt x="x1" y="y1" />
       </moveTo>
       <lnTo>
         <pt x="sx2" y="sy1" />
       </lnTo>
       <lnTo>
         <pt x="hc" y="t" />
       </lnTo>
       <lnTo>
         <pt x="sx3" y="sy1" />
       </lnTo>
       <lnTo>
         <pt x="x4" y="y1" />
       </lnTo>
       <lnTo>
         <pt x="sx4" y="sy2" />
       </lnTo>
       <lnTo>
         <pt x="x3" y="y2" />
       </lnTo>
       <lnTo>
         <pt x="hc" y="sy3" />
       </lnTo>
       <lnTo>
         <pt x="x2" y="y2" />
       </lnTo>
       <lnTo>
         <pt x="sx1" y="sy2" />
       </lnTo>
       <close />
     </path>
   </pathLst>

we needed to extend our custom shapes for missing features and so 5
new segment commands were added. G command for arcto drawingml record
and H I J K commands for darken, darkenless, lighten, lightenless
records. the commands are save into ODF in special namespace drawooo,
which is extension not yet in the standard. Thorsten suggested to put
it in such a namespace and keep original (incomplete) geometry for
backward compatibility, before we can extend the ODF. that's why you
will see 2 of them in cases where some of the new commands was
needed.

In order to convert preset shapes to LO's enhanced custom shape,
we need to load shape definition of preset shapes. The procedure
to convert the definition from OOXML spec for LO is documented
( also a script ) in oox/source/drawingml/customshapes/README.
The scripts in oox/source/drawingml/customshapes/ also generate pptx
files for single presets and also for all presets
cshape-all.pptx. The cshape-all.pptx file is then loaded into Impress
build with debug enabled in oox and the command line output contains
information. The generated definition is oox-drawingml-cs-presets.

Check CustomShapeProperties::initializePresetDataMap() to see how
generated presets data are loaded into LO.
While importing presets, we prefix the name with "ooxml-" so
that we can detect it on export as save it again as preset.

The generated pptx files
can be used when debugging bugs in custom shapes import/export. also
the cshape-all.pptx can be used to test the round trips. there's small
problem with these pptx as they cannot be imported into powerpoint,
but that can be fixed quickly. when fixed, we can use it to
test powerpoint odp export and see how complete it is regarding
custom shapes. OpenXML SDK tools might help when fixing
cshape-all.pptx
http://www.microsoft.com/en-us/download/details.aspx?id=30425

== Export ==
Here is how LO's enhanced custom shapes are exported:
* Shape name is ooxml-* - they are imported from ooxml, export as is.
* Denylist - ODF presets that has OOXML equivalent.
  We convert adjustment values case by case. Microsoft Office
  is rather strict about adjustment values, either none of them
  are provided so that default values are taken, or the exact set
  of handles have to be provided. In some cases we are converting
  from the preset with less handles to the one with more handles
  so that default values suitable for the odf one need to be
  provided.
* Allowlist - ODF presets that has OOXML equivalent but looks a bit
different, export them as PolyPolygon.

Check Andras Timar's presentation[1] and ShapeExport::WriteCustomShape()
for further detail.

FUTURE WORK: because we have to make sure that all the roundtrips
like PPTX --> ODP --> PPTX work correctly and doesn't lose data.
the only problematic part is probably saving custom shapes (ie. not
presets) to PPTX. that part of code predates work on custom shapes
and is unable to export general custom shapes yet. It will need a bit
of work as LO has more complex equations than DrawingML. other parts
should work OK, PPTX --> ODP should work and don't lose any
data. presets should already survive PPTX --> ODP --> PPTX roundtrip

[1]https://archive.fosdem.org/2016/schedule/event/drawingml/attachments/
slides/1184/export/events/attachments/drawingml/slides/1184/
andras_timar_fosdem_2016.pdf