# Buggy code
def ReadBSMEvent(self, parser_mediator, file_object):
    """Returns a BsmEvent from a single BSM entry.

    Args:
      parser_mediator: A parser mediator object (instance of ParserMediator).
      file_object: A file-like object.

    Returns:
      An event object.
    """
    # A list of tokens that has the entry.
    extra_tokens = []

    offset = file_object.tell()

    # Token header, first token for each entry.
    try:
        token_id = self.BSM_TYPE.parse_stream(file_object)
    except (IOError, construct.FieldError):
        return

    bsm_type, structure = self.BSM_TYPE_LIST.get(token_id, ["", ""])
    if bsm_type == "BSM_HEADER32":
        token = structure.parse_stream(file_object)
    elif bsm_type == "BSM_HEADER64":
        token = structure.parse_stream(file_object)
    elif bsm_type == "BSM_HEADER32_EX":
        token = structure.parse_stream(file_object)
    else:
        logging.warning(
            "Token ID Header {0} not expected at position 0x{1:X}."
            "The parsing of the file cannot be continued".format(
                token_id, file_object.tell()
            )
        )
        # TODO: if it is a Mac OS X, search for the trailer magic value
        #       as a end of the entry can be a possibility to continue.
        return

    length = token.bsm_header.length
    event_type = "{0} ({1})".format(
        bsmtoken.BSM_AUDIT_EVENT.get(token.bsm_header.event_type, "UNKNOWN"),
        token.bsm_header.event_type,
    )
    timestamp = timelib.Timestamp.FromPosixTimeWithMicrosecond(
        token.timestamp, token.microsecond
    )

    # Read until we reach the end of the record.
    while file_object.tell() < (offset + length):
        # Check if it is a known token.
        try:
            token_id = self.BSM_TYPE.parse_stream(file_object)
        except (IOError, construct.FieldError):
            logging.warning(
                "Unable to parse the Token ID at position: {0:d}".format(
                    file_object.tell()
                )
            )
            return
        if not token_id in self.BSM_TYPE_LIST:
            pending = (offset + length) - file_object.tell()
            extra_tokens.extend(
                self.TryWithUntestedStructures(file_object, token_id, pending)
            )
        else:
            token = self.BSM_TYPE_LIST[token_id][1].parse_stream(file_object)
            extra_tokens.append(self.FormatToken(token_id, token, file_object))

    if file_object.tell() > (offset + length):
        logging.warning(
            "Token ID {0} not expected at position 0x{1:X}."
            "Jumping for the next entry.".format(token_id, file_object.tell())
        )
        try:
            file_object.seek((offset + length) - file_object.tell(), os.SEEK_CUR)
        except (IOError, construct.FieldError) as exception:
            logging.warning(
                "Unable to jump to next entry with error: {0:s}".format(exception)
            )
            return

    # BSM can be in more than one OS: BSD, Solaris and Mac OS X.
    if parser_mediator.platform == "MacOSX":
        # In Mac OS X the last two tokens are the return status and the trailer.
        if len(extra_tokens) >= 2:
            return_value = extra_tokens[-2:-1][0]
            if return_value.startswith(
                "[BSM_TOKEN_RETURN32"
            ) or return_value.startswith("[BSM_TOKEN_RETURN64"):
                _ = extra_tokens.pop(len(extra_tokens) - 2)
            else:
                return_value = "Return unknown"
        else:
            return_value = "Return unknown"
        if extra_tokens:
            trailer = extra_tokens[-1]
            if trailer.startswith("[BSM_TOKEN_TRAILER"):
                _ = extra_tokens.pop(len(extra_tokens) - 1)
            else:
                trailer = "Trailer unknown"
        else:
            trailer = "Trailer unknown"
        return MacBsmEvent(
            event_type,
            timestamp,
            ". ".join(extra_tokens),
            return_value,
            trailer,
            offset,
        )
    else:
        # Generic BSM format.
        if extra_tokens:
            trailer = extra_tokens[-1]
            if trailer.startswith("[BSM_TOKEN_TRAILER"):
                _ = extra_tokens.pop(len(extra_tokens) - 1)
            else:
                trailer = "Trailer unknown"
        else:
            trailer = "Trailer unknown"
        return BsmEvent(event_type, timestamp, ". ".join(extra_tokens), trailer, offset)


