8 #include "InputStream.h"
10 #include "smart_ptr.h"
13 using namespace utakata::utf8;
15 UTF8InputStream::UTF8InputStream() : EOF_(0xff), strm_(), pos_(0)
19 UTF8InputStream::UTF8InputStream(smart_ptr<std::istream> strm) : EOF_(0xff), strm_(strm),
24 bool UTF8InputStream::open(smart_ptr<std::istream> strm)
26 //現在保持しているストリームと切り替える。
27 // 基本的にただスワップするだけで問題ない。
29 // NULLポインタではなく、問題無く開かれている場合には、次のようにして開始する。
30 if (strm.isNull() != false && !strm->good()) {
38 std::vector<unsigned char> UTF8InputStream::read()
41 // UTF-8に該当しない場合、空のvectorを返す。
42 if (!strm_->eof() && !strm_->good()) {
43 throw StreamException("not ready input stream");
46 // 最初に一文字だけ読みだして、チェックをかける。
49 if (c != std::istream::traits_type::eof())
51 // 末尾でない場合のみ、以降のチェックに入る。
53 // 先頭1バイトが正常でなかった場合はそのまま抜ける
54 if (is_utf8_first_byte(static_cast<unsigned char>(c), size))
58 // sizeが0より大きい場合には、この時複数バイトで文字が構成
59 // されていると考えられるため、明示的に複数文字を取得する。
60 std::vector<char> tmp(size, 0);
61 strm_->read(&tmp[0], size);
65 // 読み取りきれなかった場合には、ストリームに一応読出せた
67 std::for_each(tmp.rbegin(), tmp.rend(), PutBack(strm_));
68 return std::vector<unsigned char>(1, 0);
70 std::vector<unsigned char> rtn;
71 rtn.insert(rtn.begin(), tmp.begin(), tmp.end());
80 return std::vector<unsigned char>(1, EOF_);
83 std::vector<unsigned char> UTF8InputStream::read(int num)
86 // 途中で終了した場合、その文字の分だけunsigned charが減少すること
88 // numが0の場合、必ず空のvectorが返される。
92 return std::vector<unsigned char>();
95 // eofの場合なら、この時点でeofが返るので、それで問題はない。
96 std::vector<unsigned char> rtn = this->read();
97 for (int i = 1; i < num && !strm_->eof(); ++i)
99 // 個数に到達するか、もしくはeofとなるまでは追加しつづける。
100 std::vector<unsigned char> tmp = this->read();
101 rtn.insert(rtn.end(), tmp.begin(), tmp.end());
109 std::vector<unsigned char> UTF8InputStream::peek()
111 // 一文字分だけ先読みする。先読みした場合、文字は戻す。
112 std::vector<unsigned char> tmp = this->read();
113 // 一応戻すサイズが存在する場合だけ、これを実行させることにする。
116 // 複雑な繰り返しを表現する場合には、積極的にalgorithmを利用するようにする。
118 std::for_each(tmp.rbegin(), tmp.rend(),
119 utakata::utf8::PutBack(strm_));
125 void UTF8InputStream::unget(const std::vector<unsigned char>& ch)
127 // 渡されたバイト列をストリームに差し戻す。
129 if (is_utf8_one(ch, t))
131 std::for_each(ch.rbegin(), ch.rend(), PutBack(strm_));
140 bool utakata::utf8::UTF8InputStream::isEOF() const
145 ret = strm_->eof() ? true : false;
155 //================================================================================
157 long utakata::utf8::generateUTF8Code(const std::vector<unsigned char>& bytes)
159 // 1文字分のUTF8のバイト列を受け取って、コードに変換して返す。
160 // 先頭の値によって、次のように値を決定することができる。
162 // y1〜yN = utf8の先頭バイト以降のバイト
163 // N = utf8の先頭バイトを含むバイト数
164 // code = (y1 & ((1 << 7) - 1)) << (6 * n-1) + (y2 & ((1 << 7) -1)) << (6 * (n - 1))...+ x & ((1 << N) -1) << (6 * N-1)
165 // 先頭バイト以外は、全て先頭に10とうビットが設定されている。このビットを除いた6ビットをする。
166 // つまり、末尾のバイトから順次やっていけばよい。
168 std::vector<unsigned char> tmp(bytes);
169 const unsigned char max_c = (1 << (sizeof(unsigned char) * 8 - 1)) - 1;
179 // asciiコードは7bitなのでそこだけ切り取って返す。
180 code = tmp[0] & max_c;
187 unsigned char operator()(unsigned char c, int s) {
192 // サイズが1以外の場合、ここからがちと違う。
193 std::vector<unsigned char>::reverse_iterator beg = tmp.rbegin(),
194 end = tmp.rend() - 1;
195 const unsigned char char_bit = (1 << 6) - 1;
196 for (int i = 0; beg != end; ++i,++beg)
198 code += Lambda()((*beg & char_bit), i);
202 const unsigned char first_byte = (1 << ((sizeof(unsigned char) + 1) - tmp.size())) - 1;
203 code += Lambda()(first_byte,tmp.size() - 1);
211 long utakata::utf8::generateUTF8Code(const std::string& bytes)
213 // UTF8である一文字のstringを受け取って、先頭1文字の値を返す。
215 std::string str = bytes;
216 std::vector<unsigned char> tmp;
217 tmp.insert(tmp.end(), str.begin(), str.end());
219 // vectorにしなおしたら後は元々の関数に任せる。
220 return generateUTF8Code(tmp);
223 bool utakata::utf8::is_utf8_one(const std::vector<unsigned char>& bytes, size_t& size)
225 //渡したバイト列がUTF8の一文字に該当するかどうかを返す。
228 if (bytes.size() == 0)
236 if (!is_utf8_first_byte(bytes[0], num))
242 // そもそもbytesのサイズが足りない場合にも失敗とする。
243 if (num > bytes.size())
249 // 先頭要素以外が正しければそれで問題ないとする。
253 const CheckUTF8Byte& checker = for_each(bytes.begin() + 1, bytes.begin() + num,
264 // sizeが0の場合には、この時点で1を設定するようにする。
272 bool utakata::utf8::is_utf8_all(const std::vector<unsigned char>& bytes)
274 // 与えられたバイト列全てがUTF-8であるかどうかを返す。
276 std::vector<unsigned char>::const_iterator it = bytes.begin();
277 while (is_utf8_one(std::vector<unsigned char>(it, bytes.end()), size)) {
282 if (it == bytes.end()) {
289 bool utakata::utf8::is_utf8_first_byte(unsigned char c, size_t& size)
291 // UTf-8の先頭バイトであるかどうかを返す。
292 // 先頭バイトである場合には、その先頭バイトを含む、一文字のサイズを返す。
294 const unsigned char max_c = 1 << (sizeof(unsigned char) * 8 - 1);
298 // 最上位ビットが0である場合、これはasciiコードを指す。
305 unsigned char first = c << 1;
307 while (first & max_c) {
312 // ここまできたとき、最上位ビットは0であるはず。
313 // numが5未満である場合、とりあえず正常としておくこととする。
314 const unsigned char max_utf8_sequence = 5;
315 if (num < max_utf8_sequence) {
321 // numが1の場合、何らかの理由で先頭が欠落したと見られる。
322 // この場合、スキップするべきバイト数を返す。
333 bool utakata::utf8::is_utf8_ascii(const std::vector<unsigned char>& bytes)
335 // 一文字かつ、0x00〜0x7fの範囲であるデータであることが条件となる。
337 bool b = is_utf8_one(bytes, s);
346 bool utakata::utf8::is_utf8_numeric(const std::vector<unsigned char>& bytes)
348 // 一文字分だけが渡されていると判断する。
349 if (!is_utf8_ascii(bytes))
354 if (bytes[0] >= '0' && bytes[0] <= '9')
362 bool utakata::utf8::is_utf8_alpha(const std::vector<unsigned char>& bytes)
365 // asciiのサブセットなので、先にasciiであると判別しておく。
366 if (!is_utf8_ascii(bytes))
371 if ((bytes[0] >= 'a' && bytes[0] <= 'z') ||
372 (bytes[0] >= 'A' && bytes[0] <= 'Z'))