livemaker package

Submodules

livemaker.archive module

LiveMaker archive/exe file module.

The archive module makes it possible to read and write LiveMaker archives (and executables).

The API for archive behaves similary to Python’s zipfile module, with the exception that archives cannot be modified in-place (i.e. mode 'a' is unavailable).

class livemaker.archive.LMCompressType[source]

Bases: enum.IntEnum

An enumeration.

ZLIB = 0
NONE = 1
ENCRYPTED = 2
ENCRYPTED_ZLIB = 3
class livemaker.archive.LMObfuscator(seed=1977019961)[source]

Bases: object

Class for (de)obfuscating LiveMaker directory fields.

Note

RE’d from TTpRandom class in LiveMaker code.

transform_bytes(data)[source]
transform_int(data)[source]
transform_int_high(data)[source]
class livemaker.archive.LMArchiveDirectory[source]

Bases: object

Class for handling parsing and writing archive directories.

LiveMaker archive format is:

Directory Header:
    16-bit "vf" signature
    32-bit uint version
    32-bit uint count

Filenames (list with length <count> entries):
    32-bit uint prefixed pascal strings (CP932 (MS Shift-JIS) encoded)

Offsets (list with length <file_count> + 1):
    32-bit uint offset_low
    32-bit uint offset_high

Compression flags (list with length <file_count>)
    8-bit uint compression method

Unknown list (list length <file_count>)
    32-bit uint unk1

Checksums - (list length <file_count>)
    32-bit uint checksum

Encryption flags 0 if not encrypted (list length <file_count>)
    8-bit uint encrypt_flag

File data
    ...

Note

LiveMaker3 mangles filenames and offsets by XOR’ing them with a fixed keystream. Individual files may also be encrypted/obfuscated, this is specified by the compression flags.

Offsets are actually 64-bit long long, but they are stored as two separate 32-bit integers.

The extra offset entry is used to calculate the (compressed) size of the final file.

If encrypt_flag is zero, checksum is the checksum of the compressed file data.
If encrypt_flag is nonzero checksum is the checksum of the uncompressed and decrypted file data.

RE’d from TVrFileCollection classes in LiveMaker code.

classmethod struct()[source]
classmethod make_offset(obj)[source]

Join split offset into one 64-bit unsigned offset.

classmethod split_offset(offset)[source]

Split an offset into the expected components for writing to an archive.

classmethod directory_size(version, filenames=[])[source]

Return the size of a directory containing filenames.

classmethod checksum(data)[source]

Compute a VF archive checksum for the specified data.

RE’d from TVrFile.ChecksumStream().

Parameters:data (bytes) – The data to checksum
class livemaker.archive.LMArchive(name=None, mode='r', fp=None, exe=None, split=False, version=102)[source]

Bases: object

Provide interface to a LiveMaker archive (or exe).

Behaves in the same manner as Python tarfile.TarFile or zipfile.ZipFile. Can be used inside a Python with statement (in the same way as zip/tar files).

Parameters:
  • name – Pathname for the archive. name can be a string or path-like object. If omitted, fp must be specified.
  • mode – Either 'r' to read from an existing archive or 'w' to create a new file (overwriting an existing one). Defaults to 'r'.
  • fp – If fileobj is given, it will be used for reading and writing data. If it can be determined, mode will be overridden by fp’s mode. fileobj will be used from position 0.
  • exe – Pathname for LiveMaker executable (.exe) file. If exe is given and mode is w, the output file will be an executable with the archive appended to the end (i.e. a LiveMaker .exe file). If exe is not given, the output file will be a standalone archive (i.e. a LiveMaker .dat file). exe does nothing when opening a file for reading.
  • split – If opening in write mode and split is True, the archive data will be split into smaller files across 1GB boundaries. split has no effect in read mode or when writing an executable archive.
  • version – Archive version, only applies to write mode.

Note

fp is not closed when LiveMakerArchive is closed.

'a' is an invalid mode for LiveMakerArchive. Archives cannot be modified in place, to patch an existing archive, you must write to a new file.

When opened in write mode, the output archive file will not be written until LMArchive.close() is called. As entries are added to the archive, they will be written to a temporary file. Upon calling close(), the exe (if it exists) and archive header will be written to the output file, then the temporary file will be copied to the end of the output file.

