external/curl/CVE-2017-8816.patch | 67 +++++++++++++++ external/curl/CVE-2018-1000005.patch | 36 ++++++++ external/curl/CVE-2018-1000007.patch | 110 +++++++++++++++++++++++++ external/curl/UnpackedTarball_curl.mk | 3 hwpfilter/source/hcode.cxx | 2 hwpfilter/source/hwpfile.h | 2 sc/inc/document.hxx | 5 - sc/inc/sc.hrc | 1 sc/source/core/data/documen2.cxx | 7 + sc/source/core/data/validat.cxx | 46 +++++++++- sc/source/core/tool/interpr7.cxx | 28 ++++++ sc/source/filter/excel/xicontent.cxx | 9 ++ sc/source/filter/oox/worksheethelper.cxx | 6 + sc/source/filter/xml/XMLStylesExportHelper.cxx | 6 + sc/source/filter/xml/xmlcvali.cxx | 1 sc/source/ui/dbgui/validate.cxx | 27 ++++-- sc/source/ui/inc/validate.hxx | 1 sc/source/ui/unoobj/funcuno.cxx | 2 sc/source/ui/view/cellsh2.cxx | 2 sc/uiconfig/scalc/ui/validationcriteriapage.ui | 4 vcl/source/gdi/pdfwriter_impl2.cxx | 27 ++++-- 21 files changed, 368 insertions(+), 24 deletions(-)
New commits: commit dc1e0d630be11bf6112157e96fa8284faa822322 Author: Caolán McNamara <caol...@redhat.com> Date: Tue Feb 20 21:18:04 2018 +0000 forcepoint #4 Thanks to Antti Levomäki and Christian Jalio from Forcepoint. Change-Id: I569ca80267ad9b5a21da0029ba903d2a4c45a035 diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx index af63e2cdb3a3..dcf20ae15ae2 100644 --- a/vcl/source/gdi/pdfwriter_impl2.cxx +++ b/vcl/source/gdi/pdfwriter_impl2.cxx @@ -1605,11 +1605,8 @@ inline bool isSet( const Scanline i_pLine, long i_nIndex ) return (i_pLine[ i_nIndex/8 ] & (0x80 >> (i_nIndex&7))) != 0; } -long findBitRun( const Scanline i_pLine, long i_nStartIndex, long i_nW, bool i_bSet ) +long findBitRunImpl( const Scanline i_pLine, long i_nStartIndex, long i_nW, bool i_bSet ) { - if( i_nStartIndex < 0 ) - return i_nW; - long nIndex = i_nStartIndex; if( nIndex < i_nW ) { @@ -1671,6 +1668,24 @@ long findBitRun( const Scanline i_pLine, long i_nStartIndex, long i_nW, bool i_b return nIndex < i_nW ? nIndex : i_nW; } +long findBitRun(const Scanline i_pLine, long i_nStartIndex, long i_nW, bool i_bSet) +{ + if (i_nStartIndex < 0) + return i_nW; + + return findBitRunImpl(i_pLine, i_nStartIndex, i_nW, i_bSet); +} + +long findBitRun(const Scanline i_pLine, long i_nStartIndex, long i_nW) +{ + if (i_nStartIndex < 0) + return i_nW; + + const bool bSet = i_nStartIndex < i_nW && isSet(i_pLine, i_nStartIndex); + + return findBitRunImpl(i_pLine, i_nStartIndex, i_nW, bSet); +} + struct BitStreamState { sal_uInt8 mnBuffer; @@ -1974,7 +1989,7 @@ void PDFWriterImpl::writeG4Stream( BitmapReadAccess* i_pBitmap ) long nRefIndex1 = bRefSet ? 0 : findBitRun( pRefLine, 0, nW, bRefSet ); for( ; nLineIndex < nW; ) { - long nRefIndex2 = findBitRun( pRefLine, nRefIndex1, nW, isSet( pRefLine, nRefIndex1 ) ); + long nRefIndex2 = findBitRun( pRefLine, nRefIndex1, nW ); if( nRefIndex2 >= nRunIndex1 ) { long nDiff = nRefIndex1 - nRunIndex1; @@ -2004,7 +2019,7 @@ void PDFWriterImpl::writeG4Stream( BitmapReadAccess* i_pBitmap ) { // difference too large, horizontal coding // emit horz code 001 putG4Bits( 3, 0x1, aBitState ); - long nRunIndex2 = findBitRun( pCurLine, nRunIndex1, nW, isSet( pCurLine, nRunIndex1 ) ); + long nRunIndex2 = findBitRun( pCurLine, nRunIndex1, nW ); bool bWhiteFirst = ( nLineIndex + nRunIndex1 == 0 || ! isSet( pCurLine, nLineIndex ) ); putG4Span( nRunIndex1 - nLineIndex, bWhiteFirst, aBitState ); putG4Span( nRunIndex2 - nRunIndex1, ! bWhiteFirst, aBitState ); commit ada182569b2a4e25764d67a30f962eb16aea81a7 Author: Caolán McNamara <caol...@redhat.com> Date: Tue Feb 20 16:33:38 2018 +0000 forcepoint #2 Thanks to Antti Levomäki and Christian Jalio from Forcepoint. Change-Id: Ie2b644a3c4c1c165334768eea73d451f07f97def diff --git a/hwpfilter/source/hcode.cxx b/hwpfilter/source/hcode.cxx index e9a088c97137..9aaa9e98f04a 100644 --- a/hwpfilter/source/hcode.cxx +++ b/hwpfilter/source/hcode.cxx @@ -1217,6 +1217,8 @@ hchar_string hstr2ucsstr(hchar const* hstr) hchar_string kstr2hstr(unsigned char const* src) { hchar_string ret; + if (!src) + return ret; for (unsigned int i = 0; src[i] != '\0' ; i++) { if ( src[i] < 127 ) commit 4b108bfb65082c26c4531e806af545444f499c91 Author: Caolán McNamara <caol...@redhat.com> Date: Tue Feb 20 16:26:21 2018 +0000 forcepoint #1 Thanks to Antti Levomäki and Christian Jalio from Forcepoint. Change-Id: Ic5e9a9d0f8f8d35cb6b39e68338ba029948a4ce0 diff --git a/hwpfilter/source/hwpfile.h b/hwpfilter/source/hwpfile.h index d58faa569a7b..3fab3a5b3dd4 100644 --- a/hwpfilter/source/hwpfile.h +++ b/hwpfilter/source/hwpfile.h @@ -227,7 +227,7 @@ class DLLEXPORT HWPFile HWPInfo& GetHWPInfo(void) { return _hwpInfo; } HWPFont& GetHWPFont(void) { return _hwpFont; } HWPStyle& GetHWPStyle(void) { return _hwpStyle; } - HWPPara *GetFirstPara(void) { return plist.front(); } + HWPPara *GetFirstPara(void) { return !plist.empty() ? plist.front() : nullptr; } EmPicture *GetEmPicture(Picture *pic); EmPicture *GetEmPictureByName(char * name); commit ee3057799b9a134746947078880097881f99c0e4 Author: Michael Stahl <mst...@redhat.com> Date: Wed Jan 24 22:24:03 2018 +0100 curl: fix CVE-2018-1000005/1000007 * don't upgrade to new release, no idea how the new windows build system likes targeting Win XP which is still supported in 5.4 Change-Id: I4fbd7f1c5f1f0563895f6f8ede10063621d10a4b Reviewed-on: https://gerrit.libreoffice.org/48542 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Eike Rathke <er...@redhat.com> (cherry picked from commit ed497921314ebd41fce3483c92ca433b502628ca) diff --git a/external/curl/CVE-2018-1000005.patch b/external/curl/CVE-2018-1000005.patch new file mode 100644 index 000000000000..7b5578b1aacc --- /dev/null +++ b/external/curl/CVE-2018-1000005.patch @@ -0,0 +1,36 @@ +From fa3dbb9a147488a2943bda809c66fc497efe06cb Mon Sep 17 00:00:00 2001 +From: Zhouyihai Ding <ddyi...@ddyihai.svl.corp.google.com> +Date: Wed, 10 Jan 2018 10:12:18 -0800 +Subject: [PATCH] http2: fix incorrect trailer buffer size + +Prior to this change the stored byte count of each trailer was +miscalculated and 1 less than required. It appears any trailer +after the first that was passed to Curl_client_write would be truncated +or corrupted as well as the size. Potentially the size of some +subsequent trailer could be erroneously extracted from the contents of +that trailer, and since that size is used by client write an +out-of-bounds read could occur and cause a crash or be otherwise +processed by client write. + +The bug appears to have been born in 0761a51 (precedes 7.49.0). + +Closes https://github.com/curl/curl/pull/2231 +--- + lib/http2.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/http2.c b/lib/http2.c +index 8e2fc71996..699287940e 100644 +--- a/lib/http2.c ++++ b/lib/http2.c +@@ -925,8 +925,8 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, + + if(stream->bodystarted) { + /* This is trailer fields. */ +- /* 3 is for ":" and "\r\n". */ +- uint32_t n = (uint32_t)(namelen + valuelen + 3); ++ /* 4 is for ": " and "\r\n". */ ++ uint32_t n = (uint32_t)(namelen + valuelen + 4); + + DEBUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen, + value)); diff --git a/external/curl/CVE-2018-1000007.patch b/external/curl/CVE-2018-1000007.patch new file mode 100644 index 000000000000..c474370c78ad --- /dev/null +++ b/external/curl/CVE-2018-1000007.patch @@ -0,0 +1,110 @@ +From af32cd3859336ab963591ca0df9b1e33a7ee066b Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg <dan...@haxx.se> +Date: Fri, 19 Jan 2018 13:19:25 +0100 +Subject: [PATCH] http: prevent custom Authorization headers in redirects + +... unless CURLOPT_UNRESTRICTED_AUTH is set to allow them. This matches how +curl already handles Authorization headers created internally. + +Note: this changes behavior slightly, for the sake of reducing mistakes. + +Added test 317 and 318 to verify. + +Reported-by: Craig de Stigter +Bug: https://curl.haxx.se/docs/adv_2018-b3bf.html +--- + docs/libcurl/opts/CURLOPT_HTTPHEADER.3 | 12 ++++- + lib/http.c | 10 +++- + lib/setopt.c | 2 +- + lib/urldata.h | 2 +- + tests/data/Makefile.inc | 2 +- + tests/data/test317 | 94 +++++++++++++++++++++++++++++++++ + tests/data/test318 | 95 ++++++++++++++++++++++++++++++++++ + 7 files changed, 212 insertions(+), 5 deletions(-) + create mode 100644 tests/data/test317 + create mode 100644 tests/data/test318 + +diff --git a/docs/libcurl/opts/CURLOPT_HTTPHEADER.3 b/docs/libcurl/opts/CURLOPT_HTTPHEADER.3 +index c5ccb1a53d..c9f29e393e 100644 +--- a/docs/libcurl/opts/CURLOPT_HTTPHEADER.3 ++++ b/docs/libcurl/opts/CURLOPT_HTTPHEADER.3 +@@ -5,7 +5,7 @@ + .\" * | (__| |_| | _ <| |___ + .\" * \___|\___/|_| \_\_____| + .\" * +-.\" * Copyright (C) 1998 - 2015, Daniel Stenberg, <dan...@haxx.se>, et al. ++.\" * Copyright (C) 1998 - 2018, Daniel Stenberg, <dan...@haxx.se>, et al. + .\" * + .\" * This software is licensed as described in the file COPYING, which + .\" * you should have received as part of this distribution. The terms +@@ -77,6 +77,16 @@ the headers. They may be private or otherwise sensitive to leak. + + Use \fICURLOPT_HEADEROPT(3)\fP to make the headers only get sent to where you + intend them to get sent. ++ ++Custom headers are sent in all requests done by the easy handles, which ++implies that if you tell libcurl to follow redirects ++(\fBCURLOPT_FOLLOWLOCATION(3)\fP), the same set of custom headers will be sent ++in the subsequent request. Redirects can of course go to other hosts and thus ++those servers will get all the contents of your custom headers too. ++ ++Starting in 7.58.0, libcurl will specifically prevent "Authorization:" headers ++from being sent to other hosts than the first used one, unless specifically ++permitted with the \fBCURLOPT_UNRESTRICTED_AUTH(3)\fP option. + .SH DEFAULT + NULL + .SH PROTOCOLS +diff --git a/lib/http.c b/lib/http.c +index c1cdf2da02..a5007670d7 100644 +--- a/lib/http.c ++++ b/lib/http.c +@@ -714,7 +714,7 @@ Curl_http_output_auth(struct connectdata *conn, + if(!data->state.this_is_a_follow || + conn->bits.netrc || + !data->state.first_host || +- data->set.http_disable_hostname_check_before_authentication || ++ data->set.allow_auth_to_other_hosts || + strcasecompare(data->state.first_host, conn->host.name)) { + result = output_auth_headers(conn, authhost, request, path, FALSE); + } +@@ -1636,6 +1636,14 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, + checkprefix("Transfer-Encoding:", headers->data)) + /* HTTP/2 doesn't support chunked requests */ + ; ++ else if(checkprefix("Authorization:", headers->data) && ++ /* be careful of sending this potentially sensitive header to ++ other hosts */ ++ (data->state.this_is_a_follow && ++ data->state.first_host && ++ !data->set.allow_auth_to_other_hosts && ++ !strcasecompare(data->state.first_host, conn->host.name))) ++ ; + else { + CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n", + headers->data); +diff --git a/lib/setopt.c b/lib/setopt.c +index 66f30ea653..a5ef75c722 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -976,7 +976,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, + * Send authentication (user+password) when following locations, even when + * hostname changed. + */ +- data->set.http_disable_hostname_check_before_authentication = ++ data->set.allow_auth_to_other_hosts = + (0 != va_arg(param, long)) ? TRUE : FALSE; + break; + +diff --git a/lib/urldata.h b/lib/urldata.h +index 4dcd1a322c..5c04ad1720 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1599,7 +1599,7 @@ struct UserDefined { + bool http_keep_sending_on_error; /* for HTTP status codes >= 300 */ + bool http_follow_location; /* follow HTTP redirects */ + bool http_transfer_encoding; /* request compressed HTTP transfer-encoding */ +- bool http_disable_hostname_check_before_authentication; ++ bool allow_auth_to_other_hosts; + bool include_header; /* include received protocol headers in data output */ + bool http_set_referer; /* is a custom referer used */ + bool http_auto_referer; /* set "correct" referer when following location: */ diff --git a/external/curl/UnpackedTarball_curl.mk b/external/curl/UnpackedTarball_curl.mk index 1359340e7881..19d4ccd4bf2e 100644 --- a/external/curl/UnpackedTarball_curl.mk +++ b/external/curl/UnpackedTarball_curl.mk @@ -25,6 +25,8 @@ $(eval $(call gb_UnpackedTarball_add_patches,curl,\ external/curl/curl-7.26.0_win-proxy.patch \ external/curl/curl-xp.patch.1 \ external/curl/CVE-2017-8816.patch \ + external/curl/CVE-2018-1000005.patch \ + external/curl/CVE-2018-1000007.patch \ )) ifeq ($(SYSTEM_NSS),) commit b56f9852e5998aa879e91fae9c48117bdfcef90c Author: Michael Stahl <mst...@redhat.com> Date: Wed Nov 29 12:28:03 2017 +0100 curl: fix CVE-2017-8816 * don't upgrade to new release, no idea how the new windows build system likes targeting Win XP which is still supported in 5.4 * CVE-2017-8817 doesn't affect LO as CURLOPT_WILDCARDMATCH isn't used * CVE-2017-8818 doesn't affect the old 7.52 version Change-Id: I49ddb771ccdb93d5fe8f4b3544f74ab9b171c156 Reviewed-on: https://gerrit.libreoffice.org/45487 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> (cherry picked from commit aa0f44de5b260b2b2a39bdd2de9445d72ab14265) diff --git a/external/curl/CVE-2017-8816.patch b/external/curl/CVE-2017-8816.patch new file mode 100644 index 000000000000..dd4fa677e03f --- /dev/null +++ b/external/curl/CVE-2017-8816.patch @@ -0,0 +1,67 @@ +From 7947c50bcd09cf471c95511739bc66d2cb506ee2 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg <dan...@haxx.se> +Date: Mon, 6 Nov 2017 23:51:52 +0100 +Subject: [PATCH] ntlm: avoid integer overflow for malloc size + +Reported-by: Alex Nichols +Assisted-by: Kamil Dudka and Max Dymond + +CVE-2017-8816 + +Bug: https://curl.haxx.se/docs/adv_2017-11e7.html +--- + lib/curl_ntlm_core.c | 23 +++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c +index 1309bf0d9..e8962769c 100644 +--- a/lib/curl_ntlm_core.c ++++ b/lib/curl_ntlm_core.c +@@ -644,23 +644,42 @@ CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, + Curl_HMAC_final(ctxt, output); + + return CURLE_OK; + } + ++#ifndef SIZE_T_MAX ++/* some limits.h headers have this defined, some don't */ ++#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4) ++#define SIZE_T_MAX 18446744073709551615U ++#else ++#define SIZE_T_MAX 4294967295U ++#endif ++#endif ++ + /* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode + * (uppercase UserName + Domain) as the data + */ + CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, + const char *domain, size_t domlen, + unsigned char *ntlmhash, + unsigned char *ntlmv2hash) + { + /* Unicode representation */ +- size_t identity_len = (userlen + domlen) * 2; +- unsigned char *identity = malloc(identity_len); ++ size_t identity_len; ++ unsigned char *identity; + CURLcode result = CURLE_OK; + ++ /* we do the length checks below separately to avoid integer overflow risk ++ on extreme data lengths */ ++ if((userlen > SIZE_T_MAX/2) || ++ (domlen > SIZE_T_MAX/2) || ++ ((userlen + domlen) > SIZE_T_MAX/2)) ++ return CURLE_OUT_OF_MEMORY; ++ ++ identity_len = (userlen + domlen) * 2; ++ identity = malloc(identity_len); ++ + if(!identity) + return CURLE_OUT_OF_MEMORY; + + ascii_uppercase_to_unicode_le(identity, user, userlen); + ascii_to_unicode_le(identity + (userlen << 1), domain, domlen); +-- +2.15.0 + diff --git a/external/curl/UnpackedTarball_curl.mk b/external/curl/UnpackedTarball_curl.mk index 546f4aa38aa9..1359340e7881 100644 --- a/external/curl/UnpackedTarball_curl.mk +++ b/external/curl/UnpackedTarball_curl.mk @@ -24,6 +24,7 @@ $(eval $(call gb_UnpackedTarball_add_patches,curl,\ external/curl/curl-7.26.0_mingw.patch \ external/curl/curl-7.26.0_win-proxy.patch \ external/curl/curl-xp.patch.1 \ + external/curl/CVE-2017-8816.patch \ )) ifeq ($(SYSTEM_NSS),) commit c949766fb458d2950f09868fe68ee09eed885e15 Author: Eike Rathke <er...@redhat.com> Date: Mon Feb 19 23:43:51 2018 +0100 Resolves: tdf#115710 let css::sheet::FunctionAccess execute WEBSERVICE ... independent of a LinkManager that is not present in the interim FunctionAccess document. FunctionAccess is executed by extensions, Add-Ons and macros that the user gave permission already. (cherry picked from commit 121fda77b0cc16d54607a1f5f7b26c0f1050284f) Change-Id: I9349a59ee24089c3657de7786b49e5e81946f175 diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index a40c07509d27..884651a580ab 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -235,7 +235,8 @@ enum ScDocumentMode { SCDOCMODE_DOCUMENT, SCDOCMODE_CLIP, - SCDOCMODE_UNDO + SCDOCMODE_UNDO, + SCDOCMODE_FUNCTIONACCESS }; struct ScDocStat @@ -422,6 +423,7 @@ private: bool bCalculatingFormulaTree; bool bIsClip; bool bIsUndo; + bool bIsFunctionAccess; bool bIsVisible; // set from view ctor bool bIsEmbedded; // display/adjust Embedded area? @@ -1376,6 +1378,7 @@ public: bool IsClipboard() const { return bIsClip; } bool IsUndoEnabled() const { return mbUndoEnabled; } SC_DLLPUBLIC void EnableUndo( bool bVal ); + bool IsFunctionAccess() const { return bIsFunctionAccess; } bool IsAdjustHeightEnabled() const { return mbAdjustHeightEnabled; } void EnableAdjustHeight( bool bVal ) { mbAdjustHeightEnabled = bVal; } diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx index 017f8629c910..529bd61bc644 100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -180,12 +180,13 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) : eHardRecalcState(HARDRECALCSTATE_OFF), nVisibleTab( 0 ), eLinkMode(LM_UNKNOWN), - bAutoCalc( eMode == SCDOCMODE_DOCUMENT ), + bAutoCalc( eMode == SCDOCMODE_DOCUMENT || eMode == SCDOCMODE_FUNCTIONACCESS ), bAutoCalcShellDisabled( false ), bForcedFormulaPending( false ), bCalculatingFormulaTree( false ), bIsClip( eMode == SCDOCMODE_CLIP ), bIsUndo( eMode == SCDOCMODE_UNDO ), + bIsFunctionAccess( eMode == SCDOCMODE_FUNCTIONACCESS ), bIsVisible( false ), bIsEmbedded( false ), bInsertingFromOtherDoc( false ), @@ -224,7 +225,9 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) : eSrcSet = osl_getThreadTextEncoding(); - if ( eMode == SCDOCMODE_DOCUMENT ) + /* TODO: for SCDOCMODE_FUNCTIONACCESS it might not even be necessary to + * have all of these available. */ + if ( eMode == SCDOCMODE_DOCUMENT || eMode == SCDOCMODE_FUNCTIONACCESS ) { xPoolHelper = new ScPoolHelper( this ); diff --git a/sc/source/core/tool/interpr7.cxx b/sc/source/core/tool/interpr7.cxx index e2f562848a31..381dd4488ba3 100644 --- a/sc/source/core/tool/interpr7.cxx +++ b/sc/source/core/tool/interpr7.cxx @@ -256,6 +256,21 @@ static ScWebServiceLink* lcl_GetWebServiceLink(const sfx2::LinkManager* pLinkMgr return nullptr; } +static bool lcl_FunctionAccessLoadWebServiceLink( OUString& rResult, ScDocument* pDoc, const OUString& rURI ) +{ + // For FunctionAccess service always force a changed data update. + ScWebServiceLink aLink( pDoc, rURI); + if (aLink.DataChanged( OUString(), css::uno::Any()) != sfx2::SvBaseLink::UpdateResult::SUCCESS) + return false; + + if (!aLink.HasResult()) + return false; + + rResult = aLink.GetResult(); + + return true; +} + void ScInterpreter::ScWebservice() { sal_uInt8 nParamCount = GetByte(); @@ -279,7 +294,18 @@ void ScInterpreter::ScWebservice() if (!mpLinkManager) { - PushError(FormulaError::NoValue); + if (!pDok->IsFunctionAccess() || pDok->HasLinkFormulaNeedingCheck()) + { + PushError( FormulaError::NoValue); + } + else + { + OUString aResult; + if (lcl_FunctionAccessLoadWebServiceLink( aResult, pDok, aURI)) + PushString( aResult); + else + PushError( FormulaError::NoValue); + } return; } diff --git a/sc/source/ui/unoobj/funcuno.cxx b/sc/source/ui/unoobj/funcuno.cxx index e9dd22b0ba0a..76585ab8d585 100644 --- a/sc/source/ui/unoobj/funcuno.cxx +++ b/sc/source/ui/unoobj/funcuno.cxx @@ -74,7 +74,7 @@ public: ScDocument* ScTempDocSource::CreateDocument() { - ScDocument* pDoc = new ScDocument; // SCDOCMODE_DOCUMENT + ScDocument* pDoc = new ScDocument( SCDOCMODE_FUNCTIONACCESS ); pDoc->MakeTable( 0 ); return pDoc; } commit cebc7844bf4156de47027ef380f2c78161cb3a8e Author: Marco Cecchetti <marco.cecche...@collabora.com> Date: Thu Feb 1 12:28:54 2018 +0100 tdf#96698 - calc: add support for custom validation (through a formula) Now it is possible to select a `custom` validation in the validation dialog: this type of validation let's the user to define a formula, the cell content is valid when the formula is evaluted to true, and not valid when evaluated to false. The `cutom` validation is correctly saved and restored for ods documents, and is correctly imported and exported to xlsx documents This patch contains an adaptation of a preliminary work of Justin Luth for importing custom validation from xlsx documents. Thanks Justin! Change-Id: Idc26654ba69a6f73d1b208d63acdad4b880c776d Reviewed-on: https://gerrit.libreoffice.org/49979 Reviewed-by: Jan Holesovsky <ke...@collabora.com> Tested-by: Jan Holesovsky <ke...@collabora.com> diff --git a/sc/inc/sc.hrc b/sc/inc/sc.hrc index 64ae387c84e3..20849ac3cc90 100644 --- a/sc/inc/sc.hrc +++ b/sc/inc/sc.hrc @@ -954,6 +954,7 @@ #define SCSTR_VALID_LIST (STR_START + 318) #define SCSTR_SELECT (STR_START + 319) +#define SCSTR_VALID_FORMULA (STR_START + 320) // media shell #define SCSTR_MEDIASHELL (STR_START + 401) diff --git a/sc/source/core/data/validat.cxx b/sc/source/core/data/validat.cxx index acc192fcc61e..f311d152a666 100644 --- a/sc/source/core/data/validat.cxx +++ b/sc/source/core/data/validat.cxx @@ -524,9 +524,49 @@ bool ScValidationData::IsDataValid( ScRefCellValue& rCell, const ScAddress& rPos break; case SC_VALID_CUSTOM: - // for Custom, it must be eOp == SC_COND_DIRECT - //TODO: the value must be in the document !!! - bOk = IsCellValid(rCell, rPos); + { + // for Custom, it must be eOp == ScConditionMode::Direct + // the value must be in the document !!! + + // so we save the original value + OUString aStrVal = mpDoc->GetString(rPos); + svl::SharedString aSS = mpDoc->GetSharedStringPool().intern(aStrVal); + std::unique_ptr<EditTextObject> pEditTextVal; + std::unique_ptr<ScFormulaCell> pFormulaVal; + + ScRefCellValue aOriginalCellValue; + aOriginalCellValue.meType = mpDoc->GetCellType(rPos); + switch (aOriginalCellValue.meType) + { + case CELLTYPE_VALUE: + aOriginalCellValue.mfValue = mpDoc->GetValue(rPos); + break; + case CELLTYPE_STRING: + aOriginalCellValue.mpString = &aSS; + break; + case CELLTYPE_EDIT: + { + pEditTextVal.reset(new EditTextObject(*(mpDoc->GetEditText(rPos)))); + aOriginalCellValue.mpEditText = pEditTextVal.get(); + } + break; + case CELLTYPE_FORMULA: + { + pFormulaVal.reset(mpDoc->GetFormulaCell(rPos)->Clone()); + aOriginalCellValue.mpFormula = pFormulaVal.get(); + } + break; + case CELLTYPE_NONE: + break; + } + + // set cell value to current input + rCell.commit(*mpDoc, rPos); + // check if the new value is valid + bOk = IsCellValid(rCell, rPos); + // and restore the original value + aOriginalCellValue.commit(*mpDoc, rPos); + } break; case SC_VALID_TEXTLEN: diff --git a/sc/source/filter/excel/xicontent.cxx b/sc/source/filter/excel/xicontent.cxx index d2418806da53..77f10c628c5c 100644 --- a/sc/source/filter/excel/xicontent.cxx +++ b/sc/source/filter/excel/xicontent.cxx @@ -886,6 +886,15 @@ void XclImpValidationManager::ReadDV( XclImpStream& rStrm ) // No valid validation found. Bail out. return; + // The default value for comparision is _BETWEEN. However, custom + // rules are a formula, and thus the comparator should be ignored + // and only a true or false from the formula is evaluated. In Calc, + // formulas use comparison SC_COND_DIRECT. + if( eValMode == SC_VALID_CUSTOM ) + { + eCondMode = SC_COND_DIRECT; + } + // first range for base address for relative references const ScRange& rScRange = *aScRanges.front(); // aScRanges is not empty diff --git a/sc/source/filter/oox/worksheethelper.cxx b/sc/source/filter/oox/worksheethelper.cxx index 978571508a08..6f75635dd32f 100644 --- a/sc/source/filter/oox/worksheethelper.cxx +++ b/sc/source/filter/oox/worksheethelper.cxx @@ -25,6 +25,7 @@ #include <com/sun/star/awt/Point.hpp> #include <com/sun/star/awt/Size.hpp> #include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/sheet/ConditionOperator2.hpp> #include <com/sun/star/sheet/TableValidationVisibility.hpp> #include <com/sun/star/sheet/ValidationType.hpp> #include <com/sun/star/sheet/ValidationAlertStyle.hpp> @@ -1131,7 +1132,10 @@ void WorksheetGlobals::finalizeValidationRanges() const { // condition operator Reference< XSheetCondition2 > xSheetCond( xValidation, UNO_QUERY_THROW ); - xSheetCond->setConditionOperator( CondFormatBuffer::convertToApiOperator( aIt->mnOperator ) ); + if( eType == ValidationType_CUSTOM ) + xSheetCond->setConditionOperator( ConditionOperator2::FORMULA ); + else + xSheetCond->setConditionOperator( CondFormatBuffer::convertToApiOperator( aIt->mnOperator ) ); // condition formulas Reference< XMultiFormulaTokens > xTokens( xValidation, UNO_QUERY_THROW ); diff --git a/sc/source/filter/xml/XMLStylesExportHelper.cxx b/sc/source/filter/xml/XMLStylesExportHelper.cxx index 06dd75fd522c..5d4734c9912c 100644 --- a/sc/source/filter/xml/XMLStylesExportHelper.cxx +++ b/sc/source/filter/xml/XMLStylesExportHelper.cxx @@ -205,12 +205,18 @@ OUString ScMyValidationsContainer::GetCondition(ScXMLExport& rExport, const ScMy case sheet::ValidationType_WHOLE : sCondition += "cell-content-is-whole-number()"; break; + case sheet::ValidationType_CUSTOM : + sCondition += "is-true-formula("; + sCondition += aValidation.sFormula1; + sCondition += ")"; + break; default: { // added to avoid warnings } } if (aValidation.aValidationType != sheet::ValidationType_LIST && + aValidation.aValidationType != sheet::ValidationType_CUSTOM && (!aValidation.sFormula1.isEmpty() || ((aValidation.aOperator == sheet::ConditionOperator_BETWEEN || aValidation.aOperator == sheet::ConditionOperator_NOT_BETWEEN) && diff --git a/sc/source/filter/xml/xmlcvali.cxx b/sc/source/filter/xml/xmlcvali.cxx index 8fdd9af90848..2220ffe6257f 100644 --- a/sc/source/filter/xml/xmlcvali.cxx +++ b/sc/source/filter/xml/xmlcvali.cxx @@ -339,6 +339,7 @@ void ScXMLContentValidationContext::GetCondition( ScMyImportValidation& rValidat case XML_COND_TEXTLENGTH_ISBETWEEN: // condition is 'cell-content-text-length-is-between(<expression1>,<expression2>)' case XML_COND_TEXTLENGTH_ISNOTBETWEEN: // condition is 'cell-content-text-length-is-not-between(<expression1>,<expression2>)' case XML_COND_ISINLIST: // condition is 'cell-content-is-in-list(<expression>)' + case XML_COND_ISTRUEFORMULA: // condition is 'is-true-formula(<expression>)' rValidation.aValidationType = aParseResult.meValidation; rValidation.aOperator = aParseResult.meOperator; break; diff --git a/sc/source/ui/dbgui/validate.cxx b/sc/source/ui/dbgui/validate.cxx index d496c6f6d8cf..15935623d7f9 100644 --- a/sc/source/ui/dbgui/validate.cxx +++ b/sc/source/ui/dbgui/validate.cxx @@ -59,6 +59,7 @@ #define SC_VALIDDLG_ALLOW_RANGE 5 #define SC_VALIDDLG_ALLOW_LIST 6 #define SC_VALIDDLG_ALLOW_TEXTLEN 7 +#define SC_VALIDDLG_ALLOW_CUSTOM 8 /* Position indexes for "Data" list box. They do not map directly to ScConditionMode and can safely be modified to @@ -71,6 +72,7 @@ #define SC_VALIDDLG_DATA_NOTEQUAL 5 #define SC_VALIDDLG_DATA_VALIDRANGE 6 #define SC_VALIDDLG_DATA_INVALIDRANGE 7 +#define SC_VALIDDLG_DATA_DIRECT 8 namespace ValidListType = css::sheet::TableValidationVisibility; @@ -200,7 +202,7 @@ sal_uInt16 lclGetPosFromValMode( ScValidationMode eValMode ) case SC_VALID_TIME: nLbPos = SC_VALIDDLG_ALLOW_TIME; break; case SC_VALID_TEXTLEN: nLbPos = SC_VALIDDLG_ALLOW_TEXTLEN; break; case SC_VALID_LIST: nLbPos = SC_VALIDDLG_ALLOW_RANGE; break; - case SC_VALID_CUSTOM: nLbPos = SC_VALIDDLG_ALLOW_ANY; break; // not supported + case SC_VALID_CUSTOM: nLbPos = SC_VALIDDLG_ALLOW_CUSTOM; break; default: OSL_FAIL( "lclGetPosFromValMode - unknown validity mode" ); } return nLbPos; @@ -220,6 +222,7 @@ ScValidationMode lclGetValModeFromPos( sal_uInt16 nLbPos ) case SC_VALIDDLG_ALLOW_RANGE: eValMode = SC_VALID_LIST; break; case SC_VALIDDLG_ALLOW_LIST: eValMode = SC_VALID_LIST; break; case SC_VALIDDLG_ALLOW_TEXTLEN: eValMode = SC_VALID_TEXTLEN; break; + case SC_VALIDDLG_ALLOW_CUSTOM: eValMode = SC_VALID_CUSTOM; break; default: OSL_FAIL( "lclGetValModeFromPos - invalid list box position" ); } return eValMode; @@ -240,6 +243,7 @@ sal_uInt16 lclGetPosFromCondMode( ScConditionMode eCondMode ) case SC_COND_NOTEQUAL: nLbPos = SC_VALIDDLG_DATA_NOTEQUAL; break; case SC_COND_BETWEEN: nLbPos = SC_VALIDDLG_DATA_VALIDRANGE; break; case SC_COND_NOTBETWEEN: nLbPos = SC_VALIDDLG_DATA_INVALIDRANGE; break; + case SC_COND_DIRECT: nLbPos = SC_VALIDDLG_DATA_DIRECT; break; default: OSL_FAIL( "lclGetPosFromCondMode - unknown condition mode" ); } return nLbPos; @@ -259,6 +263,7 @@ ScConditionMode lclGetCondModeFromPos( sal_uInt16 nLbPos ) case SC_VALIDDLG_DATA_NOTEQUAL: eCondMode = SC_COND_NOTEQUAL; break; case SC_VALIDDLG_DATA_VALIDRANGE: eCondMode = SC_COND_BETWEEN; break; case SC_VALIDDLG_DATA_INVALIDRANGE: eCondMode = SC_COND_NOTBETWEEN; break; + case SC_VALIDDLG_DATA_DIRECT: eCondMode = SC_COND_DIRECT; break; default: OSL_FAIL( "lclGetCondModeFromPos - invalid list box position" ); } return eCondMode; @@ -323,6 +328,7 @@ ScTPValidationValue::ScTPValidationValue( vcl::Window* pParent, const SfxItemSet , maStrMin(ScResId(SCSTR_VALID_MINIMUM)) , maStrMax(ScResId(SCSTR_VALID_MAXIMUM)) , maStrValue(ScResId(SCSTR_VALID_VALUE)) + , maStrFormula(ScResId(SCSTR_VALID_FORMULA)) , maStrRange(ScResId(SCSTR_VALID_RANGE)) , maStrList(ScResId(SCSTR_VALID_LIST)) , m_pRefEdit(nullptr) @@ -464,10 +470,13 @@ bool ScTPValidationValue::FillItemSet( SfxItemSet* rArgSet ) (m_pCbSort->IsChecked() ? ValidListType::SORTEDASCENDING : ValidListType::UNSORTED) : ValidListType::INVISIBLE; - rArgSet->Put( SfxAllEnumItem( FID_VALID_MODE, sal::static_int_cast<sal_uInt16>( - lclGetValModeFromPos( m_pLbAllow->GetSelectEntryPos() ) ) ) ); - rArgSet->Put( SfxAllEnumItem( FID_VALID_CONDMODE, sal::static_int_cast<sal_uInt16>( - lclGetCondModeFromPos( m_pLbValue->GetSelectEntryPos() ) ) ) ); + const sal_Int32 nLbPos = m_pLbAllow->GetSelectEntryPos(); + bool bCustom = (nLbPos == SC_VALIDDLG_ALLOW_CUSTOM); + ScConditionMode eCondMode = bCustom ? + SC_COND_DIRECT : lclGetCondModeFromPos( m_pLbValue->GetSelectEntryPos() ); + + rArgSet->Put( SfxAllEnumItem( FID_VALID_MODE, sal::static_int_cast<sal_uInt16>( lclGetValModeFromPos( nLbPos ) ) ) ); + rArgSet->Put( SfxAllEnumItem( FID_VALID_CONDMODE, sal::static_int_cast<sal_uInt16>( eCondMode ) ) ); rArgSet->Put( SfxStringItem( FID_VALID_VALUE1, GetFirstFormula() ) ); rArgSet->Put( SfxStringItem( FID_VALID_VALUE2, GetSecondFormula() ) ); rArgSet->Put( SfxBoolItem( FID_VALID_BLANK, m_pCbAllow->IsChecked() ) ); @@ -609,6 +618,7 @@ IMPL_LINK_NOARG(ScTPValidationValue, SelectHdl, ListBox&, void) bool bEnable = (nLbPos != SC_VALIDDLG_ALLOW_ANY); bool bRange = (nLbPos == SC_VALIDDLG_ALLOW_RANGE); bool bList = (nLbPos == SC_VALIDDLG_ALLOW_LIST); + bool bCustom = (nLbPos == SC_VALIDDLG_ALLOW_CUSTOM); m_pCbAllow->Enable( bEnable ); // Empty cell m_pFtValue->Enable( bEnable ); @@ -620,10 +630,13 @@ IMPL_LINK_NOARG(ScTPValidationValue, SelectHdl, ListBox&, void) m_pEdMax->Enable( bEnable ); bool bShowMax = false; + if( bRange ) m_pFtMin->SetText( maStrRange ); else if( bList ) m_pFtMin->SetText( maStrList ); + else if( bCustom ) + m_pFtMin->SetText( maStrFormula ); else { switch( m_pLbValue->GetSelectEntryPos() ) @@ -647,8 +660,8 @@ IMPL_LINK_NOARG(ScTPValidationValue, SelectHdl, ListBox&, void) m_pCbShow->Show( bRange || bList ); m_pCbSort->Show( bRange || bList ); - m_pFtValue->Show( !bRange && !bList ); - m_pLbValue->Show( !bRange && !bList ); + m_pFtValue->Show( !bRange && !bList && !bCustom); + m_pLbValue->Show( !bRange && !bList && !bCustom ); m_pEdMin->Show( !bList ); m_pEdList->Show( bList ); m_pMinGrid->set_vexpand( bList ); diff --git a/sc/source/ui/inc/validate.hxx b/sc/source/ui/inc/validate.hxx index 350e32a612c8..270b2fd00990 100644 --- a/sc/source/ui/inc/validate.hxx +++ b/sc/source/ui/inc/validate.hxx @@ -119,6 +119,7 @@ private: OUString maStrMin; OUString maStrMax; OUString maStrValue; + OUString maStrFormula; OUString maStrRange; OUString maStrList; sal_Unicode mcFmlaSep; /// List separator in formulas. diff --git a/sc/source/ui/view/cellsh2.cxx b/sc/source/ui/view/cellsh2.cxx index c3073f36c173..b492633ed875 100644 --- a/sc/source/ui/view/cellsh2.cxx +++ b/sc/source/ui/view/cellsh2.cxx @@ -855,7 +855,7 @@ void ScCellShell::ExecuteDB( SfxRequest& rReq ) } // cell range picker - ScopedVclPtrInstance<ScValidationDlg> pDlg(nullptr, &aArgSet, pTabViewShell); + ScopedVclPtrInstance<ScValidationDlg> pDlg(GetViewData()->GetActiveWin(), &aArgSet, pTabViewShell); short nResult = pDlg->Execute(); if ( nResult == RET_OK ) diff --git a/sc/uiconfig/scalc/ui/validationcriteriapage.ui b/sc/uiconfig/scalc/ui/validationcriteriapage.ui index 9c5efefdb16b..4954a20a263e 100644 --- a/sc/uiconfig/scalc/ui/validationcriteriapage.ui +++ b/sc/uiconfig/scalc/ui/validationcriteriapage.ui @@ -43,6 +43,10 @@ <col id="0" translatable="yes">Text length</col> <col id="1">7</col> </row> + <row> + <col id="0" translatable="yes" context="validationcriteriapage|liststore1">Custom</col> + <col id="1">8</col> + </row> </data> </object> <object class="GtkListStore" id="liststore2"> _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits