Imported Upstream version 2.1.2
[platform/upstream/fdupes.git] / mbstowcs_escape_invalid.c
1 /* Copyright (c) 2019 Adrian Lopez
2
3    This software is provided 'as-is', without any express or implied
4    warranty. In no event will the authors be held liable for any damages
5    arising from the use of this software.
6
7    Permission is granted to anyone to use this software for any purpose,
8    including commercial applications, and to alter it and redistribute it
9    freely, subject to the following restrictions:
10
11    1. The origin of this software must not be misrepresented; you must not
12       claim that you wrote the original software. If you use this software
13       in a product, an acknowledgment in the product documentation would be
14       appreciated but is not required.
15    2. Altered source versions must be plainly marked as such, and must not be
16       misrepresented as being the original software.
17    3. This notice may not be removed or altered from any source distribution. */
18
19 #include "config.h"
20 #include "mbstowcs_escape_invalid.h"
21 #include <wchar.h>
22 #include <string.h>
23 #include <stdio.h>
24
25 void reset_mbstate(mbstate_t *state)
26 {
27     memset(state, 0, sizeof(mbstate_t));
28 }
29
30 size_t putoctal(wchar_t *dest, char c)
31 {
32     swprintf(dest, 5, L"\\%03o", (unsigned char) c);
33     return 4;
34 }
35
36 size_t put_invalid_sequence(wchar_t *dest, const char *src, size_t *destination_index, size_t count, size_t max)
37 {
38     size_t x;
39
40     for (x = 0; x < count; ++x)
41     {
42         if (dest != 0)
43         {
44             if (*destination_index + 5 > max)
45                 return x;
46
47             putoctal(dest + *destination_index, src[x]);
48         }
49
50         *destination_index += 4;
51     }
52
53     return count;
54 }
55
56 size_t mbstowcs_escape_invalid(wchar_t *dest, const char *src, size_t n)
57 {
58     mbstate_t state;
59     wchar_t wc;
60     size_t x;
61     size_t i;
62     size_t dx;
63     size_t write;
64     size_t written;
65     size_t result;
66
67     reset_mbstate(&state);
68
69     x = 0;
70     i = 0;
71     dx = 0;
72
73     while (src[x] != '\0')
74     {
75         result = mbrtowc(&wc, src + x, 1, &state);
76
77         if (result == -2)
78         /* sequence is not yet complete */
79         {
80             ++x;
81             ++i;
82         }
83         else if (result == -1)
84         /* invalid sequence */
85         {
86             write = i == 0 ? 1 : i;
87
88             if (dest != 0)
89             {
90                 written = put_invalid_sequence(dest, src + (x - i), &dx, write, n);
91
92                 if (written != write)
93                     return -1;
94             }
95             else
96                 put_invalid_sequence(0, src + (x - i), &dx, write, 0);
97
98             if (i == 0)
99                 ++x;
100     
101             i = 0;
102
103             reset_mbstate(&state);
104         }
105         else if (result != 0)
106         /* OK, add character */
107         {
108             if (dest != 0)
109             {
110                 if (dx < n)
111                     dest[dx++] = wc;
112                 else
113                     return -1;
114             }
115             else
116                 ++dx;
117
118             ++x;
119
120             i = 0;
121         }
122         
123         if (src[x] == L'\0' && i > 0)
124         /* output final incomplete sequence */
125         {
126             if (dest != 0)
127             {
128                 written = put_invalid_sequence(dest, src + (x - i), &dx, i, n);
129
130                 if (written != i)
131                     return -1;
132             }
133             else
134                 put_invalid_sequence(0, src + (x - i), &dx, i, 0);
135         }        
136     }
137
138     if (dest != 0)
139     {
140         if (dx < n)
141             dest[dx] = L'\0';
142         else
143             return -1;
144     }
145
146     return dx + 1;
147 }