summaryrefslogtreecommitdiff
path: root/basic
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2020-01-01 13:54:05 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2020-01-01 19:21:50 +0100
commit4abb191916916c7003deedcfdcf46287faccaf01 (patch)
treee3cedd8eaeb9457cf08a68a832e540f8ff3bc44b /basic
parent83955c30405b086fb9b753f2734827c63e951c91 (diff)
tdf#57113: store UTF-16 stringpool data after legacy 1-byte data
This allows to correctly store and read Unicode strings used in password-protected libraries. The additional data stored after all legacy data of the stringpool record (after a magic number to mark its presence), and so is invisible for older versions of program: this allows to keep the version of data and backward compatibility. Of course, older versions will only see legacy data, with broken Unicode strings; and password-protected libraries edited and saved in older versions will not contain Unicode data. read_uInt16s_ToOUString and write_uInt16s_FromOUString are used for correct handling of UTF-16 strings on LE/BE systems. Change-Id: I990bc27b5cc7d499e71c43d45b7f263af41911e7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86065 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'basic')
-rw-r--r--basic/source/classes/image.cxx54
-rw-r--r--basic/source/inc/filefmt.hxx2
2 files changed, 49 insertions, 7 deletions
diff --git a/basic/source/classes/image.cxx b/basic/source/classes/image.cxx
index fc2cbf0b154c..959681636dcd 100644
--- a/basic/source/classes/image.cxx
+++ b/basic/source/classes/image.cxx
@@ -90,6 +90,27 @@ static void SbiCloseRecord( SvStream& r, sal_uInt64 nOff )
r.Seek( nPos );
}
+static constexpr sal_uInt32 nUnicodeDataMagicNumber = 0x556E6920; // "Uni " BE
+
+static bool GetToUnicodePoolData(SvStream& r, sal_uInt64 nLen, sal_uInt64 nNext)
+{
+ const auto nPos = r.Tell();
+ // Check space for legacy data, magic number and Unicode data
+ bool bResult = nPos + nLen + sizeof(sal_uInt32) + nLen * sizeof(sal_Unicode) <= nNext;
+ if (bResult)
+ {
+ r.SeekRel(nLen); // Skip legacy data
+ sal_uInt32 nMagic = 0;
+ r.ReadUInt32(nMagic);
+ if (nMagic != nUnicodeDataMagicNumber)
+ {
+ r.Seek(nPos); // return
+ bResult = false;
+ }
+ }
+ return bResult;
+}
+
bool SbiImage::Load( SvStream& r, sal_uInt32& nVersion )
{
@@ -189,6 +210,11 @@ bool SbiImage::Load( SvStream& r, sal_uInt32& nVersion )
break;
case FileOffset::StringPool:
{
+ // the data layout is: nCount of 32-bit offsets into both legacy 1-byte char stream
+ // and resulting char buffer (1:1 correspondence assumed; 16 of 32 bits used);
+ // 32-bit length N of following 1-byte char stream (16 bits used); N bytes of 1-byte
+ // char stream; then optional magic number and stream of N sal_Unicode characters.
+
if( bBadVer ) break;
//assuming an empty string with just the lead 32bit len indicator
const sal_uInt64 nMinStringSize = 4;
@@ -211,13 +237,21 @@ bool SbiImage::Load( SvStream& r, sal_uInt32& nVersion )
pStrings.reset(new sal_Unicode[ nLen ]);
nStringSize = static_cast<sal_uInt16>(nLen);
- std::unique_ptr<char[]> pByteStrings(new char[ nLen ]);
- r.ReadBytes(pByteStrings.get(), nStringSize);
- for( size_t j = 0; j < mvStringOffsets.size(); j++ )
+ if (GetToUnicodePoolData(r, nLen, nNext))
{
- sal_uInt16 nOff2 = static_cast<sal_uInt16>(mvStringOffsets[ j ]);
- OUString aStr( pByteStrings.get() + nOff2, strlen(pByteStrings.get() + nOff2), eCharSet );
- memcpy( pStrings.get() + nOff2, aStr.getStr(), (aStr.getLength() + 1) * sizeof( sal_Unicode ) );
+ OUString s = read_uInt16s_ToOUString(r, nLen);
+ memcpy(pStrings.get(), s.getStr(), s.getLength() * sizeof(sal_Unicode));
+ }
+ else
+ {
+ std::unique_ptr<char[]> pByteStrings(new char[nLen]);
+ r.ReadBytes(pByteStrings.get(), nLen);
+ for (size_t j = 0; j < mvStringOffsets.size(); j++)
+ {
+ sal_uInt16 nOff2 = static_cast<sal_uInt16>(mvStringOffsets[j]);
+ OUString aStr(pByteStrings.get() + nOff2, strlen(pByteStrings.get() + nOff2), eCharSet);
+ memcpy(pStrings.get() + nOff2, aStr.getStr(), (aStr.getLength() + 1) * sizeof(sal_Unicode));
+ }
}
}
break;
@@ -435,8 +469,14 @@ bool SbiImage::Save( SvStream& r, sal_uInt32 nVer )
}
r.WriteUInt32( nStringSize );
r.WriteBytes(pByteStrings.get(), nStringSize);
-
pByteStrings.reset();
+
+ // Now write magic number and store the same data in UTF-16; this is backward compatible:
+ // old readers will not read this data after having read legacy data, and will proceed
+ // straight to the end of the record. So no version restriction here.
+ r.WriteUInt32(nUnicodeDataMagicNumber);
+ write_uInt16s_FromOUString(r, OUString(pStrings.get(), nStringSize));
+
SbiCloseRecord( r, nPos );
}
// User defined types
diff --git a/basic/source/inc/filefmt.hxx b/basic/source/inc/filefmt.hxx
index c4126907a671..eb1990087d9e 100644
--- a/basic/source/inc/filefmt.hxx
+++ b/basic/source/inc/filefmt.hxx
@@ -41,6 +41,8 @@ class SvStream;
// Version 12: aoo#64377 increase code size that basic can handle
// tdf#75973 support user defined types B_USERTYPES in password protected macros
// Version 13: tdf#94617 store methods nStart information greater than sal_Int16 limit
+// tdf#57113 store UTF-16 strings after legacy 1-byte-encoded strings in pool (no
+// version number bump for backward compatibility; relies on magic number)
//
#define B_LEGACYVERSION 0x00000011