1// Copyright (C) 2003-2015 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 3, 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 COPYING3.  If not see
16// <http://www.gnu.org/licenses/>.
17
18// 27.8.1.4 Overridden virtual functions
19
20#include <fstream>
21#include <locale>
22#include <cstdio>
23#include <testsuite_hooks.h>
24
25template <typename InternT, typename StateT = mbstate_t>
26class checksumcvt : public std::codecvt<InternT, char, StateT>
27{
28  typedef std::codecvt<InternT, char, StateT> Base;
29  static const size_t width = sizeof(InternT) + 1;
30
31public:
32  typedef InternT intern_type;
33  typedef char extern_type;
34
35  explicit checksumcvt(size_t refs = 0)
36  : Base(refs)
37  { }
38
39protected:
40  virtual typename std::codecvt<InternT, char, StateT>::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 = reinterpret_cast<const char*>(from);
52	unsigned char checksum = 0;
53
54	for (size_t i = 0; i < sizeof(intern_type); ++i)
55	  {
56	    *to++ = p[i];
57	    checksum ^= static_cast<unsigned char>(p[i]);
58	  }
59
60	*to++ = checksum;
61	++from;
62      }
63
64    from_next = from;
65    to_next = to;
66    return from_next == from_end ? std::codecvt<InternT, char, StateT>::ok
67           : std::codecvt<InternT, char, StateT>::partial;
68  }
69
70  virtual typename std::codecvt<InternT, char, StateT>::result
71  do_unshift(StateT&, extern_type* to,
72	     extern_type*, extern_type*& to_next) const
73  {
74    to_next = to;
75    return std::codecvt<InternT, char, StateT>::ok;
76  }
77
78  virtual typename std::codecvt<InternT, char, StateT>::result
79  do_in(StateT&, const extern_type* from,
80	const extern_type* from_end, const extern_type*& from_next,
81	intern_type* to, intern_type* to_end,
82	intern_type*& to_next) const
83  {
84    size_t len = std::min(static_cast<size_t>(to_end - to),
85			  static_cast<size_t>(from_end - from) / width);
86
87    while (len)
88      {
89	const char* f = from;
90	intern_type tmp;
91	char* p = reinterpret_cast<char*>(&tmp);
92	unsigned char checksum = 0;
93
94	for (size_t i = 0; i < sizeof(intern_type); ++i)
95	  {
96	    p[i] = *f;
97	    checksum ^= static_cast<unsigned char>(*f++);
98	  }
99
100	if (*f++ != checksum)
101	  break;
102
103	from = f;
104	*to++ = tmp;
105	len--;
106      }
107
108    from_next = from;
109    to_next = to;
110    return len ? std::codecvt<InternT, char, StateT>::error :
111      (from_next == from_end ? std::codecvt<InternT, char, StateT>::ok
112       : std::codecvt<InternT, char, StateT>::partial);
113  }
114
115  virtual int
116  do_encoding() const throw()
117  { return width; }
118
119  virtual int
120  do_length(StateT&, const extern_type* from,
121	    const extern_type* end, size_t max) const
122  {
123    size_t len = std::min(max, static_cast<size_t>(end - from) / width);
124
125    int ret = 0;
126    while (len--)
127      {
128	unsigned char checksum = 0;
129
130	for (size_t i = 0; i < sizeof(intern_type); ++i)
131	  {
132	    checksum ^= static_cast<unsigned char>(*from++);
133	  }
134
135	if (*from++ != checksum)
136	  break;
137
138	ret++;
139      }
140
141    return ret;
142  }
143
144  virtual int
145  do_max_length() const throw()
146  { return width; }
147
148  virtual bool
149  do_always_noconv() const throw()
150  { return false; }
151};
152
153// libstdc++/11544 (invalid byte sequence in file)
154void test02()
155{
156  using namespace std;
157  bool test __attribute__((unused)) = true;
158
159  locale loc(locale::classic(), new checksumcvt<wchar_t>);
160
161  const char* name = "tmp_11544-2";
162
163  FILE* f = fopen(name, "w");
164  VERIFY( fwrite("aaaab", 1, 5, f) == 5 );
165  fclose(f);
166
167  wifstream in;
168  in.imbue(loc);
169  in.open(name);
170
171  VERIFY( in.good() );
172  in.get();
173  VERIFY( !in.good() );
174  VERIFY( in.bad() );
175  VERIFY( !in.eof() );
176
177  in.close();
178}
179
180int main()
181{
182  test02();
183  return 0;
184}
185