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 <string>
23#include <iterator>
24#include <algorithm>
25#include <locale>
26#include <testsuite_hooks.h>
27
28template <typename InternT, typename StateT = mbstate_t>
29class checksumcvt : public std::codecvt<InternT, char, StateT>
30{
31  typedef std::codecvt<InternT, char, StateT> Base;
32  static const size_t width = sizeof(InternT) + 1;
33
34public:
35  typedef InternT intern_type;
36  typedef char extern_type;
37
38  explicit checksumcvt(size_t refs = 0)
39  : Base(refs)
40  { }
41
42protected:
43  virtual typename std::codecvt<InternT, char, StateT>::result
44  do_out(StateT&, const intern_type* from,
45	 const intern_type* from_end, const intern_type*& from_next,
46	 extern_type* to, extern_type* to_end,
47	 extern_type*& to_next) const
48  {
49    size_t len = std::min(static_cast<size_t>(from_end - from),
50			  static_cast<size_t>(to_end - to) / width);
51
52    while (len--)
53      {
54	const char* p = reinterpret_cast<const char*>(from);
55	unsigned char checksum = 0;
56
57	for (size_t i = 0; i < sizeof(intern_type); ++i)
58	  {
59	    *to++ = p[i];
60	    checksum ^= static_cast<unsigned char>(p[i]);
61	  }
62
63	*to++ = checksum;
64	++from;
65      }
66
67    from_next = from;
68    to_next = to;
69    return from_next == from_end ? std::codecvt<InternT, char, StateT>::ok
70           : std::codecvt<InternT, char, StateT>::partial;
71  }
72
73  virtual typename std::codecvt<InternT, char, StateT>::result
74  do_unshift(StateT&, extern_type* to,
75	     extern_type*, extern_type*& to_next) const
76  {
77    to_next = to;
78    return std::codecvt<InternT, char, StateT>::ok;
79  }
80
81  virtual typename std::codecvt<InternT, char, StateT>::result
82  do_in(StateT&, const extern_type* from,
83	const extern_type* from_end, const extern_type*& from_next,
84	intern_type* to, intern_type* to_end,
85	intern_type*& to_next) const
86  {
87    size_t len = std::min(static_cast<size_t>(to_end - to),
88			  static_cast<size_t>(from_end - from) / width);
89
90    while (len)
91      {
92	const char* f = from;
93	intern_type tmp;
94	char* p = reinterpret_cast<char*>(&tmp);
95	unsigned char checksum = 0;
96
97	for (size_t i = 0; i < sizeof(intern_type); ++i)
98	  {
99	    p[i] = *f;
100	    checksum ^= static_cast<unsigned char>(*f++);
101	  }
102
103	if (*f++ != checksum)
104	  break;
105
106	from = f;
107	*to++ = tmp;
108	len--;
109      }
110
111    from_next = from;
112    to_next = to;
113    return len ? std::codecvt<InternT, char, StateT>::error :
114      (from_next == from_end ? std::codecvt<InternT, char, StateT>::ok
115       : std::codecvt<InternT, char, StateT>::partial);
116  }
117
118  virtual int
119  do_encoding() const throw()
120  {
121    return width;
122  }
123
124  virtual int
125  do_length(StateT&, const extern_type* from,
126	    const extern_type* end, size_t max) const
127  {
128    size_t len = std::min(max, static_cast<size_t>(end - from) / width);
129
130    int ret = 0;
131    while (len--)
132      {
133	unsigned char checksum = 0;
134
135	for (size_t i = 0; i < sizeof(intern_type); ++i)
136	  {
137	    checksum ^= static_cast<unsigned char>(*from++);
138	  }
139
140	if (*from++ != checksum)
141	  break;
142
143	ret++;
144      }
145
146    return ret;
147  }
148
149  virtual int
150  do_max_length() const throw()
151  {
152    return width;
153  }
154
155  virtual bool
156  do_always_noconv() const throw()
157  {
158    return false;
159  }
160};
161
162void test01()
163{
164  using namespace std;
165  bool test __attribute__((unused)) = true;
166
167  locale loc;
168  loc = locale(loc, new checksumcvt<wchar_t>);
169
170  wfilebuf fbuf1;
171  fbuf1.pubimbue(loc);
172  fbuf1.open("tmp_9178", ios_base::out | ios_base::trunc);
173
174  string tmpstr = "abcdefghijklmnopqrstuvwxyz0123456789 \t\n";
175
176  wifstream stream;
177  wstring str1;
178
179  while (str1.length() < 20000)
180    {
181      transform(tmpstr.begin(), tmpstr.end(),
182		back_inserter(str1),
183		bind1st(std::mem_fun(&std::wios::widen), &stream));
184    }
185
186  fbuf1.sputn(str1.data(), str1.size());
187  fbuf1.close();
188
189  wfilebuf fbuf2;
190  fbuf2.pubimbue(loc);
191  fbuf2.open("tmp_9178", std::ios_base::in);
192
193  wstring str2;
194  copy(istreambuf_iterator<wchar_t>(&fbuf2),
195       istreambuf_iterator<wchar_t>(),
196       back_inserter(str2));
197
198  VERIFY( str1 == str2 );
199}
200
201int main()
202{
203  test01();
204  return 0;
205}
206