Beispiel #1
0
        public override void HandlePacket(Packet packet)
        {
            base.HandlePacket(packet);

            while (true)
            {
                PacketStream.State prevState = stream.CurrentState;

                try
                {
                    List <PacketSlice> slices = new List <PacketSlice>(2);

                    TransactionNode node;

                    if (stream.Direction == PacketDirection.PACKET_DIRECTION_OUTGOING)
                    {
                        RemSyncCommand cmdType;
                        string         cmdTypeStr;

                        List <PacketSlice> argSlices = new List <PacketSlice>(2);
                        UInt16             arg       = stream.ReadU16(argSlices);

                        UInt16 cmdTypeRaw = stream.ReadU16(slices);

                        ParseCommandType(cmdTypeRaw, out cmdType, out cmdTypeStr);

                        node = new TransactionNode(cmdTypeStr);

                        switch (cmdType)
                        {
                        case RemSyncCommand.SetStatus:
                            node.AddField("MessageSize", Convert.ToString(arg),
                                          "Size of zero-terminated unicode string following the next field.",
                                          argSlices);
                            break;

                        case RemSyncCommand.SetProgressValue:
                            node.AddField("NewValue", Convert.ToString(arg),
                                          "The new progress value, within ProgressMin and ProgressMax as specified with SetProgressRange.",
                                          argSlices);
                            break;

                        default:
                            node.AddField("Argument", Convert.ToString(arg),
                                          "Argument, meaning depending on the NotificationType field.",
                                          argSlices);
                            break;
                        }

                        node.AddField("NotificationType", cmdTypeStr, "Type of notification.", slices);

                        UInt16 u16;

                        switch (cmdType)
                        {
                        case RemSyncCommand.SetStatus:
                            string msg = stream.ReadCString(arg, slices);
                            node.AddField("MessageBytes", msg,
                                          "A zero-terminated unicode LE16 string with the size as specified by MessageSize (which includes the terminating NUL byte).",
                                          slices);
                            break;

                        case RemSyncCommand.SetProgressRange:
                            u16 = stream.ReadU16(slices);
                            node.AddField("ProgressMin", Convert.ToString(u16),
                                          "Progressbar min value.", slices);

                            u16 = stream.ReadU16(slices);
                            node.AddField("ProgressMax", Convert.ToString(u16),
                                          "Progressbar max value.", slices);
                            break;
                        }
                    }
                    else
                    {
                        node = new TransactionNode("RemSync::UNKNOWN_REPLY");

                        byte[] bytes = stream.ReadBytes((int)stream.Length, slices);
                        node.AddField("UnknownBytes", Util.FormatByteArray(bytes), "Unknown reply data.", slices);
                    }

                    node.Description = node.Name;

                    AddTransactionNode(node);
                }
                catch (EndOfStreamException)
                {
                    if (stream.HasNextDirection())
                    {
                        stream.NextDirection();
                        continue;
                    }
                    else
                    {
                        stream.CurrentState = prevState;
                        return;
                    }
                }
            }
        }
