Json.NET
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


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
}