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 }