예제 #1
0
            /// <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);
            }
예제 #2
0
            private static void ReadElement(List <Token <ModelTokenType> > tokens, BinaryReader reader, bool isArrayItem)
            {
                BsonElementType elemType = (BsonElementType)reader.ReadByte();

                string ename = BsonTokenizer.ReadCString(reader);

                if (!isArrayItem)
                {
                    tokens.Add(ModelGrammar.TokenProperty(ename));
                }

                switch (elemType)
                {
                case BsonElementType.Double:
                {
                    double value = reader.ReadDouble();
                    tokens.Add(ModelGrammar.TokenPrimitive(value));
                    break;
                }

                case BsonElementType.String:
                {
                    string value = BsonTokenizer.ReadString(reader);
                    tokens.Add(ModelGrammar.TokenPrimitive(value));
                    break;
                }

                case BsonElementType.JavaScriptCode:
                {
                    BsonJavaScriptCode value = (BsonJavaScriptCode)BsonTokenizer.ReadString(reader);
                    tokens.Add(ModelGrammar.TokenPrimitive(value));
                    break;
                }

                case BsonElementType.Symbol:
                {
                    BsonSymbol value = (BsonSymbol)BsonTokenizer.ReadString(reader);
                    tokens.Add(ModelGrammar.TokenPrimitive(value));
                    break;
                }

                case BsonElementType.Document:
                {
                    BsonTokenizer.ReadDocument(tokens, reader, false);
                    break;
                }

                case BsonElementType.Array:
                {
                    BsonTokenizer.ReadDocument(tokens, reader, true);
                    break;
                }

                case BsonElementType.Binary:
                {
                    BsonTokenizer.ReadBinary(tokens, reader);
                    break;
                }

                case BsonElementType.ObjectID:
                {
                    byte[] value = reader.ReadBytes(BsonWriter.SizeOfObjectID);
                    tokens.Add(ModelGrammar.TokenPrimitive(new BsonObjectID(value)));
                    break;
                }

                case BsonElementType.Boolean:
                {
                    bool value = reader.ReadByte() != BsonWriter.FalseByte;
                    tokens.Add(value ? ModelGrammar.TokenTrue : ModelGrammar.TokenFalse);
                    break;
                }

                case BsonElementType.DateTimeUtc:
                {
                    DateTime value = BsonWriter.UnixEpoch.AddMilliseconds(reader.ReadInt64());
                    tokens.Add(ModelGrammar.TokenPrimitive(value));
                    break;
                }

                case BsonElementType.RegExp:
                {
                    string pattern = BsonTokenizer.ReadCString(reader);

                    string optionsStr = BsonTokenizer.ReadCString(reader);

                    RegexOptions options = RegexOptions.ECMAScript;

                    for (int i = optionsStr.Length - 1; i >= 0; i--)
                    {
                        char ch = optionsStr[i];
                        switch (ch)
                        {
                        case 'g':
                        {
                            // TODO: ensure correct encoding of ^$
                            //options |= RegexOptions.Multiline;
                            break;
                        }

                        case 'i':
                        {
                            options |= RegexOptions.IgnoreCase;
                            break;
                        }

                        case 'm':
                        {
                            options |= RegexOptions.Multiline;
                            break;
                        }
                        }
                    }

                    Regex regex = new Regex(pattern, options);

                    tokens.Add(ModelGrammar.TokenPrimitive(regex));
                    break;
                }

                case BsonElementType.DBPointer:
                {
                    string value1 = BsonTokenizer.ReadString(reader);
                    byte[] value2 = reader.ReadBytes(BsonWriter.SizeOfObjectID);

                    BsonDBPointer pointer = new BsonDBPointer {
                        Namespace = value1, ObjectID = new BsonObjectID(value2)
                    };
                    tokens.Add(ModelGrammar.TokenPrimitive(pointer));
                    break;
                }

                case BsonElementType.CodeWithScope:
                {
                    int    size  = reader.ReadInt32();
                    string value = BsonTokenizer.ReadString(reader);

                    tokens.Add(ModelGrammar.TokenPrimitive(value));

                    BsonTokenizer.ReadDocument(tokens, reader, false);
                    break;
                }

                case BsonElementType.Int32:
                {
                    int value = reader.ReadInt32();
                    tokens.Add(ModelGrammar.TokenPrimitive(value));
                    break;
                }

                case BsonElementType.TimeStamp:
                {
                    long value = reader.ReadInt64();
                    // TODO: convert to TimeSpan?
                    tokens.Add(ModelGrammar.TokenPrimitive(value));
                    break;
                }

                case BsonElementType.Int64:
                {
                    long value = reader.ReadInt64();
                    tokens.Add(ModelGrammar.TokenPrimitive(value));
                    break;
                }

                case BsonElementType.Undefined:
                case BsonElementType.Null:
                case BsonElementType.MinKey:
                case BsonElementType.MaxKey:
                {
                    // no data value
                    break;
                }

                default:
                {
                    throw new DeserializationException(
                              String.Format(BsonTokenizer.ErrorUnexpectedElementType, elemType),
                              reader.BaseStream.Position);
                }
                }
            }