close()[source]

Close the archive file.

When an archive is opened in write mode, close() must be called before exiting your program or else the archive will not actually be written.

namelist()[source]

Return a list of archive entries by name.

infolist()[source]

Return a containing a LMArchiveInfo object for each entry in the archive.

getinfo(name)[source]

Return a LMArchiveInfo object for the entry with the specified name.

Raises:KeyError – If name is not an entry in the archive.
list()[source]

Print a list of archive entries to stdout.

extract(name, path=None)[source]

Extract the specified entry from the archive to the current working directory.

Parameters:
  • name (str, LMArchiveInfo) – The entry to extract, can be either it’s full name or a LMArchiveInfo object.
  • path – If given, the path will be used instead of the current working directory.
Raises:

UnsupportedLiveMakerCompression – If the specified entry uses an unsupported compression method.

extractall(path=None, entries=None, allow_unsupported=False)[source]

Extract all entries in this archive to the current working directory.

Parameters:
  • path – If path is given, it will be used instead of the current working directory.
  • entries – Optional value that must be a subset of the list returned by namelist() or infolist().
  • allow_unsupported – If True, any files which are compressed with an unsupported method will be silently ignored. If False, an exception will be raised when trying to extract any files which use unsupported compression methods.
Raises:

UnsupportedLiveMakerCompression

read(name, decompress=True, skip_checksum=True)[source]

Return the bytes of the specified file in the archive.

The archive must be open for reading.

Parameters:
  • name – Either the name of a file in the archive or a LMArchiveInfo object.
  • decompress – If True the returned bytes will be decompressed. If False the original compressed entry data will be returned.
  • skip_checksum – If True the file checksum will not be verified. If False the checksum will be verified. If the checksum does not match, the file will still be extracted, but a warning will be logged.
Raises:

UnsupportedLiveMakerCompression – If decompress is True and the specified entry uses an unsupported compression method.

read_exe()[source]

Return the exe bytes for this archive.

Raises:ValueError – If this archive is not part of a LiveMaker executable (i.e. it is a .dat file).
write(filename, arcname=None, compress_type=None, unk1=None)[source]

Write the file named filename into the archive.

Parameters:
  • filename – File to write into archive.
  • arcname – If given, the archive file entry will be named arcname. By default, arcname will be the same as filename, but with any drive letter and leading path separators removed. Posix paths will be replaced with equivalent Windows paths.
  • compress_type (LMCompressType) – If given, the file will be compressed with the specified method (defaults to uncompressed for files < 5MB in size, and zlib compressed for files >= 5MB).
Returns:

The number of (compressed) bytes written.

Raises:
  • FileExistsError – If an entry matching arcname already exists in this archive.
  • UnsupportedLiveMakerCompression – If the compress_type is unsupported.
writebytes(arcname, data, compress_type=None, skip_checksum=True)[source]

Write a raw (already compressed) file into the archive.

This method can be used to copy compressed data from an old archive into a new one without needing to do any intermediate extraction. This may be useful for copying encrypted files from one archive into another.

Parameters:
  • arcname – The archive entry name (or LMArchiveInfo object).
  • data (bytes) – The contents of arcname. data must be a bytes instance, not a str instance. data must be compressed using the compression type specified in compress_type or the arcname LMArchiveInfo object.
  • compress_type – The compression type for the newly created archive entry will be set to this value. If arcname is a string, compress_type must be explicitly set. compress_type can be omitted if arcname is an LMArchiveInfo object, in which case compression type will be read from the info object.
  • skip_checksum – If True and arcname is a LMArchiveInfo object, checksum for data will not be calculated, and will be copied from arcname.
Returns:

The number of bytes written.

Raises:

FileExistsError – If an entry matching arcname already exists in this archive.

class livemaker.archive.LMArchiveInfo(name='')[source]

Bases: object

An entry (file) contained in a LiveMaker archive.

name

Filename.

Type:str
compress_type

Compression type.

Type:LMCompressType
compressed_size

Compressed file size in bytes.

Type:int
checksum

VF checksum for the compressed data. See LMArchiveDirectory.checksum() for how checksum is calculated.

encrypt_flag

Only used for LiveMaker Pro encrypted files.

path

livemaker.exceptions module

pylivemaker exceptions.

