merge the formfield patch from ooo-build
[ooovba.git] / applied_patches / 0332-sfx2-pre-and-postprocess-during-save-load.diff
blobcd1ec5bf03b380807f083d688e9636ea3ec6ca82
1 Florian's sfx2-pre-and-postprocess-during-save-load patch
3 From: Thorsten Behrens <thb@openoffice.org>
6 ---
8 sfx2/source/doc/objstor.cxx | 225 +++++++++++++++++++++++++++++++++++++++++++
9 1 files changed, 223 insertions(+), 2 deletions(-)
12 diff --git sfx2/source/doc/objstor.cxx sfx2/source/doc/objstor.cxx
13 index d6ce464..509f208 100644
14 --- sfx2/source/doc/objstor.cxx
15 +++ sfx2/source/doc/objstor.cxx
16 @@ -110,6 +110,9 @@
17 #include <rtl/logfile.hxx>
18 #include <basic/modsizeexceeded.hxx>
19 #include <osl/file.hxx>
20 +#include <com/sun/star/util/XMacroExpander.hpp>
21 +#include <osl/process.h>
22 +#include <osl/thread.hxx>
24 #include <sfx2/signaturestate.hxx>
25 #include <sfx2/app.hxx>
26 @@ -161,6 +164,126 @@ using namespace ::cppu;
28 namespace css = ::com::sun::star;
30 +class StatusThread : public osl::Thread
32 + oslFileHandle m_handle;
34 +public:
35 + int volatile progressTicks;
37 + StatusThread(oslFileHandle handle) :
38 + osl::Thread(), m_handle(handle), progressTicks(0)
39 + {
40 + }
43 + virtual void SAL_CALL run() {
44 + sal_uInt64 nRead;
45 + char buf[1024];
46 + for(;;) {
47 + oslFileError err=osl_readFile(m_handle, buf, sizeof(buf)-1, &nRead);
48 + if (err!=osl_File_E_None || nRead<=0) {
49 + break;
50 + }
51 + buf[nRead]=0;
52 + progressTicks++;
53 + }
54 + }
56 +};
58 +static sal_Bool invokeExternalApp(String aAppName, ::rtl::OUString sourceParam, ::rtl::OUString targetParam, uno::Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator)
60 + static const char EXPAND_WILDCARD_CONST[] ="vnd.sun.star.expand:";
61 + static const char SOURCE_WILDCARD_CONST[]="%source%";
62 + static const char TARGET_WILDCARD_CONST[]="%target%";
63 + // get macro expansion
64 + uno::Reference< XMultiServiceFactory> xMS(::comphelper::getProcessServiceFactory(), UNO_QUERY);
65 + uno::Reference< beans::XPropertySet > xProps(xMS, UNO_QUERY);
66 + uno::Reference< XComponentContext > xContext(xProps->getPropertyValue(rtl::OUString::createFromAscii("DefaultContext")), UNO_QUERY);
67 + uno::Reference< util::XMacroExpander > xExpander(xContext->getValueByName(::rtl::OUString::createFromAscii("/singletons/com.sun.star.util.theMacroExpander")), UNO_QUERY);
69 + // parse preprocessing arguments
70 + int c=aAppName.GetQuotedTokenCount('\"',',');
71 + if (c<1) return sal_False;
72 + rtl_uString **args=new rtl_uString*[c];
73 + for(int i=0;i<c;i++) {
74 + String aArg=aAppName.GetQuotedToken(i,'\"',',');
75 + if (aArg.EqualsIgnoreCaseAscii(EXPAND_WILDCARD_CONST, 0, strlen(EXPAND_WILDCARD_CONST))) {
76 + rtl::OUString argStr(aArg.GetBuffer()+strlen(EXPAND_WILDCARD_CONST));
77 + aArg=xExpander->expandMacros(argStr);
78 + } else if (aArg.EqualsIgnoreCaseAscii(SOURCE_WILDCARD_CONST, 0, strlen(SOURCE_WILDCARD_CONST))) {
79 + aArg=sourceParam;
80 + } else if (aArg.EqualsIgnoreCaseAscii(TARGET_WILDCARD_CONST, 0, strlen(TARGET_WILDCARD_CONST))) {
81 + aArg=targetParam;
82 + }
83 + args[i]=rtl::OUString(aArg).pData;
84 + rtl_uString_acquire(args[i]);
85 + }
87 + sal_Bool bOk=sal_False;
89 +#ifndef NDEBUG
90 + for (int p=0;p<c;p++) {
91 + rtl::OString aOString = ::rtl::OUStringToOString (args[p], RTL_TEXTENCODING_UTF8);
92 + printf("args[%i]=\"%s\"\n", p, aOString.getStr());
93 + }
94 +#endif
95 + // invoke processing step
96 + oslProcess pProcess=NULL;
97 + oslFileHandle handle=NULL;
98 + oslProcessError error=osl_executeProcess_WithRedirectedIO(
99 + args[0],
100 + args+1,
101 + c-1,
102 + /*osl_Process_NORMAL*/ osl_Process_HIDDEN,
103 + 0,
104 + NULL,
105 + NULL,
106 + 0,
107 + &pProcess,
108 + NULL,
109 + &handle,
110 + NULL
111 + );
113 + if (error==osl_Process_E_None) {
114 + static const int MAXBARTICKS=1000;
115 + StatusThread statusThread(handle);
116 + statusThread.create();
117 + if (xStatusIndicator.is()) {
118 + xStatusIndicator->start(::rtl::OUString::createFromAscii("waiting for external application..."), MAXBARTICKS);
120 + do {
121 + TimeValue wait = {1, 0};
122 + error=osl_joinProcessWithTimeout( pProcess, &wait);
123 + if (xStatusIndicator.is()) {
124 + xStatusIndicator->setValue(statusThread.progressTicks%MAXBARTICKS);
126 + } while (error==osl_Process_E_TimedOut);
127 + if (xStatusIndicator.is()) {
128 + xStatusIndicator->end();
130 + if (error==osl_Process_E_None) {
131 + oslProcessInfo aProcessInfo;
132 + aProcessInfo.Size = sizeof(aProcessInfo);
133 + error = osl_getProcessInfo( pProcess, osl_Process_EXITCODE, &aProcessInfo );
134 + if (error==osl_Process_E_None && aProcessInfo.Code == 0) {
135 + bOk=sal_True;
138 + statusThread.join();
140 + osl_freeProcessHandle(pProcess);
142 + for(int i=0;i<c;i++) {
143 + rtl_uString_release(args[i]);
145 + delete[] args;
146 + return bOk;
150 //=========================================================================
151 void impl_addToModelCollection(const css::uno::Reference< css::frame::XModel >& xModel)
153 @@ -693,7 +816,51 @@ sal_Bool SfxObjectShell::DoLoad( SfxMedium *pMed )
155 pImp->nLoadedFlags = 0;
156 pImp->bModelInitialized = sal_False;
157 - bOk = xStorage.is() && LoadOwnFormat( *pMed );
158 + int end, pos = STRING_NOTFOUND;
159 + String aUserData;
160 + static const char PREPROCESS_CONST[]="Preprocess=<";
161 + if (pFilter) {
162 + aUserData=pFilter->GetUserData();
163 + // check whether a prepocessing step is requested in the configuration
164 + pos=aUserData.Search(::rtl::OUString::createFromAscii(PREPROCESS_CONST).getStr(), 0);
165 + end=aUserData.Search( '>', pos+strlen(PREPROCESS_CONST));
167 + if (pos!=STRING_NOTFOUND && end!=STRING_NOTFOUND) {
168 + String aAppName(aUserData, pos+strlen(PREPROCESS_CONST), end-(pos+strlen(PREPROCESS_CONST)));
170 + // setup status bar
171 + SfxItemSet *pSet2 = pMed->GetItemSet();
172 + const SfxUnoAnyItem *pItem=NULL;
173 + SfxItemState ret=pSet2->GetItemState( SID_PROGRESS_STATUSBAR_CONTROL, TRUE, (const SfxPoolItem**)&pItem);
174 + uno::Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator;
175 + if (ret==SFX_ITEM_SET && pItem!=NULL)
177 + pItem->GetValue() >>= xStatusIndicator;
179 + // create a copy
180 + SfxMedium myMed(*pMed, sal_False);
181 + ::utl::TempFile aTempFile;
182 + myMed.SetName(aTempFile.GetURL(), sal_True);
183 + myMed.SetPhysicalName_Impl(aTempFile.GetFileName());
184 + myMed.ResetError();
185 + myMed.CloseStorage();
186 + myMed.CloseInStream();
187 + myMed.SetTemporary(sal_True);
189 + bOk = invokeExternalApp(aAppName, ::rtl::OUString(pMed->GetPhysicalName()), ::rtl::OUString(myMed.GetPhysicalName()), xStatusIndicator);
191 + // load from copy
192 + if (bOk) {
193 + bOk = xStorage.is() && LoadOwnFormat( myMed );
195 + } else {
196 + // We process only errors from invokeExternalApp at this point
197 + // The errors from the above LoadOwnFormat are processed later
198 + SetError( ERRCODE_IO_CANTREAD, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
200 + } else {
201 + bOk = xStorage.is() && LoadOwnFormat( *pMed );
203 if ( bOk )
205 // the document loaded from template has no name
206 @@ -1126,6 +1293,7 @@ void Lock_Impl( SfxObjectShell* pDoc, BOOL bLock )
211 //-------------------------------------------------------------------------
213 sal_Bool SfxObjectShell::SaveTo_Impl
214 @@ -1606,6 +1774,59 @@ sal_Bool SfxObjectShell::SaveTo_Impl
215 bOk = SaveChildren( TRUE );
218 + if (bOk) { // commit *before* we do the conversion!
219 + bOk = rMedium.Commit();
222 + uno::Reference< embed::XStorage > xNewTmpStorage;
223 + if (bOk) {
224 + String aUserData=pFilter->GetUserData();
225 + // check whether a postprocessing step is requested in the configuration
226 + static const char POSTPROCESS_CONST[]="Postprocess=<";
227 + int pos=aUserData.Search(::rtl::OUString::createFromAscii(POSTPROCESS_CONST).getStr(), 0);
228 + int end=aUserData.Search( '>', pos+strlen(POSTPROCESS_CONST));
229 + if (pos!=STRING_NOTFOUND && end!=STRING_NOTFOUND) {
230 + String aAppName(aUserData, pos+strlen(POSTPROCESS_CONST), end-(pos+strlen(POSTPROCESS_CONST)));
232 + // setup status bar
233 + SfxItemSet *pSet2 = rMedium.GetItemSet();
234 + const SfxUnoAnyItem *pItem=NULL;
235 + SfxItemState ret=pSet2->GetItemState( SID_PROGRESS_STATUSBAR_CONTROL, TRUE, (const SfxPoolItem**)&pItem);
236 + uno::Reference< ::com::sun::star::task::XStatusIndicator > xStatusIndicator;
237 + if (ret==SFX_ITEM_SET && pItem!=NULL)
239 + pItem->GetValue() >>= xStatusIndicator;
242 + // create copy
243 + ::rtl::OUString aTmpVersionURL = CreateTempCopyOfStorage_Impl( rMedium.GetStorage() );
244 + rMedium.CloseAndRelease();
246 + rtl::OUString aSourceFile;
247 + osl::FileBase::getSystemPathFromFileURL(aTmpVersionURL, aSourceFile);
248 + String aTargetFile(rMedium.GetPhysicalName());
250 + // remove the current target file after it was copied
251 + // the postprocess might crash and the unprocessed file would confuse users
252 + String aTargetFileURL;
253 + ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aTargetFile, aTargetFileURL );
254 + osl_removeFile(::rtl::OUString(aTargetFileURL).pData);
256 + bOk=invokeExternalApp(aAppName, aSourceFile, aTargetFile, xStatusIndicator);
258 + if (bOk) {
259 + // create a new tmp storage
260 + xNewTmpStorage=::comphelper::OStorageHelper::GetStorageFromURL( aTmpVersionURL, embed::ElementModes::READWRITE );
261 + // it does not make sense to reopen the file if it was not saved correctly
262 + rMedium.ReOpen();
267 + if (bOk && xNewTmpStorage.is()) {
268 + rMedium.SetStorage_Impl(xNewTmpStorage);
271 if ( bOk )
273 // if ODF version of oasis format changes on saving the signature should not be preserved
274 @@ -1713,11 +1934,11 @@ sal_Bool SfxObjectShell::SaveTo_Impl
275 // transfer data to its destinated location
276 // the medium commits the storage or the stream it is based on
277 RegisterTransfer( rMedium );
278 - bOk = rMedium.Commit();
280 if ( bOk )
282 AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Storing is successful." ) ) );
283 + bOk = rMedium.Commit();
285 // if the target medium is an alien format and the "old" medium was an own format and the "old" medium
286 // has a name, the object storage must be exchanged, because now we need a new temporary storage