std::wstring CSizeFormatBase::Format(COptionsBase* pOptions, int64_t size, bool add_bytes_suffix, CSizeFormatBase::_format format, bool thousands_separator, int num_decimal_places)
{
	assert(format != formats_count);
	assert(size >= 0);
	if (size < 0) {
		size = 0;
	}

	if (format == bytes) {
		std::wstring result = FormatNumber(pOptions, size, &thousands_separator);

		if (!add_bytes_suffix) {
			return result;
		}
		else {
			return fz::sprintf(fztranslate("%s byte", "%s bytes", size), result);
		}
	}

	std::wstring places;

	int divider;
	if (format == si1000) {
		divider = 1000;
	}
	else {
		divider = 1024;
	}

	// Exponent (2^(10p) or 10^(3p) depending on option
	int p = 0;

	int64_t r = size;
	int remainder = 0;
	bool clipped = false;
	while (r > divider && p < 6) {
		int64_t const rr = r / divider;
		if (remainder != 0) {
			clipped = true;
		}
		remainder = static_cast<int>(r - rr * divider);
		r = rr;
		++p;
	}
	if (!num_decimal_places) {
		if (remainder != 0 || clipped) {
			++r;
		}
	}
	else if (p) { // Don't add decimal places on exact bytes
		if (format != si1000) {
			// Binary, need to convert 1024 into range from 1-1000
			if (clipped) {
				++remainder;
				clipped = false;
			}
			remainder = (int)ceil((double)remainder * 1000 / 1024);
		}

		int max;
		switch (num_decimal_places)
		{
		default:
			num_decimal_places = 1;
			// Fall-through
		case 1:
			max = 9;
			divider = 100;
			break;
		case 2:
			max = 99;
			divider = 10;
			break;
		case 3:
			max = 999;
			break;
		}

		if (num_decimal_places != 3) {
			if (remainder % divider) {
				clipped = true;
			}
			remainder /= divider;
		}

		if (clipped) {
			remainder++;
		}
		if (remainder > max) {
			r++;
			remainder = 0;
		}

		wchar_t fmt[] = L"%00d";
		fmt[2] = '0' + num_decimal_places;
		places = fz::sprintf(fmt, remainder);
	}

	std::wstring result = ToString(r, 0, 0);
	if (!places.empty()) {
		std::wstring const& sep = GetRadixSeparator();

		result += sep;
		result += places;
	}
	result += ' ';

	static wchar_t byte_unit = 0;
	if (!byte_unit) {
		std::wstring t = _("B <Unit symbol for bytes. Only translate first letter>"); // @translator: Only translate first letter.
		byte_unit = t[0];
	}

	if (!p) {
		return result + byte_unit;
	}

	result += prefix[p];
	if (format == iec) {
		result += 'i';
	}

	result += byte_unit;

	return result;
}
wxString CSizeFormatBase::Format(COptionsBase* pOptions, wxLongLong size, bool add_bytes_suffix, enum CSizeFormatBase::_format format, bool thousands_separator, int num_decimal_places)
{
	wxASSERT(format != formats_count);
	wxASSERT(size >= 0);
	if( size < 0 ) {
		size = 0;
	}

	if (format == bytes) {
		wxString result = FormatNumber(pOptions, size, &thousands_separator);

		if (!add_bytes_suffix)
			return result;
		else
		{
			// wxPLURAL has no support for wxLongLong
			int last;
			if (size > 1000000000)
				last = (1000000000 + (size % 1000000000)).GetLo();
			else
				last = size.GetLo();
			return wxString::Format(wxPLURAL("%s byte", "%s bytes", last), result);
		}
	}

	wxString places;

	int divider;
	if (format == si1000)
		divider = 1000;
	else
		divider = 1024;

	// Exponent (2^(10p) or 10^(3p) depending on option
	int p = 0;

	wxLongLong r = size;
	int remainder = 0;
	bool clipped = false;
	while (r > divider && p < 6) {
		const wxLongLong rr = r / divider;
		if (remainder != 0)
			clipped = true;
		remainder = (r - rr * divider).GetLo();
		r = rr;
		++p;
	}
	if (!num_decimal_places) {
		if (remainder != 0 || clipped)
			++r;
	}
	else if (p) { // Don't add decimal places on exact bytes
		if (format != si1000) {
			// Binary, need to convert 1024 into range from 1-1000
			if (clipped) {
				++remainder;
				clipped = false;
			}
			remainder = (int)ceil((double)remainder * 1000 / 1024);
		}

		int max;
		switch (num_decimal_places)
		{
		default:
			num_decimal_places = 1;
			// Fall-through
		case 1:
			max = 9;
			divider = 100;
			break;
		case 2:
			max = 99;
			divider = 10;
			break;
		case 3:
			max = 999;
			break;
		}

		if (num_decimal_places != 3) {
			if (remainder % divider)
				clipped = true;
			remainder /= divider;
		}

		if (clipped)
			remainder++;
		if (remainder > max) {
			r++;
			remainder = 0;
		}

		places.Printf(_T("%d"), remainder);
		const size_t len = places.Len();
		for (size_t i = len; i < static_cast<size_t>(num_decimal_places); ++i)
			places = _T("0") + places;
	}

	wxString result = r.ToString();
	if (!places.empty()) {
		const wxString& sep = GetRadixSeparator();

		result += sep;
		result += places;
	}
	result += ' ';

	static wxChar byte_unit = 0;
	if (!byte_unit)
	{
		wxString t = _("B <Unit symbol for bytes. Only translate first letter>");
		byte_unit = t[0];
	}

	if (!p)
		return result + byte_unit;

	result += prefix[p];
	if (format == iec)
		result += 'i';

	result += byte_unit;

	return result;
}