1 /**********************************************************\ 2 | | 3 | hprose | 4 | | 5 | Official WebSite: http://www.hprose.com/ | 6 | http://www.hprose.org/ | 7 | | 8 \**********************************************************/ 9 10 /**********************************************************\ 11 * * 12 * hprose/io/bytes.d * 13 * * 14 * hprose bytes io library for D. * 15 * * 16 * LastModified: Mar 11, 2016 * 17 * Author: Ma Bingyao <andot@hprose.com> * 18 * * 19 \**********************************************************/ 20 21 module hprose.io.bytes; 22 23 @trusted: 24 25 import hprose.io.tags; 26 import std.algorithm; 27 import std.bigint; 28 import std.conv; 29 import std.stdio; 30 import std.string; 31 import std.traits; 32 33 class BytesIO { 34 private { 35 char[] _buffer; 36 int _pos; 37 } 38 39 @property { 40 int size() { 41 return cast(int)_buffer.length; 42 } 43 bool eof() { 44 return _pos >= size; 45 } 46 immutable(ubyte)[] buffer() { 47 return cast(immutable(ubyte)[])_buffer; 48 } 49 } 50 51 this() { 52 this(""); 53 } 54 this(BytesIO data) { 55 init(data.buffer); 56 } 57 this(string data) { 58 init(data); 59 } 60 this(ubyte[] data) { 61 init(data); 62 } 63 void init(T)(T data) { 64 _buffer = cast(char[])data; 65 _pos = 0; 66 } 67 void close() { 68 _buffer.length = 0; 69 _pos = 0; 70 } 71 char read() { 72 if (size > _pos) { 73 return _buffer[_pos++]; 74 } 75 else { 76 throw new Exception("no byte found in stream"); 77 } 78 } 79 char[] read(int n) { 80 char[] bytes = _buffer[_pos .. _pos + n]; 81 _pos += n; 82 return bytes; 83 } 84 char[] readFull() { 85 char[] bytes = _buffer[_pos .. $]; 86 _pos = size; 87 return bytes; 88 } 89 char[] readUntil(T...)(T tags) { 90 long count = countUntil(_buffer[_pos .. $], tags); 91 if (count < 0) return readFull(); 92 char[] bytes = _buffer[_pos .. _pos + count]; 93 _pos += count + 1; 94 return bytes; 95 } 96 char[] readBytes(T...)(T tags) { 97 long count = countUntil(_buffer[_pos .. $], tags); 98 if (count < 0) return readFull(); 99 count++; 100 char[] bytes = _buffer[_pos .. _pos + count]; 101 _pos += count; 102 return bytes; 103 } 104 char skipUntil(T...)(T tags) { 105 auto count = countUntil(_buffer[_pos .. $], tags); 106 if (count < 0) throw new Exception("does not find tags in stream"); 107 char result = _buffer[_pos + count]; 108 _pos += count + 1; 109 return result; 110 } 111 string readUTF8Char() { 112 int pos = _pos; 113 ubyte tag = read(); 114 switch (tag >> 4) { 115 case 0: .. case 7: break; 116 case 12, 13: ++_pos; break; 117 case 14: _pos += 2; break; 118 default: throw new Exception("bad utf-8 encoding"); 119 } 120 if (_pos > size) throw new Exception("bad utf-8 encoding"); 121 return cast(string)_buffer[pos .. _pos]; 122 } 123 T readString(T = string)(int wlen) if (isSomeString!T) { 124 int pos = _pos; 125 for (int i = 0; i < wlen; ++i) { 126 ubyte tag = read(); 127 switch (tag >> 4) { 128 case 0: .. case 7: break; 129 case 12, 13: ++_pos; break; 130 case 14: _pos += 2; break; 131 case 15: _pos += 3; ++i; break; 132 default: throw new Exception("bad utf-8 encoding"); 133 } 134 } 135 if (_pos > size) throw new Exception("bad utf-8 encoding"); 136 return cast(T)_buffer[pos .. _pos]; 137 } 138 T readInt(T = int)(char tag) if (isSigned!T) { 139 int c = read(); 140 if (c == tag) return 0; 141 T result = 0; 142 int len = size; 143 T sign = 1; 144 switch (c) { 145 case TagNeg: sign = -1; goto case TagPos; 146 case TagPos: c = read(); goto default; 147 default: break; 148 } 149 while (_pos < len && c != tag) { 150 result *= 10; 151 result += (c - '0') * sign; 152 c = read(); 153 } 154 return result; 155 } 156 T readInt(T)(char tag) if (isUnsigned!T) { 157 return cast(T)readInt!(Signed!T)(tag); 158 } 159 void skip(int n) { 160 _pos += n; 161 } 162 BytesIO write(in char[] data) { 163 if (data.length > 0) { 164 _buffer ~= data; 165 } 166 return this; 167 } 168 BytesIO write(in byte[] data) { 169 return write(cast(char[])data); 170 } 171 BytesIO write(in ubyte[] data) { 172 return write(cast(char[])data); 173 } 174 BytesIO write(BytesIO data) { 175 return write(cast(char[])data.buffer); 176 } 177 BytesIO write(T)(in T x) { 178 static if (is(T == char)) { 179 _buffer ~= x; 180 } 181 else static if (is(T == ubyte) || is(T == byte)) { 182 _buffer ~= cast(char)x; 183 } 184 else static if (isIntegral!T || 185 isSomeChar!T || 186 is(T == float)) { 187 _buffer ~= cast(char[])to!string(x); 188 } 189 else static if (is(T == double) || 190 is(T == real)) { 191 _buffer ~= cast(char[])format("%.16g", x); 192 } 193 return this; 194 } 195 override string toString() { 196 return cast(string)_buffer; 197 } 198 } 199 200 unittest { 201 BytesIO bytes = new BytesIO("i123;d3.14;"); 202 assert(bytes.readUntil(';') == "i123"); 203 assert(bytes.readUntil(';') == "d3.14"); 204 bytes.write("hello"); 205 assert(bytes.read(5) == "hello"); 206 const int i = 123456789; 207 bytes.write(i).write(';'); 208 assert(bytes.readInt(';') == i); 209 bytes.write(1).write('1').write(';'); 210 assert(bytes.readInt(';') == 11); 211 const float f = 3.14159265; 212 bytes.write(f).write(';'); 213 assert(bytes.readUntil(';') == "3.14159"); 214 const double d = 3.141592653589793238; 215 bytes.write(d).write(';'); 216 assert(bytes.readUntil(';') == "3.141592653589793"); 217 const real r = 3.141592653589793238; 218 bytes.write(r).write(';'); 219 assert(bytes.readUntil(';', '.') == "3"); 220 assert(bytes.skipUntil(';', '.') == ';'); 221 bytes.write("你好啊"); 222 assert(bytes.readString(3) == "你好啊"); 223 }