kindle manager

This commit is contained in:
gavin
2021-08-25 17:58:31 +08:00
parent 5f0c0a9724
commit 6b3c0f3b6b
303 changed files with 87829 additions and 42537 deletions

204
mobimaster/mobi/mobi_sectioner.py Executable file
View File

@@ -0,0 +1,204 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
from __future__ import unicode_literals, division, absolute_import, print_function
from .compatibility_utils import PY2, hexlify, bstr, bord, bchar
from loguru import logger
import datetime
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]
# CG struct.unpack_from(fmt, buffer, offset=0)
(self.num_sections,) = struct.unpack_from(b">H", self.palmheader, 76)
self.filelength = len(self.data)
## CGDBG ???
## sectionsdata (9680, 0, 18618, 2, 22275, 4, 25504, 6, 28607, 8,...
sectionsdata = struct.unpack_from( bstr(">%dL" % (self.num_sections * 2)), self.data, 78
) + (self.filelength, 0)
## 所有section的offset和长度
# sectionsoffset (9680, 18618, 22275, 25504, 28607, ...
self.sectionoffsets = sectionsdata[::2]
# ectionattributes (0, 2, 4, 6, 8, ...
self.sectionattributes = sectionsdata[1::2]
self.sectiondescriptions = ["" for x in range(self.num_sections + 1)]
self.sectiondescriptions[-1] = "File Length Only"
# CGDBG upack_from 返回什么tuple (,)
print( 'sectionsdata {} {}'.format(sectionsdata, bstr(">%dL" % (self.num_sections * 2))))
print( 'sectionsoffset {} \n sectionattributes {}'.format( self.sectionoffsets, self.sectionattributes ))
print( 'sectionsdescriptions {} '.format( self.sectiondescriptions))
print( bstr(">%dL" % (self.num_sections * 2) ) )
print( struct.unpack_from(bstr(">%dL" % (self.num_sections * 2)) , self.data, 78) )
print( (self.filelength, 0) )
return
# sections information
def dumpsectionsinfo(self):
logger.debug("Section Offset Length UID Attribs Description")
for i in range(self.num_sections):
'''
logger.debug(
"{} {} {} {} {} {} {}\n".format( 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 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]