1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sfx2.hxx" 26 27 #include <sfx2/docinf.hxx> 28 #include <com/sun/star/beans/PropertyAttribute.hpp> 29 #include <com/sun/star/beans/XPropertySet.hpp> 30 #include <com/sun/star/beans/XPropertyContainer.hpp> 31 #include <com/sun/star/document/XDocumentProperties.hpp> 32 #include <com/sun/star/uno/Exception.hpp> 33 #include <rtl/ustring.hxx> 34 #include <tools/debug.hxx> 35 #include <comphelper/string.hxx> 36 #include <sot/storage.hxx> 37 #include <vcl/gdimtf.hxx> 38 #include <vcl/dibtools.hxx> 39 #include "oleprops.hxx" 40 41 // ============================================================================ 42 43 // stream names 44 #define STREAM_SUMMARYINFO "\005SummaryInformation" 45 #define STREAM_DOCSUMMARYINFO "\005DocumentSummaryInformation" 46 47 // usings 48 using namespace ::com::sun::star; 49 50 51 namespace sfx2 { 52 53 sal_uInt32 SFX2_DLLPUBLIC LoadOlePropertySet( 54 uno::Reference< document::XDocumentProperties> i_xDocProps, 55 SotStorage* i_pStorage ) 56 { 57 // *** global properties from stream "005SummaryInformation" *** 58 59 // load the property set 60 SfxOlePropertySet aGlobSet; 61 ErrCode nGlobError = aGlobSet.LoadPropertySet(i_pStorage, 62 String( RTL_CONSTASCII_USTRINGPARAM( STREAM_SUMMARYINFO ) ) ); 63 64 // global section 65 SfxOleSectionRef xGlobSect = aGlobSet.GetSection( SECTION_GLOBAL ); 66 if( xGlobSect.get() ) 67 { 68 // set supported properties 69 String aStrValue; 70 util::DateTime aDateTime; 71 72 if( xGlobSect->GetStringValue( aStrValue, PROPID_TITLE ) ) 73 i_xDocProps->setTitle( aStrValue ); 74 if( xGlobSect->GetStringValue( aStrValue, PROPID_SUBJECT ) ) 75 i_xDocProps->setSubject( aStrValue ); 76 if( xGlobSect->GetStringValue( aStrValue, PROPID_KEYWORDS ) ) { 77 i_xDocProps->setKeywords( 78 ::comphelper::string::convertCommaSeparated(aStrValue) ); 79 } 80 if( xGlobSect->GetStringValue( aStrValue, PROPID_TEMPLATE ) ) 81 i_xDocProps->setTemplateName( aStrValue ); 82 if( xGlobSect->GetStringValue( aStrValue, PROPID_COMMENTS ) ) 83 i_xDocProps->setDescription( aStrValue ); 84 85 util::DateTime aInvalid; 86 if( xGlobSect->GetStringValue( aStrValue, PROPID_AUTHOR) ) 87 i_xDocProps->setAuthor( aStrValue ); 88 else 89 i_xDocProps->setAuthor( ::rtl::OUString() ); 90 if( xGlobSect->GetFileTimeValue( aDateTime, PROPID_CREATED ) ) 91 i_xDocProps->setCreationDate( aDateTime ); 92 else 93 i_xDocProps->setCreationDate( aInvalid ); 94 95 if( xGlobSect->GetStringValue( aStrValue, PROPID_LASTAUTHOR) ) 96 i_xDocProps->setModifiedBy( aStrValue ); 97 else 98 i_xDocProps->setModifiedBy( ::rtl::OUString() ); 99 if( xGlobSect->GetFileTimeValue( aDateTime, PROPID_LASTSAVED ) ) 100 i_xDocProps->setModificationDate( aDateTime ); 101 else 102 i_xDocProps->setModificationDate( aInvalid ); 103 104 i_xDocProps->setPrintedBy( ::rtl::OUString() ); 105 if( xGlobSect->GetFileTimeValue( aDateTime, PROPID_LASTPRINTED ) ) 106 i_xDocProps->setPrintDate( aDateTime ); 107 else 108 i_xDocProps->setPrintDate( aInvalid ); 109 110 if( xGlobSect->GetStringValue( aStrValue, PROPID_REVNUMBER ) ) 111 { 112 sal_Int16 nRevision = static_cast< sal_Int16 >( aStrValue.ToInt32() ); 113 if ( nRevision > 0 ) 114 i_xDocProps->setEditingCycles( nRevision ); 115 } 116 117 if( xGlobSect->GetFileTimeValue( aDateTime, PROPID_EDITTIME ) ) 118 { 119 // subtract offset 1601-01-01 120 aDateTime.Year -= 1601; 121 aDateTime.Month -= 1; 122 aDateTime.Day -= 1; 123 try 124 { 125 i_xDocProps->setEditingDuration( 126 aDateTime.Day * 60*60*24 + 127 aDateTime.Hours * 60*60 + 128 aDateTime.Minutes * 60 + 129 aDateTime.Seconds ); 130 } 131 catch (lang::IllegalArgumentException &) 132 { 133 // ignore 134 } 135 } 136 } 137 138 // *** custom properties from stream "005DocumentSummaryInformation" *** 139 140 // load the property set 141 SfxOlePropertySet aDocSet; 142 ErrCode nDocError = aDocSet.LoadPropertySet(i_pStorage, 143 String( RTL_CONSTASCII_USTRINGPARAM( STREAM_DOCSUMMARYINFO ) ) ); 144 145 // custom properties 146 SfxOleSectionRef xCustomSect = aDocSet.GetSection( SECTION_CUSTOM ); 147 if( xCustomSect.get() ) 148 { 149 uno::Reference < beans::XPropertyContainer > xUserDefined( 150 i_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); 151 ::std::vector< sal_Int32 > aPropIds; 152 xCustomSect->GetPropertyIds( aPropIds ); 153 for( ::std::vector< sal_Int32 >::const_iterator aIt = aPropIds.begin(), 154 aEnd = aPropIds.end(); aIt != aEnd; ++aIt ) 155 { 156 ::rtl::OUString aPropName = xCustomSect->GetPropertyName( *aIt ); 157 uno::Any aPropValue = xCustomSect->GetAnyValue( *aIt ); 158 if( (aPropName.getLength() > 0) && aPropValue.hasValue() ) { 159 try { 160 xUserDefined->addProperty( aPropName, 161 beans::PropertyAttribute::REMOVEABLE, aPropValue ); 162 } catch ( uno::Exception& ) { 163 //ignore 164 } 165 } 166 } 167 } 168 169 // return code 170 return (nGlobError != ERRCODE_NONE) ? nGlobError : nDocError; 171 } 172 173 bool SFX2_DLLPUBLIC SaveOlePropertySet( 174 uno::Reference< document::XDocumentProperties> i_xDocProps, 175 SotStorage* i_pStorage, 176 const uno::Sequence<sal_uInt8> * i_pThumb, 177 const uno::Sequence<sal_uInt8> * i_pGuid, 178 const uno::Sequence<sal_uInt8> * i_pHyperlinks) 179 { 180 // *** global properties into stream "005SummaryInformation" *** 181 182 SfxOlePropertySet aGlobSet; 183 184 // set supported properties 185 SfxOleSection& rGlobSect = aGlobSet.AddSection( SECTION_GLOBAL ); 186 rGlobSect.SetStringValue( PROPID_TITLE, i_xDocProps->getTitle() ); 187 rGlobSect.SetStringValue( PROPID_SUBJECT, i_xDocProps->getSubject() ); 188 String aStr = ::comphelper::string::convertCommaSeparated( 189 i_xDocProps->getKeywords() ); 190 rGlobSect.SetStringValue( PROPID_KEYWORDS, aStr ); 191 rGlobSect.SetStringValue( PROPID_TEMPLATE, i_xDocProps->getTemplateName() ); 192 rGlobSect.SetStringValue( PROPID_COMMENTS, i_xDocProps->getDescription() ); 193 rGlobSect.SetStringValue( PROPID_AUTHOR, i_xDocProps->getAuthor() ); 194 rGlobSect.SetFileTimeValue(PROPID_CREATED, i_xDocProps->getCreationDate()); 195 rGlobSect.SetStringValue( PROPID_LASTAUTHOR, i_xDocProps->getModifiedBy() ); 196 rGlobSect.SetFileTimeValue(PROPID_LASTSAVED, 197 i_xDocProps->getModificationDate() ); 198 // note: apparently PrintedBy is not supported in file format 199 rGlobSect.SetFileTimeValue(PROPID_LASTPRINTED, i_xDocProps->getPrintDate()); 200 201 sal_Int32 dur = i_xDocProps->getEditingDuration(); 202 util::DateTime aEditTime; 203 // add offset 1601-01-01 204 aEditTime.Year = 1601; 205 aEditTime.Month = 1; 206 aEditTime.Day = 1; 207 aEditTime.Hours = static_cast<sal_Int16>(dur / 3600); 208 aEditTime.Minutes = static_cast<sal_Int16>((dur % 3600) / 60); 209 aEditTime.Seconds = static_cast<sal_Int16>(dur % 60); 210 rGlobSect.SetFileTimeValue( PROPID_EDITTIME, aEditTime ); 211 212 rGlobSect.SetStringValue( PROPID_REVNUMBER, 213 String::CreateFromInt32( i_xDocProps->getEditingCycles() ) ); 214 if ( i_pThumb && i_pThumb->getLength() ) 215 rGlobSect.SetThumbnailValue( PROPID_THUMBNAIL, *i_pThumb ); 216 217 // save the property set 218 ErrCode nGlobError = aGlobSet.SavePropertySet(i_pStorage, 219 String( RTL_CONSTASCII_USTRINGPARAM( STREAM_SUMMARYINFO ) ) ); 220 221 // *** custom properties into stream "005DocumentSummaryInformation" *** 222 223 SfxOlePropertySet aDocSet; 224 225 // set builtin properties 226 aDocSet.AddSection( SECTION_BUILTIN ); 227 228 // set custom properties 229 SfxOleSection& rCustomSect = aDocSet.AddSection( SECTION_CUSTOM ); 230 231 // write GUID 232 if (i_pGuid) { 233 const sal_Int32 nPropId = rCustomSect.GetFreePropertyId(); 234 rCustomSect.SetBlobValue( nPropId, *i_pGuid ); 235 rCustomSect.SetPropertyName( nPropId, 236 ::rtl::OUString::createFromAscii("_PID_GUID") ); 237 } 238 239 // write hyperlinks 240 if (i_pHyperlinks) { 241 const sal_Int32 nPropId = rCustomSect.GetFreePropertyId(); 242 rCustomSect.SetBlobValue( nPropId, *i_pHyperlinks ); 243 rCustomSect.SetPropertyName( nPropId, 244 ::rtl::OUString::createFromAscii("_PID_HLINKS") ); 245 } 246 247 uno::Reference<beans::XPropertySet> xUserDefinedProps( 248 i_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); 249 DBG_ASSERT(xUserDefinedProps.is(), "UserDefinedProperties is null"); 250 uno::Reference<beans::XPropertySetInfo> xPropInfo = 251 xUserDefinedProps->getPropertySetInfo(); 252 DBG_ASSERT(xPropInfo.is(), "UserDefinedProperties Info is null"); 253 uno::Sequence<beans::Property> props = xPropInfo->getProperties(); 254 for (sal_Int32 i = 0; i < props.getLength(); ++i) { 255 try { 256 // skip transient properties 257 if (~props[i].Attributes & beans::PropertyAttribute::TRANSIENT) 258 { 259 const ::rtl::OUString name = props[i].Name; 260 const sal_Int32 nPropId = rCustomSect.GetFreePropertyId(); 261 if (rCustomSect.SetAnyValue( nPropId, 262 xUserDefinedProps->getPropertyValue(name))) { 263 rCustomSect.SetPropertyName( nPropId, name ); 264 } 265 } 266 } catch (uno::Exception &) { 267 // may happen with concurrent modification... 268 DBG_WARNING("SavePropertySet: exception"); 269 } 270 } 271 272 // save the property set 273 ErrCode nDocError = aDocSet.SavePropertySet(i_pStorage, 274 String( RTL_CONSTASCII_USTRINGPARAM( STREAM_DOCSUMMARYINFO ) ) ); 275 276 // return code 277 return (nGlobError == ERRCODE_NONE) && (nDocError == ERRCODE_NONE); 278 } 279 280 uno::Sequence<sal_uInt8> SFX2_DLLPUBLIC convertMetaFile(GDIMetaFile* i_pThumb) 281 { 282 if (i_pThumb) { 283 BitmapEx aBitmap; 284 SvMemoryStream aStream; 285 // magic value 160 taken from GraphicHelper::getThumbnailFormatFromGDI_Impl() 286 if( i_pThumb->CreateThumbnail( 160, aBitmap ) ) { 287 WriteDIB(aBitmap.GetBitmap(), aStream, false, false); 288 // uno::Sequence<sal_uInt8> aSeq(aStream.GetSize()); // WRONG 289 aStream.Seek(STREAM_SEEK_TO_END); 290 uno::Sequence<sal_uInt8> aSeq(aStream.Tell()); 291 const sal_uInt8* pBlob( 292 static_cast<const sal_uInt8*>(aStream.GetData())); 293 for (sal_Int32 j = 0; j < aSeq.getLength(); ++j) { 294 aSeq[j] = pBlob[j]; 295 } 296 return aSeq; 297 } 298 } 299 return uno::Sequence<sal_uInt8>(); 300 } 301 302 } // namespace sfx2 303 304