Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/svl/zformat.hxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
#ifndef INCLUDED_SVL_ZFORMAT_HXX
20
#define INCLUDED_SVL_ZFORMAT_HXX
21
22
#include <svl/svldllapi.h>
23
#include <svl/zforlist.hxx>
24
#include <svl/nfkeytab.hxx>
25
#include <vector>
26
27
namespace utl {
28
    class DigitGroupingIterator;
29
}
30
31
namespace com::sun::star::i18n { struct NativeNumberXmlAttributes2; }
32
33
class Color;
34
class CalendarWrapper;
35
class LocaleDataWrapper;
36
enum class DateOrder;
37
38
class SvNFLanguageData;
39
40
class ImpSvNumberformatScan;            // format code string scanner
41
class ImpSvNumberInputScan;             // input string scanner
42
class NativeNumberWrapper;
43
class SvNFFormatData;
44
class SvNumberFormatter;
45
46
enum SvNumberformatLimitOps
47
{
48
    NUMBERFORMAT_OP_NO  = 0,            // Undefined, no OP
49
    NUMBERFORMAT_OP_EQ  = 1,            // Operator =
50
    NUMBERFORMAT_OP_NE  = 2,            // Operator <>
51
    NUMBERFORMAT_OP_LT  = 3,            // Operator <
52
    NUMBERFORMAT_OP_LE  = 4,            // Operator <=
53
    NUMBERFORMAT_OP_GT  = 5,            // Operator >
54
    NUMBERFORMAT_OP_GE  = 6             // Operator >=
55
};
56
57
struct ImpSvNumberformatInfo            // Struct for FormatInfo
58
{
59
    std::vector<OUString> sStrArray;    // Array of symbols
60
    std::vector<short> nTypeArray;      // Array of infos
61
    sal_uInt16 nThousand;               // Count of group separator sequences
62
    sal_uInt16 nCntPre;                 // Count of digits before decimal point
63
    sal_uInt16 nCntPost;                // Count of digits after decimal point
64
    sal_uInt16 nCntExp;                 // Count of exponent digits, or AM/PM
65
    SvNumFormatType eScannedType;       // Type determined by scan
66
    bool bThousand;                     // Has group (AKA thousand) separator
67
68
    void Copy( const ImpSvNumberformatInfo& rNumFor, sal_uInt16 nCount );
69
};
70
71
// NativeNumber, represent numbers using CJK or other digits if nNum>0,
72
// eLang specifies the Locale to use.
73
class SvNumberNatNum
74
{
75
    OUString sParams;               // For [NatNum12 ordinal-number]-like syntax
76
    LanguageType eLang;
77
    sal_uInt8            nNum;
78
    bool            bDBNum  :1;     // DBNum, to be converted to NatNum
79
    bool            bDate   :1;     // Used in date? (needed for DBNum/NatNum mapping)
80
    bool            bSet    :1;     // If set, since NatNum0 is possible
81
82
public:
83
84
    static  sal_uInt8    MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang, bool bDate );
85
    static  sal_uInt8    MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLang, bool bDate );
86
87
90.1M
                    SvNumberNatNum() : eLang( LANGUAGE_DONTKNOW ), nNum(0),
88
90.1M
                                        bDBNum(false), bDate(false), bSet(false) {}
89
98.8k
    bool            IsComplete() const  { return bSet && eLang != LANGUAGE_DONTKNOW; }
90
48.7M
    sal_uInt8       GetNatNum() const   { return bDBNum ? MapDBNumToNatNum( nNum, eLang, bDate ) : nNum; }
91
0
    sal_uInt8       GetDBNum() const    { return bDBNum ? nNum : MapNatNumToDBNum( nNum, eLang, bDate ); }
92
2.16M
    LanguageType    GetLang() const     { return eLang; }
93
2.10M
    void            SetLang( LanguageType e ) { eLang = e; }
94
    void            SetNum( sal_uInt8 nNumber, bool bDBNumber )
95
1.97M
                        {
96
1.97M
                            nNum = nNumber;
97
1.97M
                            bDBNum = bDBNumber;
98
1.97M
                            bSet = true;
99
1.97M
                        }
100
54.3M
    bool            IsSet() const       { return bSet; }
101
1.97M
    void            SetDate( bool bDateP )   { bDate = bDateP; }
102
1.92M
    void            SetParams(const OUString& s) { sParams = s; }
103
1.93M
    OUString const & GetParams() const { return sParams; }
