class_docstr: OLE2 Directory Entry
class_docstr_tok: ["OLE2","Directory","Entry"]
docstr: Constructor for an OleDirectoryEntry object.
  Parses a 128-bytes entry from the OLE Directory stream.
  
  :param entry  : string (must be 128 bytes long)
  :param sid    : index of this directory entry in the OLE file directory
  :param olefile: OleFileIO containing this directory entry
docstr_tok: ["Constructor","for","an","OleDirectoryEntry","object",".","Parses","a","128-bytes","entry","from","the","OLE","Directory","stream",".",":","param","entry",":","string","(","must","be","128","bytes","long",")",":","param","sid",":","index","of","this","directory","entry","in","the","OLE","file","directory",":","param","olefile",":","OleFileIO","containing","this","directory","entry"]
code: def __init__(self, entry, sid, olefile):
      """
      Constructor for an OleDirectoryEntry object.
      Parses a 128-bytes entry from the OLE Directory stream.
  
      :param entry  : string (must be 128 bytes long)
      :param sid    : index of this directory entry in the OLE file directory
      :param olefile: OleFileIO containing this directory entry
      """
      self.sid = sid
      # ref to olefile is stored for future use
      self.olefile = olefile
      # kids is a list of children entries, if this entry is a storage:
      # (list of OleDirectoryEntry objects)
      self.kids = []
      # kids_dict is a dictionary of children entries, indexed by their
      # name in lowercase: used to quickly find an entry, and to detect
      # duplicates
      self.kids_dict = {}
      # flag used to detect if the entry is referenced more than once in
      # directory:
      self.used = False
      # decode DirEntry
      (
          self.name_raw,  # 64s: string containing entry name in unicode UTF-16 (max 31 chars) + null char = 64 bytes
          self.namelength,  # H: uint16, number of bytes used in name buffer, including null = (len+1)*2
          self.entry_type,
          self.color,
          self.sid_left,
          self.sid_right,
          self.sid_child,
          clsid,
          self.dwUserFlags,
          self.createTime,
          self.modifyTime,
          self.isectStart,
          self.sizeLow,
          self.sizeHigh,
      ) = struct.unpack(OleDirectoryEntry.STRUCT_DIRENTRY, entry)
      if self.entry_type not in [
          STGTY_ROOT,
          STGTY_STORAGE,
          STGTY_STREAM,
          STGTY_EMPTY,
      ]:
          olefile._raise_defect(
              DEFECT_INCORRECT, "unhandled OLE storage type"
          )
      # only first directory entry can (and should) be root:
      if self.entry_type == STGTY_ROOT and sid != 0:
          olefile._raise_defect(
              DEFECT_INCORRECT, "duplicate OLE root entry"
          )
      if sid == 0 and self.entry_type != STGTY_ROOT:
          olefile._raise_defect(
              DEFECT_INCORRECT, "incorrect OLE root entry"
          )
      # log.debug(struct.unpack(fmt_entry, entry[:len_entry]))
      # name should be at most 31 unicode characters + null character,
      # so 64 bytes in total (31*2 + 2):
      if self.namelength > 64:
          olefile._raise_defect(
              DEFECT_INCORRECT,
              "incorrect DirEntry name length >64 bytes",
          )
          # if exception not raised, namelength is set to the maximum value:
          self.namelength = 64
      # only characters without ending null char are kept:
      self.name_utf16 = self.name_raw[: (self.namelength - 2)]
      # TODO: check if the name is actually followed by a null unicode character ([MS-CFB] 2.6.1)
      # TODO: check if the name does not contain forbidden characters:
      # [MS-CFB] 2.6.1: "The following characters are illegal and MUST NOT be part of the name: '/', '\', ':', '!'."
      # name is converted from UTF-16LE to the path encoding specified in the OleFileIO:
      self.name = olefile._decode_utf16_str(self.name_utf16)
  
      log.debug("DirEntry SID=%d: %s" % (self.sid, repr(self.name)))
      log.debug(" - type: %d" % self.entry_type)
      log.debug(" - sect: %Xh" % self.isectStart)
      log.debug(
          " - SID left: %d, right: %d, child: %d"
          % (self.sid_left, self.sid_right, self.sid_child)
      )
  
      # sizeHigh is only used for 4K sectors, it should be zero for 512 bytes
      # sectors, BUT apparently some implementations set it as 0xFFFFFFFF, 1
      # or some other value so it cannot be raised as a defect in general:
      if olefile.sectorsize == 512:
          if self.sizeHigh != 0 and self.sizeHigh != 0xFFFFFFFF:
              log.debug(
                  "sectorsize=%d, sizeLow=%d, sizeHigh=%d (%X)"
                  % (
                      olefile.sectorsize,
                      self.sizeLow,
                      self.sizeHigh,
                      self.sizeHigh,
                  )
              )
              olefile._raise_defect(
                  DEFECT_UNSURE, "incorrect OLE stream size"
              )
          self.size = self.sizeLow
      else:
          self.size = self.sizeLow + (long(self.sizeHigh) << 32)
      log.debug(
          " - size: %d (sizeLow=%d, sizeHigh=%d)"
          % (self.size, self.sizeLow, self.sizeHigh)
      )
  
      self.clsid = _clsid(clsid)
      # a storage should have a null size, BUT some implementations such as
      # Word 8 for Mac seem to allow non-null values => Potential defect:
      if self.entry_type == STGTY_STORAGE and self.size != 0:
          olefile._raise_defect(
              DEFECT_POTENTIAL, "OLE storage with size>0"
          )
      # check if stream is not already referenced elsewhere:
      self.is_minifat = False
      if (
          self.entry_type in (STGTY_ROOT, STGTY_STREAM)
          and self.size > 0
      ):
          if (
              self.size < olefile.minisectorcutoff
              and self.entry_type == STGTY_STREAM
          ):  # only streams can be in MiniFAT
              # ministream object
              self.is_minifat = True
          else:
              self.is_minifat = False
          olefile._check_duplicate_stream(
              self.isectStart, self.is_minifat
          )
      self.sect_chain = None
  
imports: from __future__ import print_function
  import io
  import sys
  import struct, array, os.path, datetime, logging
label_desc: Use image node_id 1 to create a new OleDirectoryEntry object  with example: obj = OleDirectoryEntry(entry, sid, olefile)