1 /* 2 * hunt-proton: AMQP Protocol library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.proton.codec.WritableBuffer; 13 14 import hunt.proton.codec.ReadableBuffer; 15 import hunt.Exceptions; 16 import hunt.io.ByteBuffer; 17 import hunt.io.BufferUtils; 18 import std.stdio; 19 20 abstract class WritableBuffer { 21 void put(byte b); 22 23 void putFloat(float f); 24 25 void putDouble(double d); 26 27 void put(byte[] src, int offset, int length); 28 29 void putShort(short s); 30 31 void putInt(int i); 32 33 void putLong(long l); 34 35 bool hasRemaining(); 36 37 //default void ensureRemaining(int requiredRemaining) { 38 // // No-op to allow for drop in updates 39 //} 40 void ensureRemaining(int requiredRemaining) { 41 // No-op to allow for drop in updates 42 } 43 44 int remaining(); 45 46 int position(); 47 48 void position(int position); 49 50 void put(ByteBuffer payload); 51 52 void put(ReadableBuffer payload); 53 54 void put(string value) { 55 int length = cast(int)value.length; 56 57 for (int i = 0; i < length; i++) { 58 int c = value[i]; 59 if ((c & 0xFF80) == 0) { 60 // U+0000..U+007F 61 put(cast(byte) c); 62 } else if ((c & 0xF800) == 0) { 63 // U+0080..U+07FF 64 put(cast(byte) (0xC0 | ((c >> 6) & 0x1F))); 65 put(cast(byte) (0x80 | (c & 0x3F))); 66 } else if ((c & 0xD800) != 0xD800 || (c > 0xDBFF)) { 67 // U+0800..U+FFFF - excluding surrogate pairs 68 put(cast(byte) (0xE0 | ((c >> 12) & 0x0F))); 69 put(cast(byte) (0x80 | ((c >> 6) & 0x3F))); 70 put(cast(byte) (0x80 | (c & 0x3F))); 71 } else { 72 int low; 73 74 if ((++i == length) || ((low = value[i]) & 0xDC00) != 0xDC00) { 75 throw new IllegalArgumentException("String contains invalid Unicode code points"); 76 } 77 78 c = 0x010000 + ((c & 0x03FF) << 10) + (low & 0x03FF); 79 80 put(cast(byte) (0xF0 | ((c >> 18) & 0x07))); 81 put(cast(byte) (0x80 | ((c >> 12) & 0x3F))); 82 put(cast(byte) (0x80 | ((c >> 6) & 0x3F))); 83 put(cast(byte) (0x80 | (c & 0x3F))); 84 } 85 } 86 } 87 88 int limit(); 89 90 } 91 92 93 class ByteBufferWrapper : WritableBuffer { 94 private ByteBuffer _buf; 95 96 this(ByteBuffer buf) { 97 _buf = buf; 98 } 99 100 override 101 public void put(byte b) { 102 _buf.put(b); 103 } 104 105 override 106 public void putFloat(float f) { 107 _buf.putInt(cast(int)f); 108 } 109 110 override 111 public void putDouble(double d) { 112 _buf.putLong(cast(long)d); 113 } 114 115 override 116 public void put(byte[] src, int offset, int length) { 117 _buf.put(src, offset, length); 118 } 119 120 override 121 public void putShort(short s) { 122 _buf.putShort(s); 123 } 124 125 override 126 public void putInt(int i) { 127 _buf.putInt(i); 128 } 129 130 override 131 public void putLong(long l) { 132 _buf.putLong(l); 133 } 134 135 override 136 public bool hasRemaining() { 137 return _buf.hasRemaining(); 138 } 139 140 override 141 public void ensureRemaining(int remaining) { 142 if (remaining < 0) { 143 throw new IllegalArgumentException("Required remaining bytes cannot be negative"); 144 } 145 146 if (_buf.remaining() < remaining) { 147 writefln("....... %d ..... %d",_buf.remaining(),remaining); 148 //IndexOutOfBoundsException cause = new IndexOutOfBoundsException(String.format( 149 // "Requested min remaining bytes(%d) exceeds remaining(%d) in underlying ByteBuffer: %s", 150 // remaining, _buf.remaining(), _buf)); 151 152 throw (new BufferOverflowException()); 153 } 154 } 155 156 override 157 public int remaining() { 158 return _buf.remaining(); 159 } 160 161 override 162 public int position() { 163 return _buf.position(); 164 } 165 166 override 167 public void position(int position) { 168 _buf.position(position); 169 } 170 171 override 172 public void put(ByteBuffer src) { 173 _buf.put(src); 174 } 175 176 override 177 public void put(ReadableBuffer src) { 178 src.get(this); 179 } 180 181 override 182 public void put(string value) { 183 int length = cast(int)value.length; 184 185 int pos = _buf.position(); 186 187 for (int i = 0; i < length; i++) { 188 int c = value[i]; 189 try { 190 if ((c & 0xFF80) == 0) { 191 // U+0000..U+007F 192 put(pos++, cast(byte) c); 193 } else if ((c & 0xF800) == 0) { 194 // U+0080..U+07FF 195 put(pos++, cast(byte) (0xC0 | ((c >> 6) & 0x1F))); 196 put(pos++, cast(byte) (0x80 | (c & 0x3F))); 197 } else if ((c & 0xD800) != 0xD800 || (c > 0xDBFF)) { 198 // U+0800..U+FFFF - excluding surrogate pairs 199 put(pos++, cast(byte) (0xE0 | ((c >> 12) & 0x0F))); 200 put(pos++, cast(byte) (0x80 | ((c >> 6) & 0x3F))); 201 put(pos++, cast(byte) (0x80 | (c & 0x3F))); 202 } else { 203 int low; 204 205 if ((++i == length) || ((low = value[i]) & 0xDC00) != 0xDC00) { 206 throw new IllegalArgumentException("String contains invalid Unicode code points"); 207 } 208 209 c = 0x010000 + ((c & 0x03FF) << 10) + (low & 0x03FF); 210 211 put(pos++, cast(byte) (0xF0 | ((c >> 18) & 0x07))); 212 put(pos++, cast(byte) (0x80 | ((c >> 12) & 0x3F))); 213 put(pos++, cast(byte) (0x80 | ((c >> 6) & 0x3F))); 214 put(pos++, cast(byte) (0x80 | (c & 0x3F))); 215 } 216 } 217 catch(IndexOutOfBoundsException ioobe) { 218 throw new BufferOverflowException(); 219 } 220 } 221 222 // Now move the buffer position to reflect the work done here 223 _buf.position(pos); 224 } 225 226 override 227 public int limit() { 228 return _buf.limit(); 229 } 230 231 public ByteBuffer byteBuffer() { 232 return _buf; 233 } 234 235 public ReadableBuffer toReadableBuffer() { 236 return ByteBufferReader.wrap(cast(ByteBuffer) _buf.duplicate().flip()); 237 } 238 239 //override 240 //public string toString() { 241 // return String.format("[pos: %d, limit: %d, remaining:%d]", _buf.position(), _buf.limit(), _buf.remaining()); 242 //} 243 244 public static ByteBufferWrapper allocate(int size) { 245 ByteBuffer allocated = BufferUtils.allocate(size); 246 return new ByteBufferWrapper(allocated); 247 } 248 249 public static ByteBufferWrapper wrap(ByteBuffer buffer) { 250 return new ByteBufferWrapper(buffer); 251 } 252 253 public static ByteBufferWrapper wrap(byte[] bytes) { 254 return new ByteBufferWrapper(BufferUtils.toBuffer(bytes)); 255 } 256 257 private void put(int index, byte value) { 258 if (_buf.hasArray()) { 259 _buf.array()[_buf.arrayOffset() + index] = value; 260 } else { 261 _buf.put(index, value); 262 } 263 } 264 }