Beispiel #2
0
        public override void HandlePacket(Packet packet)
        {
            base.HandlePacket(packet);

            while (true)
            {
                PacketStream.State prevState = stream.CurrentState;

                try
                {
                    List<PacketSlice> slices = new List<PacketSlice>(2);

                    TransactionNode node;

                    if (stream.Direction == PacketDirection.PACKET_DIRECTION_OUTGOING)
                    {
                        RemSyncCommand cmdType;
                        string cmdTypeStr;

                        List<PacketSlice> argSlices = new List<PacketSlice>(2);
                        UInt16 arg = stream.ReadU16(argSlices);

                        UInt16 cmdTypeRaw = stream.ReadU16(slices);

                        ParseCommandType(cmdTypeRaw, out cmdType, out cmdTypeStr);

                        node = new TransactionNode(cmdTypeStr);

                        switch (cmdType)
                        {
                            case RemSyncCommand.SetStatus:
                                node.AddField("MessageSize", Convert.ToString(arg),
                                    "Size of zero-terminated unicode string following the next field.",
                                    argSlices);
                                break;
                            case RemSyncCommand.SetProgressValue:
                                node.AddField("NewValue", Convert.ToString(arg),
                                    "The new progress value, within ProgressMin and ProgressMax as specified with SetProgressRange.",
                                    argSlices);
                                break;
                            default:
                                node.AddField("Argument", Convert.ToString(arg),
                                    "Argument, meaning depending on the NotificationType field.",
                                    argSlices);
                                break;
                        }

                        node.AddField("NotificationType", cmdTypeStr, "Type of notification.", slices);

                        UInt16 u16;

                        switch (cmdType)
                        {
                            case RemSyncCommand.SetStatus:
                                string msg = stream.ReadCString(arg, slices);
                                node.AddField("MessageBytes", msg,
                                    "A zero-terminated unicode LE16 string with the size as specified by MessageSize (which includes the terminating NUL byte).",
                                    slices);
                                break;
                            case RemSyncCommand.SetProgressRange:
                                u16 = stream.ReadU16(slices);
                                node.AddField("ProgressMin", Convert.ToString(u16),
                                    "Progressbar min value.", slices);

                                u16 = stream.ReadU16(slices);
                                node.AddField("ProgressMax", Convert.ToString(u16),
                                    "Progressbar max value.", slices);
                                break;
                        }
                    }
                    else
                    {
                        node = new TransactionNode("RemSync::UNKNOWN_REPLY");

                        byte[] bytes = stream.ReadBytes((int)stream.Length, slices);
                        node.AddField("UnknownBytes", Util.FormatByteArray(bytes), "Unknown reply data.", slices);
                    }

                    node.Description = node.Name;

                    AddTransactionNode(node);
                }
                catch (EndOfStreamException)
                {
                    if (stream.HasNextDirection())
                    {
                        stream.NextDirection();
                        continue;
                    }
                    else
                    {
                        stream.CurrentState = prevState;
                        return;
                    }
                }
            }
        }
Beispiel #3
0
        protected void ParseCommandReply(TransactionNode cmd, int cmdLen)
        {
            UInt32 u32;

            byte[]             bytes;
            string             str;
            List <PacketSlice> slices = new List <PacketSlice>(2);

            UInt32      replyCmdTypeRaw;
            RRACCommand replyCmdType;
            string      replyCmdTypeStr;

            replyCmdTypeRaw = stream.ReadU32(slices);

            ParseCommandType((UInt16)replyCmdTypeRaw, out replyCmdType, out replyCmdTypeStr);

            cmd.AddField("ReplyToCommand", replyCmdTypeStr,
                         "Command which this is a reply to.", slices);

            int replyLen = cmdLen - 4;

            if (replyCmdType != RRACCommand.UNKNOWN)
            {
                if (!pendingReplies.ContainsKey(replyCmdType))
                {
                    throw new StreamSessionParseError(String.Format(
                                                          "Got reply to a command we don't know about: {0} ({1})",
                                                          replyCmdType, replyCmdTypeRaw));
                }
            }

            bool handled = true;

            cmd.Description = String.Format("{0} to {1}", cmd.Name, replyCmdTypeStr);

            u32 = stream.ReadU32(slices);
            cmd.AddField("Result", Util.FormatValue(u32),
                         "Result of the request.", slices);

            u32 = stream.ReadU32(slices);
            cmd.AddField("ResponseDataSize", Util.FormatValue(u32),
                         "Number of bytes of response data following the next field.", slices);

            u32 = stream.ReadU32(slices);
            cmd.AddField("Unknown1", Util.FormatValue(u32),
                         "Unknown field.", slices);

            replyLen -= 3 * 4;

            if (replyCmdType == RRACCommand.GetMetaData)
            {
                GetMetaDataCmd listCmd =
                    pendingReplies[replyCmdType] as GetMetaDataCmd;

                switch (listCmd.Flags)
                {
                case 0x7c1:
                    u32 = stream.ReadU32(slices);
                    cmd.AddField("MagicValue", Util.FormatFlags(u32),
                                 "Magic value that must be 0xF0000001.", slices);

                    u32 = stream.ReadU32(slices);
                    cmd.AddField("Success", Util.FormatBool(u32),
                                 "A value that must be TRUE, probably signifying whether the command succeeded.", slices);

                    u32 = stream.ReadU32(slices);
                    cmd.AddField("HasBody", Util.FormatBool(u32),
                                 "A BOOL indicating if the response contains a body or is empty.", slices);

                    u32 = stream.ReadU32(slices);
                    cmd.AddField("ResponseTo", Util.FormatValue(u32),
                                 "Two to the power of the position of the bit to which this is a response. So for instance " +
                                 "if this is the response to bit 4, this field contains the value 16.", slices);

                    UInt32 typeCount = stream.ReadU32(slices);
                    cmd.AddField("TypeCount", Convert.ToString(typeCount),
                                 "Number of types following.", slices);

                    TransactionNode objTypes = new TransactionNode("ObjectTypes");
                    cmd.AddChild(objTypes);

                    for (int i = 0; i < typeCount; i++)
                    {
                        TransactionNode node = new TransactionNode(
                            Convert.ToString(i));

                        u32 = stream.ReadU32(slices);
                        node.AddField("Flags", Util.FormatValue(u32),
                                      "Unknown.", slices);

                        str = stream.ReadCString(200, slices);
                        node.AddField("Name1", str, "Name of the object type.", slices);

                        str = stream.ReadCString(80, slices);
                        node.AddField("Name2", str, "Name/description of the object type.", slices);

                        str = stream.ReadCString(80, slices);
                        node.AddField("Name3", str, "Another name/description of the object type (usually blank).", slices);

                        u32 = stream.ReadU32(slices);
                        node.AddField("SSPId", Util.FormatFlags(u32),
                                      "Identifier of the object type.", slices);

                        u32 = stream.ReadU32(slices);
                        node.AddField("Count", Util.FormatValue(u32),
                                      "Number of items of this object type on the device.", slices);

                        u32 = stream.ReadU32(slices);
                        node.AddField("TotalSize", Util.FormatValue(u32),
                                      "Total size of the items of this object type on the device.", slices);

                        List <PacketSlice> allSlices = new List <PacketSlice>(2);

                        UInt32 timeLow = stream.ReadU32(slices);
                        allSlices.AddRange(slices);

                        UInt32 timeHigh = stream.ReadU32(slices);
                        allSlices.AddRange(slices);

                        UInt64 time = (UInt64)timeLow & ((UInt64)timeHigh << 32);

                        node.AddField("FileTime", String.Format("0x{0:x16}", time),
                                      "Time of last modification of any of the items of this object type on the device (?).", allSlices);

                        objTypes.AddChild(node);
                    }

                    break;

                default:
                    handled = false;
                    break;
                }
            }
            else
            {
                handled = false;
            }

            if (!handled)
            {
                if (replyLen > 0)
                {
                    bytes = stream.ReadBytes(replyLen, slices);
                    cmd.AddField("UnknownReplyData", Util.FormatByteArray(bytes),
                                 "Unknown reply data.", slices);
                }
            }

            pendingReplies.Remove(replyCmdType);
        }