exception livemaker.exceptions.LiveMakerException[source]

Bases: Exception

Base pylivemaker exception.

exception livemaker.exceptions.BadLiveMakerArchive[source]

Bases: livemaker.exceptions.LiveMakerException

Error raised for bad/invalid archive files.

exception livemaker.exceptions.UnsupportedLiveMakerVersion[source]

Bases: livemaker.exceptions.LiveMakerException

exception livemaker.exceptions.UnsupportedLiveMakerCompression[source]

Bases: livemaker.exceptions.LiveMakerException

exception livemaker.exceptions.BadLsbError[source]

Bases: livemaker.exceptions.LiveMakerException

Error raised for bad/invalid LSB script files.

exception livemaker.exceptions.BadLpbError[source]

Bases: livemaker.exceptions.LiveMakerException

Error raised for bad/invalid LPB project settings files.

exception livemaker.exceptions.BadLnsError[source]

Bases: livemaker.exceptions.LiveMakerException

Error raised for bad/invalid LNS novel scripts.

exception livemaker.exceptions.InvalidCharError(ch, encoding='cp932')[source]

Bases: livemaker.exceptions.BadLnsError

exception livemaker.exceptions.BadTextIdentifierError[source]

Bases: livemaker.exceptions.LiveMakerException

Error raised for bad/invalid translatable text IDs.

livemaker.lpb module

LiveMaker project settings file (LPB) module.

class livemaker.lpb.LMProject(version=117, project_name='', unk1=0, unk2=0, init_lsb='', exit_lsb='', project_dir='', unk3=0, bool1=0, bool2=0, audio_formats='.wav.wma.ogg.mid.mp3', bool3=0, bool4=0, bool5=1, insert_disk_prompt='', exit_prompt='', system_settings=[], **kwargs)[source]

Bases: object

Class for handling project settings files.

RE’d from TProject, TProjectSettings classes in LiveMaker code.

keys()[source]
items()[source]
lm_version
classmethod from_struct(struct, **kwargs)[source]

Create an LMProject from the specified struct.

classmethod from_file(infile)[source]

Parse the specified file into an LMProject.

Parameters:infile – Input .lpb file. Can be string, path-like or file-like object.
to_lpb()[source]

Compile settings into binary .lpb format.

livemaker.lpm module

LiveMaker preview menu file (LPM) module.

exception livemaker.lpm.BadLPMError[source]

Bases: livemaker.exceptions.LiveMakerException

class livemaker.lpm.LPMVersionValidator(subcon)[source]

Bases: construct.core.Validator

class livemaker.lpm.LMLivePrevMenu(version=106, unk1=0, buttons=[], **kwargs)[source]

Bases: object

Class for handling preview menu files.

RE’d from TLivePrevMenu, TLivePrevImages classes in LiveMaker code.

keys()[source]
items()[source]
classmethod from_struct(struct, **kwargs)[source]

Create an LMProject from the specified struct.

classmethod from_file(infile)[source]

Parse the specified file into an LMLivePrevMenu.

Parameters:infile – Input .lpm file. Can be string, path-like or file-like object.
to_lpm()[source]

Compile settings into binary .lpm format.

livemaker.project module

pylivemaker project management module.

class livemaker.project.PylmProject(path)[source]

Bases: object

static find_root(path)[source]

Return root LM project dir for the specified path.

call_name(path)[source]
update_labels(lsb)[source]

Update labels from the specified lsb.

resolve_label(ref)[source]

Return tuple(line_no, name) for the specified label reference.

livemaker.scramble module

LiveMaker scramble (encryption) module.

class livemaker.scramble.LMScramble(seed=0)[source]

Bases: object

PRNG used for LM TScramble encryption.

RE’d from TScrambleInts, TGetRandom classes in LM3 code.

FACTORS = (2111111111, 1492, 1776, 5115)
rand()[source]

Return a random integer in the range [0, uint32_max).

random()[source]

Return a random float in the range [0.0, 1.0).

randint(low, high)[source]

Return a random integer in the range [low, high].

classmethod randseq(count, seed)[source]

Generate a random sequence of the specified length.

livemaker.scramble.decrypt(data)[source]

Unscramble the specified data stream and return the result.

Module contents

Top-level package for pylivemaker.

