@@ -172,10 +172,34 @@ CharSetConverterICU::convert(StringRef Source,
172172
173173#elif defined(HAVE_ICONV)
174174class CharSetConverterIconv : public details ::CharSetConverterImplBase {
175- iconv_t ConvDesc;
175+ class UniqueIconvT {
176+ iconv_t ConvDesc;
177+
178+ public:
179+ operator iconv_t () const { return ConvDesc; }
180+ UniqueIconvT (iconv_t CD) : ConvDesc(CD) {}
181+ ~UniqueIconvT () {
182+ if (ConvDesc != (iconv_t )-1 ) {
183+ iconv_close (ConvDesc);
184+ ConvDesc = (iconv_t )-1 ;
185+ }
186+ }
187+ UniqueIconvT (UniqueIconvT &&Other) : ConvDesc(Other.ConvDesc) {
188+ Other.ConvDesc = (iconv_t )-1 ;
189+ }
190+ UniqueIconvT &operator =(UniqueIconvT &&Other) {
191+ if (&Other != this ) {
192+ ConvDesc = Other.ConvDesc ;
193+ Other.ConvDesc = (iconv_t )-1 ;
194+ }
195+ return *this ;
196+ }
197+ };
198+ UniqueIconvT ConvDesc;
176199
177200public:
178- CharSetConverterIconv (iconv_t ConvDesc) : ConvDesc(ConvDesc) {}
201+ CharSetConverterIconv (UniqueIconvT ConvDesc)
202+ : ConvDesc(std::move(ConvDesc)) {}
179203
180204 std::error_code convert (StringRef Source,
181205 SmallVectorImpl<char > &Result) const override ;
@@ -184,19 +208,16 @@ class CharSetConverterIconv : public details::CharSetConverterImplBase {
184208std::error_code
185209CharSetConverterIconv::convert (StringRef Source,
186210 SmallVectorImpl<char > &Result) const {
187- // Setup the input. Use nullptr to reset iconv state if input length is zero.
188- size_t InputLength = Source.size ();
189- char *Input = InputLength ? const_cast <char *>(Source.data ()) : nullptr ;
190211 // Setup the output. We directly write into the SmallVector.
191- Result.resize_for_overwrite (Source.size ());
192212 size_t Capacity = Result.capacity ();
193213 char *Output = static_cast <char *>(Result.data ());
194214 size_t OutputLength = Capacity;
215+ Result.resize_for_overwrite (Capacity);
195216
196217 size_t Ret;
197-
198218 // Handle errors returned from iconv().
199- auto HandleError = [&Capacity, &Output, &OutputLength, &Result](size_t Ret) {
219+ auto HandleError = [&Capacity, &Output, &OutputLength, &Result,
220+ this ](size_t Ret) {
200221 if (Ret == static_cast <size_t >(-1 )) {
201222 // An error occured. Check if we can gracefully handle it.
202223 if (errno == E2BIG && Capacity < std::numeric_limits<size_t >::max ()) {
@@ -217,14 +238,26 @@ CharSetConverterIconv::convert(StringRef Source,
217238 }
218239 };
219240
220- // Convert the string.
221- while ((Ret = iconv (ConvDesc, &Input, &InputLength, &Output, &OutputLength)))
222- if (auto EC = HandleError (Ret))
223- return EC;
224- // Flush the converter
225- while ((Ret = iconv (ConvDesc, nullptr , nullptr , &Output, &OutputLength)))
226- if (auto EC = HandleError (Ret))
227- return EC;
241+ do {
242+ // Setup the input. Use nullptr to reset iconv state if input length is
243+ // zero.
244+ size_t InputLength = Source.size ();
245+ char *Input = InputLength ? const_cast <char *>(Source.data ()) : nullptr ;
246+ Ret = iconv (ConvDesc, &Input, &InputLength, &Output, &OutputLength);
247+ if (Ret != 0 ) {
248+ if (auto EC = HandleError (Ret))
249+ return EC;
250+ continue ;
251+ }
252+ // Flush the converter
253+ Ret = iconv (ConvDesc, nullptr , nullptr , &Output, &OutputLength);
254+ if (Ret != 0 ) {
255+ if (auto EC = HandleError (Ret))
256+ return EC;
257+ continue ;
258+ }
259+ break ;
260+ } while (true );
228261
229262 // Re-adjust size to actual size.
230263 Result.resize (Capacity - OutputLength);
0 commit comments