309 switch (cr.fStatus) {
310 case ConversionStatusFlag::sourceIllegal:
311 UTFConvert::Throw (cr.fStatus, cr.fSourceConsumed);
312 case ConversionStatusFlag::sourceExhausted:
314 if (not from->empty ()) {
315 *from = from->subspan (0, from->size () - 1);
319 return span<CHAR_T>{};
321 case ConversionStatusFlag::ok:
322 return to.subspan (0, cr.fTargetProduced);
325 return span<CHAR_T>{};
330 virtual span<byte> Characters2Bytes (span<const CHAR_T> from, span<byte> to)
const override
332 Require (to.size () >= ComputeTargetByteBufferSize (from) or to.size () >= this->_Characters2Bytes (from));
333 if constexpr (
sizeof (CHAR_T) ==
sizeof (INTERMEDIATE_CHAR_T)) {
334 return fBytesVSIntermediateCvt_.Characters2Bytes (Memory::SpanBytesCast<span<const INTERMEDIATE_CHAR_T>> (from), to);
341 Memory::StackBuffer<INTERMEDIATE_CHAR_T> intermediateBuf{
342 fIntermediateVSFinalCHARCvt_.template ComputeTargetBufferSize<INTERMEDIATE_CHAR_T> (from)};
347 span<INTERMEDIATE_CHAR_T> intermediateSpan =
348 fIntermediateVSFinalCHARCvt_.ConvertSpan (from, span<INTERMEDIATE_CHAR_T>{intermediateBuf.data (), intermediateBuf.size ()});
351 return fBytesVSIntermediateCvt_.Characters2Bytes (intermediateSpan, to);
354 virtual size_t ComputeTargetCharacterBufferSize (variant<span<const byte>,
size_t> src)
const override
356 size_t intermediateCharCntMax = [&] () {
357 if (
const size_t* i = get_if<size_t> (&src)) {
358 return fBytesVSIntermediateCvt_.ComputeTargetCharacterBufferSize (*i);
361 return fBytesVSIntermediateCvt_.ComputeTargetCharacterBufferSize (get<span<const byte>> (src));
364 if constexpr (
sizeof (CHAR_T) ==
sizeof (INTERMEDIATE_CHAR_T)) {
365 return intermediateCharCntMax;
368 return fIntermediateVSFinalCHARCvt_.template ComputeTargetBufferSize<CHAR_T, INTERMEDIATE_CHAR_T> (intermediateCharCntMax);
371 virtual size_t ComputeTargetByteBufferSize (variant<span<const CHAR_T>,
size_t> src)
const override
373 size_t intermediateCharCntMax = [&] () {
374 if constexpr (
sizeof (CHAR_T) ==
sizeof (INTERMEDIATE_CHAR_T)) {
375 if (
const size_t* i = get_if<size_t> (&src)) {
379 return get<span<const CHAR_T>> (src).size ();
383 if (
const size_t* i = get_if<size_t> (&src)) {
384 return fIntermediateVSFinalCHARCvt_.template ComputeTargetBufferSize<INTERMEDIATE_CHAR_T, CHAR_T> (*i);
387 return fIntermediateVSFinalCHARCvt_.template ComputeTargetBufferSize<INTERMEDIATE_CHAR_T> (get<span<const CHAR_T>> (src));
391 return fBytesVSIntermediateCvt_.ComputeTargetByteBufferSize (intermediateCharCntMax);
393 CodeCvt<INTERMEDIATE_CHAR_T> fBytesVSIntermediateCvt_;
394 conditional_t<
sizeof (CHAR_T) !=
sizeof (INTERMEDIATE_CHAR_T), UTFConvert,
byte> fIntermediateVSFinalCHARCvt_;
403 template <IUNICODECanAlwaysConvertTo CHAR_T>
404 template <
typename STD_CODE_CVT_T>
405 struct CodeCvt<CHAR_T>::CodeCvt_WrapStdCodeCvt_ : CodeCvt<CHAR_T>::IRep {
406 unique_ptr<STD_CODE_CVT_T> fCodeCvt_;
407 optional<Character> fInvalidCharacterReplacement_;
408 optional<span<byte>> fInvalidCharacterReplacementBytes_;
409 using extern_type =
typename STD_CODE_CVT_T::extern_type;
410 extern_type fInvalidCharacterReplacementBytesBuf[8];
411 static_assert (same_as<CHAR_T, typename STD_CODE_CVT_T::intern_type>);
412#if qCompilerAndStdLib_arm_asan_FaultStackUseAfterScope_Buggy
413 Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_ADDRESS
415 CodeCvt_WrapStdCodeCvt_ (
const Options& options, unique_ptr<STD_CODE_CVT_T>&& codeCvt)
416 : fCodeCvt_{move (codeCvt)}
417 , fInvalidCharacterReplacement_{options.fInvalidCharacterReplacement}
419 if (fInvalidCharacterReplacement_) {
420 mbstate_t ignoredMBState{};
421 Memory::StackBuffer<CHAR_T> tmpBuf;
422 span<const CHAR_T> invalCharPartlyEncode = fInvalidCharacterReplacement_->As<CHAR_T> (&tmpBuf);
423 const CHAR_T* ignoreCharsConsumed =
nullptr;
424 extern_type* bytesInvalChar = fInvalidCharacterReplacementBytesBuf;
426 auto r = fCodeCvt_->out (ignoredMBState, invalCharPartlyEncode.data (),
427 invalCharPartlyEncode.data () + invalCharPartlyEncode.size (), ignoreCharsConsumed,
428 fInvalidCharacterReplacementBytesBuf,
429 fInvalidCharacterReplacementBytesBuf + size (fInvalidCharacterReplacementBytesBuf), bytesInvalChar);
430 DISABLE_COMPILER_MSC_WARNING_END (4996)
431 if (r == STD_CODE_CVT_T::ok) [[likely]] {
432 fInvalidCharacterReplacementBytes_ = as_writable_bytes (
433 span{fInvalidCharacterReplacementBytesBuf}.subspan (0, bytesInvalChar - fInvalidCharacterReplacementBytesBuf));
439 virtual Options GetOptions ()
const override
441 return Options{.fInvalidCharacterReplacement = fInvalidCharacterReplacement_};
443 virtual span<CHAR_T>
Bytes2Characters (span<const byte>* from, span<CHAR_T> to)
const override
446 Require (to.size () >= ComputeTargetCharacterBufferSize (*from));
447 const extern_type* _First1 =
reinterpret_cast<const extern_type*
> (from->data ());
448 const extern_type* _Last1 = _First1 + from->size ();
449 const extern_type* _Mid1 = _First1;
450 CHAR_T* _First2 = to.data ();
451 CHAR_T* _Last2 = _First2 + to.size ();
452 CHAR_T* _Mid2 = _First2;
453 mbstate_t ignoredMBState{};
454 size_t bytesDone = 0;
455 size_t charsDone = 0;
457 auto r = fCodeCvt_->in (ignoredMBState, _First1 + bytesDone, _Last1, _Mid1, _First2 + charsDone, _Last2, _Mid2);
460 if (r == STD_CODE_CVT_T::partial and _Last1 - _Mid1 >= fCodeCvt_->max_length ()) {
461 r = STD_CODE_CVT_T::error;
463 if (r == STD_CODE_CVT_T::partial) {
464 *from = from->subspan (
static_cast<size_t> (_Mid1 - _First1));
465 Assert (from->size () != 0);
467 else if (r != STD_CODE_CVT_T::ok) {
468 if (fInvalidCharacterReplacement_) {
469 bytesDone = _Mid1 - _First1 + 1;
470 charsDone = _Mid2 - _First2;
471 ignoredMBState = mbstate_t{};
473 Memory::StackBuffer<CHAR_T> badCharTmpBuf;
474 span<const CHAR_T> badCharReplaceSpan = fInvalidCharacterReplacement_->As<CHAR_T> (&badCharTmpBuf);
475 span<CHAR_T> copied = Memory::CopyBytes (badCharReplaceSpan, span{&_First2[charsDone], _Last2});
476 Assert (copied.size () >= 0);
477 charsDone += copied.size ();
478 Assert (charsDone <= to.size ());
482 Private_::ThrowErrorConvertingBytes2Characters_ (_Mid1 - _First1);
486 Require (_Mid1 == _Last1);
487 *from = span<const byte>{};
489 return to.subspan (0, _Mid2 - _First2);
491 virtual span<byte> Characters2Bytes (span<const CHAR_T> from, span<byte> to)
const override
493 Require (to.size () >= ComputeTargetByteBufferSize (from));
494 const CHAR_T* _First1 = from.data ();
495 const CHAR_T* _Last1 = _First1 + from.size ();
496 const CHAR_T* _Mid1 = _First1;
497 extern_type* _First2 =
reinterpret_cast<extern_type*
> (to.data ());
498 extern_type* _Last2 = _First2 + to.size ();
499 extern_type* _Mid2 = _First2;
500 mbstate_t ignoredMBState{};
501 size_t charsDone = 0;
502 size_t bytesDone = 0;
504 auto r = fCodeCvt_->out (ignoredMBState, _First1 + charsDone, _Last1, _Mid1, _First2 + bytesDone, _Last2, _Mid2);
505 if (r != STD_CODE_CVT_T::ok) {
506 if (fInvalidCharacterReplacementBytes_) {
507 charsDone = _Mid1 - _First1 + 1;
508 bytesDone = _Mid2 - _First2;
509 memcpy (_First2 + bytesDone, fInvalidCharacterReplacementBytes_->data (), fInvalidCharacterReplacementBytes_->size ());
510 bytesDone += fInvalidCharacterReplacementBytes_->size ();
514 Private_::ThrowErrorConvertingCharacters2Bytes_ (_Mid1 - _First1);
517 Require (_Mid1 == _Last1);
518 return to.subspan (0, _Mid2 - _First2);
520 virtual size_t ComputeTargetCharacterBufferSize (variant<span<const byte>,
size_t> src)
const override
523 if (
const size_t* i = get_if<size_t> (&src)) {
527 return get<span<const byte>> (src).size ();
530 virtual size_t ComputeTargetByteBufferSize (variant<span<const CHAR_T>,
size_t> src)
const override
532 if (
const size_t* i = get_if<size_t> (&src)) {
533 return (*i) * fCodeCvt_->max_length ();
538 return get<span<const CHAR_T>> (src).size () * fCodeCvt_->max_length ();
545 struct BuiltinSingleByteTableCodePageRep_ final : CodeCvt<char16_t>::IRep {
546 BuiltinSingleByteTableCodePageRep_ (
CodePage cp, optional<Character> invalidCharacterReplacement);
547 virtual ~BuiltinSingleByteTableCodePageRep_ () =
default;
548 virtual CodeCvt<char16_t>::Options GetOptions ()
const override
550 optional<char16_t> invalRepChar;
551 if (fInvalidCharacterReplacementByte_ != nullopt) {
553 auto byteSpan = span{&*fInvalidCharacterReplacementByte_, 1};
554 (void)this->Bytes2Characters (&byteSpan, span{&x, 1});
557 return CodeCvt<char16_t>::Options{.fInvalidCharacterReplacement = invalRepChar};
559 virtual span<char16_t> Bytes2Characters (span<const byte>* from, span<char16_t> to)
const override;
560 virtual span<byte> Characters2Bytes (span<const char16_t> from, span<byte> to)
const override;
561 virtual size_t ComputeTargetCharacterBufferSize (variant<span<const byte>,
size_t> src)
const override;
562 virtual size_t ComputeTargetByteBufferSize (variant<span<const char16_t>,
size_t> src)
const override;
563 const char16_t* fMap_;
564 optional<byte> fInvalidCharacterReplacementByte_;
566#if qStroika_Platform_Windows
567 struct WindowsNative_ final : CodeCvt<char16_t>::IRep {
568 constexpr WindowsNative_ (CodePage cp)
572 virtual ~WindowsNative_ () =
default;
573 virtual CodeCvt<char16_t>::Options GetOptions ()
const override
577 virtual span<char16_t> Bytes2Characters (span<const byte>* from, span<char16_t> to)
const override;
578 virtual span<byte> Characters2Bytes (span<const char16_t> from, span<byte> to)
const override;
579 virtual size_t ComputeTargetCharacterBufferSize (variant<span<const byte>,
size_t> src)
const override;
580 virtual size_t ComputeTargetByteBufferSize (variant<span<const char16_t>,
size_t> src)
const override;
591 template <IUNICODECanAlwaysConvertTo CHAR_T>
592 template <qCompilerAndStdLib_Constra
intDiffersInTemplateRedeclaration_BWA (IUNICODECanAlwaysConvertTo) FROM_CHAR_T_OPTIONS>
593 constexpr inline auto CodeCvt<CHAR_T>::Options::New (
typename CodeCvt<FROM_CHAR_T_OPTIONS>::Options o) -> Options
595 return Options{.fInvalidCharacterReplacement = o.fInvalidCharacterReplacement};
603 template <IUNICODECanAlwaysConvertTo CHAR_T>
605 : fRep_{Memory::MakeSharedPtr<UTFConvertRep_<char8_t>> (options)}
608 template <IUNICODECanAlwaysConvertTo CHAR_T>
612 if constexpr (same_as<CHAR_T,
wchar_t>) {
613 *
this = mkFromStdCodeCvt<codecvt_byname<wchar_t, char, mbstate_t>> (options, l.name ());
615 else if constexpr (same_as<CHAR_T, char16_t> or same_as<CHAR_T, char32_t>) {
616 *
this = mkFromStdCodeCvt<codecvt_byname<CHAR_T, char8_t, mbstate_t>> (options, l.name ());
618 else if constexpr (same_as<CHAR_T, Character>) {
620 CodeCvt<char32_t>::Options::New<CHAR_T> (options), l.name ()));
626 DISABLE_COMPILER_MSC_WARNING_END (4996)
628 template <IUNICODECanAlwaysConvertTo CHAR_T>
631 if (charset == WellKnownCharsets::kISO_8859_1) {
632 fRep_ = Memory::MakeSharedPtr<Latin1ConvertRep_> (options);
634 else if (charset == WellKnownCharsets::kUTF8) {
635 *
this = CodeCvt<CHAR_T>{UnicodeExternalEncodings::eUTF8};
637 else if (same_as<CHAR_T, Character>) {
640 fRep_ = Memory::MakeSharedPtr<UTF2UTFRep_<
char32_t>> (CodeCvt<
char32_t>::mkFromStdCodeCvt<codecvt_byname<
char32_t,
char8_t, mbstate_t>> (
641 CodeCvt<
char32_t>::Options::New<CHAR_T> (options), charset.AsNarrowSDKString ()));
642 DISABLE_COMPILER_MSC_WARNING_END (4996)
645 Private_::ThrowCharsetNotSupportedException_ (charset);
648 template <IUNICODECanAlwaysConvertTo CHAR_T>
653 case UnicodeExternalEncodings::eUTF8:
654 fRep_ = Memory::MakeSharedPtr<UTFConvertRep_<char8_t>> (options);
656 case UnicodeExternalEncodings::eUTF16_BE:
657 case UnicodeExternalEncodings::eUTF16_LE:
658 if (e == UnicodeExternalEncodings::eUTF16) {
659 fRep_ = Memory::MakeSharedPtr<UTFConvertRep_<char16_t>> (options);
662 fRep_ = Memory::MakeSharedPtr<UTFConvertSwappedRep_<char16_t>> (options);
665 case UnicodeExternalEncodings::eUTF32_BE:
666 case UnicodeExternalEncodings::eUTF32_LE:
667 if (e == UnicodeExternalEncodings::eUTF32) {
668 fRep_ = Memory::MakeSharedPtr<UTFConvertRep_<char32_t>> (options);
671 fRep_ = Memory::MakeSharedPtr<UTFConvertSwappedRep_<char32_t>> (options);
678 template <IUNICODECanAlwaysConvertTo CHAR_T>
679 CodeCvt<CHAR_T>::CodeCvt (span<const byte>* guessFormatFrom,
const optional<CodeCvt>& useElse,
const Options& options)
683 Require (useElse == nullopt or useElse->GetOptions ().fInvalidCharacterReplacement == options.fInvalidCharacterReplacement);
684 if (optional<tuple<UnicodeExternalEncodings, size_t>> r =
ReadByteOrderMark (*guessFormatFrom)) {
685 *guessFormatFrom = guessFormatFrom->subspan (get<size_t> (*r));
686 fRep_ =
CodeCvt{get<UnicodeExternalEncodings> (*r), options}.fRep_;
689 fRep_ = useElse ? useElse->fRep_ :
CodeCvt{options}.fRep_;
692 template <IUNICODECanAlwaysConvertTo CHAR_T>
701 case WellKnownCodePages::kANSI:
702 case WellKnownCodePages::kMAC:
703 case WellKnownCodePages::kPC:
704 case WellKnownCodePages::kPCA:
705 case WellKnownCodePages::kGreek:
706 case WellKnownCodePages::kTurkish:
707 case WellKnownCodePages::kHebrew:
708 case WellKnownCodePages::kArabic:
709 fRep_ = Memory::MakeSharedPtr<UTF2UTFRep_<char16_t>> (CodeCvt<char16_t> (
710 Memory::MakeSharedPtr<Private_::BuiltinSingleByteTableCodePageRep_> (cp, options.fInvalidCharacterReplacement)));
712 case WellKnownCodePages::kUTF8:
713 fRep_ = Memory::MakeSharedPtr<UTFConvertRep_<char8_t>> (options);
715 case WellKnownCodePages::kUNICODE_WIDE:
716 fRep_ = Memory::MakeSharedPtr<UTFConvertRep_<char16_t>> (options);
718 case WellKnownCodePages::kUNICODE_WIDE_BIGENDIAN:
719 fRep_ = Memory::MakeSharedPtr<UTFConvertSwappedRep_<char16_t>> (options);
722#if qStroika_Platform_Windows
723 if (options.fInvalidCharacterReplacement) {
724 Private_::ThrowCodePageNotSupportedException_ (cp);
726 fRep_ = Memory::MakeSharedPtr<UTF2UTFRep_<char16_t>> (CodeCvt<char16_t> (Memory::MakeSharedPtr<Private_::WindowsNative_> (cp)));
729 Private_::ThrowCodePageNotSupportedException_ (cp);
733 template <IUNICODECanAlwaysConvertTo CHAR_T>
736#if qStroika_Platform_Windows
738 return CodeCvt{Private_::GetANSICodePage_ (), options};
740 locale l = locale::classic ();
747 const string name = l.name ();
748 if (name ==
"C" or name ==
"POSIX" or name.find (
"UTF-8") != string::npos or name.find (
"utf8") != string::npos) {
749 return CodeCvt{UnicodeExternalEncodings::eUTF8, options};
754 template <IUNICODECanAlwaysConvertTo CHAR_T>
755 template <IUNICODECanAlwaysConvertTo INTERMEDIATE_CHAR_T>
757 : fRep_{Memory::MakeSharedPtr<UTF2UTFRep_<INTERMEDIATE_CHAR_T>> (basedOn)}
760 template <IUNICODECanAlwaysConvertTo CHAR_T>
765 template <IUNICODECanAlwaysConvertTo CHAR_T>
766 template <IStdCodeCVT STD_CODECVT,
typename... ARGS>
768 requires (same_as<CHAR_T, typename STD_CODECVT::intern_type>)
770 auto u = make_unique<Private_::deletable_facet_<STD_CODECVT>> (forward<ARGS> (args)...);
771 return CodeCvt<CHAR_T>{Memory::MakeSharedPtr<CodeCvt_WrapStdCodeCvt_<Private_::deletable_facet_<STD_CODECVT>>> (options, move (u))};
773 template <IUNICODECanAlwaysConvertTo CHAR_T>
774 inline auto CodeCvt<CHAR_T>::GetOptions () const -> Options
776 return fRep_->GetOptions ();
778 template <IUNICODECanAlwaysConvertTo CHAR_T>
782 return fRep_->Bytes2Characters (&from, span{to}).size ();