update ooo310-m15
[ooovba.git] / applied_patches / 0459-sfx2-pre-and-postprocess-during-save-load.diff
blob6ad742636d079d4b869601f2b2ddf3448706ed2c
1 --- sfx2/source/doc/objstor.cxx.old 2009-04-06 16:41:54.000000000 +0000
2 +++ sfx2/source/doc/objstor.cxx 2009-04-06 16:42:02.000000000 +0000
3 @@ -109,6 +109,9 @@
4 #include <rtl/logfile.hxx>
5 #include <basic/modsizeexceeded.hxx>
6 #include <osl/file.hxx>
7 +#include <com/sun/star/util/XMacroExpander.hpp>
8 +#include <osl/process.h>
9 +#include <osl/thread.hxx>
11 #include <sfx2/signaturestate.hxx>
12 #include <sfx2/app.hxx>
13 @@ -154,6 +157,126 @@ using namespace ::cppu;
15 namespace css = ::com::sun::star;
17 +class StatusThread : public osl::Thread
19 + oslFileHandle m_handle;
21 +public:
22 + int volatile progressTicks;
24 + StatusThread(oslFileHandle handle) :
25 + osl::Thread(), m_handle(handle), progressTicks(0)
26 + {
27 + }
30 + virtual void SAL_CALL run() {
31 + sal_uInt64 nRead;
32 + char buf[1024];
33 + for(;;) {
34 + oslFileError err=osl_readFile(m_handle, buf, sizeof(buf)-1, &nRead);
35 + if (err!=osl_File_E_None || nRead<=0) {
36 + break;
37 + }
38 + buf[nRead]=0;
39 + progressTicks++;
40 + }
41 + }
43 +};
45 +static sal_Bool invokeExternalApp(String aAppName, ::rtl::OUString sourceParam, ::rtl::OUString targetParam, uno::Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator)
47 + static const char EXPAND_WILDCARD_CONST[] ="vnd.sun.star.expand:";
48 + static const char SOURCE_WILDCARD_CONST[]="%source%";
49 + static const char TARGET_WILDCARD_CONST[]="%target%";
50 + // get macro expansion
51 + uno::Reference< XMultiServiceFactory> xMS(::comphelper::getProcessServiceFactory(), UNO_QUERY);
52 + uno::Reference< beans::XPropertySet > xProps(xMS, UNO_QUERY);
53 + uno::Reference< XComponentContext > xContext(xProps->getPropertyValue(rtl::OUString::createFromAscii("DefaultContext")), UNO_QUERY);
54 + uno::Reference< util::XMacroExpander > xExpander(xContext->getValueByName(::rtl::OUString::createFromAscii("/singletons/com.sun.star.util.theMacroExpander")), UNO_QUERY);
56 + // parse preprocessing arguments
57 + int c=aAppName.GetQuotedTokenCount('\"',',');
58 + if (c<1) return sal_False;
59 + rtl_uString **args=new rtl_uString*[c];
60 + for(int i=0;i<c;i++) {
61 + String aArg=aAppName.GetQuotedToken(i,'\"',',');
62 + if (aArg.EqualsIgnoreCaseAscii(EXPAND_WILDCARD_CONST, 0, strlen(EXPAND_WILDCARD_CONST))) {
63 + rtl::OUString argStr(aArg.GetBuffer()+strlen(EXPAND_WILDCARD_CONST));
64 + aArg=xExpander->expandMacros(argStr);
65 + } else if (aArg.EqualsIgnoreCaseAscii(SOURCE_WILDCARD_CONST, 0, strlen(SOURCE_WILDCARD_CONST))) {
66 + aArg=sourceParam;
67 + } else if (aArg.EqualsIgnoreCaseAscii(TARGET_WILDCARD_CONST, 0, strlen(TARGET_WILDCARD_CONST))) {
68 + aArg=targetParam;
69 + }
70 + args[i]=rtl::OUString(aArg).pData;
71 + rtl_uString_acquire(args[i]);
72 + }
74 + sal_Bool bOk=sal_False;
76 +#ifndef NDEBUG
77 + for (int p=0;p<c;p++) {
78 + rtl::OString aOString = ::rtl::OUStringToOString (args[p], RTL_TEXTENCODING_UTF8);
79 + printf("args[%i]=\"%s\"\n", p, aOString.getStr());
80 + }
81 +#endif
82 + // invoke processing step
83 + oslProcess pProcess=NULL;
84 + oslFileHandle handle=NULL;
85 + oslProcessError error=osl_executeProcess_WithRedirectedIO(
86 + args[0],
87 + args+1,
88 + c-1,
89 + /*osl_Process_NORMAL*/ osl_Process_HIDDEN,
90 + 0,
91 + NULL,
92 + NULL,
93 + 0,
94 + &pProcess,
95 + NULL,
96 + &handle,
97 + NULL
98 + );
100 + if (error==osl_Process_E_None) {
101 + static const int MAXBARTICKS=1000;
102 + StatusThread statusThread(handle);
103 + statusThread.create();
104 + if (xStatusIndicator.is()) {
105 + xStatusIndicator->start(::rtl::OUString::createFromAscii("waiting for external application..."), MAXBARTICKS);
107 + do {
108 + TimeValue wait = {1, 0};
109 + error=osl_joinProcessWithTimeout( pProcess, &wait);
110 + if (xStatusIndicator.is()) {
111 + xStatusIndicator->setValue(statusThread.progressTicks%MAXBARTICKS);
113 + } while (error==osl_Process_E_TimedOut);
114 + if (xStatusIndicator.is()) {
115 + xStatusIndicator->end();
117 + if (error==osl_Process_E_None) {
118 + oslProcessInfo aProcessInfo;
119 + aProcessInfo.Size = sizeof(aProcessInfo);
120 + error = osl_getProcessInfo( pProcess, osl_Process_EXITCODE, &aProcessInfo );
121 + if (error==osl_Process_E_None && aProcessInfo.Code == 0) {
122 + bOk=sal_True;
125 + statusThread.join();
127 + osl_freeProcessHandle(pProcess);
129 + for(int i=0;i<c;i++) {
130 + rtl_uString_release(args[i]);
132 + delete[] args;
133 + return bOk;
137 //=========================================================================
138 void impl_addToModelCollection(const css::uno::Reference< css::frame::XModel >& xModel)
140 @@ -679,7 +802,47 @@ sal_Bool SfxObjectShell::DoLoad( SfxMedi
142 pImp->nLoadedFlags = 0;
143 pImp->bModelInitialized = sal_False;
144 - bOk = xStorage.is() && LoadOwnFormat( *pMed );
145 + String aUserData=pFilter->GetUserData();
146 + // check whether a prepocessing step is requested in the configuration
147 + static const char PREPROCESS_CONST[]="Preprocess=<";
148 + int pos=aUserData.Search(::rtl::OUString::createFromAscii(PREPROCESS_CONST).getStr(), 0);
149 + int end=aUserData.Search( '>', pos+strlen(PREPROCESS_CONST));
150 + if (pos!=STRING_NOTFOUND && end!=STRING_NOTFOUND) {
151 + String aAppName(aUserData, pos+strlen(PREPROCESS_CONST), end-(pos+strlen(PREPROCESS_CONST)));
153 + // setup status bar
154 + SfxItemSet *pSet = pMed->GetItemSet();
155 + const SfxUnoAnyItem *pItem=NULL;
156 + SfxItemState ret=pSet->GetItemState( SID_PROGRESS_STATUSBAR_CONTROL, TRUE, (const SfxPoolItem**)&pItem);
157 + uno::Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator;
158 + if (ret==SFX_ITEM_SET && pItem!=NULL)
160 + pItem->GetValue() >>= xStatusIndicator;
162 + // create a copy
163 + SfxMedium myMed(*pMed, sal_False);
164 + ::utl::TempFile aTempFile;
165 + myMed.SetName(aTempFile.GetURL(), sal_True);
166 + myMed.SetPhysicalName_Impl(aTempFile.GetFileName());
167 + myMed.ResetError();
168 + myMed.CloseStorage();
169 + myMed.CloseInStream();
170 + myMed.SetTemporary(sal_True);
172 + bOk = invokeExternalApp(aAppName, ::rtl::OUString(pMed->GetPhysicalName()), ::rtl::OUString(myMed.GetPhysicalName()), xStatusIndicator);
174 + // load from copy
175 + if (bOk) {
176 + bOk = xStorage.is() && LoadOwnFormat( myMed );
178 + } else {
179 + // We process only errors from invokeExternalApp at this point
180 + // The errors from the above LoadOwnFormat are processed later
181 + SetError( ERRCODE_IO_CANTREAD );
183 + } else {
184 + bOk = xStorage.is() && LoadOwnFormat( *pMed );
186 if ( bOk )
188 // the document loaded from template has no name
189 @@ -1121,6 +1284,7 @@ void Lock_Impl( SfxObjectShell* pDoc, BO
194 //-------------------------------------------------------------------------
196 sal_Bool SfxObjectShell::SaveTo_Impl
197 @@ -1622,10 +1786,10 @@ sal_Bool SfxObjectShell::SaveTo_Impl
198 // transfer data to its destinated location
199 // the medium commits the storage or the stream it is based on
200 RegisterTransfer( rMedium );
201 - bOk = rMedium.Commit();
203 if ( bOk && bScriptSignatureIsCopied )
205 + bOk = rMedium.Commit();
206 // if the script signature was copied it should be checked now
207 // usually it should be ok, so no additional actions will be done
208 // but if for any reasong ( f.e. binshell change ) it is broken it should be removed here
209 @@ -1660,7 +1824,6 @@ sal_Bool SfxObjectShell::SaveTo_Impl
210 if ( xTransact.is() )
211 xTransact->commit();
213 - bOk = rMedium.Commit();
217 @@ -1671,6 +1834,59 @@ sal_Bool SfxObjectShell::SaveTo_Impl
221 + if (bOk) { // commit *before* we do the conversion!
222 + bOk = rMedium.Commit();
225 + uno::Reference< embed::XStorage > xNewTmpStorage;
226 + if (bOk) {
227 + String aUserData=pFilter->GetUserData();
228 + // check whether a postprocessing step is requested in the configuration
229 + static const char POSTPROCESS_CONST[]="Postprocess=<";
230 + int pos=aUserData.Search(::rtl::OUString::createFromAscii(POSTPROCESS_CONST).getStr(), 0);
231 + int end=aUserData.Search( '>', pos+strlen(POSTPROCESS_CONST));
232 + if (pos!=STRING_NOTFOUND && end!=STRING_NOTFOUND) {
233 + String aAppName(aUserData, pos+strlen(POSTPROCESS_CONST), end-(pos+strlen(POSTPROCESS_CONST)));
235 + // setup status bar
236 + SfxItemSet *pSet = rMedium.GetItemSet();
237 + const SfxUnoAnyItem *pItem=NULL;
238 + SfxItemState ret=pSet->GetItemState( SID_PROGRESS_STATUSBAR_CONTROL, TRUE, (const SfxPoolItem**)&pItem);
239 + uno::Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator;
240 + if (ret==SFX_ITEM_SET && pItem!=NULL)
242 + pItem->GetValue() >>= xStatusIndicator;
245 + // create copy
246 + ::rtl::OUString aTmpVersionURL = CreateTempCopyOfStorage_Impl( rMedium.GetStorage() );
247 + rMedium.CloseAndRelease();
249 + rtl::OUString aSourceFile;
250 + osl::FileBase::getSystemPathFromFileURL(aTmpVersionURL, aSourceFile);
251 + String aTargetFile(rMedium.GetPhysicalName());
253 + // remove the current target file after it was copied
254 + // the postprocess might crash and the unprocessed file would confuse users
255 + String aTargetFileURL;
256 + ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aTargetFile, aTargetFileURL );
257 + osl_removeFile(::rtl::OUString(aTargetFileURL).pData);
259 + bOk=invokeExternalApp(aAppName, aSourceFile, aTargetFile, xStatusIndicator);
261 + if (bOk) {
262 + // create a new tmp storage
263 + xNewTmpStorage=::comphelper::OStorageHelper::GetStorageFromURL( aTmpVersionURL, embed::ElementModes::READWRITE );
264 + // it does not make sense to reopen the file if it was not saved correctly
265 + rMedium.ReOpen();
270 + if (bOk && xNewTmpStorage.is()) {
271 + rMedium.SetStorage_Impl(xNewTmpStorage);
274 if ( bOk )
276 // if the target medium is an alien format and the "old" medium was an own format and the "old" medium
277 @@ -1701,7 +1917,7 @@ sal_Bool SfxObjectShell::SaveTo_Impl
278 if ( bNeedsDisconnectionOnFail )
279 ConnectTmpStorage_Impl( pImp->m_xDocStorage, NULL );
284 // unlock user interface
285 Lock_Impl( this, sal_False );