def main(): usage = "%prog [options] thumbsdb id" description = "\n".join([ "Extracts raw thumbnail data from a thumbs.db file." "", "If thumbsdb is '-', then stdin is read." ]) parser = OptionParser(usage=usage, description=description, version=VERSION_STR) parser.add_option("-c", dest="catalog_name", action="store", help="The name of the catalog stream (def: %default)", default="Catalog") (options, args) = parser.parse_args() if len(args) < 2: parser.error("You must specify a thumbs.db file or '-' and an id") # end if if args[0] == "-": cfb = CompoundFile(ByteIStream(sys.stdin.buffer.read())) else: cfb = CompoundFile(RawIStream(args[0])) # end if tdb = ThumbsDb(cfb, options.catalog_name) entry_id = int(args[1]) sys.stdout.buffer.write(tdb.thumbnails[entry_id].data)
def main(): usage = "%prog [options] -i sid olefile" description = "\n".join([ "Displays OLE property sets from a stream in an OLE compound file.", "", "If file is '-' then stdin is read." ]) parser = OptionParser( usage=usage, description=description, version=VERSION_STR ) parser.add_option( "-r", action="store_true", dest="raw_stream", help="Input is just a stream (not an OLE compound file)", default=False ) parser.add_option( "-i", action="store", dest="sid", help="Stream to analyze", ) (options, args) = parser.parse_args() if len(args) < 1: parser.error("You must specify an olefile (or '-' for stdin)") # end if if (not options.raw_stream) and (not options.sid): parser.error("You must specify either -i or -r") # end if if args[0] == "-": input_stream = ByteIStream(sys.stdin.buffer.read()) else: input_stream = RawIStream(args[0]) # end if if options.raw_stream: output = format_output(input_stream, options) else: cfb = CompoundFile(input_stream) sid = int(options.sid) if sid not in cfb.dir_entries: print("Can't find sid {0}".format(sid), file=sys.stderr) sys.exit(-2) # end if output = format_output(cfb.get_stream(sid), options) # end if print("\n".join(output))
def main(): usage = "%prog [options] thumbsdb" description = "\n".join([ "Lists the entries in an thumbs.db file.", "", "If thumbsdb is '-', then stdin is read." ]) parser = OptionParser(usage=usage, description=description, version=VERSION_STR) parser.add_option("-p", dest="pretty_output", action="store_true", help="Display details in 'pretty-print' format", default=False) parser.add_option("-l", dest="long_output", action="store_true", help="Display details in long format", default=False) parser.add_option("-m", dest="mactime_output", action="store_true", help="Display details in mactime format", default=False) parser.add_option("-c", dest="catalog_name", action="store", help="The name of the catalog stream (def: %default)", default="Catalog") (options, args) = parser.parse_args() if options.mactime_output and options.long_output: parser.error("You can't specify both -l and -m") elif options.mactime_output and options.pretty_output: parser.error("You can't specify both -m and -p") elif options.long_output and options.pretty_output: parser.error("You can't specify both -l and -p") elif len(args) == 0: parser.error("You must specify a thumbs.db file or '-'") # end if if args[0] == "-": cfb = CompoundFile(ByteIStream(sys.stdin.buffer.read())) else: cfb = CompoundFile(RawIStream(args[0])) # end if tdb = ThumbsDb(cfb, options.catalog_name) output = format_output(tdb, options) print("\n".join(output))
def main(): usage = "%prog [options] -i sid olefile" description = "\n".join([ "Displays OLE property sets from a stream in an OLE compound file.", "", "If file is '-' then stdin is read." ]) parser = OptionParser(usage=usage, description=description, version=VERSION_STR) parser.add_option("-r", action="store_true", dest="raw_stream", help="Input is just a stream (not an OLE compound file)", default=False) parser.add_option( "-i", action="store", dest="sid", help="Stream to analyze", ) (options, args) = parser.parse_args() if len(args) < 1: parser.error("You must specify an olefile (or '-' for stdin)") # end if if (not options.raw_stream) and (not options.sid): parser.error("You must specify either -i or -r") # end if if args[0] == "-": input_stream = ByteIStream(sys.stdin.buffer.read()) else: input_stream = RawIStream(args[0]) # end if if options.raw_stream: output = format_output(input_stream, options) else: cfb = CompoundFile(input_stream) sid = int(options.sid) if sid not in cfb.dir_entries: print("Can't find sid {0}".format(sid), file=sys.stderr) sys.exit(-2) # end if output = format_output(cfb.get_stream(sid), options) # end if print("\n".join(output))
def main(): usage = "%prog olefile sid" description = "\n".join([ "Displays statistics about entries in an OLE compound file.", "", "If file is '-' then stdin is read." ]) parser = OptionParser( usage=usage, description=description, version=VERSION_STR ) (options, args) = parser.parse_args() if len(args) < 2: parser.error("Must specify both a file and stream identifier") # end if if args[0] == "-": cfb = CompoundFile(ByteIStream(sys.stdin.buffer.read())) else: cfb = CompoundFile(RawIStream(args[0])) # end if sid = int(args[1]) last_sid = len(cfb.dir_entries) header_sid = last_sid + 0 difat_sid = last_sid + 1 fat_sid = last_sid + 2 mini_fat_sid = last_sid + 3 if sid in cfb.dir_entries: entry = cfb.dir_entries[sid] if cfb.is_valid_dir_entry(entry): output = format_entry(cfb, sid) else: print("Invalid sid {0}".format(sid), file=sys.stderr) sys.exit(-2) # end if elif sid == header_sid: output = format_header(cfb) elif sid == difat_sid: output = format_di_fat(cfb) elif sid == fat_sid: output = format_fat(cfb) elif sid == mini_fat_sid: output = format_mini_fat(cfb) else: print("Invalid sid {0}".format(sid), file=sys.stderr) sys.exit(-3) # end if print ("\n".join(output))
def main(): usage = "%prog thumbsdb id" description = "\n".join([ "Displays statistics about a specific entry in a thumbs.db file." "", "If thumbsdb is '-', then stdin is read." ]) parser = OptionParser(usage=usage, description=description, version=VERSION_STR) parser.add_option("-c", dest="catalog_name", action="store", help="The name of the catalog stream (def: %default)", default="Catalog") (options, args) = parser.parse_args() if len(args) < 2: parser.error("You must specify both an thumbs.db file and an id") # end fi if args[0] == "-": cfb = CompoundFile(ByteIStream(sys.stdin.buffer.read())) else: cfb = CompoundFile(RawIStream(args[0])) # end if tdb = ThumbsDb(cfb, options.catalog_name) entry_id = int(args[1]) entries = tdb.catalog.entries key_values = dict([(getattr(entry, "id"), entry) for entry in entries]) ids = list(key_values.keys()) ids.append(ids[-1] + 1) # $Catalog if entry_id not in ids: parser.error("Unknown id {0}".format(entry_id)) # end if if entry_id == ids[-1]: output = format_catalog(tdb) else: output = format_entry(tdb, key_values[entry_id]) # end if print("\n".join(output))
def test_from_property_set(self): ae = self.assertEqual blair_path = os.path.join("data", "doc", "blair.doc") sample_path = os.path.join("data", "doc", "sample.doc") blair_cfb = CompoundFile(RawIStream(blair_path)) sample_cfb = CompoundFile(RawIStream(sample_path)) blair_si = Builder.build(blair_cfb.get_stream(3)) blair_dsi = Builder.build(blair_cfb.get_stream(4)) sample_si = Builder.build(sample_cfb.get_stream(39)) sample_dsi = Builder.build(sample_cfb.get_stream(40)) blair_si_metadata = PropertySetMetadata.from_property_set(blair_si) blair_dsi_metadata = PropertySetMetadata.from_property_set(blair_dsi) sample_si_metadata = PropertySetMetadata.from_property_set(sample_si) sample_dsi_metadata = PropertySetMetadata.from_property_set(sample_dsi) ae(blair_si_metadata.byte_order, blair_si.byte_order) ae(blair_si_metadata.version, blair_si.version) ae(blair_si_metadata.sys_id, blair_si.sys_id) ae(blair_si_metadata.clsid, blair_si.clsid) ae(blair_si_metadata.fmtid0, UUID("f29f85e0-4ff9-1068-ab91-08002b27b3d9")) ae(blair_si_metadata.fmtid1, None) ae(blair_dsi_metadata.byte_order, blair_dsi.byte_order) ae(blair_dsi_metadata.version, blair_dsi.version) ae(blair_dsi_metadata.sys_id, blair_dsi.sys_id) ae(blair_dsi_metadata.clsid, blair_dsi.clsid) ae(blair_dsi_metadata.fmtid0, UUID("d5cdd502-2e9c-101b-9397-08002b2cf9ae")) ae(blair_dsi_metadata.fmtid1, UUID("d5cdd505-2e9c-101b-9397-08002b2cf9ae")) ae(sample_si_metadata.byte_order, sample_si.byte_order) ae(sample_si_metadata.version, sample_si.version) ae(sample_si_metadata.sys_id, sample_si.sys_id) ae(sample_si_metadata.clsid, sample_si.clsid) ae(sample_si_metadata.fmtid0, UUID("f29f85e0-4ff9-1068-ab91-08002b27b3d9")) ae(sample_si_metadata.fmtid1, None) ae(sample_dsi_metadata.byte_order, sample_dsi.byte_order) ae(sample_dsi_metadata.version, sample_dsi.version) ae(sample_dsi_metadata.sys_id, sample_dsi.sys_id) ae(sample_dsi_metadata.clsid, sample_dsi.clsid) ae(sample_dsi_metadata.fmtid0, UUID("d5cdd502-2e9c-101b-9397-08002b2cf9ae")) ae(sample_dsi_metadata.fmtid1, UUID("d5cdd505-2e9c-101b-9397-08002b2cf9ae"))
def setUp(self): blair_path = join("data", "doc", "blair.doc") sample_path = join("data", "doc", "sample.doc") blair_cfb = CompoundFile(RawIStream(blair_path)) sample_cfb = CompoundFile(RawIStream(sample_path)) self.blair_si_stream = blair_cfb.get_stream(3) self.sample_si_stream = sample_cfb.get_stream(39) self.blair_dsi_stream = blair_cfb.get_stream(4) self.sample_dsi_stream = sample_cfb.get_stream(40)
def main(): usage = "%prog [options] olefile sid" description = "\n".join([ "Displays the contents of an OLE stream to standard out." "", "If file is '-', then stdin is read.", ]) parser = OptionParser( usage=usage, description=description, version=VERSION_STR ) parser.add_option( "-s", dest="include_slack", action="store_true", help="Include slack space", default=False ) (options, args) = parser.parse_args() if len(args) < 2: parser.error("Must specify both olefile and sid") # end if if args[0] == "-": cfb = CompoundFile(ByteIStream(sys.stdin.buffer.read())) else: cfb = CompoundFile(RawIStream(args[0])) # end if sid = int(args[1]) if sid not in cfb.dir_entries: print("Can't find sid {0}".format(sid), file=sys.stderr) sys.exit(-2) # end if stream = cfb.get_stream(sid, options.include_slack) stream.seek(0, SEEK_SET) sys.stdout.buffer.write(stream.read())
def main(): usage = "%prog [options] olefile [dir. entry #]" description = "\n".join([ "Lists entries in an OLE compound file.", "", "If file is '-', then stdin is read.", "If a directory entry number is not specified, root is assumed." ]) parser = OptionParser( usage=usage, description=description, version=VERSION_STR ) parser.add_option( "-D", dest="only_dirs", action="store_true", help="Display only directories (storages)", default=False ) parser.add_option( "-F", dest="only_files", action="store_true", help="Display only files (streams)", default=False ) parser.add_option( "-l", dest="long_output", action="store_true", help="Display details in long format", default=False ) parser.add_option( "-m", metavar="PATH", dest="mactime_filename", action="store", help="Display details in mactime format (prefixed by PATH)" ) parser.add_option( "-p", dest="display_full_path", action="store_true", help="Display full path when recursing", default=False ) parser.add_option( "-r", dest="recurse", action="store_true", help="Recurse into sub-directories", default=False ) (options, args) = parser.parse_args() if options.only_dirs and options.only_files: parser.error("Can't specify both -D and -F") elif options.long_output and options.mactime_filename: parser.error("Can't specify both -l and -m") # end if if (len(args) < 1) or (len(args) > 2): parser.error("Invalid number of arguments") sys.exit(-1) # end if if args[0] == "-": cfb = CompoundFile(ByteIStream(sys.stdin.buffer.read())) else: cfb = CompoundFile(RawIStream(args[0])) # end if if len(args) == 1: start_sid = DEFAULT_START_SID else: start_sid = int(args[1]) # end if if start_sid in cfb.dir_entries: entry = cfb.dir_entries[start_sid] if cfb.is_valid_dir_entry(entry): entries = enumerate_entries(cfb, start_sid, options) if options.mactime_filename: path = "".join([options.mactime_filename, "/"]) else: path = "" # end if output = format_output(cfb, entries, options, path) else: print("Invalid directory {0}".format(start_sid), file=sys.stderr) sys.exit(-2) # end if else: print("Invalid directory {0}".format(start_sid), file=sys.stderr) sys.exit(-3) # end if print("\n".join(output))
def main(): usage = "%prog [options] olefile [dir. entry #]" description = "\n".join([ "Lists entries in an OLE compound file.", "", "If file is '-', then stdin is read.", "If a directory entry number is not specified, root is assumed." ]) parser = OptionParser(usage=usage, description=description, version=VERSION_STR) parser.add_option("-D", dest="only_dirs", action="store_true", help="Display only directories (storages)", default=False) parser.add_option("-F", dest="only_files", action="store_true", help="Display only files (streams)", default=False) parser.add_option("-l", dest="long_output", action="store_true", help="Display details in long format", default=False) parser.add_option( "-m", metavar="PATH", dest="mactime_filename", action="store", help="Display details in mactime format (prefixed by PATH)") parser.add_option("-p", dest="display_full_path", action="store_true", help="Display full path when recursing", default=False) parser.add_option("-r", dest="recurse", action="store_true", help="Recurse into sub-directories", default=False) (options, args) = parser.parse_args() if options.only_dirs and options.only_files: parser.error("Can't specify both -D and -F") elif options.long_output and options.mactime_filename: parser.error("Can't specify both -l and -m") # end if if (len(args) < 1) or (len(args) > 2): parser.error("Invalid number of arguments") sys.exit(-1) # end if if args[0] == "-": cfb = CompoundFile(ByteIStream(sys.stdin.buffer.read())) else: cfb = CompoundFile(RawIStream(args[0])) # end if if len(args) == 1: start_sid = DEFAULT_START_SID else: start_sid = int(args[1]) # end if if start_sid in cfb.dir_entries: entry = cfb.dir_entries[start_sid] if cfb.is_valid_dir_entry(entry): entries = enumerate_entries(cfb, start_sid, options) if options.mactime_filename: path = "".join([options.mactime_filename, "/"]) else: path = "" # end if output = format_output(cfb, entries, options, path) else: print("Invalid directory {0}".format(start_sid), file=sys.stderr) sys.exit(-2) # end if else: print("Invalid directory {0}".format(start_sid), file=sys.stderr) sys.exit(-3) # end if print("\n".join(output))
def setUp(self): input_file = join("data", "thumbsdb", "thumbs.db") self.cfb = CompoundFile(RawIStream(input_file)) self.tdb = ThumbsDb(self.cfb)
def test_from_property_set(self): ae = self.assertEqual blair_path = os.path.join("data", "doc", "blair.doc") sample_path = os.path.join("data", "doc", "sample.doc") blair_cfb = CompoundFile(RawIStream(blair_path)) sample_cfb = CompoundFile(RawIStream(sample_path)) blair_si = Builder.build(blair_cfb.get_stream(3)) blair_dsi = Builder.build(blair_cfb.get_stream(4)) sample_si = Builder.build(sample_cfb.get_stream(39)) sample_dsi = Builder.build(sample_cfb.get_stream(40)) blair_si_metadata = PropertySetMetadata.from_property_set(blair_si) blair_dsi_metadata = PropertySetMetadata.from_property_set(blair_dsi) sample_si_metadata = PropertySetMetadata.from_property_set(sample_si) sample_dsi_metadata = PropertySetMetadata.from_property_set(sample_dsi) ae(blair_si_metadata.byte_order, blair_si.byte_order) ae(blair_si_metadata.version, blair_si.version) ae(blair_si_metadata.sys_id, blair_si.sys_id) ae(blair_si_metadata.clsid, blair_si.clsid) ae( blair_si_metadata.fmtid0, UUID("f29f85e0-4ff9-1068-ab91-08002b27b3d9") ) ae(blair_si_metadata.fmtid1, None) ae(blair_dsi_metadata.byte_order, blair_dsi.byte_order) ae(blair_dsi_metadata.version, blair_dsi.version) ae(blair_dsi_metadata.sys_id, blair_dsi.sys_id) ae(blair_dsi_metadata.clsid, blair_dsi.clsid) ae( blair_dsi_metadata.fmtid0, UUID("d5cdd502-2e9c-101b-9397-08002b2cf9ae") ) ae( blair_dsi_metadata.fmtid1, UUID("d5cdd505-2e9c-101b-9397-08002b2cf9ae") ) ae(sample_si_metadata.byte_order, sample_si.byte_order) ae(sample_si_metadata.version, sample_si.version) ae(sample_si_metadata.sys_id, sample_si.sys_id) ae(sample_si_metadata.clsid, sample_si.clsid) ae( sample_si_metadata.fmtid0, UUID("f29f85e0-4ff9-1068-ab91-08002b27b3d9") ) ae(sample_si_metadata.fmtid1, None) ae(sample_dsi_metadata.byte_order, sample_dsi.byte_order) ae(sample_dsi_metadata.version, sample_dsi.version) ae(sample_dsi_metadata.sys_id, sample_dsi.sys_id) ae(sample_dsi_metadata.clsid, sample_dsi.clsid) ae( sample_dsi_metadata.fmtid0, UUID("d5cdd502-2e9c-101b-9397-08002b2cf9ae") ) ae( sample_dsi_metadata.fmtid1, UUID("d5cdd505-2e9c-101b-9397-08002b2cf9ae") )
def test_from_properties(self): ae = self.assertEqual blair_path = os.path.join("data", "doc", "blair.doc") sample_path = os.path.join("data", "doc", "sample.doc") blair_cfb = CompoundFile(RawIStream(blair_path)) sample_cfb = CompoundFile(RawIStream(sample_path)) blair_si = Builder.build(blair_cfb.get_stream(3)) blair_dsi = Builder.build(blair_cfb.get_stream(4)) sample_si = Builder.build(sample_cfb.get_stream(39)) sample_dsi = Builder.build(sample_cfb.get_stream(40)) blair_si_metadata = PropertiesMetadata.from_properties( blair_si.property_set_0.properties ) blair_dsi_metadata_0 = PropertiesMetadata.from_properties( blair_dsi.property_set_0.properties ) blair_dsi_metadata_1 = PropertiesMetadata.from_properties( blair_dsi.property_set_1.properties ) sample_si_metadata = PropertiesMetadata.from_properties( sample_si.property_set_0.properties ) sample_dsi_metadata_0 = PropertiesMetadata.from_properties( sample_dsi.property_set_0.properties ) sample_dsi_metadata_1 = PropertiesMetadata.from_properties( sample_dsi.property_set_1.properties ) ae(blair_si_metadata.code_page, 0x4E4) ae(blair_si_metadata.dictionary, None) ae(blair_si_metadata.locale, None) ae(blair_si_metadata.behavior, None) ae(blair_si_metadata.attr_exists, set(["code_page"])) ae(blair_dsi_metadata_0.code_page, 0x4E4) ae(blair_dsi_metadata_0.dictionary, None) ae(blair_dsi_metadata_0.locale, None) ae(blair_dsi_metadata_0.behavior, None) ae(blair_dsi_metadata_0.attr_exists, set(["code_page"])) ae(blair_dsi_metadata_1.code_page, 0x4E4) ae(blair_dsi_metadata_1.dictionary, { 2: "_PID_GUID" }) ae(blair_dsi_metadata_1.locale, None) ae(blair_dsi_metadata_1.behavior, None) ae(blair_dsi_metadata_1.attr_exists, set(["dictionary", "code_page"])) ae(sample_si_metadata.code_page, 0x4E4) ae(sample_si_metadata.dictionary, None) ae(sample_si_metadata.locale, None) ae(sample_si_metadata.behavior, None) ae(sample_si_metadata.attr_exists, set(["code_page"])) ae(sample_dsi_metadata_0.code_page, 0x4E4) ae(sample_dsi_metadata_0.dictionary, None) ae(sample_dsi_metadata_0.locale, None) ae(sample_dsi_metadata_0.behavior, None) ae(sample_dsi_metadata_0.attr_exists, set(["code_page"])) ae(sample_dsi_metadata_1.code_page, 0x4E4) ae(sample_dsi_metadata_1.dictionary, { 2: "_PID_LINKBASE", 3: "_PID_HLINKS", 4: "text_name", 5: "date_name", 6: "number_name_0", 7: "number_name_1", 8: "number_name_2", 9: "number_name_3", 0xA: "number_name_4", 0xB: "number_name_5", 0xC: "number_name_6", 0xD: "number_name_7", 0xE: "yes_name_yes", 0xF: "yes_name_no", 0x10: "link_to_bookmark_name1", 0x11: "link_to_bookmark_name2", 0x12: "link_to__1326562448" } ) ae(sample_dsi_metadata_1.locale, None) ae(sample_dsi_metadata_1.behavior, None) ae(sample_dsi_metadata_1.attr_exists, set(["dictionary", "code_page"]))
def test_from_properties(self): ae = self.assertEqual blair_path = os.path.join("data", "doc", "blair.doc") sample_path = os.path.join("data", "doc", "sample.doc") blair_cfb = CompoundFile(RawIStream(blair_path)) sample_cfb = CompoundFile(RawIStream(sample_path)) blair_si = Builder.build(blair_cfb.get_stream(3)) blair_dsi = Builder.build(blair_cfb.get_stream(4)) sample_si = Builder.build(sample_cfb.get_stream(39)) sample_dsi = Builder.build(sample_cfb.get_stream(40)) blair_si_metadata = PropertiesMetadata.from_properties( blair_si.property_set_0.properties) blair_dsi_metadata_0 = PropertiesMetadata.from_properties( blair_dsi.property_set_0.properties) blair_dsi_metadata_1 = PropertiesMetadata.from_properties( blair_dsi.property_set_1.properties) sample_si_metadata = PropertiesMetadata.from_properties( sample_si.property_set_0.properties) sample_dsi_metadata_0 = PropertiesMetadata.from_properties( sample_dsi.property_set_0.properties) sample_dsi_metadata_1 = PropertiesMetadata.from_properties( sample_dsi.property_set_1.properties) ae(blair_si_metadata.code_page, 0x4E4) ae(blair_si_metadata.dictionary, None) ae(blair_si_metadata.locale, None) ae(blair_si_metadata.behavior, None) ae(blair_si_metadata.attr_exists, set(["code_page"])) ae(blair_dsi_metadata_0.code_page, 0x4E4) ae(blair_dsi_metadata_0.dictionary, None) ae(blair_dsi_metadata_0.locale, None) ae(blair_dsi_metadata_0.behavior, None) ae(blair_dsi_metadata_0.attr_exists, set(["code_page"])) ae(blair_dsi_metadata_1.code_page, 0x4E4) ae(blair_dsi_metadata_1.dictionary, {2: "_PID_GUID"}) ae(blair_dsi_metadata_1.locale, None) ae(blair_dsi_metadata_1.behavior, None) ae(blair_dsi_metadata_1.attr_exists, set(["dictionary", "code_page"])) ae(sample_si_metadata.code_page, 0x4E4) ae(sample_si_metadata.dictionary, None) ae(sample_si_metadata.locale, None) ae(sample_si_metadata.behavior, None) ae(sample_si_metadata.attr_exists, set(["code_page"])) ae(sample_dsi_metadata_0.code_page, 0x4E4) ae(sample_dsi_metadata_0.dictionary, None) ae(sample_dsi_metadata_0.locale, None) ae(sample_dsi_metadata_0.behavior, None) ae(sample_dsi_metadata_0.attr_exists, set(["code_page"])) ae(sample_dsi_metadata_1.code_page, 0x4E4) ae( sample_dsi_metadata_1.dictionary, { 2: "_PID_LINKBASE", 3: "_PID_HLINKS", 4: "text_name", 5: "date_name", 6: "number_name_0", 7: "number_name_1", 8: "number_name_2", 9: "number_name_3", 0xA: "number_name_4", 0xB: "number_name_5", 0xC: "number_name_6", 0xD: "number_name_7", 0xE: "yes_name_yes", 0xF: "yes_name_no", 0x10: "link_to_bookmark_name1", 0x11: "link_to_bookmark_name2", 0x12: "link_to__1326562448" }) ae(sample_dsi_metadata_1.locale, None) ae(sample_dsi_metadata_1.behavior, None) ae(sample_dsi_metadata_1.attr_exists, set(["dictionary", "code_page"]))