104
};
105
106
class CharClass;
107
108
class ImpSvNumFor                       // One of four subformats of the format code string
109
{
110
public:
111
    ImpSvNumFor();                      // Ctor without filling the Info
112
    ~ImpSvNumFor();
113
114
    void Enlarge(sal_uInt16 nCount);    // Init of arrays to the right size
115
116
    // if pSc is set, it is used to get the Color pointer
117
    void Copy( const ImpSvNumFor& rNumFor, const ImpSvNumberformatScan* pSc );
118
119
    // Access to Info; call Enlarge before!
120
53.8M
    ImpSvNumberformatInfo& Info() { return aI;}
121
2.99M
    const ImpSvNumberformatInfo& Info() const { return aI; }
122
123
    // Get count of substrings (symbols)
124
25.1M
    sal_uInt16 GetCount() const { return nStringsCnt;}
125
126
1.86M
    const Color* GetColor() const { return pColor; }
127
    void SetColor(const Color* pCol, OUString const& rName)
128
1.54M
     { pColor = pCol; sColorName = rName; }
129
2.17k
    const OUString& GetColorName() const { return sColorName; }
130
131
    // new SYMBOLTYPE_CURRENCY in subformat?
132
    bool HasNewCurrency() const;
133
    bool GetNewCurrencySymbol( OUString& rSymbol, OUString& rExtension ) const;
134
135
    // [NatNum1], [NatNum2], ...
136
1.97M
    void SetNatNumNum( sal_uInt8 nNum, bool bDBNum ) { aNatNum.SetNum( nNum, bDBNum ); }
137
2.10M
    void SetNatNumLang( LanguageType eLang ) { aNatNum.SetLang( eLang ); }
138
1.97M
    void SetNatNumDate( bool bDate ) { aNatNum.SetDate( bDate ); }
139
1.92M
    void SetNatNumParams(const OUString& sParams) { aNatNum.SetParams(sParams); }
140
107M
    const SvNumberNatNum& GetNatNum() const { return aNatNum; }
141
142
private:
143
    ImpSvNumberformatInfo aI;           // helper struct for remaining information
144
    OUString sColorName;                // color name
145
    const Color* pColor;                      // pointer to color of subformat
146
    sal_uInt16 nStringsCnt;             // count of symbols
147
    SvNumberNatNum aNatNum;             // DoubleByteNumber
148
149
};
150
151
class SVL_DLLPUBLIC SvNumberformat
152
{
153
    struct SAL_DLLPRIVATE LocaleType
154
    {
155
        enum class Substitute : sal_uInt8
156
        {
157
            NONE,
158
            TIME,
159
            LONGDATE
160
        };
161
162
        LanguageType meLanguage;
163
        LanguageType meLanguageWithoutLocaleData;
164
        Substitute meSubstitute;
165
        sal_uInt8 mnNumeralShape;
166
        sal_uInt8 mnCalendarType;
167
168
        OUString generateCode() const;
169
170
        LocaleType();
171
        LocaleType(sal_uInt32 nRawCode);
172
173
        bool isPlainLocale() const;
174
    };
175
176
public:
177
    // Normal ctor
178
    SvNumberformat( OUString& rString,
179
                   ImpSvNumberformatScan* pSc,
180
                   ImpSvNumberInputScan* pISc,
181
                   const NativeNumberWrapper& rNatNum,
182
                   sal_Int32& nCheckPos,
183
                   LanguageType& eLan,
184
                   bool bReplaceBooleanEquivalent = true );
185
186
    // Copy ctor
187
    SvNumberformat( SvNumberformat const & rFormat );
188
189
    // Copy ctor with exchange of format code string scanner (used in merge)
190
    SvNumberformat( SvNumberformat const & rFormat, ImpSvNumberformatScan& rSc );
191
192
    ~SvNumberformat();
193
194
    /// Get type of format, may include css::util::NumberFormat::DEFINED bit
195
846k
    SvNumFormatType GetType() const             { return eType; }
196
197
    /// Get type of format, does not include css::util::NumberFormat::DEFINED
198
6.37M
    SvNumFormatType GetMaskedType() const       { return eType & ~SvNumFormatType::DEFINED; }
199
200
1.36M
    void SetType(SvNumFormatType eSetType)      { eType = eSetType; }
201
    // Standard means the I18N defined standard format of this type
202
2.17M
    void SetStandard()                          { bStandard = true; }
203
92.0M
    bool IsStandard() const                     { return bStandard; }
204
205
    // If this format is an additional built-in format defined by i18n.
206
6.74M
    void SetAdditionalBuiltin()                 { bAdditionalBuiltin = true; }
207
0
    bool IsAdditionalBuiltin() const            { return bAdditionalBuiltin; }
208
209
679M
    LanguageType GetLanguage() const            { return maLocale.meLanguage;}
210
211
    /** If the format is a placeholder and needs to be substituted. */
212
    bool IsSubstituted() const
213
25.8M
        {
214
25.8M
            return maLocale.meSubstitute != LocaleType::Substitute::NONE;
215
25.8M
        }
216
217
    /** If the format is a placeholder for the system time format and needs to
218
        be substituted during formatting time.
219
     */
220
    bool IsSystemTimeFormat() const
221
4.11k
        {
222
4.11k
            return maLocale.meSubstitute == LocaleType::Substitute::TIME && maLocale.meLanguage == LANGUAGE_SYSTEM;
223
4.11k
        }
224
225
    /** If the format is a placeholder for the system long date format and needs
226
        to be substituted during formatting time.
227
     */
228
    bool IsSystemLongDateFormat() const
229
2.54k
        {
230
2.54k
            return maLocale.meSubstitute == LocaleType::Substitute::LONGDATE && maLocale.meLanguage == LANGUAGE_SYSTEM;
231
2.54k
        }
232
233
    /** If the format is a MM:SS or [MM]:SS format, or MM:[SS] (sic!) or even
234
        MM:SS.00 or [MM]:SS.00 or MM:[SS].00
235
     */
236
    bool IsMinuteSecondFormat() const;
237
238
574M
    const OUString& GetFormatstring() const   { return sFormatstring; }
239
240
    // Build a format string of application defined keywords
241
    OUString GetMappedFormatstring( const NfKeywordTable& rKeywords,
242
                                    const LocaleDataWrapper& rLoc,
243
                                    LanguageType nOriginalLang = LANGUAGE_DONTKNOW,
244
                                    bool bSystemLanguage = false ) const;
245
246
    /**
247
     * Get output string from a numeric value that fits the number of
248
     * characters specified.
249
     */
250
    bool GetOutputString( double fNumber, sal_uInt16 nCharCount, OUString& rOutString,
251
                          const NativeNumberWrapper& rNatNum, const SvNFLanguageData& rCurrentLang ) const;
252
253
    // bStarFlag: Take *n format as ESC n
254
    bool GetOutputString( double fNumber, OUString& OutString, const Color** ppColor, const NativeNumberWrapper& rNatNum, const SvNFLanguageData& rCurrentLang, bool bStarFlag = false) const;
255
    void GetOutputString( std::u16string_view sString, OUString& OutString, const Color** ppColor, bool bStarFlag = false) const;
256
257
    // True if type text
258
642k
    bool IsTextFormat() const { return bool(eType & SvNumFormatType::TEXT); }
259
    // True if 4th subformat present
260
    bool HasTextFormat() const
261
493k
        {
262
493k
            return (NumFor[3].GetCount() > 0) ||
263
493k
                (NumFor[3].Info().eScannedType == SvNumFormatType::TEXT);
264
493k
        }
265
266
    void GetFormatSpecialInfo(bool& bThousand,
267
                              bool& IsRed,
268
                              sal_uInt16& nPrecision,
269
                              sal_uInt16& nLeadingCnt) const;
270
271
    /// Get index of subformat (0..3) according to conditions and fNumber value
272
    sal_uInt16 GetSubformatIndex( double fNumber ) const;
273
274
    /// Count of decimal precision
275
    sal_uInt16 GetFormatPrecision( sal_uInt16 nIx = 0 ) const
276
0
        { return NumFor[nIx].Info().nCntPost; }
277
278
    /// Count of integer digits
279
    sal_uInt16 GetFormatIntegerDigits( sal_uInt16 nIx = 0 ) const
280
0
        { return NumFor[nIx].Info().nCntPre; }
281
282
    /** Count of hidden integer digits with thousands divisor:
283
        formats like "0," to show only thousands.
284
285
        Works only with SvNumFormatType::NUMBER and SvNumFormatType::CURRENCY,
286
        returns 0 otherwise.
287
288
        Returns SvNumberFormatter::UNLIMITED_PRECISION for formats that contain
289
        the General keyword.
290
     */
291
    sal_uInt16 GetThousandDivisorPrecision( sal_uInt16 nIx = 0 ) const;
292
293
    //! Read/write access on a special sal_uInt16 component, may only be used on the
294
    //! standard format 0, 10000, ... and only by the number formatter!
295
1.08M
    struct FormatterPrivateAccess { friend SvNumberFormatter; friend SvNFFormatData; private: FormatterPrivateAccess() {} };
296
    sal_uInt16 GetLastInsertKey( const FormatterPrivateAccess& ) const
297
421k
        { return NumFor[0].Info().nThousand; }
298
    void SetLastInsertKey( sal_uInt16 nKey, const FormatterPrivateAccess& )
299
662k
        { NumFor[0].Info().nThousand = nKey; }
300
301
    //! Only onLoad: convert from stored to current system language/country
302
    void ConvertLanguage( SvNumberFormatter& rConverter,
303
        LanguageType eConvertFrom, LanguageType eConvertTo );
304
305
    // Substring of a subformat code nNumFor (0..3)
306
    // nPos == 0xFFFF => last substring
307
    // bString==true: first/last SYMBOLTYPE_STRING or SYMBOLTYPE_CURRENCY
308
    const OUString* GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos,
309
                                     bool bString = false ) const;
