source: filezilla/trunk/fuentes/src/engine/sizeformatting_base.cpp @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 3 years ago

First release to xenial

File size: 6.1 KB
Line 
1#include <filezilla.h>
2#include "sizeformatting_base.h"
3#include "optionsbase.h"
4#ifndef __WXMSW__
5#include <langinfo.h>
6#endif
7
8namespace {
9const wxChar prefix[] = { ' ', 'K', 'M', 'G', 'T', 'P', 'E' };
10
11wxString ToString(int64_t n, wxChar const* const sepBegin = 0, wxChar const* const sepEnd = 0)
12{
13        wxString ret;
14        if (!n) {
15                ret = _T("0");
16        }
17        else {
18                bool neg = false;
19                if (n < 0) {
20                        n *= -1;
21                        neg = true;
22                }
23
24                wxChar buf[60];
25                wxChar * const end = &buf[sizeof(buf) / sizeof(wxChar) - 1];
26                wxChar * p = end;
27
28                int d = 0;
29                while (n != 0) {
30                        *--p = '0' + n % 10;
31                        n /= 10;
32
33                        if (sepBegin && !(++d % 3) && n != 0) {
34                                wxChar *q = p - (sepEnd - sepBegin);
35                                for (wxChar const* s = sepBegin; s != sepEnd; ++s) {
36                                        *q++ = *s;
37                                }
38                                p -= sepEnd - sepBegin;
39                        }
40                }
41
42                if (neg) {
43                        *--p = '-';
44                }
45
46                ret.assign(p, end - p);
47        }
48        return ret;
49}
50}
51
52wxString CSizeFormatBase::Format(COptionsBase* pOptions, int64_t size, bool add_bytes_suffix, CSizeFormatBase::_format format, bool thousands_separator, int num_decimal_places)
53{
54        wxASSERT(format != formats_count);
55        wxASSERT(size >= 0);
56        if( size < 0 ) {
57                size = 0;
58        }
59
60        if (format == bytes) {
61                wxString result = FormatNumber(pOptions, size, &thousands_separator);
62
63                if (!add_bytes_suffix)
64                        return result;
65                else {
66                        return wxString::Format(wxPLURAL_LL("%s byte", "%s bytes", size), result);
67                }
68        }
69
70        wxString places;
71
72        int divider;
73        if (format == si1000)
74                divider = 1000;
75        else
76                divider = 1024;
77
78        // Exponent (2^(10p) or 10^(3p) depending on option
79        int p = 0;
80
81        int64_t r = size;
82        int remainder = 0;
83        bool clipped = false;
84        while (r > divider && p < 6) {
85                int64_t const rr = r / divider;
86                if (remainder != 0)
87                        clipped = true;
88                remainder = static_cast<int>(r - rr * divider);
89                r = rr;
90                ++p;
91        }
92        if (!num_decimal_places) {
93                if (remainder != 0 || clipped)
94                        ++r;
95        }
96        else if (p) { // Don't add decimal places on exact bytes
97                if (format != si1000) {
98                        // Binary, need to convert 1024 into range from 1-1000
99                        if (clipped) {
100                                ++remainder;
101                                clipped = false;
102                        }
103                        remainder = (int)ceil((double)remainder * 1000 / 1024);
104                }
105
106                int max;
107                switch (num_decimal_places)
108                {
109                default:
110                        num_decimal_places = 1;
111                        // Fall-through
112                case 1:
113                        max = 9;
114                        divider = 100;
115                        break;
116                case 2:
117                        max = 99;
118                        divider = 10;
119                        break;
120                case 3:
121                        max = 999;
122                        break;
123                }
124
125                if (num_decimal_places != 3) {
126                        if (remainder % divider)
127                                clipped = true;
128                        remainder /= divider;
129                }
130
131                if (clipped)
132                        remainder++;
133                if (remainder > max) {
134                        r++;
135                        remainder = 0;
136                }
137
138                wxChar fmt[] = _T("%00d");
139                fmt[2] = '0' + num_decimal_places;
140                places.Printf(fmt, remainder);
141        }
142
143        wxString result = ToString(r, 0, 0);
144        if (!places.empty()) {
145                const wxString& sep = GetRadixSeparator();
146
147                result += sep;
148                result += places;
149        }
150        result += ' ';
151
152        static wxChar byte_unit = 0;
153        if (!byte_unit) {
154                wxString t = _("B <Unit symbol for bytes. Only translate first letter>");
155                byte_unit = t[0];
156        }
157
158        if (!p)
159                return result + byte_unit;
160
161        result += prefix[p];
162        if (format == iec)
163                result += 'i';
164
165        result += byte_unit;
166
167        return result;
168}
169
170wxString CSizeFormatBase::Format(COptionsBase* pOptions, int64_t size, bool add_bytes_suffix /*=false*/)
171{
172        const _format format = _format(pOptions->GetOptionVal(OPTION_SIZE_FORMAT));
173        const bool thousands_separator = pOptions->GetOptionVal(OPTION_SIZE_USETHOUSANDSEP) != 0;
174        const int num_decimal_places = pOptions->GetOptionVal(OPTION_SIZE_DECIMALPLACES);
175
176        return Format(pOptions, size, add_bytes_suffix, format, thousands_separator, num_decimal_places);
177}
178
179wxString CSizeFormatBase::FormatUnit(COptionsBase* pOptions, int64_t size, CSizeFormatBase::_unit unit, int base /*=1024*/)
180{
181        _format format = _format(pOptions->GetOptionVal(OPTION_SIZE_FORMAT));
182        if (base == 1000)
183                format = si1000;
184        else if (format != si1024)
185                format = iec;
186        return wxString::Format(_T("%s %s"), FormatNumber(pOptions, size), GetUnit(pOptions, unit, format));
187}
188
189wxString CSizeFormatBase::GetUnitWithBase(COptionsBase* pOptions, _unit unit, int base)
190{
191        _format format = _format(pOptions->GetOptionVal(OPTION_SIZE_FORMAT));
192        if (base == 1000)
193                format = si1000;
194        else if (format != si1024)
195                format = iec;
196        return GetUnit(pOptions, unit, format);
197}
198
199wxString CSizeFormatBase::GetUnit(COptionsBase* pOptions, _unit unit, CSizeFormatBase::_format format /*=formats_count*/)
200{
201        wxString ret;
202        if (unit != byte)
203                ret = prefix[unit];
204
205        if (format == formats_count)
206                format = _format(pOptions->GetOptionVal(OPTION_SIZE_FORMAT));
207        if (format == iec || format == bytes)
208                ret += 'i';
209
210        static wxChar byte_unit = 0;
211        if (!byte_unit)
212        {
213                wxString t = _("B <Unit symbol for bytes. Only translate first letter>");
214                byte_unit = t[0];
215        }
216
217        ret += byte_unit;
218
219        return ret;
220}
221
222const wxString& CSizeFormatBase::GetThousandsSeparator()
223{
224        static wxString sep;
225        static bool separator_initialized = false;
226        if (!separator_initialized)
227        {
228                separator_initialized = true;
229#ifdef __WXMSW__
230                wxChar tmp[5];
231                int count = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, tmp, 5);
232                if (count)
233                        sep = tmp;
234#else
235                char* chr = nl_langinfo(THOUSEP);
236                if (chr && *chr)
237                {
238                        sep = wxString(chr, wxConvLibc);
239                }
240#endif
241                if (sep.size() > 5) {
242                        sep = sep.Left(5);
243                }
244        }
245
246        return sep;
247}
248
249const wxString& CSizeFormatBase::GetRadixSeparator()
250{
251        static wxString sep;
252        static bool separator_initialized = false;
253        if (!separator_initialized)
254        {
255                separator_initialized = true;
256
257#ifdef __WXMSW__
258                wxChar tmp[5];
259                int count = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, tmp, 5);
260                if (!count)
261                        sep = _T(".");
262                else
263                {
264                        tmp[4] = 0;
265                        sep = tmp;
266                }
267#else
268                char* chr = nl_langinfo(RADIXCHAR);
269                if (!chr || !*chr)
270                        sep = _T(".");
271                else
272                {
273                        sep = wxString(chr, wxConvLibc);
274                }
275#endif
276        }
277
278        return sep;
279}
280
281wxString CSizeFormatBase::FormatNumber(COptionsBase* pOptions, int64_t size, bool* thousands_separator /*=0*/)
282{
283        wxString sep;
284        wxChar const* sepBegin = 0;
285        wxChar const* sepEnd = 0;
286
287        if ((!thousands_separator || *thousands_separator) && pOptions->GetOptionVal(OPTION_SIZE_USETHOUSANDSEP) != 0) {
288                sep = GetThousandsSeparator();
289                if (!sep.empty()) {
290                        sepBegin = sep.c_str();
291                        sepEnd = sepBegin + sep.size();
292                }
293        }
294
295        return ToString(size, sepBegin, sepEnd);
296}
Note: See TracBrowser for help on using the repository browser.