diff options
Diffstat (limited to 'oox/source/ole')
-rwxr-xr-x | oox/source/ole/axbinaryreader.cxx | 343 | ||||
-rw-r--r-- | oox/source/ole/axcontrol.cxx | 1750 | ||||
-rw-r--r-- | oox/source/ole/axcontrolfragment.cxx | 156 | ||||
-rw-r--r-- | oox/source/ole/makefile.mk | 59 | ||||
-rw-r--r-- | oox/source/ole/olehelper.cxx | 300 | ||||
-rw-r--r-- | oox/source/ole/oleobjecthelper.cxx | 141 | ||||
-rwxr-xr-x | oox/source/ole/olestorage.cxx | 423 | ||||
-rwxr-xr-x | oox/source/ole/vbacontrol.cxx | 845 | ||||
-rwxr-xr-x | oox/source/ole/vbahelper.cxx | 85 | ||||
-rw-r--r-- | oox/source/ole/vbainputstream.cxx | 185 | ||||
-rwxr-xr-x | oox/source/ole/vbamodule.cxx | 235 | ||||
-rwxr-xr-x | oox/source/ole/vbaproject.cxx | 453 |
12 files changed, 4975 insertions, 0 deletions
diff --git a/oox/source/ole/axbinaryreader.cxx b/oox/source/ole/axbinaryreader.cxx new file mode 100755 index 000000000000..68a18932bf42 --- /dev/null +++ b/oox/source/ole/axbinaryreader.cxx @@ -0,0 +1,343 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/ole/axbinaryreader.hxx" +#include "oox/ole/olehelper.hxx" + +using ::rtl::OUString; + +namespace oox { +namespace ole { + +// ============================================================================ + +namespace { + +const sal_uInt32 AX_STRING_SIZEMASK = 0x7FFFFFFF; +const sal_uInt32 AX_STRING_COMPRESSED = 0x80000000; + +} // namespace + +// ============================================================================ + +AxAlignedInputStream::AxAlignedInputStream( BinaryInputStream& rInStrm ) : + mrInStrm( rInStrm ), + mnStrmPos( 0 ) +{ +} + +sal_Int64 AxAlignedInputStream::tell() const +{ + return mnStrmPos; +} + +void AxAlignedInputStream::seek( sal_Int64 nPos ) +{ + mbEof = mbEof || (nPos < mnStrmPos); + if( !mbEof ) + skip( static_cast< sal_Int32 >( nPos - mnStrmPos ) ); +} + +sal_Int32 AxAlignedInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes ) +{ + sal_Int32 nReadSize = mrInStrm.readData( orData, nBytes ); + mnStrmPos += nReadSize; + return nReadSize; +} + +sal_Int32 AxAlignedInputStream::readMemory( void* opMem, sal_Int32 nBytes ) +{ + sal_Int32 nReadSize = mrInStrm.readMemory( opMem, nBytes ); + mnStrmPos += nReadSize; + return nReadSize; +} + +void AxAlignedInputStream::skip( sal_Int32 nBytes ) +{ + mrInStrm.skip( nBytes ); + mnStrmPos += nBytes; +} + +void AxAlignedInputStream::align( size_t nSize ) +{ + skip( static_cast< sal_Int32 >( (nSize - (mnStrmPos % nSize)) % nSize ) ); +} + +// ============================================================================ + +AxFontData::AxFontData() : + mnFontEffects( 0 ), + mnFontHeight( 160 ), + mnFontCharSet( WINDOWS_CHARSET_DEFAULT ), + mnHorAlign( AX_FONTDATA_LEFT ) +{ +} + +sal_Int16 AxFontData::getHeightPoints() const +{ + /* MSO uses weird font sizes: + 1pt->30, 2pt->45, 3pt->60, 4pt->75, 5pt->105, 6pt->120, 7pt->135, + 8pt->165, 9pt->180, 10pt->195, 11pt->225, ... */ + return getLimitedValue< sal_Int16, sal_Int32 >( (mnFontHeight + 10) / 20, 1, SAL_MAX_INT16 ); +} + +void AxFontData::setHeightPoints( sal_Int16 nPoints ) +{ + mnFontHeight = getLimitedValue< sal_Int32, sal_Int32 >( ((nPoints * 4 + 1) / 3) * 15, 30, 4294967 ); +} + +bool AxFontData::importBinaryModel( BinaryInputStream& rInStrm ) +{ + AxBinaryPropertyReader aReader( rInStrm ); + aReader.readStringProperty( maFontName ); + aReader.readIntProperty< sal_uInt32 >( mnFontEffects ); + aReader.readIntProperty< sal_Int32 >( mnFontHeight ); + aReader.skipIntProperty< sal_Int32 >(); // font offset + aReader.readIntProperty< sal_uInt8 >( mnFontCharSet ); + aReader.skipIntProperty< sal_uInt8 >(); // font pitch/family + aReader.readIntProperty< sal_uInt8 >( mnHorAlign ); + aReader.skipIntProperty< sal_uInt16 >(); // font weight + return aReader.finalizeImport(); +} + +bool AxFontData::importStdFont( BinaryInputStream& rInStrm ) +{ + StdFontInfo aFontInfo; + if( OleHelper::importStdFont( aFontInfo, rInStrm, false ) ) + { + maFontName = aFontInfo.maName; + mnFontEffects = 0; + setFlag( mnFontEffects, AX_FONTDATA_BOLD, aFontInfo.mnWeight >= OLE_STDFONT_BOLD ); + setFlag( mnFontEffects, AX_FONTDATA_ITALIC, getFlag( aFontInfo.mnFlags, OLE_STDFONT_ITALIC ) ); + setFlag( mnFontEffects, AX_FONTDATA_UNDERLINE, getFlag( aFontInfo.mnFlags, OLE_STDFONT_UNDERLINE ) ); + setFlag( mnFontEffects, AX_FONTDATA_STRIKEOUT, getFlag( aFontInfo.mnFlags,OLE_STDFONT_STRIKE ) ); + // StdFont stores font height in 1/10,000 of points + setHeightPoints( getLimitedValue< sal_Int16, sal_Int32 >( aFontInfo.mnHeight / 10000, 0, SAL_MAX_INT16 ) ); + mnFontCharSet = aFontInfo.mnCharSet; + mnHorAlign = AX_FONTDATA_LEFT; + return true; + } + return false; +} + +bool AxFontData::importGuidAndFont( BinaryInputStream& rInStrm ) +{ + OUString aGuid = OleHelper::importGuid( rInStrm ); + if( aGuid.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "{AFC20920-DA4E-11CE-B943-00AA006887B4}" ) ) ) + return importBinaryModel( rInStrm ); + if( aGuid.equalsAscii( OLE_GUID_STDFONT ) ) + return importStdFont( rInStrm ); + return false; +} + +// ============================================================================ + +namespace { + +bool lclReadString( AxAlignedInputStream& rInStrm, OUString& rValue, sal_uInt32 nSize, bool bArrayString ) +{ + bool bCompressed = getFlag( nSize, AX_STRING_COMPRESSED ); + sal_uInt32 nBufSize = nSize & AX_STRING_SIZEMASK; + // Unicode: simple strings store byte count, array strings store char count + sal_Int32 nChars = static_cast< sal_Int32 >( nBufSize / ((bCompressed || bArrayString) ? 1 : 2) ); + bool bValidChars = nChars <= 65536; + OSL_ENSURE( bValidChars, "lclReadString - string too long" ); + sal_Int64 nEndPos = rInStrm.tell() + nChars * (bCompressed ? 1 : 2); + nChars = ::std::min< sal_Int32 >( nChars, 65536 ); + rValue = bCompressed ? + // ISO-8859-1 maps all byte values xx to the same Unicode code point U+00xx + rInStrm.readCharArrayUC( nChars, RTL_TEXTENCODING_ISO_8859_1 ) : + rInStrm.readUnicodeArray( nChars ); + rInStrm.seek( nEndPos ); + return bValidChars; +} + +} // namespace + +// ---------------------------------------------------------------------------- + +AxBinaryPropertyReader::ComplexProperty::~ComplexProperty() +{ +} + +bool AxBinaryPropertyReader::PairProperty::readProperty( AxAlignedInputStream& rInStrm ) +{ + rInStrm >> mrPairData.first >> mrPairData.second; + return true; +} + +bool AxBinaryPropertyReader::StringProperty::readProperty( AxAlignedInputStream& rInStrm ) +{ + return lclReadString( rInStrm, mrValue, mnSize, false ); +} + +bool AxBinaryPropertyReader::StringArrayProperty::readProperty( AxAlignedInputStream& rInStrm ) +{ + sal_Int64 nEndPos = rInStrm.tell() + mnSize; + while( rInStrm.tell() < nEndPos ) + { + OUString aString; + if( !lclReadString( rInStrm, aString, rInStrm.readuInt32(), true ) ) + return false; + mrArray.push_back( aString ); + // every array string is aligned on 4 byte boundries + rInStrm.align( 4 ); + } + return true; +} + +bool AxBinaryPropertyReader::GuidProperty::readProperty( AxAlignedInputStream& rInStrm ) +{ + mrGuid = OleHelper::importGuid( rInStrm ); + return true; +} + +bool AxBinaryPropertyReader::FontProperty::readProperty( AxAlignedInputStream& rInStrm ) +{ + return mrFontData.importGuidAndFont( rInStrm ); +} + +bool AxBinaryPropertyReader::PictureProperty::readProperty( AxAlignedInputStream& rInStrm ) +{ + return OleHelper::importStdPic( mrPicData, rInStrm, true ); +} + +// ---------------------------------------------------------------------------- + +AxBinaryPropertyReader::AxBinaryPropertyReader( BinaryInputStream& rInStrm, bool b64BitPropFlags ) : + maInStrm( rInStrm ), + mbValid( true ) +{ + // version and size of property block + maInStrm.skip( 2 ); + sal_uInt16 nBlockSize = maInStrm.readValue< sal_uInt16 >(); + mnPropsEnd = maInStrm.tell() + nBlockSize; + // flagfield containing existing properties + if( b64BitPropFlags ) + maInStrm >> mnPropFlags; + else + mnPropFlags = maInStrm.readuInt32(); + mnNextProp = 1; +} + +void AxBinaryPropertyReader::readBoolProperty( bool& orbValue, bool bReverse ) +{ + // there is no data, the boolean value is equivalent to the property flag itself + orbValue = startNextProperty() != bReverse; +} + +void AxBinaryPropertyReader::readPairProperty( AxPairData& orPairData ) +{ + if( startNextProperty() ) + maLargeProps.push_back( ComplexPropVector::value_type( new PairProperty( orPairData ) ) ); +} + +void AxBinaryPropertyReader::readStringProperty( OUString& orValue ) +{ + if( startNextProperty() ) + { + sal_uInt32 nSize = maInStrm.readAligned< sal_uInt32 >(); + maLargeProps.push_back( ComplexPropVector::value_type( new StringProperty( orValue, nSize ) ) ); + } +} + +void AxBinaryPropertyReader::readStringArrayProperty( AxStringArray& orArray ) +{ + if( startNextProperty() ) + { + sal_uInt32 nSize = maInStrm.readAligned< sal_uInt32 >(); + maLargeProps.push_back( ComplexPropVector::value_type( new StringArrayProperty( orArray, nSize ) ) ); + } +} + +void AxBinaryPropertyReader::readGuidProperty( ::rtl::OUString& orGuid ) +{ + if( startNextProperty() ) + maLargeProps.push_back( ComplexPropVector::value_type( new GuidProperty( orGuid ) ) ); +} + +void AxBinaryPropertyReader::readFontProperty( AxFontData& orFontData ) +{ + if( startNextProperty() ) + { + sal_Int16 nData = maInStrm.readAligned< sal_Int16 >(); + if( ensureValid( nData == -1 ) ) + maStreamProps.push_back( ComplexPropVector::value_type( new FontProperty( orFontData ) ) ); + } +} + +void AxBinaryPropertyReader::readPictureProperty( StreamDataSequence& orPicData ) +{ + if( startNextProperty() ) + { + sal_Int16 nData = maInStrm.readAligned< sal_Int16 >(); + if( ensureValid( nData == -1 ) ) + maStreamProps.push_back( ComplexPropVector::value_type( new PictureProperty( orPicData ) ) ); + } +} + +bool AxBinaryPropertyReader::finalizeImport() +{ + // read large properties + maInStrm.align( 4 ); + if( ensureValid( mnPropFlags == 0 ) && !maLargeProps.empty() ) + { + for( ComplexPropVector::iterator aIt = maLargeProps.begin(), aEnd = maLargeProps.end(); ensureValid() && (aIt != aEnd); ++aIt ) + { + ensureValid( (*aIt)->readProperty( maInStrm ) ); + maInStrm.align( 4 ); + } + } + maInStrm.seek( mnPropsEnd ); + + // read stream properties (no stream alignment between properties!) + if( ensureValid() && !maStreamProps.empty() ) + for( ComplexPropVector::iterator aIt = maStreamProps.begin(), aEnd = maStreamProps.end(); ensureValid() && (aIt != aEnd); ++aIt ) + ensureValid( (*aIt)->readProperty( maInStrm ) ); + + return mbValid; +} + +bool AxBinaryPropertyReader::ensureValid( bool bCondition ) +{ + mbValid = mbValid && bCondition && !maInStrm.isEof(); + return mbValid; +} + +bool AxBinaryPropertyReader::startNextProperty() +{ + bool bHasProp = getFlag( mnPropFlags, mnNextProp ); + setFlag( mnPropFlags, mnNextProp, false ); + mnNextProp <<= 1; + return ensureValid() && bHasProp; +} + +// ============================================================================ + +} // namespace ole +} // namespace oox + diff --git a/oox/source/ole/axcontrol.cxx b/oox/source/ole/axcontrol.cxx new file mode 100644 index 000000000000..82616026a505 --- /dev/null +++ b/oox/source/ole/axcontrol.cxx @@ -0,0 +1,1750 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/ole/axcontrol.hxx" +#include <rtl/tencinfo.h> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/FontStrikeout.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/awt/ImagePosition.hpp> +#include <com/sun/star/awt/ImageScaleMode.hpp> +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/awt/ScrollBarOrientation.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/awt/TextAlign.hpp> +#include <com/sun/star/awt/VisualEffect.hpp> +#include <com/sun/star/awt/XControlModel.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <com/sun/star/form/XFormComponent.hpp> +#include <com/sun/star/form/XFormsSupplier.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/style/VerticalAlignment.hpp> +#include "properties.hxx" +#include "tokens.hxx" +#include "oox/helper/attributelist.hxx" +#include "oox/helper/binaryinputstream.hxx" +#include "oox/helper/graphichelper.hxx" +#include "oox/helper/propertymap.hxx" +#include "oox/helper/propertyset.hxx" + +using ::rtl::OUString; +using ::com::sun::star::awt::Point; +using ::com::sun::star::awt::Size; +using ::com::sun::star::awt::XControlModel; +using ::com::sun::star::container::XIndexContainer; +using ::com::sun::star::container::XNameContainer; +using ::com::sun::star::drawing::XDrawPage; +using ::com::sun::star::form::XForm; +using ::com::sun::star::form::XFormComponent; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::UNO_SET_THROW; + +namespace oox { +namespace ole { + +// ============================================================================ + +namespace { + +const sal_uInt32 COMCTL_ID_SIZE = 0x12344321; + +const sal_uInt32 COMCTL_ID_COMMONDATA = 0xABCDEF01; +const sal_uInt32 COMCTL_COMMON_FLATBORDER = 0x00000001; +const sal_uInt32 COMCTL_COMMON_ENABLED = 0x00000002; +const sal_uInt32 COMCTL_COMMON_3DBORDER = 0x00000004; +const sal_uInt32 COMCTL_COMMON_OLEDROPMAN = 0x00002000; + +const sal_uInt32 COMCTL_ID_COMPLEXDATA = 0xBDECDE1F; +const sal_uInt32 COMCTL_COMPLEX_FONT = 0x00000001; +const sal_uInt32 COMCTL_COMPLEX_MOUSEICON = 0x00000002; + +const sal_uInt32 COMCTL_ID_SCROLLBAR_60 = 0x99470A83; +const sal_uInt32 COMCTL_SCROLLBAR_HOR = 0x00000010; +const sal_Int32 COMCTL_SCROLLBAR_3D = 0; +const sal_Int32 COMCTL_SCROLLBAR_FLAT = 1; +const sal_Int32 COMCTL_SCROLLBAR_TRACK3D = 2; + +const sal_uInt32 COMCTL_ID_PROGRESSBAR_50 = 0xE6E17E84; +const sal_uInt32 COMCTL_ID_PROGRESSBAR_60 = 0x97AB8A01; + +// ---------------------------------------------------------------------------- + +const sal_uInt32 AX_FLAGS_ENABLED = 0x00000002; +const sal_uInt32 AX_FLAGS_LOCKED = 0x00000004; +const sal_uInt32 AX_FLAGS_OPAQUE = 0x00000008; +const sal_uInt32 AX_FLAGS_COLUMNHEADS = 0x00000400; +const sal_uInt32 AX_FLAGS_ENTIREROWS = 0x00000800; +const sal_uInt32 AX_FLAGS_EXISTINGENTRIES = 0x00001000; +const sal_uInt32 AX_FLAGS_CAPTIONLEFT = 0x00002000; +const sal_uInt32 AX_FLAGS_EDITABLE = 0x00004000; +const sal_uInt32 AX_FLAGS_IMEMODE_MASK = 0x00078000; +const sal_uInt32 AX_FLAGS_DRAGENABLED = 0x00080000; +const sal_uInt32 AX_FLAGS_ENTERASNEWLINE = 0x00100000; +const sal_uInt32 AX_FLAGS_KEEPSELECTION = 0x00200000; +const sal_uInt32 AX_FLAGS_TABASCHARACTER = 0x00400000; +const sal_uInt32 AX_FLAGS_WORDWRAP = 0x00800000; +const sal_uInt32 AX_FLAGS_BORDERSSUPPRESSED = 0x02000000; +const sal_uInt32 AX_FLAGS_SELECTLINE = 0x04000000; +const sal_uInt32 AX_FLAGS_SINGLECHARSELECT = 0x08000000; +const sal_uInt32 AX_FLAGS_AUTOSIZE = 0x10000000; +const sal_uInt32 AX_FLAGS_HIDESELECTION = 0x20000000; +const sal_uInt32 AX_FLAGS_MAXLENAUTOTAB = 0x40000000; +const sal_uInt32 AX_FLAGS_MULTILINE = 0x80000000; + +const sal_uInt32 AX_CMDBUTTON_DEFFLAGS = 0x0000001B; +const sal_uInt32 AX_LABEL_DEFFLAGS = 0x0080001B; +const sal_uInt32 AX_IMAGE_DEFFLAGS = 0x0000001B; +const sal_uInt32 AX_MORPHDATA_DEFFLAGS = 0x2C80081B; +const sal_uInt32 AX_SPINBUTTON_DEFFLAGS = 0x0000001B; +const sal_uInt32 AX_SCROLLBAR_DEFFLAGS = 0x0000001B; +const sal_uInt32 AX_TABSTRIP_DEFFLAGS = 0x0000001B; + +const sal_uInt16 AX_POS_TOPLEFT = 0; +const sal_uInt16 AX_POS_TOP = 1; +const sal_uInt16 AX_POS_TOPRIGHT = 2; +const sal_uInt16 AX_POS_LEFT = 3; +const sal_uInt16 AX_POS_CENTER = 4; +const sal_uInt16 AX_POS_RIGHT = 5; +const sal_uInt16 AX_POS_BOTTOMLEFT = 6; +const sal_uInt16 AX_POS_BOTTOM = 7; +const sal_uInt16 AX_POS_BOTTOMRIGHT = 8; + +#define AX_PICPOS_IMPL( label, image ) ((AX_POS_##label << 16) | AX_POS_##image) +const sal_uInt32 AX_PICPOS_LEFTTOP = AX_PICPOS_IMPL( TOPRIGHT, TOPLEFT ); +const sal_uInt32 AX_PICPOS_LEFTCENTER = AX_PICPOS_IMPL( RIGHT, LEFT ); +const sal_uInt32 AX_PICPOS_LEFTBOTTOM = AX_PICPOS_IMPL( BOTTOMRIGHT, BOTTOMLEFT ); +const sal_uInt32 AX_PICPOS_RIGHTTOP = AX_PICPOS_IMPL( TOPLEFT, TOPRIGHT ); +const sal_uInt32 AX_PICPOS_RIGHTCENTER = AX_PICPOS_IMPL( LEFT, RIGHT ); +const sal_uInt32 AX_PICPOS_RIGHTBOTTOM = AX_PICPOS_IMPL( BOTTOMLEFT, BOTTOMRIGHT ); +const sal_uInt32 AX_PICPOS_ABOVELEFT = AX_PICPOS_IMPL( BOTTOMLEFT, TOPLEFT ); +const sal_uInt32 AX_PICPOS_ABOVECENTER = AX_PICPOS_IMPL( BOTTOM, TOP ); +const sal_uInt32 AX_PICPOS_ABOVERIGHT = AX_PICPOS_IMPL( BOTTOMRIGHT, TOPRIGHT ); +const sal_uInt32 AX_PICPOS_BELOWLEFT = AX_PICPOS_IMPL( TOPLEFT, BOTTOMLEFT ); +const sal_uInt32 AX_PICPOS_BELOWCENTER = AX_PICPOS_IMPL( TOP, BOTTOM ); +const sal_uInt32 AX_PICPOS_BELOWRIGHT = AX_PICPOS_IMPL( TOPRIGHT, BOTTOMRIGHT ); +const sal_uInt32 AX_PICPOS_CENTER = AX_PICPOS_IMPL( CENTER, CENTER ); +#undef AX_PICPOS_IMPL + +const sal_Int32 AX_DISPLAYSTYLE_TEXT = 1; +const sal_Int32 AX_DISPLAYSTYLE_LISTBOX = 2; +const sal_Int32 AX_DISPLAYSTYLE_COMBOBOX = 3; +const sal_Int32 AX_DISPLAYSTYLE_CHECKBOX = 4; +const sal_Int32 AX_DISPLAYSTYLE_OPTBUTTON = 5; +const sal_Int32 AX_DISPLAYSTYLE_TOGGLE = 6; +const sal_Int32 AX_DISPLAYSTYLE_DROPDOWN = 7; + +const sal_Int32 AX_SELCTION_SINGLE = 0; +const sal_Int32 AX_SELCTION_MULTI = 1; +const sal_Int32 AX_SELCTION_EXTENDED = 2; + +const sal_Int32 AX_SCROLLBAR_NONE = 0x00; +const sal_Int32 AX_SCROLLBAR_HORIZONTAL = 0x01; +const sal_Int32 AX_SCROLLBAR_VERTICAL = 0x02; + +const sal_Int32 AX_MATCHENTRY_FIRSTLETTER = 0; +const sal_Int32 AX_MATCHENTRY_COMPLETE = 1; +const sal_Int32 AX_MATCHENTRY_NONE = 2; + +const sal_Int32 AX_SHOWDROPBUTTON_NEVER = 0; +const sal_Int32 AX_SHOWDROPBUTTON_FOCUS = 1; +const sal_Int32 AX_SHOWDROPBUTTON_ALWAYS = 2; + +const sal_Int32 AX_ORIENTATION_AUTO = -1; +const sal_Int32 AX_ORIENTATION_VERTICAL = 0; +const sal_Int32 AX_ORIENTATION_HORIZONTAL = 1; + +const sal_Int32 AX_PROPTHUMB_ON = -1; +const sal_Int32 AX_PROPTHUMB_OFF = 0; + +const sal_uInt32 AX_TABSTRIP_TABS = 0; +const sal_uInt32 AX_TABSTRIP_BUTTONS = 1; +const sal_uInt32 AX_TABSTRIP_NONE = 2; + +const sal_uInt32 AX_CONTAINER_ENABLED = 0x00000004; +const sal_uInt32 AX_CONTAINER_HASDESIGNEXT = 0x00004000; +const sal_uInt32 AX_CONTAINER_NOCLASSTABLE = 0x00008000; + +const sal_uInt32 AX_CONTAINER_DEFFLAGS = 0x00000004; + +const sal_Int32 AX_CONTAINER_DEFWIDTH = 4000; +const sal_Int32 AX_CONTAINER_DEFHEIGHT = 3000; + +const sal_Int32 AX_CONTAINER_CYCLEALL = 0; +const sal_Int32 AX_CONTAINER_CYCLECURRENT = 2; + +const sal_Int32 AX_CONTAINER_SCR_NONE = 0x00; +const sal_Int32 AX_CONTAINER_SCR_HOR = 0x01; +const sal_Int32 AX_CONTAINER_SCR_VER = 0x02; +const sal_Int32 AX_CONTAINER_SCR_KEEP_HOR = 0x04; +const sal_Int32 AX_CONTAINER_SCR_KEEP_VER = 0x08; +const sal_Int32 AX_CONTAINER_SCR_SHOW_LEFT = 0x10; + +// ---------------------------------------------------------------------------- + +const sal_Int16 API_BORDER_NONE = 0; +const sal_Int16 API_BORDER_SUNKEN = 1; +const sal_Int16 API_BORDER_FLAT = 2; + +const sal_Int16 API_STATE_UNCHECKED = 0; +const sal_Int16 API_STATE_CHECKED = 1; +const sal_Int16 API_STATE_DONTKNOW = 2; + +} // namespace + +// ============================================================================ + +ControlConverter::ControlConverter( const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr ) : + mrGraphicHelper( rGraphicHelper ), + mbDefaultColorBgr( bDefaultColorBgr ) +{ +} + +ControlConverter::~ControlConverter() +{ +} + +// Generic conversion --------------------------------------------------------- + +void ControlConverter::convertPosition( PropertyMap& rPropMap, const AxPairData& rPos ) const +{ + // position is given in 1/100 mm, UNO needs AppFont units + Point aAppFontPos = mrGraphicHelper.convertHmmToAppFont( Point( rPos.first, rPos.second ) ); + rPropMap.setProperty( PROP_PositionX, aAppFontPos.X ); + rPropMap.setProperty( PROP_PositionY, aAppFontPos.Y ); +} + +void ControlConverter::convertSize( PropertyMap& rPropMap, const AxPairData& rSize ) const +{ + // size is given in 1/100 mm, UNO needs AppFont units + Size aAppFontSize = mrGraphicHelper.convertHmmToAppFont( Size( rSize.first, rSize.second ) ); + rPropMap.setProperty( PROP_Width, aAppFontSize.Width ); + rPropMap.setProperty( PROP_Height, aAppFontSize.Height ); +} + +void ControlConverter::convertColor( PropertyMap& rPropMap, sal_Int32 nPropId, sal_uInt32 nOleColor ) const +{ + rPropMap.setProperty( nPropId, OleHelper::decodeOleColor( mrGraphicHelper, nOleColor, mbDefaultColorBgr ) ); +} + +void ControlConverter::convertPicture( PropertyMap& rPropMap, const StreamDataSequence& rPicData ) const +{ + if( rPicData.hasElements() ) + { + OUString aGraphicUrl = mrGraphicHelper.importGraphicObject( rPicData ); + if( aGraphicUrl.getLength() > 0 ) + rPropMap.setProperty( PROP_ImageURL, aGraphicUrl ); + } +} + +void ControlConverter::convertOrientation( PropertyMap& rPropMap, bool bHorizontal ) const +{ + namespace AwtScrollBarOrient = ::com::sun::star::awt::ScrollBarOrientation; + sal_Int32 nScrollOrient = bHorizontal ? AwtScrollBarOrient::HORIZONTAL : AwtScrollBarOrient::VERTICAL; + rPropMap.setProperty( PROP_Orientation, nScrollOrient ); +} + +void ControlConverter::convertScrollBar( PropertyMap& rPropMap, + sal_Int32 nMin, sal_Int32 nMax, sal_Int32 nPosition, + sal_Int32 nSmallChange, sal_Int32 nLargeChange, bool bAwtModel ) const +{ + rPropMap.setProperty( PROP_ScrollValueMin, ::std::min( nMin, nMax ) ); + rPropMap.setProperty( PROP_ScrollValueMax, ::std::max( nMin, nMax ) ); + rPropMap.setProperty( PROP_LineIncrement, nSmallChange ); + rPropMap.setProperty( PROP_BlockIncrement, nLargeChange ); + rPropMap.setProperty( bAwtModel ? PROP_ScrollValue : PROP_DefaultScrollValue, nPosition ); +} + +// ActiveX (Forms 2.0) specific conversion ------------------------------------ + +void ControlConverter::convertAxBackground( PropertyMap& rPropMap, + sal_uInt32 nBackColor, sal_uInt32 nFlags, ApiTransparencyMode eTranspMode ) const +{ + bool bOpaque = getFlag( nFlags, AX_FLAGS_OPAQUE ); + switch( eTranspMode ) + { + case API_TRANSPARENCY_NOTSUPPORTED: + // fake transparency by using system window background if needed + convertColor( rPropMap, PROP_BackgroundColor, bOpaque ? nBackColor : AX_SYSCOLOR_WINDOWBACK ); + break; + case API_TRANSPARENCY_PAINTTRANSPARENT: + rPropMap.setProperty( PROP_PaintTransparent, !bOpaque ); + // run-through intended! + case API_TRANSPARENCY_VOID: + // keep transparency by leaving the (void) default property value + if( bOpaque ) + convertColor( rPropMap, PROP_BackgroundColor, nBackColor ); + break; + } +} + +void ControlConverter::convertAxBorder( PropertyMap& rPropMap, + sal_uInt32 nBorderColor, sal_Int32 nBorderStyle, sal_Int32 nSpecialEffect ) const +{ + sal_Int16 nBorder = (nBorderStyle == AX_BORDERSTYLE_SINGLE) ? API_BORDER_FLAT : + ((nSpecialEffect == AX_SPECIALEFFECT_FLAT) ? API_BORDER_NONE : API_BORDER_SUNKEN); + rPropMap.setProperty( PROP_Border, nBorder ); + convertColor( rPropMap, PROP_BorderColor, nBorderColor ); +} + +void ControlConverter::convertAxVisualEffect( PropertyMap& rPropMap, sal_Int32 nSpecialEffect ) const +{ + namespace AwtVisualEffect = ::com::sun::star::awt::VisualEffect; + sal_Int16 nVisualEffect = (nSpecialEffect == AX_SPECIALEFFECT_FLAT) ? AwtVisualEffect::FLAT : AwtVisualEffect::LOOK3D; + rPropMap.setProperty( PROP_VisualEffect, nVisualEffect ); +} + +void ControlConverter::convertAxPicture( PropertyMap& rPropMap, const StreamDataSequence& rPicData, sal_uInt32 nPicPos ) const +{ + // the picture + convertPicture( rPropMap, rPicData ); + + // picture position + namespace AwtImagePos = ::com::sun::star::awt::ImagePosition; + sal_Int16 nImagePos = AwtImagePos::LeftCenter; + switch( nPicPos ) + { + case AX_PICPOS_LEFTTOP: nImagePos = AwtImagePos::LeftTop; break; + case AX_PICPOS_LEFTCENTER: nImagePos = AwtImagePos::LeftCenter; break; + case AX_PICPOS_LEFTBOTTOM: nImagePos = AwtImagePos::LeftBottom; break; + case AX_PICPOS_RIGHTTOP: nImagePos = AwtImagePos::RightTop; break; + case AX_PICPOS_RIGHTCENTER: nImagePos = AwtImagePos::RightCenter; break; + case AX_PICPOS_RIGHTBOTTOM: nImagePos = AwtImagePos::RightBottom; break; + case AX_PICPOS_ABOVELEFT: nImagePos = AwtImagePos::AboveLeft; break; + case AX_PICPOS_ABOVECENTER: nImagePos = AwtImagePos::AboveCenter; break; + case AX_PICPOS_ABOVERIGHT: nImagePos = AwtImagePos::AboveRight; break; + case AX_PICPOS_BELOWLEFT: nImagePos = AwtImagePos::BelowLeft; break; + case AX_PICPOS_BELOWCENTER: nImagePos = AwtImagePos::BelowCenter; break; + case AX_PICPOS_BELOWRIGHT: nImagePos = AwtImagePos::BelowRight; break; + case AX_PICPOS_CENTER: nImagePos = AwtImagePos::Centered; break; + default: OSL_ENSURE( false, "ControlConverter::convertAxPicture - unknown picture position" ); + } + rPropMap.setProperty( PROP_ImagePosition, nImagePos ); +} + +void ControlConverter::convertAxPicture( PropertyMap& rPropMap, const StreamDataSequence& rPicData, + sal_Int32 nPicSizeMode, sal_Int32 /*nPicAlign*/, bool /*bPicTiling*/ ) const +{ + // the picture + convertPicture( rPropMap, rPicData ); + + // picture scale mode + namespace AwtScaleMode = ::com::sun::star::awt::ImageScaleMode; + sal_Int16 nScaleMode = AwtScaleMode::None; + switch( nPicSizeMode ) + { + case AX_PICSIZE_CLIP: nScaleMode = AwtScaleMode::None; break; + case AX_PICSIZE_STRETCH: nScaleMode = AwtScaleMode::Anisotropic; break; + case AX_PICSIZE_ZOOM: nScaleMode = AwtScaleMode::Isotropic; break; + default: OSL_ENSURE( false, "ControlConverter::convertAxPicture - unknown picture size mode" ); + } + rPropMap.setProperty( PROP_ScaleMode, nScaleMode ); +} + +void ControlConverter::convertAxState( PropertyMap& rPropMap, + const OUString& rValue, sal_Int32 nMultiSelect, ApiDefaultStateMode eDefStateMode, bool bAwtModel ) const +{ + bool bBooleanState = eDefStateMode == API_DEFAULTSTATE_BOOLEAN; + bool bSupportsTriState = eDefStateMode == API_DEFAULTSTATE_TRISTATE; + + // state + sal_Int16 nState = bSupportsTriState ? API_STATE_DONTKNOW : API_STATE_UNCHECKED; + if( rValue.getLength() == 1 ) switch( rValue[ 0 ] ) + { + case '0': nState = API_STATE_UNCHECKED; break; + case '1': nState = API_STATE_CHECKED; break; + // any other string (also empty) means 'dontknow' + } + sal_Int32 nPropId = bAwtModel ? PROP_State : PROP_DefaultState; + if( bBooleanState ) + rPropMap.setProperty( nPropId, nState != API_STATE_UNCHECKED ); + else + rPropMap.setProperty( nPropId, nState ); + + // tristate + if( bSupportsTriState ) + rPropMap.setProperty( PROP_TriState, nMultiSelect == AX_SELCTION_MULTI ); +} + +void ControlConverter::convertAxOrientation( PropertyMap& rPropMap, + const AxPairData& rSize, sal_Int32 nOrientation ) const +{ + bool bHorizontal = true; + switch( nOrientation ) + { + case AX_ORIENTATION_AUTO: bHorizontal = rSize.first > rSize.second; break; + case AX_ORIENTATION_VERTICAL: bHorizontal = false; break; + case AX_ORIENTATION_HORIZONTAL: bHorizontal = true; break; + default: OSL_ENSURE( false, "ControlConverter::convertAxOrientation - unknown orientation" ); + } + convertOrientation( rPropMap, bHorizontal ); +} + +// ============================================================================ + +ControlModelBase::ControlModelBase() : + maSize( 0, 0 ), + mbAwtModel( false ) +{ +} + +ControlModelBase::~ControlModelBase() +{ +} + +OUString ControlModelBase::getServiceName() const +{ + ApiControlType eCtrlType = getControlType(); + if( mbAwtModel ) switch( eCtrlType ) + { + case API_CONTROL_BUTTON: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlButtonModel" ); + case API_CONTROL_FIXEDTEXT: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlFixedTextModel" ); + case API_CONTROL_IMAGE: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlImageControlModel" ); + case API_CONTROL_CHECKBOX: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlCheckBoxModel" ); + case API_CONTROL_RADIOBUTTON: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlRadioButtonModel" ); + case API_CONTROL_EDIT: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlEditModel" ); + case API_CONTROL_LISTBOX: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlListBoxModel" ); + case API_CONTROL_COMBOBOX: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlComboBoxModel" ); + case API_CONTROL_SPINBUTTON: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlSpinButtonModel" ); + case API_CONTROL_SCROLLBAR: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlScrollBarModel" ); + case API_CONTROL_PROGRESSBAR: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlProgressBarModel" ); + case API_CONTROL_GROUPBOX: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlGroupBoxModel" ); + case API_CONTROL_DIALOG: return CREATE_OUSTRING( "com.sun.star.awt.UnoControlDialogModel" ); + default: OSL_ENSURE( false, "ControlModelBase::getServiceName - no AWT model service supported" ); + } + else switch( eCtrlType ) + { + case API_CONTROL_BUTTON: return CREATE_OUSTRING( "com.sun.star.form.component.CommandButton" ); + case API_CONTROL_FIXEDTEXT: return CREATE_OUSTRING( "com.sun.star.form.component.FixedText" ); + case API_CONTROL_IMAGE: return CREATE_OUSTRING( "com.sun.star.form.component.DatabaseImageControl" ); + case API_CONTROL_CHECKBOX: return CREATE_OUSTRING( "com.sun.star.form.component.CheckBox" ); + case API_CONTROL_RADIOBUTTON: return CREATE_OUSTRING( "com.sun.star.form.component.RadioButton" ); + case API_CONTROL_EDIT: return CREATE_OUSTRING( "com.sun.star.form.component.TextField" ); + case API_CONTROL_LISTBOX: return CREATE_OUSTRING( "com.sun.star.form.component.ListBox" ); + case API_CONTROL_COMBOBOX: return CREATE_OUSTRING( "com.sun.star.form.component.ComboBox" ); + case API_CONTROL_SPINBUTTON: return CREATE_OUSTRING( "com.sun.star.form.component.SpinButton" ); + case API_CONTROL_SCROLLBAR: return CREATE_OUSTRING( "com.sun.star.form.component.ScrollBar" ); + case API_CONTROL_GROUPBOX: return CREATE_OUSTRING( "com.sun.star.form.component.GroupBox" ); + default: OSL_ENSURE( false, "ControlModelBase::getServiceName - no form component service supported" ); + } + return OUString(); +} + +void ControlModelBase::importProperty( sal_Int32 /*nPropId*/, const OUString& /*rValue*/ ) +{ +} + +void ControlModelBase::importPictureData( sal_Int32 /*nPropId*/, BinaryInputStream& /*rInStrm*/ ) +{ +} + +void ControlModelBase::convertProperties( PropertyMap& /*rPropMap*/, const ControlConverter& /*rConv*/ ) const +{ +} + +void ControlModelBase::convertSize( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rConv.convertSize( rPropMap, maSize ); +} + +// ============================================================================ + +ComCtlModelBase::ComCtlModelBase( sal_uInt32 nDataPartId5, sal_uInt32 nDataPartId6, + sal_uInt16 nVersion, bool bCommonPart, bool bComplexPart ) : + maFontData( CREATE_OUSTRING( "Tahoma" ), 82500 ), + mnFlags( 0 ), + mnVersion( nVersion ), + mnDataPartId5( nDataPartId5 ), + mnDataPartId6( nDataPartId6 ), + mbCommonPart( bCommonPart ), + mbComplexPart( bComplexPart ) +{ +} + +bool ComCtlModelBase::importBinaryModel( BinaryInputStream& rInStrm ) +{ + // read initial size part and header of the control data part + if( importSizePart( rInStrm ) && readPartHeader( rInStrm, getDataPartId(), mnVersion ) ) + { + // if flags part exists, the first int32 of the data part contains its size + sal_uInt32 nCommonPartSize = mbCommonPart ? rInStrm.readuInt32() : 0; + // implementations must read the exact amount of data, stream must point to its end afterwards + importControlData( rInStrm ); + // read following parts + if( !rInStrm.isEof() && + (!mbCommonPart || importCommonPart( rInStrm, nCommonPartSize )) && + (!mbComplexPart || importComplexPart( rInStrm )) ) + { + return !rInStrm.isEof(); + } + } + return false; +} + +void ComCtlModelBase::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + if( mbCommonPart ) + rPropMap.setProperty( PROP_Enabled, getFlag( mnFlags, COMCTL_COMMON_ENABLED ) ); + ControlModelBase::convertProperties( rPropMap, rConv ); +} + +void ComCtlModelBase::importCommonExtraData( BinaryInputStream& /*rInStrm*/ ) +{ +} + +void ComCtlModelBase::importCommonTrailingData( BinaryInputStream& /*rInStrm*/ ) +{ +} + +sal_uInt32 ComCtlModelBase::getDataPartId() const +{ + switch( mnVersion ) + { + case 5: return mnDataPartId5; + case 6: return mnDataPartId6; + } + OSL_ENSURE( false, "ComCtlObjectBase::getDataPartId - unxpected version" ); + return SAL_MAX_UINT32; +} + +bool ComCtlModelBase::readPartHeader( BinaryInputStream& rInStrm, sal_uInt32 nExpPartId, sal_uInt16 nExpMajor, sal_uInt16 nExpMinor ) +{ + // no idea if all this is correct... + sal_uInt32 nPartId; + sal_uInt16 nMajor, nMinor; + rInStrm >> nPartId >> nMinor >> nMajor; + bool bPartId = nPartId == nExpPartId; + OSL_ENSURE( bPartId, "ComCtlObjectBase::readPartHeader - unexpected part identifier" ); + bool bVersion = ((nExpMajor == SAL_MAX_UINT16) || (nExpMajor == nMajor)) && ((nExpMinor == SAL_MAX_UINT16) || (nExpMinor == nMinor)); + OSL_ENSURE( bVersion, "ComCtlObjectBase::readPartHeader - unexpected part version" ); + return !rInStrm.isEof() && bPartId && bVersion; +} + +bool ComCtlModelBase::importSizePart( BinaryInputStream& rInStrm ) +{ + if( readPartHeader( rInStrm, COMCTL_ID_SIZE, 0, 8 ) ) + { + rInStrm >> maSize.first >> maSize.second; + return !rInStrm.isEof(); + } + return false; +} + +bool ComCtlModelBase::importCommonPart( BinaryInputStream& rInStrm, sal_uInt32 nPartSize ) +{ + sal_Int64 nEndPos = rInStrm.tell() + nPartSize; + if( (nPartSize >= 16) && readPartHeader( rInStrm, COMCTL_ID_COMMONDATA, 5, 0 ) ) + { + rInStrm.skip( 4 ); + rInStrm >> mnFlags; + // implementations may read less than the exact amount of data + importCommonExtraData( rInStrm ); + rInStrm.seek( nEndPos ); + // implementations must read the exact amount of data, stream must point to its end afterwards + importCommonTrailingData( rInStrm ); + return !rInStrm.isEof(); + } + return false; +} + +bool ComCtlModelBase::importComplexPart( BinaryInputStream& rInStrm ) +{ + if( readPartHeader( rInStrm, COMCTL_ID_COMPLEXDATA, 5, 1 ) ) + { + sal_uInt32 nContFlags; + rInStrm >> nContFlags; + bool bReadOk = + (!getFlag( nContFlags, COMCTL_COMPLEX_FONT ) || OleHelper::importStdFont( maFontData, rInStrm, true )) && + (!getFlag( nContFlags, COMCTL_COMPLEX_MOUSEICON ) || OleHelper::importStdPic( maMouseIcon, rInStrm, true )); + return bReadOk && !rInStrm.isEof(); + } + return false; +} + +// ============================================================================ + +ComCtlScrollBarModel::ComCtlScrollBarModel( sal_uInt16 nVersion ) : + ComCtlModelBase( SAL_MAX_UINT32, COMCTL_ID_SCROLLBAR_60, nVersion, true, true ), + mnScrollBarFlags( 0x00000011 ), + mnLargeChange( 1 ), + mnSmallChange( 1 ), + mnMin( 0 ), + mnMax( 32767 ), + mnPosition( 0 ) +{ +} + +ApiControlType ComCtlScrollBarModel::getControlType() const +{ + return API_CONTROL_SCROLLBAR; +} + +void ComCtlScrollBarModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Border, API_BORDER_NONE ); + rConv.convertOrientation( rPropMap, getFlag( mnScrollBarFlags, COMCTL_SCROLLBAR_HOR ) ); + rConv.convertScrollBar( rPropMap, mnMin, mnMax, mnPosition, mnSmallChange, mnLargeChange, mbAwtModel ); + ComCtlModelBase::convertProperties( rPropMap, rConv ); +} + +void ComCtlScrollBarModel::importControlData( BinaryInputStream& rInStrm ) +{ + rInStrm >> mnScrollBarFlags >> mnLargeChange >> mnSmallChange >> mnMin >> mnMax >> mnPosition; +} + +// ============================================================================ + +ComCtlProgressBarModel::ComCtlProgressBarModel( sal_uInt16 nVersion ) : + ComCtlModelBase( COMCTL_ID_PROGRESSBAR_50, COMCTL_ID_PROGRESSBAR_60, nVersion, true, true ), + mfMin( 0.0 ), + mfMax( 100.0 ), + mnVertical( 0 ), + mnSmooth( 0 ) +{ +} + +ApiControlType ComCtlProgressBarModel::getControlType() const +{ + return API_CONTROL_PROGRESSBAR; +} + +void ComCtlProgressBarModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + sal_uInt16 nBorder = getFlag( mnFlags, COMCTL_COMMON_3DBORDER ) ? API_BORDER_SUNKEN : + (getFlag( mnFlags, COMCTL_COMMON_FLATBORDER ) ? API_BORDER_FLAT : API_BORDER_NONE); + rPropMap.setProperty( PROP_Border, nBorder ); + rPropMap.setProperty( PROP_ProgressValueMin, getLimitedValue< sal_Int32, double >( ::std::min( mfMin, mfMax ), 0.0, SAL_MAX_INT32 ) ); + rPropMap.setProperty( PROP_ProgressValueMax, getLimitedValue< sal_Int32, double >( ::std::max( mfMin, mfMax ), 0.0, SAL_MAX_INT32 ) ); + // ComCtl model does not provide current value? + ComCtlModelBase::convertProperties( rPropMap, rConv ); +} + +void ComCtlProgressBarModel::importControlData( BinaryInputStream& rInStrm ) +{ + rInStrm >> mfMin >> mfMax; + if( mnVersion == 6 ) + rInStrm >> mnVertical >> mnSmooth; +} + +// ============================================================================ + +AxControlModelBase::AxControlModelBase() +{ +} + +void AxControlModelBase::importProperty( sal_Int32 nPropId, const OUString& rValue ) +{ + switch( nPropId ) + { + // size of the control shape: format is "width;height" + case XML_Size: + { + sal_Int32 nSepPos = rValue.indexOf( ';' ); + OSL_ENSURE( nSepPos >= 0, "AxControlModelBase::importProperty - missing separator in 'Size' property" ); + if( nSepPos >= 0 ) + { + maSize.first = rValue.copy( 0, nSepPos ).toInt32(); + maSize.second = rValue.copy( nSepPos + 1 ).toInt32(); + } + } + break; + } +} + +// ============================================================================ + +AxFontDataModel::AxFontDataModel( bool bSupportsAlign ) : + mbSupportsAlign( bSupportsAlign ) +{ +} + +void AxFontDataModel::importProperty( sal_Int32 nPropId, const OUString& rValue ) +{ + switch( nPropId ) + { + case XML_FontName: maFontData.maFontName = rValue; break; + case XML_FontEffects: maFontData.mnFontEffects = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_FontHeight: maFontData.mnFontHeight = AttributeConversion::decodeInteger( rValue ); break; + case XML_FontCharSet: maFontData.mnFontCharSet = AttributeConversion::decodeInteger( rValue ); break; + case XML_ParagraphAlign: maFontData.mnHorAlign = AttributeConversion::decodeInteger( rValue ); break; + default: AxControlModelBase::importProperty( nPropId, rValue ); + } +} + +bool AxFontDataModel::importBinaryModel( BinaryInputStream& rInStrm ) +{ + return maFontData.importBinaryModel( rInStrm ); +} + +void AxFontDataModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + namespace cssa = ::com::sun::star::awt; + + // font name + if( maFontData.maFontName.getLength() > 0 ) + rPropMap.setProperty( PROP_FontName, maFontData.maFontName ); + + // font effects + rPropMap.setProperty( PROP_FontWeight, getFlagValue( maFontData.mnFontEffects, AX_FONTDATA_BOLD, cssa::FontWeight::BOLD, cssa::FontWeight::NORMAL ) ); + rPropMap.setProperty( PROP_FontSlant, getFlagValue< sal_Int16 >( maFontData.mnFontEffects, AX_FONTDATA_ITALIC, cssa::FontSlant_ITALIC, cssa::FontSlant_NONE ) ); + rPropMap.setProperty( PROP_FontUnderline, getFlagValue( maFontData.mnFontEffects, AX_FONTDATA_UNDERLINE, cssa::FontUnderline::SINGLE, cssa::FontUnderline::NONE ) ); + rPropMap.setProperty( PROP_FontStrikeout, getFlagValue( maFontData.mnFontEffects, AX_FONTDATA_STRIKEOUT, cssa::FontStrikeout::SINGLE, cssa::FontStrikeout::NONE ) ); + rPropMap.setProperty( PROP_FontHeight, maFontData.getHeightPoints() ); + + // font character set + rtl_TextEncoding eFontEnc = RTL_TEXTENCODING_DONTKNOW; + if( (0 <= maFontData.mnFontCharSet) && (maFontData.mnFontCharSet <= SAL_MAX_UINT8) ) + eFontEnc = rtl_getTextEncodingFromWindowsCharset( static_cast< sal_uInt8 >( maFontData.mnFontCharSet ) ); + if( eFontEnc != RTL_TEXTENCODING_DONTKNOW ) + rPropMap.setProperty( PROP_FontCharset, static_cast< sal_Int16 >( eFontEnc ) ); + + // text alignment + if( mbSupportsAlign ) + { + sal_Int32 nAlign = cssa::TextAlign::LEFT; + switch( maFontData.mnHorAlign ) + { + case AX_FONTDATA_LEFT: nAlign = cssa::TextAlign::LEFT; break; + case AX_FONTDATA_RIGHT: nAlign = cssa::TextAlign::RIGHT; break; + case AX_FONTDATA_CENTER: nAlign = cssa::TextAlign::CENTER; break; + default: OSL_ENSURE( false, "AxFontDataModel::convertProperties - unknown text alignment" ); + } + // form controls expect short value + rPropMap.setProperty( PROP_Align, static_cast< sal_Int16 >( nAlign ) ); + } + + // process base class properties + AxControlModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxCommandButtonModel::AxCommandButtonModel() : + mnTextColor( AX_SYSCOLOR_BUTTONTEXT ), + mnBackColor( AX_SYSCOLOR_BUTTONFACE ), + mnFlags( AX_CMDBUTTON_DEFFLAGS ), + mnPicturePos( AX_PICPOS_ABOVECENTER ), + mbFocusOnClick( true ) +{ +} + +void AxCommandButtonModel::importProperty( sal_Int32 nPropId, const OUString& rValue ) +{ + switch( nPropId ) + { + case XML_Caption: maCaption = rValue; break; + case XML_ForeColor: mnTextColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_BackColor: mnBackColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_VariousPropertyBits: mnFlags = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_PicturePosition: mnPicturePos = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_TakeFocusOnClick: mbFocusOnClick = AttributeConversion::decodeInteger( rValue ) != 0; break; + default: AxFontDataModel::importProperty( nPropId, rValue ); + } +} + +void AxCommandButtonModel::importPictureData( sal_Int32 nPropId, BinaryInputStream& rInStrm ) +{ + switch( nPropId ) + { + case XML_Picture: OleHelper::importStdPic( maPictureData, rInStrm, true ); break; + default: AxFontDataModel::importPictureData( nPropId, rInStrm ); + } +} + +bool AxCommandButtonModel::importBinaryModel( BinaryInputStream& rInStrm ) +{ + AxBinaryPropertyReader aReader( rInStrm ); + aReader.readIntProperty< sal_uInt32 >( mnTextColor ); + aReader.readIntProperty< sal_uInt32 >( mnBackColor ); + aReader.readIntProperty< sal_uInt32 >( mnFlags ); + aReader.readStringProperty( maCaption ); + aReader.readIntProperty< sal_uInt32 >( mnPicturePos ); + aReader.readPairProperty( maSize ); + aReader.skipIntProperty< sal_uInt8 >(); // mouse pointer + aReader.readPictureProperty( maPictureData ); + aReader.skipIntProperty< sal_uInt16 >(); // accelerator + aReader.readBoolProperty( mbFocusOnClick, true ); // binary flag means "do not take focus" + aReader.skipPictureProperty(); // mouse icon + return aReader.finalizeImport() && AxFontDataModel::importBinaryModel( rInStrm ); +} + +ApiControlType AxCommandButtonModel::getControlType() const +{ + return API_CONTROL_BUTTON; +} + +void AxCommandButtonModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Label, maCaption ); + rPropMap.setProperty( PROP_Enabled, getFlag( mnFlags, AX_FLAGS_ENABLED ) ); + rPropMap.setProperty( PROP_MultiLine, getFlag( mnFlags, AX_FLAGS_WORDWRAP ) ); + rPropMap.setProperty( PROP_FocusOnClick, mbFocusOnClick ); + rPropMap.setProperty( PROP_VerticalAlign, ::com::sun::star::style::VerticalAlignment_MIDDLE ); + rConv.convertColor( rPropMap, PROP_TextColor, mnTextColor ); + rConv.convertAxBackground( rPropMap, mnBackColor, mnFlags, API_TRANSPARENCY_NOTSUPPORTED ); + rConv.convertAxPicture( rPropMap, maPictureData, mnPicturePos ); + AxFontDataModel::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxLabelModel::AxLabelModel() : + mnTextColor( AX_SYSCOLOR_BUTTONTEXT ), + mnBackColor( AX_SYSCOLOR_BUTTONFACE ), + mnFlags( AX_LABEL_DEFFLAGS ), + mnBorderColor( AX_SYSCOLOR_WINDOWFRAME ), + mnBorderStyle( AX_BORDERSTYLE_NONE ), + mnSpecialEffect( AX_SPECIALEFFECT_FLAT ) +{ +} + +void AxLabelModel::importProperty( sal_Int32 nPropId, const OUString& rValue ) +{ + switch( nPropId ) + { + case XML_Caption: maCaption = rValue; break; + case XML_ForeColor: mnTextColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_BackColor: mnBackColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_VariousPropertyBits: mnFlags = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_BorderColor: mnBorderColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_BorderStyle: mnBorderStyle = AttributeConversion::decodeInteger( rValue ); break; + case XML_SpecialEffect: mnSpecialEffect = AttributeConversion::decodeInteger( rValue ); break; + default: AxFontDataModel::importProperty( nPropId, rValue ); + } +} + +bool AxLabelModel::importBinaryModel( BinaryInputStream& rInStrm ) +{ + AxBinaryPropertyReader aReader( rInStrm ); + aReader.readIntProperty< sal_uInt32 >( mnTextColor ); + aReader.readIntProperty< sal_uInt32 >( mnBackColor ); + aReader.readIntProperty< sal_uInt32 >( mnFlags ); + aReader.readStringProperty( maCaption ); + aReader.skipIntProperty< sal_uInt32 >(); // picture position + aReader.readPairProperty( maSize ); + aReader.skipIntProperty< sal_uInt8 >(); // mouse pointer + aReader.readIntProperty< sal_uInt32 >( mnBorderColor ); + aReader.readIntProperty< sal_uInt16 >( mnBorderStyle ); + aReader.readIntProperty< sal_uInt16 >( mnSpecialEffect ); + aReader.skipPictureProperty(); // picture + aReader.skipIntProperty< sal_uInt16 >(); // accelerator + aReader.skipPictureProperty(); // mouse icon + return aReader.finalizeImport() && AxFontDataModel::importBinaryModel( rInStrm ); +} + +ApiControlType AxLabelModel::getControlType() const +{ + return API_CONTROL_FIXEDTEXT; +} + +void AxLabelModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Label, maCaption ); + rPropMap.setProperty( PROP_Enabled, getFlag( mnFlags, AX_FLAGS_ENABLED ) ); + rPropMap.setProperty( PROP_MultiLine, getFlag( mnFlags, AX_FLAGS_WORDWRAP ) ); + rPropMap.setProperty( PROP_VerticalAlign, ::com::sun::star::style::VerticalAlignment_TOP ); + rConv.convertColor( rPropMap, PROP_TextColor, mnTextColor ); + rConv.convertAxBackground( rPropMap, mnBackColor, mnFlags, API_TRANSPARENCY_VOID ); + rConv.convertAxBorder( rPropMap, mnBorderColor, mnBorderStyle, mnSpecialEffect ); + AxFontDataModel::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxImageModel::AxImageModel() : + mnBackColor( AX_SYSCOLOR_BUTTONFACE ), + mnFlags( AX_IMAGE_DEFFLAGS ), + mnBorderColor( AX_SYSCOLOR_WINDOWFRAME ), + mnBorderStyle( AX_BORDERSTYLE_SINGLE ), + mnSpecialEffect( AX_SPECIALEFFECT_FLAT ), + mnPicSizeMode( AX_PICSIZE_CLIP ), + mnPicAlign( AX_PICALIGN_CENTER ), + mbPicTiling( false ) +{ +} + +void AxImageModel::importProperty( sal_Int32 nPropId, const OUString& rValue ) +{ + switch( nPropId ) + { + case XML_BackColor: mnBackColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_VariousPropertyBits: mnFlags = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_BorderColor: mnBorderColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_BorderStyle: mnBorderStyle = AttributeConversion::decodeInteger( rValue ); break; + case XML_SpecialEffect: mnSpecialEffect = AttributeConversion::decodeInteger( rValue ); break; + case XML_SizeMode: mnPicSizeMode = AttributeConversion::decodeInteger( rValue ); break; + case XML_PictureAlignment: mnPicAlign = AttributeConversion::decodeInteger( rValue ); break; + case XML_PictureTiling: mbPicTiling = AttributeConversion::decodeInteger( rValue ) != 0; break; + default: AxControlModelBase::importProperty( nPropId, rValue ); + } +} + +void AxImageModel::importPictureData( sal_Int32 nPropId, BinaryInputStream& rInStrm ) +{ + switch( nPropId ) + { + case XML_Picture: OleHelper::importStdPic( maPictureData, rInStrm, true ); break; + default: AxControlModelBase::importPictureData( nPropId, rInStrm ); + } +} + +bool AxImageModel::importBinaryModel( BinaryInputStream& rInStrm ) +{ + AxBinaryPropertyReader aReader( rInStrm ); + aReader.skipUndefinedProperty(); + aReader.skipUndefinedProperty(); + aReader.skipBoolProperty(); // auto-size + aReader.readIntProperty< sal_uInt32 >( mnBorderColor ); + aReader.readIntProperty< sal_uInt32 >( mnBackColor ); + aReader.readIntProperty< sal_uInt8 >( mnBorderStyle ); + aReader.skipIntProperty< sal_uInt8 >(); // mouse pointer + aReader.readIntProperty< sal_uInt8 >( mnPicSizeMode ); + aReader.readIntProperty< sal_uInt8 >( mnSpecialEffect ); + aReader.readPairProperty( maSize ); + aReader.readPictureProperty( maPictureData ); + aReader.readIntProperty< sal_uInt8 >( mnPicAlign ); + aReader.readBoolProperty( mbPicTiling ); + aReader.readIntProperty< sal_uInt32 >( mnFlags ); + aReader.skipPictureProperty(); // mouse icon + return aReader.finalizeImport(); +} + +ApiControlType AxImageModel::getControlType() const +{ + return API_CONTROL_IMAGE; +} + +void AxImageModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Enabled, getFlag( mnFlags, AX_FLAGS_ENABLED ) ); + rConv.convertAxBackground( rPropMap, mnBackColor, mnFlags, API_TRANSPARENCY_VOID ); + rConv.convertAxBorder( rPropMap, mnBorderColor, mnBorderStyle, mnSpecialEffect ); + rConv.convertAxPicture( rPropMap, maPictureData, mnPicSizeMode, mnPicAlign, mbPicTiling ); + AxControlModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxMorphDataModelBase::AxMorphDataModelBase() : + mnTextColor( AX_SYSCOLOR_WINDOWTEXT ), + mnBackColor( AX_SYSCOLOR_WINDOWBACK ), + mnFlags( AX_MORPHDATA_DEFFLAGS ), + mnPicturePos( AX_PICPOS_ABOVECENTER ), + mnBorderColor( AX_SYSCOLOR_WINDOWFRAME ), + mnBorderStyle( AX_BORDERSTYLE_NONE ), + mnSpecialEffect( AX_SPECIALEFFECT_SUNKEN ), + mnDisplayStyle( AX_DISPLAYSTYLE_TEXT ), + mnMultiSelect( AX_SELCTION_SINGLE ), + mnScrollBars( AX_SCROLLBAR_NONE ), + mnMatchEntry( AX_MATCHENTRY_NONE ), + mnShowDropButton( AX_SHOWDROPBUTTON_NEVER ), + mnMaxLength( 0 ), + mnPasswordChar( 0 ), + mnListRows( 8 ) +{ +} + +void AxMorphDataModelBase::importProperty( sal_Int32 nPropId, const OUString& rValue ) +{ + switch( nPropId ) + { + case XML_Caption: maCaption = rValue; break; + case XML_Value: maValue = rValue; break; + case XML_GroupName: maGroupName = rValue; break; + case XML_ForeColor: mnTextColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_BackColor: mnBackColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_VariousPropertyBits: mnFlags = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_PicturePosition: mnPicturePos = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_BorderColor: mnBorderColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_BorderStyle: mnBorderStyle = AttributeConversion::decodeInteger( rValue ); break; + case XML_SpecialEffect: mnSpecialEffect = AttributeConversion::decodeInteger( rValue ); break; + case XML_DisplayStyle: mnDisplayStyle = AttributeConversion::decodeInteger( rValue ); break; + case XML_MultiSelect: mnMultiSelect = AttributeConversion::decodeInteger( rValue ); break; + case XML_ScrollBars: mnScrollBars = AttributeConversion::decodeInteger( rValue ); break; + case XML_MatchEntry: mnMatchEntry = AttributeConversion::decodeInteger( rValue ); break; + case XML_ShowDropButtonWhen: mnShowDropButton = AttributeConversion::decodeInteger( rValue );break; + case XML_MaxLength: mnMaxLength = AttributeConversion::decodeInteger( rValue ); break; + case XML_PasswordChar: mnPasswordChar = AttributeConversion::decodeInteger( rValue ); break; + case XML_ListRows: mnListRows = AttributeConversion::decodeInteger( rValue ); break; + default: AxFontDataModel::importProperty( nPropId, rValue ); + } +} + +void AxMorphDataModelBase::importPictureData( sal_Int32 nPropId, BinaryInputStream& rInStrm ) +{ + switch( nPropId ) + { + case XML_Picture: OleHelper::importStdPic( maPictureData, rInStrm, true ); break; + default: AxFontDataModel::importPictureData( nPropId, rInStrm ); + } +} + +bool AxMorphDataModelBase::importBinaryModel( BinaryInputStream& rInStrm ) +{ + AxBinaryPropertyReader aReader( rInStrm, true ); + aReader.readIntProperty< sal_uInt32 >( mnFlags ); + aReader.readIntProperty< sal_uInt32 >( mnBackColor ); + aReader.readIntProperty< sal_uInt32 >( mnTextColor ); + aReader.readIntProperty< sal_Int32 >( mnMaxLength ); + aReader.readIntProperty< sal_uInt8 >( mnBorderStyle ); + aReader.readIntProperty< sal_uInt8 >( mnScrollBars ); + aReader.readIntProperty< sal_uInt8 >( mnDisplayStyle ); + aReader.skipIntProperty< sal_uInt8 >(); // mouse pointer + aReader.readPairProperty( maSize ); + aReader.readIntProperty< sal_uInt16 >( mnPasswordChar ); + aReader.skipIntProperty< sal_uInt32 >(); // list width + aReader.skipIntProperty< sal_uInt16 >(); // bound column + aReader.skipIntProperty< sal_Int16 >(); // text column + aReader.skipIntProperty< sal_Int16 >(); // column count + aReader.readIntProperty< sal_uInt16 >( mnListRows ); + aReader.skipIntProperty< sal_uInt16 >(); // column info count + aReader.readIntProperty< sal_uInt8 >( mnMatchEntry ); + aReader.skipIntProperty< sal_uInt8 >(); // list style + aReader.readIntProperty< sal_uInt8 >( mnShowDropButton ); + aReader.skipUndefinedProperty(); + aReader.skipIntProperty< sal_uInt8 >(); // drop down style + aReader.readIntProperty< sal_uInt8 >( mnMultiSelect ); + aReader.readStringProperty( maValue ); + aReader.readStringProperty( maCaption ); + aReader.readIntProperty< sal_uInt32 >( mnPicturePos ); + aReader.readIntProperty< sal_uInt32 >( mnBorderColor ); + aReader.readIntProperty< sal_uInt32 >( mnSpecialEffect ); + aReader.skipPictureProperty(); // mouse icon + aReader.readPictureProperty( maPictureData ); + aReader.skipIntProperty< sal_uInt16 >(); // accelerator + aReader.skipUndefinedProperty(); + aReader.skipBoolProperty(); + aReader.readStringProperty( maGroupName ); + return aReader.finalizeImport() && AxFontDataModel::importBinaryModel( rInStrm ); +} + +void AxMorphDataModelBase::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Enabled, getFlag( mnFlags, AX_FLAGS_ENABLED ) ); + rConv.convertColor( rPropMap, PROP_TextColor, mnTextColor ); + AxFontDataModel::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxToggleButtonModel::AxToggleButtonModel() +{ +} + +ApiControlType AxToggleButtonModel::getControlType() const +{ + OSL_ENSURE( mnDisplayStyle == AX_DISPLAYSTYLE_TOGGLE, "AxToggleButtonModel::getControlType - invalid control type" ); + return API_CONTROL_BUTTON; +} + +void AxToggleButtonModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Label, maCaption ); + rPropMap.setProperty( PROP_MultiLine, getFlag( mnFlags, AX_FLAGS_WORDWRAP ) ); + rPropMap.setProperty( PROP_VerticalAlign, ::com::sun::star::style::VerticalAlignment_MIDDLE ); + rPropMap.setProperty( PROP_Toggle, true ); + rConv.convertAxBackground( rPropMap, mnBackColor, mnFlags, API_TRANSPARENCY_NOTSUPPORTED ); + rConv.convertAxPicture( rPropMap, maPictureData, mnPicturePos ); + rConv.convertAxState( rPropMap, maValue, mnMultiSelect, API_DEFAULTSTATE_BOOLEAN, mbAwtModel ); + AxMorphDataModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxCheckBoxModel::AxCheckBoxModel() +{ +} + +ApiControlType AxCheckBoxModel::getControlType() const +{ + OSL_ENSURE( mnDisplayStyle == AX_DISPLAYSTYLE_CHECKBOX, "AxCheckBoxModel::getControlType - invalid control type" ); + return API_CONTROL_CHECKBOX; +} + +void AxCheckBoxModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Label, maCaption ); + rPropMap.setProperty( PROP_MultiLine, getFlag( mnFlags, AX_FLAGS_WORDWRAP ) ); + rPropMap.setProperty( PROP_VerticalAlign, ::com::sun::star::style::VerticalAlignment_MIDDLE ); + rConv.convertAxBackground( rPropMap, mnBackColor, mnFlags, API_TRANSPARENCY_VOID ); + rConv.convertAxVisualEffect( rPropMap, mnSpecialEffect ); + rConv.convertAxPicture( rPropMap, maPictureData, mnPicturePos ); + rConv.convertAxState( rPropMap, maValue, mnMultiSelect, API_DEFAULTSTATE_TRISTATE, mbAwtModel ); + AxMorphDataModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxOptionButtonModel::AxOptionButtonModel() +{ +} + +ApiControlType AxOptionButtonModel::getControlType() const +{ + OSL_ENSURE( mnDisplayStyle == AX_DISPLAYSTYLE_OPTBUTTON, "AxOptionButtonModel::getControlType - invalid control type" ); + return API_CONTROL_RADIOBUTTON; +} + +void AxOptionButtonModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Label, maCaption ); + rPropMap.setProperty( PROP_MultiLine, getFlag( mnFlags, AX_FLAGS_WORDWRAP ) ); + rPropMap.setProperty( PROP_VerticalAlign, ::com::sun::star::style::VerticalAlignment_MIDDLE ); + rConv.convertAxBackground( rPropMap, mnBackColor, mnFlags, API_TRANSPARENCY_VOID ); + rConv.convertAxVisualEffect( rPropMap, mnSpecialEffect ); + rConv.convertAxPicture( rPropMap, maPictureData, mnPicturePos ); + rConv.convertAxState( rPropMap, maValue, mnMultiSelect, API_DEFAULTSTATE_SHORT, mbAwtModel ); + AxMorphDataModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxTextBoxModel::AxTextBoxModel() +{ +} + +ApiControlType AxTextBoxModel::getControlType() const +{ + OSL_ENSURE( mnDisplayStyle == AX_DISPLAYSTYLE_TEXT, "AxTextBoxModel::getControlType - invalid control type" ); + return API_CONTROL_EDIT; +} + +void AxTextBoxModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_MultiLine, getFlag( mnFlags, AX_FLAGS_MULTILINE ) ); + rPropMap.setProperty( PROP_HideInactiveSelection, getFlag( mnFlags, AX_FLAGS_HIDESELECTION ) ); + rPropMap.setProperty( mbAwtModel ? PROP_Text : PROP_DefaultText, maValue ); + rPropMap.setProperty( PROP_MaxTextLen, getLimitedValue< sal_Int16, sal_Int32 >( mnMaxLength, 0, SAL_MAX_INT16 ) ); + if( (0 < mnPasswordChar) && (mnPasswordChar <= SAL_MAX_INT16) ) + rPropMap.setProperty( PROP_EchoChar, static_cast< sal_Int16 >( mnPasswordChar ) ); + rPropMap.setProperty( PROP_HScroll, getFlag( mnScrollBars, AX_SCROLLBAR_HORIZONTAL ) ); + rPropMap.setProperty( PROP_VScroll, getFlag( mnScrollBars, AX_SCROLLBAR_VERTICAL ) ); + rConv.convertAxBackground( rPropMap, mnBackColor, mnFlags, API_TRANSPARENCY_VOID ); + rConv.convertAxBorder( rPropMap, mnBorderColor, mnBorderStyle, mnSpecialEffect ); + AxMorphDataModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxListBoxModel::AxListBoxModel() +{ +} + +ApiControlType AxListBoxModel::getControlType() const +{ + OSL_ENSURE( mnDisplayStyle == AX_DISPLAYSTYLE_LISTBOX, "AxListBoxModel::getControlType - invalid control type" ); + return API_CONTROL_LISTBOX; +} + +void AxListBoxModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + bool bMultiSelect = (mnMultiSelect == AX_SELCTION_MULTI) || (mnMultiSelect == AX_SELCTION_EXTENDED); + rPropMap.setProperty( PROP_MultiSelection, bMultiSelect ); + rPropMap.setProperty( PROP_Dropdown, false ); + rConv.convertAxBackground( rPropMap, mnBackColor, mnFlags, API_TRANSPARENCY_VOID ); + rConv.convertAxBorder( rPropMap, mnBorderColor, mnBorderStyle, mnSpecialEffect ); + AxMorphDataModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxComboBoxModel::AxComboBoxModel() +{ +} + +ApiControlType AxComboBoxModel::getControlType() const +{ + OSL_ENSURE( (mnDisplayStyle == AX_DISPLAYSTYLE_COMBOBOX) || (mnDisplayStyle == AX_DISPLAYSTYLE_DROPDOWN), "AxComboBoxModel::getControlType - invalid control type" ); + return (mnDisplayStyle == AX_DISPLAYSTYLE_DROPDOWN) ? API_CONTROL_LISTBOX : API_CONTROL_COMBOBOX; +} + +void AxComboBoxModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + if( mnDisplayStyle != AX_DISPLAYSTYLE_DROPDOWN ) + { + rPropMap.setProperty( PROP_HideInactiveSelection, getFlag( mnFlags, AX_FLAGS_HIDESELECTION ) ); + rPropMap.setProperty( mbAwtModel ? PROP_Text : PROP_DefaultText, maValue ); + rPropMap.setProperty( PROP_MaxTextLen, getLimitedValue< sal_Int16, sal_Int32 >( mnMaxLength, 0, SAL_MAX_INT16 ) ); + bool bAutoComplete = (mnMatchEntry == AX_MATCHENTRY_FIRSTLETTER) || (mnMatchEntry == AX_MATCHENTRY_COMPLETE); + rPropMap.setProperty( PROP_Autocomplete, bAutoComplete ); + } + bool bShowDropdown = (mnShowDropButton == AX_SHOWDROPBUTTON_FOCUS) || (mnShowDropButton == AX_SHOWDROPBUTTON_ALWAYS); + rPropMap.setProperty( PROP_Dropdown, bShowDropdown ); + rPropMap.setProperty( PROP_LineCount, getLimitedValue< sal_Int16, sal_Int32 >( mnListRows, 1, SAL_MAX_INT16 ) ); + rConv.convertAxBackground( rPropMap, mnBackColor, mnFlags, API_TRANSPARENCY_VOID ); + rConv.convertAxBorder( rPropMap, mnBorderColor, mnBorderStyle, mnSpecialEffect ); + AxMorphDataModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxSpinButtonModel::AxSpinButtonModel() : + mnArrowColor( AX_SYSCOLOR_BUTTONTEXT ), + mnBackColor( AX_SYSCOLOR_BUTTONFACE ), + mnFlags( AX_SPINBUTTON_DEFFLAGS ), + mnOrientation( AX_ORIENTATION_AUTO ), + mnMin( 0 ), + mnMax( 100 ), + mnPosition( 0 ), + mnSmallChange( 1 ), + mnDelay( 50 ) +{ +} + +ApiControlType AxSpinButtonModel::getControlType() const +{ + return API_CONTROL_SPINBUTTON; +} + +void AxSpinButtonModel::importProperty( sal_Int32 nPropId, const OUString& rValue ) +{ + switch( nPropId ) + { + case XML_ForeColor: mnArrowColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_BackColor: mnBackColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_VariousPropertyBits: mnFlags = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_Orientation: mnOrientation = AttributeConversion::decodeInteger( rValue ); break; + case XML_Min: mnMin = AttributeConversion::decodeInteger( rValue ); break; + case XML_Max: mnMax = AttributeConversion::decodeInteger( rValue ); break; + case XML_Position: mnPosition = AttributeConversion::decodeInteger( rValue ); break; + case XML_SmallChange: mnSmallChange = AttributeConversion::decodeInteger( rValue ); break; + case XML_Delay: mnDelay = AttributeConversion::decodeInteger( rValue ); break; + default: AxControlModelBase::importProperty( nPropId, rValue ); + } +} + +bool AxSpinButtonModel::importBinaryModel( BinaryInputStream& rInStrm ) +{ + AxBinaryPropertyReader aReader( rInStrm ); + aReader.readIntProperty< sal_uInt32 >( mnArrowColor ); + aReader.readIntProperty< sal_uInt32 >( mnBackColor ); + aReader.readIntProperty< sal_uInt32 >( mnFlags ); + aReader.readPairProperty( maSize ); + aReader.skipIntProperty< sal_uInt32 >(); // unused + aReader.readIntProperty< sal_Int32 >( mnMin ); + aReader.readIntProperty< sal_Int32 >( mnMax ); + aReader.readIntProperty< sal_Int32 >( mnPosition ); + aReader.skipIntProperty< sal_uInt32 >(); // prev enabled + aReader.skipIntProperty< sal_uInt32 >(); // next enabled + aReader.readIntProperty< sal_Int32 >( mnSmallChange ); + aReader.readIntProperty< sal_Int32 >( mnOrientation ); + aReader.readIntProperty< sal_Int32 >( mnDelay ); + aReader.skipPictureProperty(); // mouse icon + aReader.skipIntProperty< sal_uInt8 >(); // mouse pointer + return aReader.finalizeImport(); +} + +void AxSpinButtonModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + sal_Int32 nMin = ::std::min( mnMin, mnMax ); + sal_Int32 nMax = ::std::max( mnMin, mnMax ); + rPropMap.setProperty( PROP_Enabled, getFlag( mnFlags, AX_FLAGS_ENABLED ) ); + rPropMap.setProperty( PROP_SpinValueMin, nMin ); + rPropMap.setProperty( PROP_SpinValueMax, nMax ); + rPropMap.setProperty( PROP_SpinIncrement, mnSmallChange ); + rPropMap.setProperty( mbAwtModel ? PROP_SpinValue : PROP_DefaultSpinValue, mnPosition ); + rPropMap.setProperty( PROP_Repeat, true ); + rPropMap.setProperty( PROP_RepeatDelay, mnDelay ); + rPropMap.setProperty( PROP_Border, API_BORDER_NONE ); + rConv.convertColor( rPropMap, PROP_SymbolColor, mnArrowColor ); + rConv.convertAxBackground( rPropMap, mnBackColor, mnFlags, API_TRANSPARENCY_NOTSUPPORTED ); + rConv.convertAxOrientation( rPropMap, maSize, mnOrientation ); + AxControlModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxScrollBarModel::AxScrollBarModel() : + mnArrowColor( AX_SYSCOLOR_BUTTONTEXT ), + mnBackColor( AX_SYSCOLOR_BUTTONFACE ), + mnFlags( AX_SCROLLBAR_DEFFLAGS ), + mnOrientation( AX_ORIENTATION_AUTO ), + mnPropThumb( AX_PROPTHUMB_ON ), + mnMin( 0 ), + mnMax( 32767 ), + mnPosition( 0 ), + mnSmallChange( 1 ), + mnLargeChange( 1 ), + mnDelay( 50 ) +{ +} + +ApiControlType AxScrollBarModel::getControlType() const +{ + return API_CONTROL_SCROLLBAR; +} + +void AxScrollBarModel::importProperty( sal_Int32 nPropId, const OUString& rValue ) +{ + switch( nPropId ) + { + case XML_ForeColor: mnArrowColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_BackColor: mnBackColor = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_VariousPropertyBits: mnFlags = AttributeConversion::decodeUnsigned( rValue ); break; + case XML_Orientation: mnOrientation = AttributeConversion::decodeInteger( rValue ); break; + case XML_ProportionalThumb: mnPropThumb = AttributeConversion::decodeInteger( rValue ); break; + case XML_Min: mnMin = AttributeConversion::decodeInteger( rValue ); break; + case XML_Max: mnMax = AttributeConversion::decodeInteger( rValue ); break; + case XML_Position: mnPosition = AttributeConversion::decodeInteger( rValue ); break; + case XML_SmallChange: mnSmallChange = AttributeConversion::decodeInteger( rValue ); break; + case XML_LargeChange: mnLargeChange = AttributeConversion::decodeInteger( rValue ); break; + case XML_Delay: mnDelay = AttributeConversion::decodeInteger( rValue ); break; + default: AxControlModelBase::importProperty( nPropId, rValue ); + } +} + +bool AxScrollBarModel::importBinaryModel( BinaryInputStream& rInStrm ) +{ + AxBinaryPropertyReader aReader( rInStrm ); + aReader.readIntProperty< sal_uInt32 >( mnArrowColor ); + aReader.readIntProperty< sal_uInt32 >( mnBackColor ); + aReader.readIntProperty< sal_uInt32 >( mnFlags ); + aReader.readPairProperty( maSize ); + aReader.skipIntProperty< sal_uInt8 >(); // mouse pointer + aReader.readIntProperty< sal_Int32 >( mnMin ); + aReader.readIntProperty< sal_Int32 >( mnMax ); + aReader.readIntProperty< sal_Int32 >( mnPosition ); + aReader.skipIntProperty< sal_uInt32 >(); // unused + aReader.skipIntProperty< sal_uInt32 >(); // prev enabled + aReader.skipIntProperty< sal_uInt32 >(); // next enabled + aReader.readIntProperty< sal_Int32 >( mnSmallChange ); + aReader.readIntProperty< sal_Int32 >( mnLargeChange ); + aReader.readIntProperty< sal_Int32 >( mnOrientation ); + aReader.readIntProperty< sal_Int16 >( mnPropThumb ); + aReader.readIntProperty< sal_Int32 >( mnDelay ); + aReader.skipPictureProperty(); // mouse icon + return aReader.finalizeImport(); +} + +void AxScrollBarModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Enabled, getFlag( mnFlags, AX_FLAGS_ENABLED ) ); + rPropMap.setProperty( PROP_RepeatDelay, mnDelay ); + rPropMap.setProperty( PROP_Border, API_BORDER_NONE ); + if( (mnPropThumb == AX_PROPTHUMB_ON) && (mnMin != mnMax) && (mnLargeChange > 0) ) + { + // use double to prevent integer overflow in division (fInterval+mnLargeChange may become 0 when performed as int) + double fInterval = fabs( static_cast< double >( mnMax - mnMin ) ); + sal_Int32 nThumbLen = getLimitedValue< sal_Int32, double >( (fInterval * mnLargeChange) / (fInterval + mnLargeChange), 1, SAL_MAX_INT32 ); + rPropMap.setProperty( PROP_VisibleSize, nThumbLen ); + } + rConv.convertColor( rPropMap, PROP_SymbolColor, mnArrowColor ); + rConv.convertAxBackground( rPropMap, mnBackColor, mnFlags, API_TRANSPARENCY_NOTSUPPORTED ); + rConv.convertAxOrientation( rPropMap, maSize, mnOrientation ); + rConv.convertScrollBar( rPropMap, mnMin, mnMax, mnPosition, mnSmallChange, mnLargeChange, mbAwtModel ); + AxControlModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxTabStripModel::AxTabStripModel() : + AxFontDataModel( false ), // no support for Align property + mnBackColor( AX_SYSCOLOR_BUTTONFACE ), + mnTextColor( AX_SYSCOLOR_BUTTONTEXT ), + mnFlags( AX_TABSTRIP_DEFFLAGS ), + mnSelectedTab( -1 ), + mnTabStyle( AX_TABSTRIP_TABS ), + mnTabFlagCount( 0 ) +{ +} + +bool AxTabStripModel::importBinaryModel( BinaryInputStream& rInStrm ) +{ + AxBinaryPropertyReader aReader( rInStrm ); + aReader.readIntProperty< sal_Int32 >( mnSelectedTab ); + aReader.readIntProperty< sal_uInt32 >( mnBackColor ); + aReader.readIntProperty< sal_uInt32 >( mnTextColor ); + aReader.skipUndefinedProperty(); + aReader.readPairProperty( maSize ); + aReader.readStringArrayProperty( maCaptions ); + aReader.skipIntProperty< sal_uInt8 >(); // mouse pointer + aReader.skipUndefinedProperty(); + aReader.skipIntProperty< sal_uInt32 >(); // tab orientation + aReader.readIntProperty< sal_uInt32 >( mnTabStyle ); + aReader.skipBoolProperty(); // multiple rows + aReader.skipIntProperty< sal_uInt32 >(); // fixed width + aReader.skipIntProperty< sal_uInt32 >(); // fixed height + aReader.skipBoolProperty(); // tooltips + aReader.skipUndefinedProperty(); + aReader.skipStringArrayProperty(); // tooltip strings + aReader.skipUndefinedProperty(); + aReader.skipStringArrayProperty(); // tab names + aReader.readIntProperty< sal_uInt32 >( mnFlags ); + aReader.skipBoolProperty(); // new version + aReader.skipIntProperty< sal_uInt32 >(); // tabs allocated + aReader.skipStringArrayProperty(); // tags + aReader.readIntProperty< sal_uInt32 >( mnTabFlagCount ); + aReader.skipStringArrayProperty(); // accelerators + aReader.skipPictureProperty(); // mouse icon + return aReader.finalizeImport() && AxFontDataModel::importBinaryModel( rInStrm ); +} + +ApiControlType AxTabStripModel::getControlType() const +{ + return API_CONTROL_TABSTRIP; +} + +void AxTabStripModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Decoration, mnTabStyle != AX_TABSTRIP_NONE ); + rPropMap.setProperty( PROP_MultiPageValue, mnSelectedTab ); + rConv.convertColor( rPropMap, PROP_BackgroundColor, mnBackColor ); + AxFontDataModel::convertProperties( rPropMap, rConv ); +} + +OUString AxTabStripModel::getCaption( sal_Int32 nIndex ) const +{ + return ContainerHelper::getVectorElement( maCaptions, nIndex, OUString() ); +} + +// ============================================================================ + +AxContainerModelBase::AxContainerModelBase( bool bFontSupport ) : + AxFontDataModel( false ), // no support for Align property + maLogicalSize( AX_CONTAINER_DEFWIDTH, AX_CONTAINER_DEFHEIGHT ), + maScrollPos( 0, 0 ), + mnBackColor( AX_SYSCOLOR_BUTTONFACE ), + mnTextColor( AX_SYSCOLOR_BUTTONTEXT ), + mnFlags( AX_CONTAINER_DEFFLAGS ), + mnBorderColor( AX_SYSCOLOR_BUTTONTEXT ), + mnBorderStyle( AX_BORDERSTYLE_NONE ), + mnScrollBars( AX_CONTAINER_SCR_NONE ), + mnCycleType( AX_CONTAINER_CYCLEALL ), + mnSpecialEffect( AX_SPECIALEFFECT_FLAT ), + mnPicAlign( AX_PICALIGN_CENTER ), + mnPicSizeMode( AX_PICSIZE_CLIP ), + mbPicTiling( false ), + mbFontSupport( bFontSupport ) +{ + setAwtModelMode(); + // different default size for frame + maSize = AxPairData( AX_CONTAINER_DEFWIDTH, AX_CONTAINER_DEFHEIGHT ); +} + +void AxContainerModelBase::importProperty( sal_Int32 nPropId, const OUString& rValue ) +{ + if( nPropId == XML_Caption ) + maCaption = rValue; +} + +bool AxContainerModelBase::importBinaryModel( BinaryInputStream& rInStrm ) +{ + AxBinaryPropertyReader aReader( rInStrm ); + aReader.skipUndefinedProperty(); + aReader.readIntProperty< sal_uInt32 >( mnBackColor ); + aReader.readIntProperty< sal_uInt32 >( mnTextColor ); + aReader.skipIntProperty< sal_uInt32 >(); // next availbale control ID + aReader.skipUndefinedProperty(); + aReader.skipUndefinedProperty(); + aReader.readIntProperty< sal_uInt32 >( mnFlags ); + aReader.readIntProperty< sal_uInt8 >( mnBorderStyle ); + aReader.skipIntProperty< sal_uInt8 >(); // mouse pointer + aReader.readIntProperty< sal_uInt8 >( mnScrollBars ); + aReader.readPairProperty( maSize ); + aReader.readPairProperty( maLogicalSize ); + aReader.readPairProperty( maScrollPos ); + aReader.skipIntProperty< sal_uInt32 >(); // number of control groups + aReader.skipUndefinedProperty(); + aReader.skipPictureProperty(); // mouse icon + aReader.readIntProperty< sal_uInt8 >( mnCycleType ); + aReader.readIntProperty< sal_uInt8 >( mnSpecialEffect ); + aReader.readIntProperty< sal_uInt32 >( mnBorderColor ); + aReader.readStringProperty( maCaption ); + aReader.readFontProperty( maFontData ); + aReader.readPictureProperty( maPictureData ); + aReader.skipIntProperty< sal_Int32 >(); // zoom + aReader.readIntProperty< sal_uInt8 >( mnPicAlign ); + aReader.readBoolProperty( mbPicTiling ); + aReader.readIntProperty< sal_uInt8 >( mnPicSizeMode ); + aReader.skipIntProperty< sal_uInt32 >(); // shape cookie + aReader.skipIntProperty< sal_uInt32 >(); // draw buffer size + return aReader.finalizeImport(); +} + +void AxContainerModelBase::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + if( mbFontSupport ) + { + rConv.convertColor( rPropMap, PROP_TextColor, mnTextColor ); + AxFontDataModel::convertProperties( rPropMap, rConv ); + } +} + +bool AxContainerModelBase::importClassTable( BinaryInputStream& rInStrm, AxClassTable& orClassTable ) +{ + bool bValid = true; + orClassTable.clear(); + if( !getFlag( mnFlags, AX_CONTAINER_NOCLASSTABLE ) ) + { + sal_uInt16 nCount = rInStrm.readuInt16(); + for( sal_uInt16 nIndex = 0; bValid && (nIndex < nCount); ++nIndex ) + { + orClassTable.push_back( OUString() ); + AxBinaryPropertyReader aReader( rInStrm ); + aReader.readGuidProperty( orClassTable.back() ); + aReader.skipGuidProperty(); // source interface GUID + aReader.skipUndefinedProperty(); + aReader.skipGuidProperty(); // default interface GUID + aReader.skipIntProperty< sal_uInt32 >(); // class table and var flags + aReader.skipIntProperty< sal_uInt32 >(); // method count + aReader.skipIntProperty< sal_Int32 >(); // IDispatch identifier for linked cell access + aReader.skipIntProperty< sal_uInt16 >(); // get function index for linked cell access + aReader.skipIntProperty< sal_uInt16 >(); // put function index for linked cell access + aReader.skipIntProperty< sal_uInt16 >(); // linked cell access property type + aReader.skipIntProperty< sal_uInt16 >(); // get function index of value + aReader.skipIntProperty< sal_uInt16 >(); // put function index of value + aReader.skipIntProperty< sal_uInt16 >(); // value type + aReader.skipIntProperty< sal_Int32 >(); // IDispatch identifier for source range access + aReader.skipIntProperty< sal_uInt16 >(); // get function index for source range access + bValid = aReader.finalizeImport(); + } + } + return bValid; +} + +// ============================================================================ + +AxFrameModel::AxFrameModel() : + AxContainerModelBase( true ) +{ +} + +ApiControlType AxFrameModel::getControlType() const +{ + return API_CONTROL_GROUPBOX; +} + +void AxFrameModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Label, maCaption ); + rPropMap.setProperty( PROP_Enabled, getFlag( mnFlags, AX_CONTAINER_ENABLED ) ); + AxContainerModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxFormPageModel::AxFormPageModel() +{ +} + +ApiControlType AxFormPageModel::getControlType() const +{ + return API_CONTROL_PAGE; +} + +void AxFormPageModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Title, maCaption ); + rPropMap.setProperty( PROP_Enabled, getFlag( mnFlags, AX_CONTAINER_ENABLED ) ); + rConv.convertColor( rPropMap, PROP_BackgroundColor, mnBackColor ); + AxContainerModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +AxMultiPageModel::AxMultiPageModel() +{ +} + +ApiControlType AxMultiPageModel::getControlType() const +{ + return API_CONTROL_MULTIPAGE; +} + +void AxMultiPageModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Enabled, getFlag( mnFlags, AX_CONTAINER_ENABLED ) ); + if( mxTabStrip.get() ) + mxTabStrip->convertProperties( rPropMap, rConv ); + AxContainerModelBase::convertProperties( rPropMap, rConv ); +} + +void AxMultiPageModel::setTabStripModel( const AxTabStripModelRef& rxTabStrip ) +{ + mxTabStrip = rxTabStrip; +} + +// ============================================================================ + +AxUserFormModel::AxUserFormModel() +{ +} + +ApiControlType AxUserFormModel::getControlType() const +{ + return API_CONTROL_DIALOG; +} + +void AxUserFormModel::convertProperties( PropertyMap& rPropMap, const ControlConverter& rConv ) const +{ + rPropMap.setProperty( PROP_Title, maCaption ); + rConv.convertColor( rPropMap, PROP_BackgroundColor, mnBackColor ); + AxContainerModelBase::convertProperties( rPropMap, rConv ); +} + +// ============================================================================ + +EmbeddedControl::EmbeddedControl( const OUString& rName ) : + maName( rName ) +{ +} + +EmbeddedControl::~EmbeddedControl() +{ +} + +ControlModelRef EmbeddedControl::createModel( const OUString& rClassId ) +{ + OUString aClassId = rClassId.toAsciiUpperCase(); + if( aClassId.equalsAscii( AX_GUID_COMMANDBUTTON ) ) + mxModel.reset( new AxCommandButtonModel ); + else if( aClassId.equalsAscii( AX_GUID_LABEL ) ) + mxModel.reset( new AxLabelModel ); + else if( aClassId.equalsAscii( AX_GUID_IMAGE ) ) + mxModel.reset( new AxImageModel ); + else if( aClassId.equalsAscii( AX_GUID_TOGGLEBUTTON ) ) + mxModel.reset( new AxToggleButtonModel ); + else if( aClassId.equalsAscii( AX_GUID_CHECKBOX ) ) + mxModel.reset( new AxCheckBoxModel ); + else if( aClassId.equalsAscii( AX_GUID_OPTIONBUTTON ) ) + mxModel.reset( new AxOptionButtonModel ); + else if( aClassId.equalsAscii( AX_GUID_TEXTBOX ) ) + mxModel.reset( new AxTextBoxModel ); + else if( aClassId.equalsAscii( AX_GUID_LISTBOX ) ) + mxModel.reset( new AxListBoxModel ); + else if( aClassId.equalsAscii( AX_GUID_COMBOBOX ) ) + mxModel.reset( new AxComboBoxModel ); + else if( aClassId.equalsAscii( AX_GUID_SPINBUTTON ) ) + mxModel.reset( new AxSpinButtonModel ); + else if( aClassId.equalsAscii( AX_GUID_SCROLLBAR ) ) + mxModel.reset( new AxScrollBarModel ); + else if( aClassId.equalsAscii( AX_GUID_FRAME ) ) + mxModel.reset( new AxFrameModel ); + else if( aClassId.equalsAscii( COMCTL_GUID_SCROLLBAR_60 ) ) + mxModel.reset( new ComCtlScrollBarModel( 6 ) ); + else + mxModel.reset(); + + // embedded controls are form component instances + if( mxModel.get() ) + mxModel->setFormComponentMode(); + + return mxModel; +} + +OUString EmbeddedControl::getServiceName() const +{ + return mxModel.get() ? mxModel->getServiceName() : OUString(); +} + +bool EmbeddedControl::convertProperties( const Reference< XControlModel >& rxCtrlModel, const ControlConverter& rConv ) const +{ + if( mxModel.get() && rxCtrlModel.is() && (maName.getLength() > 0) ) + { + PropertyMap aPropMap; + aPropMap.setProperty( PROP_Name, maName ); + mxModel->convertProperties( aPropMap, rConv ); + PropertySet aPropSet( rxCtrlModel ); + aPropSet.setProperties( aPropMap ); + return true; + } + return false; +} + +// ============================================================================ + +EmbeddedForm::EmbeddedForm( const Reference< XMultiServiceFactory >& rxModelFactory, + const Reference< XDrawPage >& rxDrawPage, const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr ) : + ControlConverter( rGraphicHelper, bDefaultColorBgr ), + mxModelFactory( rxModelFactory ), + mxFormsSupp( rxDrawPage, UNO_QUERY ) +{ + OSL_ENSURE( mxModelFactory.is(), "EmbeddedForm::EmbeddedForm - missing service factory" ); +} + +Reference< XControlModel > EmbeddedForm::convertAndInsert( const EmbeddedControl& rControl ) +{ + if( mxModelFactory.is() && rControl.hasModel() ) try + { + // create the UNO control model + OUString aServiceName = rControl.getServiceName(); + Reference< XFormComponent > xFormComp( mxModelFactory->createInstance( aServiceName ), UNO_QUERY_THROW ); + Reference< XControlModel > xCtrlModel( xFormComp, UNO_QUERY_THROW ); + + // insert the control into the form + Reference< XIndexContainer > xFormIC( createForm(), UNO_SET_THROW ); + sal_Int32 nNewIndex = xFormIC->getCount(); + xFormIC->insertByIndex( nNewIndex, Any( xFormComp ) ); + + // convert the control properties + if( rControl.convertProperties( xCtrlModel, *this ) ) + return xCtrlModel; + } + catch( Exception& ) + { + } + return Reference< XControlModel >(); +} + +Reference< XIndexContainer > EmbeddedForm::createForm() +{ + if( mxFormsSupp.is() ) + { + try + { + Reference< XNameContainer > xFormsNC( mxFormsSupp->getForms(), UNO_SET_THROW ); + OUString aFormName = CREATE_OUSTRING( "Standard" ); + if( xFormsNC->hasByName( aFormName ) ) + { + mxFormIC.set( xFormsNC->getByName( aFormName ), UNO_QUERY_THROW ); + } + else if( mxModelFactory.is() ) + { + Reference< XForm > xForm( mxModelFactory->createInstance( CREATE_OUSTRING( "com.sun.star.form.component.Form" ) ), UNO_QUERY_THROW ); + xFormsNC->insertByName( aFormName, Any( xForm ) ); + mxFormIC.set( xForm, UNO_QUERY_THROW ); + } + } + catch( Exception& ) + { + } + // always clear the forms supplier to not try to create the form again + mxFormsSupp.clear(); + } + return mxFormIC; +} + +// ============================================================================ + +} // namespace ole +} // namespace oox diff --git a/oox/source/ole/axcontrolfragment.cxx b/oox/source/ole/axcontrolfragment.cxx new file mode 100644 index 000000000000..ecd782da2cb0 --- /dev/null +++ b/oox/source/ole/axcontrolfragment.cxx @@ -0,0 +1,156 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/ole/axcontrolfragment.hxx" +#include "oox/helper/binaryinputstream.hxx" +#include "oox/helper/binaryoutputstream.hxx" +#include "oox/core/xmlfilterbase.hxx" +#include "oox/ole/axcontrol.hxx" +#include "oox/ole/olehelper.hxx" +#include "oox/ole/olestorage.hxx" + +using ::rtl::OUString; +using ::com::sun::star::io::XInputStream; +using ::com::sun::star::uno::Reference; +using ::oox::core::ContextHandler2; +using ::oox::core::ContextHandlerRef; +using ::oox::core::FragmentHandler2; +using ::oox::core::XmlFilterBase; + +namespace oox { +namespace ole { + +// ============================================================================ + +AxControlPropertyContext::AxControlPropertyContext( FragmentHandler2& rFragment, ControlModelBase& rModel ) : + ContextHandler2( rFragment ), + mrModel( rModel ), + mnPropId( XML_TOKEN_INVALID ) +{ +} + +ContextHandlerRef AxControlPropertyContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case AX_TOKEN( ocx ): + if( nElement == AX_TOKEN( ocxPr ) ) + { + mnPropId = rAttribs.getToken( AX_TOKEN( name ), XML_TOKEN_INVALID ); + switch( mnPropId ) + { + case XML_TOKEN_INVALID: + return 0; + case XML_Picture: + case XML_MouseIcon: + return this; // import picture path from ax:picture child element + default: + mrModel.importProperty( mnPropId, rAttribs.getString( AX_TOKEN( value ), OUString() ) ); + } + } + break; + + case AX_TOKEN( ocxPr ): + if( nElement == AX_TOKEN( picture ) ) + { + OUString aPicturePath = getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ); + if( aPicturePath.getLength() > 0 ) + { + BinaryXInputStream aInStrm( getFilter().openInputStream( aPicturePath ), true ); + mrModel.importPictureData( mnPropId, aInStrm ); + } + } + break; + } + return 0; +} + +// ============================================================================ + +AxControlFragment::AxControlFragment( XmlFilterBase& rFilter, const OUString& rFragmentPath, EmbeddedControl& rControl ) : + FragmentHandler2( rFilter, rFragmentPath, true ), + mrControl( rControl ) +{ +} + +ContextHandlerRef AxControlFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + if( isRootElement() && (nElement == AX_TOKEN( ocx )) ) + { + OUString aClassId = rAttribs.getString( AX_TOKEN( classid ), OUString() ); + switch( rAttribs.getToken( AX_TOKEN( persistence ), XML_TOKEN_INVALID ) ) + { + case XML_persistPropertyBag: + if( ControlModelBase* pModel = mrControl.createModel( aClassId ).get() ) + return new AxControlPropertyContext( *this, *pModel ); + break; + + case XML_persistStreamInit: + { + OUString aFragmentPath = getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ); + if( aFragmentPath.getLength() > 0 ) + { + BinaryXInputStream aInStrm( getFilter().openInputStream( aFragmentPath ), true ); + if( !aInStrm.isEof() ) + { + // binary stream contains a copy of the class ID, must be equal to attribute value + OUString aStrmClassId = OleHelper::importGuid( aInStrm ); + OSL_ENSURE( aClassId.equalsIgnoreAsciiCase( aStrmClassId ), + "AxControlFragment::importBinaryControl - form control class ID mismatch" ); + if( ControlModelBase* pModel = mrControl.createModel( aStrmClassId ).get() ) + pModel->importBinaryModel( aInStrm ); + } + } + } + break; + + case XML_persistStorage: + { + OUString aFragmentPath = getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ); + if( aFragmentPath.getLength() > 0 ) + { + Reference< XInputStream > xStrgStrm = getFilter().openInputStream( aFragmentPath ); + if( xStrgStrm.is() ) + { + OleStorage aStorage( getFilter().getGlobalFactory(), xStrgStrm, false ); + BinaryXInputStream aInStrm( aStorage.openInputStream( CREATE_OUSTRING( "f" ) ), true ); + if( !aInStrm.isEof() ) + if( AxContainerModelBase* pModel = dynamic_cast< AxContainerModelBase* >( mrControl.createModel( aClassId ).get() ) ) + pModel->importBinaryModel( aInStrm ); + } + } + } + break; + } + } + return 0; +} + +// ============================================================================ + +} // namespace ole +} // namespace oox diff --git a/oox/source/ole/makefile.mk b/oox/source/ole/makefile.mk new file mode 100644 index 000000000000..4e01392d4a57 --- /dev/null +++ b/oox/source/ole/makefile.mk @@ -0,0 +1,59 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=oox +TARGET=ole +AUTOSEG=true + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE: $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/axbinaryreader.obj \ + $(SLO)$/axcontrol.obj \ + $(SLO)$/axcontrolfragment.obj \ + $(SLO)$/olehelper.obj \ + $(SLO)$/oleobjecthelper.obj \ + $(SLO)$/olestorage.obj \ + $(SLO)$/vbacontrol.obj \ + $(SLO)$/vbahelper.obj \ + $(SLO)$/vbainputstream.obj \ + $(SLO)$/vbamodule.obj \ + $(SLO)$/vbaproject.obj + +# --- Targets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/oox/source/ole/olehelper.cxx b/oox/source/ole/olehelper.cxx new file mode 100644 index 000000000000..0a0796e15a7e --- /dev/null +++ b/oox/source/ole/olehelper.cxx @@ -0,0 +1,300 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/ole/olehelper.hxx" +#include <rtl/ustrbuf.hxx> +#include "tokens.hxx" +#include "oox/helper/binaryinputstream.hxx" +#include "oox/helper/graphichelper.hxx" + +using ::rtl::OUString; +using ::rtl::OUStringBuffer; + +namespace oox { +namespace ole { + +// ============================================================================ + +namespace { + +const sal_uInt32 OLE_COLORTYPE_MASK = 0xFF000000; +const sal_uInt32 OLE_COLORTYPE_CLIENT = 0x00000000; +const sal_uInt32 OLE_COLORTYPE_PALETTE = 0x01000000; +const sal_uInt32 OLE_COLORTYPE_BGR = 0x02000000; +const sal_uInt32 OLE_COLORTYPE_SYSCOLOR = 0x80000000; + +const sal_uInt32 OLE_PALETTECOLOR_MASK = 0x0000FFFF; +const sal_uInt32 OLE_BGRCOLOR_MASK = 0x00FFFFFF; +const sal_uInt32 OLE_SYSTEMCOLOR_MASK = 0x0000FFFF; + +/** Returns the UNO RGB color from the passed encoded OLE BGR color. */ +inline sal_Int32 lclDecodeBgrColor( sal_uInt32 nOleColor ) +{ + return static_cast< sal_Int32 >( ((nOleColor & 0x0000FF) << 16) | (nOleColor & 0x00FF00) | ((nOleColor & 0xFF0000) >> 16) ); +} + +// ---------------------------------------------------------------------------- + +const sal_Char* const OLE_GUID_URLMONIKER = "{79EAC9E0-BAF9-11CE-8C82-00AA004BA90B}"; +const sal_Char* const OLE_GUID_FILEMONIKER = "{00000303-0000-0000-C000-000000000046}"; + +const sal_uInt32 OLE_STDPIC_ID = 0x0000746C; + +const sal_uInt32 OLE_STDHLINK_VERSION = 2; +const sal_uInt32 OLE_STDHLINK_HASTARGET = 0x00000001; /// Has hyperlink moniker. +const sal_uInt32 OLE_STDHLINK_ABSOLUTE = 0x00000002; /// Absolute path. +const sal_uInt32 OLE_STDHLINK_HASLOCATION = 0x00000008; /// Has target location. +const sal_uInt32 OLE_STDHLINK_HASDISPLAY = 0x00000010; /// Has display string. +const sal_uInt32 OLE_STDHLINK_HASGUID = 0x00000020; /// Has identification GUID. +const sal_uInt32 OLE_STDHLINK_HASTIME = 0x00000040; /// Has creation time. +const sal_uInt32 OLE_STDHLINK_HASFRAME = 0x00000080; /// Has frame. +const sal_uInt32 OLE_STDHLINK_ASSTRING = 0x00000100; /// Hyperlink as simple string. + +// ---------------------------------------------------------------------------- + +template< typename Type > +void lclAppendHex( OUStringBuffer& orBuffer, Type nValue ) +{ + const sal_Int32 nWidth = 2 * sizeof( Type ); + static const sal_Unicode spcHexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + orBuffer.setLength( orBuffer.getLength() + nWidth ); + for( sal_Int32 nCharIdx = orBuffer.getLength() - 1, nCharEnd = nCharIdx - nWidth; nCharIdx > nCharEnd; --nCharIdx, nValue >>= 4 ) + orBuffer.setCharAt( nCharIdx, spcHexChars[ nValue & 0xF ] ); +} + +OUString lclReadStdHlinkString( BinaryInputStream& rInStrm, bool bUnicode ) +{ + OUString aRet; + sal_Int32 nChars = rInStrm.readInt32(); + if( nChars > 0 ) + { + sal_Int32 nReadChars = getLimitedValue< sal_Int32, sal_Int32 >( nChars, 0, SAL_MAX_UINT16 ); + // byte strings are always in ANSI (Windows 1252) encoding + aRet = bUnicode ? rInStrm.readUnicodeArray( nReadChars, true ) : rInStrm.readCharArrayUC( nReadChars, RTL_TEXTENCODING_MS_1252, true ); + // strings are NUL terminated, remove trailing NUL and possible other garbage + sal_Int32 nNulPos = aRet.indexOf( '\0' ); + if( nNulPos >= 0 ) + aRet = aRet.copy( 0, nNulPos ); + // skip remaining chars + rInStrm.skip( (bUnicode ? 2 : 1) * (nChars - nReadChars) ); + } + return aRet; +} + +} // namespace + +// ============================================================================ + +StdFontInfo::StdFontInfo() : + mnHeight( 0 ), + mnWeight( OLE_STDFONT_NORMAL ), + mnCharSet( WINDOWS_CHARSET_ANSI ), + mnFlags( 0 ) +{ +} + +StdFontInfo::StdFontInfo( const ::rtl::OUString& rName, sal_uInt32 nHeight, + sal_uInt16 nWeight, sal_uInt16 nCharSet, sal_uInt8 nFlags ) : + maName( rName ), + mnHeight( nHeight ), + mnWeight( nWeight ), + mnCharSet( nCharSet ), + mnFlags( nFlags ) +{ +} + +// ============================================================================ + +/*static*/ sal_Int32 OleHelper::decodeOleColor( + const GraphicHelper& rGraphicHelper, sal_uInt32 nOleColor, bool bDefaultColorBgr ) +{ + static const sal_Int32 spnSystemColors[] = + { + XML_scrollBar, XML_background, XML_activeCaption, XML_inactiveCaption, + XML_menu, XML_window, XML_windowFrame, XML_menuText, + XML_windowText, XML_captionText, XML_activeBorder, XML_inactiveBorder, + XML_appWorkspace, XML_highlight, XML_highlightText, XML_btnFace, + XML_btnShadow, XML_grayText, XML_btnText, XML_inactiveCaptionText, + XML_btnHighlight, XML_3dDkShadow, XML_3dLight, XML_infoText, + XML_infoBk + }; + + switch( nOleColor & OLE_COLORTYPE_MASK ) + { + case OLE_COLORTYPE_CLIENT: + return bDefaultColorBgr ? lclDecodeBgrColor( nOleColor ) : rGraphicHelper.getPaletteColor( nOleColor & OLE_PALETTECOLOR_MASK ); + + case OLE_COLORTYPE_PALETTE: + return rGraphicHelper.getPaletteColor( nOleColor & OLE_PALETTECOLOR_MASK ); + + case OLE_COLORTYPE_BGR: + return lclDecodeBgrColor( nOleColor ); + + case OLE_COLORTYPE_SYSCOLOR: + return rGraphicHelper.getSystemColor( STATIC_ARRAY_SELECT( spnSystemColors, nOleColor & OLE_SYSTEMCOLOR_MASK, XML_TOKEN_INVALID ), API_RGB_WHITE ); + } + OSL_ENSURE( false, "OleHelper::decodeOleColor - unknown color type" ); + return API_RGB_BLACK; +} + +/*static*/ OUString OleHelper::importGuid( BinaryInputStream& rInStrm ) +{ + OUStringBuffer aBuffer; + aBuffer.append( sal_Unicode( '{' ) ); + lclAppendHex( aBuffer, rInStrm.readuInt32() ); + aBuffer.append( sal_Unicode( '-' ) ); + lclAppendHex( aBuffer, rInStrm.readuInt16() ); + aBuffer.append( sal_Unicode( '-' ) ); + lclAppendHex( aBuffer, rInStrm.readuInt16() ); + aBuffer.append( sal_Unicode( '-' ) ); + lclAppendHex( aBuffer, rInStrm.readuInt8() ); + lclAppendHex( aBuffer, rInStrm.readuInt8() ); + aBuffer.append( sal_Unicode( '-' ) ); + for( int nIndex = 0; nIndex < 6; ++nIndex ) + lclAppendHex( aBuffer, rInStrm.readuInt8() ); + aBuffer.append( sal_Unicode( '}' ) ); + return aBuffer.makeStringAndClear(); +} + +/*static*/ bool OleHelper::importStdFont( StdFontInfo& orFontInfo, BinaryInputStream& rInStrm, bool bWithGuid ) +{ + if( bWithGuid ) + { + bool bIsStdFont = importGuid( rInStrm ).equalsAscii( OLE_GUID_STDFONT ); + OSL_ENSURE( bIsStdFont, "OleHelper::importStdFont - unexpected header GUID, expected StdFont" ); + if( !bIsStdFont ) + return false; + } + + sal_uInt8 nVersion, nNameLen; + rInStrm >> nVersion >> orFontInfo.mnCharSet >> orFontInfo.mnFlags >> orFontInfo.mnWeight >> orFontInfo.mnHeight >> nNameLen; + // according to spec the name is ASCII + orFontInfo.maName = rInStrm.readCharArrayUC( nNameLen, RTL_TEXTENCODING_ASCII_US ); + OSL_ENSURE( nVersion <= 1, "OleHelper::importStdFont - wrong version" ); + return !rInStrm.isEof() && (nVersion <= 1); +} + +/*static*/ bool OleHelper::importStdPic( StreamDataSequence& orGraphicData, BinaryInputStream& rInStrm, bool bWithGuid ) +{ + if( bWithGuid ) + { + bool bIsStdPic = importGuid( rInStrm ).equalsAscii( OLE_GUID_STDPIC ); + OSL_ENSURE( bIsStdPic, "OleHelper::importStdPic - unexpected header GUID, expected StdPic" ); + if( !bIsStdPic ) + return false; + } + + sal_uInt32 nStdPicId; + sal_Int32 nBytes; + rInStrm >> nStdPicId >> nBytes; + OSL_ENSURE( nStdPicId == OLE_STDPIC_ID, "OleHelper::importStdPic - unexpected header version" ); + return !rInStrm.isEof() && (nStdPicId == OLE_STDPIC_ID) && (nBytes > 0) && (rInStrm.readData( orGraphicData, nBytes ) == nBytes); +} + +/*static*/ bool OleHelper::importStdHlink( StdHlinkInfo& orHlinkInfo, BinaryInputStream& rInStrm, bool bWithGuid ) +{ + if( bWithGuid ) + { + bool bIsStdHlink = importGuid( rInStrm ).equalsAscii( OLE_GUID_STDHLINK ); + OSL_ENSURE( bIsStdHlink, "OleHelper::importStdHlink - unexpected header GUID, expected StdHlink" ); + if( !bIsStdHlink ) + return false; + } + + sal_uInt32 nVersion, nFlags; + rInStrm >> nVersion >> nFlags; + OSL_ENSURE( nVersion == OLE_STDHLINK_VERSION, "OleHelper::importStdHlink - unexpected header version" ); + if( rInStrm.isEof() || (nVersion != OLE_STDHLINK_VERSION) ) + return false; + + // display string + if( getFlag( nFlags, OLE_STDHLINK_HASDISPLAY ) ) + orHlinkInfo.maDisplay = lclReadStdHlinkString( rInStrm, true ); + // frame string + if( getFlag( nFlags, OLE_STDHLINK_HASFRAME ) ) + orHlinkInfo.maFrame = lclReadStdHlinkString( rInStrm, true ); + + // target + if( getFlag( nFlags, OLE_STDHLINK_HASTARGET ) ) + { + if( getFlag( nFlags, OLE_STDHLINK_ASSTRING ) ) + { + OSL_ENSURE( getFlag( nFlags, OLE_STDHLINK_ABSOLUTE ), "OleHelper::importStdHlink - link not absolute" ); + orHlinkInfo.maTarget = lclReadStdHlinkString( rInStrm, true ); + } + else // hyperlink moniker + { + OUString aGuid = importGuid( rInStrm ); + if( aGuid.equalsAscii( OLE_GUID_FILEMONIKER ) ) + { + // file name, maybe relative and with directory up-count + sal_Int16 nUpLevels; + rInStrm >> nUpLevels; + OSL_ENSURE( (nUpLevels == 0) || !getFlag( nFlags, OLE_STDHLINK_ABSOLUTE ), "OleHelper::importStdHlink - absolute filename with upcount" ); + orHlinkInfo.maTarget = lclReadStdHlinkString( rInStrm, false ); + rInStrm.skip( 24 ); + sal_Int32 nBytes = rInStrm.readInt32(); + if( nBytes > 0 ) + { + sal_Int64 nEndPos = rInStrm.tell() + ::std::max< sal_Int32 >( nBytes, 0 ); + sal_uInt16 nChars = getLimitedValue< sal_uInt16, sal_Int32 >( rInStrm.readInt32() / 2, 0, SAL_MAX_UINT16 ); + rInStrm.skip( 2 ); // key value + orHlinkInfo.maTarget = rInStrm.readUnicodeArray( nChars ); // NOT null terminated + rInStrm.seek( nEndPos ); + } + if( !getFlag( nFlags, OLE_STDHLINK_ABSOLUTE ) ) + for( sal_Int16 nLevel = 0; nLevel < nUpLevels; ++nLevel ) + orHlinkInfo.maTarget = CREATE_OUSTRING( "../" ) + orHlinkInfo.maTarget; + } + else if( aGuid.equalsAscii( OLE_GUID_URLMONIKER ) ) + { + // URL, maybe relative and with leading '../' + sal_Int32 nBytes = rInStrm.readInt32(); + sal_Int64 nEndPos = rInStrm.tell() + ::std::max< sal_Int32 >( nBytes, 0 ); + orHlinkInfo.maTarget = rInStrm.readNulUnicodeArray(); + rInStrm.seek( nEndPos ); + } + else + { + OSL_ENSURE( false, "OleHelper::importStdHlink - unsupported hyperlink moniker" ); + return false; + } + } + } + + // target location + if( getFlag( nFlags, OLE_STDHLINK_HASLOCATION ) ) + orHlinkInfo.maLocation = lclReadStdHlinkString( rInStrm, true ); + + return !rInStrm.isEof(); +} + +// ============================================================================ + +} // namespace ole +} // namespace oox + diff --git a/oox/source/ole/oleobjecthelper.cxx b/oox/source/ole/oleobjecthelper.cxx new file mode 100644 index 000000000000..5ef65fe2292e --- /dev/null +++ b/oox/source/ole/oleobjecthelper.cxx @@ -0,0 +1,141 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/ole/oleobjecthelper.hxx" +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/document/XEmbeddedObjectResolver.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include "properties.hxx" +#include "oox/helper/propertymap.hxx" + +using ::rtl::OUString; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::container::XNameAccess; +using ::com::sun::star::lang::XComponent; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::io::XOutputStream; +using ::com::sun::star::awt::Rectangle; +using ::com::sun::star::awt::Size; + +namespace oox { +namespace ole { + +// ============================================================================ + +OleObjectInfo::OleObjectInfo() : + mbLinked( false ), + mbShowAsIcon( false ), + mbAutoUpdate( false ) +{ +} + +// ============================================================================ + +OleObjectHelper::OleObjectHelper( const Reference< XMultiServiceFactory >& rxFactory ) : + maEmbeddedObjScheme( CREATE_OUSTRING( "vnd.sun.star.EmbeddedObject:" ) ), + mnObjectId( 100 ) +{ + if( rxFactory.is() ) + mxResolver.set( rxFactory->createInstance( CREATE_OUSTRING( "com.sun.star.document.ImportEmbeddedObjectResolver" ) ), UNO_QUERY ); +} + +OleObjectHelper::~OleObjectHelper() +{ + try + { + Reference< XComponent > xResolverComp( mxResolver, UNO_QUERY_THROW ); + xResolverComp->dispose(); + } + catch( Exception& ) + { + } +} + +bool OleObjectHelper::importOleObject( PropertyMap& rPropMap, const OleObjectInfo& rOleObject, const Size& rObjSize ) +{ + bool bRet = false; + + if( rOleObject.mbLinked ) + { + // linked OLE object - set target URL + if( rOleObject.maTargetLink.getLength() > 0 ) + { + rPropMap[ PROP_LinkURL ] <<= rOleObject.maTargetLink; + bRet = true; + } + } + else + { + // embedded OLE object - import the embedded data + if( rOleObject.maEmbeddedData.hasElements() && mxResolver.is() ) try + { + OUString aObjectId = CREATE_OUSTRING( "Obj" ) + OUString::valueOf( mnObjectId++ ); + + Reference< XNameAccess > xResolverNA( mxResolver, UNO_QUERY_THROW ); + Reference< XOutputStream > xOutStrm( xResolverNA->getByName( aObjectId ), UNO_QUERY_THROW ); + xOutStrm->writeBytes( rOleObject.maEmbeddedData ); + xOutStrm->closeOutput(); + + OUString aUrl = mxResolver->resolveEmbeddedObjectURL( aObjectId ); + OSL_ENSURE( aUrl.match( maEmbeddedObjScheme ), "OleObjectHelper::importOleObject - unexpected URL scheme" ); + OUString aPersistName = aUrl.copy( maEmbeddedObjScheme.getLength() ); + if( aPersistName.getLength() > 0 ) + { + rPropMap[ PROP_PersistName ] <<= aPersistName; + bRet = true; + } + } + catch( Exception& ) + { + } + } + + if( bRet ) + { + // aspect mode + using namespace ::com::sun::star::embed::Aspects; + sal_Int64 nAspect = rOleObject.mbShowAsIcon ? MSOLE_ICON : MSOLE_CONTENT; + rPropMap[ PROP_Aspect ] <<= nAspect; + // visual area + rPropMap[ PROP_VisualArea ] <<= Rectangle( 0, 0, rObjSize.Width, rObjSize.Height ); + } + return bRet; +} + +// ============================================================================ + +} // namespace ole +} // namespace oox + diff --git a/oox/source/ole/olestorage.cxx b/oox/source/ole/olestorage.cxx new file mode 100755 index 000000000000..0ca2992d47ad --- /dev/null +++ b/oox/source/ole/olestorage.cxx @@ -0,0 +1,423 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/ole/olestorage.hxx" +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <cppuhelper/implbase2.hxx> +#include "oox/helper/helper.hxx" +#include "oox/helper/binaryinputstream.hxx" +#include "oox/helper/binaryoutputstream.hxx" + +using ::rtl::OUString; +using ::com::sun::star::container::XNameContainer; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::embed::XStorage; +using ::com::sun::star::embed::XTransactedObject; +using ::com::sun::star::io::BufferSizeExceededException; +using ::com::sun::star::io::IOException; +using ::com::sun::star::io::NotConnectedException; +using ::com::sun::star::io::XInputStream; +using ::com::sun::star::io::XOutputStream; +using ::com::sun::star::io::XSeekable; +using ::com::sun::star::io::XStream; +using ::com::sun::star::lang::IllegalArgumentException; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::UNO_SET_THROW; + +namespace oox { +namespace ole { + +// ============================================================================ + +namespace { + +typedef ::cppu::WeakImplHelper2< XSeekable, XOutputStream > OleOutputStreamBase; + +/** Implementation of an OLE storage output stream that inserts itself into the + storage when it is closed. + */ +class OleOutputStream : public OleOutputStreamBase +{ +public: + explicit OleOutputStream( + const Reference< XMultiServiceFactory >& rxFactory, + const Reference< XNameContainer >& rxStorage, + const OUString& rElementName ); + virtual ~OleOutputStream(); + + virtual void SAL_CALL seek( sal_Int64 nPos ) throw( IllegalArgumentException, IOException, RuntimeException ); + virtual sal_Int64 SAL_CALL getPosition() throw( IOException, RuntimeException ); + virtual sal_Int64 SAL_CALL getLength() throw( IOException, RuntimeException ); + + virtual void SAL_CALL writeBytes( const Sequence< sal_Int8 >& rData ) throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException ); + virtual void SAL_CALL flush() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException ); + virtual void SAL_CALL closeOutput() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException ); + +private: + void ensureSeekable() const throw( IOException ); + void ensureConnected() const throw( NotConnectedException ); + +private: + Reference< XNameContainer > mxStorage; + Reference< XStream > mxTempFile; + Reference< XOutputStream > mxOutStrm; + Reference< XSeekable > mxSeekable; + OUString maElementName; +}; + +// ---------------------------------------------------------------------------- + +OleOutputStream::OleOutputStream( const Reference< XMultiServiceFactory >& rxFactory, + const Reference< XNameContainer >& rxStorage, const OUString& rElementName ) : + mxStorage( rxStorage ), + maElementName( rElementName ) +{ + try + { + mxTempFile.set( rxFactory->createInstance( CREATE_OUSTRING( "com.sun.star.io.TempFile" ) ), UNO_QUERY_THROW ); + mxOutStrm = mxTempFile->getOutputStream(); + mxSeekable.set( mxOutStrm, UNO_QUERY ); + } + catch( Exception& ) + { + } +} + +OleOutputStream::~OleOutputStream() +{ +} + +void SAL_CALL OleOutputStream::seek( sal_Int64 nPos ) throw( IllegalArgumentException, IOException, RuntimeException ) +{ + ensureSeekable(); + mxSeekable->seek( nPos ); +} + +sal_Int64 SAL_CALL OleOutputStream::getPosition() throw( IOException, RuntimeException ) +{ + ensureSeekable(); + return mxSeekable->getPosition(); +} + +sal_Int64 SAL_CALL OleOutputStream::getLength() throw( IOException, RuntimeException ) +{ + ensureSeekable(); + return mxSeekable->getLength(); +} + +void SAL_CALL OleOutputStream::writeBytes( const Sequence< sal_Int8 >& rData ) throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException ) +{ + ensureConnected(); + mxOutStrm->writeBytes( rData ); +} + +void SAL_CALL OleOutputStream::flush() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException ) +{ + ensureConnected(); + mxOutStrm->flush(); +} + +void SAL_CALL OleOutputStream::closeOutput() throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException ) +{ + ensureConnected(); + ensureSeekable(); + // remember the class members + Reference< XOutputStream > xOutStrm = mxOutStrm; + Reference< XSeekable > xSeekable = mxSeekable; + // reset all class members + mxOutStrm.clear(); + mxSeekable.clear(); + // close stream (and let it throw something if needed) + xOutStrm->closeOutput(); + // on success, insert the stream into the OLE storage (must be seeked back before) + xSeekable->seek( 0 ); + if( !ContainerHelper::insertByName( mxStorage, maElementName, Any( mxTempFile ) ) ) + throw IOException(); +} + +void OleOutputStream::ensureSeekable() const throw( IOException ) +{ + if( !mxSeekable.is() ) + throw IOException(); +} + +void OleOutputStream::ensureConnected() const throw( NotConnectedException ) +{ + if( !mxOutStrm.is() ) + throw NotConnectedException(); +} + +} // namespace + +// ============================================================================ + +OleStorage::OleStorage( + const Reference< XMultiServiceFactory >& rxFactory, + const Reference< XInputStream >& rxInStream, + bool bBaseStreamAccess ) : + StorageBase( rxInStream, bBaseStreamAccess ), + mxFactory( rxFactory ), + mpParentStorage( 0 ) +{ + OSL_ENSURE( mxFactory.is(), "OleStorage::OleStorage - missing service factory" ); + initStorage( rxInStream ); +} + +OleStorage::OleStorage( + const Reference< XMultiServiceFactory >& rxFactory, + const Reference< XStream >& rxOutStream, + bool bBaseStreamAccess ) : + StorageBase( rxOutStream, bBaseStreamAccess ), + mxFactory( rxFactory ), + mpParentStorage( 0 ) +{ + OSL_ENSURE( mxFactory.is(), "OleStorage::OleStorage - missing service factory" ); + initStorage( rxOutStream ); +} + +OleStorage::OleStorage( + const OleStorage& rParentStorage, + const Reference< XNameContainer >& rxStorage, + const OUString& rElementName, + bool bReadOnly ) : + StorageBase( rParentStorage, rElementName, bReadOnly ), + mxFactory( rParentStorage.mxFactory ), + mxStorage( rxStorage ), + mpParentStorage( &rParentStorage ) +{ + OSL_ENSURE( mxStorage.is(), "OleStorage::OleStorage - missing substorage elements" ); +} + +OleStorage::OleStorage( + const OleStorage& rParentStorage, + const Reference< XStream >& rxOutStream, + const OUString& rElementName ) : + StorageBase( rParentStorage, rElementName, false ), + mxFactory( rParentStorage.mxFactory ), + mpParentStorage( &rParentStorage ) +{ + initStorage( rxOutStream ); +} + +OleStorage::~OleStorage() +{ +} + +// ---------------------------------------------------------------------------- + +void OleStorage::initStorage( const Reference< XInputStream >& rxInStream ) +{ + // if stream is not seekable, create temporary copy + Reference< XInputStream > xInStrm = rxInStream; + if( !Reference< XSeekable >( xInStrm, UNO_QUERY ).is() ) try + { + Reference< XStream > xTempFile( mxFactory->createInstance( CREATE_OUSTRING( "com.sun.star.io.TempFile" ) ), UNO_QUERY_THROW ); + { + Reference< XOutputStream > xOutStrm( xTempFile->getOutputStream(), UNO_SET_THROW ); + /* Pass false to both binary stream objects to keep the UNO + streams alive. Life time of these streams is controlled by the + tempfile implementation. */ + BinaryXOutputStream aOutStrm( xOutStrm, false ); + BinaryXInputStream aInStrm( xInStrm, false ); + aInStrm.copyToStream( aOutStrm ); + } // scope closes output stream of tempfile + xInStrm = xTempFile->getInputStream(); + } + catch( Exception& ) + { + OSL_ENSURE( false, "OleStorage::initStorage - cannot create temporary copy of input stream" ); + } + + // create base storage object + if( xInStrm.is() ) try + { + Sequence< Any > aArgs( 2 ); + aArgs[ 0 ] <<= xInStrm; + aArgs[ 1 ] <<= true; // true = do not create a copy of the input stream + mxStorage.set( mxFactory->createInstanceWithArguments( + CREATE_OUSTRING( "com.sun.star.embed.OLESimpleStorage" ), aArgs ), UNO_QUERY_THROW ); + } + catch( Exception& ) + { + } +} + +void OleStorage::initStorage( const Reference< XStream >& rxOutStream ) +{ + // create base storage object + if( rxOutStream.is() ) try + { + Sequence< Any > aArgs( 2 ); + aArgs[ 0 ] <<= rxOutStream; + aArgs[ 1 ] <<= true; // true = do not create a copy of the stream + mxStorage.set( mxFactory->createInstanceWithArguments( + CREATE_OUSTRING( "com.sun.star.embed.OLESimpleStorage" ), aArgs ), UNO_QUERY_THROW ); + } + catch( Exception& ) + { + } +} + +// StorageBase interface ------------------------------------------------------ + +bool OleStorage::implIsStorage() const +{ + if( mxStorage.is() ) try + { + /* If this is not an OLE storage, hasElements() of the OLESimpleStorage + implementation throws an exception. But we do not return the result + of hasElements(), because an empty storage is a valid storage too. */ + mxStorage->hasElements(); + return true; + } + catch( Exception& ) + { + } + return false; +} + +Reference< XStorage > OleStorage::implGetXStorage() const +{ + OSL_ENSURE( false, "OleStorage::getXStorage - not implemented" ); + return Reference< XStorage >(); +} + +void OleStorage::implGetElementNames( ::std::vector< OUString >& orElementNames ) const +{ + Sequence< OUString > aNames; + if( mxStorage.is() ) try + { + aNames = mxStorage->getElementNames(); + if( aNames.getLength() > 0 ) + orElementNames.insert( orElementNames.end(), aNames.getConstArray(), aNames.getConstArray() + aNames.getLength() ); + } + catch( Exception& ) + { + } +} + +StorageRef OleStorage::implOpenSubStorage( const OUString& rElementName, bool bCreateMissing ) +{ + StorageRef xSubStorage; + if( mxStorage.is() && (rElementName.getLength() > 0) ) + { + try + { + Reference< XNameContainer > xSubElements( mxStorage->getByName( rElementName ), UNO_QUERY_THROW ); + xSubStorage.reset( new OleStorage( *this, xSubElements, rElementName, true ) ); + } + catch( Exception& ) + { + } + + /* The OLESimpleStorage API implementation seems to be buggy in the + area of writable inplace substorage (sometimes it overwrites other + unrelated streams with zero bytes). We go the save way and create a + new OLE storage based on a temporary file. All operations are + performed on this clean storage. On committing, the storage will be + completely re-inserted into the parent storage. */ + if( !isReadOnly() && (bCreateMissing || xSubStorage.get()) ) try + { + // create new storage based on a temp file + Reference< XStream > xTempFile( mxFactory->createInstance( CREATE_OUSTRING( "com.sun.star.io.TempFile" ) ), UNO_QUERY_THROW ); + StorageRef xTempStorage( new OleStorage( *this, xTempFile, rElementName ) ); + // copy existing substorage into temp storage + if( xSubStorage.get() ) + xSubStorage->copyStorageToStorage( *xTempStorage ); + // return the temp storage to caller + xSubStorage = xTempStorage; + } + catch( Exception& ) + { + } + } + return xSubStorage; +} + +Reference< XInputStream > OleStorage::implOpenInputStream( const OUString& rElementName ) +{ + Reference< XInputStream > xInStream; + if( mxStorage.is() ) try + { + xInStream.set( mxStorage->getByName( rElementName ), UNO_QUERY ); + } + catch( Exception& ) + { + } + return xInStream; +} + +Reference< XOutputStream > OleStorage::implOpenOutputStream( const OUString& rElementName ) +{ + Reference< XOutputStream > xOutStream; + if( mxStorage.is() && (rElementName.getLength() > 0) ) + xOutStream.set( new OleOutputStream( mxFactory, mxStorage, rElementName ) ); + return xOutStream; +} + +void OleStorage::implCommit() const +{ + try + { + // commit this storage (finalizes the file this storage is based on) + Reference< XTransactedObject >( mxStorage, UNO_QUERY_THROW )->commit(); + // re-insert this storage into the parent storage + if( mpParentStorage ) + { + if( mpParentStorage->mxStorage->hasByName( getName() ) ) + { + // replaceByName() does not work (#i109539#) + mpParentStorage->mxStorage->removeByName( getName() ); + Reference< XTransactedObject >( mpParentStorage->mxStorage, UNO_QUERY_THROW )->commit(); + } + mpParentStorage->mxStorage->insertByName( getName(), Any( mxStorage ) ); + // this requires another commit(), which will be performed by the parent storage + } + } + catch( Exception& ) + { + } +} + +// ============================================================================ + +} // namespace ole +} // namespace oox diff --git a/oox/source/ole/vbacontrol.cxx b/oox/source/ole/vbacontrol.cxx new file mode 100755 index 000000000000..2a36cb4ff3ca --- /dev/null +++ b/oox/source/ole/vbacontrol.cxx @@ -0,0 +1,845 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/ole/vbacontrol.hxx" +#include <algorithm> +#include <set> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/awt/XControlModel.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/io/XInputStreamProvider.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <xmlscript/xmldlg_imexp.hxx> +#include "properties.hxx" +#include "tokens.hxx" +#include "oox/helper/attributelist.hxx" +#include "oox/helper/binaryinputstream.hxx" +#include "oox/helper/propertymap.hxx" +#include "oox/helper/propertyset.hxx" +#include "oox/helper/storagebase.hxx" +#include "oox/helper/textinputstream.hxx" +#include "oox/ole/vbahelper.hxx" + +using ::rtl::OUString; +using ::rtl::OUStringBuffer; +using ::com::sun::star::awt::XControlModel; +using ::com::sun::star::container::XNameContainer; +using ::com::sun::star::io::XInputStreamProvider; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::UNO_SET_THROW; +using ::com::sun::star::uno::XComponentContext; + +namespace oox { +namespace ole { + +// ============================================================================ + +namespace { + +const sal_uInt16 VBA_SITE_CLASSIDINDEX = 0x8000; +const sal_uInt16 VBA_SITE_INDEXMASK = 0x7FFF; +const sal_uInt16 VBA_SITE_FORM = 7; +const sal_uInt16 VBA_SITE_IMAGE = 12; +const sal_uInt16 VBA_SITE_FRAME = 14; +const sal_uInt16 VBA_SITE_SPINBUTTON = 16; +const sal_uInt16 VBA_SITE_COMMANDBUTTON = 17; +const sal_uInt16 VBA_SITE_TABSTRIP = 18; +const sal_uInt16 VBA_SITE_LABEL = 21; +const sal_uInt16 VBA_SITE_TEXTBOX = 23; +const sal_uInt16 VBA_SITE_LISTBOX = 24; +const sal_uInt16 VBA_SITE_COMBOBOX = 25; +const sal_uInt16 VBA_SITE_CHECKBOX = 26; +const sal_uInt16 VBA_SITE_OPTIONBUTTON = 27; +const sal_uInt16 VBA_SITE_TOGGLEBUTTON = 28; +const sal_uInt16 VBA_SITE_SCROLLBAR = 47; +const sal_uInt16 VBA_SITE_MULTIPAGE = 57; +const sal_uInt16 VBA_SITE_UNKNOWN = 0x7FFF; + +const sal_uInt32 VBA_SITE_TABSTOP = 0x00000001; +const sal_uInt32 VBA_SITE_VISIBLE = 0x00000002; +const sal_uInt32 VBA_SITE_DEFAULTBUTTON = 0x00000004; +const sal_uInt32 VBA_SITE_CANCELBUTTON = 0x00000008; +const sal_uInt32 VBA_SITE_OSTREAM = 0x00000010; +const sal_uInt32 VBA_SITE_DEFFLAGS = 0x00000033; + +const sal_uInt8 VBA_SITEINFO_COUNT = 0x80; +const sal_uInt8 VBA_SITEINFO_MASK = 0x7F; + +// ---------------------------------------------------------------------------- + +/** Collects names of all controls in a user form or container control. Allows + to generate unused names for dummy controls separating option groups. + */ +class VbaControlNamesSet +{ +public: + explicit VbaControlNamesSet(); + + /** Inserts the name of the passed control. */ + void insertName( const VbaFormControl& rControl ); + /** Returns a name that is not contained in this set. */ + OUString generateDummyName(); + +private: + typedef ::std::set< OUString > OUStringSet; + OUStringSet maCtrlNames; + const OUString maDummyBaseName; + sal_Int32 mnIndex; +}; + +VbaControlNamesSet::VbaControlNamesSet() : + maDummyBaseName( CREATE_OUSTRING( "DummyGroupSep" ) ), + mnIndex( 0 ) +{ +} + +void VbaControlNamesSet::insertName( const VbaFormControl& rControl ) +{ + OUString aName = rControl.getControlName(); + if( aName.getLength() > 0 ) + maCtrlNames.insert( aName ); +} + +OUString VbaControlNamesSet::generateDummyName() +{ + OUString aCtrlName; + do + { + aCtrlName = OUStringBuffer( maDummyBaseName ).append( ++mnIndex ).makeStringAndClear(); + } + while( maCtrlNames.count( aCtrlName ) > 0 ); + maCtrlNames.insert( aCtrlName ); + return aCtrlName; +} + +// ---------------------------------------------------------------------------- + +/** Functor that inserts the name of a control into a VbaControlNamesSet. */ +struct VbaControlNameInserter +{ +public: + VbaControlNamesSet& mrCtrlNames; + inline explicit VbaControlNameInserter( VbaControlNamesSet& rCtrlNames ) : mrCtrlNames( rCtrlNames ) {} + inline void operator()( const VbaFormControl& rControl ) { mrCtrlNames.insertName( rControl ); } +}; + +// ---------------------------------------------------------------------------- + +/** A dummy invisible form control (fixed label without text) that is used to + separate two groups of option buttons. + */ +class VbaDummyFormControl : public VbaFormControl +{ +public: + explicit VbaDummyFormControl( const OUString& rName ); +}; + +VbaDummyFormControl::VbaDummyFormControl( const OUString& rName ) +{ + mxSiteModel.reset( new VbaSiteModel ); + mxSiteModel->importProperty( XML_Name, rName ); + mxSiteModel->importProperty( XML_VariousPropertyBits, OUString( sal_Unicode( '0' ) ) ); + + mxCtrlModel.reset( new AxLabelModel ); + mxCtrlModel->setAwtModelMode(); + mxCtrlModel->importProperty( XML_Size, CREATE_OUSTRING( "10;10" ) ); +} + +} // namespace + +// ============================================================================ + +VbaSiteModel::VbaSiteModel() : + maPos( 0, 0 ), + mnId( 0 ), + mnHelpContextId( 0 ), + mnFlags( VBA_SITE_DEFFLAGS ), + mnStreamLen( 0 ), + mnTabIndex( -1 ), + mnClassIdOrCache( VBA_SITE_UNKNOWN ), + mnGroupId( 0 ) +{ +} + +VbaSiteModel::~VbaSiteModel() +{ +} + +void VbaSiteModel::importProperty( sal_Int32 nPropId, const OUString& rValue ) +{ + switch( nPropId ) + { + case XML_Name: maName = rValue; break; + case XML_Tag: maTag = rValue; break; + case XML_VariousPropertyBits: mnFlags = AttributeConversion::decodeUnsigned( rValue ); break; + } +} + +bool VbaSiteModel::importBinaryModel( BinaryInputStream& rInStrm ) +{ + AxBinaryPropertyReader aReader( rInStrm ); + aReader.readStringProperty( maName ); + aReader.readStringProperty( maTag ); + aReader.readIntProperty< sal_Int32 >( mnId ); + aReader.readIntProperty< sal_Int32 >( mnHelpContextId ); + aReader.readIntProperty< sal_uInt32 >( mnFlags ); + aReader.readIntProperty< sal_uInt32 >( mnStreamLen ); + aReader.readIntProperty< sal_Int16 >( mnTabIndex ); + aReader.readIntProperty< sal_uInt16 >( mnClassIdOrCache ); + aReader.readPairProperty( maPos ); + aReader.readIntProperty< sal_uInt16 >( mnGroupId ); + aReader.skipUndefinedProperty(); + aReader.readStringProperty( maToolTip ); + aReader.skipStringProperty(); // license key + aReader.readStringProperty( maLinkedCell ); + aReader.readStringProperty( maSourceRange ); + return aReader.finalizeImport(); +} + +void VbaSiteModel::moveRelative( const AxPairData& rDistance ) +{ + maPos.first += rDistance.first; + maPos.second += rDistance.second; +} + +bool VbaSiteModel::isVisible() const +{ + return getFlag( mnFlags, VBA_SITE_VISIBLE ); +} + +bool VbaSiteModel::isContainer() const +{ + return !getFlag( mnFlags, VBA_SITE_OSTREAM ); +} + +sal_uInt32 VbaSiteModel::getStreamLength() const +{ + return isContainer() ? 0 : mnStreamLen; +} + +OUString VbaSiteModel::getSubStorageName() const +{ + if( mnId >= 0 ) + { + OUStringBuffer aBuffer; + aBuffer.append( sal_Unicode( 'i' ) ); + if( mnId < 10 ) + aBuffer.append( sal_Unicode( '0' ) ); + aBuffer.append( mnId ); + return aBuffer.makeStringAndClear(); + } + return OUString(); +} + +ControlModelRef VbaSiteModel::createControlModel( const AxClassTable& rClassTable ) const +{ + ControlModelRef xCtrlModel; + + sal_Int32 nTypeIndex = static_cast< sal_Int32 >( mnClassIdOrCache & VBA_SITE_INDEXMASK ); + if( !getFlag( mnClassIdOrCache, VBA_SITE_CLASSIDINDEX ) ) + { + switch( nTypeIndex ) + { + case VBA_SITE_COMMANDBUTTON: xCtrlModel.reset( new AxCommandButtonModel ); break; + case VBA_SITE_LABEL: xCtrlModel.reset( new AxLabelModel ); break; + case VBA_SITE_IMAGE: xCtrlModel.reset( new AxImageModel ); break; + case VBA_SITE_TOGGLEBUTTON: xCtrlModel.reset( new AxToggleButtonModel ); break; + case VBA_SITE_CHECKBOX: xCtrlModel.reset( new AxCheckBoxModel ); break; + case VBA_SITE_OPTIONBUTTON: xCtrlModel.reset( new AxOptionButtonModel ); break; + case VBA_SITE_TEXTBOX: xCtrlModel.reset( new AxTextBoxModel ); break; + case VBA_SITE_LISTBOX: xCtrlModel.reset( new AxListBoxModel ); break; + case VBA_SITE_COMBOBOX: xCtrlModel.reset( new AxComboBoxModel ); break; + case VBA_SITE_SPINBUTTON: /*xCtrlModel.reset( new AxSpinButtonModel );*/ break; // not supported (?) + case VBA_SITE_SCROLLBAR: xCtrlModel.reset( new AxScrollBarModel ); break; + case VBA_SITE_TABSTRIP: break; // not supported + case VBA_SITE_FRAME: xCtrlModel.reset( new AxFrameModel ); break; + case VBA_SITE_MULTIPAGE: break; // not supported + case VBA_SITE_FORM: break; // not supported + default: OSL_ENSURE( false, "VbaSiteModel::createControlModel - unknown type index" ); + } + } + else + { + const OUString* pGuid = ContainerHelper::getVectorElement( rClassTable, nTypeIndex ); + OSL_ENSURE( pGuid, "VbaSiteModel::createControlModel - invalid class table index" ); + if( pGuid ) + { + if( pGuid->equalsAscii( COMCTL_GUID_SCROLLBAR_60 ) ) + xCtrlModel.reset( new ComCtlScrollBarModel( 6 ) ); + else if( pGuid->equalsAscii( COMCTL_GUID_PROGRESSBAR_50 ) ) + xCtrlModel.reset( new ComCtlProgressBarModel( 5 ) ); + else if( pGuid->equalsAscii( COMCTL_GUID_PROGRESSBAR_60 ) ) + xCtrlModel.reset( new ComCtlProgressBarModel( 6 ) ); + } + } + + if( xCtrlModel.get() ) + { + // user form controls are AWT models + xCtrlModel->setAwtModelMode(); + + // check that container model matches container flag in site data + bool bModelIsContainer = dynamic_cast< const AxContainerModelBase* >( xCtrlModel.get() ) != 0; + bool bTypeMatch = bModelIsContainer == isContainer(); + OSL_ENSURE( bTypeMatch, "VbaSiteModel::createControlModel - container type does not match container flag" ); + if( !bTypeMatch ) + xCtrlModel.reset(); + } + return xCtrlModel; +} + +void VbaSiteModel::convertProperties( PropertyMap& rPropMap, + const ControlConverter& rConv, ApiControlType eCtrlType, sal_Int32 nCtrlIndex ) const +{ + rPropMap.setProperty( PROP_Name, maName ); + rPropMap.setProperty( PROP_Tag, maTag ); + + if( eCtrlType != API_CONTROL_DIALOG ) + { + rPropMap.setProperty( PROP_HelpText, maToolTip ); + rPropMap.setProperty( PROP_EnableVisible, getFlag( mnFlags, VBA_SITE_VISIBLE ) ); + // we need to set the passed control index to make option button groups work + if( (0 <= nCtrlIndex) && (nCtrlIndex <= SAL_MAX_INT16) ) + rPropMap.setProperty( PROP_TabIndex, static_cast< sal_Int16 >( nCtrlIndex ) ); + // progress bar and group box support TabIndex, but not Tabstop... + if( (eCtrlType != API_CONTROL_PROGRESSBAR) && (eCtrlType != API_CONTROL_GROUPBOX) && (eCtrlType != API_CONTROL_FRAME) && (eCtrlType != API_CONTROL_PAGE) ) + rPropMap.setProperty( PROP_Tabstop, getFlag( mnFlags, VBA_SITE_TABSTOP ) ); + rConv.convertPosition( rPropMap, maPos ); + } +} + +// ============================================================================ + +VbaFormControl::VbaFormControl() +{ +} + +VbaFormControl::~VbaFormControl() +{ +} + +void VbaFormControl::importModelOrStorage( BinaryInputStream& rInStrm, StorageBase& rStrg, const AxClassTable& rClassTable ) +{ + if( mxSiteModel.get() ) + { + if( mxSiteModel->isContainer() ) + { + StorageRef xSubStrg = rStrg.openSubStorage( mxSiteModel->getSubStorageName(), false ); + OSL_ENSURE( xSubStrg.get(), "VbaFormControl::importModelOrStorage - cannot find storage for embedded control" ); + if( xSubStrg.get() ) + importStorage( *xSubStrg, rClassTable ); + } + else if( !rInStrm.isEof() ) + { + sal_Int64 nNextStrmPos = rInStrm.tell() + mxSiteModel->getStreamLength(); + importControlModel( rInStrm, rClassTable ); + rInStrm.seek( nNextStrmPos ); + } + } +} + +OUString VbaFormControl::getControlName() const +{ + return mxSiteModel.get() ? mxSiteModel->getName() : OUString(); +} + +sal_Int32 VbaFormControl::getControlId() const +{ + return mxSiteModel.get() ? mxSiteModel->getId() : -1; +} + +void VbaFormControl::createAndConvert( sal_Int32 nCtrlIndex, + const Reference< XNameContainer >& rxParentNC, const ControlConverter& rConv ) const +{ + if( rxParentNC.is() && mxSiteModel.get() && mxCtrlModel.get() ) try + { + // create the control model + OUString aServiceName = mxCtrlModel->getServiceName(); + Reference< XMultiServiceFactory > xModelFactory( rxParentNC, UNO_QUERY_THROW ); + Reference< XControlModel > xCtrlModel( xModelFactory->createInstance( aServiceName ), UNO_QUERY_THROW ); + + // convert all properties and embedded controls + if( convertProperties( xCtrlModel, rConv, nCtrlIndex ) ) + { + // insert into parent container + const OUString& rCtrlName = mxSiteModel->getName(); + OSL_ENSURE( !rxParentNC->hasByName( rCtrlName ), "VbaFormControl::createAndConvert - multiple controls with equal name" ); + ContainerHelper::insertByName( rxParentNC, rCtrlName, Any( xCtrlModel ) ); + } + } + catch( Exception& ) + { + } +} + +// protected ------------------------------------------------------------------ + +void VbaFormControl::importControlModel( BinaryInputStream& rInStrm, const AxClassTable& rClassTable ) +{ + createControlModel( rClassTable ); + if( mxCtrlModel.get() ) + mxCtrlModel->importBinaryModel( rInStrm ); +} + +void VbaFormControl::importStorage( StorageBase& rStrg, const AxClassTable& rClassTable ) +{ + createControlModel( rClassTable ); + AxContainerModelBase* pContainerModel = dynamic_cast< AxContainerModelBase* >( mxCtrlModel.get() ); + OSL_ENSURE( pContainerModel, "VbaFormControl::importStorage - missing container control model" ); + if( pContainerModel ) + { + /* Open the 'f' stream containing the model of this control and a list + of site models for all child controls. */ + BinaryXInputStream aFStrm( rStrg.openInputStream( CREATE_OUSTRING( "f" ) ), true ); + OSL_ENSURE( !aFStrm.isEof(), "VbaFormControl::importStorage - missing 'f' stream" ); + + /* Read the properties of this container control and the class table + (into the maClassTable vector) containing a list of GUIDs for + exotic embedded controls. */ + if( !aFStrm.isEof() && pContainerModel->importBinaryModel( aFStrm ) && pContainerModel->importClassTable( aFStrm, maClassTable ) ) + { + /* Read the site models of all embedded controls (this fills the + maControls vector). Ignore failure of importSiteModels() but + try to import as much controls as possible. */ + importEmbeddedSiteModels( aFStrm ); + + /* Open the 'o' stream containing models of embedded simple + controls. Stream may be empty or missing, if this control + contains no controls or only container controls. */ + BinaryXInputStream aOStrm( rStrg.openInputStream( CREATE_OUSTRING( "o" ) ), true ); + + /* Iterate over all embedded controls, import model from 'o' + stream (for embedded simple controls) or from the substorage + (for embedded container controls). */ + maControls.forEachMem( &VbaFormControl::importModelOrStorage, + ::boost::ref( aOStrm ), ::boost::ref( rStrg ), ::boost::cref( maClassTable ) ); + + /* Reorder the controls (sorts all option buttons of an option + group together), and move all children of all embedded frames + (group boxes) to this control (UNO group boxes cannot contain + other controls). */ + finalizeEmbeddedControls(); + } + } +} + +bool VbaFormControl::convertProperties( const Reference< XControlModel >& rxCtrlModel, + const ControlConverter& rConv, sal_Int32 nCtrlIndex ) const +{ + if( rxCtrlModel.is() && mxSiteModel.get() && mxCtrlModel.get() ) + { + const OUString& rCtrlName = mxSiteModel->getName(); + OSL_ENSURE( rCtrlName.getLength() > 0, "VbaFormControl::convertProperties - control without name" ); + if( rCtrlName.getLength() > 0 ) + { + // convert all properties + PropertyMap aPropMap; + mxSiteModel->convertProperties( aPropMap, rConv, mxCtrlModel->getControlType(), nCtrlIndex ); + mxCtrlModel->convertProperties( aPropMap, rConv ); + mxCtrlModel->convertSize( aPropMap, rConv ); + PropertySet aPropSet( rxCtrlModel ); + aPropSet.setProperties( aPropMap ); + + // create and convert all embedded controls + if( !maControls.empty() ) try + { + Reference< XNameContainer > xCtrlModelNC( rxCtrlModel, UNO_QUERY_THROW ); + /* Call conversion for all controls. Pass vector index as new + tab order to make option button groups work correctly. */ + maControls.forEachMemWithIndex( &VbaFormControl::createAndConvert, + ::boost::cref( xCtrlModelNC ), ::boost::cref( rConv ) ); + } + catch( Exception& ) + { + OSL_ENSURE( false, "VbaFormControl::convertProperties - cannot get control container interface" ); + } + + return true; + } + } + return false; +} + +// private -------------------------------------------------------------------- + +void VbaFormControl::createControlModel( const AxClassTable& rClassTable ) +{ + // derived classes may have created their own control model + if( !mxCtrlModel && mxSiteModel.get() ) + mxCtrlModel = mxSiteModel->createControlModel( rClassTable ); +} + +bool VbaFormControl::importSiteModel( BinaryInputStream& rInStrm ) +{ + mxSiteModel.reset( new VbaSiteModel ); + return mxSiteModel->importBinaryModel( rInStrm ); +} + +bool VbaFormControl::importEmbeddedSiteModels( BinaryInputStream& rInStrm ) +{ + sal_uInt64 nAnchorPos = rInStrm.tell(); + sal_uInt32 nSiteCount, nSiteDataSize; + rInStrm >> nSiteCount >> nSiteDataSize; + sal_Int64 nSiteEndPos = rInStrm.tell() + nSiteDataSize; + + // skip the site info structure + sal_uInt32 nSiteIndex = 0; + while( !rInStrm.isEof() && (nSiteIndex < nSiteCount) ) + { + rInStrm.skip( 1 ); // site depth + sal_uInt8 nTypeCount = rInStrm.readuInt8(); // 'type-or-count' byte + if( getFlag( nTypeCount, VBA_SITEINFO_COUNT ) ) + { + /* Count flag is set: the 'type-or-count' byte contains the number + of controls in the lower bits, the type specifier follows in + the next byte. The type specifier should always be 1 according + to the specification. */ + rInStrm.skip( 1 ); + nSiteIndex += (nTypeCount & VBA_SITEINFO_MASK); + } + else + { + /* Count flag is not set: the 'type-or-count' byte contains the + type specifier of *one* control in the lower bits (this type + should be 1, see above). */ + ++nSiteIndex; + } + } + // align the stream to 32bit, relative to start of entire site info + rInStrm.alignToBlock( 4, nAnchorPos ); + + // import the site models for all embedded controls + maControls.clear(); + bool bValid = !rInStrm.isEof(); + for( nSiteIndex = 0; bValid && (nSiteIndex < nSiteCount); ++nSiteIndex ) + { + VbaFormControlRef xControl( new VbaFormControl ); + maControls.push_back( xControl ); + bValid = xControl->importSiteModel( rInStrm ); + } + + rInStrm.seek( nSiteEndPos ); + return bValid; +} + +void VbaFormControl::finalizeEmbeddedControls() +{ + /* This function performs two tasks: + + 1) Reorder the controls appropriately (sort all option buttons of an + option group together to make grouping work). + 2) Move all children of all embedded frames (group boxes) to this + control (UNO group boxes cannot contain other controls). + */ + + // first, sort all controls by original tab index + ::std::sort( maControls.begin(), maControls.end(), &compareByTabIndex ); + + /* Collect the programmatical names of all embedded controls (needed to be + able to set unused names to new dummy controls created below). Also + collect the names of all children of embedded frames (group boxes). + Luckily, names of controls must be unique in the entire form, not just + in the current container. */ + VbaControlNamesSet aControlNames; + VbaControlNameInserter aInserter( aControlNames ); + maControls.forEach( aInserter ); + for( VbaFormControlVector::iterator aIt = maControls.begin(), aEnd = maControls.end(); aIt != aEnd; ++aIt ) + if( (*aIt)->mxCtrlModel.get() && ((*aIt)->mxCtrlModel->getControlType() == API_CONTROL_GROUPBOX) ) + (*aIt)->maControls.forEach( aInserter ); + + /* Reprocess the sorted list and collect all option button controls that + are part of the same option group (determined by group name). All + controls will be stored in a vector of vectors, that collects every + option button group in one vector element, and other controls between + these option groups (or leading or trailing controls) in other vector + elements. If an option button group follows another group, a dummy + separator control has to be inserted. */ + typedef RefVector< VbaFormControlVector > VbaFormControlVectorVector; + VbaFormControlVectorVector aControlGroups; + + typedef RefMap< OUString, VbaFormControlVector > VbaFormControlVectorMap; + VbaFormControlVectorMap aOptionGroups; + + typedef VbaFormControlVectorMap::mapped_type VbaFormControlVectorRef; + bool bLastWasOptionButton = false; + for( VbaFormControlVector::iterator aIt = maControls.begin(), aEnd = maControls.end(); aIt != aEnd; ++aIt ) + { + VbaFormControlRef xControl = *aIt; + const ControlModelBase* pCtrlModel = xControl->mxCtrlModel.get(); + + if( const AxOptionButtonModel* pOptButtonModel = dynamic_cast< const AxOptionButtonModel* >( pCtrlModel ) ) + { + // check if a new option group needs to be created + const OUString& rGroupName = pOptButtonModel->getGroupName(); + VbaFormControlVectorRef& rxOptionGroup = aOptionGroups[ rGroupName ]; + if( !rxOptionGroup ) + { + /* If last control was an option button too, we have two + option groups following each other, so a dummy separator + control is needed. */ + if( bLastWasOptionButton ) + { + VbaFormControlVectorRef xDummyGroup( new VbaFormControlVector ); + aControlGroups.push_back( xDummyGroup ); + OUString aName = aControlNames.generateDummyName(); + VbaFormControlRef xDummyControl( new VbaDummyFormControl( aName ) ); + xDummyGroup->push_back( xDummyControl ); + } + rxOptionGroup.reset( new VbaFormControlVector ); + aControlGroups.push_back( rxOptionGroup ); + } + /* Append the option button to the control group (which is now + referred by the vector aControlGroups and by the map + aOptionGroups). */ + rxOptionGroup->push_back( xControl ); + bLastWasOptionButton = true; + } + else + { + // open a new control group, if the last group is an option group + if( bLastWasOptionButton || aControlGroups.empty() ) + { + VbaFormControlVectorRef xControlGroup( new VbaFormControlVector ); + aControlGroups.push_back( xControlGroup ); + } + // append the control to the last control group + VbaFormControlVector& rLastGroup = *aControlGroups.back(); + rLastGroup.push_back( xControl ); + bLastWasOptionButton = false; + + // if control is a group box, move all its children to this control + if( pCtrlModel && (pCtrlModel->getControlType() == API_CONTROL_GROUPBOX) ) + { + /* Move all embedded controls of the group box relative to the + position of the group box. */ + xControl->moveEmbeddedToAbsoluteParent(); + /* Insert all children of the group box into the last control + group (following the group box). */ + rLastGroup.insert( rLastGroup.end(), xControl->maControls.begin(), xControl->maControls.end() ); + xControl->maControls.clear(); + // check if last control of the group box is an option button + bLastWasOptionButton = dynamic_cast< const AxOptionButtonModel* >( rLastGroup.back()->mxCtrlModel.get() ) != 0; + } + } + } + + // flatten the vector of vectors of form controls to a single vector + maControls.clear(); + for( VbaFormControlVectorVector::iterator aIt = aControlGroups.begin(), aEnd = aControlGroups.end(); aIt != aEnd; ++aIt ) + maControls.insert( maControls.end(), (*aIt)->begin(), (*aIt)->end() ); +} + +void VbaFormControl::moveRelative( const AxPairData& rDistance ) +{ + if( mxSiteModel.get() ) + mxSiteModel->moveRelative( rDistance ); +} + +void VbaFormControl::moveEmbeddedToAbsoluteParent() +{ + if( mxSiteModel.get() && !maControls.empty() ) + { + // distance to move is equal to position of this control in its parent + AxPairData aDistance = mxSiteModel->getPosition(); + + /* For group boxes: add half of the font height to Y position (VBA + positions relative to frame border line, not to 'top' of frame). */ + const AxFontDataModel* pFontModel = dynamic_cast< const AxFontDataModel* >( mxCtrlModel.get() ); + if( pFontModel && (pFontModel->getControlType() == API_CONTROL_GROUPBOX) ) + { + // convert points to 1/100 mm (1 pt = 1/72 inch = 2.54/72 cm = 2540/72 1/100 mm) + sal_Int32 nFontHeight = static_cast< sal_Int32 >( pFontModel->getFontHeight() * 2540 / 72 ); + aDistance.second += nFontHeight / 2; + } + + // move the embedded controls + maControls.forEachMem( &VbaFormControl::moveRelative, ::boost::cref( aDistance ) ); + } +} + +/*static*/ bool VbaFormControl::compareByTabIndex( const VbaFormControlRef& rxLeft, const VbaFormControlRef& rxRight ) +{ + // sort controls without model to the end + sal_Int32 nLeftTabIndex = rxLeft->mxSiteModel.get() ? rxLeft->mxSiteModel->getTabIndex() : SAL_MAX_INT32; + sal_Int32 nRightTabIndex = rxRight->mxSiteModel.get() ? rxRight->mxSiteModel->getTabIndex() : SAL_MAX_INT32; + return nLeftTabIndex < nRightTabIndex; +} + +// ============================================================================ + +namespace { + +OUString lclGetQuotedString( const OUString& rCodeLine ) +{ + OUStringBuffer aBuffer; + sal_Int32 nLen = rCodeLine.getLength(); + if( (nLen > 0) && (rCodeLine[ 0 ] == '"') ) + { + bool bExitLoop = false; + for( sal_Int32 nIndex = 1; !bExitLoop && (nIndex < nLen); ++nIndex ) + { + sal_Unicode cChar = rCodeLine[ nIndex ]; + // exit on closing quote char (but check on double quote chars) + bExitLoop = (cChar == '"') && ((nIndex + 1 == nLen) || (rCodeLine[ nIndex + 1 ] != '"')); + if( !bExitLoop ) + { + aBuffer.append( cChar ); + // skip second quote char + if( cChar == '"' ) + ++nIndex; + } + } + } + return aBuffer.makeStringAndClear(); +} + +bool lclEatWhitespace( OUString& rCodeLine ) +{ + sal_Int32 nIndex = 0; + while( (nIndex < rCodeLine.getLength()) && ((rCodeLine[ nIndex ] == ' ') || (rCodeLine[ nIndex ] == '\t')) ) + ++nIndex; + if( nIndex > 0 ) + { + rCodeLine = rCodeLine.copy( nIndex ); + return true; + } + return false; +} + +bool lclEatKeyword( OUString& rCodeLine, const OUString& rKeyword ) +{ + if( rCodeLine.matchIgnoreAsciiCase( rKeyword ) ) + { + rCodeLine = rCodeLine.copy( rKeyword.getLength() ); + // success, if code line ends after keyword, or if whitespace follows + return (rCodeLine.getLength() == 0) || lclEatWhitespace( rCodeLine ); + } + return false; +} + +} // namespace + +// ---------------------------------------------------------------------------- + +VbaUserForm::VbaUserForm( const Reference< XMultiServiceFactory >& rxGlobalFactory, + const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr ) : + ControlConverter( rGraphicHelper, bDefaultColorBgr ), + mxGlobalFactory( rxGlobalFactory ) +{ + OSL_ENSURE( mxGlobalFactory.is(), "VbaUserForm::VbaUserForm - missing service factory" ); +} + +void VbaUserForm::importForm( const Reference< XNameContainer >& rxDialogLib, + StorageBase& rVbaFormStrg, const OUString& rModuleName, rtl_TextEncoding eTextEnc ) +{ + OSL_ENSURE( rxDialogLib.is(), "VbaUserForm::importForm - missing dialog library" ); + if( !mxGlobalFactory.is() || !rxDialogLib.is() ) + return; + + // check that the '03VBFrame' stream exists, this is required for forms + BinaryXInputStream aInStrm( rVbaFormStrg.openInputStream( CREATE_OUSTRING( "\003VBFrame" ) ), true ); + OSL_ENSURE( !aInStrm.isEof(), "VbaUserForm::importForm - missing \\003VBFrame stream" ); + if( aInStrm.isEof() ) + return; + + // scan for the line 'Begin {GUID} <FormName>' + TextInputStream aFrameTextStrm( aInStrm, eTextEnc ); + const OUString aBegin = CREATE_OUSTRING( "Begin" ); + OUString aLine; + bool bBeginFound = false; + while( !bBeginFound && !aFrameTextStrm.isEof() ) + { + aLine = aFrameTextStrm.readLine().trim(); + bBeginFound = lclEatKeyword( aLine, aBegin ); + } + // check for the specific GUID that represents VBA forms + if( !bBeginFound || !lclEatKeyword( aLine, CREATE_OUSTRING( "{C62A69F0-16DC-11CE-9E98-00AA00574A4F}" ) ) ) + return; + + // remaining line is the form name + OUString aFormName = aLine.trim(); + OSL_ENSURE( aFormName.getLength() > 0, "VbaUserForm::importForm - missing form name" ); + OSL_ENSURE( rModuleName.equalsIgnoreAsciiCase( aFormName ), "VbaUserForm::importFrameStream - form and module name mismatch" ); + if( aFormName.getLength() == 0 ) + aFormName = rModuleName; + if( aFormName.getLength() == 0 ) + return; + mxSiteModel.reset( new VbaSiteModel ); + mxSiteModel->importProperty( XML_Name, aFormName ); + + // read the form properties (caption is contained in this '03VBFrame' stream, not in the 'f' stream) + mxCtrlModel.reset( new AxUserFormModel ); + OUString aKey, aValue; + bool bExitLoop = false; + while( !bExitLoop && !aFrameTextStrm.isEof() ) + { + aLine = aFrameTextStrm.readLine().trim(); + bExitLoop = aLine.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "End" ) ); + if( !bExitLoop && VbaHelper::extractKeyValue( aKey, aValue, aLine ) ) + { + if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Caption" ) ) ) + mxCtrlModel->importProperty( XML_Caption, lclGetQuotedString( aValue ) ); + else if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Tag" ) ) ) + mxSiteModel->importProperty( XML_Tag, lclGetQuotedString( aValue ) ); + } + } + + // use generic container control functionality to import the embedded controls + importStorage( rVbaFormStrg, AxClassTable() ); + + try + { + // create the dialog model + OUString aServiceName = mxCtrlModel->getServiceName(); + Reference< XControlModel > xDialogModel( mxGlobalFactory->createInstance( aServiceName ), UNO_QUERY_THROW ); + Reference< XNameContainer > xDialogNC( xDialogModel, UNO_QUERY_THROW ); + + // convert properties and embedded controls + if( convertProperties( xDialogModel, *this, 0 ) ) + { + // export the dialog to XML and insert it into the dialog library + PropertySet aFactoryProps( mxGlobalFactory ); + Reference< XComponentContext > xCompContext( aFactoryProps.getAnyProperty( PROP_DefaultContext ), UNO_QUERY_THROW ); + Reference< XInputStreamProvider > xDialogSource( ::xmlscript::exportDialogModel( xDialogNC, xCompContext ), UNO_SET_THROW ); + OSL_ENSURE( !rxDialogLib->hasByName( aFormName ), "VbaUserForm::importForm - multiple dialogs with equal name" ); + ContainerHelper::insertByName( rxDialogLib, aFormName, Any( xDialogSource ) ); + } + } + catch( Exception& ) + { + } +} + +// ============================================================================ + +} // namespace ole +} // namespace oox diff --git a/oox/source/ole/vbahelper.cxx b/oox/source/ole/vbahelper.cxx new file mode 100755 index 000000000000..3bf72d30bfa5 --- /dev/null +++ b/oox/source/ole/vbahelper.cxx @@ -0,0 +1,85 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/ole/vbahelper.hxx" +#include <rtl/ustrbuf.hxx> +#include "oox/helper/binaryinputstream.hxx" + +namespace oox { +namespace ole { + +using ::rtl::OUString; +using ::rtl::OUStringBuffer; +using namespace ::com::sun::star::uno; + +// ============================================================================ + +/*static*/ OUString VbaHelper::getBasicScriptUrl( + const OUString& rLibraryName, const OUString& rModuleName, const OUString& rMacroName ) +{ + OSL_ENSURE( rLibraryName.getLength() > 0, "VbaHelper::getBasicScriptUrl - library name is empty" ); + OSL_ENSURE( rModuleName.getLength() > 0, "VbaHelper::getBasicScriptUrl - module name is empty" ); + OSL_ENSURE( rMacroName.getLength() > 0, "VbaHelper::getBasicScriptUrl - macro name is empty" ); + const sal_Unicode cDot = '.'; + return OUStringBuffer(). + appendAscii( RTL_CONSTASCII_STRINGPARAM( "vnd.sun.star.script:" ) ). + append( rLibraryName ).append( cDot ).append( rModuleName ).append( cDot ).append( rMacroName ). + appendAscii( RTL_CONSTASCII_STRINGPARAM( "?language=Basic&location=document" ) ). + makeStringAndClear(); +} + +/*static*/ bool VbaHelper::readDirRecord( sal_uInt16& rnRecId, StreamDataSequence& rRecData, BinaryInputStream& rInStrm ) +{ + // read the record header + sal_Int32 nRecSize; + rInStrm >> rnRecId >> nRecSize; + // for no obvious reason, PROJECTVERSION record contains size field of 4, but is 6 bytes long + if( rnRecId == VBA_ID_PROJECTVERSION ) + { + OSL_ENSURE( nRecSize == 4, "VbaHelper::readDirRecord - unexpected record size for PROJECTVERSION" ); + nRecSize = 6; + } + // read the record contents into the passed sequence + return !rInStrm.isEof() && (rInStrm.readData( rRecData, nRecSize ) == nRecSize); +} + +/*static*/ bool VbaHelper::extractKeyValue( OUString& rKey, OUString& rValue, const OUString& rKeyValue ) +{ + sal_Int32 nEqSignPos = rKeyValue.indexOf( '=' ); + if( nEqSignPos > 0 ) + { + rKey = rKeyValue.copy( 0, nEqSignPos ).trim(); + rValue = rKeyValue.copy( nEqSignPos + 1 ).trim(); + return (rKey.getLength() > 0) && (rValue.getLength() > 0); + } + return false; +} + +// ============================================================================ + +} // namespace ole +} // namespace oox diff --git a/oox/source/ole/vbainputstream.cxx b/oox/source/ole/vbainputstream.cxx new file mode 100644 index 000000000000..b2c8d5c64859 --- /dev/null +++ b/oox/source/ole/vbainputstream.cxx @@ -0,0 +1,185 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/ole/vbainputstream.hxx" +#include <osl/diagnose.h> + +namespace oox { +namespace ole { + +namespace { + +const sal_uInt8 VBASTREAM_SIGNATURE = 1; + +const sal_uInt16 VBACHUNK_SIGMASK = 0x7000; +const sal_uInt16 VBACHUNK_SIG = 0x3000; +const sal_uInt16 VBACHUNK_COMPRESSED = 0x8000; +const sal_uInt16 VBACHUNK_LENMASK = 0x0FFF; + +} // namespace + +// ============================================================================ + +VbaInputStream::VbaInputStream( BinaryInputStream& rInStrm ) : + mrInStrm( rInStrm ), + mnChunkPos( 0 ) +{ + maChunk.reserve( 4096 ); + + sal_uInt8 nSig = mrInStrm.readuInt8(); + OSL_ENSURE( nSig == VBASTREAM_SIGNATURE, "VbaInputStream::VbaInputStream - wrong signature" ); + mbEof = nSig != VBASTREAM_SIGNATURE; +} + +sal_Int32 VbaInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes ) +{ + sal_Int32 nRet = 0; + if( !mbEof ) + { + orData.realloc( ::std::max< sal_Int32 >( nBytes, 0 ) ); + if( nBytes > 0 ) + { + nRet = readMemory( orData.getArray(), nBytes ); + if( nRet < nBytes ) + orData.realloc( nRet ); + } + } + return nRet; +} + +sal_Int32 VbaInputStream::readMemory( void* opMem, sal_Int32 nBytes ) +{ + sal_Int32 nRet = 0; + sal_uInt8* opnMem = reinterpret_cast< sal_uInt8* >( opMem ); + while( (nBytes > 0) && updateChunk() ) + { + sal_Int32 nChunkLeft = static_cast< sal_Int32 >( maChunk.size() - mnChunkPos ); + sal_Int32 nReadBytes = ::std::min( nBytes, nChunkLeft ); + memcpy( opnMem, &*(maChunk.begin() + mnChunkPos), nReadBytes ); + opnMem += nReadBytes; + mnChunkPos += static_cast< size_t >( nReadBytes ); + nBytes -= nReadBytes; + nRet += nReadBytes; + } + return nRet; +} + +void VbaInputStream::skip( sal_Int32 nBytes ) +{ + while( (nBytes > 0) && updateChunk() ) + { + sal_Int32 nChunkLeft = static_cast< sal_Int32 >( maChunk.size() - mnChunkPos ); + sal_Int32 nSkipBytes = ::std::min( nBytes, nChunkLeft ); + mnChunkPos += static_cast< size_t >( nSkipBytes ); + nBytes -= nSkipBytes; + } +} + +// private -------------------------------------------------------------------- + +bool VbaInputStream::updateChunk() +{ + if( mbEof || (mnChunkPos < maChunk.size()) ) return !mbEof; + + // try to read next chunk header, this may trigger EOF + sal_uInt16 nHeader = mrInStrm.readuInt16(); + mbEof = mrInStrm.isEof(); + if( mbEof ) return false; + + // check header signature + OSL_ENSURE( (nHeader & VBACHUNK_SIGMASK) == VBACHUNK_SIG, "VbaInputStream::updateChunk - invalid chunk signature" ); + mbEof = (nHeader & VBACHUNK_SIGMASK) != VBACHUNK_SIG; + if( mbEof ) return false; + + // decode length of chunk data and compression flag + bool bCompressed = getFlag( nHeader, VBACHUNK_COMPRESSED ); + sal_uInt16 nChunkLen = (nHeader & VBACHUNK_LENMASK) + 1; + OSL_ENSURE( bCompressed || (nChunkLen == 4096), "VbaInputStream::updateChunk - invalid uncompressed chunk size" ); + if( bCompressed ) + { + maChunk.clear(); + sal_uInt8 nBitCount = 4; + sal_uInt16 nChunkPos = 0; + while( !mbEof && !mrInStrm.isEof() && (nChunkPos < nChunkLen) ) + { + sal_uInt8 nTokenFlags = mrInStrm.readuInt8(); + ++nChunkPos; + for( int nBit = 0; !mbEof && !mrInStrm.isEof() && (nBit < 8) && (nChunkPos < nChunkLen); ++nBit, nTokenFlags >>= 1 ) + { + if( nTokenFlags & 1 ) + { + sal_uInt16 nCopyToken = mrInStrm.readuInt16(); + nChunkPos = nChunkPos + 2; + // update bit count used for offset/length in the token + while( static_cast< size_t >( 1 << nBitCount ) < maChunk.size() ) ++nBitCount; + // extract length from lower (16-nBitCount) bits, plus 3 + sal_uInt16 nLength = extractValue< sal_uInt16 >( nCopyToken, 0, 16 - nBitCount ) + 3; + // extract offset from high nBitCount bits, plus 1 + sal_uInt16 nOffset = extractValue< sal_uInt16 >( nCopyToken, 16 - nBitCount, nBitCount ) + 1; + mbEof = (nOffset > maChunk.size()) || (maChunk.size() + nLength > 4096); + OSL_ENSURE( !mbEof, "VbaInputStream::updateChunk - invalid offset or size in copy token" ); + if( !mbEof ) + { + // append data to buffer + maChunk.resize( maChunk.size() + nLength ); + sal_uInt8* pnTo = &*(maChunk.end() - nLength); + const sal_uInt8* pnEnd = pnTo + nLength; + const sal_uInt8* pnFrom = pnTo - nOffset; + // offset may be less than length, effectively duplicating source data several times + size_t nRunLen = ::std::min< size_t >( nLength, nOffset ); + while( pnTo < pnEnd ) + { + size_t nStepLen = ::std::min< size_t >( nRunLen, pnEnd - pnTo ); + memcpy( pnTo, pnFrom, nStepLen ); + pnTo += nStepLen; + } + } + } + else + { + maChunk.resize( maChunk.size() + 1 ); + mrInStrm >> maChunk.back(); + ++nChunkPos; + } + } + } + } + else + { + maChunk.resize( nChunkLen ); + mrInStrm.readMemory( &maChunk.front(), nChunkLen ); + } + + mnChunkPos = 0; + return !mbEof; +} + +// ============================================================================ + +} // namespace ole +} // namespace oox + diff --git a/oox/source/ole/vbamodule.cxx b/oox/source/ole/vbamodule.cxx new file mode 100755 index 000000000000..9886f2cc5968 --- /dev/null +++ b/oox/source/ole/vbamodule.cxx @@ -0,0 +1,235 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/ole/vbamodule.hxx" +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/script/ModuleInfo.hpp> +#include <com/sun/star/script/ModuleType.hpp> +#include <com/sun/star/script/vba/XVBAModuleInfo.hpp> +#include "oox/helper/binaryinputstream.hxx" +#include "oox/helper/storagebase.hxx" +#include "oox/helper/textinputstream.hxx" +#include "oox/ole/vbahelper.hxx" +#include "oox/ole/vbainputstream.hxx" + +using ::rtl::OUString; +using ::rtl::OUStringBuffer; + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::script; +using namespace ::com::sun::star::script::vba; +using namespace ::com::sun::star::uno; + +namespace oox { +namespace ole { + +// ============================================================================ + +VbaModule::VbaModule( const Reference< XModel >& rxDocModel, const OUString& rName, rtl_TextEncoding eTextEnc, bool bExecutable ) : + mxDocModel( rxDocModel ), + maName( rName ), + meTextEnc( eTextEnc ), + mnType( ModuleType::UNKNOWN ), + mnOffset( SAL_MAX_UINT32 ), + mbReadOnly( false ), + mbPrivate( false ), + mbExecutable( bExecutable ) +{ +} + +void VbaModule::importDirRecords( BinaryInputStream& rDirStrm ) +{ + sal_uInt16 nRecId = 0; + StreamDataSequence aRecData; + while( VbaHelper::readDirRecord( nRecId, aRecData, rDirStrm ) && (nRecId != VBA_ID_MODULEEND) ) + { + SequenceInputStream aRecStrm( aRecData ); + sal_Int32 nRecSize = aRecData.getLength(); + switch( nRecId ) + { +#define OOX_ENSURE_RECORDSIZE( cond ) OSL_ENSURE( cond, "VbaModule::importDirRecords - invalid record size" ) + case VBA_ID_MODULENAME: + OSL_ENSURE( false, "VbaModule::importDirRecords - unexpected MODULENAME record" ); + maName = aRecStrm.readCharArrayUC( nRecSize, meTextEnc ); + break; + case VBA_ID_MODULENAMEUNICODE: + break; + case VBA_ID_MODULESTREAMNAME: + maStreamName = aRecStrm.readCharArrayUC( nRecSize, meTextEnc ); + break; + case VBA_ID_MODULESTREAMNAMEUNICODE: + break; + case VBA_ID_MODULEDOCSTRING: + maDocString = aRecStrm.readCharArrayUC( nRecSize, meTextEnc ); + break; + case VBA_ID_MODULEDOCSTRINGUNICODE: + break; + case VBA_ID_MODULEOFFSET: + OOX_ENSURE_RECORDSIZE( nRecSize == 4 ); + aRecStrm >> mnOffset; + break; + case VBA_ID_MODULEHELPCONTEXT: + OOX_ENSURE_RECORDSIZE( nRecSize == 4 ); + break; + case VBA_ID_MODULECOOKIE: + OOX_ENSURE_RECORDSIZE( nRecSize == 2 ); + break; + case VBA_ID_MODULETYPEPROCEDURAL: + OOX_ENSURE_RECORDSIZE( nRecSize == 0 ); + OSL_ENSURE( mnType == ModuleType::UNKNOWN, "VbaModule::importDirRecords - multiple module type records" ); + mnType = ModuleType::NORMAL; + break; + case VBA_ID_MODULETYPEDOCUMENT: + OOX_ENSURE_RECORDSIZE( nRecSize == 0 ); + OSL_ENSURE( mnType == ModuleType::UNKNOWN, "VbaModule::importDirRecords - multiple module type records" ); + mnType = ModuleType::DOCUMENT; + break; + case VBA_ID_MODULEREADONLY: + OOX_ENSURE_RECORDSIZE( nRecSize == 0 ); + mbReadOnly = true; + break; + case VBA_ID_MODULEPRIVATE: + OOX_ENSURE_RECORDSIZE( nRecSize == 0 ); + mbPrivate = true; + break; + default: + OSL_ENSURE( false, "VbaModule::importDirRecords - unknown module record" ); +#undef OOX_ENSURE_RECORDSIZE + } + } + OSL_ENSURE( maName.getLength() > 0, "VbaModule::importDirRecords - missing module name" ); + OSL_ENSURE( maStreamName.getLength() > 0, "VbaModule::importDirRecords - missing module stream name" ); + OSL_ENSURE( mnType != ModuleType::UNKNOWN, "VbaModule::importDirRecords - missing module type" ); + OSL_ENSURE( mnOffset < SAL_MAX_UINT32, "VbaModule::importDirRecords - missing module stream offset" ); +} + +void VbaModule::importSourceCode( StorageBase& rVbaStrg, + const Reference< XNameContainer >& rxBasicLib, const Reference< XNameAccess >& rxDocObjectNA ) const +{ + if( (maName.getLength() == 0) || (maStreamName.getLength() == 0) || (mnOffset == SAL_MAX_UINT32) ) + return; + + BinaryXInputStream aInStrm( rVbaStrg.openInputStream( maStreamName ), true ); + OSL_ENSURE( !aInStrm.isEof(), "VbaModule::importSourceCode - cannot open module stream" ); + // skip the 'performance cache' stored before the actual source code + aInStrm.seek( mnOffset ); + // if stream is still valid, load the source code + if( aInStrm.isEof() ) + return; + + // prepare the Basic module + ModuleInfo aModuleInfo; + aModuleInfo.ModuleType = mnType; + OUStringBuffer aSourceCode; + aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Rem Attribute VBA_ModuleType=" ) ); + switch( mnType ) + { + case ModuleType::NORMAL: + aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBAModule" ) ); + break; + case ModuleType::CLASS: + aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBAClassModule" ) ); + break; + case ModuleType::FORM: + aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBAFormModule" ) ); + // hack from old filter, document Basic should know the XModel, but it doesn't + aModuleInfo.ModuleObject.set( mxDocModel, UNO_QUERY ); + break; + case ModuleType::DOCUMENT: + aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBADocumentModule" ) ); + // get the VBA object associated to the document module + if( rxDocObjectNA.is() ) try + { + aModuleInfo.ModuleObject.set( rxDocObjectNA->getByName( maName ), UNO_QUERY ); + } + catch( Exception& ) + { + } + break; + default: + aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBAUnknown" ) ); + } + aSourceCode.append( sal_Unicode( '\n' ) ); + if( mbExecutable ) + { + aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Option VBASupport 1\n" ) ); + if( mnType == ModuleType::CLASS ) + aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Option ClassModule\n" ) ); + } + else + { + // add a subroutine named after the module itself + aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Sub " ) ). + append( maName.replace( ' ', '_' ) ).append( sal_Unicode( '\n' ) ); + } + + // decompression starts at current stream position of aInStrm + VbaInputStream aVbaStrm( aInStrm ); + // load the source code line-by-line, with some more processing + TextInputStream aVbaTextStrm( aVbaStrm, meTextEnc ); + while( !aVbaTextStrm.isEof() ) + { + OUString aCodeLine = aVbaTextStrm.readLine(); + // skip all 'Attribute' statements + if( !aCodeLine.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "Attribute " ) ) ) + { + if( !mbExecutable ) + aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Rem " ) ); + aSourceCode.append( aCodeLine ).append( sal_Unicode( '\n' ) ); + } + } + + // close the subroutine named after the module + if( !mbExecutable ) + aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "End Sub\n" ) ); + + // insert extended module info + try + { + Reference< XVBAModuleInfo > xVBAModuleInfo( rxBasicLib, UNO_QUERY_THROW ); + xVBAModuleInfo->insertModuleInfo( maName, aModuleInfo ); + } + catch( Exception& ) + { + } + + // insert the module into the passed Basic library + try + { + rxBasicLib->insertByName( maName, Any( aSourceCode.makeStringAndClear() ) ); + } + catch( Exception& ) + { + OSL_ENSURE( false, "VbaModule::importSourceCode - cannot insert module into library" ); + } +} + +// ============================================================================ + +} // namespace ole +} // namespace oox diff --git a/oox/source/ole/vbaproject.cxx b/oox/source/ole/vbaproject.cxx new file mode 100755 index 000000000000..deff066a5ed5 --- /dev/null +++ b/oox/source/ole/vbaproject.cxx @@ -0,0 +1,453 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/ole/vbaproject.hxx" +#include <com/sun/star/document/XStorageBasedDocument.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/script/ModuleType.hpp> +#include <com/sun/star/script/XLibraryContainer.hpp> +#include <com/sun/star/script/vba/XVBACompatibility.hpp> +#include <rtl/tencinfo.h> +#include <rtl/ustrbuf.h> +#include <comphelper/configurationhelper.hxx> +#include <comphelper/string.hxx> +#include "properties.hxx" +#include "tokens.hxx" +#include "oox/helper/binaryinputstream.hxx" +#include "oox/helper/containerhelper.hxx" +#include "oox/helper/propertyset.hxx" +#include "oox/helper/textinputstream.hxx" +#include "oox/ole/olestorage.hxx" +#include "oox/ole/vbacontrol.hxx" +#include "oox/ole/vbahelper.hxx" +#include "oox/ole/vbainputstream.hxx" +#include "oox/ole/vbamodule.hxx" + +using ::rtl::OUString; +using ::rtl::OUStringBuffer; +using ::comphelper::ConfigurationHelper; + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::script; +using namespace ::com::sun::star::script::vba; +using namespace ::com::sun::star::uno; + +namespace oox { +namespace ole { + +// ============================================================================ + +namespace { + +bool lclReadConfigItem( const Reference< XInterface >& rxConfigAccess, const OUString& rItemName ) +{ + // some applications do not support all configuration items, assume 'false' in this case + try + { + Any aItem = ConfigurationHelper::readRelativeKey( rxConfigAccess, CREATE_OUSTRING( "Filter/Import/VBA" ), rItemName ); + return aItem.has< bool >() && aItem.get< bool >(); + } + catch( Exception& ) + { + } + return false; +} + +} // namespace + +// ---------------------------------------------------------------------------- + +VbaFilterConfig::VbaFilterConfig( const Reference< XMultiServiceFactory >& rxGlobalFactory, const OUString& rConfigCompName ) +{ + OSL_ENSURE( rxGlobalFactory.is(), "VbaFilterConfig::VbaFilterConfig - missing service factory" ); + try + { + OSL_ENSURE( rConfigCompName.getLength() > 0, "VbaFilterConfig::VbaFilterConfig - invalid configuration component name" ); + OUString aConfigPackage = CREATE_OUSTRING( "org.openoffice.Office." ) + rConfigCompName; + mxConfigAccess = ConfigurationHelper::openConfig( rxGlobalFactory, aConfigPackage, ConfigurationHelper::E_READONLY ); + } + catch( Exception& ) + { + } + OSL_ENSURE( mxConfigAccess.is(), "VbaFilterConfig::VbaFilterConfig - cannot open configuration" ); +} + +VbaFilterConfig::~VbaFilterConfig() +{ +} + +bool VbaFilterConfig::isImportVba() const +{ + return lclReadConfigItem( mxConfigAccess, CREATE_OUSTRING( "Load" ) ); +} + +bool VbaFilterConfig::isImportVbaExecutable() const +{ + return lclReadConfigItem( mxConfigAccess, CREATE_OUSTRING( "Executable" ) ); +} + +bool VbaFilterConfig::isExportVba() const +{ + return lclReadConfigItem( mxConfigAccess, CREATE_OUSTRING( "Save" ) ); +} + +// ============================================================================ + +VbaProject::VbaProject( const Reference< XMultiServiceFactory >& rxGlobalFactory, + const Reference< XModel >& rxDocModel, const OUString& rConfigCompName ) : + VbaFilterConfig( rxGlobalFactory, rConfigCompName ), + mxGlobalFactory( rxGlobalFactory ), + mxDocModel( rxDocModel ), + maLibName( CREATE_OUSTRING( "Standard" ) ) +{ + OSL_ENSURE( mxDocModel.is(), "VbaProject::VbaProject - missing document model" ); + mxBasicLib = openLibrary( PROP_BasicLibraries, false ); + mxDialogLib = openLibrary( PROP_DialogLibraries, false ); +} + +VbaProject::~VbaProject() +{ +} + +void VbaProject::importVbaProject( StorageBase& rVbaPrjStrg, const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr ) +{ + if( rVbaPrjStrg.isStorage() ) + { + // load the code modules and forms + if( isImportVba() ) + importVba( rVbaPrjStrg, rGraphicHelper, bDefaultColorBgr ); + // copy entire storage into model + if( isExportVba() ) + copyStorage( rVbaPrjStrg ); + } +} + +bool VbaProject::hasModules() const +{ + return mxBasicLib.is() && mxBasicLib->hasElements(); +} + +bool VbaProject::hasModule( const OUString& rModuleName ) const +{ + return mxBasicLib.is() && mxBasicLib->hasByName( rModuleName ); +} + +bool VbaProject::hasDialogs() const +{ + return mxDialogLib.is() && mxDialogLib->hasElements(); +} + +bool VbaProject::hasDialog( const OUString& rDialogName ) const +{ + return mxDialogLib.is() && mxDialogLib->hasByName( rDialogName ); +} + +// private -------------------------------------------------------------------- + +Reference< XLibraryContainer > VbaProject::getLibraryContainer( sal_Int32 nPropId ) +{ + PropertySet aDocProp( mxDocModel ); + Reference< XLibraryContainer > xLibContainer( aDocProp.getAnyProperty( nPropId ), UNO_QUERY ); + return xLibContainer; +} + +Reference< XNameContainer > VbaProject::openLibrary( sal_Int32 nPropId, bool bCreateMissing ) +{ + Reference< XNameContainer > xLibrary; + try + { + Reference< XLibraryContainer > xLibContainer( getLibraryContainer( nPropId ), UNO_SET_THROW ); + if( bCreateMissing && !xLibContainer->hasByName( maLibName ) ) + xLibContainer->createLibrary( maLibName ); + xLibrary.set( xLibContainer->getByName( maLibName ), UNO_QUERY_THROW ); + } + catch( Exception& ) + { + } + OSL_ENSURE( !bCreateMissing || xLibrary.is(), "VbaProject::openLibrary - cannot create library" ); + return xLibrary; +} + +Reference< XNameContainer > VbaProject::createBasicLibrary() +{ + if( !mxBasicLib.is() ) + mxBasicLib = openLibrary( PROP_BasicLibraries, true ); + return mxBasicLib; +} + +Reference< XNameContainer > VbaProject::createDialogLibrary() +{ + if( !mxDialogLib.is() ) + mxDialogLib = openLibrary( PROP_DialogLibraries, true ); + return mxDialogLib; +} + +void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr ) +{ + StorageRef xVbaStrg = rVbaPrjStrg.openSubStorage( CREATE_OUSTRING( "VBA" ), false ); + OSL_ENSURE( xVbaStrg.get(), "VbaProject::importVba - cannot open 'VBA' substorage" ); + if( !xVbaStrg ) + return; + + /* Read the 'VBA/dir' stream which contains general settings of the VBA + project such as the text encoding used throughout several streams, and + a list of all code modules. + */ + BinaryXInputStream aInStrm( xVbaStrg->openInputStream( CREATE_OUSTRING( "dir" ) ), true ); + // VbaInputStream implements decompression + VbaInputStream aDirStrm( aInStrm ); + OSL_ENSURE( !aDirStrm.isEof(), "VbaProject::importVba - cannot open 'dir' stream" ); + if( aDirStrm.isEof() ) + return; + + // read all records of the directory + rtl_TextEncoding eTextEnc = RTL_TEXTENCODING_MS_1252; + sal_uInt16 nModuleCount = 0; + bool bExecutable = isImportVbaExecutable(); + + typedef RefMap< OUString, VbaModule > VbaModuleMap; + VbaModuleMap aModules, aModulesByStrm; + + sal_uInt16 nRecId = 0; + StreamDataSequence aRecData; + while( VbaHelper::readDirRecord( nRecId, aRecData, aDirStrm ) && (nRecId != VBA_ID_PROJECTEND) ) + { + // create record stream object from imported record data + SequenceInputStream aRecStrm( aRecData ); + sal_Int32 nRecSize = aRecData.getLength(); + switch( nRecId ) + { +#define OOX_ENSURE_RECORDSIZE( cond ) OSL_ENSURE( cond, "VbaProject::importVba - invalid record size" ) + case VBA_ID_PROJECTCODEPAGE: + { + OOX_ENSURE_RECORDSIZE( nRecSize == 2 ); + OSL_ENSURE( aModules.empty(), "VbaProject::importVba - unexpected PROJECTCODEPAGE record" ); + rtl_TextEncoding eNewTextEnc = rtl_getTextEncodingFromWindowsCodePage( aRecStrm.readuInt16() ); + OSL_ENSURE( eNewTextEnc != RTL_TEXTENCODING_DONTKNOW, "VbaProject::importVba - unknown text encoding" ); + if( eNewTextEnc != RTL_TEXTENCODING_DONTKNOW ) + eTextEnc = eNewTextEnc; + } + break; + case VBA_ID_PROJECTMODULES: + OOX_ENSURE_RECORDSIZE( nRecSize == 2 ); + OSL_ENSURE( aModules.empty(), "VbaProject::importVba - unexpected PROJECTMODULES record" ); + aRecStrm >> nModuleCount; + break; + case VBA_ID_MODULENAME: + { + OUString aName = aRecStrm.readCharArrayUC( nRecSize, eTextEnc ); + OSL_ENSURE( aName.getLength() > 0, "VbaProject::importVba - invalid module name" ); + OSL_ENSURE( !aModules.has( aName ), "VbaProject::importVba - multiple modules with the same name" ); + VbaModuleMap::mapped_type& rxModule = aModules[ aName ]; + rxModule.reset( new VbaModule( mxDocModel, aName, eTextEnc, bExecutable ) ); + // read all remaining records until the MODULEEND record + rxModule->importDirRecords( aDirStrm ); + OSL_ENSURE( !aModulesByStrm.has( rxModule->getStreamName() ), "VbaProject::importVba - multiple modules with the same stream name" ); + aModulesByStrm[ rxModule->getStreamName() ] = rxModule; + } + break; +#undef OOX_ENSURE_RECORDSIZE + } + } + OSL_ENSURE( nModuleCount == aModules.size(), "VbaProject::importVba - invalid module count" ); + + /* The directory does not contain the real type of the modules, it + distinguishes only between 'procedural' and 'document' (the latter + includes class and form modules). Now, the exact type of all modules + will be read from the 'PROJECT' stream. It consists of text lines in + 'key=value' format which list the code modules by type. + + - The line 'document=<modulename>/&HXXXXXXXX' declares document + modules. These are attached to the Word document (usually called + 'ThisDocument'), the Excel workbook (usually called + 'ThisWorkbook'), or single Excel worksheets or chartsheets (usually + called 'SheetX' or 'ChartX', X being a decimal number). Of course, + users may rename all these modules. The slash character separates + an automation server version number (hexadecimal 'XXXXXXXX') from + the module name. + - The line 'Module=<modulename>' declares common procedural code + modules. + - The line 'Class=<modulename>' declares a class module. + - The line 'BaseClass=<modulename>' declares a code module attached + to a user form with the same name. + */ + BinaryXInputStream aPrjStrm( rVbaPrjStrg.openInputStream( CREATE_OUSTRING( "PROJECT" ) ), true ); + OSL_ENSURE( !aPrjStrm.isEof(), "VbaProject::importVba - cannot open 'PROJECT' stream" ); + // do not exit if this stream does not exist, but proceed to load the modules below + if( !aPrjStrm.isEof() ) + { + TextInputStream aPrjTextStrm( aPrjStrm, eTextEnc ); + OUString aKey, aValue; + bool bExitLoop = false; + while( !bExitLoop && !aPrjTextStrm.isEof() ) + { + // read a text line from the stream + OUString aLine = aPrjTextStrm.readLine().trim(); + sal_Int32 nLineLen = aLine.getLength(); + // exit if a subsection starts (section name is given in brackets) + bExitLoop = (nLineLen >= 2) && (aLine[ 0 ] == '[') && (aLine[ nLineLen - 1 ] == ']'); + if( !bExitLoop && VbaHelper::extractKeyValue( aKey, aValue, aLine ) ) + { + sal_Int32 nType = ModuleType::UNKNOWN; + if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Document" ) ) ) + { + nType = ModuleType::DOCUMENT; + // strip automation server version from module names + sal_Int32 nSlashPos = aValue.indexOf( '/' ); + if( nSlashPos >= 0 ) + aValue = aValue.copy( 0, nSlashPos ); + } + else if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Module" ) ) ) + nType = ModuleType::NORMAL; + else if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Class" ) ) ) + nType = ModuleType::CLASS; + else if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "BaseClass" ) ) ) + nType = ModuleType::FORM; + + if( (nType != ModuleType::UNKNOWN) && (aValue.getLength() > 0) ) + { + OSL_ENSURE( aModules.has( aValue ), "VbaProject::importVba - module not found" ); + if( VbaModule* pModule = aModules.get( aValue ).get() ) + pModule->setType( nType ); + } + } + } + } + + /* Now it is time to load the source code. All modules will be inserted + into the Basic library of the document specified by the 'maLibName' + member. Do not create the Basic library, if there are no modules + specified. */ + if( !aModules.empty() ) try + { + // get the model factory and the basic library + Reference< XMultiServiceFactory > xModelFactory( mxDocModel, UNO_QUERY_THROW ); + Reference< XNameContainer > xBasicLib( createBasicLibrary(), UNO_SET_THROW ); + + // set library container to VBA compatibility mode + try + { + Reference< XVBACompatibility >( getLibraryContainer( PROP_BasicLibraries ), UNO_QUERY_THROW )->setVBACompatibilityMode( sal_True ); + } + catch( Exception& ) + { + } + + // create the VBAGlobals object, the model will store it in the Basic manager + try + { + xModelFactory->createInstance( CREATE_OUSTRING( "ooo.vba.VBAGlobals" ) ); + } + catch( Exception& ) + { + } + + // try to get access to document objects related to code modules + Reference< XNameAccess > xDocObjectNA; + try + { + xDocObjectNA.set( xModelFactory->createInstance( CREATE_OUSTRING( "ooo.vba.VBAObjectModuleObjectProvider" ) ), UNO_QUERY ); + } + catch( Exception& ) + { + // not all documents support this + } + + // call Basic source code import for each module, boost::[c]ref enforces pass-by-ref + if( xBasicLib.is() ) + aModules.forEachMem( &VbaModule::importSourceCode, + ::boost::ref( *xVbaStrg ), ::boost::cref( xBasicLib ), ::boost::cref( xDocObjectNA ) ); + } + catch( Exception& ) + { + } + + /* Load the forms. The file format specification requires that a module + must exist for every form. We are a bit more tolerant and scan the + project storage for all form substorages. This may 'repair' broken VBA + storages that misses to mention a module for an existing form. */ + ::std::vector< OUString > aElements; + rVbaPrjStrg.getElementNames( aElements ); + for( ::std::vector< OUString >::iterator aIt = aElements.begin(), aEnd = aElements.end(); aIt != aEnd; ++aIt ) + { + // try to open the element as storage + if( !aIt->equals( CREATE_OUSTRING( "VBA" ) ) ) + { + StorageRef xSubStrg = rVbaPrjStrg.openSubStorage( *aIt, false ); + if( xSubStrg.get() ) try + { + // resolve module name from storage name (which equals the module stream name) + VbaModule* pModule = aModulesByStrm.get( *aIt ).get(); + OSL_ENSURE( pModule && (pModule->getType() == ModuleType::FORM), + "VbaProject::importVba - form substorage without form module" ); + OUString aModuleName; + if( pModule ) + aModuleName = pModule->getName(); + + // create and import the form + Reference< XNameContainer > xDialogLib( createDialogLibrary(), UNO_SET_THROW ); + VbaUserForm aForm( mxGlobalFactory, rGraphicHelper, bDefaultColorBgr ); + aForm.importForm( xDialogLib, *xSubStrg, aModuleName, eTextEnc ); + } + catch( Exception& ) + { + } + } + } +} + +void VbaProject::copyStorage( StorageBase& rVbaPrjStrg ) +{ + try + { + Reference< XStorageBasedDocument > xStorageBasedDoc( mxDocModel, UNO_QUERY_THROW ); + Reference< XStorage > xDocStorage( xStorageBasedDoc->getDocumentStorage(), UNO_QUERY_THROW ); + { + using namespace ::com::sun::star::embed::ElementModes; + Reference< XStream > xDocStream( xDocStorage->openStreamElement( CREATE_OUSTRING( "_MS_VBA_Macros" ), SEEKABLE | WRITE | TRUNCATE ), UNO_SET_THROW ); + OleStorage aDestStorage( mxGlobalFactory, xDocStream, false ); + rVbaPrjStrg.copyStorageToStorage( aDestStorage ); + aDestStorage.commit(); + } + Reference< XTransactedObject >( xDocStorage, UNO_QUERY_THROW )->commit(); + } + catch( Exception& ) + { + } +} + +// ============================================================================ + +} // namespace ole +} // namespace oox |