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.StringType; 13 14 import hunt.proton.codec.SmallFloatingSizePrimitiveTypeEncoding; 15 import hunt.proton.codec.TypeEncoding; 16 import hunt.proton.codec.EncodingCodes; 17 import hunt.proton.codec.EncoderImpl; 18 import hunt.proton.codec.PrimitiveTypeEncoding; 19 import hunt.proton.codec.ReadableBuffer; 20 import hunt.proton.codec.AbstractPrimitiveType; 21 import hunt.proton.codec.DecoderImpl; 22 import hunt.collection.Collection; 23 import hunt.Exceptions; 24 import hunt.String; 25 import hunt.collection.ArrayList; 26 27 import hunt.proton.codec.LargeFloatingSizePrimitiveTypeEncoding; 28 import hunt.logging; 29 30 31 interface StringEncoding : PrimitiveTypeEncoding!(String) 32 { 33 void setValue(String val, int length); 34 } 35 36 37 class StringType : AbstractPrimitiveType!(String) 38 { 39 private static DecoderImpl.TypeDecoder!(String) _stringCreator ; 40 41 private StringEncoding _stringEncoding; 42 private StringEncoding _shortStringEncoding; 43 44 this(EncoderImpl encoder, DecoderImpl decoder) 45 { 46 StringType._stringCreator = new class DecoderImpl.TypeDecoder!(String) 47 { 48 override 49 public String decode(DecoderImpl decoder, ReadableBuffer buffer) 50 { 51 // CharsetDecoder charsetDecoder = decoder.getCharsetDecoder(); 52 try 53 { 54 return new String(buffer.readUTF8()); 55 } 56 catch (CharacterCodingException e) 57 { 58 throw new IllegalArgumentException("Cannot parse String"); 59 } 60 //finally 61 //{ 62 // charsetDecoder.reset(); 63 //} 64 } 65 }; 66 _stringEncoding = new AllStringEncoding(encoder, decoder); 67 _shortStringEncoding = new ShortStringEncoding(encoder, decoder); 68 encoder.register(typeid(String), this); 69 decoder.register(this); 70 } 71 72 public TypeInfo getTypeClass() 73 { 74 return typeid(String); 75 } 76 77 public ITypeEncoding getEncoding(Object val) 78 { 79 int length = calculateUTF8Length(cast(String)val); 80 StringEncoding encoding = length <= 255 81 ? _shortStringEncoding 82 : _stringEncoding; 83 encoding.setValue(cast(String)val, length); 84 return encoding; 85 } 86 87 static int calculateUTF8Length(String str) 88 { 89 string s = str.value; 90 // int stringLength = cast(int)((cast(byte[])s).length); 91 92 // ASCII Optimized length case 93 //int utf8len = stringLength; 94 //int processed = 0; 95 //for (; processed < stringLength && s[processed] < 0x80; processed++) {} 96 // 97 //if (processed < stringLength) 98 //{ 99 // // Non-ASCII length remainder 100 // utf8len = extendedCalculateUTF8Length(str, processed, stringLength, utf8len); 101 //} 102 103 return cast(int)(s.length); 104 } 105 106 static int extendedCalculateUTF8Length(String str, int index, int length, int utf8len) { 107 string s = str.value; 108 for (; index < length; index++) 109 { 110 int c = s[index]; 111 if ((c & 0xFF80) != 0) /* U+0080.. */ 112 { 113 utf8len++; 114 if(((c & 0xF800) != 0)) /* U+0800.. */ 115 { 116 utf8len++; 117 // surrogate pairs should always combine to create a code point with a 4 octet representation 118 if ((c & 0xD800) == 0xD800 && c < 0xDC00) 119 { 120 index++; 121 } 122 } 123 } 124 } 125 126 return utf8len; 127 } 128 129 public StringEncoding getCanonicalEncoding() 130 { 131 return _stringEncoding; 132 } 133 134 public Collection!(TypeEncoding!(String)) getAllEncodings() 135 { 136 ArrayList!(TypeEncoding!(String)) lst = new ArrayList!(TypeEncoding!(String))(); 137 lst.add(_shortStringEncoding); 138 lst.add(_stringEncoding); 139 return lst; 140 } 141 142 //Collection!(PrimitiveTypeEncoding!(String)) getAllEncodings() 143 //{ 144 // return super.getAllEncodings(); 145 //} 146 147 148 class AllStringEncoding 149 : LargeFloatingSizePrimitiveTypeEncoding!(String) 150 , StringEncoding 151 { 152 private String _value; 153 private int _length; 154 155 this(EncoderImpl encoder, DecoderImpl decoder) 156 { 157 super(encoder, decoder); 158 } 159 160 override 161 protected void writeEncodedValue(String val) 162 { 163 getEncoder().getBuffer().ensureRemaining(getEncodedValueSize(val)); 164 getEncoder().writeRaw(val); 165 } 166 167 override 168 protected int getEncodedValueSize(String val) 169 { 170 return (val == _value) ? _length : calculateUTF8Length(val); 171 } 172 173 override 174 public byte getEncodingCode() 175 { 176 return EncodingCodes.STR32; 177 } 178 179 override 180 public StringType getType() 181 { 182 return this.outer; 183 } 184 185 override 186 public bool encodesSuperset(TypeEncoding!(String) encoding) 187 { 188 return (getType() == encoding.getType()); 189 } 190 191 override 192 public Object readValue() 193 { 194 DecoderImpl decoder = getDecoder(); 195 int size = decoder.readRawInt(); 196 return size == 0 ? new String("") : decoder.readRaw(_stringCreator, size); 197 } 198 199 override 200 public void setValue(String val, int length) 201 { 202 _value = val; 203 _length = length; 204 } 205 206 override 207 public void skipValue() 208 { 209 DecoderImpl decoder = getDecoder(); 210 ReadableBuffer buffer = decoder.getBuffer(); 211 int size = decoder.readRawInt(); 212 buffer.position(buffer.position() + size); 213 } 214 215 override bool encodesJavaPrimitive() 216 { 217 return super.encodesJavaPrimitive(); 218 } 219 220 override TypeInfo getTypeClass() 221 { 222 return super.getTypeClass(); 223 } 224 225 override void writeConstructor() 226 { 227 return super.writeConstructor(); 228 } 229 230 override int getConstructorSize() 231 { 232 return super.getConstructorSize(); 233 } 234 } 235 236 class ShortStringEncoding 237 : SmallFloatingSizePrimitiveTypeEncoding!(String) 238 , StringEncoding 239 { 240 private String _value; 241 private int _length; 242 243 this(EncoderImpl encoder, DecoderImpl decoder) 244 { 245 super(encoder, decoder); 246 } 247 248 override 249 protected void writeEncodedValue(String val) 250 { 251 getEncoder().getBuffer().ensureRemaining(getEncodedValueSize(val)); 252 getEncoder().writeRaw(val); 253 } 254 255 override 256 protected int getEncodedValueSize(String val) 257 { 258 // logInfof("size : %d",(val == _value) ? _length : calculateUTF8Length(val)); 259 return (val == _value) ? _length : calculateUTF8Length(val); 260 } 261 262 override 263 public byte getEncodingCode() 264 { 265 return EncodingCodes.STR8; 266 } 267 268 override 269 public StringType getType() 270 { 271 return this.outer; 272 } 273 274 override 275 public bool encodesSuperset(TypeEncoding!(String) encoder) 276 { 277 return encoder == this; 278 } 279 280 override 281 public Object readValue() 282 { 283 DecoderImpl decoder = getDecoder(); 284 int size = (cast(int)decoder.readRawByte()) & 0xff; 285 String a; 286 if (size == 0) 287 { 288 a = new String(""); 289 } 290 else 291 { 292 a =decoder.readRaw(_stringCreator, size); 293 } 294 //return size == 0 ? new String("") : decoder.readRaw(_stringCreator, size); 295 // logInfof("dddddddddddddddddd %s",a); 296 return a; 297 } 298 299 override 300 public void setValue(String val, int length) 301 { 302 _value = val; 303 _length = length; 304 } 305 306 override 307 public void skipValue() 308 { 309 DecoderImpl decoder = getDecoder(); 310 ReadableBuffer buffer = decoder.getBuffer(); 311 int size = (cast(int)decoder.readRawByte()) & 0xff; 312 buffer.position(buffer.position() + size); 313 } 314 315 override bool encodesJavaPrimitive() 316 { 317 return super.encodesJavaPrimitive(); 318 } 319 320 override TypeInfo getTypeClass() 321 { 322 return super.getTypeClass(); 323 } 324 325 override void writeConstructor() 326 { 327 return super.writeConstructor(); 328 } 329 330 override int getConstructorSize() 331 { 332 return super.getConstructorSize(); 333 } 334 } 335 }