Beispiel #4
0
        private void ParseControlCommand()
        {
            List <PacketSlice> slices = new List <PacketSlice>(2);

            UInt16             cmdTypeRaw, cmdLen;
            RRACCommand        cmdType;
            string             cmdTypeStr;
            List <PacketSlice> cmdTypeSlices = new List <PacketSlice>(1);
            List <PacketSlice> cmdLenSlices  = new List <PacketSlice>(1);

            UInt32 u32;

            byte[] bytes;

            try
            {
                // Command type
                cmdTypeRaw = stream.ReadU16(cmdTypeSlices);

                // Command length
                cmdLen = stream.ReadU16(cmdLenSlices);

                ParseCommandType(cmdTypeRaw, out cmdType, out cmdTypeStr);

                TransactionNode cmd = new TransactionNode(cmdTypeStr);

                cmd.AddField("CommandType", cmdTypeStr,
                             "Command type.", cmdTypeSlices);
                cmd.AddField("CommandLength", Convert.ToString(cmdLen),
                             "Number of bytes following this field.", cmdLenSlices);

                if (cmdType != RRACCommand.Response)
                {
                    cmd.Description = cmd.Name;
                }

                bool handled = true;

                switch (cmdType)
                {
                case RRACCommand.GetMetaData:
                    u32 = stream.ReadU32(slices);
                    cmd.AddField("GetMask", Util.FormatFlags(u32),
                                 "A bitmask specifying what metadata to get.", slices);

                    pendingReplies[cmdType] = new GetMetaDataCmd(u32);
                    break;

                case RRACCommand.SetMetaData:
                    u32 = stream.ReadU32(slices);
                    cmd.AddField("PayloadSize", Convert.ToString(u32),
                                 "The number of bytes of payload following this field.", slices);

                    u32 = stream.ReadU32(slices);
                    cmd.AddField("MagicValue", Util.FormatFlags(u32),
                                 "Magic value that must be 0xF0000001.", slices);

                    u32 = stream.ReadU32(slices);
                    cmd.AddField("SetOid", FormatSetType(u32),
                                 "The identifier of the object to set.", slices);

                    pendingReplies[cmdType] = new SetMetaDataCmd(u32);

                    switch (u32)
                    {
                    case SetMetaDataCmd.TYPE_BORING_SSPIDS:
                        bytes = stream.ReadBytes(16, slices);
                        cmd.AddField("FourUnknownDWORDs", Util.FormatByteArray(bytes),
                                     "Four unknown DWORDs.", slices);

                        UInt32 numObjects = stream.ReadU32(slices);
                        cmd.AddField("NumBoringObjects", Convert.ToString(numObjects),
                                     "Number of boring objects following this field.", slices);

                        TransactionNode boringObjects = new TransactionNode("BoringObjects");
                        cmd.AddChild(boringObjects);

                        for (int i = 0; i < numObjects; i++)
                        {
                            u32 = stream.ReadU32(slices);
                            boringObjects.AddField(Convert.ToString(i), Util.FormatFlags(u32),
                                                   "Object type ID.", slices);
                        }
                        break;

                    default:
                        handled = false;
                        cmdLen -= 4 * 3;
                        break;
                    }
                    break;

                case RRACCommand.Notify:
                    UInt32 notifyType = stream.ReadU32(slices);
                    cmd.AddField("NotifyType", FormatNotifyType(notifyType),
                                 "Type of notification.", slices);

                    switch (notifyType)
                    {
                    case NotifyCmd.TYPE_PARTNERSHIPS:
                        u32 = stream.ReadU32(slices);
                        cmd.AddField("Unknown1", Util.FormatFlags(u32),
                                     "Unknown field 1.", slices);

                        u32 = stream.ReadU32(slices);
                        cmd.AddField("Unknown2", Util.FormatFlags(u32),
                                     "Unknown field 2.", slices);

                        u32 = stream.ReadU32(slices);
                        cmd.AddField("Size", Convert.ToString(u32),
                                     "Size of the remaining fields.", slices);

                        u32 = stream.ReadU32(slices);
                        cmd.AddField("PCur", Convert.ToString(u32),
                                     "Current partner index.", slices);

                        u32 = stream.ReadU32(slices);
                        cmd.AddField("P1", Util.FormatFlags(u32),
                                     "Partner 1 ID.", slices);

                        u32 = stream.ReadU32(slices);
                        cmd.AddField("P2", Util.FormatFlags(u32),
                                     "Partner 2 ID.", slices);
                        break;

                    default:
                        handled = false;
                        cmdLen -= 4;
                        break;
                    }
                    break;

                case RRACCommand.Response:
                    ParseCommandReply(cmd, cmdLen);
                    break;

                default:
                    handled = false;
                    break;
                }

                if (!handled)
                {
                    if (cmdLen > 0)
                    {
                        bytes = stream.ReadBytes((int)cmdLen, slices);
                        cmd.AddField("UnknownData", Util.FormatByteArray(bytes), "Unknown data.", slices);
                    }
                }

                AddTransactionNode(cmd);
            }
            catch (EndOfStreamException e)
            {
                throw new StreamSessionParseError(e.Message);
            }
        }
Beispiel #5
0
        private void ParseControlCommand()
        {
            List<PacketSlice> slices = new List<PacketSlice>(2);

            UInt16 cmdTypeRaw, cmdLen;
            RRACCommand cmdType;
            string cmdTypeStr;
            List<PacketSlice> cmdTypeSlices = new List<PacketSlice>(1);
            List<PacketSlice> cmdLenSlices = new List<PacketSlice>(1);

            UInt32 u32;
            byte[] bytes;

            try
            {
                // Command type
                cmdTypeRaw = stream.ReadU16(cmdTypeSlices);

                // Command length
                cmdLen = stream.ReadU16(cmdLenSlices);

                ParseCommandType(cmdTypeRaw, out cmdType, out cmdTypeStr);

                TransactionNode cmd = new TransactionNode(cmdTypeStr);

                cmd.AddField("CommandType", cmdTypeStr,
                    "Command type.", cmdTypeSlices);
                cmd.AddField("CommandLength", Convert.ToString(cmdLen),
                    "Number of bytes following this field.", cmdLenSlices);

                if (cmdType != RRACCommand.Response)
                {
                    cmd.Description = cmd.Name;
                }

                bool handled = true;

                switch (cmdType)
                {
                    case RRACCommand.GetMetaData:
                        u32 = stream.ReadU32(slices);
                        cmd.AddField("GetMask", Util.FormatFlags(u32),
                            "A bitmask specifying what metadata to get.", slices);

                        pendingReplies[cmdType] = new GetMetaDataCmd(u32);
                        break;
                    case RRACCommand.SetMetaData:
                        u32 = stream.ReadU32(slices);
                        cmd.AddField("PayloadSize", Convert.ToString(u32),
                            "The number of bytes of payload following this field.", slices);

                        u32 = stream.ReadU32(slices);
                        cmd.AddField("MagicValue", Util.FormatFlags(u32),
                            "Magic value that must be 0xF0000001.", slices);

                        u32 = stream.ReadU32(slices);
                        cmd.AddField("SetOid", FormatSetType(u32),
                            "The identifier of the object to set.", slices);

                        pendingReplies[cmdType] = new SetMetaDataCmd(u32);

                        switch (u32)
                        {
                            case SetMetaDataCmd.TYPE_BORING_SSPIDS:
                                bytes = stream.ReadBytes(16, slices);
                                cmd.AddField("FourUnknownDWORDs", Util.FormatByteArray(bytes),
                                    "Four unknown DWORDs.", slices);

                                UInt32 numObjects = stream.ReadU32(slices);
                                cmd.AddField("NumBoringObjects", Convert.ToString(numObjects),
                                    "Number of boring objects following this field.", slices);

                                TransactionNode boringObjects = new TransactionNode("BoringObjects");
                                cmd.AddChild(boringObjects);

                                for (int i = 0; i < numObjects; i++)
                                {
                                    u32 = stream.ReadU32(slices);
                                    boringObjects.AddField(Convert.ToString(i), Util.FormatFlags(u32),
                                        "Object type ID.", slices);
                                }
                                break;
                            default:
                                handled = false;
                                cmdLen -= 4 * 3;
                                break;
                        }
                        break;
                    case RRACCommand.Notify:
                        UInt32 notifyType = stream.ReadU32(slices);
                        cmd.AddField("NotifyType", FormatNotifyType(notifyType),
                            "Type of notification.", slices);

                        switch (notifyType)
                        {
                            case NotifyCmd.TYPE_PARTNERSHIPS:
                                u32 = stream.ReadU32(slices);
                                cmd.AddField("Unknown1", Util.FormatFlags(u32),
                                    "Unknown field 1.", slices);

                                u32 = stream.ReadU32(slices);
                                cmd.AddField("Unknown2", Util.FormatFlags(u32),
                                    "Unknown field 2.", slices);

                                u32 = stream.ReadU32(slices);
                                cmd.AddField("Size", Convert.ToString(u32),
                                    "Size of the remaining fields.", slices);

                                u32 = stream.ReadU32(slices);
                                cmd.AddField("PCur", Convert.ToString(u32),
                                    "Current partner index.", slices);

                                u32 = stream.ReadU32(slices);
                                cmd.AddField("P1", Util.FormatFlags(u32),
                                    "Partner 1 ID.", slices);

                                u32 = stream.ReadU32(slices);
                                cmd.AddField("P2", Util.FormatFlags(u32),
                                    "Partner 2 ID.", slices);
                                break;
                            default:
                                handled = false;
                                cmdLen -= 4;
                                break;
                        }
                        break;
                    case RRACCommand.Response:
                        ParseCommandReply(cmd, cmdLen);
                        break;
                    default:
                        handled = false;
                        break;
                }

                if (!handled)
                {
                    if (cmdLen > 0)
                    {
                        bytes = stream.ReadBytes((int)cmdLen, slices);
                        cmd.AddField("UnknownData", Util.FormatByteArray(bytes), "Unknown data.", slices);
                    }
                }

                AddTransactionNode(cmd);
            }
            catch (EndOfStreamException e)
            {
                throw new StreamSessionParseError(e.Message);
            }
        }
Beispiel #6
0
        protected void ParseCommandReply(TransactionNode cmd, int cmdLen)
        {
            UInt32 u32;
            byte[] bytes;
            string str;
            List<PacketSlice> slices = new List<PacketSlice>(2);

            UInt32 replyCmdTypeRaw;
            RRACCommand replyCmdType;
            string replyCmdTypeStr;

            replyCmdTypeRaw = stream.ReadU32(slices);

            ParseCommandType((UInt16)replyCmdTypeRaw, out replyCmdType, out replyCmdTypeStr);

            cmd.AddField("ReplyToCommand", replyCmdTypeStr,
                "Command which this is a reply to.", slices);

            int replyLen = cmdLen - 4;

            if (replyCmdType != RRACCommand.UNKNOWN)
            {
                if (!pendingReplies.ContainsKey(replyCmdType))
                    throw new StreamSessionParseError(String.Format(
                        "Got reply to a command we don't know about: {0} ({1})",
                        replyCmdType, replyCmdTypeRaw));
            }

            bool handled = true;

            cmd.Description = String.Format("{0} to {1}", cmd.Name, replyCmdTypeStr);

            u32 = stream.ReadU32(slices);
            cmd.AddField("Result", Util.FormatValue(u32),
                "Result of the request.", slices);

            u32 = stream.ReadU32(slices);
            cmd.AddField("ResponseDataSize", Util.FormatValue(u32),
                "Number of bytes of response data following the next field.", slices);

            u32 = stream.ReadU32(slices);
            cmd.AddField("Unknown1", Util.FormatValue(u32),
                "Unknown field.", slices);

            replyLen -= 3 * 4;

            if (replyCmdType == RRACCommand.GetMetaData)
            {
                GetMetaDataCmd listCmd =
                    pendingReplies[replyCmdType] as GetMetaDataCmd;

                switch (listCmd.Flags)
                {
                    case 0x7c1:
                        u32 = stream.ReadU32(slices);
                        cmd.AddField("MagicValue", Util.FormatFlags(u32),
                            "Magic value that must be 0xF0000001.", slices);

                        u32 = stream.ReadU32(slices);
                        cmd.AddField("Success", Util.FormatBool(u32),
                            "A value that must be TRUE, probably signifying whether the command succeeded.", slices);

                        u32 = stream.ReadU32(slices);
                        cmd.AddField("HasBody", Util.FormatBool(u32),
                            "A BOOL indicating if the response contains a body or is empty.", slices);

                        u32 = stream.ReadU32(slices);
                        cmd.AddField("ResponseTo", Util.FormatValue(u32),
                            "Two to the power of the position of the bit to which this is a response. So for instance " +
                            "if this is the response to bit 4, this field contains the value 16.", slices);

                        UInt32 typeCount = stream.ReadU32(slices);
                        cmd.AddField("TypeCount", Convert.ToString(typeCount),
                            "Number of types following.", slices);

                        TransactionNode objTypes = new TransactionNode("ObjectTypes");
                        cmd.AddChild(objTypes);

                        for (int i = 0; i < typeCount; i++)
                        {
                            TransactionNode node = new TransactionNode(
                                Convert.ToString(i));

                            u32 = stream.ReadU32(slices);
                            node.AddField("Flags", Util.FormatValue(u32),
                                "Unknown.", slices);

                            str = stream.ReadCString(200, slices);
                            node.AddField("Name1", str, "Name of the object type.", slices);

                            str = stream.ReadCString(80, slices);
                            node.AddField("Name2", str, "Name/description of the object type.", slices);

                            str = stream.ReadCString(80, slices);
                            node.AddField("Name3", str, "Another name/description of the object type (usually blank).", slices);

                            u32 = stream.ReadU32(slices);
                            node.AddField("SSPId", Util.FormatFlags(u32),
                                "Identifier of the object type.", slices);

                            u32 = stream.ReadU32(slices);
                            node.AddField("Count", Util.FormatValue(u32),
                                "Number of items of this object type on the device.", slices);

                            u32 = stream.ReadU32(slices);
                            node.AddField("TotalSize", Util.FormatValue(u32),
                                "Total size of the items of this object type on the device.", slices);

                            List<PacketSlice> allSlices = new List<PacketSlice>(2);

                            UInt32 timeLow = stream.ReadU32(slices);
                            allSlices.AddRange(slices);

                            UInt32 timeHigh = stream.ReadU32(slices);
                            allSlices.AddRange(slices);

                            UInt64 time = (UInt64)timeLow & ((UInt64)timeHigh << 32);

                            node.AddField("FileTime", String.Format("0x{0:x16}", time),
                                "Time of last modification of any of the items of this object type on the device (?).", allSlices);

                            objTypes.AddChild(node);
                        }

                        break;
                    default:
                        handled = false;
                        break;
                }
            }
            else
            {
                handled = false;
            }

            if (!handled)
            {
                if (replyLen > 0)
                {
                    bytes = stream.ReadBytes(replyLen, slices);
                    cmd.AddField("UnknownReplyData", Util.FormatByteArray(bytes),
                        "Unknown reply data.", slices);
                }
            }

            pendingReplies.Remove(replyCmdType);
        }