Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions hachoir-list
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env python3
from hachoir.listtool import main
main()
101 changes: 101 additions & 0 deletions hachoir/listtool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#
# Tool for parsing a file and writing all fields to stdout.
#

from hachoir.core.cmd_line import getHachoirOptions, configureHachoir
from hachoir.core.cmd_line import displayVersion
from hachoir.stream import InputStreamError, FileInputStream
from hachoir.parser import guessParser, HachoirParserList
from optparse import OptionGroup, OptionParser
import sys


def printFieldSet(field_set, args, options={}, indent=0):
indent_string = " " * indent
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add --indent command line option to configure the indentation size?

for field in field_set:
value_display = ""
if field.value is not None and options["display_value"]:
value_display = f": {field.display}"
size_display = ""
if options["display_size"]:
size_display = f", {field.size}b"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to format a number of bytes using B? Something like:

if size % 8 == 0:
   return "{size // 8}B"
else:
   return "{size}b"

print(f"{indent_string}{field.name} <{field.__class__.__name__}{size_display}> ({field.description}){value_display}")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to hide the description by default, and only show it if --descr (new) option is used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added --description; the on command line the option names can be shortened as long as they are unique.


if field.is_field_set:
printFieldSet(field, args, options, indent + 1)


def displayParserList(*args):
HachoirParserList().print_()
sys.exit(0)


def parseOptions():
parser = OptionParser(usage="%prog [options] filename [filenames...]")

common = OptionGroup(parser, "List Tool", "Options of list tool")
common.add_option("--parser", help="Use the specified parser (use its identifier)",
type="str", action="store", default=None)
common.add_option("--offset", help="Skip first bytes of input file",
type="long", action="store", default=0)
common.add_option("--parser-list", help="List all parsers then exit",
action="callback", callback=displayParserList)
common.add_option("--size", help="Maximum size of bytes of input file",
type="long", action="store", default=None)
common.add_option("--hide-value", dest="display_value", help="Don't display value",
action="store_false", default=True)
common.add_option("--hide-size", dest="display_size", help="Don't display size",
action="store_false", default=True)
common.add_option("--version", help="Display version and exit",
action="callback", callback=displayVersion)
parser.add_option_group(common)

hachoir = getHachoirOptions(parser)
parser.add_option_group(hachoir)

values, arguments = parser.parse_args()
if len(arguments) < 1:
parser.print_help()
sys.exit(1)
return values, arguments


def openParser(parser_id, filename, offset, size):
tags = []
if parser_id:
tags += [("id", parser_id), None]
try:
stream = FileInputStream(filename,
offset=offset, size=size, tags=tags)
except InputStreamError as err:
return None, "Unable to open file: %s" % err
parser = guessParser(stream)
if not parser:
return None, "Unable to parse file: %s" % filename
return parser, None


def main():
# Parse options and initialize Hachoir
values, filenames = parseOptions()
configureHachoir(values)

# Open file and create parser
for filename in filenames:
print(f"File: {filename}")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to omit the filename if there is a single filename?

parser, err = openParser(values.parser, filename,
values.offset, values.size)
if err:
print(err)
sys.exit(1)

# Explore file
with parser:
printFieldSet(parser, values, {
"display_size": values.display_size,
"display_value": values.display_value,
})
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is more than one file, it would be nice to have a newline at the end for readability.



if __name__ == "__main__":
main()
Loading