# Traceback (WindowsError)
(plaso) C:\dev\plaso>python tools\psort.py -o xlsx G:\test_data\set_1_output.zip -w G:\test_data\set_1_output.xlsx --status_view none -d --analysis browser_search
2016-08-30 12:37:21,882 [INFO] (MainProcess) PID:9376 <psort> Starting analysis plugins.
2016-08-30 12:37:21,888 [DEBUG] (MainProcess) PID:9376 <zeromq_queue> Creating socket for browser_search output event queue
2016-08-30 12:37:21,898 [DEBUG] (MainProcess) PID:9376 <zeromq_queue> browser_search output event queue bound to random port 61649
2016-08-30 12:37:22,417 [INFO] (MainProcess) PID:9376 <psort> Started analysis plugin: browser_search (PID: 14200).
2016-08-30 12:37:24,822 [INFO] (MainProcess) PID:9376 <psort> Analysis plugins running
Traceback (most recent call last):
File "tools\psort.py", line 867, in <module>
if not Main():
File "tools\psort.py", line 853, in Main
tool.ProcessStorage()
File "tools\psort.py", line 787, in ProcessStorage
status_update_callback=status_update_callback)
File "C:\dev\plaso\plaso\frontend\psort.py", line 103, in AnalyzeEvents
status_update_callback=status_update_callback)
File "C:\dev\plaso\plaso\multi_processing\psort.py", line 536, in AnalyzeEvents
storage_writer.Open()
File "C:\dev\plaso\plaso\storage\zip_file.py", line 3217, in Open
self._storage_file.Open(path=self._output_file, read_only=False)
File "C:\dev\plaso\plaso\storage\zip_file.py", line 2754, in Open
self._OpenZIPFile(path, read_only)
File "C:\dev\plaso\plaso\storage\zip_file.py", line 1740, in _OpenZIPFile
os.rename(path, zipfile_path)
WindowsError: [Error 32] The process cannot access the file because it is being used by another process

# Fixed code
def ReadBSMEvent(self, parser_mediator, file_object):
    """Returns a BsmEvent from a single BSM entry.

    Args:
      parser_mediator: A parser mediator object (instance of ParserMediator).
      file_object: A file-like object.

    Returns:
      An event object.
    """
    # A list of tokens that has the entry.
    extra_tokens = []

    offset = file_object.tell()

    # Token header, first token for each entry.
    try:
        token_id = self.BSM_TYPE.parse_stream(file_object)
    except (IOError, construct.FieldError):
        return

    bsm_type, structure = self.BSM_TYPE_LIST.get(token_id, ["", ""])
    if bsm_type == "BSM_HEADER32":
        token = structure.parse_stream(file_object)
    elif bsm_type == "BSM_HEADER64":
        token = structure.parse_stream(file_object)
    elif bsm_type == "BSM_HEADER32_EX":
        token = structure.parse_stream(file_object)
    else:
        logging.warning(
            "Token ID Header {0} not expected at position 0x{1:X}."
            "The parsing of the file cannot be continued".format(
                token_id, file_object.tell()
            )
        )
        # TODO: if it is a Mac OS X, search for the trailer magic value
        #       as a end of the entry can be a possibility to continue.
        return

    length = token.bsm_header.length
    event_type = "{0} ({1})".format(
        bsmtoken.BSM_AUDIT_EVENT.get(token.bsm_header.event_type, "UNKNOWN"),
        token.bsm_header.event_type,
    )
    timestamp = timelib.Timestamp.FromPosixTimeWithMicrosecond(
        token.timestamp, token.microsecond
    )

    # Read until we reach the end of the record.
    while file_object.tell() < (offset + length):
        # Check if it is a known token.
        try:
            token_id = self.BSM_TYPE.parse_stream(file_object)
        except (IOError, construct.FieldError):
            logging.warning(
                "Unable to parse the Token ID at position: {0:d}".format(
                    file_object.tell()
                )
            )
            return
        if token_id not in self.BSM_TYPE_LIST:
            pending = (offset + length) - file_object.tell()
            extra_tokens.extend(
                self.TryWithUntestedStructures(file_object, token_id, pending)
            )
        else:
            token = self.BSM_TYPE_LIST[token_id][1].parse_stream(file_object)
            extra_tokens.append(self.FormatToken(token_id, token, file_object))

    if file_object.tell() > (offset + length):
        logging.warning(
            "Token ID {0} not expected at position 0x{1:X}."
            "Jumping for the next entry.".format(token_id, file_object.tell())
        )
        try:
            file_object.seek((offset + length) - file_object.tell(), os.SEEK_CUR)
        except (IOError, construct.FieldError) as exception:
            logging.warning(
                "Unable to jump to next entry with error: {0:s}".format(exception)
            )
            return

    # BSM can be in more than one OS: BSD, Solaris and Mac OS X.
    if parser_mediator.platform == "MacOSX":
        # In Mac OS X the last two tokens are the return status and the trailer.
        if len(extra_tokens) >= 2:
            return_value = extra_tokens[-2:-1][0]
            if return_value.startswith(
                "[BSM_TOKEN_RETURN32"
            ) or return_value.startswith("[BSM_TOKEN_RETURN64"):
                _ = extra_tokens.pop(len(extra_tokens) - 2)
            else:
                return_value = "Return unknown"
        else:
            return_value = "Return unknown"
        if extra_tokens:
            trailer = extra_tokens[-1]
            if trailer.startswith("[BSM_TOKEN_TRAILER"):
                _ = extra_tokens.pop(len(extra_tokens) - 1)
            else:
                trailer = "Trailer unknown"
        else:
            trailer = "Trailer unknown"
        return MacBsmEvent(
            event_type,
            timestamp,
            ". ".join(extra_tokens),
            return_value,
            trailer,
            offset,
        )
    else:
        # Generic BSM format.
        if extra_tokens:
            trailer = extra_tokens[-1]
            if trailer.startswith("[BSM_TOKEN_TRAILER"):
                _ = extra_tokens.pop(len(extra_tokens) - 1)
            else:
                trailer = "Trailer unknown"
        else:
            trailer = "Trailer unknown"
        return BsmEvent(event_type, timestamp, ". ".join(extra_tokens), trailer, offset)