sage/py3/lib/python3.10/site-packages/mobi/mobi_sectioner.py

155 lines
5.8 KiB
Python

#!/usr/bin/env python
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
import datetime
from loguru import logger
from .compatibility_utils import PY2, bchar, bord, bstr, hexlify
if PY2:
range = xrange
# note: struct pack, unpack, unpack_from all require bytestring format
# data all the way up to at least python 2.7.5, python 3 okay with bytestring
import struct
from .unipath import pathof
DUMP = False
""" Set to True to dump all possible information. """
class unpackException(Exception):
pass
def describe(data):
txtans = ""
hexans = hexlify(data)
for i in data:
if bord(i) < 32 or bord(i) > 127:
txtans += "?"
else:
txtans += bchar(i).decode("latin-1")
return '"' + txtans + '"' + " 0x" + hexans
def datetimefrompalmtime(palmtime):
if palmtime > 0x7FFFFFFF:
pythondatetime = datetime.datetime(year=1904, month=1, day=1) + datetime.timedelta(seconds=palmtime)
else:
pythondatetime = datetime.datetime(year=1970, month=1, day=1) + datetime.timedelta(seconds=palmtime)
return pythondatetime
class Sectionizer:
def __init__(self, filename):
self.data = b""
with open(pathof(filename), "rb") as f:
self.data = f.read()
self.palmheader = self.data[:78]
self.palmname = self.data[:32]
self.ident = self.palmheader[0x3C : 0x3C + 8]
(self.num_sections,) = struct.unpack_from(b">H", self.palmheader, 76)
self.filelength = len(self.data)
sectionsdata = struct.unpack_from(bstr(">%dL" % (self.num_sections * 2)), self.data, 78) + (self.filelength, 0)
self.sectionoffsets = sectionsdata[::2]
self.sectionattributes = sectionsdata[1::2]
self.sectiondescriptions = ["" for x in range(self.num_sections + 1)]
self.sectiondescriptions[-1] = "File Length Only"
return
def dumpsectionsinfo(self):
logger.debug("Section Offset Length UID Attribs Description")
for i in range(self.num_sections):
logger.debug(
"%3d %3X 0x%07X 0x%05X % 8d % 7d %s"
% (
i,
i,
self.sectionoffsets[i],
self.sectionoffsets[i + 1] - self.sectionoffsets[i],
self.sectionattributes[i] & 0xFFFFFF,
(self.sectionattributes[i] >> 24) & 0xFF,
self.sectiondescriptions[i],
)
)
logger.debug(
"%3d %3X 0x%07X %s"
% (
self.num_sections,
self.num_sections,
self.sectionoffsets[self.num_sections],
self.sectiondescriptions[self.num_sections],
)
)
def setsectiondescription(self, section, description):
if section < len(self.sectiondescriptions):
self.sectiondescriptions[section] = description
else:
logger.debug("Section out of range: %d, description %s" % (section, description))
def dumppalmheader(self):
logger.debug("Palm Database Header")
logger.debug("Database name: " + repr(self.palmheader[:32]))
(dbattributes,) = struct.unpack_from(b">H", self.palmheader, 32)
logger.debug(
"Bitfield attributes: 0x%0X" % dbattributes,
)
if dbattributes != 0:
print(
" (",
)
if dbattributes & 2:
print(
"Read-only; ",
)
if dbattributes & 4:
print(
"Dirty AppInfoArea; ",
)
if dbattributes & 8:
print(
"Needs to be backed up; ",
)
if dbattributes & 16:
print(
"OK to install over newer; ",
)
if dbattributes & 32:
print(
"Reset after installation; ",
)
if dbattributes & 64:
print(
"No copying by PalmPilot beaming; ",
)
print(")")
else:
print("")
logger.debug("File version: %d" % struct.unpack_from(b">H", self.palmheader, 34)[0])
(dbcreation,) = struct.unpack_from(b">L", self.palmheader, 36)
logger.debug("Creation Date: " + str(datetimefrompalmtime(dbcreation)) + (" (0x%0X)" % dbcreation))
(dbmodification,) = struct.unpack_from(b">L", self.palmheader, 40)
logger.debug("Modification Date: " + str(datetimefrompalmtime(dbmodification)) + (" (0x%0X)" % dbmodification))
(dbbackup,) = struct.unpack_from(b">L", self.palmheader, 44)
if dbbackup != 0:
logger.debug("Backup Date: " + str(datetimefrompalmtime(dbbackup)) + (" (0x%0X)" % dbbackup))
logger.debug("Modification No.: %d" % struct.unpack_from(b">L", self.palmheader, 48)[0])
logger.debug("App Info offset: 0x%0X" % struct.unpack_from(b">L", self.palmheader, 52)[0])
logger.debug("Sort Info offset: 0x%0X" % struct.unpack_from(b">L", self.palmheader, 56)[0])
logger.debug("Type/Creator: %s/%s" % (repr(self.palmheader[60:64]), repr(self.palmheader[64:68])))
logger.debug("Unique seed: 0x%0X" % struct.unpack_from(b">L", self.palmheader, 68)[0])
(expectedzero,) = struct.unpack_from(b">L", self.palmheader, 72)
if expectedzero != 0:
logger.debug("Should be zero but isn't: %d" % struct.unpack_from(b">L", self.palmheader, 72)[0])
logger.debug("Number of sections: %d" % struct.unpack_from(b">H", self.palmheader, 76)[0])
return
def loadSection(self, section):
before, after = self.sectionoffsets[section : section + 2]
return self.data[before:after]