310
311
    // Subtype of a subformat code nNumFor (0..3)
312
    // nPos == 0xFFFF => last substring
313
    short GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos ) const;
314
315
    OUString GetPercentString( sal_uInt16 nNumFor = 0 ) const;
316
317
    OUString GetDenominatorString( sal_uInt16 nNumFor ) const;
318
    OUString GetNumeratorString( sal_uInt16 nNumFor ) const;
319
    OUString GetIntegerFractionDelimiterString( sal_uInt16 nNumFor ) const;
320
    /// Round fNumber to its fraction representation
321
    double GetRoundFractionValue ( double fNumber ) const;
322
323
    /// Create a format string for time with a new precision
324
    OUString GetFormatStringForTimePrecision( int nPrecision ) const;
325
326
327
    /** If the count of string elements (substrings, ignoring [modifiers] and
328
        so on) in a subformat code nNumFor (0..3) is equal to the given number.
329
        Used by ImpSvNumberInputScan::IsNumberFormatMain() to detect a matched
330
        format.  */
331
    bool IsNumForStringElementCountEqual( sal_uInt16 nNumFor, sal_uInt16 nAllCount,
332
            sal_uInt16 nNumCount ) const
333
22.4k
        {
334
22.4k
            if ( nNumFor < 4 )
335
22.4k
            {
336
                // First try a simple approach. Note that this is called only
337
                // if all MidStrings did match so far, to verify that all
338
                // strings of the format were matched and not just the starting
339
                // sequence, so we don't have to check if GetCount() includes
340
                // [modifiers] or anything else if both counts are equal.
341
22.4k
                sal_uInt16 nCnt = NumFor[nNumFor].GetCount();
342
22.4k
                if ( nAllCount == nCnt )
343
8.48k
                    return true;
344
13.9k
                if ( nAllCount < nCnt ) // check ignoring [modifiers] and so on
345
13.3k
                    return ImpGetNumForStringElementCount( nNumFor ) ==
346
13.3k
                        (nAllCount - nNumCount);
347
13.9k
            }
348
562
            return false;
349
22.4k
        }