class livemaker.LMArchive(name=None, mode='r', fp=None, exe=None, split=False, version=102)[source]

Bases: object

Provide interface to a LiveMaker archive (or exe).

Behaves in the same manner as Python tarfile.TarFile or zipfile.ZipFile. Can be used inside a Python with statement (in the same way as zip/tar files).

Parameters:
  • name – Pathname for the archive. name can be a string or path-like object. If omitted, fp must be specified.
  • mode – Either 'r' to read from an existing archive or 'w' to create a new file (overwriting an existing one). Defaults to 'r'.
  • fp – If fileobj is given, it will be used for reading and writing data. If it can be determined, mode will be overridden by fp’s mode. fileobj will be used from position 0.
  • exe – Pathname for LiveMaker executable (.exe) file. If exe is given and mode is w, the output file will be an executable with the archive appended to the end (i.e. a LiveMaker .exe file). If exe is not given, the output file will be a standalone archive (i.e. a LiveMaker .dat file). exe does nothing when opening a file for reading.
  • split – If opening in write mode and split is True, the archive data will be split into smaller files across 1GB boundaries. split has no effect in read mode or when writing an executable archive.
  • version – Archive version, only applies to write mode.

Note

fp is not closed when LiveMakerArchive is closed.

'a' is an invalid mode for LiveMakerArchive. Archives cannot be modified in place, to patch an existing archive, you must write to a new file.

When opened in write mode, the output archive file will not be written until LMArchive.close() is called. As entries are added to the archive, they will be written to a temporary file. Upon calling close(), the exe (if it exists) and archive header will be written to the output file, then the temporary file will be copied to the end of the output file.

close()[source]

Close the archive file.

When an archive is opened in write mode, close() must be called before exiting your program or else the archive will not actually be written.

namelist()[source]

Return a list of archive entries by name.

infolist()[source]

Return a containing a LMArchiveInfo object for each entry in the archive.

getinfo(name)[source]

Return a LMArchiveInfo object for the entry with the specified name.

Raises:KeyError – If name is not an entry in the archive.
list()[source]

Print a list of archive entries to stdout.

extract(name, path=None)[source]

Extract the specified entry from the archive to the current working directory.

Parameters:
  • name (str, LMArchiveInfo) – The entry to extract, can be either it’s full name or a LMArchiveInfo object.
  • path – If given, the path will be used instead of the current working directory.
Raises:

UnsupportedLiveMakerCompression – If the specified entry uses an unsupported compression method.

extractall(path=None, entries=None, allow_unsupported=False)[source]

Extract all entries in this archive to the current working directory.

Parameters:
  • path – If path is given, it will be used instead of the current working directory.
  • entries – Optional value that must be a subset of the list returned by namelist() or infolist().
  • allow_unsupported – If True, any files which are compressed with an unsupported method will be silently ignored. If False, an exception will be raised when trying to extract any files which use unsupported compression methods.
Raises:

UnsupportedLiveMakerCompression

read(name, decompress=True, skip_checksum=True)[source]

Return the bytes of the specified file in the archive.

The archive must be open for reading.

Parameters:
  • name – Either the name of a file in the archive or a LMArchiveInfo object.
  • decompress – If True the returned bytes will be decompressed. If False the original compressed entry data will be returned.
  • skip_checksum – If True the file checksum will not be verified. If False the checksum will be verified. If the checksum does not match, the file will still be extracted, but a warning will be logged.
Raises:

UnsupportedLiveMakerCompression – If decompress is True and the specified entry uses an unsupported compression method.

read_exe()[source]

Return the exe bytes for this archive.

Raises:ValueError – If this archive is not part of a LiveMaker executable (i.e. it is a .dat file).
write(filename, arcname=None, compress_type=None, unk1=None)[source]

Write the file named filename into the archive.

Parameters:
  • filename – File to write into archive.
  • arcname – If given, the archive file entry will be named arcname. By default, arcname will be the same as filename, but with any drive letter and leading path separators removed. Posix paths will be replaced with equivalent Windows paths.
  • compress_type (LMCompressType) – If given, the file will be compressed with the specified method (defaults to uncompressed for files < 5MB in size, and zlib compressed for files >= 5MB).
Returns:

The number of (compressed) bytes written.

