]>
Commit | Line | Data |
---|---|---|
5536b61c PC |
1 | // Copyright (C) 2003 Free Software Foundation, Inc. |
2 | // | |
3 | // This file is part of the GNU ISO C++ Library. This library is free | |
4 | // software; you can redistribute it and/or modify it under the | |
5 | // terms of the GNU General Public License as published by the | |
6 | // Free Software Foundation; either version 2, or (at your option) | |
7 | // any later version. | |
8 | ||
9 | // This library is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
13 | ||
14 | // You should have received a copy of the GNU General Public License along | |
15 | // with this library; see the file COPYING. If not, write to the Free | |
16 | // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |
17 | // USA. | |
18 | ||
19 | // 27.8.1.4 Overridden virtual functions | |
20 | ||
21 | #include <fstream> | |
22 | #include <locale> | |
23 | #include <testsuite_hooks.h> | |
24 | ||
25 | template <typename InternT, typename StateT = std::mbstate_t> | |
26 | class checksumcvt : public std::codecvt<InternT, char, StateT> | |
27 | { | |
28 | typedef std::codecvt<InternT, char, StateT> Base; | |
29 | static const std::size_t width = sizeof(InternT) + 1; | |
30 | ||
31 | public: | |
32 | typedef InternT intern_type; | |
33 | typedef char extern_type; | |
34 | ||
35 | explicit checksumcvt(std::size_t refs = 0) | |
36 | : Base(refs) | |
37 | { } | |
38 | ||
39 | protected: | |
40 | virtual std::codecvt_base::result | |
41 | do_out(StateT&, const intern_type* from, | |
42 | const intern_type* from_end, const intern_type*& from_next, | |
43 | extern_type* to, extern_type* to_end, | |
44 | extern_type*& to_next) const | |
45 | { | |
46 | size_t len = std::min(static_cast<size_t>(from_end - from), | |
47 | static_cast<size_t>(to_end - to) / width); | |
48 | ||
49 | while (len--) | |
50 | { | |
51 | const char* p = | |
52 | reinterpret_cast<const char*>(from); | |
53 | unsigned char checksum = 0; | |
54 | ||
55 | for (std::size_t i = 0; i < sizeof(intern_type); ++i) | |
56 | { | |
57 | *to++ = p[i]; | |
58 | checksum ^= static_cast<unsigned char>(p[i]); | |
59 | } | |
60 | ||
61 | *to++ = checksum; | |
62 | ++from; | |
63 | } | |
64 | ||
65 | from_next = from; | |
66 | to_next = to; | |
67 | return from_next == from_end ? std::codecvt_base::ok | |
68 | : std::codecvt_base::partial; | |
69 | } | |
70 | ||
71 | virtual std::codecvt_base::result | |
72 | do_unshift(StateT&, extern_type* to, | |
73 | extern_type*, extern_type*& to_next) const | |
74 | { | |
75 | to_next = to; | |
76 | return std::codecvt_base::ok; | |
77 | } | |
78 | ||
79 | virtual std::codecvt_base::result | |
80 | do_in(StateT&, const extern_type* from, | |
81 | const extern_type* from_end, const extern_type*& from_next, | |
82 | intern_type* to, intern_type* to_end, | |
83 | intern_type*& to_next) const | |
84 | { | |
85 | size_t len = std::min(static_cast<size_t>(to_end - to), | |
86 | static_cast<size_t>(from_end - from) / width); | |
87 | ||
88 | while (len) | |
89 | { | |
90 | const char* f = from; | |
91 | intern_type tmp; | |
92 | char* p = reinterpret_cast<char*>(&tmp); | |
93 | unsigned char checksum = 0; | |
94 | ||
95 | for (std::size_t i = 0; i < sizeof(intern_type); ++i) | |
96 | { | |
97 | p[i] = *f; | |
98 | checksum ^= static_cast<unsigned char>(*f++); | |
99 | } | |
100 | ||
101 | if (*f++ != checksum) | |
102 | break; | |
103 | ||
104 | from = f; | |
105 | *to++ = tmp; | |
106 | len--; | |
107 | } | |
108 | ||
109 | from_next = from; | |
110 | to_next = to; | |
111 | return len ? std::codecvt_base::error : | |
112 | (from_next == from_end ? std::codecvt_base::ok | |
113 | : std::codecvt_base::partial); | |
114 | } | |
115 | ||
116 | virtual int | |
117 | do_encoding() const throw() | |
118 | { return width; } | |
119 | ||
120 | virtual int | |
121 | do_length(const StateT&, const extern_type* from, | |
122 | const extern_type* end, size_t max) const | |
123 | { | |
124 | size_t len = std::min(max, | |
125 | static_cast<size_t>(end - from) / width); | |
126 | ||
127 | int ret = 0; | |
128 | while (len--) | |
129 | { | |
130 | unsigned char checksum = 0; | |
131 | ||
132 | for (std::size_t i = 0; i < sizeof(intern_type); ++i) | |
133 | { | |
134 | checksum ^= static_cast<unsigned char>(*from++); | |
135 | } | |
136 | ||
137 | if (*from++ != checksum) | |
138 | break; | |
139 | ||
140 | ret++; | |
141 | } | |
142 | ||
143 | return ret; | |
144 | } | |
145 | ||
146 | virtual int | |
147 | do_max_length() const throw() | |
148 | { return width; } | |
149 | ||
150 | virtual bool | |
151 | do_always_noconv() const throw() | |
152 | { return false; } | |
153 | }; | |
154 | ||
155 | class Buf : public std::wfilebuf | |
156 | { | |
157 | public: | |
158 | std::streamsize pub_showmanyc() | |
159 | { return showmanyc(); } | |
160 | std::wfilebuf::int_type pub_underflow() | |
161 | { return underflow(); } | |
162 | }; | |
163 | ||
164 | // libstdc++/11603 | |
165 | void test01() | |
166 | { | |
167 | using namespace std; | |
168 | bool test __attribute__((unused)) = true; | |
169 | ||
170 | filebuf fbout; | |
171 | fbout.open("tmp_11603", ios_base::out); | |
172 | fbout.sputn("aaaab", 5); | |
173 | fbout.close(); | |
174 | ||
175 | locale loc(locale::classic(), new checksumcvt<wchar_t>); | |
176 | ||
177 | Buf fb; | |
178 | fb.pubimbue(loc); | |
179 | fb.open("tmp_11603", ios_base::in); | |
180 | assert(fb.pub_showmanyc() == 1); | |
181 | ||
182 | try | |
183 | { | |
184 | wfilebuf::int_type ret = fb.pub_underflow(); | |
185 | VERIFY( ret != wfilebuf::traits_type::eof() ); | |
186 | fb.sbumpc(); | |
187 | ret = fb.pub_underflow(); | |
188 | VERIFY( ret == wfilebuf::traits_type::eof() ); | |
189 | } | |
190 | catch (...) | |
191 | { } | |
192 | ||
193 | fb.close(); | |
194 | } | |
195 | ||
196 | int main() | |
197 | { | |
198 | test01(); | |
199 | return 0; | |
200 | } |