Code Coverage Statistics for Source File
Newtonsoft.Json\Bson\BsonBinaryWriter.cs
Symbol Coverage: 98.65% (146 of 148)
Branch Coverage: 95.12% (39 of 41)
Cyclomatic Complexity Avg: 5.56 Max:18
Code Lines: 140
Symbol Coverage Trend
View:
L | V | Source |
---|---|---|
1 |
using System; |
|
2 |
using System.Collections.Generic; |
|
3 |
using System.Globalization; |
|
4 |
using System.IO; |
|
5 |
using System.Linq; |
|
6 |
using System.Text; |
|
7 |
using Newtonsoft.Json.Utilities; |
|
8 |
||
9 |
namespace Newtonsoft.Json.Bson |
|
10 |
{ |
|
11 |
internal class BsonBinaryWriter |
|
12 |
{ |
|
13 |
1 |
private static readonly Encoding Encoding = Encoding.UTF8;
|
14 |
||
15 |
private readonly BinaryWriter _writer; |
|
16 |
||
17 |
private byte[] _largeByteBuffer; |
|
18 |
private int _maxChars; |
|
19 |
||
20 |
10443 |
public BsonBinaryWriter(Stream stream)
|
21 |
{ |
|
22 |
10443 |
_writer = new BinaryWriter(stream);
|
23 |
10443 |
}
|
24 |
||
25 |
public void Flush() |
|
26 |
{ |
|
27 |
404 |
_writer.Flush();
|
28 |
404 |
}
|
29 |
||
30 |
public void WriteToken(BsonToken t) |
|
31 |
{ |
|
32 |
10439 |
CalculateSize(t);
|
33 |
10439 |
WriteTokenInternal(t);
|
34 |
10439 |
}
|
35 |
||
36 |
private void WriteTokenInternal(BsonToken t) |
|
37 |
{ |
|
38 |
436320 |
switch (t.Type)
|
39 |
{ |
|
40 |
case BsonType.Object: |
|
41 |
{ |
|
42 |
126275 |
BsonObject value = (BsonObject) t;
|
43 |
126275 |
_writer.Write(value.CalculatedSize);
|
44 |
126275 |
foreach (BsonProperty property in value)
|
45 |
{ |
|
46 |
399791 |
_writer.Write((sbyte)property.Value.Type);
|
47 |
399791 |
WriteString((string)property.Name.Value, property.Name.ByteCount, null);
|
48 |
399791 |
WriteTokenInternal(property.Value);
|
49 |
} |
|
50 |
126275 |
_writer.Write((byte)0);
|
51 |
} |
|
52 |
126275 |
break;
|
53 |
case BsonType.Array: |
|
54 |
{ |
|
55 |
10421 |
BsonArray value = (BsonArray) t;
|
56 |
10421 |
_writer.Write(value.CalculatedSize);
|
57 |
10421 |
int index = 0;
|
58 |
10421 |
foreach (BsonToken c in value)
|
59 |
{ |
|
60 |
26090 |
_writer.Write((sbyte)c.Type);
|
61 |
26090 |
WriteString(index.ToString(CultureInfo.InvariantCulture), MathUtils.IntLength(index), null);
|
62 |
26090 |
WriteTokenInternal(c);
|
63 |
26090 |
index++;
|
64 |
} |
|
65 |
10421 |
_writer.Write((byte)0);
|
66 |
} |
|
67 |
10421 |
break;
|
68 |
case BsonType.Integer: |
|
69 |
{ |
|
70 |
115651 |
BsonValue value = (BsonValue) t;
|
71 |
115651 |
_writer.Write(Convert.ToInt32(value.Value, CultureInfo.InvariantCulture));
|
72 |
} |
|
73 |
115651 |
break;
|
74 |
case BsonType.Long: |
|
75 |
{ |
|
76 |
2 |
BsonValue value = (BsonValue)t;
|
77 |
2 |
_writer.Write(Convert.ToInt64(value.Value, CultureInfo.InvariantCulture));
|
78 |
} |
|
79 |
2 |
break;
|
80 |
case BsonType.Number: |
|
81 |
{ |
|
82 |
5235 |
BsonValue value = (BsonValue)t;
|
83 |
5235 |
_writer.Write(Convert.ToDouble(value.Value, CultureInfo.InvariantCulture));
|
84 |
} |
|
85 |
5235 |
break;
|
86 |
case BsonType.String: |
|
87 |
{ |
|
88 |
142292 |
BsonString value = (BsonString)t;
|
89 |
142292 |
WriteString((string)value.Value, value.ByteCount, value.CalculatedSize - 4);
|
90 |
} |
|
91 |
142292 |
break;
|
92 |
case BsonType.Boolean: |
|
93 |
{ |
|
94 |
3 |
BsonValue value = (BsonValue)t;
|
95 |
3 |
_writer.Write((bool)value.Value);
|
96 |
} |
|
97 |
3 |
break;
|
98 |
case BsonType.Null: |
|
99 |
case BsonType.Undefined: |
|
100 |
15412 |
break;
|
101 |
case BsonType.Date: |
|
102 |
{ |
|
103 |
20817 |
BsonValue value = (BsonValue)t;
|
104 |
||
105 |
20817 |
long ticks = 0;
|
106 |
||
107 |
20817 |
if (value.Value is DateTime)
|
108 |
{ |
|
109 |
20816 |
DateTime dateTime = (DateTime) value.Value;
|
110 |
20816 |
dateTime = dateTime.ToUniversalTime();
|
111 |
20816 |
ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(dateTime);
|
112 |
} |
|
113 |
#if !PocketPC && !NET20 |
|
114 |
else |
|
115 |
{ |
|
116 |
1 |
DateTimeOffset dateTimeOffset = (DateTimeOffset) value.Value;
|
117 |
1 |
ticks = JsonConvert.ConvertDateTimeToJavaScriptTicks(dateTimeOffset.UtcDateTime, dateTimeOffset.Offset);
|
118 |
} |
|
119 |
#endif |
|
120 |
||
121 |
20817 |
_writer.Write(ticks);
|
122 |
} |
|
123 |
20817 |
break;
|
124 |
case BsonType.Binary: |
|
125 |
{ |
|
126 |
204 |
BsonValue value = (BsonValue)t;
|
127 |
||
128 |
204 |
byte[] data = (byte[])value.Value;
|
129 |
204 |
_writer.Write(data.Length);
|
130 |
204 |
_writer.Write((byte)BsonBinaryType.Data);
|
131 |
204 |
_writer.Write(data);
|
132 |
} |
|
133 |
204 |
break;
|
134 |
case BsonType.Oid: |
|
135 |
{ |
|
136 |
3 |
BsonValue value = (BsonValue)t;
|
137 |
||
138 |
3 |
byte[] data = (byte[])value.Value;
|
139 |
3 |
_writer.Write(data);
|
140 |
} |
|
141 |
3 |
break;
|
142 |
case BsonType.Regex: |
|
143 |
{ |
|
144 |
5 |
BsonRegex value = (BsonRegex) t;
|
145 |
||
146 |
5 |
WriteString((string)value.Pattern.Value, value.Pattern.ByteCount, null);
|
147 |
5 |
WriteString((string)value.Options.Value, value.Options.ByteCount, null);
|
148 |
} |
|
149 |
5 |
break;
|
150 |
default: |
|
151 |
0 |
throw new ArgumentOutOfRangeException("t", "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
|
152 |
} |
|
153 |
436320 |
}
|
154 |
||
155 |
private void WriteString(string s, int byteCount, int? calculatedlengthPrefix) |
|
156 |
{ |
|
157 |
568183 |
if (calculatedlengthPrefix != null)
|
158 |
142292 |
_writer.Write(calculatedlengthPrefix.Value);
|
159 |
||
160 |
568183 |
if (s != null)
|
161 |
{ |
|
162 |
568182 |
if (_largeByteBuffer == null)
|
163 |
{ |
|
164 |
10439 |
_largeByteBuffer = new byte[256];
|
165 |
10439 |
_maxChars = 256/Encoding.GetMaxByteCount(1);
|
166 |
} |
|
167 |
568182 |
if (byteCount <= 256)
|
168 |
{ |
|
169 |
568174 |
Encoding.GetBytes(s, 0, s.Length, _largeByteBuffer, 0);
|
170 |
568174 |
_writer.Write(_largeByteBuffer, 0, byteCount);
|
171 |
} |
|
172 |
else |
|
173 |
{ |
|
174 |
int charCount; |
|
175 |
8 |
int totalCharsWritten = 0;
|
176 |
8 |
for (int i = s.Length; i > 0; i -= charCount) |
177 |
{ |
|
178 |
56 |
charCount = (i > _maxChars) ? _maxChars : i;
|
179 |
56 |
int count = Encoding.GetBytes(s, totalCharsWritten, charCount, _largeByteBuffer, 0);
|
180 |
56 |
_writer.Write(_largeByteBuffer, 0, count);
|
181 |
56 |
totalCharsWritten += charCount;
|
182 |
} |
|
183 |
} |
|
184 |
} |
|
185 |
||
186 |
568183 |
_writer.Write((byte)0);
|
187 |
568183 |
}
|
188 |
||
189 |
private int CalculateSize(int stringByteCount) |
|
190 |
{ |
|
191 |
26090 |
return stringByteCount + 1;
|
192 |
26090 |
}
|
193 |
||
194 |
private int CalculateSizeWithLength(int stringByteCount, bool includeSize) |
|
195 |
{ |
|
196 |
542093 |
int baseSize = (includeSize)
|
197 |
542093 |
? 5 // size bytes + terminator
|
198 |
542093 |
: 1; // terminator
|
199 |
||
200 |
542093 |
return baseSize + stringByteCount;
|
201 |
542093 |
}
|
202 |
||
203 |
private int CalculateSize(BsonToken t) |
|
204 |
{ |
|
205 |
836121 |
switch (t.Type)
|
206 |
{ |
|
207 |
case BsonType.Object: |
|
208 |
{ |
|
209 |
126275 |
BsonObject value = (BsonObject) t;
|
210 |
||
211 |
126275 |
int bases = 4;
|
212 |
126275 |
foreach (BsonProperty p in value)
|
213 |
{ |
|
214 |
399791 |
int size = 1;
|
215 |
399791 |
size += CalculateSize(p.Name);
|
216 |
399791 |
size += CalculateSize(p.Value);
|
217 |
||
218 |
399791 |
bases += size;
|
219 |
} |
|
220 |
126275 |
bases += 1;
|
221 |
126275 |
value.CalculatedSize = bases;
|
222 |
126275 |
return bases;
|
223 |
} |
|
224 |
case BsonType.Array: |
|
225 |
{ |
|
226 |
10421 |
BsonArray value = (BsonArray)t;
|
227 |
||
228 |
10421 |
int size = 4;
|
229 |
10421 |
int index = 0;
|
230 |
10421 |
foreach (BsonToken c in value)
|
231 |
{ |
|
232 |
26090 |
size += 1;
|
233 |
26090 |
size += CalculateSize(MathUtils.IntLength(index));
|
234 |
26090 |
size += CalculateSize(c);
|
235 |
26090 |
index++;
|
236 |
} |
|
237 |
10421 |
size += 1;
|
238 |
10421 |
value.CalculatedSize = size;
|
239 |
||
240 |
10421 |
return value.CalculatedSize;
|
241 |
} |
|
242 |
case BsonType.Integer: |
|
243 |
115651 |
return 4;
|
244 |
case BsonType.Long: |
|
245 |
2 |
return 8;
|
246 |
case BsonType.Number: |
|
247 |
5235 |
return 8;
|
248 |
case BsonType.String: |
|
249 |
{ |
|
250 |
542093 |
BsonString value = (BsonString)t;
|
251 |
542093 |
string s = (string) value.Value;
|
252 |
542093 |
value.ByteCount = (s != null) ? Encoding.GetByteCount(s) : 0;
|
253 |
542093 |
value.CalculatedSize = CalculateSizeWithLength(value.ByteCount, value.IncludeLength);
|
254 |
||
255 |
542093 |
return value.CalculatedSize;
|
256 |
} |
|
257 |
case BsonType.Boolean: |
|
258 |
3 |
return 1;
|
259 |
case BsonType.Null: |
|
260 |
case BsonType.Undefined: |
|
261 |
15412 |
return 0;
|
262 |
case BsonType.Date: |
|
263 |
20817 |
return 8;
|
264 |
case BsonType.Binary: |
|
265 |
{ |
|
266 |
204 |
BsonValue value = (BsonValue) t;
|
267 |
||
268 |
204 |
byte[] data = (byte[])value.Value;
|
269 |
204 |
value.CalculatedSize = 4 + 1 + data.Length;
|
270 |
||
271 |
204 |
return value.CalculatedSize;
|
272 |
} |
|
273 |
case BsonType.Oid: |
|
274 |
3 |
return 12;
|
275 |
case BsonType.Regex: |
|
276 |
{ |
|
277 |
5 |
BsonRegex value = (BsonRegex) t;
|
278 |
5 |
int size = 0;
|
279 |
5 |
size += CalculateSize(value.Pattern);
|
280 |
5 |
size += CalculateSize(value.Options);
|
281 |
5 |
value.CalculatedSize = size;
|
282 |
||
283 |
5 |
return value.CalculatedSize;
|
284 |
} |
|
285 |
default: |
|
286 |
0 |
throw new ArgumentOutOfRangeException("t", "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
|
287 |
} |
|
288 |
836121 |
}
|
289 |
} |
|
290 |
} |