diff options
Diffstat (limited to 'tools/source')
36 files changed, 2165 insertions, 2455 deletions
diff --git a/tools/source/datetime/datetime.cxx b/tools/source/datetime/datetime.cxx index 00790ff78dd4..6f9dea26c6e8 100644 --- a/tools/source/datetime/datetime.cxx +++ b/tools/source/datetime/datetime.cxx @@ -17,6 +17,7 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include <tools/datetime.hxx> +#include <tools/duration.hxx> #include <rtl/math.hxx> #include <sal/log.hxx> @@ -94,32 +95,37 @@ sal_Int64 DateTime::GetSecFromDateTime( const Date& rDate ) const } } -DateTime& DateTime::operator +=( const tools::Time& rTime ) +void DateTime::NormalizeTimeRemainderAndApply( tools::Time& rTime ) { - tools::Time aTime = *this; - aTime += rTime; - sal_uInt16 nHours = aTime.GetHour(); - if ( aTime.GetTime() > 0 ) + sal_uInt16 nHours = rTime.GetHour(); + if ( rTime.GetTime() > 0 ) { - while ( nHours >= 24 ) + if (nHours >= 24) { - Date::operator++(); - nHours -= 24; + AddDays( nHours / 24 ); + nHours %= 24; + rTime.SetHour( nHours ); } - aTime.SetHour( nHours ); } - else if ( aTime.GetTime() != 0 ) + else if ( rTime.GetTime() != 0 ) { - while ( nHours >= 24 ) + if (nHours >= 24) { - Date::operator--(); - nHours -= 24; + AddDays( -static_cast<sal_Int32>(nHours) / 24 ); + nHours %= 24; + rTime.SetHour( nHours ); } Date::operator--(); - aTime = Time( 24, 0, 0 )+aTime; + rTime = Time( 24, 0, 0 ) + rTime; } - tools::Time::operator=( aTime ); + tools::Time::operator=( rTime ); +} +DateTime& DateTime::operator +=( const tools::Time& rTime ) +{ + tools::Time aTime = *this; + aTime += rTime; + NormalizeTimeRemainderAndApply(aTime); return *this; } @@ -127,28 +133,14 @@ DateTime& DateTime::operator -=( const tools::Time& rTime ) { tools::Time aTime = *this; aTime -= rTime; - sal_uInt16 nHours = aTime.GetHour(); - if ( aTime.GetTime() > 0 ) - { - while ( nHours >= 24 ) - { - Date::operator++(); - nHours -= 24; - } - aTime.SetHour( nHours ); - } - else if ( aTime.GetTime() != 0 ) - { - while ( nHours >= 24 ) - { - Date::operator--(); - nHours -= 24; - } - Date::operator--(); - aTime = Time( 24, 0, 0 )+aTime; - } - tools::Time::operator=( aTime ); + NormalizeTimeRemainderAndApply(aTime); + return *this; +} +DateTime& DateTime::operator +=( const tools::Duration& rDuration ) +{ + AddDays(rDuration.GetDays()); + operator+=(rDuration.GetTime()); return *this; } @@ -180,27 +172,19 @@ DateTime operator -( const DateTime& rDateTime, const tools::Time& rTime ) return aDateTime; } +DateTime operator +( const DateTime& rDateTime, const tools::Duration& rDuration ) +{ + DateTime aDateTime(rDateTime); + aDateTime.AddDays( rDuration.GetDays()); + aDateTime += rDuration.GetTime(); + return aDateTime; +} + void DateTime::AddTime( double fTimeInDays ) { - double fInt, fFrac; - if ( fTimeInDays < 0.0 ) - { - fInt = ::rtl::math::approxCeil( fTimeInDays ); - fFrac = fInt <= fTimeInDays ? 0.0 : fTimeInDays - fInt; - } - else - { - fInt = ::rtl::math::approxFloor( fTimeInDays ); - fFrac = fInt >= fTimeInDays ? 0.0 : fTimeInDays - fInt; - } - AddDays( sal_Int32(fInt) ); // full days - if ( fFrac ) - { - tools::Time aTime(0); // default ctor calls system time, we don't need that - fFrac *= ::tools::Time::nanoSecPerDay; // time expressed in nanoseconds - aTime.MakeTimeFromNS( static_cast<sal_Int64>(fFrac) ); // method handles negative ns - operator+=( aTime ); - } + // Use Duration to diminish floating point accuracy errors. + tools::Duration aDuration(fTimeInDays); + operator+=(aDuration); } DateTime operator +( const DateTime& rDateTime, double fTimeInDays ) @@ -210,20 +194,21 @@ DateTime operator +( const DateTime& rDateTime, double fTimeInDays ) return aDateTime; } -double operator -( const DateTime& rDateTime1, const DateTime& rDateTime2 ) +tools::Duration operator -( const DateTime& rDateTime1, const DateTime& rDateTime2 ) +{ + return tools::Duration( rDateTime2, rDateTime1); +} + +// static +double DateTime::Sub( const DateTime& rDateTime1, const DateTime& rDateTime2 ) { - sal_Int32 nDays = static_cast<const Date&>(rDateTime1) - - static_cast<const Date&>(rDateTime2); - sal_Int64 nTime = rDateTime1.GetNSFromTime() - rDateTime2.GetNSFromTime(); - if ( nTime ) + if (static_cast<const tools::Time&>(rDateTime1) != static_cast<const tools::Time&>(rDateTime2)) { - double fTime = double(nTime); - fTime /= ::tools::Time::nanoSecPerDay; // convert from nanoseconds to fraction - if ( nDays < 0 && fTime > 0.0 ) - fTime = 1.0 - fTime; - return double(nDays) + fTime; + // Use Duration to diminish floating point accuracy errors. + const tools::Duration aDuration( rDateTime2, rDateTime1); + return aDuration.GetInDays(); } - return double(nDays); + return static_cast<const Date&>(rDateTime1) - static_cast<const Date&>(rDateTime2); } void DateTime::GetWin32FileDateTime( sal_uInt32 & rLower, sal_uInt32 & rUpper ) const diff --git a/tools/source/datetime/duration.cxx b/tools/source/datetime/duration.cxx new file mode 100644 index 000000000000..a655f016a1bc --- /dev/null +++ b/tools/source/datetime/duration.cxx @@ -0,0 +1,328 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <tools/duration.hxx> +#include <tools/datetime.hxx> +#include <rtl/math.hxx> +#include <o3tl/safeint.hxx> +#include <cmath> + +namespace tools +{ +Duration::Duration(const ::DateTime& rStart, const ::DateTime& rEnd) + : mnDays(static_cast<const Date&>(rEnd) - static_cast<const Date&>(rStart)) +{ + SetTimeDiff(rStart, rEnd); +} + +Duration::Duration(const Time& rStart, const Time& rEnd) +{ + const sal_uInt16 nStartHour = rStart.GetHour(); + const sal_uInt16 nEndHour = rEnd.GetHour(); + if (nStartHour >= 24 || nEndHour >= 24) + { + Time aEnd(rEnd); + if (nEndHour >= 24) + { + mnDays = (nEndHour / 24) * (aEnd.GetTime() < 0 ? -1 : 1); + aEnd.SetHour(nEndHour % 24); + } + Time aStart(rStart); + if (nStartHour >= 24) + { + mnDays -= (nStartHour / 24) * (aStart.GetTime() < 0 ? -1 : 1); + aStart.SetHour(nStartHour % 24); + } + SetTimeDiff(aStart, aEnd); + } + else + { + SetTimeDiff(rStart, rEnd); + } +} + +Duration::Duration(double fTimeInDays, sal_uInt64 nAccuracyEpsilonNanoseconds) +{ + assert(nAccuracyEpsilonNanoseconds <= Time::nanoSecPerSec - 1); + double fInt, fFrac; + if (fTimeInDays < 0.0) + { + fInt = ::rtl::math::approxCeil(fTimeInDays); + fFrac = fInt <= fTimeInDays ? 0.0 : fTimeInDays - fInt; + } + else + { + fInt = ::rtl::math::approxFloor(fTimeInDays); + fFrac = fInt >= fTimeInDays ? 0.0 : fTimeInDays - fInt; + } + mnDays = static_cast<sal_Int32>(fInt); + if (fFrac) + { + fFrac *= Time::nanoSecPerDay; + fFrac = ::rtl::math::approxFloor(fFrac); + sal_Int64 nNS = static_cast<sal_Int64>(fFrac); + const sal_Int64 nN = nNS % Time::nanoSecPerSec; + if (nN) + { + const sal_uInt64 nA = std::abs(nN); + if (nA <= nAccuracyEpsilonNanoseconds) + nNS -= (nNS < 0) ? -nN : nN; + else if (nA >= Time::nanoSecPerSec - nAccuracyEpsilonNanoseconds) + { + const sal_Int64 nD = Time::nanoSecPerSec - nA; + nNS += (nNS < 0) ? -nD : nD; + if (std::abs(nNS) >= Time::nanoSecPerDay) + { + mnDays += nNS / Time::nanoSecPerDay; + nNS %= Time::nanoSecPerDay; + } + } + } + maTime.MakeTimeFromNS(nNS); + assert(mnDays == 0 || maTime.GetTime() == 0 || (mnDays < 0) == (nNS < 0)); + } +} + +Duration::Duration(sal_Int32 nDays, const Time& rTime) + : mnDays(nDays) +{ + assert(nDays == 0 || rTime.GetTime() == 0 || (nDays < 0) == (rTime.GetTime() < 0)); + Normalize(rTime.GetHour(), rTime.GetMin(), rTime.GetSec(), rTime.GetNanoSec(), + ((nDays < 0) || (rTime.GetTime() < 0))); +} + +Duration::Duration(sal_Int32 nDays, sal_uInt32 nHours, sal_uInt32 nMinutes, sal_uInt32 nSeconds, + sal_uInt64 nNanoseconds) + : mnDays(nDays) +{ + Normalize(nHours, nMinutes, nSeconds, nNanoseconds, nDays < 0); +} + +Duration::Duration(sal_Int32 nDays, sal_Int64 nTime) + : maTime(nTime) + , mnDays(nDays) +{ +} + +void Duration::Normalize(sal_uInt64 nHours, sal_uInt64 nMinutes, sal_uInt64 nSeconds, + sal_uInt64 nNanoseconds, bool bNegative) +{ + if (nNanoseconds >= Time::nanoSecPerSec) + { + nSeconds += nNanoseconds / Time::nanoSecPerSec; + nNanoseconds %= Time::nanoSecPerSec; + } + if (nSeconds >= Time::secondPerMinute) + { + nMinutes += nSeconds / Time::secondPerMinute; + nSeconds %= Time::secondPerMinute; + } + if (nMinutes >= Time::minutePerHour) + { + nHours += nMinutes / Time::minutePerHour; + nMinutes %= Time::minutePerHour; + } + if (nHours >= Time::hourPerDay) + { + sal_Int64 nDiff = nHours / Time::hourPerDay; + nHours %= Time::hourPerDay; + bool bOverflow = false; + if (bNegative) + { + nDiff = -nDiff; + bOverflow = (nDiff < SAL_MIN_INT32); + bOverflow |= o3tl::checked_add(mnDays, static_cast<sal_Int32>(nDiff), mnDays); + if (bOverflow) + mnDays = SAL_MIN_INT32; + } + else + { + bOverflow = (nDiff > SAL_MAX_INT32); + bOverflow |= o3tl::checked_add(mnDays, static_cast<sal_Int32>(nDiff), mnDays); + if (bOverflow) + mnDays = SAL_MAX_INT32; + } + assert(!bOverflow); + if (bOverflow) + { + nHours = Time::hourPerDay - 1; + nMinutes = Time::minutePerHour - 1; + nSeconds = Time::secondPerMinute - 1; + nNanoseconds = Time::nanoSecPerSec - 1; + } + } + maTime = Time(nHours, nMinutes, nSeconds, nNanoseconds); + if (bNegative) + maTime = -maTime; + assert(mnDays == 0 || maTime.GetTime() == 0 || (mnDays < 0) == (maTime.GetTime() < 0)); +} + +void Duration::ApplyTime(sal_Int64 nNS) +{ + if (mnDays > 0 && nNS < 0) + { + --mnDays; + nNS = Time::nanoSecPerDay + nNS; + } + else if (mnDays < 0 && nNS > 0) + { + ++mnDays; + nNS = -Time::nanoSecPerDay + nNS; + } + maTime.MakeTimeFromNS(nNS); + assert(mnDays == 0 || maTime.GetTime() == 0 || (mnDays < 0) == (maTime.GetTime() < 0)); +} + +void Duration::SetTimeDiff(const Time& rStart, const Time& rEnd) +{ + const sal_Int64 nNS = rEnd.GetNSFromTime() - rStart.GetNSFromTime(); + ApplyTime(nNS); +} + +Duration Duration::operator-() const +{ + Duration aD(-mnDays, -maTime.GetTime()); + return aD; +} + +Duration& Duration::Add(const Duration& rDuration, bool& rbOverflow) +{ + rbOverflow = o3tl::checked_add(mnDays, rDuration.mnDays, mnDays); + // Duration is always normalized, time values >= 24h don't occur. + sal_Int64 nNS = maTime.GetNSFromTime() + rDuration.maTime.GetNSFromTime(); + if (nNS < -Time::nanoSecPerDay) + { + rbOverflow |= o3tl::checked_sub(mnDays, sal_Int32(1), mnDays); + nNS += Time::nanoSecPerDay; + } + else if (nNS > Time::nanoSecPerDay) + { + rbOverflow |= o3tl::checked_add(mnDays, sal_Int32(1), mnDays); + nNS -= Time::nanoSecPerDay; + } + ApplyTime(nNS); + return *this; +} + +Duration Duration::Mult(sal_Int32 nMult, bool& rbOverflow) const +{ + // First try a simple calculation in nanoseconds. + bool bBadNS = false; + sal_Int64 nNS; + sal_Int64 nDays; + if (o3tl::checked_multiply(static_cast<sal_Int64>(mnDays), static_cast<sal_Int64>(nMult), nDays) + || o3tl::checked_multiply(nDays, Time::nanoSecPerDay, nDays) + || o3tl::checked_multiply(maTime.GetNSFromTime(), static_cast<sal_Int64>(nMult), nNS) + || o3tl::checked_add(nDays, nNS, nNS)) + { + bBadNS = rbOverflow = true; + } + else + { + const sal_Int64 nD = nNS / Time::nanoSecPerDay; + if (nD < SAL_MIN_INT32 || SAL_MAX_INT32 < nD) + rbOverflow = true; + else + { + rbOverflow = false; + nNS -= nD * Time::nanoSecPerDay; + Duration aD(static_cast<sal_Int32>(nD), 0); + aD.ApplyTime(nNS); + return aD; + } + } + if (bBadNS) + { + // Simple calculation in overall nanoseconds overflowed, try with + // individual components. + const sal_uInt64 nMult64 = (nMult < 0) ? -nMult : nMult; + do + { + sal_uInt64 nN; + if (o3tl::checked_multiply(static_cast<sal_uInt64>(maTime.GetNanoSec()), nMult64, nN)) + break; + sal_uInt64 nS; + if (o3tl::checked_multiply(static_cast<sal_uInt64>(maTime.GetSec()), nMult64, nS)) + break; + sal_uInt64 nM; + if (o3tl::checked_multiply(static_cast<sal_uInt64>(maTime.GetMin()), nMult64, nM)) + break; + sal_uInt64 nH; + if (o3tl::checked_multiply(static_cast<sal_uInt64>(maTime.GetHour()), nMult64, nH)) + break; + sal_uInt64 nD; + if (o3tl::checked_multiply( + mnDays < 0 ? static_cast<sal_uInt64>(-static_cast<sal_Int64>(mnDays)) + : static_cast<sal_uInt64>(mnDays), + nMult64, nD)) + break; + if (nN > Time::nanoSecPerSec) + { + const sal_uInt64 nC = nN / Time::nanoSecPerSec; + if (o3tl::checked_add(nS, nC, nS)) + break; + nN -= nC * Time::nanoSecPerSec; + } + if (nS > Time::secondPerMinute) + { + const sal_uInt64 nC = nS / Time::secondPerMinute; + if (o3tl::checked_add(nM, nC, nM)) + break; + nS -= nC * Time::secondPerMinute; + } + if (nM > Time::minutePerHour) + { + const sal_uInt64 nC = nM / Time::minutePerHour; + if (o3tl::checked_add(nH, nC, nH)) + break; + nM -= nC * Time::minutePerHour; + } + if (nH > Time::hourPerDay) + { + const sal_uInt64 nC = nH / Time::hourPerDay; + if (o3tl::checked_add(nD, nC, nD)) + break; + nH -= nC * Time::hourPerDay; + } + if (IsNegative() ? (static_cast<sal_uInt64>(SAL_MAX_INT32) + 1) < nD + || -static_cast<sal_Int64>(nD) < SAL_MIN_INT32 + : SAL_MAX_INT32 < nD) + break; + + rbOverflow = false; + Time aTime(nH, nM, nS, nN); + if (IsNegative() == (nMult < 0)) + { + Duration aD(nD, aTime.GetTime()); + return aD; + } + else + { + Duration aD(-static_cast<sal_Int64>(nD), -aTime.GetTime()); + return aD; + } + } while (false); + } + assert(rbOverflow); + if (IsNegative() == (nMult < 0)) + { + Duration aD(SAL_MAX_INT32, 0); + aD.ApplyTime(Time::nanoSecPerDay - 1); + return aD; + } + else + { + Duration aD(SAL_MIN_INT32, 0); + aD.ApplyTime(-(Time::nanoSecPerDay - 1)); + return aD; + } +} +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/tools/source/datetime/tdate.cxx b/tools/source/datetime/tdate.cxx index 979611333813..e20add430353 100644 --- a/tools/source/datetime/tdate.cxx +++ b/tools/source/datetime/tdate.cxx @@ -21,25 +21,7 @@ #include <com/sun/star/util/DateTime.hpp> #include <systemdatetime.hxx> - -const sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30, - 31, 31, 30, 31, 30, 31 }; - -// Once upon a time the number of days we internally handled was limited to -// MAX_DAYS 3636532. That changed with a full 16-bit year. -// Assuming the first valid positive date in a proleptic Gregorian calendar is -// 0001-01-01, this resulted in an end date of 9957-06-26. -// Hence we documented that years up to and including 9956 are handled. -/* XXX: it is unclear history why this value was chosen, the representable - * 9999-12-31 would be 3652060 days from 0001-01-01. Even 9998-12-31 to - * distinguish from a maximum possible date would be 3651695. - * There is connectivity/source/commontools/dbconversion.cxx that still has the - * same value to calculate with css::util::Date */ -/* XXX can that dbconversion cope with years > 9999 or negative years at all? - * Database fields may be limited to positive 4 digits. */ - -const sal_Int32 MIN_DAYS = -11968265; // -32768-01-01 -const sal_Int32 MAX_DAYS = 11967900; // 32767-12-31 +#include <comphelper/date.hxx> namespace { @@ -47,54 +29,6 @@ namespace const sal_Int16 kYearMax = SAL_MAX_INT16; const sal_Int16 kYearMin = SAL_MIN_INT16; -// Days until start of year from zero, so month and day of month can be added. -// year 1 => 0 days, year 2 => 365 days, ... -// year -1 => -366 days, year -2 => -731 days, ... -sal_Int32 ImpYearToDays( sal_Int16 nYear ) -{ - assert( nYear != 0 ); - sal_Int32 nOffset; - sal_Int32 nYr; - if (nYear < 0) - { - nOffset = -366; - nYr = nYear + 1; - } - else - { - nOffset = 0; - nYr = nYear - 1; - } - return nOffset + nYr*365 + nYr/4 - nYr/100 + nYr/400; -} - -bool ImpIsLeapYear( sal_Int16 nYear ) -{ - // Leap years BCE are -1, -5, -9, ... - // See - // https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar#Usage - // https://en.wikipedia.org/wiki/0_(year)#History_of_astronomical_usage - assert( nYear != 0 ); - if (nYear < 0) - nYear = -nYear - 1; - return ( ( ((nYear % 4) == 0) && ((nYear % 100) != 0) ) || - ( (nYear % 400) == 0 ) ); -} - -// All callers must have sanitized or normalized month and year values! -sal_uInt16 ImplDaysInMonth( sal_uInt16 nMonth, sal_Int16 nYear ) -{ - if ( nMonth != 2 ) - return aDaysInMonth[nMonth-1]; - else - { - if (ImpIsLeapYear(nYear)) - return aDaysInMonth[nMonth-1] + 1; - else - return aDaysInMonth[nMonth-1]; - } -} - } void Date::setDateFromDMY( sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear ) @@ -130,7 +64,7 @@ sal_uInt16 Date::GetDaysInMonth( sal_uInt16 nMonth, sal_Int16 nYear ) nMonth = 1; else if (12 < nMonth) nMonth = 12; - return ImplDaysInMonth( nMonth, nYear); + return comphelper::date::getDaysInMonth( nMonth, nYear); } sal_Int32 Date::GetAsNormalizedDays() const @@ -138,71 +72,33 @@ sal_Int32 Date::GetAsNormalizedDays() const // This is a very common datum we often calculate from. if (mnDate == 18991230) // 1899-12-30 { - assert(DateToDays( GetDay(), GetMonth(), GetYear() ) == 693594); +#ifndef NDEBUG + static sal_Int32 nDays = DateToDays( GetDay(), GetMonth(), GetYear()); + assert(nDays == 693594); +#endif return 693594; } - return DateToDays( GetDay(), GetMonth(), GetYear() ); + // Not calling comphelper::date::convertDateToDaysNormalizing() here just + // avoids a second check on null-date handling like above. + sal_uInt16 nDay = GetDay(); + sal_uInt16 nMonth = GetMonth(); + sal_Int16 nYear = GetYear(); + comphelper::date::normalize( nDay, nMonth, nYear); + return comphelper::date::convertDateToDays( nDay, nMonth, nYear); } sal_Int32 Date::DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear ) { - Normalize( nDay, nMonth, nYear); - - sal_Int32 nDays = ImpYearToDays(nYear); - for( sal_uInt16 i = 1; i < nMonth; i++ ) - nDays += ImplDaysInMonth(i,nYear); - nDays += nDay; - return nDays; + return comphelper::date::convertDateToDaysNormalizing( nDay, nMonth, nYear); } static Date lcl_DaysToDate( sal_Int32 nDays ) { - if ( nDays <= MIN_DAYS ) - return Date( 1, 1, kYearMin ); - if ( nDays >= MAX_DAYS ) - return Date( 31, 12, kYearMax ); - - // Day 0 is -0001-12-31, day 1 is 0001-01-01 - const sal_Int16 nSign = (nDays <= 0 ? -1 : 1); - sal_Int32 nTempDays; - sal_Int32 i = 0; - bool bCalc; - + sal_uInt16 nDay; + sal_uInt16 nMonth; sal_Int16 nYear; - do - { - nYear = static_cast<sal_Int16>((nDays / 365) - (i * nSign)); - if (nYear == 0) - nYear = nSign; - nTempDays = nDays - ImpYearToDays(nYear); - bCalc = false; - if ( nTempDays < 1 ) - { - i += nSign; - bCalc = true; - } - else - { - if ( nTempDays > 365 ) - { - if ( (nTempDays != 366) || !ImpIsLeapYear( nYear ) ) - { - i -= nSign; - bCalc = true; - } - } - } - } - while ( bCalc ); - - sal_uInt16 nMonth = 1; - while ( nTempDays > ImplDaysInMonth( nMonth, nYear ) ) - { - nTempDays -= ImplDaysInMonth( nMonth, nYear ); - ++nMonth; - } - - return Date( static_cast<sal_uInt16>(nTempDays), nMonth, nYear ); + comphelper::date::convertDaysToDate( nDays, nDay, nMonth, nYear); + return Date( nDay, nMonth, nYear); } Date::Date( DateInitSystem ) @@ -269,7 +165,7 @@ void Date::AddYears( sal_Int16 nAddYears ) } SetYear( nYear ); - if (GetMonth() == 2 && GetDay() == 29 && !ImpIsLeapYear( nYear)) + if (GetMonth() == 2 && GetDay() == 29 && !comphelper::date::isLeapYear( nYear)) SetDay(28); } @@ -306,7 +202,7 @@ sal_uInt16 Date::GetDayOfYear() const Normalize( nDay, nMonth, nYear); for( sal_uInt16 i = 1; i < nMonth; i++ ) - nDay += ::ImplDaysInMonth( i, nYear ); + nDay += comphelper::date::getDaysInMonth( i, nYear ); return nDay; } @@ -403,13 +299,13 @@ sal_uInt16 Date::GetDaysInMonth() const sal_Int16 nYear = GetYear(); Normalize( nDay, nMonth, nYear); - return ImplDaysInMonth( nMonth, nYear ); + return comphelper::date::getDaysInMonth( nMonth, nYear ); } bool Date::IsLeapYear() const { sal_Int16 nYear = GetYear(); - return ImpIsLeapYear( nYear ); + return comphelper::date::isLeapYear( nYear ); } bool Date::IsValidAndGregorian() const @@ -420,7 +316,7 @@ bool Date::IsValidAndGregorian() const if ( !nMonth || (nMonth > 12) ) return false; - if ( !nDay || (nDay > ImplDaysInMonth( nMonth, nYear )) ) + if ( !nDay || (nDay > comphelper::date::getDaysInMonth( nMonth, nYear )) ) return false; else if ( nYear <= 1582 ) { @@ -437,19 +333,13 @@ bool Date::IsValidAndGregorian() const bool Date::IsValidDate() const { - return IsValidDate( GetDay(), GetMonth(), GetYear()); + return comphelper::date::isValidDate( GetDay(), GetMonth(), GetYear()); } //static bool Date::IsValidDate( sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear ) { - if (nYear == 0) - return false; - if ( !nMonth || (nMonth > 12) ) - return false; - if ( !nDay || (nDay > ImplDaysInMonth( nMonth, nYear )) ) - return false; - return true; + return comphelper::date::isValidDate( nDay, nMonth, nYear); } bool Date::IsEndOfMonth() const @@ -460,7 +350,8 @@ bool Date::IsEndOfMonth() const //static bool Date::IsEndOfMonth(sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear) { - return IsValidDate(nDay, nMonth, nYear) && ImplDaysInMonth(nMonth, nYear) == nDay; + return comphelper::date::isValidDate(nDay, nMonth, nYear) + && comphelper::date::getDaysInMonth(nMonth, nYear) == nDay; } void Date::Normalize() @@ -478,83 +369,7 @@ void Date::Normalize() //static bool Date::Normalize( sal_uInt16 & rDay, sal_uInt16 & rMonth, sal_Int16 & rYear ) { - if (IsValidDate( rDay, rMonth, rYear)) - return false; - - if (rDay == 0 && rMonth == 0 && rYear == 0) - return false; // empty date - - if (rDay == 0) - { - if (rMonth == 0) - ; // nothing, handled below - else - --rMonth; - // Last day of month is determined at the end. - } - - if (rMonth > 12) - { - rYear += rMonth / 12; - rMonth = rMonth % 12; - if (rYear == 0) - rYear = 1; - } - if (rMonth == 0) - { - --rYear; - if (rYear == 0) - rYear = -1; - rMonth = 12; - } - - if (rYear < 0) - { - sal_uInt16 nDays; - while (rDay > (nDays = ImplDaysInMonth( rMonth, rYear))) - { - rDay -= nDays; - if (rMonth > 1) - --rMonth; - else - { - if (rYear == kYearMin) - { - rDay = 1; - rMonth = 1; - return true; - } - --rYear; - rMonth = 12; - } - } - } - else - { - sal_uInt16 nDays; - while (rDay > (nDays = ImplDaysInMonth( rMonth, rYear))) - { - rDay -= nDays; - if (rMonth < 12) - ++rMonth; - else - { - if (rYear == kYearMax) - { - rDay = 31; - rMonth = 12; - return true; - } - ++rYear; - rMonth = 1; - } - } - } - - if (rDay == 0) - rDay = ImplDaysInMonth( rMonth, rYear); - - return true; + return comphelper::date::normalize( rDay, rMonth, rYear); } void Date::AddDays( sal_Int32 nDays ) diff --git a/tools/source/datetime/ttime.cxx b/tools/source/datetime/ttime.cxx index c6c89c934886..fcfa2e080e99 100644 --- a/tools/source/datetime/ttime.cxx +++ b/tools/source/datetime/ttime.cxx @@ -125,6 +125,18 @@ void tools::Time::init( sal_uInt32 nHour, sal_uInt32 nMin, sal_uInt32 nSec, sal_ nHour += nMin / minInHour; nMin %= minInHour; + // 922337 * HOUR_MASK = 9223370000000000000 largest possible value, 922338 + // would be -9223364073709551616. + assert(HOUR_MASK * nHour >= 0 && "use tools::Duration with days instead!"); + if (HOUR_MASK * nHour < 0) + nHour = 922337; + + // But as is, GetHour() retrieves only sal_uInt16. Though retrieving in + // nanoseconds or milliseconds might be possible this is all crap. + assert(nHour <= SAL_MAX_UINT16 && "use tools::Duration with days instead!"); + if (nHour > SAL_MAX_UINT16) + nHour = SAL_MAX_UINT16; + // construct time nTime = nNanoSec + nSec * SEC_MASK + @@ -412,17 +424,17 @@ Time tools::Time::GetUTCOffset() { nTime = time( nullptr ); localtime_r( &nTime, &aTM ); - sal_Int32 nLocalTime = mktime( &aTM ); + auto nLocalTime = mktime( &aTM ); #if defined(__sun) // Solaris gmtime_r() seems not to handle daylight saving time // flags correctly - nUTC = nLocalTime + ( aTM.tm_isdst == 0 ? timezone : altzone ); + auto nUTC = nLocalTime + ( aTM.tm_isdst == 0 ? timezone : altzone ); #elif defined( LINUX ) // Linux mktime() seems not to handle tm_isdst correctly - sal_Int32 nUTC = nLocalTime - aTM.tm_gmtoff; + auto nUTC = nLocalTime - aTM.tm_gmtoff; #else gmtime_r( &nTime, &aTM ); - sal_Int32 nUTC = mktime( &aTM ); + auto nUTC = mktime( &aTM ); #endif nCacheTicks = nTicks; nCacheSecOffset = (nLocalTime-nUTC) / 60; @@ -477,11 +489,12 @@ sal_uInt64 tools::Time::GetMonotonicTicks() #if defined(_POSIX_TIMERS) struct timespec currentTime; clock_gettime( CLOCK_MONOTONIC, ¤tTime ); - nMicroSeconds = currentTime.tv_sec * 1000 * 1000 + currentTime.tv_nsec / 1000; + nMicroSeconds + = static_cast<sal_uInt64>(currentTime.tv_sec) * 1000 * 1000 + currentTime.tv_nsec / 1000; #else struct timeval currentTime; gettimeofday( ¤tTime, nullptr ); - nMicroSeconds = currentTime.tv_sec * 1000 * 1000 + currentTime.tv_usec; + nMicroSeconds = static_cast<sal_uInt64>(currentTime.tv_sec) * 1000 * 1000 + currentTime.tv_usec; #endif #endif // __MACH__ return nMicroSeconds; diff --git a/tools/source/debug/debug.cxx b/tools/source/debug/debug.cxx index 82406a3624ff..197ba2450493 100644 --- a/tools/source/debug/debug.cxx +++ b/tools/source/debug/debug.cxx @@ -17,49 +17,8 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <com/sun/star/configuration/CorruptedConfigurationException.hpp> -#include <com/sun/star/configuration/backend/BackendSetupException.hpp> -#include <com/sun/star/configuration/backend/MalformedDataException.hpp> -#include <com/sun/star/configuration/InvalidBootstrapFileException.hpp> -#include <com/sun/star/configuration/MissingBootstrapFileException.hpp> -#include <com/sun/star/deployment/DependencyException.hpp> -#include <com/sun/star/deployment/DeploymentException.hpp> -#include <com/sun/star/document/CorruptedFilterConfigurationException.hpp> -#include <com/sun/star/document/UndoFailedException.hpp> -#include <com/sun/star/lang/IllegalArgumentException.hpp> -#include <com/sun/star/lang/WrappedTargetException.hpp> -#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> -#include <com/sun/star/ldap/LdapGenericException.hpp> -#include <com/sun/star/script/BasicErrorException.hpp> -#include <com/sun/star/script/CannotConvertException.hpp> -#include <com/sun/star/script/provider/ScriptExceptionRaisedException.hpp> -#include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp> -#include <com/sun/star/sdbc/SQLException.hpp> -#include <com/sun/star/system/SystemShellExecuteException.hpp> -#include <com/sun/star/task/ErrorCodeIOException.hpp> -#include <com/sun/star/ucb/CommandFailedException.hpp> -#include <com/sun/star/ucb/ContentCreationException.hpp> -#include <com/sun/star/ucb/MissingPropertiesException.hpp> -#include <com/sun/star/ucb/NameClashException.hpp> -#include <com/sun/star/ucb/InteractiveIOException.hpp> -#include <com/sun/star/util/MalformedNumberFormatException.hpp> -#include <com/sun/star/xml/dom/DOMException.hpp> -#include <com/sun/star/xml/sax/SAXException.hpp> -#include <com/sun/star/xml/sax/SAXParseException.hpp> -#include <comphelper/anytostring.hxx> #include <tools/debug.hxx> #include <sal/log.hxx> -#include <osl/thread.h> -#include <rtl/strbuf.hxx> - -#include <cstdlib> -#include <typeinfo> - -#include <tools/diagnose_ex.h> - -#if defined __GLIBCXX__ -#include <cxxabi.h> -#endif namespace { @@ -95,336 +54,4 @@ void DbgTestSolarMutex() aDebugData.pDbgTestSolarMutex(); } -static void exceptionToStringImpl(OStringBuffer& sMessage, const css::uno::Any & caught) -{ - auto toOString = [](OUString const & s) { - return OUStringToOString( s, osl_getThreadTextEncoding() ); - }; - sMessage.append(toOString(caught.getValueTypeName())); - css::uno::Exception exception; - caught >>= exception; - if ( !exception.Message.isEmpty() ) - { - sMessage.append(" message: "); - sMessage.append(toOString(exception.Message)); - } -/* TODO FIXME (see https://gerrit.libreoffice.org/#/c/83245/) - if ( exception.Context.is() ) - { - const char* pContext = typeid( *exception.Context ).name(); -#if defined __GLIBCXX__ - // demangle the type name, not necessary under windows, we already get demangled names there - int status; - pContext = abi::__cxa_demangle( pContext, nullptr, nullptr, &status); -#endif - sMessage.append(" context: "); - sMessage.append(pContext); -#if defined __GLIBCXX__ - std::free(const_cast<char *>(pContext)); -#endif - } -*/ - { - css::configuration::CorruptedConfigurationException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" details: "); - sMessage.append(toOString(specialized.Details)); - } - } - { - css::configuration::InvalidBootstrapFileException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" BootstrapFileURL: "); - sMessage.append(toOString(specialized.BootstrapFileURL)); - } - } - { - css::configuration::MissingBootstrapFileException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" BootstrapFileURL: "); - sMessage.append(toOString(specialized.BootstrapFileURL)); - } - } - { - css::configuration::backend::MalformedDataException specialized; - if ( caught >>= specialized ) - { - sMessage.append("\n wrapped: "); - sMessage.append(exceptionToString(specialized.ErrorDetails)); - } - } - { - css::configuration::backend::BackendSetupException specialized; - if ( caught >>= specialized ) - { - sMessage.append("\n wrapped: "); - sMessage.append(exceptionToString(specialized.BackendException)); - } - } - { - css::deployment::DependencyException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" UnsatisfiedDependencies: "); - sMessage.append(toOString(comphelper::anyToString(css::uno::Any(specialized.UnsatisfiedDependencies)))); - } - } - { - css::deployment::DeploymentException specialized; - if ( caught >>= specialized ) - { - sMessage.append("\n wrapped: "); - sMessage.append(exceptionToString(specialized.Cause)); - } - } - { - css::document::CorruptedFilterConfigurationException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" Details: "); - sMessage.append(toOString(specialized.Details)); - } - } - { - css::document::UndoFailedException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" Reason: "); - sMessage.append(toOString(comphelper::anyToString(specialized.Reason))); - } - } - { - css::lang::IllegalArgumentException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" ArgumentPosition: "); - sMessage.append(static_cast<sal_Int32>(specialized.ArgumentPosition)); - } - } - { - css::lang::WrappedTargetException specialized; - if ( caught >>= specialized ) - { - sMessage.append("\n wrapped: "); - sMessage.append(exceptionToString(specialized.TargetException)); - } - } - { - css::lang::WrappedTargetRuntimeException specialized; - if ( caught >>= specialized ) - { - sMessage.append("\n wrapped: "); - sMessage.append(exceptionToString(specialized.TargetException)); - } - } - { - css::ldap::LdapGenericException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" ErrorCode: "); - sMessage.append(specialized.ErrorCode); - } - } - { - css::script::BasicErrorException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" ErrorCode: "); - sMessage.append(specialized.ErrorCode); - sMessage.append(" ErrorMessageArgument: "); - sMessage.append(toOString(specialized.ErrorMessageArgument)); - } - } - { - css::script::CannotConvertException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" DestinationTypeClass: "); - sMessage.append(toOString(comphelper::anyToString(css::uno::Any(specialized.DestinationTypeClass)))); - sMessage.append(" Reason: "); - sMessage.append(specialized.Reason); - sMessage.append(" ArgumentIndex: "); - sMessage.append(specialized.ArgumentIndex); - } - } - { - css::script::provider::ScriptErrorRaisedException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" scriptName: "); - sMessage.append(toOString(specialized.scriptName)); - sMessage.append(" language: "); - sMessage.append(toOString(specialized.language)); - sMessage.append(" lineNum: "); - sMessage.append(specialized.lineNum); - } - } - { - css::script::provider::ScriptExceptionRaisedException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" exceptionType: "); - sMessage.append(toOString(specialized.exceptionType)); - } - } - { - css::script::provider::ScriptFrameworkErrorException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" scriptName: "); - sMessage.append(toOString(specialized.scriptName)); - sMessage.append(" language: "); - sMessage.append(toOString(specialized.language)); - sMessage.append(" errorType: "); - sMessage.append(specialized.errorType); - } - } - { - css::sdbc::SQLException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" SQLState: "); - sMessage.append(toOString(specialized.SQLState)); - sMessage.append(" ErrorCode: "); - sMessage.append(specialized.ErrorCode); - sMessage.append("\n wrapped: "); - sMessage.append(exceptionToString(specialized.NextException)); - } - } - { - css::system::SystemShellExecuteException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" PosixError: "); - sMessage.append(specialized.PosixError); - } - } - { - css::task::ErrorCodeIOException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" errcode: "); - sMessage.append( specialized.ErrCode ); - } - } - { - css::ucb::CommandFailedException specialized; - if ( caught >>= specialized ) - { - sMessage.append("\n Reason: "); - sMessage.append(exceptionToString( specialized.Reason )); - } - } - { - css::ucb::ContentCreationException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" eError: "); - sMessage.append(toOString(comphelper::anyToString( css::uno::Any(specialized.eError) ))); - } - } - { - css::ucb::MissingPropertiesException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" Properties: "); - sMessage.append(toOString(comphelper::anyToString( css::uno::Any(specialized.Properties) ))); - } - } - { - css::ucb::NameClashException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" Name: "); - sMessage.append(toOString( specialized.Name )); - } - } - { - css::util::MalformedNumberFormatException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" CheckPos: "); - sMessage.append( specialized.CheckPos ); - } - } - { - css::xml::dom::DOMException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" Code: "); - sMessage.append(toOString(comphelper::anyToString( css::uno::Any(specialized.Code) ))); - } - } - { - css::xml::dom::DOMException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" Code: "); - sMessage.append(toOString(comphelper::anyToString( css::uno::Any(specialized.Code) ))); - } - } - { - css::xml::sax::SAXException specialized; - if ( caught >>= specialized ) - { - sMessage.append("\n wrapped: "); - sMessage.append(exceptionToString( specialized.WrappedException )); - } - } - { - css::xml::sax::SAXParseException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" PublicId: "); - sMessage.append(toOString( specialized.PublicId )); - sMessage.append(" SystemId: "); - sMessage.append(toOString( specialized.SystemId )); - sMessage.append(" LineNumber: "); - sMessage.append( specialized.LineNumber ); - sMessage.append(" ColumnNumber: "); - sMessage.append( specialized.ColumnNumber ); - } - } - { - css::ucb::InteractiveIOException specialized; - if ( caught >>= specialized ) - { - sMessage.append(" Code: "); - sMessage.append( static_cast<sal_Int32>(specialized.Code) ); - } - } -} - -OString exceptionToString(const css::uno::Any & caught) -{ - OStringBuffer sMessage(512); - exceptionToStringImpl(sMessage, caught); - return sMessage.makeStringAndClear(); -} - -void DbgUnhandledException(const css::uno::Any & caught, const char* currentFunction, const char* fileAndLineNo, - const char* area, const char* explanatory) -{ - OStringBuffer sMessage( 512 ); - sMessage.append( "DBG_UNHANDLED_EXCEPTION in " ); - sMessage.append(currentFunction); - if (explanatory) - { - sMessage.append("\n when: "); - sMessage.append(explanatory); - } - sMessage.append(" exception: "); - exceptionToStringImpl(sMessage, caught); - - if (area == nullptr) - area = "legacy.osl"; - - SAL_DETAIL_LOG_FORMAT( - SAL_DETAIL_ENABLE_LOG_WARN, SAL_DETAIL_LOG_LEVEL_WARN, - area, fileAndLineNo, "%s", sMessage.getStr()); -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/fileutil.cxx b/tools/source/fsys/fileutil.cxx index ec20e0a513bf..0e3512e5a160 100644 --- a/tools/source/fsys/fileutil.cxx +++ b/tools/source/fsys/fileutil.cxx @@ -10,6 +10,7 @@ #include <tools/fileutil.hxx> #if defined _WIN32 #include <osl/file.hxx> +#include <rtl/uri.hxx> #include <o3tl/char16_t2wchar_t.hxx> #define WIN32_LEAN_AND_MEAN #include <Windows.h> @@ -29,7 +30,11 @@ OUString UNCToDavURL(LPCWSTR sUNC) bufURL = std::make_unique<wchar_t[]>(nSize); nResult = DavGetHTTPFromUNCPath(sUNC, bufURL.get(), &nSize); } - return nResult == ERROR_SUCCESS ? OUString(o3tl::toU(bufURL.get())) : OUString(); + // looks like on different Windowses this may or may not be URL encoded? + return nResult == ERROR_SUCCESS + ? ::rtl::Uri::encode(OUString(o3tl::toU(bufURL.get())), rtl_UriCharClassUric, + rtl_UriEncodeKeepEscapes, RTL_TEXTENCODING_UTF8) + : OUString(); } #endif } diff --git a/tools/source/fsys/urlobj.cxx b/tools/source/fsys/urlobj.cxx index 8c3d2845eab2..b1e3073f39b4 100644 --- a/tools/source/fsys/urlobj.cxx +++ b/tools/source/fsys/urlobj.cxx @@ -45,6 +45,7 @@ #include <com/sun/star/uno/Sequence.hxx> #include <comphelper/base64.hxx> +#include <comphelper/string.hxx> using namespace css; @@ -291,7 +292,7 @@ int INetURLObject::SubString::compare(SubString const & rOther, struct INetURLObject::SchemeInfo { - rtl::OUStringConstExpr m_sScheme; + OUString m_sScheme; char const * m_pPrefix; bool m_bAuthority; bool m_bUser; @@ -317,36 +318,37 @@ struct INetURLObject::PrefixInfo inline INetURLObject::SchemeInfo const & INetURLObject::getSchemeInfo(INetProtocol eTheScheme) { - static constexpr OUStringLiteral EMPTY = u""; - static constexpr OUStringLiteral FTP = u"ftp"; - static constexpr OUStringLiteral HTTP = u"http"; - static constexpr OUStringLiteral FILE1 = u"file"; // because FILE is already defined - static constexpr OUStringLiteral MAILTO = u"mailto"; - static constexpr OUStringLiteral VND_WEBDAV = u"vnd.sun.star.webdav"; - static constexpr OUStringLiteral PRIVATE = u"private"; - static constexpr OUStringLiteral VND_HELP = u"vnd.sun.star.help"; - static constexpr OUStringLiteral HTTPS = u"https"; - static constexpr OUStringLiteral SLOT = u"slot"; - static constexpr OUStringLiteral MACRO = u"macro"; - static constexpr OUStringLiteral JAVASCRIPT = u"javascript"; - static constexpr OUStringLiteral DATA = u"data"; - static constexpr OUStringLiteral CID = u"cid"; - static constexpr OUStringLiteral VND_HIER = u"vnd.sun.star.hier"; - static constexpr OUStringLiteral UNO = u".uno"; - static constexpr OUStringLiteral COMPONENT = u".component"; - static constexpr OUStringLiteral VND_PKG = u"vnd.sun.star.pkg"; - static constexpr OUStringLiteral LDAP = u"ldap"; - static constexpr OUStringLiteral DB = u"db"; - static constexpr OUStringLiteral VND_CMD = u"vnd.sun.star.cmd"; - static constexpr OUStringLiteral TELNET = u"telnet"; - static constexpr OUStringLiteral VND_EXPAND = u"vnd.sun.star.expand"; - static constexpr OUStringLiteral VND_TDOC = u"vnd.sun.star.tdoc"; - static constexpr OUStringLiteral SMB = u"smb"; - static constexpr OUStringLiteral HID = u"hid"; - static constexpr OUStringLiteral SFTP = u"sftp"; - static constexpr OUStringLiteral VND_CMIS = u"vnd.libreoffice.cmis"; - - static o3tl::enumarray<INetProtocol, SchemeInfo> const map = { + static constexpr OUString EMPTY = u""_ustr; + static constexpr OUString FTP = u"ftp"_ustr; + static constexpr OUString HTTP = u"http"_ustr; + static constexpr OUString FILE1 = u"file"_ustr; // because FILE is already defined + static constexpr OUString MAILTO = u"mailto"_ustr; + static constexpr OUString VND_WEBDAV = u"vnd.sun.star.webdav"_ustr; + static constexpr OUString PRIVATE = u"private"_ustr; + static constexpr OUString VND_HELP = u"vnd.sun.star.help"_ustr; + static constexpr OUString HTTPS = u"https"_ustr; + static constexpr OUString SLOT = u"slot"_ustr; + static constexpr OUString MACRO = u"macro"_ustr; + static constexpr OUString JAVASCRIPT = u"javascript"_ustr; + static constexpr OUString DATA = u"data"_ustr; + static constexpr OUString CID = u"cid"_ustr; + static constexpr OUString VND_HIER = u"vnd.sun.star.hier"_ustr; + static constexpr OUString UNO = u".uno"_ustr; + static constexpr OUString COMPONENT = u".component"_ustr; + static constexpr OUString VND_PKG = u"vnd.sun.star.pkg"_ustr; + static constexpr OUString LDAP = u"ldap"_ustr; + static constexpr OUString DB = u"db"_ustr; + static constexpr OUString VND_CMD = u"vnd.sun.star.cmd"_ustr; + static constexpr OUString TELNET = u"telnet"_ustr; + static constexpr OUString VND_EXPAND = u"vnd.sun.star.expand"_ustr; + static constexpr OUString VND_TDOC = u"vnd.sun.star.tdoc"_ustr; + static constexpr OUString SMB = u"smb"_ustr; + static constexpr OUString HID = u"hid"_ustr; + static constexpr OUString SFTP = u"sftp"_ustr; + static constexpr OUString VND_CMIS = u"vnd.libreoffice.cmis"_ustr; + + static o3tl::enumarray<INetProtocol, SchemeInfo> constexpr map = { + // [-loplugin:redundantfcast]: SchemeInfo{ EMPTY, "", false, false, false, false, false, false, false, false}, SchemeInfo{ @@ -616,6 +618,7 @@ std::unique_ptr<SvMemoryStream> memoryStream( std::unique_ptr<SvMemoryStream> s( new SvMemoryStream(b.get(), length, StreamMode::READ)); s->ObjectOwnsMemory(true); + // coverity[leaked_storage : FALSE] - belongs to SvMemoryStream s at this point b.release(); return s; } @@ -646,10 +649,10 @@ std::unique_ptr<SvMemoryStream> INetURLObject::getData() const else if (sURLPath.matchIgnoreAsciiCase(";base64,", nCharactersSkipped)) { nCharactersSkipped += strlen(";base64,"); - OUString sBase64Data = sURLPath.copy( nCharactersSkipped ); + std::u16string_view sBase64Data = sURLPath.subView( nCharactersSkipped ); css::uno::Sequence< sal_Int8 > aDecodedData; if (comphelper::Base64::decodeSomeChars(aDecodedData, sBase64Data) - == sBase64Data.getLength()) + == sBase64Data.size()) { return memoryStream( aDecodedData.getArray(), aDecodedData.getLength()); @@ -719,14 +722,14 @@ OUString parseScheme( } -bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, +bool INetURLObject::setAbsURIRef(std::u16string_view rTheAbsURIRef, EncodeMechanism eMechanism, rtl_TextEncoding eCharset, bool bSmart, FSysStyle eStyle) { - sal_Unicode const * pPos = rTheAbsURIRef.getStr(); - sal_Unicode const * pEnd = pPos + rTheAbsURIRef.getLength(); + sal_Unicode const * pPos = rTheAbsURIRef.data(); + sal_Unicode const * pEnd = pPos + rTheAbsURIRef.size(); setInvalid(); @@ -806,6 +809,17 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, eMechanism = EncodeMechanism::All; nFragmentDelimiter = 0x80000000; } + else if (eStyle & FSysStyle::Dos + && pEnd - p1 >= 6 + && p1[0] == '\\' && p1[1] == '\\' && p1[2] == '?' && p1[3] == '\\' + && rtl::isAsciiAlpha(p1[4]) + && p1[5] == ':' + && (pEnd - p1 == 6 || p1[6] == '/' || p1[6] == '\\')) + { + m_eScheme = INetProtocol::File; // 8th, 9th + eMechanism = EncodeMechanism::All; + nFragmentDelimiter = 0x80000000; + } else if (pEnd - p1 >= 2 && p1[0] == '/' && p1[1] == '/') { p1 += 2; @@ -825,6 +839,14 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, && p1[1] == '\\') { p1 += 2; + if (pEnd - p1 >= 6 && p1[0] == '?' && p1[1] == '\\' && p1[5] == '\\' + && rtl::toAsciiLowerCase(p1[2]) == 'u' + && rtl::toAsciiLowerCase(p1[3]) == 'n' + && rtl::toAsciiLowerCase(p1[4]) == 'c') + { + p1 += 6; // "\\?\UNC\Servername\..." + } + sal_Int32 n = rtl_ustr_indexOfChar_WithLength( p1, pEnd - p1, '\\'); sal_Unicode const * pe = n == -1 ? pEnd : p1 + n; @@ -869,8 +891,34 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, aSynScheme = parseScheme(&p1, pEnd, nFragmentDelimiter); if (!aSynScheme.isEmpty()) { - m_eScheme = INetProtocol::Generic; - pPos = p1; + if (bSmart && m_eSmartScheme != m_eScheme && p1 != pEnd && rtl::isAsciiDigit(*p1)) + { + // rTheAbsURIRef doesn't define a known scheme (handled by the "if (pPrefix)" + // branch above); but a known scheme is defined in m_eSmartScheme. If this + // scheme may have a port in authority component, then avoid misinterpreting + // URLs like www.foo.bar:123/baz as using unknown "www.foo.bar" scheme with + // 123/baz rootless path. For now, do not try to handle possible colons in + // user information, require such ambiguous URLs to have explicit scheme part. + // Also ignore possibility of empty port. + const SchemeInfo& rInfo = getSchemeInfo(m_eSmartScheme); + if (rInfo.m_bAuthority && rInfo.m_bPort) + { + // Make sure that all characters from colon to [/?#] or to EOL are digits. + // Or maybe make it simple, and just assume that "xyz:1..." is more likely + // to be host "xyz" and port "1...", than scheme "xyz" and path "1..."? + sal_Unicode const* p2 = p1 + 1; + while (p2 != pEnd && rtl::isAsciiDigit(*p2)) + ++p2; + if (p2 == pEnd || *p2 == '/' || *p2 == '?' || *p2 == '#') + m_eScheme = m_eSmartScheme; + } + } + + if (m_eScheme == INetProtocol::NotValid) + { + m_eScheme = INetProtocol::Generic; + pPos = p1; + } } } @@ -887,7 +935,7 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, } if (m_eScheme != INetProtocol::Generic) { - aSynScheme = static_cast<const OUString&>(getSchemeInfo().m_sScheme); + aSynScheme = getSchemeInfo().m_sScheme; } m_aScheme.set(m_aAbsURIRef, aSynScheme, m_aAbsURIRef.getLength()); m_aAbsURIRef.append(':'); @@ -930,7 +978,7 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, PART_AUTHORITY, eCharset, false); } m_aHost.set(m_aAbsURIRef, - aSynAuthority.makeStringAndClear(), + aSynAuthority, m_aAbsURIRef.getLength()); // misusing m_aHost to store the authority break; @@ -966,7 +1014,7 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, return false; } m_aHost.set(m_aAbsURIRef, - aSynAuthority.makeStringAndClear(), + aSynAuthority, m_aAbsURIRef.getLength()); // misusing m_aHost to store the authority } @@ -1007,7 +1055,7 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, else { m_aUser.set(m_aAbsURIRef, - aSynUser.makeStringAndClear(), + aSynUser, m_aAbsURIRef.getLength()); m_aAbsURIRef.append("@"); ++pPos; @@ -1030,7 +1078,7 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, return false; } m_aHost.set(m_aAbsURIRef, - aSynAuthority.makeStringAndClear(), + aSynAuthority, m_aAbsURIRef.getLength()); // misusing m_aHost to store the authority break; @@ -1132,6 +1180,16 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, && pPos[1] == '\\') { sal_Unicode const * p1 = pPos + 2; + sal_Unicode const * pHostPortTentativeBegin = p1; + if (pEnd - p1 >= 6 && p1[0] == '?' && p1[1] == '\\' && p1[5] == '\\' + && rtl::toAsciiLowerCase(p1[2]) == 'u' + && rtl::toAsciiLowerCase(p1[3]) == 'n' + && rtl::toAsciiLowerCase(p1[4]) == 'c') + { + p1 += 6; // "\\?\UNC\Servername\..." + pHostPortTentativeBegin = p1; + } + sal_Unicode const * pe = p1; while (pe < pEnd && *pe != '\\' && *pe != nFragmentDelimiter) @@ -1146,7 +1204,7 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, ) { m_aAbsURIRef.append("//"); - pHostPortBegin = pPos + 2; + pHostPortBegin = pHostPortTentativeBegin; pHostPortEnd = pe; pPos = pe; nSegmentDelimiter = '\\'; @@ -1164,18 +1222,26 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, // becomes // "file:///" ALPHA ":" ["/" *path] ["#" *UCS4] // replacing "\" by "/" within <*path> - if (eStyle & FSysStyle::Dos - && pEnd - pPos >= 2 - && rtl::isAsciiAlpha(pPos[0]) - && pPos[1] == ':' - && (pEnd - pPos == 2 - || pPos[2] == '/' - || pPos[2] == '\\')) + if (eStyle & FSysStyle::Dos) { - m_aAbsURIRef.append("//"); - nAltSegmentDelimiter = '\\'; - bSkippedInitialSlash = true; - break; + sal_Unicode const* p1 = pPos; + if (pEnd - p1 >= 4 && p1[0] == '\\' && p1[1] == '\\' && p1[2] == '?' + && p1[3] == '\\') + p1 += 4; // "\\?\c:\..." + + if (pEnd - p1 >= 2 + && rtl::isAsciiAlpha(p1[0]) + && p1[1] == ':' + && (pEnd - p1 == 2 + || p1[2] == '/' + || p1[2] == '\\')) + { + pPos = p1; + m_aAbsURIRef.append("//"); + nAltSegmentDelimiter = '\\'; + bSkippedInitialSlash = true; + break; + } } // 9th Production (any): @@ -1314,8 +1380,7 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, appendUCS4(aSynUser, nUTF32, eEscapeType, ePart, eCharset, false); } - m_aUser.set(m_aAbsURIRef, aSynUser.makeStringAndClear(), - m_aAbsURIRef.getLength()); + m_aUser.set(m_aAbsURIRef, aSynUser, m_aAbsURIRef.getLength()); if (bHasAuth) { if (bSupportsPassword) @@ -1331,8 +1396,7 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, appendUCS4(aSynAuth, nUTF32, eEscapeType, ePart, eCharset, false); } - m_aAuth.set(m_aAbsURIRef, aSynAuth.makeStringAndClear(), - m_aAbsURIRef.getLength()); + m_aAuth.set(m_aAbsURIRef, aSynAuth, m_aAbsURIRef.getLength()); } else { @@ -1352,8 +1416,7 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, appendUCS4(aSynAuth, nUTF32, eEscapeType, ePart, eCharset, false); } - m_aAuth.set(m_aAbsURIRef, aSynAuth.makeStringAndClear(), - m_aAbsURIRef.getLength()); + m_aAuth.set(m_aAbsURIRef, aSynAuth, m_aAbsURIRef.getLength()); } } if (pHostPortBegin) @@ -1444,8 +1507,7 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, appendUCS4(aSynQuery, nUTF32, eEscapeType, PART_URIC, eCharset, true); } - m_aQuery.set(m_aAbsURIRef, aSynQuery.makeStringAndClear(), - m_aAbsURIRef.getLength()); + m_aQuery.set(m_aAbsURIRef, aSynQuery, m_aAbsURIRef.getLength()); } // Parse #<fragment> @@ -1461,8 +1523,7 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, appendUCS4(aSynFragment, nUTF32, eEscapeType, PART_URIC, eCharset, true); } - m_aFragment.set(m_aAbsURIRef, aSynFragment.makeStringAndClear(), - m_aAbsURIRef.getLength()); + m_aFragment.set(m_aAbsURIRef, aSynFragment, m_aAbsURIRef.getLength()); } if (pPos != pEnd) @@ -1557,12 +1618,35 @@ bool INetURLObject::convertRelToAbs(OUString const & rTheRelURIRef, q += 2; sal_Int32 n = rtl_ustr_indexOfChar_WithLength( q, pEnd - q, '\\'); - sal_Unicode const * qe = n == -1 ? pEnd : q + n; - if (parseHostOrNetBiosName( - q, qe, EncodeMechanism::All, RTL_TEXTENCODING_DONTKNOW, - true, nullptr)) + if (n == 1 && q[0] == '?') + { + // "\\?\c:\..." or "\\?\UNC\servername\..." + q += 2; + if (pEnd - q >= 2 + && rtl::isAsciiAlpha(q[0]) + && q[1] == ':' + && (pEnd - q == 2 || q[2] == '/' || q[2] == '\\')) + { + bFSys = true; // 2nd, 3rd + } + else if (pEnd - q >= 4 + && q[3] == '\\' + && rtl::toAsciiLowerCase(q[0]) == 'u' + && rtl::toAsciiLowerCase(q[1]) == 'n' + && rtl::toAsciiLowerCase(q[2]) == 'c') + { + q += 4; // Check if it's 1st below + } + } + if (!bFSys) { - bFSys = true; // 1st + sal_Unicode const * qe = n == -1 ? pEnd : q + n; + if (parseHostOrNetBiosName( + q, qe, EncodeMechanism::All, RTL_TEXTENCODING_DONTKNOW, + true, nullptr)) + { + bFSys = true; // 1st + } } } if (bFSys) @@ -1645,7 +1729,7 @@ bool INetURLObject::convertRelToAbs(OUString const & rTheRelURIRef, // is empty ("") in that case, so take the scheme from m_aAbsURIRef if (m_eScheme != INetProtocol::Generic) { - aSynAbsURIRef.append(getSchemeInfo().m_sScheme.asView()); + aSynAbsURIRef.append(getSchemeInfo().m_sScheme); } else { @@ -1875,7 +1959,7 @@ bool INetURLObject::convertRelToAbs(OUString const & rTheRelURIRef, } } - INetURLObject aNewURI(aSynAbsURIRef.makeStringAndClear()); + INetURLObject aNewURI(aSynAbsURIRef); if (aNewURI.HasError()) { // Detect cases where a relative input could not be made absolute @@ -2038,15 +2122,13 @@ bool INetURLObject::convertAbsToRel(OUString const & rTheAbsURIRef, // to the new relative URL: if (aSubject.m_aQuery.isPresent()) { - aSynRelURIRef.append('?'); - aSynRelURIRef.append(aSubject.decode(aSubject.m_aQuery, - eDecodeMechanism, eCharset)); + aSynRelURIRef.append("?" + + aSubject.decode(aSubject.m_aQuery, eDecodeMechanism, eCharset)); } if (aSubject.m_aFragment.isPresent()) { - aSynRelURIRef.append('#'); - aSynRelURIRef.append(aSubject.decode(aSubject.m_aFragment, - eDecodeMechanism, eCharset)); + aSynRelURIRef.append("#" + + aSubject.decode(aSubject.m_aFragment, eDecodeMechanism, eCharset)); } rTheRelURIRef = aSynRelURIRef.makeStringAndClear(); @@ -2059,8 +2141,9 @@ bool INetURLObject::convertIntToExt(std::u16string_view rTheIntURIRef, DecodeMechanism eDecodeMechanism, rtl_TextEncoding eCharset) { - OUString aSynExtURIRef(encodeText(rTheIntURIRef, PART_VISIBLE, - EncodeMechanism::NotCanonical, eCharset, true)); + OUStringBuffer aSynExtURIRef(256); + encodeText(aSynExtURIRef, rTheIntURIRef, PART_VISIBLE, + EncodeMechanism::NotCanonical, eCharset, true); sal_Unicode const * pBegin = aSynExtURIRef.getStr(); sal_Unicode const * pEnd = pBegin + aSynExtURIRef.getLength(); sal_Unicode const * p = pBegin; @@ -2068,8 +2151,7 @@ bool INetURLObject::convertIntToExt(std::u16string_view rTheIntURIRef, bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::Kind::Internal; if (bConvert) { - aSynExtURIRef = - aSynExtURIRef.replaceAt(0, p - pBegin, + comphelper::string::replaceAt(aSynExtURIRef, 0, p - pBegin, OUString::createFromAscii(pPrefix->m_pTranslatedPrefix)); } rTheExtURIRef = decode(aSynExtURIRef, eDecodeMechanism, eCharset); @@ -2082,8 +2164,9 @@ bool INetURLObject::convertExtToInt(std::u16string_view rTheExtURIRef, DecodeMechanism eDecodeMechanism, rtl_TextEncoding eCharset) { - OUString aSynIntURIRef(encodeText(rTheExtURIRef, PART_VISIBLE, - EncodeMechanism::NotCanonical, eCharset, true)); + OUStringBuffer aSynIntURIRef(256); + encodeText(aSynIntURIRef, rTheExtURIRef, PART_VISIBLE, + EncodeMechanism::NotCanonical, eCharset, true); sal_Unicode const * pBegin = aSynIntURIRef.getStr(); sal_Unicode const * pEnd = pBegin + aSynIntURIRef.getLength(); sal_Unicode const * p = pBegin; @@ -2091,9 +2174,8 @@ bool INetURLObject::convertExtToInt(std::u16string_view rTheExtURIRef, bool bConvert = pPrefix && pPrefix->m_eKind == PrefixInfo::Kind::External; if (bConvert) { - aSynIntURIRef = - aSynIntURIRef.replaceAt(0, p - pBegin, - OUString::createFromAscii(pPrefix->m_pTranslatedPrefix)); + comphelper::string::replaceAt(aSynIntURIRef, 0, p - pBegin, + OUString::createFromAscii(pPrefix->m_pTranslatedPrefix)); } rTheIntURIRef = decode(aSynIntURIRef, eDecodeMechanism, eCharset); return bConvert; @@ -2262,8 +2344,9 @@ bool INetURLObject::setUser(std::u16string_view rTheUser, return false; } - OUString aNewUser(encodeText(rTheUser, PART_USER_PASSWORD, - EncodeMechanism::WasEncoded, eCharset, false)); + OUStringBuffer aNewUser; + encodeText(aNewUser, rTheUser, PART_USER_PASSWORD, + EncodeMechanism::WasEncoded, eCharset, false); sal_Int32 nDelta; if (m_aUser.isPresent()) nDelta = m_aUser.set(m_aAbsURIRef, aNewUser); @@ -2317,8 +2400,9 @@ bool INetURLObject::setPassword(std::u16string_view rThePassword, { if (!getSchemeInfo().m_bPassword) return false; - OUString aNewAuth(encodeText(rThePassword, PART_USER_PASSWORD, - EncodeMechanism::WasEncoded, eCharset, false)); + OUStringBuffer aNewAuth; + encodeText(aNewAuth, rThePassword, PART_USER_PASSWORD, + EncodeMechanism::WasEncoded, eCharset, false); sal_Int32 nDelta; if (m_aAuth.isPresent()) nDelta = m_aAuth.set(m_aAbsURIRef, aNewAuth); @@ -2831,63 +2915,47 @@ bool INetURLObject::parseHostOrNetBiosName( EncodeMechanism eMechanism, rtl_TextEncoding eCharset, bool bNetBiosName, OUStringBuffer* pCanonic) { + if (pBegin >= pEnd) + return true; sal_Int32 nOriginalCanonicLength = pCanonic ? pCanonic->getLength() : 0; - if (pBegin < pEnd) + if (sal_Unicode const* p = pBegin; parseHost(p, pEnd, pCanonic) && p == pEnd) + return true; + if (pCanonic) + pCanonic->setLength(nOriginalCanonicLength); // discard parseHost results + if (!bNetBiosName) + return false; + while (pBegin < pEnd) { - sal_Unicode const * p = pBegin; - if (!parseHost(p, pEnd, pCanonic) || p != pEnd) + EscapeType eEscapeType; + switch (sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, eMechanism, eCharset, eEscapeType)) { - if (bNetBiosName) - { - OUStringBuffer buf; - while (pBegin < pEnd) + default: + if (INetMIME::isVisible(nUTF32)) { - EscapeType eEscapeType; - sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, - eMechanism, eCharset, - eEscapeType); - if (!INetMIME::isVisible(nUTF32)) - { - if (pCanonic) - pCanonic->setLength(nOriginalCanonicLength); - return false; - } - if (!rtl::isAsciiAlphanumeric(nUTF32)) - switch (nUTF32) - { - case '"': - case '*': - case '+': - case ',': - case '/': - case ':': - case ';': - case '<': - case '=': - case '>': - case '?': - case '[': - case '\\': - case ']': - case '`': - case '|': - return false; - } - if (pCanonic != nullptr) { - appendUCS4( - buf, nUTF32, eEscapeType, PART_URIC, - eCharset, true); - } + if (pCanonic) + appendUCS4(*pCanonic, nUTF32, eEscapeType, PART_URIC, eCharset, true); + break; } - if (pCanonic) - pCanonic->append(buf); - } - else - { + [[fallthrough]]; + case '"': + case '*': + case '+': + case ',': + case '/': + case ':': + case ';': + case '<': + case '=': + case '>': + case '?': + case '[': + case '\\': + case ']': + case '`': + case '|': if (pCanonic) pCanonic->setLength(nOriginalCanonicLength); return false; - } } } return true; @@ -2904,8 +2972,7 @@ bool INetURLObject::setHost(std::u16string_view rTheHost, { case INetProtocol::File: { - OUString sTemp(aSynHost.toString()); - if (sTemp.equalsIgnoreAsciiCase("localhost")) + if (OUString::unacquired(aSynHost).equalsIgnoreAsciiCase("localhost")) { aSynHost.setLength(0); } @@ -2926,7 +2993,7 @@ bool INetURLObject::setHost(std::u16string_view rTheHost, aSynHost.getStr(), aSynHost.getStr() + aSynHost.getLength(), EncodeMechanism::WasEncoded, eCharset, bNetBiosName, &aSynHost)) return false; - sal_Int32 nDelta = m_aHost.set(m_aAbsURIRef, aSynHost.makeStringAndClear()); + sal_Int32 nDelta = m_aHost.set(m_aAbsURIRef, aSynHost); m_aPort += nDelta; m_aPath += nDelta; m_aQuery += nDelta; @@ -2976,7 +3043,8 @@ bool INetURLObject::parsePath(INetProtocol eScheme, case INetProtocol::Https: case INetProtocol::Smb: case INetProtocol::Cmis: - if (pPos < pEnd && *pPos != '/' && *pPos != nFragmentDelimiter) + if (pPos < pEnd && *pPos != '/' && *pPos != nQueryDelimiter + && *pPos != nFragmentDelimiter) goto failed; while (pPos < pEnd && *pPos != nQueryDelimiter && *pPos != nFragmentDelimiter) @@ -3191,18 +3259,18 @@ failed: return false; } -bool INetURLObject::setPath(OUString const & rThePath, +bool INetURLObject::setPath(std::u16string_view rThePath, EncodeMechanism eMechanism, rtl_TextEncoding eCharset) { OUStringBuffer aSynPath(256); - sal_Unicode const * p = rThePath.getStr(); - sal_Unicode const * pEnd = p + rThePath.getLength(); + sal_Unicode const * p = rThePath.data(); + sal_Unicode const * pEnd = p + rThePath.size(); if (!parsePath(m_eScheme, &p, pEnd, eMechanism, eCharset, false, '/', 0x80000000, 0x80000000, 0x80000000, aSynPath) || p != pEnd) return false; - sal_Int32 nDelta = m_aPath.set(m_aAbsURIRef, aSynPath.makeStringAndClear()); + sal_Int32 nDelta = m_aPath.set(m_aAbsURIRef, aSynPath); m_aQuery += nDelta; m_aFragment += nDelta; return true; @@ -3344,16 +3412,17 @@ bool INetURLObject::insertName(std::u16string_view rTheName, } OUStringBuffer aNewPath(256); - aNewPath.append(pPathBegin, pPrefixEnd - pPathBegin); - aNewPath.append('/'); - aNewPath.append(encodeText(rTheName, PART_PCHAR, - eMechanism, eCharset, true)); + aNewPath.append( + OUString::Concat(std::u16string_view(pPathBegin, pPrefixEnd - pPathBegin)) + + "/"); + encodeText(aNewPath, rTheName, PART_PCHAR, + eMechanism, eCharset, true); if (bInsertSlash) { aNewPath.append('/'); } aNewPath.append(pSuffixBegin, pPathEnd - pSuffixBegin); - return setPath(aNewPath.makeStringAndClear(), EncodeMechanism::NotCanonical, + return setPath(aNewPath, EncodeMechanism::NotCanonical, RTL_TEXTENCODING_UTF8); } @@ -3375,8 +3444,9 @@ bool INetURLObject::setQuery(std::u16string_view rTheQuery, { if (!getSchemeInfo().m_bQuery) return false; - OUString aNewQuery(encodeText(rTheQuery, PART_URIC, - eMechanism, eCharset, true)); + OUStringBuffer aNewQuery; + encodeText(aNewQuery, rTheQuery, PART_URIC, + eMechanism, eCharset, true); sal_Int32 nDelta; if (m_aQuery.isPresent()) nDelta = m_aQuery.set(m_aAbsURIRef, aNewQuery); @@ -3408,8 +3478,9 @@ bool INetURLObject::setFragment(std::u16string_view rTheFragment, { if (HasError()) return false; - OUString aNewFragment(encodeText(rTheFragment, PART_URIC, - eMechanism, eCharset, true)); + OUStringBuffer aNewFragment; + encodeText(aNewFragment, rTheFragment, PART_URIC, + eMechanism, eCharset, true); if (m_aFragment.isPresent()) m_aFragment.set(m_aAbsURIRef, aNewFragment); else @@ -3432,22 +3503,21 @@ bool INetURLObject::hasDosVolume(FSysStyle eStyle) const } // static -OUString INetURLObject::encodeText(sal_Unicode const * pBegin, - sal_Unicode const * pEnd, - Part ePart, EncodeMechanism eMechanism, - rtl_TextEncoding eCharset, - bool bKeepVisibleEscapes) +void INetURLObject::encodeText( OUStringBuffer& rOutputBuffer, + sal_Unicode const * pBegin, + sal_Unicode const * pEnd, + Part ePart, EncodeMechanism eMechanism, + rtl_TextEncoding eCharset, + bool bKeepVisibleEscapes) { - OUStringBuffer aResult(256); while (pBegin < pEnd) { EscapeType eEscapeType; sal_uInt32 nUTF32 = getUTF32(pBegin, pEnd, eMechanism, eCharset, eEscapeType); - appendUCS4(aResult, nUTF32, eEscapeType, ePart, + appendUCS4(rOutputBuffer, nUTF32, eEscapeType, ePart, eCharset, bKeepVisibleEscapes); } - return aResult.makeStringAndClear(); } // static @@ -3536,7 +3606,7 @@ INetURLObject::getAbbreviated( // is empty ("") in that case, so take the scheme from m_aAbsURIRef if (m_eScheme != INetProtocol::Generic) { - aBuffer.append(getSchemeInfo().m_sScheme.asView()); + aBuffer.append(getSchemeInfo().m_sScheme); } else { @@ -3596,9 +3666,7 @@ INetURLObject::getAbbreviated( OUStringBuffer aResult(aBuffer); if (pSuffixEnd != pBegin) aResult.append("..."); - aResult.append(aSegment); - aResult.append(aTrailer); - aResult.append(aRest); + aResult.append(aSegment + aTrailer + aRest); if (rStringWidth-> queryStringWidth(aResult.makeStringAndClear()) <= nWidth) @@ -3633,12 +3701,10 @@ INetURLObject::getAbbreviated( eMechanism, eCharset)); pPrefixBegin = p; - OUStringBuffer aResult(aBuffer); - aResult.append(aSegment); + OUStringBuffer aResult(aBuffer + aSegment); if (pPrefixBegin != pEnd) aResult.append("..."); - aResult.append(aTrailer); - aResult.append(aRest); + aResult.append(aTrailer + aRest); if (rStringWidth-> queryStringWidth(aResult.makeStringAndClear()) <= nWidth) @@ -3670,13 +3736,11 @@ INetURLObject::getAbbreviated( eCharset)); if (m_aQuery.isPresent()) { - aBuffer.append('?'); - aBuffer.append(decode(m_aQuery, eMechanism, eCharset)); + aBuffer.append("?" + decode(m_aQuery, eMechanism, eCharset)); } if (m_aFragment.isPresent()) { - aBuffer.append('#'); - aBuffer.append(decode(m_aFragment, eMechanism, eCharset)); + aBuffer.append("#" + decode(m_aFragment, eMechanism, eCharset)); } if (!aBuffer.isEmpty()) { @@ -3711,7 +3775,7 @@ bool INetURLObject::operator ==(INetURLObject const & rObject) const if (m_eScheme != rObject.m_eScheme) return false; if (m_eScheme == INetProtocol::NotValid) - return m_aAbsURIRef.toString() == rObject.m_aAbsURIRef.toString(); + return std::u16string_view(m_aAbsURIRef) == std::u16string_view(rObject.m_aAbsURIRef); if ((m_aScheme.compare( rObject.m_aScheme, m_aAbsURIRef, rObject.m_aAbsURIRef) != 0) @@ -3764,14 +3828,14 @@ bool INetURLObject::ConcatData(INetProtocol eTheScheme, std::u16string_view rThePassword, std::u16string_view rTheHost, sal_uInt32 nThePort, - OUString const & rThePath) + std::u16string_view rThePath) { setInvalid(); m_eScheme = eTheScheme; if (HasError() || m_eScheme == INetProtocol::Generic) return false; m_aAbsURIRef.setLength(0); - m_aAbsURIRef.append(getSchemeInfo().m_sScheme.asView()); + m_aAbsURIRef.append(getSchemeInfo().m_sScheme); m_aAbsURIRef.append(':'); if (getSchemeInfo().m_bAuthority) { @@ -3781,10 +3845,10 @@ bool INetURLObject::ConcatData(INetProtocol eTheScheme, { if (!rTheUser.empty()) { - m_aUser.set(m_aAbsURIRef, - encodeText(rTheUser, PART_USER_PASSWORD, - EncodeMechanism::WasEncoded, RTL_TEXTENCODING_UTF8, false), - m_aAbsURIRef.getLength()); + OUStringBuffer aNewUser; + encodeText(aNewUser, rTheUser, PART_USER_PASSWORD, + EncodeMechanism::WasEncoded, RTL_TEXTENCODING_UTF8, false); + m_aUser.set(m_aAbsURIRef, aNewUser, m_aAbsURIRef.getLength()); bUserInfo = true; } } @@ -3798,10 +3862,10 @@ bool INetURLObject::ConcatData(INetProtocol eTheScheme, if (getSchemeInfo().m_bPassword) { m_aAbsURIRef.append(':'); - m_aAuth.set(m_aAbsURIRef, - encodeText(rThePassword, PART_USER_PASSWORD, - EncodeMechanism::WasEncoded, RTL_TEXTENCODING_UTF8, false), - m_aAbsURIRef.getLength()); + OUStringBuffer aNewAuth; + encodeText(aNewAuth, rThePassword, PART_USER_PASSWORD, + EncodeMechanism::WasEncoded, RTL_TEXTENCODING_UTF8, false); + m_aAuth.set(m_aAbsURIRef, aNewAuth, m_aAbsURIRef.getLength()); bUserInfo = true; } else @@ -3820,8 +3884,7 @@ bool INetURLObject::ConcatData(INetProtocol eTheScheme, { case INetProtocol::File: { - OUString sTemp(aSynHost.toString()); - if (sTemp.equalsIgnoreAsciiCase( "localhost" )) + if (OUString::unacquired(aSynHost).equalsIgnoreAsciiCase( "localhost" )) { aSynHost.setLength(0); } @@ -3852,8 +3915,7 @@ bool INetURLObject::ConcatData(INetProtocol eTheScheme, setInvalid(); return false; } - m_aHost.set(m_aAbsURIRef, aSynHost.makeStringAndClear(), - m_aAbsURIRef.getLength()); + m_aHost.set(m_aAbsURIRef, aSynHost, m_aAbsURIRef.getLength()); if (nThePort != 0) { if (getSchemeInfo().m_bPort) @@ -3877,8 +3939,8 @@ bool INetURLObject::ConcatData(INetProtocol eTheScheme, } } OUStringBuffer aSynPath(256); - sal_Unicode const * p = rThePath.getStr(); - sal_Unicode const * pEnd = p + rThePath.getLength(); + sal_Unicode const * p = rThePath.data(); + sal_Unicode const * pEnd = p + rThePath.size(); if (!parsePath(m_eScheme, &p, pEnd, EncodeMechanism::WasEncoded, RTL_TEXTENCODING_UTF8, false, '/', 0x80000000, 0x80000000, 0x80000000, aSynPath) || p != pEnd) @@ -3886,13 +3948,12 @@ bool INetURLObject::ConcatData(INetProtocol eTheScheme, setInvalid(); return false; } - m_aPath.set(m_aAbsURIRef, aSynPath.makeStringAndClear(), - m_aAbsURIRef.getLength()); + m_aPath.set(m_aAbsURIRef, aSynPath, m_aAbsURIRef.getLength()); return true; } // static -OUString INetURLObject::GetAbsURL(OUString const & rTheBaseURIRef, +OUString INetURLObject::GetAbsURL(std::u16string_view rTheBaseURIRef, OUString const & rTheRelURIRef, EncodeMechanism eEncodeMechanism, DecodeMechanism eDecodeMechanism, @@ -3920,7 +3981,7 @@ OUString INetURLObject::getExternalURL() const { OUString aTheExtURIRef; translateToExternal( - m_aAbsURIRef.toString(), aTheExtURIRef); + m_aAbsURIRef, aTheExtURIRef); return aTheExtURIRef; } @@ -3955,11 +4016,10 @@ const OUString & INetURLObject::GetSchemeName(INetProtocol eTheScheme) } // static -INetProtocol INetURLObject::CompareProtocolScheme(OUString const & - rTheAbsURIRef) +INetProtocol INetURLObject::CompareProtocolScheme(std::u16string_view aTheAbsURIRef) { - sal_Unicode const * p = rTheAbsURIRef.getStr(); - PrefixInfo const * pPrefix = getPrefix(p, p + rTheAbsURIRef.getLength()); + sal_Unicode const * p = aTheAbsURIRef.data(); + PrefixInfo const * pPrefix = getPrefix(p, p + aTheAbsURIRef.size()); return pPrefix ? pPrefix->m_eScheme : INetProtocol::NotValid; } @@ -3973,8 +4033,7 @@ OUString INetURLObject::GetHostPort(DecodeMechanism eMechanism, OUStringBuffer aHostPort(decode(m_aHost, eMechanism, eCharset)); if (m_aPort.isPresent()) { - aHostPort.append(':'); - aHostPort.append(decode(m_aPort, eMechanism, eCharset)); + aHostPort.append(":" + decode(m_aPort, eMechanism, eCharset)); } return aHostPort.makeStringAndClear(); } @@ -4049,7 +4108,7 @@ bool INetURLObject::removeSegment(sal_Int32 nIndex, bool bIgnoreFinalSlash) aNewPath.append('/'); } - return setPath(aNewPath.makeStringAndClear(), EncodeMechanism::NotCanonical, + return setPath(aNewPath, EncodeMechanism::NotCanonical, RTL_TEXTENCODING_UTF8); } @@ -4094,12 +4153,11 @@ bool INetURLObject::setName(std::u16string_view rTheName, EncodeMechanism eMecha while (p != pSegEnd && *p != ';') ++p; - return setPath( - std::u16string_view(pPathBegin, pSegBegin - pPathBegin) - + encodeText(rTheName, PART_PCHAR, eMechanism, eCharset, true) - + std::u16string_view(p, pPathEnd - p), - EncodeMechanism::NotCanonical, - RTL_TEXTENCODING_UTF8); + OUStringBuffer aNewPath(256); + aNewPath.append(std::u16string_view(pPathBegin, pSegBegin - pPathBegin)); + encodeText(aNewPath, rTheName, PART_PCHAR, eMechanism, eCharset, true); + aNewPath.append(std::u16string_view(p, pPathEnd - p)); + return setPath(aNewPath, EncodeMechanism::NotCanonical, RTL_TEXTENCODING_UTF8); } bool INetURLObject::hasExtension() @@ -4171,12 +4229,11 @@ bool INetURLObject::setBase(std::u16string_view rTheBase, sal_Int32 nIndex, if (!pExtension) pExtension = p; - return setPath( - std::u16string_view(pPathBegin, pSegBegin - pPathBegin) - + encodeText(rTheBase, PART_PCHAR, eMechanism, eCharset, true) - + std::u16string_view(pExtension, pPathEnd - pExtension), - EncodeMechanism::NotCanonical, - RTL_TEXTENCODING_UTF8); + OUStringBuffer aNewPath(256); + aNewPath.append(std::u16string_view(pPathBegin, pSegBegin - pPathBegin)); + encodeText(aNewPath, rTheBase, PART_PCHAR, eMechanism, eCharset, true); + aNewPath.append(std::u16string_view(pExtension, pPathEnd - pExtension)); + return setPath(aNewPath, EncodeMechanism::NotCanonical, RTL_TEXTENCODING_UTF8); } OUString INetURLObject::getExtension(sal_Int32 nIndex, @@ -4231,12 +4288,11 @@ bool INetURLObject::setExtension(std::u16string_view rTheExtension, if (!pExtension) pExtension = p; - return setPath( - OUString::Concat(std::u16string_view(pPathBegin, pExtension - pPathBegin)) + "." - + encodeText(rTheExtension, PART_PCHAR, EncodeMechanism::WasEncoded, eCharset, true) - + std::u16string_view(p, pPathEnd - p), - EncodeMechanism::NotCanonical, - RTL_TEXTENCODING_UTF8); + OUStringBuffer aNewPath(256); + aNewPath.append(OUString::Concat(std::u16string_view(pPathBegin, pExtension - pPathBegin)) + "."); + encodeText(aNewPath, rTheExtension, PART_PCHAR, EncodeMechanism::WasEncoded, eCharset, true); + aNewPath.append(std::u16string_view(p, pPathEnd - p)); + return setPath(aNewPath, EncodeMechanism::NotCanonical, RTL_TEXTENCODING_UTF8); } bool INetURLObject::removeExtension(sal_Int32 nIndex, bool bIgnoreFinalSlash) @@ -4358,8 +4414,7 @@ OUString INetURLObject::getFSysPath(FSysStyle eStyle, if (pDelimiter) *pDelimiter = '/'; - OUStringBuffer aSynFSysPath; - aSynFSysPath.append("//"); + OUStringBuffer aSynFSysPath("//"); if (m_aHost.isPresent() && m_aHost.getLength() > 0) aSynFSysPath.append(decode(m_aHost, DecodeMechanism::WithCharset, RTL_TEXTENCODING_UTF8)); @@ -4389,10 +4444,9 @@ OUString INetURLObject::getFSysPath(FSysStyle eStyle, OUStringBuffer aSynFSysPath(64); if (m_aHost.isPresent() && m_aHost.getLength() > 0) { - aSynFSysPath.append("\\\\"); - aSynFSysPath.append(decode(m_aHost, DecodeMechanism::WithCharset, - RTL_TEXTENCODING_UTF8)); - aSynFSysPath.append('\\'); + aSynFSysPath.append("\\\\" + + decode(m_aHost, DecodeMechanism::WithCharset, RTL_TEXTENCODING_UTF8) + + "\\"); } sal_Unicode const * p = m_aAbsURIRef.getStr() + m_aPath.getBegin(); @@ -4822,8 +4876,18 @@ void INetURLObject::SetExtension(std::u16string_view rTheExtension) OUString INetURLObject::CutExtension() { OUString aTheExtension(getExtension(LAST_SEGMENT, false)); - return removeExtension(LAST_SEGMENT, false) - ? aTheExtension : OUString(); + if (removeExtension(LAST_SEGMENT, false)) + return aTheExtension; + return OUString(); +} + +bool INetURLObject::IsExoticProtocol() const +{ + return m_eScheme == INetProtocol::Slot || + m_eScheme == INetProtocol::Macro || + m_eScheme == INetProtocol::Uno || + isSchemeEqualTo(u"vnd.sun.star.script") || + isSchemeEqualTo(u"service"); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/fsys/wldcrd.cxx b/tools/source/fsys/wldcrd.cxx index 6e0259696aca..e8199975c6e5 100644 --- a/tools/source/fsys/wldcrd.cxx +++ b/tools/source/fsys/wldcrd.cxx @@ -25,85 +25,96 @@ * '?' in pWild mean match exactly one character. * */ -bool WildCard::ImpMatch( const sal_Unicode *pWild, const sal_Unicode *pStr ) +bool WildCard::ImpMatch( std::u16string_view aWild, std::u16string_view aStr ) { - int pos=0; - int flag=0; + const sal_Unicode* pPosAfterAsterisk = nullptr; + const sal_Unicode* pWild = aWild.data(); + const sal_Unicode* pWildEnd = aWild.data() + aWild.size(); + const sal_Unicode* pStr = aStr.data(); + const sal_Unicode* pStrEnd = aStr.data() + aStr.size(); - while ( *pWild || flag ) + while (pWild != pWildEnd) { switch (*pWild) { case '?': - if ( *pStr == '\0' ) + if ( pStr == pStrEnd ) return false; - break; - - default: - if ( (*pWild == '\\') && ((*(pWild+1)=='?') || (*(pWild+1) == '*')) ) + break; // Match -> proceed to the next character + case '\\': // Escaping '?' and '*'; don't we need to escape '\\'? + if ((pWild + 1 != pWildEnd) && ((*(pWild + 1) == '?') || (*(pWild + 1) == '*'))) pWild++; - if ( *pWild != *pStr ) - if ( !pos ) - return false; - else - pWild += pos; - else - break; - // WARNING/TODO: may cause execution of next case in some - // circumstances! + [[fallthrough]]; + default: // No wildcard, literal match + if (pStr == pStrEnd) + return false; + if (*pWild == *pStr) + break; // Match -> proceed to the next character + if (!pPosAfterAsterisk) + return false; + pWild = pPosAfterAsterisk; [[fallthrough]]; case '*': - while ( *pWild == '*' ) + while ( pWild != pWildEnd && *pWild == '*' ) pWild++; - if ( *pWild == '\0' ) + if ( pWild == pWildEnd ) return true; - flag = 1; - pos = 0; - if ( *pStr == '\0' ) - return ( *pWild == '\0' ); - while ( *pStr && *pStr != *pWild ) + // Consider strange things like "**?*?*" + while (*pWild == '?') { - if ( *pWild == '?' ) { + if (pStr == pStrEnd) + return false; + pWild++; + pStr++; + while (pWild != pWildEnd && *pWild == '*') pWild++; - while ( *pWild == '*' ) - pWild++; - } + if (pWild == pWildEnd) + return true; + } + // At this point, we are past wildcards, and a literal match must follow + if ( pStr == pStrEnd ) + return false; + pPosAfterAsterisk = pWild; + if ((*pWild == '\\') && (pWild + 1 != pWildEnd) && ((*(pWild + 1) == '?') || (*(pWild + 1) == '*'))) + pWild++; + while (*pStr != *pWild) + { pStr++; - if ( *pStr == '\0' ) - return ( *pWild == '\0' ); + if ( pStr == pStrEnd ) + return false; } - break; + break; // Match -> proceed to the next character } - if ( *pWild != '\0' ) - pWild++; - if ( *pStr != '\0' ) - pStr++; - else - flag = 0; - if ( flag ) - pos--; + // We arrive here when the current characters in pWild and pStr match + assert(pWild != pWildEnd); + pWild++; + assert(pStr != pStrEnd); + pStr++; + if (pWild == pWildEnd && pPosAfterAsterisk && pStr != pStrEnd) + pWild = pPosAfterAsterisk; // Try again on the rest of pStr } - return ( *pStr == '\0' ) && ( *pWild == '\0' ); + assert(pWild == pWildEnd); + return pStr == pStrEnd; } bool WildCard::Matches( std::u16string_view rString ) const { - OUString aTmpWild = aWildString; + std::u16string_view aTmpWild = aWildString; - sal_Int32 nSepPos; + size_t nSepPos; if ( cSepSymbol != '\0' ) { - while ( (nSepPos = aTmpWild.indexOf(cSepSymbol)) != -1 ) + while ( (nSepPos = aTmpWild.find(cSepSymbol)) != std::u16string_view::npos ) { // Check all split wildcards - if ( ImpMatch( aTmpWild.subView( 0, nSepPos ).data(), rString.data() ) ) + if ( ImpMatch( aTmpWild.substr( 0, nSepPos ), rString ) ) return true; - aTmpWild = aTmpWild.copy(nSepPos + 1); // remove separator + aTmpWild = aTmpWild.substr(nSepPos + 1); // remove separator } } - return ImpMatch( aTmpWild.getStr(), rString.data() ); + return ImpMatch( aTmpWild, rString ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/generic/b3dtrans.cxx b/tools/source/generic/b3dtrans.cxx index 0215610956a8..0cae750da0dc 100644 --- a/tools/source/generic/b3dtrans.cxx +++ b/tools/source/generic/b3dtrans.cxx @@ -252,7 +252,7 @@ void B3dTransformationSet::CalcViewport() // #i36281# // OpenGL needs a little more rough additional size to not let // the front face vanish. Changed from SMALL_DVALUE to 0.000001, - // which is 1/10000th, comared with 1/tenth of a million from SMALL_DVALUE. + // which is 1/10000th, compared with 1/tenth of a million from SMALL_DVALUE. const double fDistPart((gfFarBound - gfNearBound) * 0.0001); // To avoid critical clipping, set Near & Far generously diff --git a/tools/source/generic/bigint.cxx b/tools/source/generic/bigint.cxx index f6627200a61c..80b86af6013c 100644 --- a/tools/source/generic/bigint.cxx +++ b/tools/source/generic/bigint.cxx @@ -17,13 +17,15 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <math.h> +#include <sal/config.h> #include <osl/diagnose.h> #include <tools/bigint.hxx> #include <algorithm> -#include <string.h> +#include <cmath> +#include <cstring> +#include <span> /** * The range in which we can perform add/sub without fear of overflow @@ -38,123 +40,116 @@ const sal_Int32 MY_MINLONG = -MY_MAXLONG; * chapter 4.3.1. The Classical Algorithms. */ -// TODO: Needs conversion to sal_uInt16/INT16/sal_uInt32/sal_Int32 -void BigInt::MakeBigInt( const BigInt& rVal ) +BigInt BigInt::MakeBig() const { - if ( rVal.nLen != 0 ) + if (IsBig()) { - memcpy( static_cast<void*>(this), static_cast<const void*>(&rVal), sizeof( BigInt ) ); - while ( nLen > 1 && nNum[nLen-1] == 0 ) - nLen--; + BigInt ret(*this); + while ( ret.nLen > 1 && ret.nNum[ret.nLen-1] == 0 ) + ret.nLen--; + return ret; + } + + BigInt ret; + if (nVal < 0) + { + ret.bIsNeg = true; + ret.nNum[0] = -static_cast<sal_Int64>(nVal); } else { - nVal = rVal.nVal; - sal_uInt32 nTmp; - if (nVal < 0) - { - bIsNeg = true; - nTmp = -static_cast<sal_Int64>(nVal); - } - else - { - bIsNeg = false; - nTmp = nVal; - } - - nNum[0] = static_cast<sal_uInt16>(nTmp & 0xffffL); - nNum[1] = static_cast<sal_uInt16>(nTmp >> 16); - if ( nTmp & 0xffff0000L ) - nLen = 2; - else - nLen = 1; + ret.bIsNeg = false; + ret.nNum[0] = nVal; } + ret.nLen = 1; + return ret; } void BigInt::Normalize() { - if ( nLen != 0 ) + if (IsBig()) { while ( nLen > 1 && nNum[nLen-1] == 0 ) nLen--; - if ( nLen < 3 ) + if (nLen < 2) { - sal_Int32 newVal; - if ( nLen < 2 ) - newVal = nNum[0]; - else if ( nNum[1] & 0x8000 ) - return; - else - newVal = (static_cast<sal_Int32>(nNum[1]) << 16) + nNum[0]; - - nLen = 0; - nVal = newVal; - - if ( bIsNeg ) - nVal = -nVal; + constexpr sal_uInt32 maxForPosInt32 = std::numeric_limits<sal_Int32>::max(); + constexpr sal_uInt32 maxForNegInt32 = -sal_Int64(std::numeric_limits<sal_Int32>::min()); + sal_uInt32 nNum0 = nNum[0]; + if (bIsNeg && nNum0 <= maxForNegInt32) + { + nVal = -sal_Int64(nNum0); + nLen = 0; + } + else if (!bIsNeg && nNum0 <= maxForPosInt32) + { + nVal = nNum0; + nLen = 0; + } } - // else nVal is undefined !!! W.P. } - // why? nVal is undefined ??? W.P. - else if ( nVal & 0xFFFF0000L ) - nLen = 2; - else - nLen = 1; } -void BigInt::Mult( const BigInt &rVal, sal_uInt16 nMul ) +// Normalization in DivLong requires that dividend is multiplied by a number, and the resulting +// value has 1 more 32-bit "digits". 'ret' provides enough room for that. Use of std::span gives +// run-time index checking in debug builds. +static std::span<sal_uInt32> Mult(std::span<const sal_uInt32> aNum, sal_uInt32 nMul, std::span<sal_uInt32> retBuf) { - sal_uInt16 nK = 0; - for ( int i = 0; i < rVal.nLen; i++ ) + assert(retBuf.size() >= aNum.size()); + sal_uInt64 nK = 0; + for (size_t i = 0; i < aNum.size(); i++) { - sal_uInt32 nTmp = static_cast<sal_uInt32>(rVal.nNum[i]) * static_cast<sal_uInt32>(nMul) + nK; - nK = static_cast<sal_uInt16>(nTmp >> 16); - nNum[i] = static_cast<sal_uInt16>(nTmp); + sal_uInt64 nTmp = static_cast<sal_uInt64>(aNum[i]) * nMul + nK; + nK = nTmp >> 32; + retBuf[i] = static_cast<sal_uInt32>(nTmp); } if ( nK ) { - nNum[rVal.nLen] = nK; - nLen = rVal.nLen + 1; + assert(retBuf.size() > aNum.size()); + retBuf[aNum.size()] = nK; + return retBuf.subspan(0, aNum.size() + 1); } - else - nLen = rVal.nLen; - bIsNeg = rVal.bIsNeg; + return retBuf.subspan(0, aNum.size()); } -void BigInt::Div( sal_uInt16 nDiv, sal_uInt16& rRem ) +static size_t DivInPlace(std::span<sal_uInt32> aNum, sal_uInt32 nDiv, sal_uInt32& rRem) { - sal_uInt32 nK = 0; - for ( int i = nLen - 1; i >= 0; i-- ) + assert(aNum.size() > 0); + sal_uInt64 nK = 0; + for (int i = aNum.size() - 1; i >= 0; i--) { - sal_uInt32 nTmp = static_cast<sal_uInt32>(nNum[i]) + (nK << 16); - nNum[i] = static_cast<sal_uInt16>(nTmp / nDiv); + sal_uInt64 nTmp = aNum[i] + (nK << 32); + aNum[i] = nTmp / nDiv; nK = nTmp % nDiv; } - rRem = static_cast<sal_uInt16>(nK); + rRem = nK; - if ( nNum[nLen-1] == 0 ) - nLen -= 1; + if (aNum[aNum.size() - 1] == 0) + return aNum.size() - 1; + + return aNum.size(); } -bool BigInt::IsLess( const BigInt& rVal ) const +bool BigInt::ABS_IsLessBig(const BigInt& rVal) const { + assert(IsBig() && rVal.IsBig()); if ( rVal.nLen < nLen) - return true; - if ( rVal.nLen > nLen ) return false; + if ( rVal.nLen > nLen ) + return true; - int i; - for ( i = nLen - 1; i > 0 && nNum[i] == rVal.nNum[i]; i-- ) - { - } - return rVal.nNum[i] < nNum[i]; + int i = nLen - 1; + while (i > 0 && nNum[i] == rVal.nNum[i]) + --i; + return nNum[i] < rVal.nNum[i]; } -void BigInt::AddLong( BigInt& rB, BigInt& rErg ) +void BigInt::AddBig(BigInt& rB, BigInt& rRes) { + assert(IsBig() && rB.IsBig()); if ( bIsNeg == rB.bIsNeg ) { int i; @@ -176,189 +171,176 @@ void BigInt::AddLong( BigInt& rB, BigInt& rErg ) } // Add numerals, starting from the back - sal_Int32 k; - sal_Int32 nZ = 0; - for (i = 0, k = 0; i < len; i++) { - nZ = static_cast<sal_Int32>(nNum[i]) + static_cast<sal_Int32>(rB.nNum[i]) + k; - if (nZ & 0xff0000L) + sal_Int64 k = 0; + for (i = 0; i < len; i++) { + sal_Int64 nZ = static_cast<sal_Int64>(nNum[i]) + static_cast<sal_Int64>(rB.nNum[i]) + k; + if (nZ > sal_Int64(std::numeric_limits<sal_uInt32>::max())) k = 1; else k = 0; - rErg.nNum[i] = static_cast<sal_uInt16>(nZ & 0xffffL); + rRes.nNum[i] = static_cast<sal_uInt32>(nZ); } // If an overflow occurred, add to solution - if (nZ & 0xff0000L) // or if(k) + if (k) { - rErg.nNum[i] = 1; + assert(i < MAX_DIGITS); + rRes.nNum[i] = 1; len++; } // Set length and sign - rErg.nLen = len; - rErg.bIsNeg = bIsNeg && rB.bIsNeg; + rRes.nLen = len; + rRes.bIsNeg = bIsNeg; } // If one of the values is negative, perform subtraction instead - else if (bIsNeg) - { - bIsNeg = false; - rB.SubLong(*this, rErg); - bIsNeg = true; - } else { - rB.bIsNeg = false; - SubLong(rB, rErg); - rB.bIsNeg = true; + bIsNeg = !bIsNeg; + rB.SubBig(*this, rRes); + bIsNeg = !bIsNeg; } } -void BigInt::SubLong( BigInt& rB, BigInt& rErg ) +void BigInt::SubBig(BigInt& rB, BigInt& rRes) { + assert(IsBig() && rB.IsBig()); if ( bIsNeg == rB.bIsNeg ) { - int i; char len; - sal_Int32 nZ, k; // if length of the two values differ, fill remaining positions // of the smaller value with zeros. if (nLen >= rB.nLen) { len = nLen; - for (i = rB.nLen; i < len; i++) + for (int i = rB.nLen; i < len; i++) rB.nNum[i] = 0; } else { len = rB.nLen; - for (i = nLen; i < len; i++) + for (int i = nLen; i < len; i++) nNum[i] = 0; } - if ( IsLess(rB) ) - { - for (i = 0, k = 0; i < len; i++) - { - nZ = static_cast<sal_Int32>(nNum[i]) - static_cast<sal_Int32>(rB.nNum[i]) + k; - if (nZ < 0) - k = -1; - else - k = 0; - rErg.nNum[i] = static_cast<sal_uInt16>(nZ & 0xffffL); - } - rErg.bIsNeg = bIsNeg; - } - else + const bool bThisIsLess = ABS_IsLessBig(rB); + BigInt& rGreater = bThisIsLess ? rB : *this; + BigInt& rSmaller = bThisIsLess ? *this : rB; + + sal_Int64 k = 0; + for (int i = 0; i < len; i++) { - for (i = 0, k = 0; i < len; i++) - { - nZ = static_cast<sal_Int32>(rB.nNum[i]) - static_cast<sal_Int32>(nNum[i]) + k; - if (nZ < 0) - k = -1; - else - k = 0; - rErg.nNum[i] = static_cast<sal_uInt16>(nZ & 0xffffL); - } - // if a < b, revert sign - rErg.bIsNeg = !bIsNeg; + sal_Int64 nZ = static_cast<sal_Int64>(rGreater.nNum[i]) - static_cast<sal_Int64>(rSmaller.nNum[i]) + k; + if (nZ < 0) + k = -1; + else + k = 0; + rRes.nNum[i] = static_cast<sal_uInt32>(nZ); } - rErg.nLen = len; + + // if a < b, revert sign + rRes.bIsNeg = bThisIsLess ? !bIsNeg : bIsNeg; + rRes.nLen = len; } // If one of the values is negative, perform addition instead - else if (bIsNeg) - { - bIsNeg = false; - AddLong(rB, rErg); - bIsNeg = true; - rErg.bIsNeg = true; - } else { - rB.bIsNeg = false; - AddLong(rB, rErg); - rB.bIsNeg = true; - rErg.bIsNeg = false; + bIsNeg = !bIsNeg; + AddBig(rB, rRes); + bIsNeg = !bIsNeg; + rRes.bIsNeg = bIsNeg; } } -void BigInt::MultLong( const BigInt& rB, BigInt& rErg ) const +void BigInt::MultBig(const BigInt& rB, BigInt& rRes) const { - int i, j; - sal_uInt32 nZ, k; + assert(IsBig() && rB.IsBig()); - rErg.bIsNeg = bIsNeg != rB.bIsNeg; - rErg.nLen = nLen + rB.nLen; + rRes.bIsNeg = bIsNeg != rB.bIsNeg; + rRes.nLen = nLen + rB.nLen; + assert(rRes.nLen <= MAX_DIGITS); - for (i = 0; i < rErg.nLen; i++) - rErg.nNum[i] = 0; + for (int i = 0; i < rRes.nLen; i++) + rRes.nNum[i] = 0; - for (j = 0; j < rB.nLen; j++) + for (int j = 0; j < rB.nLen; j++) { - for (i = 0, k = 0; i < nLen; i++) + sal_uInt64 k = 0; + int i; + for (i = 0; i < nLen; i++) { - nZ = static_cast<sal_uInt32>(nNum[i]) * static_cast<sal_uInt32>(rB.nNum[j]) + - static_cast<sal_uInt32>(rErg.nNum[i + j]) + k; - rErg.nNum[i + j] = static_cast<sal_uInt16>(nZ & 0xffffU); - k = nZ >> 16; + sal_uInt64 nZ = static_cast<sal_uInt64>(nNum[i]) * static_cast<sal_uInt64>(rB.nNum[j]) + + static_cast<sal_uInt64>(rRes.nNum[i + j]) + k; + rRes.nNum[i + j] = static_cast<sal_uInt32>(nZ); + k = nZ >> 32; } - rErg.nNum[i + j] = static_cast<sal_uInt16>(k); + rRes.nNum[i + j] = k; } } -void BigInt::DivLong( const BigInt& rB, BigInt& rErg ) const +void BigInt::DivModBig(const BigInt& rB, BigInt* pDiv, BigInt* pMod) const { - int i, j; - sal_uInt16 nK, nQ, nMult; - sal_uInt16 nLenB = rB.nLen; - sal_uInt16 nLenB1 = rB.nLen - 1; - BigInt aTmpA, aTmpB; + assert(IsBig() && rB.IsBig()); + assert(nLen >= rB.nLen); - nMult = static_cast<sal_uInt16>(0x10000L / (static_cast<sal_Int32>(rB.nNum[nLenB1]) + 1)); + assert(rB.nNum[rB.nLen - 1] != 0); + sal_uInt32 nMult = static_cast<sal_uInt32>(0x100000000 / (static_cast<sal_Int64>(rB.nNum[rB.nLen - 1]) + 1)); - aTmpA.Mult( *this, nMult ); - if ( aTmpA.nLen == nLen ) + sal_uInt32 numBuf[MAX_DIGITS + 1]; // normalized dividend + auto num = Mult({ nNum, nLen }, nMult, numBuf); + if (num.size() == nLen) { - aTmpA.nNum[aTmpA.nLen] = 0; - aTmpA.nLen++; + num = std::span(numBuf, nLen + 1); + num[nLen] = 0; } - aTmpB.Mult( rB, nMult ); + sal_uInt32 denBuf[MAX_DIGITS + 1]; // normalized divisor + const auto den = Mult({ rB.nNum, rB.nLen }, nMult, denBuf); + assert(den.size() == rB.nLen); + const sal_uInt64 nDenMostSig = den[rB.nLen - 1]; + assert(nDenMostSig >= 0x100000000 / 2); + const sal_uInt64 nDen2ndSig = rB.nLen > 1 ? den[rB.nLen - 2] : 0; + + BigInt aTmp; + BigInt& rRes = pDiv ? *pDiv : aTmp; - for (j = aTmpA.nLen - 1; j >= nLenB; j--) + for (size_t j = num.size() - 1; j >= den.size(); j--) { // guess divisor - sal_uInt32 nTmp = ( static_cast<sal_uInt32>(aTmpA.nNum[j]) << 16 ) + aTmpA.nNum[j - 1]; - if (aTmpA.nNum[j] == aTmpB.nNum[nLenB1]) - nQ = 0xFFFF; + assert(num[j] < nDenMostSig || (num[j] == nDenMostSig && num[j - 1] == 0)); + sal_uInt64 nTmp = ( static_cast<sal_uInt64>(num[j]) << 32 ) + num[j - 1]; + sal_uInt32 nQ; + if (num[j] == nDenMostSig) + nQ = 0xFFFFFFFF; else - nQ = static_cast<sal_uInt16>(nTmp / aTmpB.nNum[nLenB1]); + nQ = static_cast<sal_uInt32>(nTmp / nDenMostSig); - if ( (static_cast<sal_uInt32>(aTmpB.nNum[nLenB1 - 1]) * nQ) > - ((nTmp - static_cast<sal_uInt32>(aTmpB.nNum[nLenB1]) * nQ) << 16) + aTmpA.nNum[j - 2]) + if (nDen2ndSig && (nDen2ndSig * nQ) > ((nTmp - nDenMostSig * nQ) << 32) + num[j - 2]) nQ--; // Start division - nK = 0; - for (i = 0; i < nLenB; i++) + sal_uInt32 nK = 0; + size_t i; + for (i = 0; i < den.size(); i++) { - nTmp = static_cast<sal_uInt32>(aTmpA.nNum[j - nLenB + i]) - - (static_cast<sal_uInt32>(aTmpB.nNum[i]) * nQ) + nTmp = static_cast<sal_uInt64>(num[j - den.size() + i]) + - (static_cast<sal_uInt64>(den[i]) * nQ) - nK; - aTmpA.nNum[j - nLenB + i] = static_cast<sal_uInt16>(nTmp); - nK = static_cast<sal_uInt16>(nTmp >> 16); + num[j - den.size() + i] = static_cast<sal_uInt32>(nTmp); + nK = static_cast<sal_uInt32>(nTmp >> 32); if ( nK ) - nK = static_cast<sal_uInt16>(0x10000U - nK); + nK = static_cast<sal_uInt32>(0x100000000 - nK); } - sal_uInt16& rNum( aTmpA.nNum[j - nLenB + i] ); + sal_uInt32& rNum(num[j - den.size() + i]); rNum -= nK; - if (aTmpA.nNum[j - nLenB + i] == 0) - rErg.nNum[j - nLenB] = nQ; + if (num[j - den.size() + i] == 0) + rRes.nNum[j - den.size()] = nQ; else { - rErg.nNum[j - nLenB] = nQ - 1; + rRes.nNum[j - den.size()] = nQ - 1; nK = 0; - for (i = 0; i < nLenB; i++) + for (i = 0; i < den.size(); i++) { - nTmp = aTmpA.nNum[j - nLenB + i] + aTmpB.nNum[i] + nK; - aTmpA.nNum[j - nLenB + i] = static_cast<sal_uInt16>(nTmp & 0xFFFFL); - if (nTmp & 0xFFFF0000L) + nTmp = num[j - den.size() + i] + den[i] + nK; + num[j - den.size() + i] = static_cast<sal_uInt32>(nTmp & 0xFFFFFFFF); + if (nTmp > std::numeric_limits<sal_uInt32>::max()) nK = 1; else nK = 0; @@ -366,135 +348,47 @@ void BigInt::DivLong( const BigInt& rB, BigInt& rErg ) const } } - rErg.bIsNeg = bIsNeg != rB.bIsNeg; - rErg.nLen = nLen - rB.nLen + 1; -} - -void BigInt::ModLong( const BigInt& rB, BigInt& rErg ) const -{ - sal_uInt16 i, j; - sal_uInt16 nK, nQ, nMult; - sal_Int16 nLenB = rB.nLen; - sal_Int16 nLenB1 = rB.nLen - 1; - BigInt aTmpA, aTmpB; - - nMult = static_cast<sal_uInt16>(0x10000L / (static_cast<sal_Int32>(rB.nNum[nLenB1]) + 1)); - - aTmpA.Mult( *this, nMult); - if ( aTmpA.nLen == nLen ) + if (pMod) { - aTmpA.nNum[aTmpA.nLen] = 0; - aTmpA.nLen++; - } - - aTmpB.Mult( rB, nMult); - - for (j = aTmpA.nLen - 1; j >= nLenB; j--) - { // Guess divisor - sal_uInt32 nTmp = ( static_cast<sal_uInt32>(aTmpA.nNum[j]) << 16 ) + aTmpA.nNum[j - 1]; - if (aTmpA.nNum[j] == aTmpB.nNum[nLenB1]) - nQ = 0xFFFF; - else - nQ = static_cast<sal_uInt16>(nTmp / aTmpB.nNum[nLenB1]); - - if ( (static_cast<sal_uInt32>(aTmpB.nNum[nLenB1 - 1]) * nQ) > - ((nTmp - aTmpB.nNum[nLenB1] * nQ) << 16) + aTmpA.nNum[j - 2]) - nQ--; - // Start division - nK = 0; - for (i = 0; i < nLenB; i++) - { - nTmp = static_cast<sal_uInt32>(aTmpA.nNum[j - nLenB + i]) - - (static_cast<sal_uInt32>(aTmpB.nNum[i]) * nQ) - - nK; - aTmpA.nNum[j - nLenB + i] = static_cast<sal_uInt16>(nTmp); - nK = static_cast<sal_uInt16>(nTmp >> 16); - if ( nK ) - nK = static_cast<sal_uInt16>(0x10000U - nK); - } - sal_uInt16& rNum( aTmpA.nNum[j - nLenB + i] ); - rNum = rNum - nK; - if (aTmpA.nNum[j - nLenB + i] == 0) - rErg.nNum[j - nLenB] = nQ; - else - { - rErg.nNum[j - nLenB] = nQ - 1; - nK = 0; - for (i = 0; i < nLenB; i++) { - nTmp = aTmpA.nNum[j - nLenB + i] + aTmpB.nNum[i] + nK; - aTmpA.nNum[j - nLenB + i] = static_cast<sal_uInt16>(nTmp & 0xFFFFL); - if (nTmp & 0xFFFF0000L) - nK = 1; - else - nK = 0; - } - } + pMod->nLen = DivInPlace(num, nMult, nMult); + assert(pMod->nLen <= MAX_DIGITS); + pMod->bIsNeg = bIsNeg; + std::copy_n(num.begin(), pMod->nLen, pMod->nNum); + pMod->Normalize(); } - - rErg = aTmpA; - rErg.Div( nMult, nQ ); -} - -bool BigInt::ABS_IsLess( const BigInt& rB ) const -{ - if (nLen != 0 || rB.nLen != 0) + if (pDiv) // rRes references pDiv { - BigInt nA, nB; - nA.MakeBigInt( *this ); - nB.MakeBigInt( rB ); - if (nA.nLen == nB.nLen) - { - int i; - for (i = nA.nLen - 1; i > 0 && nA.nNum[i] == nB.nNum[i]; i--) - { - } - return nA.nNum[i] < nB.nNum[i]; - } - else - return nA.nLen < nB.nLen; + pDiv->bIsNeg = bIsNeg != rB.bIsNeg; + pDiv->nLen = nLen - rB.nLen + 1; + pDiv->Normalize(); } - if ( nVal < 0 ) - if ( rB.nVal < 0 ) - return nVal > rB.nVal; - else - return nVal > -rB.nVal; - else - if ( rB.nVal < 0 ) - return nVal < -rB.nVal; - else - return nVal < rB.nVal; -} - -BigInt::BigInt( const BigInt& rBigInt ) - : nLen(0) - , bIsNeg(false) -{ - if ( rBigInt.nLen != 0 ) - memcpy( static_cast<void*>(this), static_cast<const void*>(&rBigInt), sizeof( BigInt ) ); - else - nVal = rBigInt.nVal; } -BigInt::BigInt( const OUString& rString ) +BigInt::BigInt( std::u16string_view rString ) : nLen(0) { bIsNeg = false; nVal = 0; bool bNeg = false; - const sal_Unicode* p = rString.getStr(); + auto p = rString.begin(); + auto pEnd = rString.end(); + if (p == pEnd) + return; if ( *p == '-' ) { bNeg = true; p++; } - while( *p >= '0' && *p <= '9' ) + if (p == pEnd) + return; + while( p != pEnd && *p >= '0' && *p <= '9' ) { *this *= 10; *this += *p - '0'; p++; } - if ( nLen != 0 ) + if (IsBig()) bIsNeg = bNeg; else if( bNeg ) nVal = -nVal; @@ -522,36 +416,34 @@ BigInt::BigInt( double nValue ) { int i=0; - while ( ( nValue > 65536.0 ) && ( i < MAX_DIGITS ) ) + while ( ( nValue > 0x100000000 ) && ( i < MAX_DIGITS ) ) { - nNum[i] = static_cast<sal_uInt16>(fmod( nValue, 65536.0 )); + nNum[i] = static_cast<sal_uInt32>(fmod( nValue, 0x100000000 )); nValue -= nNum[i]; - nValue /= 65536.0; + nValue /= 0x100000000; i++; } if ( i < MAX_DIGITS ) - nNum[i++] = static_cast<sal_uInt16>(nValue); + nNum[i++] = static_cast<sal_uInt32>(nValue); nLen = i; - if ( i < 3 ) + if ( i < 2 ) Normalize(); } } BigInt::BigInt( sal_uInt32 nValue ) : nVal(0) + , bIsNeg(false) { if ( nValue & 0x80000000U ) { - bIsNeg = false; - nNum[0] = static_cast<sal_uInt16>(nValue & 0xffffU); - nNum[1] = static_cast<sal_uInt16>(nValue >> 16); - nLen = 2; + nNum[0] = nValue; + nLen = 1; } else { - bIsNeg = false; nVal = nValue; nLen = 0; } @@ -569,30 +461,25 @@ BigInt::BigInt( sal_Int64 nValue ) } else { - sal_uInt64 nUValue = static_cast<sal_uInt64>(bIsNeg ? -nValue : nValue); - for (int i = 0; (i != sizeof(sal_uInt64) / 2) && (nUValue != 0); ++i) - { - nNum[i] = static_cast<sal_uInt16>(nUValue & 0xffffUL); - nUValue = nUValue >> 16; - ++nLen; - } + for (sal_uInt64 n = static_cast<sal_uInt64>(bIsNeg ? -nValue : nValue); n != 0; n >>= 32) + nNum[nLen++] = static_cast<sal_uInt32>(n); } } BigInt::operator double() const { - if ( nLen == 0 ) + if (!IsBig()) return static_cast<double>(nVal); else { int i = nLen-1; - double nRet = static_cast<double>(static_cast<sal_uInt32>(nNum[i])); + double nRet = static_cast<double>(nNum[i]); while ( i ) { - nRet *= 65536.0; + nRet *= 0x100000000; i--; - nRet += static_cast<double>(static_cast<sal_uInt32>(nNum[i])); + nRet += static_cast<double>(nNum[i]); } if ( bIsNeg ) @@ -607,7 +494,7 @@ BigInt& BigInt::operator=( const BigInt& rBigInt ) if (this == &rBigInt) return *this; - if ( rBigInt.nLen != 0 ) + if (rBigInt.IsBig()) memcpy( static_cast<void*>(this), static_cast<const void*>(&rBigInt), sizeof( BigInt ) ); else { @@ -619,7 +506,7 @@ BigInt& BigInt::operator=( const BigInt& rBigInt ) BigInt& BigInt::operator+=( const BigInt& rVal ) { - if ( nLen == 0 && rVal.nLen == 0 ) + if (!IsBig() && !rVal.IsBig()) { if( nVal <= MY_MAXLONG && rVal.nVal <= MY_MAXLONG && nVal >= MY_MINLONG && rVal.nVal >= MY_MINLONG ) @@ -635,17 +522,15 @@ BigInt& BigInt::operator+=( const BigInt& rVal ) } } - BigInt aTmp1, aTmp2; - aTmp1.MakeBigInt( *this ); - aTmp2.MakeBigInt( rVal ); - aTmp1.AddLong( aTmp2, *this ); + BigInt aTmp2 = rVal.MakeBig(); + MakeBig().AddBig(aTmp2, *this); Normalize(); return *this; } BigInt& BigInt::operator-=( const BigInt& rVal ) { - if ( nLen == 0 && rVal.nLen == 0 ) + if (!IsBig() && !rVal.IsBig()) { if ( nVal <= MY_MAXLONG && rVal.nVal <= MY_MAXLONG && nVal >= MY_MINLONG && rVal.nVal >= MY_MINLONG ) @@ -661,10 +546,8 @@ BigInt& BigInt::operator-=( const BigInt& rVal ) } } - BigInt aTmp1, aTmp2; - aTmp1.MakeBigInt( *this ); - aTmp2.MakeBigInt( rVal ); - aTmp1.SubLong( aTmp2, *this ); + BigInt aTmp2 = rVal.MakeBig(); + MakeBig().SubBig(aTmp2, *this); Normalize(); return *this; } @@ -674,7 +557,7 @@ BigInt& BigInt::operator*=( const BigInt& rVal ) static const sal_Int32 MY_MAXSHORT = 0x00007fff; static const sal_Int32 MY_MINSHORT = -MY_MAXSHORT; - if ( nLen == 0 && rVal.nLen == 0 + if (!IsBig() && !rVal.IsBig() && nVal <= MY_MAXSHORT && rVal.nVal <= MY_MAXSHORT && nVal >= MY_MINSHORT && rVal.nVal >= MY_MINSHORT ) // TODO: not optimal !!! W.P. @@ -683,149 +566,147 @@ BigInt& BigInt::operator*=( const BigInt& rVal ) } else { - BigInt aTmp1, aTmp2; - aTmp1.MakeBigInt( rVal ); - aTmp2.MakeBigInt( *this ); - aTmp1.MultLong(aTmp2, *this); + rVal.MakeBig().MultBig(MakeBig(), *this); Normalize(); } return *this; } -BigInt& BigInt::operator/=( const BigInt& rVal ) +void BigInt::DivMod(const BigInt& rVal, BigInt* pDiv, BigInt* pMod) const { - if ( rVal.nLen == 0 ) + assert(pDiv || pMod); // Avoid useless calls + if (!rVal.IsBig()) { if ( rVal.nVal == 0 ) { OSL_FAIL( "BigInt::operator/ --> divide by zero" ); - return *this; + return; } - if ( nLen == 0 ) + if (rVal.nVal == 1) { - // No overflows may occur here - nVal /= rVal.nVal; - return *this; + if (pDiv) + { + *pDiv = *this; + pDiv->Normalize(); + } + if (pMod) + *pMod = 0; + return; } - if ( rVal.nVal == 1 ) - return *this; - - if ( rVal.nVal == -1 ) + if (!IsBig()) { - bIsNeg = !bIsNeg; - return *this; + // No overflows may occur here + const sal_Int32 nDiv = nVal / rVal.nVal; // Compilers usually optimize adjacent + const sal_Int32 nMod = nVal % rVal.nVal; // / and % into a single instruction + if (pDiv) + *pDiv = nDiv; + if (pMod) + *pMod = nMod; + return; } - if ( rVal.nVal <= 0xFFFF && rVal.nVal >= -0xFFFF ) + if ( rVal.nVal == -1 ) { - // Divide BigInt with an sal_uInt16 - sal_uInt16 nTmp; - if ( rVal.nVal < 0 ) + if (pDiv) { - nTmp = static_cast<sal_uInt16>(-rVal.nVal); - bIsNeg = !bIsNeg; + *pDiv = *this; + pDiv->bIsNeg = !bIsNeg; + pDiv->Normalize(); } - else - nTmp = static_cast<sal_uInt16>(rVal.nVal); - - Div( nTmp, nTmp ); - Normalize(); - return *this; + if (pMod) + *pMod = 0; + return; } - } - - if ( ABS_IsLess( rVal ) ) - { - *this = BigInt( 0 ); - return *this; - } - - // Divide BigInt with BigInt - BigInt aTmp1, aTmp2; - aTmp1.MakeBigInt( *this ); - aTmp2.MakeBigInt( rVal ); - aTmp1.DivLong(aTmp2, *this); - Normalize(); - return *this; -} -BigInt& BigInt::operator%=( const BigInt& rVal ) -{ - if ( rVal.nLen == 0 ) - { - if ( rVal.nVal == 0 ) + // Divide BigInt with an sal_uInt32 + sal_uInt32 nTmp; + bool bNegate; + if ( rVal.nVal < 0 ) { - OSL_FAIL( "BigInt::operator/ --> divide by zero" ); - return *this; + nTmp = static_cast<sal_uInt32>(-rVal.nVal); + bNegate = true; } - - if ( nLen == 0 ) + else { - // No overflows may occur here - nVal %= rVal.nVal; - return *this; + nTmp = static_cast<sal_uInt32>(rVal.nVal); + bNegate = false; } - if ( rVal.nVal <= 0xFFFF && rVal.nVal >= -0xFFFF ) + BigInt aTmp; + BigInt& rDiv = pDiv ? *pDiv : aTmp; + rDiv = *this; + rDiv.nLen = DivInPlace({ rDiv.nNum, rDiv.nLen }, nTmp, nTmp); + if (pDiv) { - // Divide Bigint by int16 - sal_uInt16 nTmp; - if ( rVal.nVal < 0 ) - { - nTmp = static_cast<sal_uInt16>(-rVal.nVal); - bIsNeg = !bIsNeg; - } - else - nTmp = static_cast<sal_uInt16>(rVal.nVal); - - Div( nTmp, nTmp ); - *this = BigInt( nTmp ); - return *this; + if (bNegate) + pDiv->bIsNeg = !pDiv->bIsNeg; + pDiv->Normalize(); + } + if (pMod) + { + *pMod = BigInt(nTmp); } + return; } - if ( ABS_IsLess( rVal ) ) - return *this; + BigInt tmpA = MakeBig(), tmpB = rVal.MakeBig(); + if (tmpA.ABS_IsLessBig(tmpB)) + { + // First store *this to *pMod, then nullify *pDiv, to handle 'pDiv == this' case + if (pMod) + { + *pMod = *this; + pMod->Normalize(); + } + if (pDiv) + *pDiv = 0; + return; + } // Divide BigInt with BigInt - BigInt aTmp1, aTmp2; - aTmp1.MakeBigInt( *this ); - aTmp2.MakeBigInt( rVal ); - aTmp1.ModLong(aTmp2, *this); - Normalize(); + tmpA.DivModBig(tmpB, pDiv, pMod); +} + +BigInt& BigInt::operator/=( const BigInt& rVal ) +{ + DivMod(rVal, this, nullptr); + return *this; +} + +BigInt& BigInt::operator%=( const BigInt& rVal ) +{ + DivMod(rVal, nullptr, this); return *this; } bool operator==( const BigInt& rVal1, const BigInt& rVal2 ) { - if (rVal1.nLen == 0 && rVal2.nLen == 0) + if (!rVal1.IsBig() && !rVal2.IsBig()) return rVal1.nVal == rVal2.nVal; - BigInt nA, nB; - nA.MakeBigInt(rVal1); - nB.MakeBigInt(rVal2); + BigInt nA = rVal1.MakeBig(), nB = rVal2.MakeBig(); return nA.bIsNeg == nB.bIsNeg && nA.nLen == nB.nLen && std::equal(nA.nNum, nA.nNum + nA.nLen, nB.nNum); } -bool operator<( const BigInt& rVal1, const BigInt& rVal2 ) +std::strong_ordering operator<=>(const BigInt& rVal1, const BigInt& rVal2) { - if (rVal1.nLen == 0 && rVal2.nLen == 0) - return rVal1.nVal < rVal2.nVal; + if (!rVal1.IsBig() && !rVal2.IsBig()) + return rVal1.nVal <=> rVal2.nVal; - BigInt nA, nB; - nA.MakeBigInt(rVal1); - nB.MakeBigInt(rVal2); + BigInt nA = rVal1.MakeBig(), nB = rVal2.MakeBig(); if (nA.bIsNeg != nB.bIsNeg) - return !nB.bIsNeg; - if (nA.nLen != nB.nLen) - return nA.bIsNeg ? (nA.nLen > nB.nLen) : (nA.nLen < nB.nLen); + return nB.bIsNeg ? std::strong_ordering::less : std::strong_ordering::greater; + if (nA.nLen < nB.nLen) + return nB.bIsNeg ? std::strong_ordering::greater : std::strong_ordering::less; + if (nA.nLen > nB.nLen) + return nB.bIsNeg ? std::strong_ordering::less : std::strong_ordering::greater; int i = nA.nLen - 1; while (i > 0 && nA.nNum[i] == nB.nNum[i]) --i; - return nA.bIsNeg ? (nA.nNum[i] > nB.nNum[i]) : (nA.nNum[i] < nB.nNum[i]); + return nB.bIsNeg ? (nB.nNum[i] <=> nA.nNum[i]) : (nA.nNum[i] <=> nB.nNum[i]); } tools::Long BigInt::Scale( tools::Long nVal, tools::Long nMul, tools::Long nDiv ) diff --git a/tools/source/generic/color.cxx b/tools/source/generic/color.cxx index 5df32719eb2c..208a6caee883 100644 --- a/tools/source/generic/color.cxx +++ b/tools/source/generic/color.cxx @@ -27,7 +27,9 @@ #include <tools/color.hxx> #include <tools/helpers.hxx> #include <tools/long.hxx> +#include <o3tl/string_view.hxx> #include <basegfx/color/bcolortools.hxx> +#include <basegfx/numeric/ftools.hxx> void Color::IncreaseLuminance(sal_uInt8 cLumInc) { @@ -50,9 +52,9 @@ void Color::DecreaseContrast(sal_uInt8 nContDec) const double fM = (128.0 - 0.4985 * nContDec) / 128.0; const double fOff = 128.0 - fM * 128.0; - R = sal_uInt8(std::clamp(FRound(R * fM + fOff), tools::Long(0), tools::Long(255))); - G = sal_uInt8(std::clamp(FRound(G * fM + fOff), tools::Long(0), tools::Long(255))); - B = sal_uInt8(std::clamp(FRound(B * fM + fOff), tools::Long(0), tools::Long(255))); + R = basegfx::fround<sal_uInt8>(R * fM + fOff); + G = basegfx::fround<sal_uInt8>(G * fM + fOff); + B = basegfx::fround<sal_uInt8>(B * fM + fOff); } } @@ -158,30 +160,30 @@ Color Color::HSBtoRGB( sal_uInt16 nHue, sal_uInt16 nSat, sal_uInt16 nBri ) return Color( cR, cG, cB ); } -Color Color::STRtoRGB(const OUString& colorname) +Color Color::STRtoRGB(std::u16string_view colorname) { Color col; - if(colorname.isEmpty()) return col; + if(colorname.empty()) return col; - switch(colorname.getLength()){ + switch(colorname.size()){ case 7: - col.mValue = colorname.copy(1,6).toUInt32(16); + col.mValue = o3tl::toUInt32(colorname.substr(1,6), 16); break; case 6: - col.mValue = colorname.toUInt32(16); + col.mValue = o3tl::toUInt32(colorname, 16); break; case 4: { sal_Unicode data[6] = { colorname[1], colorname[1], colorname[2], colorname[2], colorname[3], colorname[3] }; - col.mValue = OUString(data,6).toUInt32(16); + col.mValue = o3tl::toUInt32(std::u16string_view(data,6), 16); break; } case 3: { sal_Unicode data[6] = { colorname[0], colorname[0], colorname[1], colorname[1], colorname[2], colorname[2] }; - col.mValue = OUString(data,6).toUInt32(16); + col.mValue = o3tl::toUInt32(std::u16string_view(data,6), 16); break; } default: @@ -194,14 +196,14 @@ OUString Color::AsRGBHexString() const { std::stringstream ss; ss << std::hex << std::setfill ('0') << std::setw(6) << sal_uInt32(GetRGBColor()); - return OUString::createFromAscii(ss.str().c_str()); + return OUString::createFromAscii(ss.str()); } OUString Color::AsRGBHEXString() const { std::stringstream ss; ss << std::hex << std::uppercase << std::setfill ('0') << std::setw(6) << sal_uInt32(GetRGBColor()); - return OUString::createFromAscii(ss.str().c_str()); + return OUString::createFromAscii(ss.str()); } void Color::ApplyTintOrShade(sal_Int16 n100thPercent) diff --git a/tools/source/generic/config.cxx b/tools/source/generic/config.cxx index b2eb546c0ef7..cc5cce9c3b16 100644 --- a/tools/source/generic/config.cxx +++ b/tools/source/generic/config.cxx @@ -205,7 +205,6 @@ static void ImplMakeConfigList( ImplConfigData* pData, sal_uInt64 i; const sal_uInt8* pLine; ImplKeyData* pPrevKey = nullptr; - ImplKeyData* pKey; ImplGroupData* pPrevGroup = nullptr; ImplGroupData* pGroup = nullptr; i = 0; @@ -250,7 +249,6 @@ static void ImplMakeConfigList( ImplConfigData* pData, pData->mpFirstGroup = pGroup; pPrevGroup = pGroup; pPrevKey = nullptr; - pKey = nullptr; // filter group names pLine++; @@ -292,7 +290,7 @@ static void ImplMakeConfigList( ImplConfigData* pData, { while ( pGroup->mnEmptyLines ) { - pKey = new ImplKeyData; + ImplKeyData* pKey = new ImplKeyData; pKey->mbIsComment = true; pPrevKey->mpNext = pKey; pPrevKey = pKey; @@ -301,7 +299,7 @@ static void ImplMakeConfigList( ImplConfigData* pData, } // Generate new key - pKey = new ImplKeyData; + ImplKeyData* pKey = new ImplKeyData; pKey->mpNext = nullptr; if ( pPrevKey ) pPrevKey->mpNext = pKey; diff --git a/tools/source/generic/fract.cxx b/tools/source/generic/fract.cxx index 93a92fb3a12a..7dfddf50a880 100644 --- a/tools/source/generic/fract.cxx +++ b/tools/source/generic/fract.cxx @@ -19,24 +19,22 @@ #include <tools/fract.hxx> #include <tools/debug.hxx> -#include <tools/stream.hxx> +#include <o3tl/hash_combine.hxx> #include <o3tl/safeint.hxx> #include <sal/log.hxx> #include <osl/diagnose.h> #include <algorithm> +#include <bit> #include <cmath> #include <numeric> #include <boost/rational.hpp> -#ifdef _MSC_VER -#include <intrin.h> -#endif - static boost::rational<sal_Int32> rational_FromDouble(double dVal); static void rational_ReduceInaccurate(boost::rational<sal_Int32>& rRational, unsigned nSignificantBits); -static int impl_NumberOfBits( sal_uInt32 nNum ); +// Find the number of bits required to represent this number +static int impl_NumberOfBits(sal_uInt32 nNum) { return 32 - std::countl_zero(nNum); } static boost::rational<sal_Int32> toRational(sal_Int32 n, sal_Int32 d) { @@ -49,24 +47,40 @@ static boost::rational<sal_Int32> toRational(sal_Int32 n, sal_Int32 d) return boost::rational<sal_Int32>(n, d); } -// Initialized by setting nNum as nominator and nDen as denominator -// Negative values in the denominator are invalid and cause the -// inversion of both nominator and denominator signs -// in order to return the correct value. +static constexpr bool isOutOfRange(sal_Int64 nNum) +{ + return nNum < std::numeric_limits<sal_Int32>::min() + || nNum > std::numeric_limits<sal_Int32>::max(); +} + Fraction::Fraction( sal_Int64 nNum, sal_Int64 nDen ) : mnNumerator(nNum), mnDenominator(nDen) { - assert( nNum >= std::numeric_limits<sal_Int32>::min() ); - assert( nNum <= std::numeric_limits<sal_Int32>::max( )); - assert( nDen >= std::numeric_limits<sal_Int32>::min() ); - assert( nDen <= std::numeric_limits<sal_Int32>::max( )); - if ( nDen == 0 ) + if ( isOutOfRange(nNum) || isOutOfRange(nDen) ) + { + // tdf#143200 + if (const auto gcd = std::gcd(nNum, nDen); gcd > 1) + { + nNum /= gcd; + nDen /= gcd; + } + SAL_WARN_IF(isOutOfRange(nNum) || isOutOfRange(nDen), + "tools.fraction", "values outside of range we can represent, doing reduction, which will reduce precision"); + while (isOutOfRange(nNum) || isOutOfRange(nDen)) + { + nNum /= 2; + nDen /= 2; + } + mnNumerator = nNum; + mnDenominator = nDen; + } + if ( mnDenominator == 0 ) { mbValid = false; SAL_WARN( "tools.fraction", "'Fraction(" << nNum << ",0)' invalid fraction created" ); return; } - if ((nDen == -1 && nNum == std::numeric_limits<sal_Int32>::min()) || - (nNum == -1 && nDen == std::numeric_limits<sal_Int32>::min())) + else if ((nDen == -1 && nNum == std::numeric_limits<sal_Int32>::min()) || + (nNum == -1 && nDen == std::numeric_limits<sal_Int32>::min())) { mbValid = false; SAL_WARN("tools.fraction", "'Fraction(" << nNum << "," << nDen << ")' invalid fraction created"); @@ -77,21 +91,9 @@ Fraction::Fraction( sal_Int64 nNum, sal_Int64 nDen ) : mnNumerator(nNum), mnDeno /** * only here to prevent passing of NaN */ -Fraction::Fraction( double nNum, double nDen ) : mnNumerator(sal_Int64(nNum)), mnDenominator(sal_Int64(nDen)) -{ - assert( !std::isnan(nNum) ); - assert( !std::isnan(nDen) ); - assert( nNum >= std::numeric_limits<sal_Int32>::min() ); - assert( nNum <= std::numeric_limits<sal_Int32>::max( )); - assert( nDen >= std::numeric_limits<sal_Int32>::min() ); - assert( nDen <= std::numeric_limits<sal_Int32>::max( )); - if ( nDen == 0 ) - { - mbValid = false; - SAL_WARN( "tools.fraction", "'Fraction(" << nNum << ",0)' invalid fraction created" ); - return; - } -} +Fraction::Fraction( double nNum, double nDen ) + : Fraction(sal_Int64(nNum), sal_Int64(nDen)) +{} Fraction::Fraction( double dVal ) { @@ -182,6 +184,9 @@ namespace sal_Int32 gcd1 = std::gcd(i.numerator(), den); sal_Int32 gcd2 = std::gcd(num, i.denominator()); + if (!gcd1 || !gcd2) + return true; + bool fail = false; fail |= o3tl::checked_multiply(i.numerator() / gcd1, num / gcd2, num); fail |= o3tl::checked_multiply(i.denominator() / gcd2, den / gcd1, den); @@ -399,22 +404,6 @@ static boost::rational<sal_Int32> rational_FromDouble(double dVal) return boost::rational<sal_Int32>( sal_Int32(dVal), nDen ); } -/** - * Find the number of bits required to represent this number, using the CLZ intrinsic - */ -static int impl_NumberOfBits( sal_uInt32 nNum ) -{ - if (nNum == 0) - return 0; -#ifdef _MSC_VER - unsigned long r = 0; - _BitScanReverse(&r, nNum); - return r + 1; -#else - return 32 - __builtin_clz(nNum); -#endif -} - /** Inaccurate cancellation for a fraction. Clip both nominator and denominator to said number of bits. If @@ -471,4 +460,60 @@ static void rational_ReduceInaccurate(boost::rational<sal_Int32>& rRational, uns rRational.assign( bNeg ? -nMul : nMul, nDiv ); } +size_t Fraction::GetHashValue() const +{ + size_t hash = 0; + o3tl::hash_combine( hash, mnNumerator ); + o3tl::hash_combine( hash, mnDenominator ); + o3tl::hash_combine( hash, mbValid ); + return hash; +} + +Fraction Fraction::MakeFraction( tools::Long nN1, tools::Long nN2, tools::Long nD1, tools::Long nD2 ) +{ + if( nD1 == 0 || nD2 == 0 ) //under these bad circumstances the following while loop will be endless + { + SAL_WARN("tools.fraction", "Invalid parameter for ImplMakeFraction"); + return Fraction( 1, 1 ); + } + + tools::Long i = 1; + + if ( nN1 < 0 ) { i = -i; nN1 = -nN1; } + if ( nN2 < 0 ) { i = -i; nN2 = -nN2; } + if ( nD1 < 0 ) { i = -i; nD1 = -nD1; } + if ( nD2 < 0 ) { i = -i; nD2 = -nD2; } + // all positive; i sign + + assert( nN1 >= std::numeric_limits<sal_Int32>::min() ); + assert( nN1 <= std::numeric_limits<sal_Int32>::max( )); + assert( nD1 >= std::numeric_limits<sal_Int32>::min() ); + assert( nD1 <= std::numeric_limits<sal_Int32>::max( )); + assert( nN2 >= std::numeric_limits<sal_Int32>::min() ); + assert( nN2 <= std::numeric_limits<sal_Int32>::max( )); + assert( nD2 >= std::numeric_limits<sal_Int32>::min() ); + assert( nD2 <= std::numeric_limits<sal_Int32>::max( )); + + boost::rational<sal_Int32> a = toRational(i*nN1, nD1); + boost::rational<sal_Int32> b = toRational(nN2, nD2); + bool bFail = checked_multiply_by(a, b); + + while ( bFail ) { + if ( nN1 > nN2 ) + nN1 = (nN1 + 1) / 2; + else + nN2 = (nN2 + 1) / 2; + if ( nD1 > nD2 ) + nD1 = (nD1 + 1) / 2; + else + nD2 = (nD2 + 1) / 2; + + a = toRational(i*nN1, nD1); + b = toRational(nN2, nD2); + bFail = checked_multiply_by(a, b); + } + + return Fraction(a.numerator(), a.denominator()); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/generic/gen.cxx b/tools/source/generic/gen.cxx index 1fe47071d4ce..012318c0218d 100644 --- a/tools/source/generic/gen.cxx +++ b/tools/source/generic/gen.cxx @@ -18,14 +18,13 @@ */ #include <sal/config.h> -#include <sal/log.hxx> +#include <rtl/string.hxx> #include <algorithm> -#include <cassert> -#include <sstream> +#include <tuple> +#include <o3tl/hash_combine.hxx> #include <o3tl/safeint.hxx> #include <tools/gen.hxx> -#include <tools/stream.hxx> OString Pair::toString() const { @@ -35,159 +34,152 @@ OString Pair::toString() const return OString::number(A()) + ", " + OString::number(B()); } -void tools::Rectangle::SetSize( const Size& rSize ) +size_t Pair::GetHashValue() const { - if ( rSize.Width() < 0 ) - nRight = nLeft + rSize.Width() +1; - else if ( rSize.Width() > 0 ) - nRight = nLeft + rSize.Width() -1; - else - SetWidthEmpty(); - - if ( rSize.Height() < 0 ) - nBottom = nTop + rSize.Height() +1; - else if ( rSize.Height() > 0 ) - nBottom = nTop + rSize.Height() -1; - else - SetHeightEmpty(); + size_t hash = 0; + o3tl::hash_combine( hash, mnA ); + o3tl::hash_combine( hash, mnB ); + return hash; } -void tools::Rectangle::SaturatingSetSize(const Size& rSize) +void RectangleTemplateBase::SaturatingSetSize(const SizeTemplateBase& rSize) { if (rSize.Width() < 0) - nRight = o3tl::saturating_add(nLeft, (rSize.Width() + 1)); + mnRight = o3tl::saturating_add(mnLeft, (rSize.Width() + 1)); else if ( rSize.Width() > 0 ) - nRight = o3tl::saturating_add(nLeft, (rSize.Width() - 1)); + mnRight = o3tl::saturating_add(mnLeft, (rSize.Width() - 1)); else SetWidthEmpty(); if ( rSize.Height() < 0 ) - nBottom = o3tl::saturating_add(nTop, (rSize.Height() + 1)); + mnBottom = o3tl::saturating_add(mnTop, (rSize.Height() + 1)); else if ( rSize.Height() > 0 ) - nBottom = o3tl::saturating_add(nTop, (rSize.Height() - 1)); + mnBottom = o3tl::saturating_add(mnTop, (rSize.Height() - 1)); else SetHeightEmpty(); } -void tools::Rectangle::SaturatingSetPosX(tools::Long x) +void RectangleTemplateBase::SaturatingSetPosX(tools::Long x) { if (!IsWidthEmpty()) - nRight = o3tl::saturating_add(nRight, x - nLeft); - nLeft = x; + mnRight = o3tl::saturating_add(mnRight, x - mnLeft); + mnLeft = x; } -void tools::Rectangle::SaturatingSetPosY(tools::Long y) +void RectangleTemplateBase::SaturatingSetPosY(tools::Long y) { if (!IsHeightEmpty()) - nBottom = o3tl::saturating_add(nBottom, y - nTop); - nTop = y; + mnBottom = o3tl::saturating_add(mnBottom, y - mnTop); + mnTop = y; } -tools::Rectangle& tools::Rectangle::Union( const tools::Rectangle& rRect ) +void RectangleTemplateBase::Union( const RectangleTemplateBase& rRect ) { if ( rRect.IsEmpty() ) - return *this; + return; if ( IsEmpty() ) *this = rRect; else { - std::tie(nLeft, nRight) = std::minmax({ nLeft, rRect.nLeft, nRight, rRect.nRight }); - std::tie(nTop, nBottom) = std::minmax({ nTop, rRect.nTop, nBottom, rRect.nBottom }); + std::tie(mnLeft, mnRight) = std::minmax({ mnLeft, rRect.mnLeft, mnRight, rRect.mnRight }); + std::tie(mnTop, mnBottom) = std::minmax({ mnTop, rRect.mnTop, mnBottom, rRect.mnBottom }); } - - return *this; } -tools::Rectangle& tools::Rectangle::Intersection( const tools::Rectangle& rRect ) +void RectangleTemplateBase::Intersection( const RectangleTemplateBase& rRect ) { if ( IsEmpty() ) - return *this; + return; if ( rRect.IsEmpty() ) { *this = tools::Rectangle(); - return *this; + return; } - // Justify rectangle - tools::Rectangle aTmpRect( rRect ); - Justify(); - aTmpRect.Justify(); + // Normalize rectangle + RectangleTemplateBase aTmpRect( rRect ); + Normalize(); + aTmpRect.Normalize(); // Perform intersection - nLeft = std::max( nLeft, aTmpRect.nLeft ); - nRight = std::min( nRight, aTmpRect.nRight ); - nTop = std::max( nTop, aTmpRect.nTop ); - nBottom= std::min( nBottom, aTmpRect.nBottom ); + mnLeft = std::max( mnLeft, aTmpRect.mnLeft ); + mnRight = std::min( mnRight, aTmpRect.mnRight ); + mnTop = std::max( mnTop, aTmpRect.mnTop ); + mnBottom= std::min( mnBottom, aTmpRect.mnBottom ); // Determine if intersection is empty - if ( nRight < nLeft || nBottom < nTop ) + if ( mnRight < mnLeft || mnBottom < mnTop ) *this = tools::Rectangle(); - - return *this; } -void tools::Rectangle::Justify() +void RectangleTemplateBase::Normalize() { - if ((nRight < nLeft) && (!IsWidthEmpty())) + if ((mnRight < mnLeft) && (!IsWidthEmpty())) { - std::swap(nLeft, nRight); + std::swap(mnLeft, mnRight); } - if ((nBottom < nTop) && (!IsHeightEmpty())) + if ((mnBottom < mnTop) && (!IsHeightEmpty())) { - std::swap(nBottom, nTop); + std::swap(mnBottom, mnTop); } } -bool tools::Rectangle::Contains( const Point& rPoint ) const +bool RectangleTemplateBase::Contains( const PointTemplateBase& rPoint ) const { if ( IsEmpty() ) return false; - if ( nLeft <= nRight ) + if ( mnLeft <= mnRight ) { - if ( (rPoint.X() < nLeft) || (rPoint.X() > nRight) ) + if ( (rPoint.X() < mnLeft) || (rPoint.X() > mnRight) ) return false; } else { - if ( (rPoint.X() > nLeft) || (rPoint.X() < nRight) ) + if ( (rPoint.X() > mnLeft) || (rPoint.X() < mnRight) ) return false; } - if ( nTop <= nBottom ) + if ( mnTop <= mnBottom ) { - if ( (rPoint.Y() < nTop) || (rPoint.Y() > nBottom) ) + if ( (rPoint.Y() < mnTop) || (rPoint.Y() > mnBottom) ) return false; } else { - if ( (rPoint.Y() > nTop) || (rPoint.Y() < nBottom) ) + if ( (rPoint.Y() > mnTop) || (rPoint.Y() < mnBottom) ) return false; } return true; } -bool tools::Rectangle::Contains( const tools::Rectangle& rRect ) const +bool RectangleTemplateBase::Contains( const RectangleTemplateBase& rRect ) const { - return Contains( rRect.TopLeft() ) && Contains( rRect.BottomRight() ); + return Contains( PointTemplateBase{ rRect.Left(), rRect.Top() } ) + && Contains( PointTemplateBase{ rRect.Right(), rRect.Bottom() } ); } -bool tools::Rectangle::Overlaps( const tools::Rectangle& rRect ) const +bool RectangleTemplateBase::Overlaps( const RectangleTemplateBase& rRect ) const { // If there's no intersection, they don't overlap - return !GetIntersection( rRect ).IsEmpty(); + RectangleTemplateBase aTmp(*this); + aTmp.Intersection(rRect); + return !aTmp.IsEmpty(); } -OString tools::Rectangle::toString() const +OString RectangleTemplateBase::toString() const { // Note that this is not just used for debugging output but the // format is parsed by external code (passed in callbacks to // LibreOfficeKit clients). So don't change. - return OString::number(Left()) + ", " + OString::number(Top()) + ", " + OString::number(getWidth()) + ", " + OString::number(getHeight()); + return OString::number(Left()) + ", " + + OString::number(Top()) + ", " + + OString::number(getOpenWidth()) + ", " + + OString::number(getOpenHeight()); } -void tools::Rectangle::expand(tools::Long nExpandBy) +void RectangleTemplateBase::expand(tools::Long nExpandBy) { AdjustLeft(-nExpandBy); AdjustTop(-nExpandBy); @@ -195,32 +187,32 @@ void tools::Rectangle::expand(tools::Long nExpandBy) AdjustBottom(nExpandBy); } -void tools::Rectangle::shrink(tools::Long nShrinkBy) +void RectangleTemplateBase::shrink(tools::Long nShrinkBy) { - nLeft += nShrinkBy; - nTop += nShrinkBy; + mnLeft += nShrinkBy; + mnTop += nShrinkBy; if (!IsWidthEmpty()) - nRight -= nShrinkBy; + mnRight -= nShrinkBy; if (!IsHeightEmpty()) - nBottom -= nShrinkBy; + mnBottom -= nShrinkBy; } -tools::Long tools::Rectangle::AdjustRight(tools::Long nHorzMoveDelta) +tools::Long RectangleTemplateBase::AdjustRight(tools::Long nHorzMoveDelta) { if (IsWidthEmpty()) - nRight = nLeft + nHorzMoveDelta - 1; + mnRight = mnLeft + nHorzMoveDelta - 1; else - nRight += nHorzMoveDelta; - return nRight; + mnRight += nHorzMoveDelta; + return mnRight; } -tools::Long tools::Rectangle::AdjustBottom( tools::Long nVertMoveDelta ) +tools::Long RectangleTemplateBase::AdjustBottom( tools::Long nVertMoveDelta ) { if (IsHeightEmpty()) - nBottom = nTop + nVertMoveDelta - 1; + mnBottom = mnTop + nVertMoveDelta - 1; else - nBottom += nVertMoveDelta; - return nBottom; + mnBottom += nVertMoveDelta; + return mnBottom; } static_assert( std::is_trivially_copyable< Pair >::value ); diff --git a/tools/source/generic/line.cxx b/tools/source/generic/line.cxx index 26465c5c85d6..328ae3e35e66 100644 --- a/tools/source/generic/line.cxx +++ b/tools/source/generic/line.cxx @@ -17,6 +17,9 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <sal/config.h> + +#include <basegfx/numeric/ftools.hxx> #include <tools/line.hxx> #include <tools/helpers.hxx> @@ -37,8 +40,8 @@ bool Line::Intersection( const Line& rLine, Point& rIntersection ) const if( Intersection( rLine, fX, fY ) ) { - rIntersection.setX( FRound( fX ) ); - rIntersection.setY( FRound( fY ) ); + rIntersection.setX(basegfx::fround<tools::Long>(fX)); + rIntersection.setY(basegfx::fround<tools::Long>(fY)); bRet = true; } else @@ -49,17 +52,17 @@ bool Line::Intersection( const Line& rLine, Point& rIntersection ) const bool Line::Intersection( const tools::Line& rLine, double& rIntersectionX, double& rIntersectionY ) const { - const double fAx = maEnd.X() - maStart.X(); - const double fAy = maEnd.Y() - maStart.Y(); - const double fBx = rLine.maStart.X() - rLine.maEnd.X(); - const double fBy = rLine.maStart.Y() - rLine.maEnd.Y(); + const double fAx = static_cast<double>(maEnd.X()) - maStart.X(); + const double fAy = static_cast<double>(maEnd.Y()) - maStart.Y(); + const double fBx = static_cast<double>(rLine.maStart.X()) - rLine.maEnd.X(); + const double fBy = static_cast<double>(rLine.maStart.Y()) - rLine.maEnd.Y(); const double fDen = fAy * fBx - fAx * fBy; bool bOk = false; if( fDen != 0. ) { - const double fCx = maStart.X() - rLine.maStart.X(); - const double fCy = maStart.Y() - rLine.maStart.Y(); + const double fCx = static_cast<double>(maStart.X()) - rLine.maStart.X(); + const double fCy = static_cast<double>(maStart.Y()) - rLine.maStart.Y(); const double fA = fBy * fCx - fBx * fCy; const bool bGreater = ( fDen > 0. ); @@ -104,13 +107,13 @@ double Line::GetDistance( const double& rPtX, const double& rPtY ) const if( maStart != maEnd ) { - const double fDistX = maEnd.X() - maStart.X(); - const double fDistY = maEnd.Y() - maStart.Y(); - const double fACX = maStart.X() - rPtX; - const double fACY = maStart.Y() - rPtY; - const double fL2 = fDistX * fDistX + fDistY * fDistY; - const double fR = ( fACY * -fDistY - fACX * fDistX ) / fL2; - const double fS = ( fACY * fDistX - fACX * fDistY ) / fL2; + const double fDistX = static_cast<double>(maEnd.X()) - maStart.X(); + const double fDistY = static_cast<double>(maEnd.Y()) - maStart.Y(); + const double fACX = static_cast<double>(maStart.X()) - rPtX; + const double fACY = static_cast<double>(maStart.Y()) - rPtY; + const double fL2 = fDistX * fDistX + fDistY * fDistY; + const double fR = ( fACY * -fDistY - fACX * fDistX ) / fL2; + const double fS = ( fACY * fDistX - fACX * fDistY ) / fL2; if( fR < 0.0 ) { diff --git a/tools/source/generic/point.cxx b/tools/source/generic/point.cxx index e9c3bd842a15..e71f60411a86 100644 --- a/tools/source/generic/point.cxx +++ b/tools/source/generic/point.cxx @@ -18,23 +18,22 @@ */ #include <tools/gen.hxx> -#include <basegfx/numeric/ftools.hxx> -void Point::RotateAround( Point& rPoint, +void PointTemplateBase::RotateAround( PointTemplateBase& rPoint, Degree10 nOrientation ) const { - tools::Long nX = rPoint.X(); - tools::Long nY = rPoint.Y(); + tools::Long nX = rPoint.mnA; + tools::Long nY = rPoint.mnB; RotateAround(nX, nY, nOrientation); - rPoint.setX(nX); - rPoint.setY(nY); + rPoint.mnA = nX; + rPoint.mnB = nY; } -void Point::RotateAround( tools::Long& rX, tools::Long& rY, +void PointTemplateBase::RotateAround( tools::Long& rX, tools::Long& rY, Degree10 nOrientation ) const { - const tools::Long nOriginX = X(); - const tools::Long nOriginY = Y(); + const tools::Long nOriginX = mnA; + const tools::Long nOriginY = mnB; if ( (nOrientation >= 0_deg10) && !(nOrientation % 900_deg10) ) { diff --git a/tools/source/generic/poly.cxx b/tools/source/generic/poly.cxx index 13d2df0e47ef..81419f7e70c3 100644 --- a/tools/source/generic/poly.cxx +++ b/tools/source/generic/poly.cxx @@ -38,20 +38,19 @@ #include <memory> #include <vector> -#include <iterator> #include <algorithm> -#include <cstdlib> +#include <cassert> #include <cstring> #include <limits.h> #include <cmath> -#define EDGE_LEFT 1 -#define EDGE_TOP 2 -#define EDGE_RIGHT 4 -#define EDGE_BOTTOM 8 -#define EDGE_HORZ (EDGE_RIGHT | EDGE_LEFT) -#define EDGE_VERT (EDGE_TOP | EDGE_BOTTOM) -#define SMALL_DVALUE 0.0000001 +constexpr int EDGE_LEFT = 1; +constexpr int EDGE_TOP = 2; +constexpr int EDGE_RIGHT = 4; +constexpr int EDGE_BOTTOM = 8; +constexpr int EDGE_HORZ = EDGE_RIGHT | EDGE_LEFT; +constexpr int EDGE_VERT = EDGE_TOP | EDGE_BOTTOM; +constexpr double SMALL_DVALUE = 0.0000001; #define FSQRT2 1.4142135623730950488016887242097 static double ImplGetParameter( const Point& rCenter, const Point& rPt, double fWR, double fHR ) @@ -122,7 +121,7 @@ ImplPolygon::ImplPolygon( const tools::Rectangle& rRect, sal_uInt32 nHorzRound, if ( !rRect.IsEmpty() ) { tools::Rectangle aRect( rRect ); - aRect.Justify(); // SJ: i9140 + aRect.Normalize(); // SJ: i9140 nHorzRound = std::min( nHorzRound, static_cast<sal_uInt32>(std::abs( aRect.GetWidth() >> 1 )) ); nVertRound = std::min( nVertRound, static_cast<sal_uInt32>(std::abs( aRect.GetHeight() >> 1 )) ); @@ -179,10 +178,10 @@ ImplPolygon::ImplPolygon( const Point& rCenter, tools::Long nRadX, tools::Long n const bool bOverflow = o3tl::checked_multiply(nRadX, nRadY, nRadXY); if (!bOverflow) { - nPoints = static_cast<sal_uInt16>(MinMax( + nPoints = std::clamp( ( M_PI * ( 1.5 * ( nRadX + nRadY ) - sqrt( static_cast<double>(std::abs(nRadXY)) ) ) ), - 32, 256 )); + 32.0, 256.0 ); } else { @@ -204,8 +203,8 @@ ImplPolygon::ImplPolygon( const Point& rCenter, tools::Long nRadX, tools::Long n for( i=0, nAngle = 0.0; i < nPoints4; i++, nAngle += nAngleStep ) { - tools::Long nX = FRound( nRadX * cos( nAngle ) ); - tools::Long nY = FRound( -nRadY * sin( nAngle ) ); + tools::Long nX = basegfx::fround<tools::Long>(nRadX * cos(nAngle)); + tools::Long nY = basegfx::fround<tools::Long>(nRadY * -sin(nAngle)); Point* pPt = &(mxPointAry[i]); pPt->setX( nX + rCenter.X() ); @@ -225,30 +224,30 @@ ImplPolygon::ImplPolygon( const Point& rCenter, tools::Long nRadX, tools::Long n mnPoints = 0; } -ImplPolygon::ImplPolygon( const tools::Rectangle& rBound, const Point& rStart, const Point& rEnd, - PolyStyle eStyle ) +ImplPolygon::ImplPolygon(const tools::Rectangle& rBound, const Point& rStart, const Point& rEnd, + PolyStyle eStyle, const bool bClockWiseArcDirection) { const auto nWidth = rBound.GetWidth(); const auto nHeight = rBound.GetHeight(); - if( ( nWidth != 0 ) && ( nHeight != 0 ) ) + if ((nWidth != 0) && (nHeight != 0)) { - const Point aCenter( rBound.Center() ); + const Point aCenter(rBound.Center()); // tdf#142268 Get Top Left corner of rectangle (the rectangle is not always correctly created) const auto aBoundLeft = rBound.Left() < aCenter.X() ? rBound.Left() : rBound.Right(); const auto aBoundTop = rBound.Top() < aCenter.Y() ? rBound.Top() : rBound.Bottom(); const auto nRadX = o3tl::saturating_sub(aCenter.X(), aBoundLeft); const auto nRadY = o3tl::saturating_sub(aCenter.Y(), aBoundTop); - sal_uInt16 nPoints; + sal_uInt16 nPoints; tools::Long nRadXY; const bool bOverflow = o3tl::checked_multiply(nRadX, nRadY, nRadXY); if (!bOverflow) { - nPoints = static_cast<sal_uInt16>(MinMax( + nPoints = std::clamp( ( M_PI * ( 1.5 * ( nRadX + nRadY ) - sqrt( static_cast<double>(std::abs(nRadXY)) ) ) ), - 32, 256 )); + 32.0, 256.0 ); } else { @@ -270,17 +269,30 @@ ImplPolygon::ImplPolygon( const tools::Rectangle& rBound, const Point& rStart, c double fStep; sal_uInt16 nStart; sal_uInt16 nEnd; - // #i73608# If startPoint is equal to endPoint, then draw full circle instead of nothing (as Metafiles spec) - if( fDiff <= 0. ) - fDiff += 2 * M_PI; + + if (bClockWiseArcDirection == false) + { + // #i73608# If startPoint is equal to endPoint, then draw full circle instead of nothing (as Metafiles spec) + if (fDiff <= 0.) + fDiff += 2. * M_PI; + } + else + { + fDiff = (2. * M_PI) - fDiff; + if (fDiff > 2. * M_PI) + fDiff -= 2. * M_PI; + } // Proportionally shrink number of points( fDiff / (2PI) ); - nPoints = std::max( static_cast<sal_uInt16>( ( fDiff / (2 * M_PI) ) * nPoints ), sal_uInt16(16) ); - fStep = fDiff / ( nPoints - 1 ); + nPoints = std::max(static_cast<sal_uInt16>((fDiff / (2. * M_PI)) * nPoints), sal_uInt16(16)); + fStep = fDiff / (nPoints - 1); + if (bClockWiseArcDirection == true) + fStep = -fStep; - if( PolyStyle::Pie == eStyle ) + if (PolyStyle::Pie == eStyle) { - const Point aCenter2( FRound( fCenterX ), FRound( fCenterY ) ); + const Point aCenter2(basegfx::fround<tools::Long>(fCenterX), + basegfx::fround<tools::Long>(fCenterY)); nStart = 1; nEnd = nPoints + 1; @@ -299,8 +311,8 @@ ImplPolygon::ImplPolygon( const tools::Rectangle& rBound, const Point& rStart, c { Point& rPt = mxPointAry[nStart]; - rPt.setX( FRound( fCenterX + fRadX * cos( fStart ) ) ); - rPt.setY( FRound( fCenterY - fRadY * sin( fStart ) ) ); + rPt.setX(basegfx::fround<tools::Long>(fCenterX + fRadX * cos(fStart))); + rPt.setY(basegfx::fround<tools::Long>(fCenterY - fRadY * sin(fStart))); } if( PolyStyle::Chord == eStyle ) @@ -344,8 +356,8 @@ ImplPolygon::ImplPolygon( const Point& rBezPt1, const Point& rCtrlPt1, double fK12 = fK_1 * fK1_2; double fK21 = fK_2 * fK1_1; - rPt.setX( FRound( fK1_3 * fX0 + fK12 * fX1 + fK21 * fX2 + fK_3 * fX3 ) ); - rPt.setY( FRound( fK1_3 * fY0 + fK12 * fY1 + fK21 * fY2 + fK_3 * fY3 ) ); + rPt.setX(basegfx::fround<tools::Long>(fK1_3 * fX0 + fK12 * fX1 + fK21 * fX2 + fK_3 * fX3)); + rPt.setY(basegfx::fround<tools::Long>(fK1_3 * fY0 + fK12 * fY1 + fK21 * fY2 + fK_3 * fY3)); } } @@ -388,7 +400,9 @@ ImplPolygon::ImplPolygon(const basegfx::B2DPolygon& rPolygon) for(sal_uInt32 a(0); a < nLoopCount; a++) { // add current point (always) and remember StartPointIndex for evtl. later corrections - const Point aStartPoint(FRound(aBezier.getStartPoint().getX()), FRound(aBezier.getStartPoint().getY())); + const Point aStartPoint( + basegfx::fround<tools::Long>(aBezier.getStartPoint().getX()), + basegfx::fround<tools::Long>(aBezier.getStartPoint().getY())); const sal_uInt32 nStartPointIndex(nArrayInsert); mxPointAry[nStartPointIndex] = aStartPoint; mxFlagAry[nStartPointIndex] = PolyFlags::Normal; @@ -403,11 +417,13 @@ ImplPolygon::ImplPolygon(const basegfx::B2DPolygon& rPolygon) if(aBezier.isBezier()) { // if one is used, add always two control points due to the old schema - mxPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointA().getX()), FRound(aBezier.getControlPointA().getY())); + mxPointAry[nArrayInsert] = Point(basegfx::fround<tools::Long>(aBezier.getControlPointA().getX()), + basegfx::fround<tools::Long>(aBezier.getControlPointA().getY())); mxFlagAry[nArrayInsert] = PolyFlags::Control; nArrayInsert++; - mxPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointB().getX()), FRound(aBezier.getControlPointB().getY())); + mxPointAry[nArrayInsert] = Point(basegfx::fround<tools::Long>(aBezier.getControlPointB().getX()), + basegfx::fround<tools::Long>(aBezier.getControlPointB().getY())); mxFlagAry[nArrayInsert] = PolyFlags::Control; nArrayInsert++; } @@ -442,7 +458,8 @@ ImplPolygon::ImplPolygon(const basegfx::B2DPolygon& rPolygon) { // add last point as closing point const basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1)); - const Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY())); + const Point aEnd(basegfx::fround<tools::Long>(aClosingPoint.getX()), + basegfx::fround<tools::Long>(aClosingPoint.getY())); mxPointAry[nArrayInsert] = aEnd; mxFlagAry[nArrayInsert] = PolyFlags::Normal; nArrayInsert++; @@ -475,7 +492,8 @@ ImplPolygon::ImplPolygon(const basegfx::B2DPolygon& rPolygon) for(sal_uInt32 a(0); a < nB2DLocalCount; a++) { basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a)); - Point aPoint(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY())); + Point aPoint(basegfx::fround<tools::Long>(aB2DPoint.getX()), + basegfx::fround<tools::Long>(aB2DPoint.getY())); mxPointAry[nIndex++] = aPoint; } @@ -903,8 +921,9 @@ Polygon::Polygon( const Point& rCenter, tools::Long nRadX, tools::Long nRadY ) { } -Polygon::Polygon( const tools::Rectangle& rBound, const Point& rStart, const Point& rEnd, - PolyStyle eStyle ) : mpImplPolygon(ImplPolygon(rBound, rStart, rEnd, eStyle)) +Polygon::Polygon(const tools::Rectangle& rBound, const Point& rStart, const Point& rEnd, + PolyStyle eStyle, const bool bClockWiseArcDirection) + : mpImplPolygon(ImplPolygon(rBound, rStart, rEnd, eStyle, bClockWiseArcDirection)) { } @@ -1025,7 +1044,7 @@ double Polygon::CalcDistance( sal_uInt16 nP1, sal_uInt16 nP2 ) const const double fDx = rP2.X() - rP1.X(); const double fDy = rP2.Y() - rP1.Y(); - return sqrt( fDx * fDx + fDy * fDy ); + return std::hypot( fDx, fDy ); } void Polygon::Optimize( PolyOptimizeFlags nOptimizeFlags ) @@ -1093,8 +1112,8 @@ void Polygon::Optimize( PolyOptimizeFlags nOptimizeFlags ) /** Recursively subdivide cubic bezier curve via deCasteljau. - @param rPointIter - Output iterator, where the subdivided polylines are written to. + @param rPoints + Output vector, where the subdivided polylines are written to. @param d Squared difference of curve to a straight line @@ -1107,7 +1126,7 @@ void Polygon::Optimize( PolyOptimizeFlags nOptimizeFlags ) curve does not deviate more than one pixel from a straight line. */ -static void ImplAdaptiveSubdivide( ::std::back_insert_iterator< ::std::vector< Point > >& rPointIter, +static void ImplAdaptiveSubdivide( std::vector<Point>& rPoints, const double old_d2, int recursionDepth, const double d2, @@ -1143,7 +1162,8 @@ static void ImplAdaptiveSubdivide( ::std::back_insert_iterator< ::std::vector< P // stop if distance from line is guaranteed to be bounded by d if( old_d2 > d2 && recursionDepth < maxRecursionDepth && - distance2 >= d2 ) + distance2 >= d2 && + rPoints.size() < SAL_MAX_UINT16 ) { // deCasteljau bezier arc, split at t=0.5 // Foley/vanDam, p. 508 @@ -1159,15 +1179,15 @@ static void ImplAdaptiveSubdivide( ::std::back_insert_iterator< ::std::vector< P // subdivide further ++recursionDepth; - ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y); - ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y); + ImplAdaptiveSubdivide(rPoints, distance2, recursionDepth, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y); + ImplAdaptiveSubdivide(rPoints, distance2, recursionDepth, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y); } else { // requested resolution reached. // Add end points to output iterator. // order is preserved, since this is so to say depth first traversal. - *rPointIter++ = Point( FRound(P1x), FRound(P1y) ); + rPoints.push_back(Point(basegfx::fround<tools::Long>(P1x), basegfx::fround<tools::Long>(P1y))); } } @@ -1183,7 +1203,6 @@ void Polygon::AdaptiveSubdivide( Polygon& rResult, const double d ) const sal_uInt16 nPts( GetSize() ); ::std::vector< Point > aPoints; aPoints.reserve( nPts ); - ::std::back_insert_iterator< ::std::vector< Point > > aPointIter( aPoints ); for(i=0; i<nPts;) { @@ -1197,7 +1216,7 @@ void Polygon::AdaptiveSubdivide( Polygon& rResult, const double d ) const ( PolyFlags::Control == mpImplPolygon->mxFlagAry[ i + 2 ] ) && ( PolyFlags::Normal == P4 || PolyFlags::Smooth == P4 || PolyFlags::Symmetric == P4 ) ) { - ImplAdaptiveSubdivide( aPointIter, d*d+1.0, 0, d*d, + ImplAdaptiveSubdivide( aPoints, d*d+1.0, 0, d*d, mpImplPolygon->mxPointAry[ i ].X(), mpImplPolygon->mxPointAry[ i ].Y(), mpImplPolygon->mxPointAry[ i+1 ].X(), mpImplPolygon->mxPointAry[ i+1 ].Y(), mpImplPolygon->mxPointAry[ i+2 ].X(), mpImplPolygon->mxPointAry[ i+2 ].Y(), @@ -1207,7 +1226,7 @@ void Polygon::AdaptiveSubdivide( Polygon& rResult, const double d ) const } } - *aPointIter++ = mpImplPolygon->mxPointAry[ i++ ]; + aPoints.push_back(mpImplPolygon->mxPointAry[i++]); if (aPoints.size() >= SAL_MAX_UINT16) { @@ -1420,8 +1439,8 @@ void Polygon::Rotate( const Point& rCenter, double fSin, double fCos ) const tools::Long nX = rPt.X() - nCenterX; const tools::Long nY = rPt.Y() - nCenterY; - rPt.setX( FRound( fCos * nX + fSin * nY ) + nCenterX ); - rPt.setY( - FRound( fSin * nX - fCos * nY ) + nCenterY ); + rPt.setX(basegfx::fround<tools::Long>(fCos * nX + fSin * nY + nCenterX)); + rPt.setY(basegfx::fround<tools::Long>(-(fSin * nX - fCos * nY - nCenterY))); } } @@ -1431,9 +1450,9 @@ void Polygon::Clip( const tools::Rectangle& rRect ) // Use PolyPolygon::Clip(). assert( !HasFlags()); - // #105251# Justify rect before edge filtering + // #105251# Normalize rect before edge filtering tools::Rectangle aJustifiedRect( rRect ); - aJustifiedRect.Justify(); + aJustifiedRect.Normalize(); sal_uInt16 nSourceSize = mpImplPolygon->mnPoints; ImplPolygonPointFilter aPolygon( nSourceSize ); @@ -1567,7 +1586,7 @@ void Polygon::Insert( sal_uInt16 nPos, const tools::Polygon& rPoly ) Point& Polygon::operator[]( sal_uInt16 nPos ) { - DBG_ASSERT( nPos < mpImplPolygon->mnPoints, "Polygon::[]: nPos >= nPoints" ); + assert( nPos < mpImplPolygon->mnPoints ); return mpImplPolygon->mxPointAry[nPos]; } @@ -1663,7 +1682,12 @@ void Polygon::ImplRead( SvStream& rIStream ) if ( bHasPolyFlags ) { mpImplPolygon->mxFlagAry.reset(new PolyFlags[mpImplPolygon->mnPoints]); - rIStream.ReadBytes(mpImplPolygon->mxFlagAry.get(), mpImplPolygon->mnPoints); + auto nRead = rIStream.ReadBytes(mpImplPolygon->mxFlagAry.get(), mpImplPolygon->mnPoints); + if (nRead != mpImplPolygon->mnPoints) + { + SAL_WARN("tools", "Short read"); + memset(mpImplPolygon->mxFlagAry.get() + nRead, 0, mpImplPolygon->mnPoints - nRead); + } } } diff --git a/tools/source/generic/poly2.cxx b/tools/source/generic/poly2.cxx index c6d0a46032c8..a00f64f41b18 100644 --- a/tools/source/generic/poly2.cxx +++ b/tools/source/generic/poly2.cxx @@ -40,6 +40,10 @@ PolyPolygon::PolyPolygon( const tools::Polygon& rPoly ) : mpImplPolyPolygon( rPoly ) { } +PolyPolygon::PolyPolygon( const tools::Rectangle& rRect ) + : mpImplPolyPolygon( tools::Polygon(rRect) ) +{ +} PolyPolygon::PolyPolygon( const tools::PolyPolygon& rPolyPoly ) : mpImplPolyPolygon( rPolyPoly.mpImplPolyPolygon ) diff --git a/tools/source/inet/hostfilter.cxx b/tools/source/inet/hostfilter.cxx new file mode 100644 index 000000000000..5bc63d42cfb7 --- /dev/null +++ b/tools/source/inet/hostfilter.cxx @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <tools/hostfilter.hxx> +#include <regex> + +static std::regex g_AllowedHostsRegex(""); +static bool g_AllowedHostsSet = false; + +void HostFilter::setAllowedHostsRegex(const char* sAllowedRegex) +{ + g_AllowedHostsSet = sAllowedRegex && sAllowedRegex[0] != '\0'; + if (g_AllowedHostsSet) + g_AllowedHostsRegex = sAllowedRegex; +} + +bool HostFilter::isForbidden(const OUString& rHost) +{ + if (!g_AllowedHostsSet) + return false; + + return !std::regex_match(rHost.toUtf8().getStr(), g_AllowedHostsRegex); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/tools/source/inet/inetmime.cxx b/tools/source/inet/inetmime.cxx index f7265523b6e2..6694dc398669 100644 --- a/tools/source/inet/inetmime.cxx +++ b/tools/source/inet/inetmime.cxx @@ -27,6 +27,7 @@ #include <rtl/strbuf.hxx> #include <rtl/ustrbuf.hxx> #include <rtl/tencinfo.h> +#include <tools/debug.hxx> #include <tools/inetmime.hxx> #include <rtl/character.hxx> @@ -131,30 +132,6 @@ std::unique_ptr<sal_Unicode[]> convertToUnicode(const char * pBegin, return pBuffer; } -/** Put the UTF-16 encoding of a UTF-32 character into a buffer. - - @param pBuffer Points to a buffer, must not be null. - - @param nUTF32 A UTF-32 character, must be in the range 0..0x10FFFF. - - @return A pointer past the UTF-16 characters put into the buffer - (i.e., pBuffer + 1 or pBuffer + 2). - */ -sal_Unicode * putUTF32Character(sal_Unicode * pBuffer, - sal_uInt32 nUTF32) -{ - DBG_ASSERT(rtl::isUnicodeCodePoint(nUTF32), "putUTF32Character(): Bad char"); - if (nUTF32 < 0x10000) - *pBuffer++ = sal_Unicode(nUTF32); - else - { - nUTF32 -= 0x10000; - *pBuffer++ = sal_Unicode(0xD800 | (nUTF32 >> 10)); - *pBuffer++ = sal_Unicode(0xDC00 | (nUTF32 & 0x3FF)); - } - return pBuffer; -} - void writeUTF8(OStringBuffer & rSink, sal_uInt32 nChar) { // See RFC 2279 for a discussion of UTF-8. @@ -163,30 +140,34 @@ void writeUTF8(OStringBuffer & rSink, sal_uInt32 nChar) if (nChar < 0x80) rSink.append(char(nChar)); else if (nChar < 0x800) - rSink.append(char(nChar >> 6 | 0xC0)) - .append(char((nChar & 0x3F) | 0x80)); + rSink.append(OStringChar(char(nChar >> 6 | 0xC0)) + + OStringChar(char((nChar & 0x3F) | 0x80))); else if (nChar < 0x10000) - rSink.append(char(nChar >> 12 | 0xE0)) - .append(char((nChar >> 6 & 0x3F) | 0x80)) - .append(char((nChar & 0x3F) | 0x80)); + rSink.append( + OStringChar(char(nChar >> 12 | 0xE0)) + + OStringChar(char((nChar >> 6 & 0x3F) | 0x80)) + + OStringChar(char((nChar & 0x3F) | 0x80))); else if (nChar < 0x200000) - rSink.append(char(nChar >> 18 | 0xF0)) - .append(char((nChar >> 12 & 0x3F) | 0x80)) - .append(char((nChar >> 6 & 0x3F) | 0x80)) - .append(char((nChar & 0x3F) | 0x80)); + rSink.append( + OStringChar(char(nChar >> 18 | 0xF0)) + + OStringChar(char((nChar >> 12 & 0x3F) | 0x80)) + + OStringChar(char((nChar >> 6 & 0x3F) | 0x80)) + + OStringChar(char((nChar & 0x3F) | 0x80))); else if (nChar < 0x4000000) - rSink.append(char(nChar >> 24 | 0xF8)) - .append(char((nChar >> 18 & 0x3F) | 0x80)) - .append(char((nChar >> 12 & 0x3F) | 0x80)) - .append(char((nChar >> 6 & 0x3F) | 0x80)) - .append(char((nChar & 0x3F) | 0x80)); + rSink.append( + OStringChar(char(nChar >> 24 | 0xF8)) + + OStringChar(char((nChar >> 18 & 0x3F) | 0x80)) + + OStringChar(char((nChar >> 12 & 0x3F) | 0x80)) + + OStringChar(char((nChar >> 6 & 0x3F) | 0x80)) + + OStringChar(char((nChar & 0x3F) | 0x80))); else - rSink.append(char(nChar >> 30 | 0xFC)) - .append(char((nChar >> 24 & 0x3F) | 0x80)) - .append(char((nChar >> 18 & 0x3F) | 0x80)) - .append(char((nChar >> 12 & 0x3F) | 0x80)) - .append(char((nChar >> 6 & 0x3F) | 0x80)) - .append(char((nChar & 0x3F) | 0x80)); + rSink.append( + OStringChar(char(nChar >> 30 | 0xFC)) + + OStringChar(char((nChar >> 24 & 0x3F) | 0x80)) + + OStringChar(char((nChar >> 18 & 0x3F) | 0x80)) + + OStringChar(char((nChar >> 12 & 0x3F) | 0x80)) + + OStringChar(char((nChar >> 6 & 0x3F) | 0x80)) + + OStringChar(char((nChar & 0x3F) | 0x80))); } bool translateUTF8Char(const char *& rBegin, @@ -1027,11 +1008,11 @@ bool INetMIME::scanUnsigned(const sal_Unicode *& rBegin, // static sal_Unicode const * INetMIME::scanContentType( - OUString const & rStr, OUString * pType, + std::u16string_view rStr, OUString * pType, OUString * pSubType, INetContentTypeParameterList * pParameters) { - sal_Unicode const * pBegin = rStr.getStr(); - sal_Unicode const * pEnd = pBegin + rStr.getLength(); + sal_Unicode const * pBegin = rStr.data(); + sal_Unicode const * pEnd = pBegin + rStr.size(); sal_Unicode const * p = skipLinearWhiteSpaceComment(pBegin, pEnd); sal_Unicode const * pTypeBegin = p; while (p != pEnd && isTokenChar(*p)) @@ -1290,10 +1271,11 @@ OUString INetMIME::decodeHeaderFieldBody(const OString& rBody) bDone = true; break; } - sText.append(rBody.subView( - (pEncodedTextCopyBegin - pBegin), - (q - 1 - pEncodedTextCopyBegin))); - sText.append(char(nDigit1 << 4 | nDigit2)); + sText.append( + rBody.subView( + (pEncodedTextCopyBegin - pBegin), + (q - 1 - pEncodedTextCopyBegin)) + + OStringChar(char(nDigit1 << 4 | nDigit2))); q += 2; pEncodedTextCopyBegin = q; break; @@ -1310,10 +1292,11 @@ OUString INetMIME::decodeHeaderFieldBody(const OString& rBody) break; case '_': - sText.append(rBody.subView( - (pEncodedTextCopyBegin - pBegin), - (q - 1 - pEncodedTextCopyBegin))); - sText.append(' '); + sText.append( + rBody.subView( + (pEncodedTextCopyBegin - pBegin), + (q - 1 - pEncodedTextCopyBegin)) + + OString::Concat(" ")); pEncodedTextCopyBegin = q; break; @@ -1386,9 +1369,7 @@ OUString INetMIME::decodeHeaderFieldBody(const OString& rBody) if (translateUTF8Char(pUTF8End, pEnd, nCharacter)) { appendISO88591(sDecoded, pCopyBegin, p - 1); - sal_Unicode aUTF16Buf[2]; - sal_Int32 nUTF16Len = putUTF32Character(aUTF16Buf, nCharacter) - aUTF16Buf; - sDecoded.append(aUTF16Buf, nUTF16Len); + sDecoded.appendUtf32(nCharacter); p = pUTF8End; pCopyBegin = p; } diff --git a/tools/source/inet/inetmsg.cxx b/tools/source/inet/inetmsg.cxx index bb8a700d16f1..a5c6838176a1 100644 --- a/tools/source/inet/inetmsg.cxx +++ b/tools/source/inet/inetmsg.cxx @@ -22,6 +22,9 @@ #include <tools/inetmsg.hxx> #include <comphelper/string.hxx> #include <rtl/character.hxx> +#include <o3tl/safeint.hxx> +#include <o3tl/sprintf.hxx> +#include <o3tl/string_view.hxx> #include <map> @@ -52,32 +55,32 @@ static const char *months[12] = "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; -static sal_uInt16 ParseNumber(const OString& rStr, sal_Int32& nIndex) +static sal_uInt16 ParseNumber(std::string_view rStr, size_t& nIndex) { - sal_Int32 n = nIndex; - while ((n < rStr.getLength()) + size_t n = nIndex; + while ((n < rStr.size()) && rtl::isAsciiDigit(static_cast<unsigned char>(rStr[n]))) n++; - OString aNum(rStr.copy(nIndex, (n - nIndex))); + std::string_view aNum(rStr.substr(nIndex, (n - nIndex))); nIndex = n; - return static_cast<sal_uInt16>(aNum.toInt32()); + return static_cast<sal_uInt16>(o3tl::toInt32(aNum)); } -static sal_uInt16 ParseMonth(const OString& rStr, sal_Int32& nIndex) +static sal_uInt16 ParseMonth(std::string_view rStr, size_t& nIndex) { - sal_Int32 n = nIndex; - while ((n < rStr.getLength()) + size_t n = nIndex; + while ((n < rStr.size()) && rtl::isAsciiAlpha(static_cast<unsigned char>(rStr[n]))) n++; - OString aMonth(rStr.copy(nIndex, 3)); + std::string_view aMonth(rStr.substr(nIndex, 3)); nIndex = n; sal_uInt16 i; for (i = 0; i < 12; i++) - if (aMonth.equalsIgnoreAsciiCase(months[i])) break; + if (o3tl::equalsIgnoreAsciiCase(aMonth, months[i])) break; return (i + 1); } @@ -92,20 +95,20 @@ bool INetMIMEMessage::ParseDateField ( if (aDateField.indexOf(':') != -1) { // Some DateTime format. - sal_Int32 nIndex = 0; + size_t nIndex = 0; // Skip over <Wkd> or <Weekday>, leading and trailing space. - while ((nIndex < aDateField.getLength()) && + while ((nIndex < o3tl::make_unsigned(aDateField.getLength())) && (aDateField[nIndex] == ' ')) nIndex++; while ( - (nIndex < aDateField.getLength()) && + (nIndex < o3tl::make_unsigned(aDateField.getLength())) && (rtl::isAsciiAlpha (static_cast<unsigned char>(aDateField[nIndex])) || (aDateField[nIndex] == ',') )) nIndex++; - while ((nIndex < aDateField.getLength()) && + while ((nIndex < o3tl::make_unsigned(aDateField.getLength())) && (aDateField[nIndex] == ' ')) nIndex++; @@ -143,7 +146,7 @@ bool INetMIMEMessage::ParseDateField ( rDateTime.SetSec (ParseNumber (aDateField, nIndex)); nIndex++; rDateTime.SetNanoSec (0); - const char cPossiblePlusMinus = nIndex < aDateField.getLength() ? aDateField[nIndex] : 0; + const char cPossiblePlusMinus = nIndex < o3tl::make_unsigned(aDateField.getLength()) ? aDateField[nIndex] : 0; if (cPossiblePlusMinus == '+' || cPossiblePlusMinus == '-') { // Offset from GMT: "(+|-)HHMM". @@ -263,10 +266,10 @@ void INetMIMEMessage::EnableAttachMultipartFormDataChild() tools::Time aCurTime( tools::Time::SYSTEM ); sal_uInt64 nThis = reinterpret_cast< sal_uIntPtr >( this ); // we can be on a 64bit architecture nThis = ( ( nThis >> 32 ) ^ nThis ) & SAL_MAX_UINT32; - sprintf (sTail, "%08X%08X", + o3tl::sprintf (sTail, "%08X%08X", static_cast< unsigned int >(aCurTime.GetTime()), static_cast< unsigned int >(nThis)); - m_aBoundary = "------------_4D48"; + m_aBoundary = "------------_4D48"_ostr; m_aBoundary += sTail; // Set header fields. diff --git a/tools/source/inet/inetstrm.cxx b/tools/source/inet/inetstrm.cxx index 62889bae4733..f4a841da9331 100644 --- a/tools/source/inet/inetstrm.cxx +++ b/tools/source/inet/inetstrm.cxx @@ -22,7 +22,6 @@ #include <cassert> #include <sal/types.h> -#include <rtl/strbuf.hxx> #include <tools/inetmsg.hxx> #include <tools/inetstrm.hxx> @@ -43,9 +42,9 @@ int INetMIMEMessageStream::GetHeaderLine(char* pData, sal_uInt32 nSize) { // NYI: Folding long lines. maMsgBuffer.WriteOString( aHeader.GetName() ); - maMsgBuffer.WriteCharPtr( ": " ); + maMsgBuffer.WriteOString( ": " ); maMsgBuffer.WriteOString( aHeader.GetValue() ); - maMsgBuffer.WriteCharPtr( "\r\n" ); + maMsgBuffer.WriteOString( "\r\n" ); } } @@ -76,10 +75,7 @@ int INetMIMEMessageStream::GetBodyLine(char* pData, sal_uInt32 nSize) if (pSourceMsg->GetDocumentLB()) { - if (pMsgStrm == nullptr) - pMsgStrm.reset(new SvStream (pSourceMsg->GetDocumentLB())); - - sal_uInt32 nRead = pMsgStrm->ReadBytes(pWBuf, (pWEnd - pWBuf)); + sal_uInt32 nRead = pSourceMsg->GetDocumentLB()->ReadBytes(pWBuf, (pWEnd - pWBuf)); pWBuf += nRead; } diff --git a/tools/source/memtools/multisel.cxx b/tools/source/memtools/multisel.cxx index 1f3f8eb5a23a..739d2874875a 100644 --- a/tools/source/memtools/multisel.cxx +++ b/tools/source/memtools/multisel.cxx @@ -17,6 +17,11 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <sal/config.h> + +#include <cstddef> + +#include <o3tl/string_view.hxx> #include <tools/debug.hxx> #include <tools/multisel.hxx> @@ -29,20 +34,20 @@ void MultiSelection::ImplClear() aSels.clear(); } -sal_Int32 MultiSelection::ImplFindSubSelection( sal_Int32 nIndex ) const +std::size_t MultiSelection::ImplFindSubSelection( sal_Int32 nIndex ) const { // iterate through the sub selections - sal_Int32 n = 0; + std::size_t n = 0; for ( ; - n < sal_Int32(aSels.size()) && nIndex > aSels[ n ].Max(); + n < aSels.size() && nIndex > aSels[ n ].Max(); ++n ) {} /* empty loop */ return n; } -void MultiSelection::ImplMergeSubSelections( sal_Int32 nPos1, sal_Int32 nPos2 ) +void MultiSelection::ImplMergeSubSelections( sal_Int32 nPos1, std::size_t nPos2 ) { // didn't a sub selection at nPos2 exist? - if ( nPos2 >= sal_Int32(aSels.size()) ) + if ( nPos2 >= aSels.size() ) return; // did the sub selections touch each other? @@ -141,12 +146,12 @@ bool MultiSelection::Select( sal_Int32 nIndex, bool bSelect ) return false; // find the virtual target position - sal_Int32 nSubSelPos = ImplFindSubSelection( nIndex ); + std::size_t nSubSelPos = ImplFindSubSelection( nIndex ); if ( bSelect ) { // is it included in the found sub selection? - if ( nSubSelPos < sal_Int32(aSels.size()) && aSels[ nSubSelPos ].Contains( nIndex ) ) + if ( nSubSelPos < aSels.size() && aSels[ nSubSelPos ].Contains( nIndex ) ) // already selected, nothing to do return false; @@ -164,7 +169,7 @@ bool MultiSelection::Select( sal_Int32 nIndex, bool bSelect ) ImplMergeSubSelections( nSubSelPos-1, nSubSelPos ); } // is it at the beginning of the found sub selection - else if ( nSubSelPos < sal_Int32(aSels.size()) + else if ( nSubSelPos < aSels.size() && aSels[ nSubSelPos ].Min() == (nIndex+1) ) // expand the found sub selection @@ -172,7 +177,7 @@ bool MultiSelection::Select( sal_Int32 nIndex, bool bSelect ) else { // create a new sub selection - if ( nSubSelPos < sal_Int32(aSels.size()) ) { + if ( nSubSelPos < aSels.size() ) { aSels.insert( aSels.begin() + nSubSelPos, Range( nIndex, nIndex ) ); } else { aSels.push_back( Range( nIndex, nIndex ) ); @@ -184,7 +189,7 @@ bool MultiSelection::Select( sal_Int32 nIndex, bool bSelect ) else { // is it excluded from the found sub selection? - if ( nSubSelPos >= sal_Int32(aSels.size()) + if ( nSubSelPos >= aSels.size() || !aSels[ nSubSelPos ].Contains( nIndex ) ) { // not selected, nothing to do @@ -212,7 +217,7 @@ bool MultiSelection::Select( sal_Int32 nIndex, bool bSelect ) else { // split the sub selection - if ( nSubSelPos < sal_Int32(aSels.size()) ) { + if ( nSubSelPos < aSels.size() ) { aSels.insert( aSels.begin() + nSubSelPos, Range( aSels[ nSubSelPos ].Min(), nIndex-1 ) ); } else { aSels.push_back( Range( aSels[ nSubSelPos ].Min(), nIndex-1 ) ); @@ -302,23 +307,23 @@ void MultiSelection::Select( const Range& rIndexRange, bool bSelect ) bool MultiSelection::IsSelected( sal_Int32 nIndex ) const { // find the virtual target position - sal_Int32 nSubSelPos = ImplFindSubSelection( nIndex ); + std::size_t nSubSelPos = ImplFindSubSelection( nIndex ); - return nSubSelPos < sal_Int32(aSels.size()) && aSels[ nSubSelPos ].Contains(nIndex); + return nSubSelPos < aSels.size() && aSels[ nSubSelPos ].Contains(nIndex); } void MultiSelection::Insert( sal_Int32 nIndex, sal_Int32 nCount ) { // find the virtual target position - sal_Int32 nSubSelPos = ImplFindSubSelection( nIndex ); + std::size_t nSubSelPos = ImplFindSubSelection( nIndex ); // did we need to shift the sub selections? - if ( nSubSelPos < sal_Int32(aSels.size()) ) + if ( nSubSelPos < aSels.size() ) { // did we insert an unselected into an existing sub selection? if ( aSels[ nSubSelPos ].Min() != nIndex && aSels[ nSubSelPos ].Contains(nIndex) ) { // split the sub selection - if ( nSubSelPos < sal_Int32(aSels.size()) ) { + if ( nSubSelPos < aSels.size() ) { aSels.insert( aSels.begin() + nSubSelPos, Range( aSels[ nSubSelPos ].Min(), nIndex-1 ) ); } else { aSels.push_back( Range( aSels[ nSubSelPos ].Min(), nIndex-1 ) ); @@ -328,7 +333,7 @@ void MultiSelection::Insert( sal_Int32 nIndex, sal_Int32 nCount ) } // shift the sub selections behind the inserting position - for ( sal_Int32 nPos = nSubSelPos; nPos < sal_Int32(aSels.size()); ++nPos ) + for ( std::size_t nPos = nSubSelPos; nPos < aSels.size(); ++nPos ) { aSels[ nPos ].Min() += nCount; aSels[ nPos ].Max() += nCount; @@ -342,10 +347,10 @@ void MultiSelection::Insert( sal_Int32 nIndex, sal_Int32 nCount ) void MultiSelection::Remove( sal_Int32 nIndex ) { // find the virtual target position - sal_Int32 nSubSelPos = ImplFindSubSelection( nIndex ); + std::size_t nSubSelPos = ImplFindSubSelection( nIndex ); // did we remove from an existing sub selection? - if ( nSubSelPos < sal_Int32(aSels.size()) + if ( nSubSelPos < aSels.size() && aSels[ nSubSelPos ].Contains(nIndex) ) { // does this sub selection only contain the index to be deleted @@ -362,7 +367,7 @@ void MultiSelection::Remove( sal_Int32 nIndex ) } // shift the sub selections behind the removed index - for ( sal_Int32 nPos = nSubSelPos; nPos < sal_Int32(aSels.size()); ++nPos ) + for ( std::size_t nPos = nSubSelPos; nPos < aSels.size(); ++nPos ) { --( aSels[ nPos ].Min() ); --( aSels[ nPos ].Max() ); @@ -386,12 +391,12 @@ sal_Int32 MultiSelection::FirstSelected() sal_Int32 MultiSelection::LastSelected() { - nCurSubSel = aSels.size() - 1; bCurValid = !aSels.empty(); if ( !bCurValid ) return SFX_ENDOFSELECTION; + nCurSubSel = aSels.size() - 1; nCurIndex = aSels[ nCurSubSel ].Max(); return nCurIndex; } @@ -406,7 +411,7 @@ sal_Int32 MultiSelection::NextSelected() return ++nCurIndex; // are there further sub selections? - if ( ++nCurSubSel >= sal_Int32(aSels.size()) ) + if ( ++nCurSubSel >= aSels.size() ) // we are at the end! return SFX_ENDOFSELECTION; @@ -468,7 +473,7 @@ void MultiSelection::SetTotalRange( const Range& rTotRange ) // StringRangeEnumerator -StringRangeEnumerator::StringRangeEnumerator( const OUString& i_rInput, +StringRangeEnumerator::StringRangeEnumerator( std::u16string_view i_rInput, sal_Int32 i_nMinNumber, sal_Int32 i_nMaxNumber, sal_Int32 i_nLogicalOffset @@ -566,26 +571,29 @@ void StringRangeEnumerator::insertJoinedRanges( } } -bool StringRangeEnumerator::setRange( const OUString& i_rNewRange ) +bool StringRangeEnumerator::setRange( std::u16string_view aNewRange ) { mnCount = 0; maSequence.clear(); - const sal_Unicode* pInput = i_rNewRange.getStr(); + auto pInput = aNewRange.begin(); + auto pInputEnd = aNewRange.end(); OUStringBuffer aNumberBuf( 16 ); std::vector< sal_Int32 > aNumbers; bool bSequence = false; - while( *pInput ) + while( pInput != pInputEnd ) { - while( *pInput >= '0' && *pInput <= '9' ) + while( pInput != pInputEnd && *pInput >= '0' && *pInput <= '9' ) aNumberBuf.append( *pInput++ ); if( !aNumberBuf.isEmpty() ) { - sal_Int32 nNumber = aNumberBuf.makeStringAndClear().toInt32() + mnOffset; + sal_Int32 nNumber = o3tl::toInt32(aNumberBuf) + mnOffset; + aNumberBuf.setLength(0); aNumbers.push_back( nNumber ); bSequence = false; } - + if (pInput == pInputEnd) + break; if( *pInput == '-' ) { bSequence = true; @@ -607,11 +615,10 @@ bool StringRangeEnumerator::setRange( const OUString& i_rNewRange ) aNumbers.clear(); bSequence = false; } - else if( *pInput && *pInput != ' ' ) + else if( *pInput != ' ' ) return false; // parse error - if( *pInput ) - pInput++; + pInput++; } // insert last entries if( bSequence && !aNumbers.empty() ) @@ -710,7 +717,7 @@ StringRangeEnumerator::Iterator StringRangeEnumerator::end( const o3tl::sorted_v return StringRangeEnumerator::Iterator( this, i_pPossibleValues, -1, -1 ); } -bool StringRangeEnumerator::getRangesFromString( const OUString& i_rPageRange, +bool StringRangeEnumerator::getRangesFromString( std::u16string_view i_rPageRange, std::vector< sal_Int32 >& o_rPageVector, sal_Int32 i_nMinNumber, sal_Int32 i_nMaxNumber, diff --git a/tools/source/misc/extendapplicationenvironment.cxx b/tools/source/misc/extendapplicationenvironment.cxx index ce2237a88c70..07f9779ccc26 100644 --- a/tools/source/misc/extendapplicationenvironment.cxx +++ b/tools/source/misc/extendapplicationenvironment.cxx @@ -38,7 +38,7 @@ namespace tools { void extendApplicationEnvironment() { -#if defined UNX +#if defined UNX && !defined EMSCRIPTEN // Try to set RLIMIT_NOFILE as large as possible (failure is harmless): rlimit lim; if (getrlimit(RLIMIT_NOFILE, &lim) == 0) diff --git a/tools/source/misc/fix16.cxx b/tools/source/misc/fix16.cxx new file mode 100644 index 000000000000..5818d5c1e55f --- /dev/null +++ b/tools/source/misc/fix16.cxx @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * libfixmath is Copyright (c) 2011-2021 Flatmush <Flatmush@gmail.com>, + * Petteri Aimonen <Petteri.Aimonen@gmail.com>, & libfixmath AUTHORS + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <tools/fix16.hxx> + +#include <bit> + +const fix16_t fix16_minimum = 0x80000000; /*!< the minimum value of fix16_t */ +const fix16_t fix16_overflow = 0x80000000; /*!< the value used to indicate overflows */ + +static inline uint32_t fix_abs(fix16_t in) +{ + if (in == fix16_minimum) + { + // minimum negative number has same representation as + // its absolute value in unsigned + return 0x80000000; + } + else + { + return (in >= 0) ? in : -in; + } +} + +/* 64-bit implementation for fix16_mul. Fastest version for e.g. ARM Cortex M3. + * Performs a 32*32 -> 64bit multiplication. The middle 32 bits are the result, + * bottom 16 bits are used for rounding, and upper 16 bits are used for overflow + * detection. + */ + +fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1) +{ + int64_t product = static_cast<int64_t>(inArg0) * inArg1; + + // The upper 17 bits should all be the same (the sign). + uint32_t upper = (product >> 47); + + if (product < 0) + { + if (~upper) + return fix16_overflow; + + // This adjustment is required in order to round -1/2 correctly + product--; + } + else + { + if (upper) + return fix16_overflow; + } + + fix16_t result = product >> 16; + result += (product & 0x8000) >> 15; + + return result; +} + +/* 32-bit implementation of fix16_div. Fastest version for e.g. ARM Cortex M3. + * Performs 32-bit divisions repeatedly to reduce the remainder. For this to + * be efficient, the processor has to have 32-bit hardware division. + */ +fix16_t fix16_div(fix16_t a, fix16_t b) +{ + // This uses a hardware 32/32 bit division multiple times, until we have + // computed all the bits in (a<<17)/b. Usually this takes 1-3 iterations. + + if (b == 0) + return fix16_minimum; + + uint32_t remainder = fix_abs(a); + uint32_t divider = fix_abs(b); + uint64_t quotient = 0; + int bit_pos = 17; + + // Kick-start the division a bit. + // This improves speed in the worst-case scenarios where N and D are large + // It gets a lower estimate for the result by N/(D >> 17 + 1). + if (divider & 0xFFF00000) + { + uint32_t shifted_div = (divider >> 17) + 1; + quotient = remainder / shifted_div; + uint64_t tmp = (quotient * static_cast<uint64_t>(divider)) >> 17; + remainder -= static_cast<uint32_t>(tmp); + } + + // If the divider is divisible by 2^n, take advantage of it. + while (!(divider & 0xF) && bit_pos >= 4) + { + divider >>= 4; + bit_pos -= 4; + } + + while (remainder && bit_pos >= 0) + { + // Shift remainder as much as we can without overflowing + int shift = std::countl_zero(remainder); + if (shift > bit_pos) + shift = bit_pos; + remainder <<= shift; + bit_pos -= shift; + + uint32_t div = remainder / divider; + remainder = remainder % divider; + quotient += static_cast<uint64_t>(div) << bit_pos; + + if (div & ~(0xFFFFFFFF >> bit_pos)) + return fix16_overflow; + + remainder <<= 1; + bit_pos--; + } + + // Quotient is always positive so rounding is easy + quotient++; + + fix16_t result = quotient >> 1; + + // Figure out the sign of the result + if ((a ^ b) & 0x80000000) + { + if (result == fix16_minimum) + return fix16_overflow; + + result = -result; + } + + return result; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/tools/source/misc/json_writer.cxx b/tools/source/misc/json_writer.cxx index d6e34179f930..f5c262573418 100644 --- a/tools/source/misc/json_writer.cxx +++ b/tools/source/misc/json_writer.cxx @@ -8,8 +8,9 @@ */ #include <tools/json_writer.hxx> +#include <o3tl/string_view.hxx> #include <stdio.h> -#include <algorithm> +#include <cstddef> #include <cstring> #include <rtl/math.hxx> @@ -20,103 +21,77 @@ namespace tools constexpr int DEFAULT_BUFFER_SIZE = 2048; JsonWriter::JsonWriter() - : mpBuffer(static_cast<char*>(malloc(DEFAULT_BUFFER_SIZE))) - , mPos(mpBuffer) + : mpBuffer(rtl_string_alloc(DEFAULT_BUFFER_SIZE)) + , mPos(mpBuffer->buffer) , mSpaceAllocated(DEFAULT_BUFFER_SIZE) , mStartNodeCount(0) , mbFirstFieldInNode(true) + , mbClosed(false) { *mPos = '{'; ++mPos; *mPos = ' '; ++mPos; + + addValidationMark(); } JsonWriter::~JsonWriter() { - assert(!mpBuffer && "forgot to extract data?"); - free(mpBuffer); + assert(mbClosed && "forgot to extract data?"); + rtl_string_release(mpBuffer); } -ScopedJsonWriterNode JsonWriter::startNode(const char* pNodeName) +JsonWriter::ScopedJsonWriterNode<'}'> JsonWriter::startNode(std::string_view pNodeName) { - auto len = strlen(pNodeName); - ensureSpace(len + 6); - - addCommaBeforeField(); + putLiteral(pNodeName, "{ "); - *mPos = '"'; - ++mPos; - memcpy(mPos, pNodeName, len); - mPos += len; - memcpy(mPos, "\": { ", 5); - mPos += 5; mStartNodeCount++; mbFirstFieldInNode = true; - return ScopedJsonWriterNode(*this); + + return { *this }; } -void JsonWriter::endNode() +void JsonWriter::endNode(char closing) { assert(mStartNodeCount && "mismatched StartNode/EndNode somewhere"); --mStartNodeCount; ensureSpace(1); - *mPos = '}'; + *mPos = closing; ++mPos; mbFirstFieldInNode = false; + + validate(); } -ScopedJsonWriterArray JsonWriter::startArray(const char* pNodeName) +JsonWriter::ScopedJsonWriterNode<']'> JsonWriter::startArray(std::string_view pNodeName) { - auto len = strlen(pNodeName); - ensureSpace(len + 6); + putLiteral(pNodeName, "[ "); - addCommaBeforeField(); - - *mPos = '"'; - ++mPos; - memcpy(mPos, pNodeName, len); - mPos += len; - memcpy(mPos, "\": [ ", 5); - mPos += 5; mStartNodeCount++; mbFirstFieldInNode = true; - return ScopedJsonWriterArray(*this); -} -void JsonWriter::endArray() -{ - assert(mStartNodeCount && "mismatched StartNode/EndNode somewhere"); - --mStartNodeCount; - ensureSpace(1); - *mPos = ']'; - ++mPos; - mbFirstFieldInNode = false; + return { *this }; } -ScopedJsonWriterStruct JsonWriter::startStruct() +JsonWriter::ScopedJsonWriterNode<']'> JsonWriter::startAnonArray() { - ensureSpace(6); - - addCommaBeforeField(); + putRaw("[ "); - *mPos = '{'; - ++mPos; - *mPos = ' '; - ++mPos; mStartNodeCount++; mbFirstFieldInNode = true; - return ScopedJsonWriterStruct(*this); + + return { *this }; } -void JsonWriter::endStruct() +JsonWriter::ScopedJsonWriterNode<'}'> JsonWriter::startStruct() { - assert(mStartNodeCount && "mismatched StartNode/EndNode somewhere"); - --mStartNodeCount; - ensureSpace(1); - *mPos = '}'; - ++mPos; - mbFirstFieldInNode = false; + putRaw("{ "); + + mStartNodeCount++; + mbFirstFieldInNode = true; + + return { *this }; } static char getEscapementChar(char ch) @@ -153,29 +128,30 @@ static bool writeEscapedSequence(sal_uInt32 ch, char*& pos) *pos++ = '\\'; *pos++ = getEscapementChar(ch); return true; - // Special processing of U+2028 and U+2029, which are valid JSON, but invalid JavaScript - // Write them in escaped '\u2028' or '\u2029' form - case 0x2028: - case 0x2029: - *pos++ = '\\'; - *pos++ = 'u'; - *pos++ = '2'; - *pos++ = '0'; - *pos++ = '2'; - *pos++ = ch == 0x2028 ? '8' : '9'; - return true; default: + if (ch <= 0x1f || ch == 0x2028 || ch == 0x2029) + { + // control characters, plus special processing of U+2028 and U+2029, which are valid + // JSON, but invalid JavaScript. Write them in escaped '\u2028' or '\u2029' form + int written = snprintf(pos, 7, "\\u%.4x", static_cast<unsigned int>(ch)); + if (written > 0) + pos += written; + return true; + } return false; } } -void JsonWriter::writeEscapedOUString(const OUString& rPropVal) +void JsonWriter::writeEscapedOUString(std::u16string_view rPropVal) { + *mPos = '"'; + ++mPos; + // Convert from UTF-16 to UTF-8 and perform escaping - sal_Int32 i = 0; - while (i < rPropVal.getLength()) + std::size_t i = 0; + while (i < rPropVal.size()) { - sal_uInt32 ch = rPropVal.iterateCodePoints(&i); + sal_uInt32 ch = o3tl::iterateCodePoints(rPropVal, &i); if (writeEscapedSequence(ch, mPos)) continue; if (ch <= 0x7F) @@ -211,158 +187,91 @@ void JsonWriter::writeEscapedOUString(const OUString& rPropVal) ++mPos; } } + + *mPos = '"'; + ++mPos; + + validate(); } -void JsonWriter::put(const char* pPropName, const OUString& rPropVal) +void JsonWriter::put(std::u16string_view pPropName, std::u16string_view rPropVal) { - auto nPropNameLength = strlen(pPropName); + auto nPropNameLength = pPropName.length(); // But values can be any UTF-8, // if the string only contains of 0x2028, it will be expanded 6 times (see writeEscapedSequence) - auto nWorstCasePropValLength = rPropVal.getLength() * 6; + auto nWorstCasePropValLength = rPropVal.size() * 6; ensureSpace(nPropNameLength + nWorstCasePropValLength + 8); addCommaBeforeField(); - *mPos = '"'; - ++mPos; - memcpy(mPos, pPropName, nPropNameLength); - mPos += nPropNameLength; - memcpy(mPos, "\": \"", 4); - mPos += 4; + writeEscapedOUString(pPropName); + + memcpy(mPos, ": ", 2); + mPos += 2; writeEscapedOUString(rPropVal); - *mPos = '"'; - ++mPos; + validate(); } -void JsonWriter::put(const char* pPropName, std::string_view rPropVal) +void JsonWriter::put(std::string_view pPropName, const OUString& rPropVal) { - // we assume property names are ascii - auto nPropNameLength = strlen(pPropName); - // escaping can double the length - auto nWorstCasePropValLength = rPropVal.size() * 2; - ensureSpace(nPropNameLength + nWorstCasePropValLength + 8); + // Values can be any UTF-8, + // if the string only contains of 0x2028, it will be expanded 6 times (see writeEscapedSequence) + auto nWorstCasePropValLength = rPropVal.getLength() * 6 + 2; + ensureSpaceAndWriteNameColon(pPropName, nWorstCasePropValLength); - addCommaBeforeField(); + writeEscapedOUString(rPropVal); +} + +void JsonWriter::put(std::string_view pPropName, std::string_view rPropVal) +{ + // escaping can double the length, plus quotes + auto nWorstCasePropValLength = rPropVal.size() * 2 + 2; + ensureSpaceAndWriteNameColon(pPropName, nWorstCasePropValLength); *mPos = '"'; ++mPos; - memcpy(mPos, pPropName, nPropNameLength); - mPos += nPropNameLength; - memcpy(mPos, "\": \"", 4); - mPos += 4; // copy and perform escaping for (size_t i = 0; i < rPropVal.size(); ++i) { char ch = rPropVal[i]; - switch (ch) + if (ch == 0) + break; + // Special processing of U+2028 and U+2029 + if (ch == '\xE2' && i + 2 < rPropVal.size() && rPropVal[i + 1] == '\x80' + && (rPropVal[i + 2] == '\xA8' || rPropVal[i + 2] == '\xA9')) { - case '\b': - case '\t': - case '\n': - case '\f': - case '\r': - case '"': - case '/': - case '\\': - writeEscapedSequence(ch, mPos); - break; - case '\xE2': // Special processing of U+2028 and U+2029 - if (i + 2 < rPropVal.size() && rPropVal[i + 1] == '\x80' - && (rPropVal[i + 2] == '\xA8' || rPropVal[i + 2] == '\xA9')) - { - writeEscapedSequence(rPropVal[i + 2] == '\xA8' ? 0x2028 : 0x2029, mPos); - i += 2; - break; - } - [[fallthrough]]; - default: - *mPos = ch; - ++mPos; - break; + writeEscapedSequence(rPropVal[i + 2] == '\xA8' ? 0x2028 : 0x2029, mPos); + i += 2; + } + else if (!writeEscapedSequence(static_cast<sal_uInt32>(ch), mPos)) + { + *mPos = ch; + ++mPos; } } *mPos = '"'; ++mPos; -} -void JsonWriter::put(const char* pPropName, sal_Int64 nPropVal) -{ - auto nPropNameLength = strlen(pPropName); - auto nWorstCasePropValLength = 32; - ensureSpace(nPropNameLength + nWorstCasePropValLength + 8); - - addCommaBeforeField(); - - *mPos = '"'; - ++mPos; - memcpy(mPos, pPropName, nPropNameLength); - mPos += nPropNameLength; - memcpy(mPos, "\": ", 3); - mPos += 3; - - mPos += sprintf(mPos, "%" SAL_PRIdINT64, nPropVal); + validate(); } -void JsonWriter::put(const char* pPropName, double fPropVal) +void JsonWriter::put(std::string_view pPropName, bool nPropVal) { - OString sPropVal = rtl::math::doubleToString(fPropVal, rtl_math_StringFormat_F, 12, '.'); - auto nPropNameLength = strlen(pPropName); - ensureSpace(nPropNameLength + sPropVal.getLength() + 8); - - addCommaBeforeField(); - - *mPos = '"'; - ++mPos; - memcpy(mPos, pPropName, nPropNameLength); - mPos += nPropNameLength; - memcpy(mPos, "\": ", 3); - mPos += 3; - - memcpy(mPos, sPropVal.getStr(), sPropVal.getLength()); - mPos += sPropVal.getLength(); + putLiteral(pPropName, nPropVal ? std::string_view("true") : std::string_view("false")); } -void JsonWriter::put(const char* pPropName, bool nPropVal) +void JsonWriter::putSimpleValue(std::u16string_view rPropVal) { - auto nPropNameLength = strlen(pPropName); - ensureSpace(nPropNameLength + 5 + 8); - - addCommaBeforeField(); - - *mPos = '"'; - ++mPos; - memcpy(mPos, pPropName, nPropNameLength); - mPos += nPropNameLength; - memcpy(mPos, "\": ", 3); - mPos += 3; - - const char* pVal; - if (nPropVal) - pVal = "true"; - else - pVal = "false"; - memcpy(mPos, pVal, strlen(pVal)); - mPos += strlen(pVal); -} - -void JsonWriter::putSimpleValue(const OUString& rPropVal) -{ - auto nWorstCasePropValLength = rPropVal.getLength() * 3; + auto nWorstCasePropValLength = rPropVal.size() * 6; ensureSpace(nWorstCasePropValLength + 4); addCommaBeforeField(); - *mPos = '"'; - ++mPos; - writeEscapedOUString(rPropVal); - - *mPos = '"'; - ++mPos; } void JsonWriter::putRaw(std::string_view rRawBuf) @@ -373,6 +282,8 @@ void JsonWriter::putRaw(std::string_view rRawBuf) memcpy(mPos, rRawBuf.data(), rRawBuf.size()); mPos += rRawBuf.size(); + + validate(); } void JsonWriter::addCommaBeforeField() @@ -390,54 +301,60 @@ void JsonWriter::addCommaBeforeField() void JsonWriter::ensureSpace(int noMoreBytesRequired) { - assert(mpBuffer && "already extracted data"); - int currentUsed = mPos - mpBuffer; + assert(!mbClosed && "already extracted data"); + int currentUsed = mPos - mpBuffer->buffer; if (currentUsed + noMoreBytesRequired >= mSpaceAllocated) { auto newSize = (currentUsed + noMoreBytesRequired) * 2; - mpBuffer = static_cast<char*>(realloc(mpBuffer, newSize)); - mPos = mpBuffer + currentUsed; + rtl_String* pNewBuffer = rtl_string_alloc(newSize); + memcpy(pNewBuffer->buffer, mpBuffer->buffer, currentUsed); + rtl_string_release(mpBuffer); + mpBuffer = pNewBuffer; + mPos = mpBuffer->buffer + currentUsed; mSpaceAllocated = newSize; + + addValidationMark(); } } -/** Hands ownership of the underlying storage buffer to the caller, - * after this no more document modifications may be written. */ -std::pair<char*, int> JsonWriter::extractDataImpl() +void JsonWriter::ensureSpaceAndWriteNameColon(std::string_view name, int valSize) { - assert(mStartNodeCount == 0 && "did not close all nodes"); - assert(mpBuffer && "data already extracted"); - ensureSpace(2); - // add closing brace - *mPos = '}'; + // we assume property names are ascii + ensureSpace(name.size() + valSize + 6); + + addCommaBeforeField(); + + *mPos = '"'; ++mPos; - // null-terminate - *mPos = 0; - const int sz = mPos - mpBuffer; - mPos = nullptr; - return { std::exchange(mpBuffer, nullptr), sz }; + memcpy(mPos, name.data(), name.size()); + mPos += name.size(); + memcpy(mPos, "\": ", 3); + mPos += 3; } -OString JsonWriter::extractAsOString() +void JsonWriter::putLiteral(std::string_view propName, std::string_view propValue) { - auto[pChar, sz] = extractDataImpl(); - OString ret(pChar, sz); - free(pChar); - return ret; -} + ensureSpaceAndWriteNameColon(propName, propValue.size()); + memcpy(mPos, propValue.data(), propValue.size()); + mPos += propValue.size(); -std::string JsonWriter::extractAsStdString() -{ - auto[pChar, sz] = extractDataImpl(); - std::string ret(pChar, sz); - free(pChar); - return ret; + validate(); } -bool JsonWriter::isDataEquals(const std::string& s) const +OString JsonWriter::finishAndGetAsOString() { - return s.length() == static_cast<size_t>(mPos - mpBuffer) - && memcmp(s.data(), mpBuffer, s.length()) == 0; + assert(mStartNodeCount == 0 && "did not close all nodes"); + assert(!mbClosed && "data already extracted"); + ensureSpace(2); + // add closing brace + *mPos = '}'; + ++mPos; + // null-terminate + *mPos = 0; + mbClosed = true; + + mpBuffer->length = mPos - mpBuffer->buffer; + return mpBuffer; } } // namespace tools diff --git a/tools/source/misc/pathutils.cxx b/tools/source/misc/pathutils.cxx index 706740a320f9..30bdbde8f013 100644 --- a/tools/source/misc/pathutils.cxx +++ b/tools/source/misc/pathutils.cxx @@ -43,63 +43,40 @@ WCHAR * filename(WCHAR * path) { } } -WCHAR * buildPath( - WCHAR * path, WCHAR const * frontBegin, WCHAR const * frontEnd, - WCHAR const * backBegin, std::size_t backLength) +std::wstring buildPath(std::wstring_view front, std::wstring_view back) { // Remove leading ".." segments in the second path together with matching // segments in the first path that are neither empty nor "." nor ".." nor // end in ":" (which is not foolproof, as it can erroneously erase the start // of a UNC path, but only if the input is bad data): - while (backLength >= 2 && backBegin[0] == L'.' && backBegin[1] == L'.' && - (backLength == 2 || backBegin[2] == L'\\')) + while (back.starts_with(L"..") && + (back.size() == 2 || back[2] == L'\\')) { - if (frontEnd - frontBegin < 2 || frontEnd[-1] != L'\\' || - frontEnd[-2] == L'\\' || frontEnd[-2] == L':' || - (frontEnd[-2] == L'.' && - (frontEnd - frontBegin < 3 || frontEnd[-3] == L'\\' || - (frontEnd[-3] == L'.' && - (frontEnd - frontBegin < 4 || frontEnd[-4] == L'\\'))))) + if (front.size() < 2 || front.back() != L'\\' || + front[front.size() - 2] == L'\\' || front[front.size() - 2] == L':' || + (front[front.size() - 2] == L'.' && + (front.size() < 3 || front[front.size() - 3] == L'\\' || + (front[front.size() - 3] == L'.' && + (front.size() < 4 || front[front.size() - 4] == L'\\'))))) { break; } - WCHAR const * p = frontEnd - 1; - while (p != frontBegin && p[-1] != L'\\') { + auto p = front.end() - 1; + while (p != front.begin() && p[-1] != L'\\') { --p; } - if (p == frontBegin) { + if (p == front.begin()) { break; } - frontEnd = p; - if (backLength == 2) { - backBegin += 2; - backLength -= 2; + front.remove_suffix(front.end() - p); + if (back.size() == 2) { + back = {}; } else { - backBegin += 3; - backLength -= 3; + back.remove_prefix(3); } } - if (backLength < - o3tl::make_unsigned(MAX_PATH - (frontEnd - frontBegin))) - { - WCHAR * p; - if (frontBegin == path) { - p = const_cast< WCHAR * >(frontEnd); - } else { - p = path; - while (frontBegin != frontEnd) { - *p++ = *frontBegin++; - } - } - for (; backLength > 0; --backLength) { - *p++ = *backBegin++; - } - *p = L'\0'; - return p; - } else { - SetLastError(ERROR_FILENAME_EXCED_RANGE); - return nullptr; - } + + return std::wstring(front) + std::wstring(back); } } diff --git a/tools/source/ref/globname.cxx b/tools/source/ref/globname.cxx index fda6fafab53c..4ae220659e3c 100644 --- a/tools/source/ref/globname.cxx +++ b/tools/source/ref/globname.cxx @@ -17,265 +17,127 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <stdio.h> #include <string.h> -#include <rtl/strbuf.hxx> +#include <comphelper/mimeconfighelper.hxx> +#include <o3tl/sprintf.hxx> #include <rtl/character.hxx> #include <tools/stream.hxx> #include <tools/globname.hxx> -// ImpSvGlobalName ------------------------------------------------------------ -ImpSvGlobalName::ImpSvGlobalName( const ImpSvGlobalName & rObj ) - : szData(rObj.szData) -{ -} - -ImpSvGlobalName::ImpSvGlobalName(sal_uInt32 n1, sal_uInt16 n2, sal_uInt16 n3, - sal_uInt8 b8, sal_uInt8 b9, sal_uInt8 b10, sal_uInt8 b11, - sal_uInt8 b12, sal_uInt8 b13, sal_uInt8 b14, sal_uInt8 b15) -{ - szData.Data1 = n1; - szData.Data2 = n2; - szData.Data3 = n3; - szData.Data4[0] = b8; - szData.Data4[1] = b9; - szData.Data4[2] = b10; - szData.Data4[3] = b11; - szData.Data4[4] = b12; - szData.Data4[5] = b13; - szData.Data4[6] = b14; - szData.Data4[7] = b15; -} - -bool ImpSvGlobalName::operator == ( const ImpSvGlobalName & rObj ) const -{ - return !memcmp( &szData, &rObj.szData, sizeof( szData ) ); -} - // SvGlobalName ---------------------------------------------------------------- -SvGlobalName::SvGlobalName() -{ -} - -SvGlobalName::SvGlobalName( const SvGUID & rId ) : - pImp( ImpSvGlobalName( rId ) ) -{ -} - -SvGlobalName::SvGlobalName( sal_uInt32 n1, sal_uInt16 n2, sal_uInt16 n3, - sal_uInt8 b8, sal_uInt8 b9, sal_uInt8 b10, sal_uInt8 b11, - sal_uInt8 b12, sal_uInt8 b13, sal_uInt8 b14, sal_uInt8 b15 ) : - pImp( ImpSvGlobalName(n1, n2, n3, b8, b9, b10, b11, b12, b13, b14, b15) ) -{ -} SvGlobalName::SvGlobalName( const css::uno::Sequence < sal_Int8 >& aSeq ) { // create SvGlobalName from a platform independent representation - SvGUID aResult = {}; if ( aSeq.getLength() == 16 ) { - aResult.Data1 = ( ( ( ( ( static_cast<sal_uInt8>(aSeq[0]) << 8 ) + static_cast<sal_uInt8>(aSeq[1]) ) << 8 ) + static_cast<sal_uInt8>(aSeq[2]) ) << 8 ) + static_cast<sal_uInt8>(aSeq[3]); - aResult.Data2 = ( static_cast<sal_uInt8>(aSeq[4]) << 8 ) + static_cast<sal_uInt8>(aSeq[5]); - aResult.Data3 = ( static_cast<sal_uInt8>(aSeq[6]) << 8 ) + static_cast<sal_uInt8>(aSeq[7]); + m_aData.Data1 = ( ( ( ( ( static_cast<sal_uInt8>(aSeq[0]) << 8 ) + static_cast<sal_uInt8>(aSeq[1]) ) << 8 ) + static_cast<sal_uInt8>(aSeq[2]) ) << 8 ) + static_cast<sal_uInt8>(aSeq[3]); + m_aData.Data2 = ( static_cast<sal_uInt8>(aSeq[4]) << 8 ) + static_cast<sal_uInt8>(aSeq[5]); + m_aData.Data3 = ( static_cast<sal_uInt8>(aSeq[6]) << 8 ) + static_cast<sal_uInt8>(aSeq[7]); for( int nInd = 0; nInd < 8; nInd++ ) - aResult.Data4[nInd] = static_cast<sal_uInt8>(aSeq[nInd+8]); + m_aData.Data4[nInd] = static_cast<sal_uInt8>(aSeq[nInd+8]); } - - pImp = ::o3tl::cow_wrapper< ImpSvGlobalName >(aResult); -} - -SvGlobalName::~SvGlobalName() -{ -} - -SvGlobalName & SvGlobalName::operator = ( const SvGlobalName & rObj ) -{ - pImp = rObj.pImp; - - return *this; -} - -SvGlobalName & SvGlobalName::operator = ( SvGlobalName && rObj ) noexcept -{ - pImp = std::move(rObj.pImp); - return *this; } SvStream& WriteSvGlobalName( SvStream& rOStr, const SvGlobalName & rObj ) { - rOStr.WriteUInt32( rObj.pImp->szData.Data1 ); - rOStr.WriteUInt16( rObj.pImp->szData.Data2 ); - rOStr.WriteUInt16( rObj.pImp->szData.Data3 ); - rOStr.WriteBytes( &rObj.pImp->szData.Data4, 8 ); + rOStr.WriteUInt32( rObj.m_aData.Data1 ); + rOStr.WriteUInt16( rObj.m_aData.Data2 ); + rOStr.WriteUInt16( rObj.m_aData.Data3 ); + rOStr.WriteBytes( &rObj.m_aData.Data4, 8 ); return rOStr; } SvStream& operator >> ( SvStream& rStr, SvGlobalName & rObj ) { - // the non-const dereferencing operator - // ensures pImp is unique - rStr.ReadUInt32( rObj.pImp->szData.Data1 ); - rStr.ReadUInt16( rObj.pImp->szData.Data2 ); - rStr.ReadUInt16( rObj.pImp->szData.Data3 ); - rStr.ReadBytes( &rObj.pImp->szData.Data4, 8 ); + rStr.ReadUInt32( rObj.m_aData.Data1 ); + rStr.ReadUInt16( rObj.m_aData.Data2 ); + rStr.ReadUInt16( rObj.m_aData.Data3 ); + rStr.ReadBytes( &rObj.m_aData.Data4, 8 ); return rStr; } - -bool SvGlobalName::operator < ( const SvGlobalName & rObj ) const +void SvGlobalName::MakeFromMemory( void const * pData ) { - if( pImp->szData.Data3 < rObj.pImp->szData.Data3 ) - return true; - else if( pImp->szData.Data3 > rObj.pImp->szData.Data3 ) - return false; - - if( pImp->szData.Data2 < rObj.pImp->szData.Data2 ) - return true; - else if( pImp->szData.Data2 > rObj.pImp->szData.Data2 ) - return false; - - return pImp->szData.Data1 < rObj.pImp->szData.Data1; + memcpy( &m_aData, pData, sizeof( m_aData ) ); } -bool SvGlobalName::operator == ( const SvGlobalName & rObj ) const +bool SvGlobalName::MakeId( std::u16string_view rIdStr ) { - return pImp == rObj.pImp; -} + const sal_Unicode *pStr = rIdStr.data(); + if( rIdStr.size() != 36 + || '-' != pStr[ 8 ] || '-' != pStr[ 13 ] + || '-' != pStr[ 18 ] || '-' != pStr[ 23 ] ) + return false; -void SvGlobalName::MakeFromMemory( void const * pData ) -{ - memcpy( &pImp->szData, pData, sizeof( pImp->szData ) ); -} + SvGUID aGuid = {}; + auto asciiHexDigitToNumber = [](sal_Unicode c) -> sal_uInt8 + { + if (rtl::isAsciiDigit(c)) + return c - '0'; + else + return rtl::toAsciiUpperCase(c) - 'A' + 10; + }; -bool SvGlobalName::MakeId( const OUString & rIdStr ) -{ - const sal_Unicode *pStr = rIdStr.getStr(); - if( rIdStr.getLength() == 36 - && '-' == pStr[ 8 ] && '-' == pStr[ 13 ] - && '-' == pStr[ 18 ] && '-' == pStr[ 23 ] ) + for( int i = 0; i < 8; i++ ) { - sal_uInt32 nFirst = 0; - int i = 0; - for( i = 0; i < 8; i++ ) - { - if( rtl::isAsciiHexDigit( *pStr ) ) - if( rtl::isAsciiDigit( *pStr ) ) - nFirst = nFirst * 16 + (*pStr - '0'); - else - nFirst = nFirst * 16 + (rtl::toAsciiUpperCase( *pStr ) - 'A' + 10 ); - else - return false; - pStr++; - } + if( !rtl::isAsciiHexDigit( *pStr ) ) + return false; + aGuid.Data1 = aGuid.Data1 * 16 + asciiHexDigitToNumber( *pStr++ ); + } - sal_uInt16 nSec = 0; - pStr++; - for( i = 0; i < 4; i++ ) - { - if( rtl::isAsciiHexDigit( *pStr ) ) - if( rtl::isAsciiDigit( *pStr ) ) - nSec = nSec * 16 + (*pStr - '0'); - else - nSec = nSec * 16 + static_cast<sal_uInt16>(rtl::toAsciiUpperCase( *pStr ) - 'A' + 10 ); - else - return false; - pStr++; - } + pStr++; + for( int i = 0; i < 4; i++ ) + { + if( !rtl::isAsciiHexDigit( *pStr ) ) + return false; + aGuid.Data2 = aGuid.Data2 * 16 + asciiHexDigitToNumber( *pStr++ ); + } - sal_uInt16 nThird = 0; - pStr++; - for( i = 0; i < 4; i++ ) - { - if( rtl::isAsciiHexDigit( *pStr ) ) - if( rtl::isAsciiDigit( *pStr ) ) - nThird = nThird * 16 + (*pStr - '0'); - else - nThird = nThird * 16 + static_cast<sal_uInt16>(rtl::toAsciiUpperCase( *pStr ) - 'A' + 10 ); - else - return false; - pStr++; - } + pStr++; + for( int i = 0; i < 4; i++ ) + { + if( !rtl::isAsciiHexDigit( *pStr ) ) + return false; + aGuid.Data3 = aGuid.Data3 * 16 + asciiHexDigitToNumber( *pStr++ ); + } - sal_Int8 szRemain[ 8 ] = {}; - pStr++; - for( i = 0; i < 16; i++ ) - { - if( rtl::isAsciiHexDigit( *pStr ) ) - if( rtl::isAsciiDigit( *pStr ) ) - szRemain[i/2] = szRemain[i/2] * 16 + (*pStr - '0'); - else - szRemain[i/2] = szRemain[i/2] * 16 + static_cast<sal_Int8>(rtl::toAsciiUpperCase( *pStr ) - 'A' + 10 ); - else - return false; + pStr++; + for( int i = 0; i < 16; i++ ) + { + if( !rtl::isAsciiHexDigit( *pStr ) ) + return false; + aGuid.Data4[i/2] = aGuid.Data4[i/2] * 16 + asciiHexDigitToNumber( *pStr++ ); + if( i == 3 ) pStr++; - if( i == 3 ) - pStr++; - } - - memcpy(&pImp->szData.Data1, &nFirst, sizeof(nFirst)); - memcpy(&pImp->szData.Data2, &nSec, sizeof(nSec)); - memcpy(&pImp->szData.Data3, &nThird, sizeof(nThird)); - memcpy(&pImp->szData.Data4, szRemain, 8); - return true; } - return false; + + m_aData = aGuid; + return true; } OUString SvGlobalName::GetHexName() const { - OStringBuffer aHexBuffer(36); - - char buf[ 10 ]; - sprintf( buf, "%8.8" SAL_PRIXUINT32, pImp->szData.Data1 ); - aHexBuffer.append(buf); - aHexBuffer.append('-'); - sprintf( buf, "%4.4X", pImp->szData.Data2 ); - aHexBuffer.append(buf); - aHexBuffer.append('-'); - sprintf( buf, "%4.4X", pImp->szData.Data3 ); - aHexBuffer.append(buf); - aHexBuffer.append('-'); - for( int i = 0; i < 2; i++ ) - { - sprintf( buf, "%2.2x", pImp->szData.Data4[ i ] ); - aHexBuffer.append(buf); - } - aHexBuffer.append('-'); - for( int i = 2; i < 8; i++ ) - { - sprintf( buf, "%2.2x", pImp->szData.Data4[ i ] ); - aHexBuffer.append(buf); - } - return OStringToOUString(aHexBuffer.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US); + char buf[ 37 ]; + int n = o3tl::sprintf(buf, + "%8.8" SAL_PRIXUINT32 "-%4.4X-%4.4X-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x", + m_aData.Data1, m_aData.Data2, m_aData.Data3, + m_aData.Data4[0], m_aData.Data4[1], m_aData.Data4[2], m_aData.Data4[3], + m_aData.Data4[4], m_aData.Data4[5], m_aData.Data4[6], m_aData.Data4[7]); + assert(n == 36); + return OUString::createFromAscii(std::string_view(buf, n)); } css::uno::Sequence < sal_Int8 > SvGlobalName::GetByteSequence() const { // platform independent representation of a "GlobalName" // maybe transported remotely - css::uno::Sequence< sal_Int8 > aResult{ - /* [ 0] */ static_cast<sal_Int8>(pImp->szData.Data1 >> 24), - /* [ 1] */ static_cast<sal_Int8>((pImp->szData.Data1 << 8 ) >> 24), - /* [ 2] */ static_cast<sal_Int8>((pImp->szData.Data1 << 16 ) >> 24), - /* [ 3] */ static_cast<sal_Int8>((pImp->szData.Data1 << 24 ) >> 24), - /* [ 4] */ static_cast<sal_Int8>(pImp->szData.Data2 >> 8), - /* [ 5] */ static_cast<sal_Int8>((pImp->szData.Data2 << 8 ) >> 8), - /* [ 6] */ static_cast<sal_Int8>(pImp->szData.Data3 >> 8), - /* [ 7] */ static_cast<sal_Int8>((pImp->szData.Data3 << 8 ) >> 8), - /* [ 8] */ static_cast<sal_Int8>(pImp->szData.Data4[ 0 ]), - /* [ 9] */ static_cast<sal_Int8>(pImp->szData.Data4[ 1 ]), - /* [10] */ static_cast<sal_Int8>(pImp->szData.Data4[ 2 ]), - /* [11] */ static_cast<sal_Int8>(pImp->szData.Data4[ 3 ]), - /* [12] */ static_cast<sal_Int8>(pImp->szData.Data4[ 4 ]), - /* [13] */ static_cast<sal_Int8>(pImp->szData.Data4[ 5 ]), - /* [14] */ static_cast<sal_Int8>(pImp->szData.Data4[ 6 ]), - /* [15] */ static_cast<sal_Int8>(pImp->szData.Data4[ 7 ]) - }; - - return aResult; + return comphelper::MimeConfigurationHelper::GetSequenceClassID( + m_aData.Data1, m_aData.Data2, m_aData.Data3, + m_aData.Data4[0], m_aData.Data4[1], m_aData.Data4[2], m_aData.Data4[3], + m_aData.Data4[4], m_aData.Data4[5], m_aData.Data4[6], m_aData.Data4[7]); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tools/source/reversemap/bestreversemap.cxx b/tools/source/reversemap/bestreversemap.cxx index 02a81932b3f2..f124140c1918 100644 --- a/tools/source/reversemap/bestreversemap.cxx +++ b/tools/source/reversemap/bestreversemap.cxx @@ -11,6 +11,7 @@ #include <rtl/textcvt.h> #include <cstdlib> +#include <iterator> #include <stdio.h> namespace { @@ -91,7 +92,7 @@ int main() sal_Unicode c = 0; while (c < 0xFFFF) { - for (size_t i = 0; i < SAL_N_ELEMENTS(aConverters); ++i) + for (size_t i = 0; i < std::size(aConverters); ++i) aConverters[i].reset(); int nMostCapable = -1; @@ -99,7 +100,7 @@ int main() while(c < 0xFFFF) { bool bSomethingCapable = false; - for (size_t i = 0; i < SAL_N_ELEMENTS(aConverters); ++i) + for (size_t i = 0; i < std::size(aConverters); ++i) { if (aConverters[i].isOK()) aConverters[i].checkSupports(c); @@ -119,7 +120,7 @@ int main() while(c < 0xFFFF) { bool bNothingCapable = true; - for (size_t i = 0; i < SAL_N_ELEMENTS(aConverters); ++i) + for (size_t i = 0; i < std::size(aConverters); ++i) { aConverters[i].checkSupports(c); if (aConverters[i].isOK()) diff --git a/tools/source/stream/GenericTypeSerializer.cxx b/tools/source/stream/GenericTypeSerializer.cxx index 7bba06d97aba..3eefb008ea67 100644 --- a/tools/source/stream/GenericTypeSerializer.cxx +++ b/tools/source/stream/GenericTypeSerializer.cxx @@ -36,9 +36,9 @@ void GenericTypeSerializer::readColor(Color& rColor) if (nColorNameID & COL_NAME_USER) { - sal_uInt16 nRed; - sal_uInt16 nGreen; - sal_uInt16 nBlue; + sal_uInt16 nRed(0); + sal_uInt16 nGreen(0); + sal_uInt16 nBlue(0); mrStream.ReadUInt16(nRed); mrStream.ReadUInt16(nGreen); @@ -130,6 +130,18 @@ void GenericTypeSerializer::readSize(Size& rSize) rSize.setWidth(nWidth); rSize.setHeight(nHeight); + + // sanitize negative size dimensions + if (rSize.Width() < 0) + { + SAL_WARN("tools", "negative width"); + rSize.setWidth(0); + } + if (rSize.Height() < 0) + { + SAL_WARN("tools", "negative height"); + rSize.setHeight(0); + } } void GenericTypeSerializer::writeSize(const Size& rSize) diff --git a/tools/source/stream/stream.cxx b/tools/source/stream/stream.cxx index d42cefdf63cf..d79a452cbade 100644 --- a/tools/source/stream/stream.cxx +++ b/tools/source/stream/stream.cxx @@ -26,12 +26,12 @@ #include <memory> #include <string.h> -#include <stdio.h> #include <o3tl/safeint.hxx> #include <osl/endian.h> #include <osl/diagnose.h> #include <rtl/strbuf.hxx> +#include <rtl/string.hxx> #include <rtl/ustrbuf.hxx> #include <sal/log.hxx> #include <tools/long.hxx> @@ -156,82 +156,43 @@ void SvStream::writeNumberWithoutSwap_(const void * pDataSrc, int nDataSize) void SvLockBytes::close() { - if (m_bOwner) - delete m_pStream; - m_pStream = nullptr; + (void)this; } // virtual -ErrCode SvLockBytes::ReadAt(sal_uInt64 const nPos, void * pBuffer, std::size_t nCount, - std::size_t * pRead) const +ErrCode SvLockBytes::ReadAt(sal_uInt64 const , void * , std::size_t , + std::size_t * ) const { - if (!m_pStream) - { - OSL_FAIL("SvLockBytes::ReadAt(): Bad stream"); - return ERRCODE_NONE; - } - - m_pStream->Seek(nPos); - std::size_t nTheRead = m_pStream->ReadBytes(pBuffer, nCount); - if (pRead) - *pRead = nTheRead; - return m_pStream->GetErrorCode(); + OSL_FAIL("SvLockBytes::ReadAt(): Bad stream"); + return ERRCODE_NONE; } // virtual -ErrCode SvLockBytes::WriteAt(sal_uInt64 const nPos, const void * pBuffer, std::size_t nCount, - std::size_t * pWritten) +ErrCode SvLockBytes::WriteAt(sal_uInt64 const , const void * , std::size_t , + std::size_t * ) { - if (!m_pStream) - { - OSL_FAIL("SvLockBytes::WriteAt(): Bad stream"); - return ERRCODE_NONE; - } - - m_pStream->Seek(nPos); - std::size_t nTheWritten = m_pStream->WriteBytes(pBuffer, nCount); - if (pWritten) - *pWritten = nTheWritten; - return m_pStream->GetErrorCode(); + OSL_FAIL("SvLockBytes::WriteAt(): Bad stream"); + return ERRCODE_NONE; } // virtual ErrCode SvLockBytes::Flush() const { - if (!m_pStream) - { - OSL_FAIL("SvLockBytes::Flush(): Bad stream"); - return ERRCODE_NONE; - } - - m_pStream->Flush(); - return m_pStream->GetErrorCode(); + OSL_FAIL("SvLockBytes::Flush(): Bad stream"); + return ERRCODE_NONE; } // virtual -ErrCode SvLockBytes::SetSize(sal_uInt64 const nSize) +ErrCode SvLockBytes::SetSize(sal_uInt64) { - if (!m_pStream) - { - OSL_FAIL("SvLockBytes::SetSize(): Bad stream"); - return ERRCODE_NONE; - } - - m_pStream->SetStreamSize(nSize); - return m_pStream->GetErrorCode(); + OSL_FAIL("SvLockBytes::SetSize(): Bad stream"); + return ERRCODE_NONE; } -ErrCode SvLockBytes::Stat(SvLockBytesStat * pStat) const +ErrCode SvLockBytes::Stat(SvLockBytesStat *) const { - if (!m_pStream) - { - OSL_FAIL("SvLockBytes::Stat(): Bad stream"); - return ERRCODE_NONE; - } - - if (pStat) - pStat->nSize = m_pStream->TellEnd(); + OSL_FAIL("SvLockBytes::Stat(): Bad stream"); return ERRCODE_NONE; } @@ -332,12 +293,6 @@ SvStream::SvStream() : SvStream::SvStream( SvLockBytes* pLockBytesP ) : SvStream() { m_xLockBytes = pLockBytesP; - if( pLockBytesP ) { - const SvStream* pStrm = pLockBytesP->GetStream(); - if( pStrm ) { - SetError( pStrm->GetErrorCode() ); - } - } SetBufferSize( 256 ); } @@ -355,20 +310,25 @@ void SvStream::ClearError() void SvStream::SetError( ErrCode nErrorCode ) { - if (m_nError == ERRCODE_NONE) + if (m_nError == ERRCODE_NONE || (m_nError.IsWarning() && nErrorCode.IsError())) m_nError = nErrorCode; } void SvStream::SetEndian( SvStreamEndian nNewFormat ) { - m_nEndian = nNewFormat; - m_isSwap = false; #ifdef OSL_BIGENDIAN - if (m_nEndian == SvStreamEndian::LITTLE) - m_isSwap = true; + m_isSwap = nNewFormat == SvStreamEndian::LITTLE; +#else + m_isSwap = nNewFormat == SvStreamEndian::BIG; +#endif +} + +SvStreamEndian SvStream::GetEndian() const +{ +#ifdef OSL_BIGENDIAN + return m_isSwap ? SvStreamEndian::LITTLE : SvStreamEndian::BIG; #else - if (m_nEndian == SvStreamEndian::BIG) - m_isSwap = true; + return m_isSwap ? SvStreamEndian::BIG : SvStreamEndian::LITTLE; #endif } @@ -378,7 +338,7 @@ void SvStream::SetBufferSize( sal_uInt16 nBufferSize ) bool bDontSeek = (m_pRWBuf == nullptr); if (m_isDirty && m_isWritable) // due to Windows NT: Access denied - Flush(); + FlushBuffer(); if (m_nBufSize) { @@ -426,13 +386,21 @@ bool SvStream::ReadByteStringLine( OUString& rStr, rtl_TextEncoding eSrcCharSet, bool SvStream::ReadLine( OString& rStr, sal_Int32 nMaxBytesToRead ) { + OStringBuffer aBuf(4096); + bool rv = ReadLine(aBuf, nMaxBytesToRead); + rStr = aBuf.makeStringAndClear(); + return rv; +} + +bool SvStream::ReadLine( OStringBuffer& aBuf, sal_Int32 nMaxBytesToRead ) +{ char buf[256+1]; bool bEnd = false; sal_uInt64 nOldFilePos = Tell(); char c = 0; std::size_t nTotalLen = 0; - OStringBuffer aBuf(4096); + aBuf.setLength(0); while( !bEnd && !GetError() ) // Don't test for EOF as we // are reading block-wise! { @@ -443,7 +411,7 @@ bool SvStream::ReadLine( OString& rStr, sal_Int32 nMaxBytesToRead ) { // Exit on first block-read error m_isEof = true; - rStr.clear(); + aBuf.setLength(0); return false; } else @@ -494,7 +462,6 @@ bool SvStream::ReadLine( OString& rStr, sal_Int32 nMaxBytesToRead ) if ( bEnd ) m_isEof = false; - rStr = aBuf.makeStringAndClear(); return bEnd; } @@ -635,9 +602,9 @@ OUString read_zeroTerminated_uInt8s_ToOUString(SvStream& rStream, rtl_TextEncodi read_zeroTerminated_uInt8s_ToOString(rStream), eEnc); } -/** Attempt to write a prefixed sequence of nUnits 16bit units from an OUString, +/** Attempt to write a sequence of nUnits 16bit units from an OUString, returned value is number of bytes written */ -std::size_t write_uInt16s_FromOUString(SvStream& rStrm, std::u16string_view rStr, +static std::size_t write_uInt16s_FromOUString(SvStream& rStrm, std::u16string_view rStr, std::size_t nUnits) { DBG_ASSERT( sizeof(sal_Unicode) == sizeof(sal_uInt16), "write_uInt16s_FromOUString: swapping sizeof(sal_Unicode) not implemented" ); @@ -664,19 +631,22 @@ std::size_t write_uInt16s_FromOUString(SvStream& rStrm, std::u16string_view rStr return nWritten; } -bool SvStream::WriteUnicodeOrByteText( std::u16string_view rStr, rtl_TextEncoding eDestCharSet ) +bool SvStream::WriteUnicodeOrByteText(std::u16string_view rStr, rtl_TextEncoding eDestCharSet, bool bZero) { if ( eDestCharSet == RTL_TEXTENCODING_UNICODE ) { write_uInt16s_FromOUString(*this, rStr, rStr.size()); - return m_nError == ERRCODE_NONE; + if (bZero) + WriteUnicode(0); } else { OString aStr(OUStringToOString(rStr, eDestCharSet)); - write_uInt8s_FromOString(*this, aStr, aStr.getLength()); - return m_nError == ERRCODE_NONE; + WriteBytes(aStr.getStr(), aStr.getLength()); + if (bZero) + WriteChar(0); } + return m_nError == ERRCODE_NONE; } bool SvStream::WriteByteStringLine( std::u16string_view rStr, rtl_TextEncoding eDestCharSet ) @@ -705,10 +675,11 @@ bool SvStream::WriteUniOrByteChar( sal_Unicode ch, rtl_TextEncoding eDestCharSet void SvStream::StartWritingUnicodeText() { + m_isSwap = false; // Switch to no endian swapping // BOM, Byte Order Mark, U+FEFF, see // http://www.unicode.org/faq/utf_bom.html#BOM // Upon read: 0xfeff(-257) => no swap; 0xfffe(-2) => swap - writeNumberWithoutSwap(sal_uInt16(0xfeff)); // write native format + WriteUInt16(0xfeff); } void SvStream::StartReadingUnicodeText( rtl_TextEncoding eReadBomCharSet ) @@ -718,52 +689,54 @@ void SvStream::StartReadingUnicodeText( rtl_TextEncoding eReadBomCharSet ) eReadBomCharSet == RTL_TEXTENCODING_UTF8)) return; // nothing to read - bool bTryUtf8 = false; - sal_uInt16 nFlag(0); - sal_sSize nBack = sizeof(nFlag); - ReadUInt16( nFlag ); + const sal_uInt64 nOldPos = Tell(); + bool bGetBack = true; + unsigned char nFlag(0); + ReadUChar( nFlag ); switch ( nFlag ) { - case 0xfeff : - // native UTF-16 + case 0xfe: // UTF-16BE? if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW || eReadBomCharSet == RTL_TEXTENCODING_UNICODE) - nBack = 0; + { + ReadUChar(nFlag); + if (nFlag == 0xff) + { + SetEndian(SvStreamEndian::BIG); + bGetBack = false; + } + } break; - case 0xfffe : - // swapped UTF-16 + case 0xff: // UTF-16LE? if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW || eReadBomCharSet == RTL_TEXTENCODING_UNICODE) { - SetEndian( m_nEndian == SvStreamEndian::BIG ? SvStreamEndian::LITTLE : SvStreamEndian::BIG ); - nBack = 0; + ReadUChar(nFlag); + if (nFlag == 0xfe) + { + SetEndian(SvStreamEndian::LITTLE); + bGetBack = false; + } } break; - case 0xefbb : - if (m_nEndian == SvStreamEndian::BIG && - (eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW || - eReadBomCharSet == RTL_TEXTENCODING_UTF8)) - bTryUtf8 = true; - break; - case 0xbbef : - if (m_nEndian == SvStreamEndian::LITTLE && - (eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW || - eReadBomCharSet == RTL_TEXTENCODING_UTF8)) - bTryUtf8 = true; + case 0xef: // UTF-8? + if ( eReadBomCharSet == RTL_TEXTENCODING_DONTKNOW || + eReadBomCharSet == RTL_TEXTENCODING_UTF8) + { + ReadUChar(nFlag); + if (nFlag == 0xbb) + { + ReadUChar(nFlag); + if (nFlag == 0xbf) + bGetBack = false; // it is UTF-8 + } + } break; default: ; // nothing } - if (bTryUtf8) - { - unsigned char nChar(0); - nBack += sizeof(nChar); - ReadUChar( nChar ); - if (nChar == 0xbf) - nBack = 0; // it is UTF-8 - } - if (nBack) - SeekRel( -nBack ); // no BOM, pure data + if (bGetBack) + Seek(nOldPos); // no BOM, pure data } sal_uInt64 SvStream::SeekRel(sal_Int64 const nPos) @@ -1014,27 +987,13 @@ SvStream& SvStream::WriteFloat( float v ) return *this; } -SvStream& SvStream::WriteDouble ( const double& r ) +SvStream& SvStream::WriteDouble ( double v ) { #if defined UNX if (m_isSwap) - { - double nHelp = r; - SwapDouble(nHelp); - writeNumberWithoutSwap(nHelp); - return *this; - } - else + SwapDouble(v); #endif - { - writeNumberWithoutSwap(r); - } - return *this; -} - -SvStream& SvStream::WriteCharPtr( const char* pBuf ) -{ - WriteBytes( pBuf, strlen(pBuf) ); + writeNumberWithoutSwap(v); return *this; } @@ -1344,22 +1303,6 @@ void SvStream::RefreshBuffer() m_isIoRead = m_isIoWrite = false; } -SvStream& SvStream::WriteInt32AsString(sal_Int32 nInt32) -{ - char buffer[12]; - std::size_t nLen = sprintf(buffer, "%" SAL_PRIdINT32, nInt32); - WriteBytes(buffer, nLen); - return *this; -} - -SvStream& SvStream::WriteUInt32AsString(sal_uInt32 nUInt32) -{ - char buffer[11]; - std::size_t nLen = sprintf(buffer, "%" SAL_PRIuUINT32, nUInt32); - WriteBytes(buffer, nLen); - return *this; -} - #define CRYPT_BUFSIZE 1024 /// Encrypt and write @@ -1544,7 +1487,7 @@ SvMemoryStream::~SvMemoryStream() if( bOwnsData ) FreeMemory(); else - Flush(); + FlushBuffer(); } } @@ -1752,7 +1695,7 @@ void SvMemoryStream::FreeMemory() void* SvMemoryStream::SwitchBuffer() { - Flush(); + FlushBuffer(); if( !bOwnsData ) return nullptr; Seek( STREAM_SEEK_TO_BEGIN ); @@ -1785,7 +1728,16 @@ void SvMemoryStream::SetSize(sal_uInt64 const nNewSize) ReAllocateMemory( nDiff ); } -//Create an OString of nLen bytes from rStream +void SvMemoryStream::MakeReadOnly() +{ + FlushBuffer(); + m_isWritable = false; + nResize = 0; + SetBufferSize( 0 ); +} + +// Create an OString of nLen bytes from rStream +// coverity[ +taint_sanitize ] OString read_uInt8s_ToOString(SvStream& rStrm, std::size_t nLen) { rtl_String *pStr = nullptr; @@ -1816,7 +1768,8 @@ OString read_uInt8s_ToOString(SvStream& rStrm, std::size_t nLen) return pStr ? OString(pStr, SAL_NO_ACQUIRE) : OString(); } -//Create an OUString of nLen sal_Unicode code units from rStream +// Create an OUString of nLen sal_Unicode code units from rStream +// coverity[ +taint_sanitize ] OUString read_uInt16s_ToOUString(SvStream& rStrm, std::size_t nLen) { rtl_uString *pStr = nullptr; @@ -1848,7 +1801,8 @@ OUString read_uInt16s_ToOUString(SvStream& rStrm, std::size_t nLen) } } - //take ownership of buffer and return, otherwise return empty string + // take ownership of buffer and return, otherwise return empty string + // coverity[tainted_data] - unhelpful untrusted loop bound return pStr ? OUString(pStr, SAL_NO_ACQUIRE) : OUString(); } @@ -1989,7 +1943,7 @@ std::size_t write_uInt16_lenPrefixed_uInt8s_FromOString(SvStream& rStrm, if (rStrm.good()) { nWritten += sizeof(sal_uInt16); - nWritten += write_uInt8s_FromOString(rStrm, rStr, nUnits); + nWritten += rStrm.WriteBytes(rStr.data(), nUnits); } return nWritten; } diff --git a/tools/source/stream/strmunx.cxx b/tools/source/stream/strmunx.cxx index 853389266ac3..881d7a28c0af 100644 --- a/tools/source/stream/strmunx.cxx +++ b/tools/source/stream/strmunx.cxx @@ -24,7 +24,7 @@ #include <tools/stream.hxx> #include <map> -#include <osl/mutex.hxx> +#include <mutex> #include <osl/thread.h> #include <sal/log.hxx> @@ -37,9 +37,9 @@ using namespace osl; namespace { -osl::Mutex& LockMutex() +std::mutex& LockMutex() { - static osl::Mutex SINGLETON; + static std::mutex SINGLETON; return SINGLETON; } @@ -63,7 +63,7 @@ bool lockFile( const SvFileStream* pStream ) if( aStatus.getFileType() == osl::FileStatus::Directory ) return true; - osl::MutexGuard aGuard( LockMutex() ); + std::unique_lock aGuard( LockMutex() ); for( const auto& [rLockStream, rLockItem] : gLocks ) { if( aItem.isIdenticalTo( rLockItem ) ) @@ -86,22 +86,12 @@ bool lockFile( const SvFileStream* pStream ) void unlockFile( SvFileStream const * pStream ) { - osl::MutexGuard aGuard( LockMutex() ); + std::unique_lock aGuard( LockMutex() ); gLocks.erase(pStream); } } -// StreamData ------------------------------------------------------------------ - -class StreamData -{ -public: - oslFileHandle rHandle; - - StreamData() : rHandle( nullptr ) { } -}; - static ErrCode GetSvError( int nErrno ) { static struct { int nErr; ErrCode sv; } const errArr[] = @@ -111,7 +101,7 @@ static ErrCode GetSvError( int nErrno ) { EBADF, SVSTREAM_INVALID_HANDLE }, #if defined(NETBSD) || \ defined(FREEBSD) || defined(MACOSX) || defined(OPENBSD) || \ - defined(__FreeBSD_kernel__) || defined (AIX) || defined(DRAGONFLY) || \ + defined(__FreeBSD_kernel__) || defined(DRAGONFLY) || \ defined(IOS) || defined(HAIKU) { EDEADLK, SVSTREAM_LOCKING_VIOLATION }, #else @@ -198,8 +188,6 @@ SvFileStream::SvFileStream( const OUString& rFileName, StreamMode nOpenMode ) { bIsOpen = false; m_isWritable = false; - mbDontFlushOnClose = false; - pInstanceData.reset(new StreamData); SetBufferSize( 1024 ); // convert URL to SystemPath, if necessary @@ -216,8 +204,6 @@ SvFileStream::SvFileStream() { bIsOpen = false; m_isWritable = false; - mbDontFlushOnClose = false; - pInstanceData.reset(new StreamData); SetBufferSize( 1024 ); } @@ -233,7 +219,7 @@ std::size_t SvFileStream::GetData( void* pData, std::size_t nSize ) sal_uInt64 nRead = 0; if ( IsOpen() ) { - oslFileError rc = osl_readFile(pInstanceData->rHandle,pData,static_cast<sal_uInt64>(nSize),&nRead); + oslFileError rc = osl_readFile(mxFileHandle,pData,static_cast<sal_uInt64>(nSize),&nRead); if ( rc != osl_File_E_None ) { SetError( ::GetSvError( rc )); @@ -250,7 +236,7 @@ std::size_t SvFileStream::PutData( const void* pData, std::size_t nSize ) sal_uInt64 nWrite = 0; if ( IsOpen() ) { - oslFileError rc = osl_writeFile(pInstanceData->rHandle,pData,static_cast<sal_uInt64>(nSize),&nWrite); + oslFileError rc = osl_writeFile(mxFileHandle,pData,static_cast<sal_uInt64>(nSize),&nWrite); if ( rc != osl_File_E_None ) { SetError( ::GetSvError( rc ) ); @@ -271,9 +257,9 @@ sal_uInt64 SvFileStream::SeekPos(sal_uInt64 const nPos) oslFileError rc; sal_uInt64 nNewPos; if ( nPos != STREAM_SEEK_TO_END ) - rc = osl_setFilePos( pInstanceData->rHandle, osl_Pos_Absolut, nPos ); + rc = osl_setFilePos( mxFileHandle, osl_Pos_Absolut, nPos ); else - rc = osl_setFilePos( pInstanceData->rHandle, osl_Pos_End, 0 ); + rc = osl_setFilePos( mxFileHandle, osl_Pos_End, 0 ); if ( rc != osl_File_E_None ) { @@ -282,7 +268,7 @@ sal_uInt64 SvFileStream::SeekPos(sal_uInt64 const nPos) } if ( nPos != STREAM_SEEK_TO_END ) return nPos; - osl_getFilePos( pInstanceData->rHandle, &nNewPos ); + osl_getFilePos( mxFileHandle, &nNewPos ); return nNewPos; } SetError( SVSTREAM_GENERALERROR ); @@ -291,7 +277,7 @@ sal_uInt64 SvFileStream::SeekPos(sal_uInt64 const nPos) void SvFileStream::FlushData() { - auto rc = osl_syncFile(pInstanceData->rHandle); + auto rc = osl_syncFile(mxFileHandle); if (rc != osl_File_E_None) SetError( ::GetSvError( rc )); } @@ -335,10 +321,7 @@ bool SvFileStream::LockFile() if( !lockFile( this ) ) { -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "InternalLock on %s failed\n", - OUStringToOString(aFilename, osl_getThreadTextEncoding()).getStr() ); -#endif + SAL_WARN("tools.stream", "InternalLock on " << aFilename << "failed"); return false; } @@ -374,14 +357,20 @@ void SvFileStream::Open( const OUString& rFilename, StreamMode nOpenMode ) // FIXME: we really need to switch to a pure URL model ... if ( osl::File::getFileURLFromSystemPath( aFilename, aFileURL ) != osl::FileBase::E_None ) aFileURL = aFilename; - bool bStatValid = ( osl::DirectoryItem::get( aFileURL, aItem) == osl::FileBase::E_None && - aItem.getFileStatus( aStatus ) == osl::FileBase::E_None ); - // SvFileStream can't open a directory - if( bStatValid && aStatus.getFileType() == osl::FileStatus::Directory ) + // don't both stat()ing a temporary file, unnecessary + bool bStatValid = true; + if (!(nOpenMode & StreamMode::TEMPORARY)) { - SetError( ::GetSvError( EISDIR ) ); - return; + bStatValid = ( osl::DirectoryItem::get( aFileURL, aItem) == osl::FileBase::E_None && + aItem.getFileStatus( aStatus ) == osl::FileBase::E_None ); + + // SvFileStream can't open a directory + if( bStatValid && aStatus.getFileType() == osl::FileStatus::Directory ) + { + SetError( ::GetSvError( EISDIR ) ); + return; + } } if ( !( nOpenMode & StreamMode::WRITE ) ) @@ -411,14 +400,9 @@ void SvFileStream::Open( const OUString& rFilename, StreamMode nOpenMode ) if (osl::File::remove( aFileURL ) == osl::FileBase::E_None ) { File::copy( aStatus.getLinkTargetURL(), aFileURL ); -#if OSL_DEBUG_LEVEL > 0 - fprintf( stderr, - "Removing link and replacing with file contents (%s) -> (%s).\n", - OUStringToOString( aStatus.getLinkTargetURL(), - RTL_TEXTENCODING_UTF8).getStr(), - OUStringToOString( aFileURL, - RTL_TEXTENCODING_UTF8).getStr() ); -#endif + SAL_INFO("tools.stream", + "Removing link and replacing with file contents (" << + aStatus.getLinkTargetURL() << ") -> (" << aFileURL << ")."); } } } @@ -436,7 +420,7 @@ void SvFileStream::Open( const OUString& rFilename, StreamMode nOpenMode ) } if ( rc == osl_File_E_None ) { - pInstanceData->rHandle = nHandleTmp; + mxFileHandle = nHandleTmp; bIsOpen = true; if ( uFlags & osl_File_OpenFlag_Write ) m_isWritable = true; @@ -446,7 +430,7 @@ void SvFileStream::Open( const OUString& rFilename, StreamMode nOpenMode ) osl_closeFile( nHandleTmp ); bIsOpen = false; m_isWritable = false; - pInstanceData->rHandle = nullptr; + mxFileHandle = nullptr; } } else @@ -460,10 +444,9 @@ void SvFileStream::Close() if ( IsOpen() ) { SAL_INFO("tools", "Closing " << aFilename); - if ( !mbDontFlushOnClose ) - Flush(); - osl_closeFile( pInstanceData->rHandle ); - pInstanceData->rHandle = nullptr; + FlushBuffer(); + osl_closeFile( mxFileHandle ); + mxFileHandle = nullptr; } bIsOpen = false; @@ -482,7 +465,7 @@ void SvFileStream::SetSize (sal_uInt64 const nSize) { if (IsOpen()) { - oslFileError rc = osl_setFileSize( pInstanceData->rHandle, nSize ); + oslFileError rc = osl_setFileSize( mxFileHandle, nSize ); if (rc != osl_File_E_None ) { SetError ( ::GetSvError( rc )); diff --git a/tools/source/stream/strmwnt.cxx b/tools/source/stream/strmwnt.cxx index c91628b55091..d7d3a73ed2ce 100644 --- a/tools/source/stream/strmwnt.cxx +++ b/tools/source/stream/strmwnt.cxx @@ -36,16 +36,6 @@ #include <osl/file.hxx> using namespace osl; -class StreamData -{ -public: - HANDLE hFile; - - StreamData() : hFile(nullptr) - { - } -}; - static ErrCode GetSvError( DWORD nWntError ) { static struct { DWORD wnt; ErrCode sv; } errArr[] = @@ -107,8 +97,6 @@ SvFileStream::SvFileStream( const OUString& rFileName, StreamMode nMode ) bIsOpen = false; nLockCounter = 0; m_isWritable = false; - mbDontFlushOnClose = false; - pInstanceData.reset( new StreamData ); SetBufferSize( 8192 ); // convert URL to SystemPath, if necessary @@ -124,8 +112,6 @@ SvFileStream::SvFileStream() bIsOpen = false; nLockCounter = 0; m_isWritable = false; - mbDontFlushOnClose = false; - pInstanceData.reset( new StreamData ); SetBufferSize( 8192 ); } @@ -141,7 +127,7 @@ std::size_t SvFileStream::GetData( void* pData, std::size_t nSize ) DWORD nCount = 0; if( IsOpen() ) { - bool bResult = ReadFile(pInstanceData->hFile,pData,nSize,&nCount,nullptr); + bool bResult = ReadFile(mxFileHandle,pData,nSize,&nCount,nullptr); if( !bResult ) { std::size_t nTestError = GetLastError(); @@ -156,7 +142,7 @@ std::size_t SvFileStream::PutData( const void* pData, std::size_t nSize ) DWORD nCount = 0; if( IsOpen() ) { - if(!WriteFile(pInstanceData->hFile,pData,nSize,&nCount,nullptr)) + if(!WriteFile(mxFileHandle,pData,nSize,&nCount,nullptr)) SetError(::GetSvError( GetLastError() ) ); } return nCount; @@ -166,31 +152,36 @@ sal_uInt64 SvFileStream::SeekPos(sal_uInt64 const nPos) { // check if a truncated STREAM_SEEK_TO_END was passed assert(nPos != SAL_MAX_UINT32); - DWORD nNewPos = 0; + LARGE_INTEGER nNewPos, nActPos; + nNewPos.QuadPart = 0; + nActPos.QuadPart = nPos; + bool result = false; if( IsOpen() ) { if( nPos != STREAM_SEEK_TO_END ) - // 64-Bit files are not supported - nNewPos=SetFilePointer(pInstanceData->hFile,nPos,nullptr,FILE_BEGIN); + { + result = SetFilePointerEx(mxFileHandle, nActPos, &nNewPos, FILE_BEGIN); + } else - nNewPos=SetFilePointer(pInstanceData->hFile,0L,nullptr,FILE_END); - - if( nNewPos == 0xFFFFFFFF ) { - SetError(::GetSvError( GetLastError() ) ); - nNewPos = 0; + result = SetFilePointerEx(mxFileHandle, nNewPos, &nNewPos, FILE_END); + } + if (!result) + { + SetError(::GetSvError(GetLastError())); + return 0; } } else SetError( SVSTREAM_GENERALERROR ); - return static_cast<sal_uInt64>(nNewPos); + return static_cast<sal_uInt64>(nNewPos.QuadPart); } void SvFileStream::FlushData() { if( IsOpen() ) { - if( !FlushFileBuffers(pInstanceData->hFile) ) + if( !FlushFileBuffers(mxFileHandle) ) SetError(::GetSvError(GetLastError())); } } @@ -202,7 +193,7 @@ bool SvFileStream::LockFile() { if( IsOpen() ) { - bRetVal = ::LockFile(pInstanceData->hFile,0L,0L,LONG_MAX,0L ); + bRetVal = ::LockFile(mxFileHandle,0L,0L,LONG_MAX,0L ); if( bRetVal ) { nLockCounter = 1; @@ -227,7 +218,7 @@ void SvFileStream::UnlockFile() { if( IsOpen() ) { - if( ::UnlockFile(pInstanceData->hFile,0L,0L,LONG_MAX,0L ) ) + if( ::UnlockFile(mxFileHandle,0L,0L,LONG_MAX,0L ) ) { nLockCounter = 0; } @@ -306,8 +297,10 @@ void SvFileStream::Open( const OUString& rFilename, StreamMode nMode ) if ( nMode & StreamMode::TEMPORARY ) nAttributes |= FILE_ATTRIBUTE_TEMPORARY; + if ( nMode & StreamMode::DELETE_ON_CLOSE ) + nAttributes |= FILE_FLAG_DELETE_ON_CLOSE; - pInstanceData->hFile = CreateFileW( + mxFileHandle = CreateFileW( o3tl::toW(aFilename.getStr()), nAccessMode, nShareMode, @@ -317,7 +310,7 @@ void SvFileStream::Open( const OUString& rFilename, StreamMode nMode ) nullptr ); - if( pInstanceData->hFile!=INVALID_HANDLE_VALUE && ( + if( mxFileHandle!=INVALID_HANDLE_VALUE && ( // Did Create Always overwrite a file? GetLastError() == ERROR_ALREADY_EXISTS || // Did Create Always open a new file? @@ -329,7 +322,7 @@ void SvFileStream::Open( const OUString& rFilename, StreamMode nMode ) } // Otherwise, determine if we're allowed to read - if( (pInstanceData->hFile==INVALID_HANDLE_VALUE) && + if( (mxFileHandle==INVALID_HANDLE_VALUE) && (nAccessMode & GENERIC_WRITE)) { ErrCode nErr = ::GetSvError( GetLastError() ); @@ -341,7 +334,7 @@ void SvFileStream::Open( const OUString& rFilename, StreamMode nMode ) // if Openaction is CREATE_ALWAYS nOpenAction = OPEN_EXISTING; SetLastError( ERROR_SUCCESS ); - pInstanceData->hFile = CreateFileW( + mxFileHandle = CreateFileW( o3tl::toW(aFilename.getStr()), GENERIC_READ, nShareMode, @@ -379,9 +372,8 @@ void SvFileStream::Close() nLockCounter = 1; UnlockFile(); } - if ( !mbDontFlushOnClose ) - Flush(); - CloseHandle( pInstanceData->hFile ); + FlushBuffer(); + CloseHandle( mxFileHandle ); } bIsOpen = false; nLockCounter= 0; @@ -402,7 +394,7 @@ void SvFileStream::SetSize(sal_uInt64 const nSize) if( IsOpen() ) { bool bError = false; - HANDLE hFile = pInstanceData->hFile; + HANDLE hFile = mxFileHandle; DWORD const nOld = SetFilePointer( hFile, 0L, nullptr, FILE_CURRENT ); if( nOld != 0xffffffff ) { diff --git a/tools/source/xml/XmlWalker.cxx b/tools/source/xml/XmlWalker.cxx index c0e8a2abef48..f486cef36b34 100644 --- a/tools/source/xml/XmlWalker.cxx +++ b/tools/source/xml/XmlWalker.cxx @@ -59,14 +59,17 @@ bool XmlWalker::open(SvStream* pStream) return true; } -OString XmlWalker::name() { return reinterpret_cast<const char*>(mpImpl->mpCurrent->name); } +std::string_view XmlWalker::name() +{ + return reinterpret_cast<const char*>(mpImpl->mpCurrent->name); +} -OString XmlWalker::namespaceHref() +std::string_view XmlWalker::namespaceHref() { return reinterpret_cast<const char*>(mpImpl->mpCurrent->ns->href); } -OString XmlWalker::namespacePrefix() +std::string_view XmlWalker::namespacePrefix() { return reinterpret_cast<const char*>(mpImpl->mpCurrent->ns->prefix); } diff --git a/tools/source/xml/XmlWriter.cxx b/tools/source/xml/XmlWriter.cxx index 726b63966045..afc6dd9b73be 100644 --- a/tools/source/xml/XmlWriter.cxx +++ b/tools/source/xml/XmlWriter.cxx @@ -29,6 +29,15 @@ int funcCloseCallback(void* pContext) return 0; // 0 or -1 in case of error } +template <typename T> +requires(sizeof(T) == sizeof(char)) void attributeBase64_impl(xmlTextWriterPtr writer, + const char* name, const T* value, + int size) +{ + (void)xmlTextWriterStartAttribute(writer, BAD_CAST(name)); + (void)xmlTextWriterWriteBase64(writer, reinterpret_cast<const char*>(value), 0, size); + (void)xmlTextWriterEndAttribute(writer); +} } // end anonymous namespace struct XmlWriterImpl @@ -82,76 +91,61 @@ void XmlWriter::endDocument() void XmlWriter::startElement(const OString& sPrefix, const OString& sName, const OString& sNamespaceUri) { - xmlChar* xmlName = xmlCharStrdup(sName.getStr()); + xmlChar* xmlName = BAD_CAST(sName.getStr()); xmlChar* xmlPrefix = nullptr; xmlChar* xmlNamespaceUri = nullptr; if (!sPrefix.isEmpty()) - xmlPrefix = xmlCharStrdup(sPrefix.getStr()); + xmlPrefix = BAD_CAST(sPrefix.getStr()); if (!sNamespaceUri.isEmpty()) - xmlNamespaceUri = xmlCharStrdup(sNamespaceUri.getStr()); + xmlNamespaceUri = BAD_CAST(sNamespaceUri.getStr()); (void)xmlTextWriterStartElementNS(mpImpl->mpWriter, xmlPrefix, xmlName, xmlNamespaceUri); - - xmlFree(xmlName); - if (!sPrefix.isEmpty()) - xmlFree(xmlPrefix); - if (!sNamespaceUri.isEmpty()) - xmlFree(xmlNamespaceUri); } -void XmlWriter::startElement(const OString& sName) +void XmlWriter::startElement(const char* pName) { - xmlChar* xmlName = xmlCharStrdup(sName.getStr()); + xmlChar* xmlName = BAD_CAST(pName); (void)xmlTextWriterStartElement(mpImpl->mpWriter, xmlName); - xmlFree(xmlName); } void XmlWriter::endElement() { (void)xmlTextWriterEndElement(mpImpl->mpWriter); } -void XmlWriter::attributeBase64(const OString& rsName, std::vector<sal_uInt8> const& rValueInBytes) +void XmlWriter::attributeBase64(const char* pName, std::vector<sal_uInt8> const& rValueInBytes) { - std::vector<char> aSignedBytes(rValueInBytes.begin(), rValueInBytes.end()); - attributeBase64(rsName, aSignedBytes); + attributeBase64_impl(mpImpl->mpWriter, pName, rValueInBytes.data(), rValueInBytes.size()); } -void XmlWriter::attributeBase64(const OString& rsName, std::vector<char> const& rValueInBytes) +void XmlWriter::attributeBase64(const char* pName, std::vector<char> const& rValueInBytes) { - xmlChar* xmlName = xmlCharStrdup(rsName.getStr()); - (void)xmlTextWriterStartAttribute(mpImpl->mpWriter, xmlName); - (void)xmlTextWriterWriteBase64(mpImpl->mpWriter, rValueInBytes.data(), 0, rValueInBytes.size()); - (void)xmlTextWriterEndAttribute(mpImpl->mpWriter); - xmlFree(xmlName); + attributeBase64_impl(mpImpl->mpWriter, pName, rValueInBytes.data(), rValueInBytes.size()); } -void XmlWriter::attribute(const OString& name, const OString& value) +void XmlWriter::attribute(const char* name, const OString& value) { - xmlChar* xmlName = xmlCharStrdup(name.getStr()); - xmlChar* xmlValue = xmlCharStrdup(value.getStr()); + xmlChar* xmlName = BAD_CAST(name); + xmlChar* xmlValue = BAD_CAST(value.getStr()); (void)xmlTextWriterWriteAttribute(mpImpl->mpWriter, xmlName, xmlValue); - xmlFree(xmlValue); - xmlFree(xmlName); } -void XmlWriter::attribute(const OString& name, std::u16string_view value) +void XmlWriter::attribute(const char* name, std::u16string_view value) { - attribute(name, OUStringToOString(value, RTL_TEXTENCODING_UTF8).getStr()); + attribute(name, OUStringToOString(value, RTL_TEXTENCODING_UTF8)); } -void XmlWriter::attribute(const OString& name, const sal_Int32 aNumber) +void XmlWriter::attribute(const char* name, const sal_Int64 aNumber) { - attribute(name, OUString::number(aNumber)); + attribute(name, OString::number(aNumber)); } -void XmlWriter::attributeDouble(const OString& name, const double aNumber) +void XmlWriter::attributeDouble(const char* name, const double aNumber) { - attribute(name, OUString::number(aNumber)); + attribute(name, OString::number(aNumber)); } void XmlWriter::content(const OString& sValue) { - xmlChar* xmlValue = xmlCharStrdup(sValue.getStr()); + xmlChar* xmlValue = BAD_CAST(sValue.getStr()); (void)xmlTextWriterWriteString(mpImpl->mpWriter, xmlValue); - xmlFree(xmlValue); } void XmlWriter::content(std::u16string_view sValue) @@ -159,7 +153,7 @@ void XmlWriter::content(std::u16string_view sValue) content(OUStringToOString(sValue, RTL_TEXTENCODING_UTF8)); } -void XmlWriter::element(const OString& sName) +void XmlWriter::element(const char* sName) { startElement(sName); endElement(); diff --git a/tools/source/zcodec/zcodec.cxx b/tools/source/zcodec/zcodec.cxx index 97a03a463021..c925ecde8a2d 100644 --- a/tools/source/zcodec/zcodec.cxx +++ b/tools/source/zcodec/zcodec.cxx @@ -29,14 +29,15 @@ #include <tools/long.hxx> /* gzip flag byte */ -// GZ_ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define GZ_HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define GZ_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define GZ_ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define GZ_COMMENT 0x10 /* bit 4 set: file comment present */ -#define GZ_RESERVED 0xE0 /* bits 5..7: reserved */ - -const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */ +// GZ_ASCII_FLAG = 0x01; /* bit 0 set: file probably ascii text */ +constexpr sal_uInt8 GZ_HEAD_CRC = 0x02; /* bit 1 set: header CRC present */ +constexpr sal_uInt8 GZ_EXTRA_FIELD = 0x04; /* bit 2 set: extra field present */ +constexpr sal_uInt8 GZ_ORIG_NAME = 0x08; /* bit 3 set: original file name present */ +constexpr sal_uInt8 GZ_COMMENT = 0x10; /* bit 4 set: file comment present */ +constexpr sal_uInt8 GZ_RESERVED = 0xE0; /* bits 5..7: reserved */ +constexpr sal_uInt16 GZ_MAGIC_BYTES_LE = 0x8B1F; /* gzip magic bytes, little endian */ +constexpr sal_uInt8 GZ_DEFLATE = 0x08; +constexpr sal_uInt8 GZ_FS_UNKNOWN = 0xFF; ZCodec::ZCodec( size_t nInBufSize, size_t nOutBufSize ) : meState(STATE_INIT) @@ -46,6 +47,9 @@ ZCodec::ZCodec( size_t nInBufSize, size_t nOutBufSize ) , mnInToRead(0) , mpOStm(nullptr) , mnOutBufSize(nOutBufSize) + , mnUncompressedSize(0) + , mnInBufCRC32(0) + , mnLastModifiedTime(0) , mnCompressLevel(0) , mbGzLib(false) { @@ -58,6 +62,16 @@ ZCodec::~ZCodec() delete pStream; } +bool ZCodec::IsZCompressed( SvStream& rIStm ) +{ + sal_uInt64 nCurPos = rIStm.Tell(); + rIStm.Seek( 0 ); + sal_uInt16 nFirstTwoBytes = 0; + rIStm.ReadUInt16( nFirstTwoBytes ); + rIStm.Seek( nCurPos ); + return nFirstTwoBytes == GZ_MAGIC_BYTES_LE; +} + void ZCodec::BeginCompression( int nCompressLevel, bool gzLib ) { assert(meState == STATE_INIT); @@ -99,6 +113,25 @@ tools::Long ZCodec::EndCompression() retvalue = pStream->total_in; deflateEnd( pStream ); + if ( mbGzLib ) + { + // metadata must be set to compress as gz format + assert(!msFilename.isEmpty()); + // overwrite zlib checksum + mpOStm->Seek(STREAM_SEEK_TO_END); + mpOStm->SeekRel(-4); + mpOStm->WriteUInt32( mnInBufCRC32 ); // Uncompressed buffer CRC32 + mpOStm->WriteUInt32( mnUncompressedSize ); // Uncompressed size mod 2^32 + mpOStm->Seek( 0 ); + mpOStm->WriteUInt16( GZ_MAGIC_BYTES_LE ) // Magic bytes + .WriteUInt8( GZ_DEFLATE ) // Compression algorithm + .WriteUInt8( GZ_ORIG_NAME ) // Filename + .WriteUInt32( mnLastModifiedTime ) // Modification time + .WriteUInt8( 0 ) // Extra flags + .WriteUInt8( GZ_FS_UNKNOWN ) // Operating system + .WriteBytes( msFilename.pData->buffer, msFilename.pData->length ); + mpOStm->WriteUInt8( 0 ); // null terminate the filename string + } } else { @@ -112,10 +145,20 @@ tools::Long ZCodec::EndCompression() return mbStatus ? retvalue : -1; } +void ZCodec::SetCompressionMetadata( const OString& sFilename, sal_uInt32 nLastModifiedTime, sal_uInt32 nInBufCRC32 ) +{ + assert( mbGzLib ); + msFilename = sFilename; + mnLastModifiedTime = nLastModifiedTime; + mnInBufCRC32 = nInBufCRC32; +} + void ZCodec::Compress( SvStream& rIStm, SvStream& rOStm ) { assert(meState == STATE_INIT); mpOStm = &rOStm; + rIStm.Seek(0); + mnUncompressedSize = rIStm.TellEnd(); InitCompress(); mpInBuf.reset(new sal_uInt8[ mnInBufSize ]); auto pStream = static_cast<z_stream*>(mpsC_Stream); @@ -255,6 +298,14 @@ void ZCodec::ImplWriteBack() void ZCodec::InitCompress() { assert(meState == STATE_INIT); + if (mbGzLib) + { + // Seek just enough so that the zlib header is overwritten after compression + // with the gz header + // 10 header bytes + filename length + null terminator - 2 bytes for + // zlib header that gets overwritten + mpOStm->Seek(10 + msFilename.getLength() + 1 - 2); + } meState = STATE_COMPRESS; auto pStream = static_cast<z_stream*>(mpsC_Stream); mbStatus = deflateInit2_( @@ -272,12 +323,11 @@ void ZCodec::InitDecompress(SvStream & inStream) if ( mbStatus && mbGzLib ) { sal_uInt8 j, nMethod, nFlags; - for (int i : gz_magic) // gz - magic number - { - inStream.ReadUChar( j ); - if ( j != i ) - mbStatus = false; - } + sal_uInt16 nFirstTwoBytes; + inStream.Seek( 0 ); + inStream.ReadUInt16( nFirstTwoBytes ); + if ( nFirstTwoBytes != GZ_MAGIC_BYTES_LE ) + mbStatus = false; inStream.ReadUChar( nMethod ); inStream.ReadUChar( nFlags ); if ( nMethod != Z_DEFLATED ) |