350
    /** Get the count of numbers among string elements **/
351
    sal_uInt16 GetNumForNumberElementCount( sal_uInt16 nNumFor ) const;
352
353
    /** Get the scanned type of the specified subformat. */
354
    SvNumFormatType GetNumForInfoScannedType( sal_uInt16 nNumFor ) const
355
2.50k
    {
356
2.50k
        return (nNumFor < 4) ? NumFor[nNumFor].Info().eScannedType : SvNumFormatType::UNDEFINED;
357
2.50k
    }
358
359
    // Whether the second subformat code is really for negative numbers
360
    // or another limit set.
361
    bool IsSecondSubformatRealNegative() const
362
51.9k
        {
363
51.9k
            return fLimit1 == 0.0 && fLimit2 == 0.0 &&
364
51.0k
            ( (eOp1 == NUMBERFORMAT_OP_GE && eOp2 == NUMBERFORMAT_OP_NO) ||
365
23.3k
              (eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT) ||
366
13.6k
              (eOp1 == NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO) );
367
51.9k
        }
368
369
    // Whether the first subformat code is really for negative numbers
370
    // or another limit set.
371
    bool IsFirstSubformatRealNegative() const
372
702
        {
373
702
            return fLimit1 == 0.0 && fLimit2 == 0.0 &&
374
702
                ((eOp1 == NUMBERFORMAT_OP_LT &&
375
28
                  (eOp2 == NUMBERFORMAT_OP_GT || eOp2 == NUMBERFORMAT_OP_EQ ||
376
28
                   eOp2 == NUMBERFORMAT_OP_GE || eOp2 == NUMBERFORMAT_OP_NO)) ||
377
674
                 (eOp1 == NUMBERFORMAT_OP_LE &&
378
0
                  (eOp2 == NUMBERFORMAT_OP_NO || eOp2 == NUMBERFORMAT_OP_GT)));
379
702
        }
380
381
    // Whether the negative format is without a sign or not
382
    bool IsNegativeWithoutSign() const;
383
384
    bool IsNegativeInBracket() const;
385
386
    bool HasPositiveBracketPlaceholder() const;
387
388
    // Whether a new SYMBOLTYPE_CURRENCY is contained in the format
389
    bool HasNewCurrency() const;
390
391
    // strip [$-yyy] from all [$xxx-yyy] leaving only xxx's,
392
    static OUString StripNewCurrencyDelimiters( const OUString& rStr );
393
394
    // If a new SYMBOLTYPE_CURRENCY is contained if the format is of type
395
    // css::util::NumberFormat::CURRENCY, and if so the symbol xxx and the extension nnn
396
    // of [$xxx-nnn] are returned
397
    bool GetNewCurrencySymbol( OUString& rSymbol, OUString& rExtension ) const;
398
399
    static bool HasStringNegativeSign( const OUString& rStr );
400
401
    /**
402
        Whether a character at position nPos is somewhere between two matching
403
        cQuote or not.
404
        If nPos points to a cQuote, a true is returned on an opening cQuote,
405
        a false is returned on a closing cQuote.
406
        A cQuote between quotes may be escaped by a cEscIn, a cQuote outside of
407
        quotes may be escaped by a cEscOut.
408
        The default '\0' results in no escapement possible.
409
        Defaults are set right according to the "unlogic" of the Numberformatter
410
     */
411
    static bool IsInQuote( const OUString& rString, sal_Int32 nPos,
412
                           sal_Unicode cQuote = '"',
413
                           sal_Unicode cEscIn = '\0', sal_Unicode cEscOut = '\\' );
414
415
    /**
416
        Return the position of a matching closing cQuote if the character at
417
        position nPos is between two matching cQuote, otherwise return -1.
418
        If nPos points to an opening cQuote the position of the matching
419
        closing cQuote is returned.
420
        If nPos points to a closing cQuote nPos is returned.
421
        If nPos points into a part which starts with an opening cQuote but has
422
        no closing cQuote, rString.Len() is returned.
423
        Uses <method>IsInQuote</method> internally, so you don't have to call
424
        that prior to a call of this method.
425
     */
