/// <summary> /// Emits a code_w_s value /// </summary> /// <param name="writer"></param> /// <param name="tokens"></param> /// <returns>number of bytes written</returns> private int WriteCodeWithScope(BinaryWriter writer, BsonCodeWithScope value) { long start = writer.BaseStream.Position; int total = BsonWriter.SizeOfInt32; // code_w_s length field // leave room for length writer.Seek(BsonWriter.SizeOfInt32, SeekOrigin.Current); // write code total += BsonFormatter.WriteString(writer, (string)value.Code, false); //TODO: this is currently broken. // write scope total += this.WriteDocument(writer, value.Scope); // seek back to write out code_w_s length long end = writer.BaseStream.Position; writer.Seek((int)(start - end), SeekOrigin.Current); writer.Write(total); // seek back to end writer.Seek((int)(end - start - BsonWriter.SizeOfInt32), SeekOrigin.Current); return(total); }
/// <summary> /// Emits a single element to the binary stream /// </summary> /// <param name="writer"></param> /// <param name="tokens"></param> /// <param name="ename"></param> /// <returns>number of bytes written</returns> private int WriteElement(BinaryWriter writer, IStream <Token <ModelTokenType> > tokens, string ename) { Token <ModelTokenType> token = tokens.Peek(); if (tokens.IsCompleted || token == null) { throw new TokenException <ModelTokenType>(token, BsonWriter.ErrorUnterminated); } BsonElementType elemType; switch (token.TokenType) { case ModelTokenType.ArrayBegin: { elemType = BsonElementType.Array; break; } case ModelTokenType.ObjectBegin: { elemType = BsonElementType.Document; break; } case ModelTokenType.Primitive: { elemType = BsonFormatter.GetElementType(token.Value); break; } default: { // the rest are invalid states throw new TokenException <ModelTokenType>(token, String.Format(BsonWriter.ErrorUnexpectedToken, token.TokenType)); } } // write element type writer.Write((byte)elemType); int total = BsonWriter.SizeOfByte; // for element type // write EName total += BsonFormatter.WriteString(writer, ename, true); IBsonFormattable formattable = token.Value as IBsonFormattable; if (formattable != null) { total += formattable.Format(this, writer); } else { switch (elemType) { case BsonElementType.Double: { // consume token value tokens.Pop(); // write double data writer.Write((double)token.Value); total += BsonWriter.SizeOfDouble; break; } case BsonElementType.String: case BsonElementType.JavaScriptCode: case BsonElementType.Symbol: { // consume token value tokens.Pop(); // write as string data total += BsonFormatter.WriteString(writer, token.ValueAsString(), false); break; } case BsonElementType.Document: case BsonElementType.Array: { // delegate property to sub-document total += this.WriteDocument(writer, tokens); break; } case BsonElementType.Binary: { // consume token value tokens.Pop(); total += BsonFormatter.WriteBinary(writer, token); break; } case BsonElementType.ObjectID: { // consume token value tokens.Pop(); // write ObjectID data writer.Write((byte[])token.Value); total += BsonWriter.SizeOfObjectID; break; } case BsonElementType.Boolean: { // consume token value tokens.Pop(); // write bool data bool value = true.Equals(token.Value); writer.Write(value ? BsonWriter.TrueByte : BsonWriter.FalseByte); total += BsonWriter.SizeOfByte; break; } case BsonElementType.DateTimeUtc: { // consume token value tokens.Pop(); DateTime value = (DateTime)token.Value; if (value.Kind == DateTimeKind.Local) { // convert server-local to UTC value = value.ToUniversalTime(); } // find the duration since Jan 1, 1970 TimeSpan duration = value.Subtract(BsonWriter.UnixEpoch); // get the total milliseconds long ticks = (long)duration.TotalMilliseconds; // write long data writer.Write((long)ticks); total += BsonWriter.SizeOfInt64; break; } case BsonElementType.RegExp: { // consume token value tokens.Pop(); Regex regex = token.Value as Regex; if (regex == null) { goto default; } // default implementation is to simply return the pattern string string pattern = regex.ToString(); // write cstring data total += BsonFormatter.WriteString(writer, pattern, true); bool isGlobal = false; // nothing to switch on string options = isGlobal ? "g" : ""; switch (regex.Options & (RegexOptions.IgnoreCase | RegexOptions.Multiline)) { case RegexOptions.IgnoreCase: { options += "i"; break; } case RegexOptions.Multiline: { options += "m"; break; } case RegexOptions.IgnoreCase | RegexOptions.Multiline: { options += "im"; break; } } // write cstring data total += BsonFormatter.WriteString(writer, options, true); break; } case BsonElementType.DBPointer: { // consume token value tokens.Pop(); BsonDBPointer pointer = token.Value as BsonDBPointer; if (pointer == null) { goto default; } // write string data total += BsonFormatter.WriteString(writer, pointer.Namespace, false); // write bytes writer.Write((byte[])pointer.ObjectID); total += BsonWriter.SizeOfObjectID; break; } case BsonElementType.CodeWithScope: { // consume token value tokens.Pop(); BsonCodeWithScope codews = token.Value as BsonCodeWithScope; if (codews == null) { goto default; } total += this.WriteCodeWithScope(writer, codews); break; } case BsonElementType.Int32: { // consume token value tokens.Pop(); // write int data writer.Write((int)token.Value); total += BsonWriter.SizeOfInt32; break; } case BsonElementType.TimeStamp: case BsonElementType.Int64: { // consume token value tokens.Pop(); // TODO: determine how to convert TimeStamp // write long data writer.Write((long)token.Value); total += BsonWriter.SizeOfInt64; break; } case BsonElementType.Undefined: case BsonElementType.Null: case BsonElementType.MinKey: case BsonElementType.MaxKey: { // consume token value tokens.Pop(); // no data emitted for these break; } default: { // the rest are invalid states throw new TokenException <ModelTokenType>(token, String.Format(BsonWriter.ErrorUnexpectedToken, token.TokenType)); } } } return(total); }