xref: /freebsd/contrib/llvm-project/llvm/lib/Support/TextEncoding.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===-- TextEncoding.cpp - Text encoding conversion class ---------*- C++ -*-=//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric ///
9*700637cbSDimitry Andric /// \file
10*700637cbSDimitry Andric /// This file provides utility classes to convert between different character
11*700637cbSDimitry Andric /// encodings.
12*700637cbSDimitry Andric ///
13*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
14*700637cbSDimitry Andric 
15*700637cbSDimitry Andric #include "llvm/Support/TextEncoding.h"
16*700637cbSDimitry Andric #include "llvm/ADT/SmallString.h"
17*700637cbSDimitry Andric #include "llvm/ADT/SmallVector.h"
18*700637cbSDimitry Andric #include "llvm/ADT/StringExtras.h"
19*700637cbSDimitry Andric #include "llvm/Support/ConvertEBCDIC.h"
20*700637cbSDimitry Andric #include <system_error>
21*700637cbSDimitry Andric 
22*700637cbSDimitry Andric #if HAVE_ICU
23*700637cbSDimitry Andric #include <unicode/ucnv.h>
24*700637cbSDimitry Andric #elif HAVE_ICONV
25*700637cbSDimitry Andric #include <iconv.h>
26*700637cbSDimitry Andric #endif
27*700637cbSDimitry Andric 
28*700637cbSDimitry Andric using namespace llvm;
29*700637cbSDimitry Andric 
30*700637cbSDimitry Andric // Normalize the charset name with the charset alias matching algorithm proposed
31*700637cbSDimitry Andric // in https://www.unicode.org/reports/tr22/tr22-8.html#Charset_Alias_Matching.
normalizeCharSetName(StringRef CSName,SmallVectorImpl<char> & Normalized)32*700637cbSDimitry Andric static void normalizeCharSetName(StringRef CSName,
33*700637cbSDimitry Andric                                  SmallVectorImpl<char> &Normalized) {
34*700637cbSDimitry Andric   bool PrevDigit = false;
35*700637cbSDimitry Andric   for (auto Ch : CSName) {
36*700637cbSDimitry Andric     if (isAlnum(Ch)) {
37*700637cbSDimitry Andric       Ch = toLower(Ch);
38*700637cbSDimitry Andric       if (Ch != '0' || PrevDigit) {
39*700637cbSDimitry Andric         PrevDigit = isDigit(Ch);
40*700637cbSDimitry Andric         Normalized.push_back(Ch);
41*700637cbSDimitry Andric       }
42*700637cbSDimitry Andric     }
43*700637cbSDimitry Andric   }
44*700637cbSDimitry Andric }
45*700637cbSDimitry Andric 
46*700637cbSDimitry Andric // Maps the encoding name to enum constant if possible.
getKnownEncoding(StringRef Name)47*700637cbSDimitry Andric static std::optional<TextEncoding> getKnownEncoding(StringRef Name) {
48*700637cbSDimitry Andric   SmallString<16> Normalized;
49*700637cbSDimitry Andric   normalizeCharSetName(Name, Normalized);
50*700637cbSDimitry Andric   if (Normalized.equals("utf8"))
51*700637cbSDimitry Andric     return TextEncoding::UTF8;
52*700637cbSDimitry Andric   if (Normalized.equals("ibm1047"))
53*700637cbSDimitry Andric     return TextEncoding::IBM1047;
54*700637cbSDimitry Andric   return std::nullopt;
55*700637cbSDimitry Andric }
56*700637cbSDimitry Andric 
57*700637cbSDimitry Andric LLVM_ATTRIBUTE_UNUSED static void
HandleOverflow(size_t & Capacity,char * & Output,size_t & OutputLength,SmallVectorImpl<char> & Result)58*700637cbSDimitry Andric HandleOverflow(size_t &Capacity, char *&Output, size_t &OutputLength,
59*700637cbSDimitry Andric                SmallVectorImpl<char> &Result) {
60*700637cbSDimitry Andric   // No space left in output buffer. Double the size of the underlying
61*700637cbSDimitry Andric   // memory in the SmallVectorImpl, adjust pointer and length and continue
62*700637cbSDimitry Andric   // the conversion.
63*700637cbSDimitry Andric   Capacity =
64*700637cbSDimitry Andric       (Capacity < Result.max_size() / 2) ? 2 * Capacity : Result.max_size();
65*700637cbSDimitry Andric   Result.resize(0);
66*700637cbSDimitry Andric   Result.resize_for_overwrite(Capacity);
67*700637cbSDimitry Andric   Output = static_cast<char *>(Result.data());
68*700637cbSDimitry Andric   OutputLength = Capacity;
69*700637cbSDimitry Andric }
70*700637cbSDimitry Andric 
71*700637cbSDimitry Andric namespace {
72*700637cbSDimitry Andric enum ConversionType {
73*700637cbSDimitry Andric   UTF8ToIBM1047,
74*700637cbSDimitry Andric   IBM1047ToUTF8,
75*700637cbSDimitry Andric };
76*700637cbSDimitry Andric 
77*700637cbSDimitry Andric // Support conversion between EBCDIC 1047 and UTF-8. This class uses
78*700637cbSDimitry Andric // built-in translation tables that allow for translation between the
79*700637cbSDimitry Andric // aforementioned encodings. The use of tables for conversion is only
80*700637cbSDimitry Andric // possible because EBCDIC 1047 is a single-byte, stateless encoding; other
81*700637cbSDimitry Andric // encodings are not supported.
82*700637cbSDimitry Andric class TextEncodingConverterTable final
83*700637cbSDimitry Andric     : public details::TextEncodingConverterImplBase {
84*700637cbSDimitry Andric   const ConversionType ConvType;
85*700637cbSDimitry Andric 
86*700637cbSDimitry Andric public:
TextEncodingConverterTable(ConversionType ConvType)87*700637cbSDimitry Andric   TextEncodingConverterTable(ConversionType ConvType) : ConvType(ConvType) {}
88*700637cbSDimitry Andric 
89*700637cbSDimitry Andric   std::error_code convertString(StringRef Source,
90*700637cbSDimitry Andric                                 SmallVectorImpl<char> &Result) override;
91*700637cbSDimitry Andric 
reset()92*700637cbSDimitry Andric   void reset() override {}
93*700637cbSDimitry Andric };
94*700637cbSDimitry Andric 
95*700637cbSDimitry Andric std::error_code
convertString(StringRef Source,SmallVectorImpl<char> & Result)96*700637cbSDimitry Andric TextEncodingConverterTable::convertString(StringRef Source,
97*700637cbSDimitry Andric                                           SmallVectorImpl<char> &Result) {
98*700637cbSDimitry Andric   switch (ConvType) {
99*700637cbSDimitry Andric   case IBM1047ToUTF8:
100*700637cbSDimitry Andric     ConverterEBCDIC::convertToUTF8(Source, Result);
101*700637cbSDimitry Andric     return std::error_code();
102*700637cbSDimitry Andric   case UTF8ToIBM1047:
103*700637cbSDimitry Andric     return ConverterEBCDIC::convertToEBCDIC(Source, Result);
104*700637cbSDimitry Andric   }
105*700637cbSDimitry Andric   llvm_unreachable("Invalid ConvType!");
106*700637cbSDimitry Andric   return std::error_code();
107*700637cbSDimitry Andric }
108*700637cbSDimitry Andric 
109*700637cbSDimitry Andric #if HAVE_ICU
110*700637cbSDimitry Andric struct UConverterDeleter {
operator ()__anonf264d0e80111::UConverterDeleter111*700637cbSDimitry Andric   void operator()(UConverter *Converter) const {
112*700637cbSDimitry Andric     if (Converter)
113*700637cbSDimitry Andric       ucnv_close(Converter);
114*700637cbSDimitry Andric   }
115*700637cbSDimitry Andric };
116*700637cbSDimitry Andric using UConverterUniquePtr = std::unique_ptr<UConverter, UConverterDeleter>;
117*700637cbSDimitry Andric 
118*700637cbSDimitry Andric class TextEncodingConverterICU final
119*700637cbSDimitry Andric     : public details::TextEncodingConverterImplBase {
120*700637cbSDimitry Andric   UConverterUniquePtr FromConvDesc;
121*700637cbSDimitry Andric   UConverterUniquePtr ToConvDesc;
122*700637cbSDimitry Andric 
123*700637cbSDimitry Andric public:
TextEncodingConverterICU(UConverterUniquePtr FromConverter,UConverterUniquePtr ToConverter)124*700637cbSDimitry Andric   TextEncodingConverterICU(UConverterUniquePtr FromConverter,
125*700637cbSDimitry Andric                            UConverterUniquePtr ToConverter)
126*700637cbSDimitry Andric       : FromConvDesc(std::move(FromConverter)),
127*700637cbSDimitry Andric         ToConvDesc(std::move(ToConverter)) {}
128*700637cbSDimitry Andric 
129*700637cbSDimitry Andric   std::error_code convertString(StringRef Source,
130*700637cbSDimitry Andric                                 SmallVectorImpl<char> &Result) override;
131*700637cbSDimitry Andric 
132*700637cbSDimitry Andric   void reset() override;
133*700637cbSDimitry Andric };
134*700637cbSDimitry Andric 
135*700637cbSDimitry Andric // TODO: The current implementation discards the partial result and restarts the
136*700637cbSDimitry Andric // conversion from the beginning if there is a conversion error due to
137*700637cbSDimitry Andric // insufficient buffer size. In the future, it would better to save the partial
138*700637cbSDimitry Andric // result and resume the conversion for the remaining string.
139*700637cbSDimitry Andric // TODO: Improve translation of ICU errors to error_code
140*700637cbSDimitry Andric std::error_code
convertString(StringRef Source,SmallVectorImpl<char> & Result)141*700637cbSDimitry Andric TextEncodingConverterICU::convertString(StringRef Source,
142*700637cbSDimitry Andric                                         SmallVectorImpl<char> &Result) {
143*700637cbSDimitry Andric   // Setup the input in case it has no backing data.
144*700637cbSDimitry Andric   size_t InputLength = Source.size();
145*700637cbSDimitry Andric   const char *In = InputLength ? const_cast<char *>(Source.data()) : "";
146*700637cbSDimitry Andric 
147*700637cbSDimitry Andric   // Setup the output. We directly write into the SmallVector.
148*700637cbSDimitry Andric   size_t Capacity = Result.capacity();
149*700637cbSDimitry Andric   size_t OutputLength = Capacity;
150*700637cbSDimitry Andric   Result.resize_for_overwrite(Capacity);
151*700637cbSDimitry Andric   char *Output;
152*700637cbSDimitry Andric   UErrorCode EC = U_ZERO_ERROR;
153*700637cbSDimitry Andric 
154*700637cbSDimitry Andric   ucnv_setToUCallBack(&*FromConvDesc, UCNV_TO_U_CALLBACK_STOP, NULL, NULL, NULL,
155*700637cbSDimitry Andric                       &EC);
156*700637cbSDimitry Andric   ucnv_setFromUCallBack(&*ToConvDesc, UCNV_FROM_U_CALLBACK_STOP, NULL, NULL,
157*700637cbSDimitry Andric                         NULL, &EC);
158*700637cbSDimitry Andric   assert(U_SUCCESS(EC));
159*700637cbSDimitry Andric 
160*700637cbSDimitry Andric   do {
161*700637cbSDimitry Andric     EC = U_ZERO_ERROR;
162*700637cbSDimitry Andric     const char *Input = In;
163*700637cbSDimitry Andric 
164*700637cbSDimitry Andric     Output = InputLength ? static_cast<char *>(Result.data()) : nullptr;
165*700637cbSDimitry Andric     ucnv_convertEx(&*ToConvDesc, &*FromConvDesc, &Output, Result.end(), &Input,
166*700637cbSDimitry Andric                    In + InputLength, /*pivotStart=*/NULL,
167*700637cbSDimitry Andric                    /*pivotSource=*/NULL, /*pivotTarget=*/NULL,
168*700637cbSDimitry Andric                    /*pivotLimit=*/NULL, /*reset=*/true,
169*700637cbSDimitry Andric                    /*flush=*/true, &EC);
170*700637cbSDimitry Andric     if (U_FAILURE(EC)) {
171*700637cbSDimitry Andric       if (EC == U_BUFFER_OVERFLOW_ERROR) {
172*700637cbSDimitry Andric         if (Capacity < Result.max_size()) {
173*700637cbSDimitry Andric           HandleOverflow(Capacity, Output, OutputLength, Result);
174*700637cbSDimitry Andric           continue;
175*700637cbSDimitry Andric         } else
176*700637cbSDimitry Andric           return std::error_code(E2BIG, std::generic_category());
177*700637cbSDimitry Andric       }
178*700637cbSDimitry Andric       // Some other error occured.
179*700637cbSDimitry Andric       Result.resize(Output - Result.data());
180*700637cbSDimitry Andric       return std::error_code(EILSEQ, std::generic_category());
181*700637cbSDimitry Andric     }
182*700637cbSDimitry Andric     break;
183*700637cbSDimitry Andric   } while (true);
184*700637cbSDimitry Andric 
185*700637cbSDimitry Andric   Result.resize(Output - Result.data());
186*700637cbSDimitry Andric   return std::error_code();
187*700637cbSDimitry Andric }
188*700637cbSDimitry Andric 
reset()189*700637cbSDimitry Andric void TextEncodingConverterICU::reset() {
190*700637cbSDimitry Andric   ucnv_reset(&*FromConvDesc);
191*700637cbSDimitry Andric   ucnv_reset(&*ToConvDesc);
192*700637cbSDimitry Andric }
193*700637cbSDimitry Andric 
194*700637cbSDimitry Andric #elif HAVE_ICONV
195*700637cbSDimitry Andric class TextEncodingConverterIconv final
196*700637cbSDimitry Andric     : public details::TextEncodingConverterImplBase {
197*700637cbSDimitry Andric   class UniqueIconvT {
198*700637cbSDimitry Andric     iconv_t ConvDesc;
199*700637cbSDimitry Andric 
200*700637cbSDimitry Andric   public:
operator iconv_t() const201*700637cbSDimitry Andric     operator iconv_t() const { return ConvDesc; }
UniqueIconvT(iconv_t CD)202*700637cbSDimitry Andric     UniqueIconvT(iconv_t CD) : ConvDesc(CD) {}
~UniqueIconvT()203*700637cbSDimitry Andric     ~UniqueIconvT() {
204*700637cbSDimitry Andric       if (ConvDesc != (iconv_t)-1) {
205*700637cbSDimitry Andric         iconv_close(ConvDesc);
206*700637cbSDimitry Andric         ConvDesc = (iconv_t)-1;
207*700637cbSDimitry Andric       }
208*700637cbSDimitry Andric     }
UniqueIconvT(UniqueIconvT && Other)209*700637cbSDimitry Andric     UniqueIconvT(UniqueIconvT &&Other) : ConvDesc(Other.ConvDesc) {
210*700637cbSDimitry Andric       Other.ConvDesc = (iconv_t)-1;
211*700637cbSDimitry Andric     }
operator =(UniqueIconvT && Other)212*700637cbSDimitry Andric     UniqueIconvT &operator=(UniqueIconvT &&Other) {
213*700637cbSDimitry Andric       if (&Other != this) {
214*700637cbSDimitry Andric         ConvDesc = Other.ConvDesc;
215*700637cbSDimitry Andric         Other.ConvDesc = (iconv_t)-1;
216*700637cbSDimitry Andric       }
217*700637cbSDimitry Andric       return *this;
218*700637cbSDimitry Andric     }
219*700637cbSDimitry Andric   };
220*700637cbSDimitry Andric   UniqueIconvT ConvDesc;
221*700637cbSDimitry Andric 
222*700637cbSDimitry Andric public:
TextEncodingConverterIconv(UniqueIconvT ConvDesc)223*700637cbSDimitry Andric   TextEncodingConverterIconv(UniqueIconvT ConvDesc)
224*700637cbSDimitry Andric       : ConvDesc(std::move(ConvDesc)) {}
225*700637cbSDimitry Andric 
226*700637cbSDimitry Andric   std::error_code convertString(StringRef Source,
227*700637cbSDimitry Andric                                 SmallVectorImpl<char> &Result) override;
228*700637cbSDimitry Andric 
229*700637cbSDimitry Andric   void reset() override;
230*700637cbSDimitry Andric };
231*700637cbSDimitry Andric 
232*700637cbSDimitry Andric // TODO: The current implementation discards the partial result and restarts the
233*700637cbSDimitry Andric // conversion from the beginning if there is a conversion error due to
234*700637cbSDimitry Andric // insufficient buffer size. In the future, it would better to save the partial
235*700637cbSDimitry Andric // result and resume the conversion for the remaining string.
236*700637cbSDimitry Andric std::error_code
convertString(StringRef Source,SmallVectorImpl<char> & Result)237*700637cbSDimitry Andric TextEncodingConverterIconv::convertString(StringRef Source,
238*700637cbSDimitry Andric                                           SmallVectorImpl<char> &Result) {
239*700637cbSDimitry Andric   // Setup the output. We directly write into the SmallVector.
240*700637cbSDimitry Andric   size_t Capacity = Result.capacity();
241*700637cbSDimitry Andric   char *Output = static_cast<char *>(Result.data());
242*700637cbSDimitry Andric   size_t OutputLength = Capacity;
243*700637cbSDimitry Andric   Result.resize_for_overwrite(Capacity);
244*700637cbSDimitry Andric 
245*700637cbSDimitry Andric   size_t Ret;
246*700637cbSDimitry Andric   // Handle errors returned from iconv().
247*700637cbSDimitry Andric   auto HandleError = [&Capacity, &Output, &OutputLength, &Result,
248*700637cbSDimitry Andric                       this](size_t Ret) {
249*700637cbSDimitry Andric     if (Ret == static_cast<size_t>(-1)) {
250*700637cbSDimitry Andric       // An error occured. Check if we can gracefully handle it.
251*700637cbSDimitry Andric       if (errno == E2BIG && Capacity < Result.max_size()) {
252*700637cbSDimitry Andric         HandleOverflow(Capacity, Output, OutputLength, Result);
253*700637cbSDimitry Andric         // Reset converter
254*700637cbSDimitry Andric         reset();
255*700637cbSDimitry Andric         return std::error_code();
256*700637cbSDimitry Andric       } else {
257*700637cbSDimitry Andric         // Some other error occured.
258*700637cbSDimitry Andric         Result.resize(Output - Result.data());
259*700637cbSDimitry Andric         return std::error_code(errno, std::generic_category());
260*700637cbSDimitry Andric       }
261*700637cbSDimitry Andric     } else {
262*700637cbSDimitry Andric       // A positive return value indicates that some characters were converted
263*700637cbSDimitry Andric       // in a nonreversible way, that is, replaced with a SUB symbol. Returning
264*700637cbSDimitry Andric       // an error in this case makes sure that both conversion routines behave
265*700637cbSDimitry Andric       // in the same way.
266*700637cbSDimitry Andric       return std::make_error_code(std::errc::illegal_byte_sequence);
267*700637cbSDimitry Andric     }
268*700637cbSDimitry Andric   };
269*700637cbSDimitry Andric 
270*700637cbSDimitry Andric   do {
271*700637cbSDimitry Andric     // Setup the input. Use nullptr to reset iconv state if input length is
272*700637cbSDimitry Andric     // zero.
273*700637cbSDimitry Andric     size_t InputLength = Source.size();
274*700637cbSDimitry Andric     char *Input = const_cast<char *>(InputLength ? Source.data() : "");
275*700637cbSDimitry Andric     Ret = iconv(ConvDesc, &Input, &InputLength, &Output, &OutputLength);
276*700637cbSDimitry Andric     if (Ret != 0) {
277*700637cbSDimitry Andric       if (auto EC = HandleError(Ret))
278*700637cbSDimitry Andric         return EC;
279*700637cbSDimitry Andric       continue;
280*700637cbSDimitry Andric     }
281*700637cbSDimitry Andric     // Flush the converter
282*700637cbSDimitry Andric     Ret = iconv(ConvDesc, nullptr, nullptr, &Output, &OutputLength);
283*700637cbSDimitry Andric     if (Ret != 0) {
284*700637cbSDimitry Andric       if (auto EC = HandleError(Ret))
285*700637cbSDimitry Andric         return EC;
286*700637cbSDimitry Andric       continue;
287*700637cbSDimitry Andric     }
288*700637cbSDimitry Andric     break;
289*700637cbSDimitry Andric   } while (true);
290*700637cbSDimitry Andric 
291*700637cbSDimitry Andric   // Re-adjust size to actual size.
292*700637cbSDimitry Andric   Result.resize(Output - Result.data());
293*700637cbSDimitry Andric   return std::error_code();
294*700637cbSDimitry Andric }
295*700637cbSDimitry Andric 
reset()296*700637cbSDimitry Andric inline void TextEncodingConverterIconv::reset() {
297*700637cbSDimitry Andric   iconv(ConvDesc, nullptr, nullptr, nullptr, nullptr);
298*700637cbSDimitry Andric }
299*700637cbSDimitry Andric 
300*700637cbSDimitry Andric #endif // HAVE_ICONV
301*700637cbSDimitry Andric } // namespace
302*700637cbSDimitry Andric 
303*700637cbSDimitry Andric ErrorOr<TextEncodingConverter>
create(TextEncoding CPFrom,TextEncoding CPTo)304*700637cbSDimitry Andric TextEncodingConverter::create(TextEncoding CPFrom, TextEncoding CPTo) {
305*700637cbSDimitry Andric 
306*700637cbSDimitry Andric   // Text encodings should be distinct.
307*700637cbSDimitry Andric   if (CPFrom == CPTo)
308*700637cbSDimitry Andric     return std::make_error_code(std::errc::invalid_argument);
309*700637cbSDimitry Andric 
310*700637cbSDimitry Andric   ConversionType Conversion;
311*700637cbSDimitry Andric   if (CPFrom == TextEncoding::UTF8 && CPTo == TextEncoding::IBM1047)
312*700637cbSDimitry Andric     Conversion = UTF8ToIBM1047;
313*700637cbSDimitry Andric   else if (CPFrom == TextEncoding::IBM1047 && CPTo == TextEncoding::UTF8)
314*700637cbSDimitry Andric     Conversion = IBM1047ToUTF8;
315*700637cbSDimitry Andric   else
316*700637cbSDimitry Andric     return std::make_error_code(std::errc::invalid_argument);
317*700637cbSDimitry Andric 
318*700637cbSDimitry Andric   return TextEncodingConverter(
319*700637cbSDimitry Andric       std::make_unique<TextEncodingConverterTable>(Conversion));
320*700637cbSDimitry Andric }
321*700637cbSDimitry Andric 
create(StringRef From,StringRef To)322*700637cbSDimitry Andric ErrorOr<TextEncodingConverter> TextEncodingConverter::create(StringRef From,
323*700637cbSDimitry Andric                                                              StringRef To) {
324*700637cbSDimitry Andric   std::optional<TextEncoding> FromEncoding = getKnownEncoding(From);
325*700637cbSDimitry Andric   std::optional<TextEncoding> ToEncoding = getKnownEncoding(To);
326*700637cbSDimitry Andric   if (FromEncoding && ToEncoding) {
327*700637cbSDimitry Andric     ErrorOr<TextEncodingConverter> Converter =
328*700637cbSDimitry Andric         create(*FromEncoding, *ToEncoding);
329*700637cbSDimitry Andric     if (Converter)
330*700637cbSDimitry Andric       return Converter;
331*700637cbSDimitry Andric   }
332*700637cbSDimitry Andric #if HAVE_ICU
333*700637cbSDimitry Andric   UErrorCode EC = U_ZERO_ERROR;
334*700637cbSDimitry Andric   UConverterUniquePtr FromConvDesc(ucnv_open(From.str().c_str(), &EC));
335*700637cbSDimitry Andric   if (U_FAILURE(EC))
336*700637cbSDimitry Andric     return std::make_error_code(std::errc::invalid_argument);
337*700637cbSDimitry Andric 
338*700637cbSDimitry Andric   UConverterUniquePtr ToConvDesc(ucnv_open(To.str().c_str(), &EC));
339*700637cbSDimitry Andric   if (U_FAILURE(EC))
340*700637cbSDimitry Andric     return std::make_error_code(std::errc::invalid_argument);
341*700637cbSDimitry Andric 
342*700637cbSDimitry Andric   auto Converter = std::make_unique<TextEncodingConverterICU>(
343*700637cbSDimitry Andric       std::move(FromConvDesc), std::move(ToConvDesc));
344*700637cbSDimitry Andric   return TextEncodingConverter(std::move(Converter));
345*700637cbSDimitry Andric #elif HAVE_ICONV
346*700637cbSDimitry Andric   iconv_t ConvDesc = iconv_open(To.str().c_str(), From.str().c_str());
347*700637cbSDimitry Andric   if (ConvDesc == (iconv_t)-1)
348*700637cbSDimitry Andric     return std::make_error_code(std::errc::invalid_argument);
349*700637cbSDimitry Andric   return TextEncodingConverter(
350*700637cbSDimitry Andric       std::make_unique<TextEncodingConverterIconv>(ConvDesc));
351*700637cbSDimitry Andric #else
352*700637cbSDimitry Andric   return std::make_error_code(std::errc::invalid_argument);
353*700637cbSDimitry Andric #endif
354*700637cbSDimitry Andric }
355