426
    static sal_Int32 GetQuoteEnd( const OUString& rString, sal_Int32 nPos,
427
                                  sal_Unicode cQuote = '"',
428
                                  sal_Unicode cEscIn = '\0' );
429
430
    void SetComment( const OUString& rStr )
431
723k
        { sComment = rStr; }
432
0
    const OUString& GetComment() const { return sComment; }
433
434
    /** Insert the number of blanks into the string that is needed to simulate
435
        the width of character c for underscore formats */
436
    static sal_Int32 InsertBlanks( OUString& r, sal_Int32 nPos, sal_Unicode c )
437
0
    {
438
0
        sal_Int32 result;
439
0
        OUStringBuffer sBuff(r);
440
0
441
0
        result = InsertBlanks(sBuff, nPos, c);
442
0
        r = sBuff.makeStringAndClear();
443
0
444
0
        return result;
445
0
    }
446
447
    /** Insert the number of blanks into the string that is needed to simulate
448
        the width of character c for underscore formats */
449
    static sal_Int32 InsertBlanks( OUStringBuffer& r, sal_Int32 nPos, sal_Unicode c );
450
451
    /// One of YMD,DMY,MDY if date format
452
    DateOrder GetDateOrder() const;
453
454
    /** A coded value of the exact YMD combination used, if date format.
455
        For example: YYYY-MM-DD => ('Y' << 16) | ('M' << 8) | 'D'
456
        or: MM/YY => ('M' << 8) | 'Y'  */
457
    sal_uInt32 GetExactDateOrder() const;
458
459
    // used in XML export
460
    void GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1,
461
                        SvNumberformatLimitOps& rOper2, double& rVal2 ) const;
462
    const Color* GetColor( sal_uInt16 nNumFor ) const;
463
    void GetNumForInfo( sal_uInt16 nNumFor, SvNumFormatType& rScannedType,
464
                    bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& nLeadingCnt ) const;
465
466
    // rAttr.Number not empty if NatNum attributes are to be stored
467
    void GetNatNumXml(
468
            css::i18n::NativeNumberXmlAttributes2& rAttr,
469
            sal_uInt16 nNumFor,
470
            const NativeNumberWrapper& rNatNum ) const;
471
    /** Return empty string if no NatNum modifier or invalid nNumFor
472
        otherwise return "[NatNum1]" or "[NatNum12 ...]" */
473
    OUString GetNatNumModifierString( sal_uInt16 nNumFor = 0 ) const;
474
475
    /** Switches to the first non-"gregorian" calendar, but only if the current
476
        calendar is "gregorian"; original calendar name and date/time returned,
477
        but only if calendar switched and rOrgCalendar was empty. */
478
    static void SwitchToOtherCalendar( const SvNFLanguageData& rCurrentLang, OUString& rOrgCalendar, double& fOrgDateTime, CalendarWrapper& rCal );
479
480
    /** Switches to the "gregorian" calendar, but only if the current calendar
481
        is non-"gregorian" and rOrgCalendar is not empty. Thus a preceding
482
        ImpSwitchToOtherCalendar() call should have been placed prior to
483
        calling this method. */
484
    static void SwitchToGregorianCalendar( const SvNFLanguageData& rCurrentLang, std::u16string_view rOrgCalendar, double fOrgDateTime, CalendarWrapper& rCal );
485
486
#ifdef THE_FUTURE
487
    /** Switches to the first specified calendar, if any, in subformat nNumFor
488
        (0..3). Original calendar name and date/time returned, but only if
489
        calendar switched and rOrgCalendar was empty.
490
491
        @return
492
            <TRUE/> if a calendar was specified and switched to,
493
            <FALSE/> else.
494
     */
495
    bool SwitchToSpecifiedCalendar( const SvNFLanguageData& rCurrentLang, OUString& rOrgCalendar, double& fOrgDateTime,
496
            sal_uInt16 nNumFor ) const
497
        {
498
            if ( nNumFor < 4 )
499
                return ImpSwitchToSpecifiedCalendar( rCurrentLang, rOrgCalendar,
500
                        fOrgDateTime, NumFor[nNumFor] );
501
            return false;
502
        }
503
#endif
504
505
    /// Whether it's a (YY)YY-M(M)-D(D) format.
506
    bool IsIso8601( sal_uInt16 nNumFor ) const
507
710
        {
508
710
            if ( nNumFor < 4 )
509
710
                return ImpIsIso8601( NumFor[nNumFor]);
510
0
            return false;
511
710
        }
512
513
private:
514
    ImpSvNumFor NumFor[4];          // Array for the 4 subformats
515
    OUString sFormatstring;         // The format code string
516
    OUString sComment;                // Comment, since number formatter version 6
517
    double fLimit1;                 // Value for first condition
518
    double fLimit2;                 // Value for second condition
519
    ImpSvNumberformatScan& rScan;   // Format code scanner