Raises:
  • FileExistsError – If an entry matching arcname already exists in this archive.
  • UnsupportedLiveMakerCompression – If the compress_type is unsupported.
writebytes(arcname, data, compress_type=None, skip_checksum=True)[source]

Write a raw (already compressed) file into the archive.

This method can be used to copy compressed data from an old archive into a new one without needing to do any intermediate extraction. This may be useful for copying encrypted files from one archive into another.

Parameters:
  • arcname – The archive entry name (or LMArchiveInfo object).
  • data (bytes) – The contents of arcname. data must be a bytes instance, not a str instance. data must be compressed using the compression type specified in compress_type or the arcname LMArchiveInfo object.
  • compress_type – The compression type for the newly created archive entry will be set to this value. If arcname is a string, compress_type must be explicitly set. compress_type can be omitted if arcname is an LMArchiveInfo object, in which case compression type will be read from the info object.
  • skip_checksum – If True and arcname is a LMArchiveInfo object, checksum for data will not be calculated, and will be copied from arcname.
Returns:

The number of bytes written.

Raises:

FileExistsError – If an entry matching arcname already exists in this archive.

class livemaker.LMArchiveInfo(name='')[source]

Bases: object

An entry (file) contained in a LiveMaker archive.

name

Filename.

Type:str
compress_type

Compression type.

Type:LMCompressType
compressed_size

Compressed file size in bytes.

Type:int
checksum

VF checksum for the compressed data. See LMArchiveDirectory.checksum() for how checksum is calculated.

encrypt_flag

Only used for LiveMaker Pro encrypted files.

path
class livemaker.LMCompressType[source]

Bases: enum.IntEnum

An enumeration.

ZLIB = 0
NONE = 1
ENCRYPTED = 2
ENCRYPTED_ZLIB = 3
class livemaker.LMScript(version=117, param_type=1, flags=0, call_name='', novel_params=[], command_params=[[]], commands=[], **kwargs)[source]

Bases: livemaker.lsb.core.BaseSerializable

LiveMaker script class.

A LiveMaker script is a collection of LiveMaker novel commands. One LiveMaker/LiveNovel “Chart” will be serialized as one script file.

Parameters:
  • version (int) – Version number. If version is not in the range [MIN_LSB_VERSION, MAX_LSB_VERSION], this LMScript cannot be compiled into a binary LSB.
  • param_type – Unknown type flag (always 1?).
  • flags (int) – Unknown (always 0?).
  • call_name (str) – String name for calling this script (only used for documentation).
  • novel_params (iterable) – Iterable containing string descriptions for parameters that this script accepts (only used for documentation).
  • command_params (iterable(iterable(bool))) – Two dimensional array of booleans specifying the command parameters are for Component type commands. (i.e. command_params[CommandType.BoxNew][PropertyType.PR_NAME] == True means that BoxNew takes a PR_NAME parameter.)
  • commands (iterable) – Iterable containing this script’s Command objects.
Raises:

BadLsbError – If the specified LMScript would be invalid or unsupported.

commands
keys()[source]
items()[source]
command_count

Return the number of command types supported by this script.

param_stream_size

Return the length of this script’s param flag bytestream.

lm_version

Return LiveMaker app version based on an LSB version.

to_lsc()[source]

Return this script in the tex .lsc format.

classmethod from_lsc(s)[source]

Create an LMScript from the specified string.

Parameters:s – String containing text .lsc format data.
Raises:BadLsbError if the string could not be parsed.

Note

Currently only supports reading version information.

classmethod from_struct(struct, **kwargs)[source]

Create an LMScript from the specified struct.

to_lsb()[source]

Compile this script into binary .lsb format.

to_xml()[source]

Return this script as an .lsc format XML etree.Element.

classmethod from_xml(root, **kwargs)[source]

Create an LMScript from the specified XML element.

Parameters:root – The root tree element.
Raises:BadLsbError – If the XML tree could not be parsed.

Note

Currently only supports reading header information.

classmethod from_file(infile, **kwargs)[source]

Parse the specified file into an LMScript.

Parameters:infile – Input .lsc or .lsb file. Can be a string, path-like, or file-like object.
Raises:BadLsbError – If the input file could not be parsed.
classmethod from_lsb(data, **kwargs)[source]

Parse the specified compiled .lsb data into an LMScript.

