1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #ifndef HIDUTIL_STREAM_IO_UTIL_H_
17 #define HIDUTIL_STREAM_IO_UTIL_H_
18
19 #include "HidLog.h"
20 #include <istream>
21 #include <iomanip>
22 #include <sstream>
23 #include <vector>
24 #include <cassert>
25
26 namespace HidUtil {
27
28 template<typename CharT>
29 class charvectorbuf : public std::streambuf { // class name is consistent with std lib
30 static_assert(std::is_const<CharT>::value == false, "cannot use const type");
31 public:
32 // r/w buffer constructors
charvectorbuf(std::vector<CharT> & vec)33 charvectorbuf(std::vector<CharT> &vec) {
34 init(vec.data(), vec.size());
35 }
36
charvectorbuf(CharT * begin,CharT * end)37 charvectorbuf(CharT *begin, CharT *end) {
38 assert(end >= begin);
39 init(begin, end - begin);
40 }
41
charvectorbuf(CharT * begin,size_t size)42 charvectorbuf(CharT *begin, size_t size) {
43 init(begin, size);
44 }
45
46 // r/o buffer constructor
charvectorbuf(const std::vector<CharT> & vec)47 charvectorbuf(const std::vector<CharT> &vec) {
48 init(vec.data(), vec.size());
49 }
50
charvectorbuf(const CharT * begin,const CharT * end)51 charvectorbuf(const CharT *begin, const CharT *end) {
52 assert(end >= begin);
53 init(begin, end - begin);
54 }
55
charvectorbuf(const CharT * begin,size_t size)56 charvectorbuf(const CharT *begin, size_t size) {
57 init(begin, size);
58 }
59 protected:
60 virtual std::streampos seekpos(
61 std::streampos sp, std::ios_base::openmode which =
62 std::ios_base::in | std::ios_base::out) override {
63 return seekoff(std::streamoff(sp), std::ios_base::beg, which);
64 }
65
66 // this is needed to use ftell() on stream
67 virtual std::streampos seekoff(
68 std::streamoff off, std::ios_base::seekdir way,
69 std::ios_base::openmode which =
70 std::ios_base::in | std::ios_base::out) override {
71
72 // pptr() == nullptr: read-only
73 assert(pptr() == nullptr || egptr() - eback() == epptr() - pbase());
74 bool in = which & std::ios_base::in;
75 bool out = which & std::ios_base::out;
76 pos_type end = egptr() - eback();
77
78 if (!in && !out) {
79 return pos_type(-1);
80 }
81
82 if (in && out && way == std::ios_base::cur) {
83 return pos_type(-1);
84 }
85
86 off_type noff;
87 switch (way) {
88 case std::ios_base::beg:
89 noff = 0;
90 break;
91 case std::ios_base::cur:
92 if (in) {
93 noff = gptr() - eback();
94 } else {
95 noff = pptr() - pbase();
96 }
97 break;
98 case std::ios_base::end:
99 noff = end;
100 break;
101 default:
102 return pos_type(-1);
103 }
104 noff += off;
105 if (noff < 0 || noff > end) {
106 return pos_type(-1);
107 }
108
109 if (noff != 0 && ((in && gptr() == nullptr) || (out && pptr() == nullptr))) {
110 return pos_type(-1);
111 }
112
113 if (in) {
114 setg(eback(), eback() + noff, egptr());
115 }
116
117 if (out) {
118 setp(pbase(), epptr());
119 pbump(noff);
120 }
121
122 return pos_type(noff);
123 }
124 private:
125 // read only buffer init
init(const CharT * base,size_t size)126 void init(const CharT *base, size_t size) {
127 setg((char*)base, (char*)base, (char*)(base + size));
128 }
129
130 // read write buffer init
init(CharT * base,size_t size)131 void init(CharT *base, size_t size) {
132 setg((char*)base, (char*)base, (char*)(base + size));
133 setp((char*)base, (char*)(base + size));
134 }
135 };
136
137 // dump binary values
138 template <class ForwardIterator>
hexdumpToStream(std::ostream & os,const ForwardIterator & first,const ForwardIterator & last)139 void hexdumpToStream(std::ostream &os, const ForwardIterator &first, const ForwardIterator &last) {
140 static_assert(
141 std::is_convertible<
142 typename std::iterator_traits<ForwardIterator>::iterator_category,
143 std::forward_iterator_tag>::value
144 && std::is_convertible<
145 typename std::iterator_traits<ForwardIterator>::value_type,
146 unsigned char>::value
147 && sizeof(typename std::iterator_traits<ForwardIterator>::value_type)
148 == sizeof(unsigned char),
149 "Only accepts forward iterator of a type of size 1 "
150 "that can be convert to unsigned char.\n");
151 size_t c = 0;
152 std::ostringstream ss;
153 for (ForwardIterator i = first; i != last; ++i, ++c) {
154 unsigned char v = *i;
155 // formatting
156 switch (c & 0xf) {
157 case 0:
158 // address
159 os << ss.str() << LOG_ENDL;
160 ss.str("");
161 ss << std::hex;
162 ss << std::setfill('0') << std::setw(4) << c << ": ";
163 break;
164 case 8:
165 // space
166 ss << " ";
167 break;
168 }
169 ss << std::setfill('0') << std::setw(2)
170 << static_cast<unsigned>(static_cast<unsigned char>(v)) << " ";
171 }
172 os << ss.str() << LOG_ENDL;
173 }
174 } //namespace HidUtil
175
176 #endif // HIDUTIL_STREAM_IO_UTIL_H_
177
178