520
    LocaleType maLocale;            // Language/country of the format, numeral shape and calendar type from Excel.
521
    SvNumberformatLimitOps eOp1;    // Operator for first condition
522
    SvNumberformatLimitOps eOp2;    // Operator for second condition
523
    SvNumFormatType eType;          // Type of format
524
    bool bAdditionalBuiltin;        // If this is an additional built-in format defined by i18n
525
    bool bStandard;                 // If this is a default standard format
526
    bool bIsUsed;                   // Flag as used for storing
527
528
    SVL_DLLPRIVATE sal_uInt16 ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const;
529
530
#ifdef THE_FUTURE
531
    SVL_DLLPRIVATE bool ImpSwitchToSpecifiedCalendar( const SvNFLanguageData& rCurrentLang,
532
                                                      OUString& rOrgCalendar,
533
                                                      double& fOrgDateTime,
534
                                                      const ImpSvNumFor& rNumFor ) const;
535
#endif
536
537
    /** Whether to use possessive genitive case month name, or partitive case
538
        month name, instead of nominative name (noun).
539
540
        @param io_nState
541
            0: execute check <br>
542
               set to 1 if nominative case is returned, <br>
543
               set to 2 if genitive case is returned, <br>
544
               set to 3 if partitive case is returned <br>
545
            1: don't execute check, return nominative case <br>
546
            2: don't execute check, return genitive case <br>
547
            3: don't execute check, return partitive case <br>
548
549
        @param eCodeType
550
            a NfKeywordIndex, must designate a month type code
551
552
        @returns one of css::i18n::CalendarDisplayCode values
553
            according to eCodeType and the check executed (or passed).
554
     */
555
    SVL_DLLPRIVATE static sal_Int32 ImpUseMonthCase( int & io_nState, const ImpSvNumFor& rNumFor, NfKeywordIndex eCodeType );
556
557
    /// Whether it's a (YY)YY-M(M)-D(D) format.
558
    SVL_DLLPRIVATE bool ImpIsIso8601( const ImpSvNumFor& rNumFor ) const;
559
560
    const CharClass& rChrCls() const;
561
    const LocaleDataWrapper& rLoc() const;
562
563
    // divide in substrings and color conditions
564
    SVL_DLLPRIVATE short ImpNextSymbol( OUStringBuffer& rString,
565
                                        sal_Int32& nPos,
566
                                        OUString& sSymbol ) const;
567
568
    // read string until ']' and strip blanks (after condition)
569
    SVL_DLLPRIVATE static sal_Int32 ImpGetNumber( OUStringBuffer& rString,
570
                                                  sal_Int32& nPos,
571
                                                  OUString& sSymbol );
572
573
    /**
574
     * Parse the content of '[$-xxx] or '[$-xxxxxxxx]' and extract the locale
575
     * type from it.  Given the string, start parsing at position specified by
576
     * nPos, and store the end position with nPos when the parsing is
577
     * complete.  The nPos should point to the '$' before the parsing, and to
578
     * the closing bracket after the parsing.  When the content is [$-xxx],
579
     * the xxx part represents the language type (aka LCID) in hex numerals.
580
     * When the content is [$-xxxxxxxx] the last 4 digits represent the LCID
581
     * (again in hex), the next 2 digits represent the calendar type, and the
582
     * 2 highest digits (if exists) is the numeral shape.
583
     *
584
     * @reference
585
     * http://office.microsoft.com/en-us/excel-help/creating-international-number-formats-HA001034635.aspx
586
     *
587
     * @param rString input string
588
     * @param nPos position (see above).
589
     *
590
     * @return struct containing numeral shape, calendar type, and LCID that
591
     *         specifies language type. See i18nlangtag/lang.h for a complete
592
     *         list of language types. These numbers also correspond with the
593
     *         numbers used by Microsoft Office.
594
     */
595
    SVL_DLLPRIVATE static LocaleType ImpGetLocaleType( std::u16string_view rString, sal_Int32& nPos );
596
597
    /** Obtain calendar and numerals from a LocaleType that was parsed from a
598
        LCID with ImpGetLocaleType().
599
600
        Inserts a NatNum modifier to rString at nPos if needed as determined
601
        from the numeral code.
602
603
        @ATTENTION: may modify <member>maLocale</member> to make it follow
604
        aTmpLocale, in which case also nLang is adapted.
605
606
        @returns a string with the calendar if one was determined from the
607
        calendar code, else an empty string. The calendar string needs to be
608
        inserted at a proper position to rString after all bracketed prefixes.
609
     */
610
    SVL_DLLPRIVATE OUString ImpObtainCalendarAndNumerals( OUStringBuffer & rString,
611
                                                          sal_Int32 nPos,
612
                                                          LanguageType & nLang,
613
                                                          const LocaleType & aTmpLocale );
614
615
    // standard number output
616
    SVL_DLLPRIVATE void ImpGetOutputStandard(double& fNumber, OUString& OutString,
617
                                             const NativeNumberWrapper& rNatNum,
618
                                             const SvNFLanguageData& rCurrentLang) const;