Parameters:data – Input .lsb data.
Raises:BadLsbError – If the input data could not be parsed.
get_command(line_no)[source]

Get specified command by line number.

Returns:tuple(cmd_index, cmd)
Raises:KeyError – the specified line_no does not exist in this LSB.
walk(start=0, unreachable=False)[source]

Iterate over LSB commands in approximate execution order.

All conditional branches will be followed (positive condition will be evaluated first), but external jumps and calls will not be followed.

Parameters:
  • start (int) – Command index to start from.
  • unreachable (bool) – If True, unreachable commands will be included.
Yields:

3-tuple in the form (index, command, last_calc)

text_scenarios(run_order=True)[source]

Return a list of LiveNovel text scenarios contained in this script.

Parameters:run_order (bool) – If True, scenarios will be returned in approximately the order they would be run in-game (via walk(). If False, text blocks will be returned in the order they occur in the LSB file.
Returns:(line_num, name, scenario)
Return type:tuple(int, str, TpWord)
get_text_blocks(run_order=False)[source]

Return LiveNovel scenario text blocks contained in this script.

Parameters:run_order (bool) – If True, text blocks will be returned in approximately the order they would be run in-game (via walk(). If False, text blocks will be returned in the order they occur in the LSB file.
Returns:list of (identifier, block) tuples
replace_text(text_objects)[source]

Replace the specified translatable text objects in this LSB.

Parameters:text_objects – Iterable containing (identifier, text) tuples
replace_text_blocks(text_objects)[source]

Replace the specified LiveNovel scenario text blocks in this LSB.

Parameters:text_objects – Iterable containing (identifier, text) tuples
get_menus(run_order=True)[source]

Return a list of LiveNovel text selection menus contained in this script.

Parameters:run_order (bool) – If True, menus will be returned in approximately the order they would be run in-game (via walk(). If False, text blocks will be returned in the order they occur in the LSB file.
Returns:(line_num, menu)
Return type:tuple(int, BaseSelectionMenu)
get_menu_choices(run_order=True)[source]

Return selection menu choices contained in this script.

Parameters:run_order (bool) – If True, menus will be returned in approximately the order they would be run in-game (via walk(). If False, menus will be returned in the order they occur in the LSB file.
Returns:list of (identifier, choice) tuples
replace_menu_choices(text_objects)[source]

Replace the specified text selection menu choices in this LSB.

Parameters:text_objects – Iterable containing (identifier, text) tuples
class livemaker.LNSCompiler[source]

Bases: _markupbase.ParserBase

Attempt to compile a LiveNovel LNS script into a TpWord block.

Based on Python3 html.parser.HTMLParser.

Note

This is only intended to be used to compile scripts which have been decompiled by pylivemaker and then translated/edited for patching. Attempting to compile a script which was not initially generated by pylivemaker may not work as intended.

END_TAGS = ('a', 'style', 'div')
reset()[source]

Reset this instance. Loses all unprocessed data.

compile(script)[source]

Compile a [decompiled] script into a TpWord block.

Parameters:script (str) – Script data
feed(data)[source]

Feed data to the parser. Call this as often as you want, with as little or as much text as you want (may include ‘n’).

close()[source]

Handle any buffered data.

get_starttag_text()[source]

Return full source of start tag: ‘<…>’.

goahead(end)[source]
parse_starttag(i)[source]
check_for_whole_start_tag(i)[source]
parse_endtag(i)[source]
handle_eventtag(tag, attrs)[source]
handle_startendtag(tag, attrs)[source]
handle_starttag(tag, attrs)[source]
handle_endtag(tag)[source]
handle_data(data)[source]
unescape(s)[source]
class livemaker.LNSDecompiler(sep='n', include_comments=True, text_only=False)[source]

Bases: object

Attempt to decompile a TpWord text block into something that resembles LiveMaker’s LiveNovel scenario script format.

Parameters:
  • sep (str) – Output line separator (defaults to os.linesep).
  • include_comments (bool) – Include comment lines in output.
  • text_only (bool) – Output text only (all tags will be removed except for variable names).
Raises:

ValueError – If tpword is not a TpWord instance.

decompile(tpword)[source]

Decompile the specified TpWord scenario script.

Parameters:tpword (TpWord) – TpWord object to decompile.