1 diff --git sc/inc/tabprotection.hxx sc/inc/tabprotection.hxx
2 index 99fec7b..b986070 100644
3 --- sc/inc/tabprotection.hxx
4 +++ sc/inc/tabprotection.hxx
6 #include <com/sun/star/uno/Sequence.hxx>
10 #include <boost/shared_ptr.hpp>
12 #define ENABLE_SHEET_PROTECTION 1
13 @@ -45,8 +44,9 @@ class ScTableProtectionImpl;
21 + PASSHASH_UNSPECIFIED
24 class ScPassHashHelper
25 @@ -56,7 +56,11 @@ public:
26 least one hash that needs to be regenerated, it returns true. If all
27 hash values are compatible with the specified hash type, then it
29 - static bool needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash);
30 + static bool needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash1, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED);
32 + static ::rtl::OUString getHashURI(ScPasswordHash eHash);
34 + static ScPasswordHash getHashTypeFromURI(const ::rtl::OUString& rURI);
38 @@ -75,11 +79,13 @@ public:
39 virtual void setProtected(bool bProtected) = 0;
41 virtual bool isPasswordEmpty() const = 0;
42 - virtual bool hasPasswordHash(ScPasswordHash eHash) const = 0;
43 + virtual bool hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const = 0;
44 virtual void setPassword(const String& aPassText) = 0;
45 - virtual ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(ScPasswordHash eHash) const = 0;
46 - virtual void setPasswordHash(const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword,
47 - ScPasswordHash eHash = PASSHASH_OOO) = 0;
48 + virtual ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(
49 + ScPasswordHash eHash, ScPasswordHash eHas2 = PASSHASH_UNSPECIFIED) const = 0;
50 + virtual void setPasswordHash(
51 + const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword,
52 + ScPasswordHash eHash = PASSHASH_SHA1, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) = 0;
53 virtual bool verifyPassword(const String& aPassText) const = 0;
56 @@ -105,11 +111,13 @@ public:
57 virtual void setProtected(bool bProtected);
59 virtual bool isPasswordEmpty() const;
60 - virtual bool hasPasswordHash(ScPasswordHash eHash) const;
61 + virtual bool hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
62 virtual void setPassword(const String& aPassText);
63 - virtual ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(ScPasswordHash eHash) const;
64 - virtual void setPasswordHash(const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword,
65 - ScPasswordHash eHash = PASSHASH_OOO);
66 + virtual ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(
67 + ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
68 + virtual void setPasswordHash(
69 + const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword,
70 + ScPasswordHash eHash = PASSHASH_SHA1, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED);
71 virtual bool verifyPassword(const String& aPassText) const;
73 bool isOptionEnabled(Option eOption) const;
74 @@ -162,11 +170,13 @@ public:
75 virtual void setProtected(bool bProtected);
77 virtual bool isPasswordEmpty() const;
78 - virtual bool hasPasswordHash(ScPasswordHash eHash) const;
79 + virtual bool hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
80 virtual void setPassword(const String& aPassText);
81 - virtual ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(ScPasswordHash eHash) const;
82 - virtual void setPasswordHash(const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword,
83 - ScPasswordHash eHash = PASSHASH_OOO);
84 + virtual ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(
85 + ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
86 + virtual void setPasswordHash(
87 + const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword,
88 + ScPasswordHash eHash = PASSHASH_SHA1, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED);
89 virtual bool verifyPassword(const String& aPassText) const;
91 bool isOptionEnabled(Option eOption) const;
92 diff --git sc/source/core/data/tabprotection.cxx sc/source/core/data/tabprotection.cxx
93 index 2e51a33..463e6a8 100644
94 --- sc/source/core/data/tabprotection.cxx
95 +++ sc/source/core/data/tabprotection.cxx
97 #include "svtools/PasswordHelper.hxx"
98 #include "document.hxx"
102 #define DEBUG_TAB_PROTECTION 0
104 +#define URI_SHA1 "http://www.w3.org/2000/09/xmldsig#sha1"
105 +#define URI_XLS_LEGACY "http://docs.oasis-open.org/office/ns/table/legacy-hash-excel"
107 using namespace ::com::sun::star;
108 using ::com::sun::star::uno::Sequence;
109 using ::rtl::OUString;
110 +using ::rtl::OUStringBuffer;
111 +using ::std::vector;
113 // ============================================================================
115 -bool ScPassHashHelper::needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash)
116 +bool ScPassHashHelper::needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash1, ScPasswordHash eHash2)
118 if (rDoc.IsDocProtected())
120 const ScDocProtection* p = rDoc.GetDocProtection();
121 - if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash))
122 + if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash1, eHash2))
126 @@ -63,13 +70,37 @@ bool ScPassHashHelper::needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash
127 // Sheet not protected. Skip it.
130 - if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash))
131 + if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash1, eHash2))
138 +OUString ScPassHashHelper::getHashURI(ScPasswordHash eHash)
142 + case PASSHASH_SHA1:
143 + return OUString::createFromAscii(URI_SHA1);
145 + return OUString::createFromAscii(URI_XLS_LEGACY);
146 + case PASSHASH_UNSPECIFIED:
153 +ScPasswordHash ScPassHashHelper::getHashTypeFromURI(const OUString& rURI)
155 + if (rURI.equalsAscii(URI_SHA1))
156 + return PASSHASH_SHA1;
157 + else if (rURI.equalsAscii(URI_XLS_LEGACY))
158 + return PASSHASH_XL;
159 + return PASSHASH_UNSPECIFIED;
162 // ============================================================================
164 ScPassHashProtectable::~ScPassHashProtectable()
165 @@ -115,7 +146,8 @@ static Sequence<sal_Int8> lcl_getXLHash(const String& aPassText)
166 class ScTableProtectionImpl
169 - static ::com::sun::star::uno::Sequence<sal_Int8> hashPassword(const String& aPassText, ScPasswordHash eHash = PASSHASH_OOO);
170 + static Sequence<sal_Int8> hashPassword(const String& aPassText, ScPasswordHash eHash = PASSHASH_SHA1);
171 + static Sequence<sal_Int8> hashPassword(const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash = PASSHASH_SHA1);
173 explicit ScTableProtectionImpl(SCSIZE nOptSize);
174 explicit ScTableProtectionImpl(const ScTableProtectionImpl& r);
175 @@ -125,10 +157,13 @@ public:
176 void setProtected(bool bProtected);
178 bool isPasswordEmpty() const;
179 - bool hasPasswordHash(ScPasswordHash eHash) const;
180 + bool hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
181 void setPassword(const String& aPassText);
182 - ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(ScPasswordHash eHash) const;
183 - void setPasswordHash(const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash = PASSHASH_OOO);
184 + ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(
185 + ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
186 + void setPasswordHash(
187 + const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword,
188 + ScPasswordHash eHash = PASSHASH_SHA1, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED);
189 bool verifyPassword(const String& aPassText) const;
191 bool isOptionEnabled(SCSIZE nOptId) const;
192 @@ -140,7 +175,8 @@ private:
193 ::std::vector<bool> maOptions;
196 - ScPasswordHash meHash;
197 + ScPasswordHash meHash1;
198 + ScPasswordHash meHash2;
201 Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(const String& aPassText, ScPasswordHash eHash)
202 @@ -151,19 +187,44 @@ Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(const String& aPassText,
204 aHash = lcl_getXLHash(aPassText);
208 + case PASSHASH_SHA1:
209 SvPasswordHelper::GetHashPassword(aHash, aPassText);
217 +Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(
218 + const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash)
220 + if (!rPassHash.getLength() || eHash == PASSHASH_UNSPECIFIED)
223 + // TODO: Right now, we only support double-hash by SHA1.
224 + if (eHash == PASSHASH_SHA1)
226 + vector<sal_Char> aChars;
227 + sal_Int32 n = rPassHash.getLength();
229 + for (sal_Int32 i = 0; i < n; ++i)
230 + aChars.push_back(static_cast<sal_Char>(rPassHash[i]));
232 + Sequence<sal_Int8> aNewHash;
233 + SvPasswordHelper::GetHashPassword(aNewHash, &aChars[0], aChars.size());
240 ScTableProtectionImpl::ScTableProtectionImpl(SCSIZE nOptSize) :
244 - meHash(PASSHASH_OOO)
245 + meHash1(PASSHASH_SHA1),
246 + meHash2(PASSHASH_UNSPECIFIED)
250 @@ -173,7 +234,8 @@ ScTableProtectionImpl::ScTableProtectionImpl(const ScTableProtectionImpl& r) :
251 maOptions(r.maOptions),
252 mbEmptyPass(r.mbEmptyPass),
253 mbProtected(r.mbProtected),
255 + meHash1(r.meHash1),
260 @@ -217,7 +279,7 @@ bool ScTableProtectionImpl::isPasswordEmpty() const
264 -bool ScTableProtectionImpl::hasPasswordHash(ScPasswordHash eHash) const
265 +bool ScTableProtectionImpl::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
269 @@ -225,35 +287,65 @@ bool ScTableProtectionImpl::hasPasswordHash(ScPasswordHash eHash) const
270 if (maPassText.Len())
273 - if (meHash == eHash)
275 + if (meHash1 == eHash)
277 + if (meHash2 == PASSHASH_UNSPECIFIED)
281 + return meHash2 == eHash2;
287 -Sequence<sal_Int8> ScTableProtectionImpl::getPasswordHash(ScPasswordHash eHash) const
288 +Sequence<sal_Int8> ScTableProtectionImpl::getPasswordHash(
289 + ScPasswordHash eHash, ScPasswordHash eHash2) const
291 + Sequence<sal_Int8> aPassHash;
295 - return Sequence<sal_Int8>();
298 if (maPassText.Len())
300 // Cleartext password exists. Hash it.
301 - return hashPassword(maPassText, eHash);
302 + aPassHash = hashPassword(maPassText, eHash);
303 + if (eHash2 != PASSHASH_UNSPECIFIED)
305 + aPassHash = hashPassword(aPassHash, eHash2);
307 - if (meHash == eHash)
308 - // Stored hash exists.
314 + // No clear text password. Check if we have a hash value of the right hash type.
315 + if (meHash1 == eHash)
317 + aPassHash = maPassHash;
319 + if (meHash2 == eHash2)
320 + // Matching double-hash requested.
322 + else if (meHash2 == PASSHASH_UNSPECIFIED)
323 + // primary hashing type match. Double hash it by the requested
324 + // double-hash type.
325 + return hashPassword(aPassHash, eHash2);
329 - // Failed to find a matching hash.
331 return Sequence<sal_Int8>();
334 -void ScTableProtectionImpl::setPasswordHash(const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash)
335 +void ScTableProtectionImpl::setPasswordHash(
336 + const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
338 sal_Int32 nLen = aPassword.getLength();
339 mbEmptyPass = nLen <= 0 ? true : false;
343 maPassHash = aPassword;
345 #if DEBUG_TAB_PROTECTION
346 @@ -277,7 +369,8 @@ bool ScTableProtectionImpl::verifyPassword(const String& aPassText) const
347 // Clear text password exists, and this one takes precedence.
348 return aPassText.Equals(maPassText);
350 - Sequence<sal_Int8> aHash = hashPassword(aPassText, meHash);
351 + Sequence<sal_Int8> aHash = hashPassword(aPassText, meHash1);
352 + aHash = hashPassword(aHash, meHash2);
354 #if DEBUG_TAB_PROTECTION
355 fprintf(stdout, "ScTableProtectionImpl::verifyPassword: hash = ");
356 @@ -353,9 +446,9 @@ bool ScDocProtection::isPasswordEmpty() const
357 return mpImpl->isPasswordEmpty();
360 -bool ScDocProtection::hasPasswordHash(ScPasswordHash eHash) const
361 +bool ScDocProtection::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
363 - return mpImpl->hasPasswordHash(eHash);
364 + return mpImpl->hasPasswordHash(eHash, eHash2);
367 void ScDocProtection::setPassword(const String& aPassText)
368 @@ -363,14 +456,15 @@ void ScDocProtection::setPassword(const String& aPassText)
369 mpImpl->setPassword(aPassText);
372 -uno::Sequence<sal_Int8> ScDocProtection::getPasswordHash(ScPasswordHash eHash) const
373 +uno::Sequence<sal_Int8> ScDocProtection::getPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
375 - return mpImpl->getPasswordHash(eHash);
376 + return mpImpl->getPasswordHash(eHash, eHash2);
379 -void ScDocProtection::setPasswordHash(const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash)
380 +void ScDocProtection::setPasswordHash(
381 + const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
383 - mpImpl->setPasswordHash(aPassword, eHash);
384 + mpImpl->setPasswordHash(aPassword, eHash, eHash2);
387 bool ScDocProtection::verifyPassword(const String& aPassText) const
388 @@ -428,9 +522,9 @@ bool ScTableProtection::isPasswordEmpty() const
389 return mpImpl->isPasswordEmpty();
392 -bool ScTableProtection::hasPasswordHash(ScPasswordHash eHash) const
393 +bool ScTableProtection::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
395 - return mpImpl->hasPasswordHash(eHash);
396 + return mpImpl->hasPasswordHash(eHash, eHash2);
399 void ScTableProtection::setPassword(const String& aPassText)
400 @@ -438,14 +532,15 @@ void ScTableProtection::setPassword(const String& aPassText)
401 mpImpl->setPassword(aPassText);
404 -Sequence<sal_Int8> ScTableProtection::getPasswordHash(ScPasswordHash eHash) const
405 +Sequence<sal_Int8> ScTableProtection::getPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
407 - return mpImpl->getPasswordHash(eHash);
408 + return mpImpl->getPasswordHash(eHash, eHash2);
411 -void ScTableProtection::setPasswordHash(const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash)
412 +void ScTableProtection::setPasswordHash(
413 + const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
415 - mpImpl->setPasswordHash(aPassword, eHash);
416 + mpImpl->setPasswordHash(aPassword, eHash, eHash2);
419 bool ScTableProtection::verifyPassword(const String& aPassText) const
420 diff --git sc/source/filter/xml/xmlbodyi.cxx sc/source/filter/xml/xmlbodyi.cxx
421 index fa993ef..c118998 100644
422 --- sc/source/filter/xml/xmlbodyi.cxx
423 +++ sc/source/filter/xml/xmlbodyi.cxx
424 @@ -77,6 +77,8 @@ ScXMLBodyContext::ScXMLBodyContext( ScXMLImport& rImport,
425 const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
426 SvXMLImportContext( rImport, nPrfx, rLName ),
428 + meHash1(PASSHASH_UNSPECIFIED),
429 + meHash2(PASSHASH_UNSPECIFIED),
430 bProtected(sal_False),
431 bHadCalculationSettings(sal_False),
432 pChangeTrackingImportHelper(NULL)
433 @@ -122,6 +124,10 @@ ScXMLBodyContext::ScXMLBodyContext( ScXMLImport& rImport,
434 bProtected = IsXMLToken(sValue, XML_TRUE);
435 else if (IsXMLToken(aLocalName, XML_PROTECTION_KEY))
437 + else if (IsXMLToken(aLocalName, XML_PROTECTION_KEY_DIGEST_ALGORITHM))
438 + meHash1 = ScPassHashHelper::getHashTypeFromURI(sValue);
439 + else if (IsXMLToken(aLocalName, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2))
440 + meHash2 = ScPassHashHelper::getHashTypeFromURI(sValue);
444 @@ -291,7 +297,7 @@ void ScXMLBodyContext::EndElement()
445 if (sPassword.getLength())
447 SvXMLUnitConverter::decodeBase64(aPass, sPassword);
448 - pProtection->setPasswordHash(aPass, PASSHASH_OOO);
449 + pProtection->setPasswordHash(aPass, meHash1, meHash2);
452 pDoc->SetDocProtection(pProtection.get());
453 diff --git sc/source/filter/xml/xmlbodyi.hxx sc/source/filter/xml/xmlbodyi.hxx
454 index 483741e..69d5407 100644
455 --- sc/source/filter/xml/xmlbodyi.hxx
456 +++ sc/source/filter/xml/xmlbodyi.hxx
458 #include <xmloff/xmlictxt.hxx>
459 #include <xmloff/xmlimp.hxx>
461 +#include "tabprotection.hxx"
464 class ScXMLChangeTrackingImportHelper;
466 class ScXMLBodyContext : public SvXMLImportContext
468 rtl::OUString sPassword;
469 + ScPasswordHash meHash1;
470 + ScPasswordHash meHash2;
472 sal_Bool bHadCalculationSettings;
474 diff --git sc/source/filter/xml/xmlexprt.cxx sc/source/filter/xml/xmlexprt.cxx
475 index 3658d78..089f12d 100644
476 --- sc/source/filter/xml/xmlexprt.cxx
477 +++ sc/source/filter/xml/xmlexprt.cxx
478 @@ -1441,12 +1441,36 @@ void ScXMLExport::SetBodyAttributes()
479 AddAttribute(XML_NAMESPACE_TABLE, XML_STRUCTURE_PROTECTED, XML_TRUE);
480 rtl::OUStringBuffer aBuffer;
481 uno::Sequence<sal_Int8> aPassHash;
482 + ScPasswordHash eHashUsed = PASSHASH_UNSPECIFIED;
483 const ScDocProtection* p = pDoc->GetDocProtection();
485 - aPassHash = p->getPasswordHash(PASSHASH_OOO);
487 + if (p->hasPasswordHash(PASSHASH_SHA1))
489 + aPassHash = p->getPasswordHash(PASSHASH_SHA1);
490 + eHashUsed = PASSHASH_SHA1;
492 + else if (p->hasPasswordHash(PASSHASH_XL, PASSHASH_SHA1))
494 + aPassHash = p->getPasswordHash(PASSHASH_XL, PASSHASH_SHA1);
495 + eHashUsed = PASSHASH_XL;
498 SvXMLUnitConverter::encodeBase64(aBuffer, aPassHash);
499 if (aBuffer.getLength())
501 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear());
502 + if (eHashUsed == PASSHASH_XL)
504 + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
505 + ScPassHashHelper::getHashURI(PASSHASH_XL));
506 + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2,
507 + ScPassHashHelper::getHashURI(PASSHASH_SHA1));
509 + else if (eHashUsed == PASSHASH_SHA1)
510 + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
511 + ScPassHashHelper::getHashURI(PASSHASH_SHA1));
516 @@ -1513,18 +1537,46 @@ void ScXMLExport::_ExportContent()
517 AddAttribute(sAttrName, sOUTableName);
518 AddAttribute(sAttrStyleName, aTableStyles[nTable]);
519 uno::Reference<util::XProtectable> xProtectable (xTable, uno::UNO_QUERY);
520 + ScTableProtection* pProtect = NULL;
521 if (xProtectable.is() && xProtectable->isProtected())
523 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE);
524 - rtl::OUStringBuffer aBuffer;
527 - ScTableProtection* pProtect = pDoc->GetTabProtection(static_cast<SCTAB>(nTable));
528 + pProtect = pDoc->GetTabProtection(static_cast<SCTAB>(nTable));
530 - SvXMLUnitConverter::encodeBase64(aBuffer, pProtect->getPasswordHash(PASSHASH_OOO));
532 + rtl::OUStringBuffer aBuffer;
533 + ScPasswordHash eHashUsed = PASSHASH_UNSPECIFIED;
534 + if (pProtect->hasPasswordHash(PASSHASH_SHA1))
536 + SvXMLUnitConverter::encodeBase64(aBuffer, pProtect->getPasswordHash(PASSHASH_SHA1));
537 + eHashUsed = PASSHASH_SHA1;
539 + else if (pProtect->hasPasswordHash(PASSHASH_XL, PASSHASH_SHA1))
541 + // Double-hash this by SHA1 on top of the legacy xls hash.
542 + uno::Sequence<sal_Int8> aHash = pProtect->getPasswordHash(PASSHASH_XL, PASSHASH_SHA1);
543 + SvXMLUnitConverter::encodeBase64(aBuffer, aHash);
544 + eHashUsed = PASSHASH_XL;
546 + if (aBuffer.getLength())
548 + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear());
549 + if (eHashUsed == PASSHASH_XL)
551 + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
552 + ScPassHashHelper::getHashURI(PASSHASH_XL));
553 + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2,
554 + ScPassHashHelper::getHashURI(PASSHASH_SHA1));
556 + else if (eHashUsed == PASSHASH_SHA1)
557 + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
558 + ScPassHashHelper::getHashURI(PASSHASH_SHA1));
563 - if (aBuffer.getLength())
564 - AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear());
566 rtl::OUString sPrintRanges;
567 table::CellRangeAddress aColumnHeaderRange;
568 @@ -1535,6 +1587,20 @@ void ScXMLExport::_ExportContent()
569 else if (!pDoc->IsPrintEntireSheet(static_cast<SCTAB>(nTable)))
570 AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT, XML_FALSE);
571 SvXMLElementExport aElemT(*this, sElemTab, sal_True, sal_True);
573 + if (pProtect && pProtect->isProtected())
575 + if (pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS))
576 + AddAttribute(XML_NAMESPACE_TABLE, XML_SELECT_PROTECTED_CELLS, XML_TRUE);
577 + if (pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS))
578 + AddAttribute(XML_NAMESPACE_TABLE, XML_SELECT_UNPROTECTED_CELLS, XML_TRUE);
580 + rtl::OUString aElemName = GetNamespaceMap().GetQNameByKey(
581 + XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE_PROTECTION));
583 + SvXMLElementExport aElemProtected(*this, aElemName, true, true);
589 diff --git sc/source/filter/xml/xmlimprt.cxx sc/source/filter/xml/xmlimprt.cxx
590 index 4517591..728373e 100644
591 --- sc/source/filter/xml/xmlimprt.cxx
592 +++ sc/source/filter/xml/xmlimprt.cxx
593 @@ -637,6 +637,7 @@ const SvXMLTokenMap& ScXMLImport::GetTableElemTokenMap()
594 { XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, XML_TOK_TABLE_HEADER_COLS },
595 { XML_NAMESPACE_TABLE, XML_TABLE_COLUMNS, XML_TOK_TABLE_COLS },
596 { XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, XML_TOK_TABLE_COL },
597 + { XML_NAMESPACE_TABLE, XML_TABLE_PROTECTION, XML_TOK_TABLE_PROTECTION },
598 { XML_NAMESPACE_TABLE, XML_TABLE_ROW_GROUP, XML_TOK_TABLE_ROW_GROUP },
599 { XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, XML_TOK_TABLE_HEADER_ROWS },
600 { XML_NAMESPACE_TABLE, XML_TABLE_ROWS, XML_TOK_TABLE_ROWS },
601 @@ -654,6 +655,22 @@ const SvXMLTokenMap& ScXMLImport::GetTableElemTokenMap()
602 return *pTableElemTokenMap;
605 +const SvXMLTokenMap& ScXMLImport::GetTableProtectionAttrTokenMap()
607 + if (!pTableProtectionElemTokenMap)
609 + static __FAR_DATA SvXMLTokenMapEntry aTableProtectionTokenMap[] =
611 + { XML_NAMESPACE_TABLE, XML_SELECT_PROTECTED_CELLS, XML_TOK_TABLE_SELECT_PROTECTED_CELLS },
612 + { XML_NAMESPACE_TABLE, XML_SELECT_UNPROTECTED_CELLS, XML_TOK_TABLE_SELECT_UNPROTECTED_CELLS },
615 + pTableProtectionElemTokenMap = new SvXMLTokenMap(aTableProtectionTokenMap);
618 + return *pTableProtectionElemTokenMap;
621 const SvXMLTokenMap& ScXMLImport::GetTableRowsElemTokenMap()
623 if( !pTableRowsElemTokenMap )
624 @@ -700,9 +717,11 @@ const SvXMLTokenMap& ScXMLImport::GetTableAttrTokenMap()
626 { XML_NAMESPACE_TABLE, XML_NAME, XML_TOK_TABLE_NAME },
627 { XML_NAMESPACE_TABLE, XML_STYLE_NAME, XML_TOK_TABLE_STYLE_NAME },
628 - { XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TOK_TABLE_PROTECTION },
629 + { XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TOK_TABLE_PROTECTED },
630 { XML_NAMESPACE_TABLE, XML_PRINT_RANGES, XML_TOK_TABLE_PRINT_RANGES },
631 { XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, XML_TOK_TABLE_PASSWORD },
632 + { XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM, XML_TOK_TABLE_PASSHASH },
633 + { XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2, XML_TOK_TABLE_PASSHASH_2 },
634 { XML_NAMESPACE_TABLE, XML_PRINT, XML_TOK_TABLE_PRINT },
637 @@ -1685,6 +1704,7 @@ ScXMLImport::ScXMLImport(
638 pLabelRangesElemTokenMap( 0 ),
639 pLabelRangeAttrTokenMap( 0 ),
640 pTableElemTokenMap( 0 ),
641 + pTableProtectionElemTokenMap(NULL),
642 pTableRowsElemTokenMap( 0 ),
643 pTableColsElemTokenMap( 0 ),
644 pTableScenarioAttrTokenMap( 0 ),
645 @@ -1811,6 +1831,7 @@ ScXMLImport::~ScXMLImport() throw()
646 delete pLabelRangesElemTokenMap;
647 delete pLabelRangeAttrTokenMap;
648 delete pTableElemTokenMap;
649 + delete pTableProtectionElemTokenMap;
650 delete pTableRowsElemTokenMap;
651 delete pTableColsElemTokenMap;
652 delete pTableAttrTokenMap;
653 diff --git sc/source/filter/xml/xmlimprt.hxx sc/source/filter/xml/xmlimprt.hxx
654 index 093846a..8ff4178 100644
655 --- sc/source/filter/xml/xmlimprt.hxx
656 +++ sc/source/filter/xml/xmlimprt.hxx
657 @@ -172,6 +172,7 @@ enum ScXMLTableTokens
659 XML_TOK_TABLE_ROW_GROUP,
660 XML_TOK_TABLE_HEADER_ROWS,
661 + XML_TOK_TABLE_PROTECTION,
664 XML_TOK_TABLE_SOURCE,
665 @@ -180,6 +181,12 @@ enum ScXMLTableTokens
669 +enum ScXMLTokenProtectionTokens
671 + XML_TOK_TABLE_SELECT_PROTECTED_CELLS,
672 + XML_TOK_TABLE_SELECT_UNPROTECTED_CELLS
675 enum ScXMLTableRowsTokens
677 XML_TOK_TABLE_ROWS_ROW_GROUP,
678 @@ -200,9 +207,11 @@ enum ScXMLTableAttrTokens
681 XML_TOK_TABLE_STYLE_NAME,
682 - XML_TOK_TABLE_PROTECTION,
683 + XML_TOK_TABLE_PROTECTED,
684 XML_TOK_TABLE_PRINT_RANGES,
685 XML_TOK_TABLE_PASSWORD,
686 + XML_TOK_TABLE_PASSHASH,
687 + XML_TOK_TABLE_PASSHASH_2,
691 @@ -699,6 +708,7 @@ class ScXMLImport: public SvXMLImport
692 SvXMLTokenMap *pLabelRangesElemTokenMap;
693 SvXMLTokenMap *pLabelRangeAttrTokenMap;
694 SvXMLTokenMap *pTableElemTokenMap;
695 + SvXMLTokenMap *pTableProtectionElemTokenMap;
696 SvXMLTokenMap *pTableRowsElemTokenMap;
697 SvXMLTokenMap *pTableColsElemTokenMap;
698 SvXMLTokenMap *pTableScenarioAttrTokenMap;
699 @@ -865,6 +875,7 @@ public:
700 const SvXMLTokenMap& GetLabelRangesElemTokenMap();
701 const SvXMLTokenMap& GetLabelRangeAttrTokenMap();
702 const SvXMLTokenMap& GetTableElemTokenMap();
703 + const SvXMLTokenMap& GetTableProtectionAttrTokenMap();
704 const SvXMLTokenMap& GetTableRowsElemTokenMap();
705 const SvXMLTokenMap& GetTableColsElemTokenMap();
706 const SvXMLTokenMap& GetTableAttrTokenMap();
707 diff --git sc/source/filter/xml/xmlsubti.cxx sc/source/filter/xml/xmlsubti.cxx
708 index 72ddec3..3a001e9 100644
709 --- sc/source/filter/xml/xmlsubti.cxx
710 +++ sc/source/filter/xml/xmlsubti.cxx
711 @@ -148,6 +148,15 @@ void ScMyTableData::SetChangedCols(const sal_Int32 nValue)
713 /*******************************************************************************************************************************/
715 +ScXMLTabProtectionData::ScXMLTabProtectionData() :
716 + meHash1(PASSHASH_UNSPECIFIED),
717 + meHash2(PASSHASH_UNSPECIFIED),
718 + mbProtected(false),
719 + mbSelectProtectedCells(false),
720 + mbSelectUnprotectedCells(false)
724 ScMyTables::ScMyTables(ScXMLImport& rTempImport)
725 : rImport(rTempImport),
726 aResizeShapes(rTempImport),
727 @@ -173,7 +182,7 @@ ScMyTables::~ScMyTables()
730 void ScMyTables::NewSheet(const rtl::OUString& sTableName, const rtl::OUString& sStyleName,
731 - const sal_Bool bTempProtection, const rtl::OUString& sTempPassword)
732 + const ScXMLTabProtectionData& rProtectData)
734 if (rImport.GetModel().is())
736 @@ -189,8 +198,7 @@ void ScMyTables::NewSheet(const rtl::OUString& sTableName, const rtl::OUString&
740 - bProtection = bTempProtection;
741 - sPassword = sTempPassword;
742 + maProtectionData = rProtectData;
743 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( rImport.GetModel(), uno::UNO_QUERY );
744 if ( xSpreadDoc.is() )
746 @@ -617,13 +625,16 @@ void ScMyTables::DeleteTable()
747 aMatrixRangeList.clear();
750 - if (rImport.GetDocument() && bProtection)
751 + if (rImport.GetDocument() && maProtectionData.mbProtected)
753 - uno::Sequence<sal_Int8> aPass;
754 - SvXMLUnitConverter::decodeBase64(aPass, sPassword);
755 + uno::Sequence<sal_Int8> aHash;
756 + SvXMLUnitConverter::decodeBase64(aHash, maProtectionData.maPassword);
758 auto_ptr<ScTableProtection> pProtect(new ScTableProtection);
759 - pProtect->setProtected(bProtection);
760 - pProtect->setPasswordHash(aPass, PASSHASH_OOO);
761 + pProtect->setProtected(maProtectionData.mbProtected);
762 + pProtect->setPasswordHash(aHash, maProtectionData.meHash1, maProtectionData.meHash2);
763 + pProtect->setOption(ScTableProtection::SELECT_LOCKED_CELLS, maProtectionData.mbSelectProtectedCells);
764 + pProtect->setOption(ScTableProtection::SELECT_UNLOCKED_CELLS, maProtectionData.mbSelectUnprotectedCells);
765 rImport.GetDocument()->SetTabProtection(static_cast<SCTAB>(nCurrentSheet), pProtect.get());
768 diff --git sc/source/filter/xml/xmlsubti.hxx sc/source/filter/xml/xmlsubti.hxx
769 index 23dc5db..349b395 100644
770 --- sc/source/filter/xml/xmlsubti.hxx
771 +++ sc/source/filter/xml/xmlsubti.hxx
774 #include "XMLTableShapeResizer.hxx"
775 #include "formula/grammar.hxx"
776 +#include "tabprotection.hxx"
780 @@ -107,6 +108,18 @@ struct ScMatrixRange
784 +struct ScXMLTabProtectionData
786 + ::rtl::OUString maPassword;
787 + ScPasswordHash meHash1;
788 + ScPasswordHash meHash2;
790 + bool mbSelectProtectedCells;
791 + bool mbSelectUnprotectedCells;
793 + ScXMLTabProtectionData();
799 @@ -121,8 +134,8 @@ private:
800 ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage > xDrawPage;
801 ::com::sun::star::uno::Reference < ::com::sun::star::drawing::XShapes > xShapes;
802 rtl::OUString sCurrentSheetName;
803 - rtl::OUString sPassword;
804 std::vector<ScMyTableData*> aTableVec;
805 + ScXMLTabProtectionData maProtectionData;
806 ScMyMatrixRangeList aMatrixRangeList;
807 com::sun::star::table::CellAddress aRealCellPos;
808 sal_Int32 nCurrentColStylePos;
809 @@ -130,7 +143,6 @@ private:
810 sal_Int16 nCurrentXShapes;
811 sal_Int32 nTableCount;
812 sal_Int32 nCurrentSheet;
813 - sal_Bool bProtection;
815 sal_Bool IsMerged (const com::sun::star::uno::Reference <com::sun::star::table::XCellRange>& xCellRange,
816 const sal_Int32 nCol, const sal_Int32 nRow,
817 @@ -145,7 +157,7 @@ public:
818 ScMyTables(ScXMLImport& rImport);
820 void NewSheet(const rtl::OUString& sTableName, const rtl::OUString& sStyleName,
821 - const sal_Bool bProtection, const rtl::OUString& sPassword);
822 + const ScXMLTabProtectionData& rProtectData);
824 void SetRowStyle(const rtl::OUString& rCellStyleName);
825 void AddColumn(sal_Bool bIsCovered);
826 @@ -156,6 +168,7 @@ public:
827 com::sun::star::table::CellAddress GetRealCellPos();
828 void AddColCount(sal_Int32 nTempColCount);
829 void AddColStyle(const sal_Int32 nRepeat, const rtl::OUString& rCellStyleName);
830 + ScXMLTabProtectionData& GetCurrentProtectionData() { return maProtectionData; }
831 rtl::OUString GetCurrentSheetName() const { return sCurrentSheetName; }
832 sal_Int32 GetCurrentSheet() const { return nCurrentSheet; }
833 sal_Int32 GetCurrentColumn() const { return aTableVec[nTableCount - 1]->GetColCount(); }
834 diff --git sc/source/filter/xml/xmltabi.cxx sc/source/filter/xml/xmltabi.cxx
835 index fc09927..5229085 100644
836 --- sc/source/filter/xml/xmltabi.cxx
837 +++ sc/source/filter/xml/xmltabi.cxx
840 using namespace com::sun::star;
841 using namespace xmloff::token;
842 +using ::com::sun::star::uno::Reference;
843 +using ::com::sun::star::xml::sax::XAttributeList;
844 +using ::rtl::OUString;
847 * Determine whether this table is an external reference cache from its
848 @@ -152,10 +155,9 @@ ScXMLTableContext::ScXMLTableContext( ScXMLImport& rImport,
850 if (!bTempIsSubTable)
852 - sal_Bool bProtection(sal_False);
853 + ScXMLTabProtectionData aProtectData;
855 rtl::OUString sStyleName;
856 - rtl::OUString sPassword;
857 sal_Int16 nAttrCount(xAttrList.is() ? xAttrList->getLength() : 0);
858 const SvXMLTokenMap& rAttrTokenMap = GetScImport().GetTableAttrTokenMap();
859 for( sal_Int16 i=0; i < nAttrCount; ++i )
860 @@ -174,15 +176,21 @@ ScXMLTableContext::ScXMLTableContext( ScXMLImport& rImport,
861 case XML_TOK_TABLE_STYLE_NAME:
864 - case XML_TOK_TABLE_PROTECTION:
865 - bProtection = IsXMLToken(sValue, XML_TRUE);
867 + case XML_TOK_TABLE_PROTECTED:
868 + aProtectData.mbProtected = IsXMLToken(sValue, XML_TRUE);
870 case XML_TOK_TABLE_PRINT_RANGES:
871 sPrintRanges = sValue;
873 case XML_TOK_TABLE_PASSWORD:
874 - sPassword = sValue;
876 + aProtectData.maPassword = sValue;
878 + case XML_TOK_TABLE_PASSHASH:
879 + aProtectData.meHash1 = ScPassHashHelper::getHashTypeFromURI(sValue);
881 + case XML_TOK_TABLE_PASSHASH_2:
882 + aProtectData.meHash2 = ScPassHashHelper::getHashTypeFromURI(sValue);
884 case XML_TOK_TABLE_PRINT:
886 if (IsXMLToken(sValue, XML_FALSE))
887 @@ -209,7 +217,7 @@ ScXMLTableContext::ScXMLTableContext( ScXMLImport& rImport,
890 // This is a regular table.
891 - GetScImport().GetTables().NewSheet(sName, sStyleName, bProtection, sPassword);
892 + GetScImport().GetTables().NewSheet(sName, sStyleName, aProtectData);
896 @@ -271,6 +279,9 @@ SvXMLImportContext *ScXMLTableContext::CreateChildContext( USHORT nPrefix,
897 pContext = new ScXMLTableColContext( GetScImport(), nPrefix,
900 + case XML_TOK_TABLE_PROTECTION:
901 + pContext = new ScXMLTableProtectionContext( GetScImport(), nPrefix, rLName, xAttrList );
903 case XML_TOK_TABLE_ROW_GROUP:
904 pContext = new ScXMLTableRowsContext( GetScImport(), nPrefix,
906 @@ -384,3 +395,61 @@ void ScXMLTableContext::EndElement()
907 GetScImport().UnlockSolarMutex();
910 +// ============================================================================
912 +ScXMLImport& ScXMLTableProtectionContext::GetScImport()
914 + return static_cast<ScXMLImport&>(GetImport());
917 +ScXMLTableProtectionContext::ScXMLTableProtectionContext(
918 + ScXMLImport& rImport, USHORT nPrefix, const OUString& rLName,
919 + const Reference<XAttributeList>& xAttrList ) :
920 + SvXMLImportContext( rImport, nPrefix, rLName )
922 + const SvXMLTokenMap& rAttrTokenMap = GetScImport().GetTableProtectionAttrTokenMap();
923 + bool bSelectProtectedCells = false;
924 + bool bSelectUnprotectedCells = false;
926 + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
928 + for (sal_Int16 i = 0; i < nAttrCount; ++i)
930 + const OUString& aAttrName = xAttrList->getNameByIndex(i);
931 + const OUString aValue = xAttrList->getValueByIndex(i);
933 + OUString aLocalName;
934 + USHORT nLocalPrefix = GetScImport().GetNamespaceMap().GetKeyByAttrName(
935 + aAttrName, &aLocalName);
937 + switch (rAttrTokenMap.Get(nLocalPrefix, aLocalName))
939 + case XML_TOK_TABLE_SELECT_PROTECTED_CELLS:
940 + bSelectProtectedCells = IsXMLToken(aValue, XML_TRUE);
942 + case XML_TOK_TABLE_SELECT_UNPROTECTED_CELLS:
943 + bSelectUnprotectedCells = IsXMLToken(aValue, XML_TRUE);
950 + ScXMLTabProtectionData& rProtectData = GetScImport().GetTables().GetCurrentProtectionData();
951 + rProtectData.mbSelectProtectedCells = bSelectProtectedCells;
952 + rProtectData.mbSelectUnprotectedCells = bSelectUnprotectedCells;
955 +ScXMLTableProtectionContext::~ScXMLTableProtectionContext()
959 +SvXMLImportContext* ScXMLTableProtectionContext::CreateChildContext(
960 + USHORT /*nPrefix*/, const OUString& /*rLocalName*/, const Reference<XAttributeList>& /*xAttrList*/ )
965 +void ScXMLTableProtectionContext::EndElement()
968 diff --git sc/source/filter/xml/xmltabi.hxx sc/source/filter/xml/xmltabi.hxx
969 index 7fc6031..bd3482c 100644
970 --- sc/source/filter/xml/xmltabi.hxx
971 +++ sc/source/filter/xml/xmltabi.hxx
972 @@ -77,4 +77,26 @@ public:
973 virtual void EndElement();
976 +// ============================================================================
978 +class ScXMLTableProtectionContext : public SvXMLImportContext
980 + ScXMLImport& GetScImport();
983 + ScXMLTableProtectionContext( ScXMLImport& rImport, USHORT nPrefix,
984 + const ::rtl::OUString& rLName,
985 + const ::com::sun::star::uno::Reference<
986 + ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
988 + virtual ~ScXMLTableProtectionContext();
990 + virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix,
991 + const ::rtl::OUString& rLocalName,
992 + const ::com::sun::star::uno::Reference<
993 + ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
995 + virtual void EndElement();
999 diff --git sc/source/ui/docshell/docsh.cxx sc/source/ui/docshell/docsh.cxx
1000 index 04825b9..9caaf5f 100644
1001 --- sc/source/ui/docshell/docsh.cxx
1002 +++ sc/source/ui/docshell/docsh.cxx
1003 @@ -1440,9 +1440,14 @@ BOOL __EXPORT ScDocShell::SaveAs( SfxMedium& rMedium )
1005 #if ENABLE_SHEET_PROTECTION
1006 ScTabViewShell* pViewShell = GetBestViewShell();
1007 - if (pViewShell && ScPassHashHelper::needsPassHashRegen(aDocument, PASSHASH_OOO))
1008 + bool bNeedsRehash = ScPassHashHelper::needsPassHashRegen(aDocument, PASSHASH_SHA1);
1010 + // legacy xls hash double-hashed by SHA1 is also supported.
1011 + bNeedsRehash = ScPassHashHelper::needsPassHashRegen(aDocument, PASSHASH_XL, PASSHASH_SHA1);
1013 + if (pViewShell && bNeedsRehash)
1015 - if (!pViewShell->ExecuteRetypePassDlg(PASSHASH_OOO))
1016 + if (!pViewShell->ExecuteRetypePassDlg(PASSHASH_SHA1))
1017 // password re-type cancelled. Don't save the document.
1020 diff --git sc/source/ui/miscdlgs/retypepassdlg.cxx sc/source/ui/miscdlgs/retypepassdlg.cxx
1021 index 7786115..899ae0d 100644
1022 --- sc/source/ui/miscdlgs/retypepassdlg.cxx
1023 +++ sc/source/ui/miscdlgs/retypepassdlg.cxx
1024 @@ -77,7 +77,7 @@ ScRetypePassDlg::ScRetypePassDlg(Window* pParent) :
1026 mpDocItem(static_cast<ScDocProtection*>(NULL)),
1028 - meDesiredHash(PASSHASH_OOO)
1029 + meDesiredHash(PASSHASH_SHA1)