Skip to content

Commit

Permalink
Add partial support for encrypted lmpro archives
Browse files Browse the repository at this point in the history
- Archive extraction now supported
- lmpatch does not yet support inserting encrypted files into an
  archive, if the original file was encrypted and uncompressed, the
  patched file will be inserted as uncompressed and unencrypted, if the
  original file was encrypted and compressed, the patched file will be
  inserted as compressed and unencrypted
- Scrambled LM Pro GAL image conversion is not yet supported

See also: #3
  • Loading branch information
pmrowla committed Feb 12, 2020
1 parent 1e9df32 commit 084cf31
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 15 deletions.
20 changes: 12 additions & 8 deletions livemaker/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@
with the exception that archives cannot be modified in-place (i.e. mode ``'a'``
is unavailable).
Note:
Reading (and writing) files which are encrypted via LiveMaker Pro is not
supported, but any non-encrypted files from a LiveMaker Pro archive can
be extracted.
"""

import enum
Expand All @@ -45,6 +40,7 @@
import construct

from .exceptions import BadLiveMakerArchive, UnsupportedLiveMakerCompression
from .scramble import decrypt


log = logging.getLogger(__name__)
Expand All @@ -60,7 +56,9 @@ class LMCompressType(enum.IntEnum):

SUPPORTED_COMPRESSIONS = [
LMCompressType.NONE,
LMCompressType.ZLIB
LMCompressType.ZLIB,
LMCompressType.ENCRYPTED,
LMCompressType.ENCRYPTED_ZLIB,
]

# LM3 seed for TpRandom
Expand Down Expand Up @@ -722,8 +720,14 @@ def read(self, name, decompress=True, skip_checksum=True):
if info.checksum != LMArchiveDirectory.checksum(data):
log.warn('Bad checksum for file {}.'.format(info.name))
if decompress:
if info.compress_type == LMCompressType.ZLIB:
data = zlib.decompress(data)
if info.compress_type in (LMCompressType.ENCRYPTED, LMCompressType.ENCRYPTED_ZLIB):
data = decrypt(data)

if info.compress_type in (LMCompressType.ZLIB, LMCompressType.ENCRYPTED_ZLIB):
try:
data = zlib.decompress(data)
except zlib.error as e:
raise UnsupportedLiveMakerCompression(str(e))
return data

def read_exe(self):
Expand Down
13 changes: 10 additions & 3 deletions livemaker/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from . import GalImagePlugin

from .archive import LMArchive
from .exceptions import LiveMakerException, BadLsbError
from .exceptions import LiveMakerException, BadLsbError, UnsupportedLiveMakerCompression
from .lsb import LMScript
from .lsb.command import BaseComponentCommand, Calc, CommandType, Jump
from .lsb.core import OpeData, OpeDataType, OpeFuncType, Param, ParamType
Expand Down Expand Up @@ -86,7 +86,11 @@ def x(dry_run, image_format, output_dir, verbose, input_file):
for info in lm.infolist():
if str(info.path).lower().endswith('.gal'):
if not dry_run:
data = lm.read(info)
try:
data = lm.read(info)
except UnsupportedLiveMakerCompression as e:
print(' Error extracting {}: {}'.format(info.path, e))
continue
if image_format in ('gal', 'both'):
if not dry_run:
path = Path.joinpath(output_dir, info.path).expanduser().resolve()
Expand Down Expand Up @@ -115,7 +119,10 @@ def x(dry_run, image_format, output_dir, verbose, input_file):
print(info.path)
else:
if not dry_run:
lm.extract(info, output_dir)
try:
lm.extract(info, output_dir)
except UnsupportedLiveMakerCompression as e:
print(' Error extracting {}: {}'.format(info.path, e))
if verbose or dry_run:
print(info.path)

Expand Down
15 changes: 11 additions & 4 deletions livemaker/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

import click

from livemaker import LMArchive
from livemaker import LMArchive, LMCompressType
from livemaker.exceptions import LiveMakerException


Expand Down Expand Up @@ -116,9 +116,16 @@ def bar_show(item):
with click.progressbar(orig_lm.infolist(), item_show_func=bar_show) as bar:
for info in bar:
if info.path == lsb_path:
# replace existing with patch version, use original
# compress type
new_lm.write(lsb_path, compress_type=info.compress_type, unk1=info.unk1)
# replace existing with patch version
#
# TODO: support writing encrypted files
if info.compress_type == LMCompressType.ENCRYPTED:
compress_type = LMCompressType.NONE
elif info.compress_type == LMCompressType.ENCRYPTED_ZLIB:
compress_type = LMCompressType.ZLIB
else:
compress_type = info.compress_type
new_lm.write(lsb_path, compress_type=compress_type, unk1=info.unk1)
log.info('patched {}'.format(lsb_path))
# print('patched')
else:
Expand Down

0 comments on commit 084cf31

Please sign in to comment.