619
    SVL_DLLPRIVATE void ImpGetOutputStandard(double& fNumber, OUStringBuffer& OutString,
620
                                             const NativeNumberWrapper& rNatNum,
621
                                             const SvNFLanguageData& rCurrentLang) const;
622
    SVL_DLLPRIVATE void ImpGetOutputStdToPrecision(double& rNumber, OUString& rOutString, sal_uInt16 nPrecision,
623
                                                   const NativeNumberWrapper& rNatNum,
624
                                                   const SvNFLanguageData& rCurrentLang) const;
625
    // numbers in input line
626
    SVL_DLLPRIVATE void ImpGetOutputInputLine( double fNumber, OUString& OutString,
627
                                               const SvNFLanguageData& rCurrentLang ) const;
628
629
    // check subcondition
630
    // OP undefined => -1
631
    // else 0 or 1
632
    SVL_DLLPRIVATE static short ImpCheckCondition(double fNumber,
633
                         double fLimit,
634
                         SvNumberformatLimitOps eOp);
635
636
    // Helper function for number strings
637
    // append string symbols, insert leading 0 or ' ', or ...
638
    SVL_DLLPRIVATE bool ImpNumberFill(
639
                    const NativeNumberWrapper& rNatNum,
640
                    const SvNFLanguageData& rCurrentLang,
641
                    OUStringBuffer& sStr,
642
                    double& rNumber,
643
                    sal_Int32& k,
644
                    sal_uInt16& j,
645
                    sal_uInt16 nIx,
646
                    short eSymbolType,
647
                    bool bStarFlag,
648
                    bool bInsertRightBlank = false ) const;
649
650
    // Helper function to fill in the integer part and the group (AKA thousand) separators
651
    SVL_DLLPRIVATE bool ImpNumberFillWithThousands(
652
                                 const NativeNumberWrapper& rNatNum,
653
                                 const SvNFLanguageData& rCurrentLang,
654
                                 OUStringBuffer& sStr,
655
                                 double& rNumber,
656
                                 sal_Int32 k,
657
                                 sal_uInt16 j,
658
                                 sal_uInt16 nIx,
659
                                 sal_Int32 nDigCnt,
660
                                 bool bStarFlag,
661
                                 bool bAddDecSep = true ) const;
662
663
    // Helper function to fill in the group (AKA thousand) separators
664
    // or to skip additional digits
665
    SVL_DLLPRIVATE void ImpDigitFill( const SvNFLanguageData& rCurrentLang,
666
                                      OUStringBuffer& sStr,
667
                                      sal_Int32 nStart,
668
                                      sal_Int32& k,
669
                                      sal_uInt16 nIx,
670
                                      sal_Int32 & nDigitCount,
671
                                      utl::DigitGroupingIterator & ) const;
672
673
    SVL_DLLPRIVATE bool ImpDecimalFill(const NativeNumberWrapper& rNatNum,
674
                                 const SvNFLanguageData& rCurrentLang,
675
                                 OUStringBuffer& sStr,
676
                                 double& rNumber,
677
                                 sal_Int32 nDecPos,
678
                                 sal_uInt16 j,
679
                                 sal_uInt16 nIx,
680
                                 bool bInteger,
681
                                 bool bStarFlag) const;
682
683
    /** Calculate each element of fraction:
684
     * integer part, numerator part, denominator part
685
     * @param fNumber value to be represented as fraction. Will contain absolute fractional part
686
     * @param nIx subformat number 0..3
687
     * @param fIntPart integral part of fraction
688
     * @param nFrac numerator of fraction
689
     * @param nDic denominator of fraction
690
     */
691
    SVL_DLLPRIVATE void ImpGetFractionElements( double& fNumber,
692
                                                sal_uInt16 nIx,
693
                                                double& fIntPart,
694
                                                sal_Int64& nFrac,
695
                                                sal_Int64& nDiv ) const;
696
    SVL_DLLPRIVATE bool ImpGetFractionOutput(double fNumber,
697
                                             sal_uInt16 nIx,
698
                                             bool bStarFlag,
699
                                             const NativeNumberWrapper& rNatNum,
700
                                             const SvNFLanguageData& rCurrentLang,
701
                                             OUStringBuffer& OutString) const;
702
    SVL_DLLPRIVATE bool ImpGetScientificOutput(double fNumber,
703
                                               sal_uInt16 nIx,
704
                                               bool bStarFlag,
705
                                               const NativeNumberWrapper& rNatNum,
706
                                               const SvNFLanguageData& rCurrentLang,
707
                                               OUStringBuffer& OutString) const;
708
709
    SVL_DLLPRIVATE bool ImpGetDateOutput( double fNumber,
710
                                          sal_uInt16 nIx,
711
                                          bool bStarFlag,
712
                                          const NativeNumberWrapper& rNatNum,
713
                                          const SvNFLanguageData& rCurrentLang,
714
                                          OUStringBuffer& OutString ) const;
715
    SVL_DLLPRIVATE bool ImpGetTimeOutput( double fNumber,
716
                                          sal_uInt16 nIx,
717
                                          bool bStarFlag,
718
                                          const NativeNumberWrapper& rNatNum,
719
                                          const SvNFLanguageData& rCurrentLang,
720
                                          OUStringBuffer& OutString ) const;
