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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17// USA.
18
19// 27.8.1.4 Overridden virtual functions
20
21#include <fstream>
22#include <locale>
23#include <cstdio>
24#include <testsuite_hooks.h>
25
26template <typename InternT, typename StateT = mbstate_t>
27class checksumcvt : public std::codecvt<InternT, char, StateT>
28{
29  typedef std::codecvt<InternT, char, StateT> Base;
30  static const size_t width = sizeof(InternT) + 1;
31
32public:
33  typedef InternT intern_type;
34  typedef char extern_type;
35
36  explicit checksumcvt(size_t refs = 0)
37  : Base(refs)
38  { }
39
40protected:
41  virtual typename std::codecvt<InternT, char, StateT>::result
42  do_out(StateT&, const intern_type* from,
43	 const intern_type* from_end, const intern_type*& from_next,
44	 extern_type* to, extern_type* to_end,
45	 extern_type*& to_next) const
46  {
47    size_t len = std::min(static_cast<size_t>(from_end - from),
48			  static_cast<size_t>(to_end - to) / width);
49
50    while (len--)
51      {
52	const char* p = reinterpret_cast<const char*>(from);
53	unsigned char checksum = 0;
54
55	for (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<InternT, char, StateT>::ok
68           : std::codecvt<InternT, char, StateT>::partial;
69  }
70
71  virtual typename std::codecvt<InternT, char, StateT>::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<InternT, char, StateT>::ok;
77  }
78
79  virtual typename std::codecvt<InternT, char, StateT>::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 (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<InternT, char, StateT>::error :
112      (from_next == from_end ? std::codecvt<InternT, char, StateT>::ok
113       : std::codecvt<InternT, char, StateT>::partial);
114  }
115
116  virtual int
117  do_encoding() const throw()
118  { return width; }
119
120  virtual int
121  do_length(StateT&, const extern_type* from,
122	    const extern_type* end, size_t max) const
123  {
124    size_t len = std::min(max, static_cast<size_t>(end - from) / width);
125
126    int ret = 0;
127    while (len--)
128      {
129	unsigned char checksum = 0;
130
131	for (size_t i = 0; i < sizeof(intern_type); ++i)
132	  {
133	    checksum ^= static_cast<unsigned char>(*from++);
134	  }
135
136	if (*from++ != checksum)
137	  break;
138
139	ret++;
140      }
141
142    return ret;
143  }
144
145  virtual int
146  do_max_length() const throw()
147  { return width; }
148
149  virtual bool
150  do_always_noconv() const throw()
151  { return false; }
152};
153
154// libstdc++/11544 (incomplete character in file)
155void test01()
156{
157  using namespace std;
158  bool test __attribute__((unused)) = true;
159
160  locale loc(locale::classic(), new checksumcvt<wchar_t>);
161
162  const char* name = "tmp_11544-1";
163
164  FILE* f = fopen(name, "w");
165  putc('a', f);
166  fclose(f);
167
168  wifstream in;
169  in.imbue(loc);
170  in.open(name);
171
172  VERIFY( in.good() );
173  in.get();
174  VERIFY( !in.good() );
175  VERIFY( in.bad() );
176  VERIFY( !in.eof() );
177
178  in.close();
179}
180
181int main()
182{
183  test01();
184  return 0;
185}
186