System.IO.FileSystemWatcher.ParseEventBufferAndNotifyForEach C# (CSharp) Method

ParseEventBufferAndNotifyForEach() private method

private ParseEventBufferAndNotifyForEach ( byte buffer ) : void
buffer byte
return void
        private void ParseEventBufferAndNotifyForEach(byte[] buffer)
        {
            // Parse each event from the buffer and notify appropriate delegates

            /******
                Format for the buffer is the following C struct:

                typedef struct _FILE_NOTIFY_INFORMATION {
                   DWORD NextEntryOffset;
                   DWORD Action;
                   DWORD FileNameLength;
                   WCHAR FileName[1];
                } FILE_NOTIFY_INFORMATION;

                NOTE1: FileNameLength is length in bytes.
                NOTE2: The Filename is a Unicode string that's NOT NULL terminated.
                NOTE3: A NextEntryOffset of zero means that it's the last entry
            *******/

            // Parse the file notify buffer:
            int offset = 0;
            int nextOffset, action, nameLength;
            string oldName = null;
            string name = null;

            do
            {
                unsafe
                {
                    fixed (byte* buffPtr = buffer)
                    {
                        // Get next offset:
                        nextOffset = *((int*)(buffPtr + offset));

                        // Get change flag:
                        action = *((int*)(buffPtr + offset + 4));

                        // Get filename length (in bytes):
                        nameLength = *((int*)(buffPtr + offset + 8));
                        name = new string((char*)(buffPtr + offset + 12), 0, nameLength / 2);
                    }
                }

                /* A slightly convoluted piece of code follows.  Here's what's happening:

                   We wish to collapse the poorly done rename notifications from the
                   ReadDirectoryChangesW API into a nice rename event. So to do that,
                   it's assumed that a FILE_ACTION_RENAMED_OLD_NAME will be followed
                   immediately by a FILE_ACTION_RENAMED_NEW_NAME in the buffer, which is
                   all that the following code is doing.

                   On a FILE_ACTION_RENAMED_OLD_NAME, it asserts that no previous one existed
                   and saves its name.  If there are no more events in the buffer, it'll
                   assert and fire a RenameEventArgs with the Name field null.

                   If a NEW_NAME action comes in with no previous OLD_NAME, we assert and fire
                   a rename event with the OldName field null.

                   If the OLD_NAME and NEW_NAME actions are indeed there one after the other,
                   we'll fire the RenamedEventArgs normally and clear oldName.

                   If the OLD_NAME is followed by another action, we assert and then fire the
                   rename event with the Name field null and then fire the next action.

                   In case it's not a OLD_NAME or NEW_NAME action, we just fire the event normally.

                   (Phew!)
                 */

                // If the action is RENAMED_FROM, save the name of the file
                if (action == Interop.Kernel32.FileOperations.FILE_ACTION_RENAMED_OLD_NAME)
                {
                    Debug.Assert(oldName == null, "Two FILE_ACTION_RENAMED_OLD_NAME in a row!  [" + oldName + "], [ " + name + "]");
                    oldName = name;
                }
                else if (action == Interop.Kernel32.FileOperations.FILE_ACTION_RENAMED_NEW_NAME)
                {
                    if (oldName != null)
                    {
                        NotifyRenameEventArgs(WatcherChangeTypes.Renamed, name, oldName);
                        oldName = null;
                    }
                    else
                    {
                        Debug.Fail("FILE_ACTION_RENAMED_NEW_NAME with no old name! [ " + name + "]");
                        NotifyRenameEventArgs(WatcherChangeTypes.Renamed, name, oldName);
                        oldName = null;
                    }
                }
                else
                {
                    if (oldName != null)
                    {
                        Debug.Fail("Previous FILE_ACTION_RENAMED_OLD_NAME with no new name!  [" + oldName + "]");
                        NotifyRenameEventArgs(WatcherChangeTypes.Renamed, null, oldName);
                        oldName = null;
                    }

                    switch (action)
                    {
                        case Interop.Kernel32.FileOperations.FILE_ACTION_ADDED:
                            NotifyFileSystemEventArgs(WatcherChangeTypes.Created, name);
                            break;
                        case Interop.Kernel32.FileOperations.FILE_ACTION_REMOVED:
                            NotifyFileSystemEventArgs(WatcherChangeTypes.Deleted, name);
                            break;
                        case Interop.Kernel32.FileOperations.FILE_ACTION_MODIFIED:
                            NotifyFileSystemEventArgs(WatcherChangeTypes.Changed, name);
                            break;
                        default:
                            Debug.Fail("Unknown FileSystemEvent action type!  Value: " + action);
                            break;
                    }
                }

                offset += nextOffset;
            } while (nextOffset != 0);

            if (oldName != null)
            {
                Debug.Fail("FILE_ACTION_RENAMED_OLD_NAME with no new name!  [" + oldName + "]");
                NotifyRenameEventArgs(WatcherChangeTypes.Renamed, null, oldName);
                oldName = null;
            }
        }