721
    SVL_DLLPRIVATE bool ImpGetDateTimeOutput( double fNumber,
722
                                              sal_uInt16 nIx,
723
                                              bool bStarFlag,
724
                                              const NativeNumberWrapper& rNatNum,
725
                                              const SvNFLanguageData& rCurrentLang,
726
                                              OUStringBuffer& OutString ) const;
727
728
    // Switches to the "gregorian" calendar if the current calendar is
729
    // non-"gregorian" and the era is a "Dummy" era of a calendar which doesn't
730
    // know a "before" era (like zh_TW ROC or ja_JP Gengou). If switched and
731
    // rOrgCalendar was "gregorian" the string is emptied. If rOrgCalendar was
732
    // empty the previous calendar name and date/time are returned.
733
    SVL_DLLPRIVATE static bool ImpFallBackToGregorianCalendar(const SvNFLanguageData& rCurrentLang,
734
                                                       OUString& rOrgCalendar,
735
                                                       double& fOrgDateTime,
736
                                                       CalendarWrapper& rCal);
737
738
    // Append a "G" short era string of the given calendar. In the case of a
739
    // Gengou calendar this is a one character abbreviation, for other
740
    // calendars the XExtendedCalendar::getDisplayString() method is called.
741
    SVL_DLLPRIVATE static void ImpAppendEraG( OUStringBuffer& OutStringBuffer, const CalendarWrapper& rCal,
742
                                              sal_Int16 nNatNum );
743
744
    SVL_DLLPRIVATE bool ImpGetLogicalOutput( double fNumber,
745
                                             sal_uInt16 nIx,
746
                                             const NativeNumberWrapper& rNatNum,
747
                                             const SvNFLanguageData& rCurrentLang,
748
                                             OUStringBuffer& OutString) const;
749
750
    SVL_DLLPRIVATE bool ImpGetNumberOutput( double fNumber,
751
                                            sal_uInt16 nIx,
752
                                            bool bStarFlag,
753
                                            const NativeNumberWrapper& rNatNum,
754
                                            const SvNFLanguageData& rCurrentLang,
755
                                            OUStringBuffer& OutString) const;
756
757
    SVL_DLLPRIVATE void ImpCopyNumberformat( const SvNumberformat& rFormat );
758
759
    // normal digits or other digits, depending on ImpSvNumFor.aNatNum,
760
    // [NatNum1], [NatNum2], ...
761
    SVL_DLLPRIVATE static OUString ImpGetNatNumString(const SvNumberNatNum& rNum, sal_Int64 nVal,
762
                                                      sal_uInt16 nMinDigits, const NativeNumberWrapper& rNatNum);
763
764
    OUString ImpIntToString(const NativeNumberWrapper& rNatNum, sal_uInt16 nIx, sal_Int64 nVal, sal_uInt16 nMinDigits = 0 ) const
765
22.4k
    {
766
22.4k
        const SvNumberNatNum& rNum = NumFor[nIx].GetNatNum();
767
22.4k
        if ( nMinDigits || rNum.IsComplete() )
768
11.5k
        {
769
11.5k
            return ImpGetNatNumString( rNum, nVal, nMinDigits, rNatNum );
770
11.5k
        }
771
10.8k
        return OUString::number(nVal);
772
22.4k
    }
773
774
    // Obtain the string of the fraction of second, without leading "0.",
775
    // rounded to nFractionDecimals (or nFractionDecimals+1 if
776
    // bAddOneRoundingDecimal==true but then truncated at nFractionDecimals,
777
    // for use with the result of tools::Time::GetClock()) with the length of
778
    // nFractionDecimals, unless nMinimumInputLineDecimals>0 is given for input
779
    // line string where extra trailing "0" are discarded.
780
    SVL_DLLPRIVATE sal_uInt16 ImpGetFractionOfSecondString( OUStringBuffer& rBuf, double fFractionOfSecond,
781
            int nFractionDecimals, bool bAddOneRoundingDecimal, sal_uInt16 nIx, sal_uInt16 nMinimumInputLineDecimals,
782
            const NativeNumberWrapper& rNatNum) const;
783
784
    // transliterate according to NativeNumber
785
    SVL_DLLPRIVATE static OUString impTransliterateImpl(const OUString& rStr, const SvNumberNatNum& rNum, sal_uInt16 nDateKey,
786
                                                    const NativeNumberWrapper& rNatNum, const SvNFLanguageData& rCurrentLang);
787
788
    OUString static impTransliterate(const OUString& rStr, const SvNumberNatNum& rNum, sal_uInt16 nDateKey,
789
                              const NativeNumberWrapper& rNatNum, const SvNFLanguageData& rCurrentLang)
790
0
    {
791
0
        return rNum.IsComplete() ? impTransliterateImpl(rStr, rNum, nDateKey, rNatNum, rCurrentLang) : rStr;
792
0
    }
793
794
};
795
796
#endif // INCLUDED_SVL_ZFORMAT_HXX
797
798
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */