2020-09-27 12:54:49 +02:00
|
|
|
#!/usr/bin/env python3
|
2013-10-02 20:59:40 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
# Mobipocket PID calculator v0.4 for Amazon Kindle.
|
|
|
|
# Copyright (c) 2007, 2009 Igor Skochinsky <skochinsky@mail.ru>
|
|
|
|
# History:
|
|
|
|
# 0.1 Initial release
|
|
|
|
# 0.2 Added support for generating PID for iPhone (thanks to mbp)
|
|
|
|
# 0.3 changed to autoflush stdout, fixed return code usage
|
|
|
|
# 0.3 updated for unicode
|
|
|
|
# 0.4 Added support for serial numbers starting with '9', fixed unicode bugs.
|
|
|
|
# 0.5 moved unicode_argv call inside main for Windows DeDRM compatibility
|
2020-09-27 12:54:49 +02:00
|
|
|
# 1.0 Python 3 for calibre 5.0
|
2013-10-02 20:59:40 +02:00
|
|
|
|
2020-10-14 17:23:49 +02:00
|
|
|
|
2013-10-02 20:59:40 +02:00
|
|
|
import sys
|
|
|
|
import binascii
|
|
|
|
|
2023-08-06 15:49:52 +02:00
|
|
|
#@@CALIBRE_COMPAT_CODE@@
|
2013-10-02 20:59:40 +02:00
|
|
|
|
2023-08-06 15:49:52 +02:00
|
|
|
from .utilities import SafeUnbuffered
|
2023-08-03 20:45:06 +02:00
|
|
|
from .argv_utils import unicode_argv
|
2013-10-02 20:59:40 +02:00
|
|
|
|
2023-08-03 20:45:06 +02:00
|
|
|
letters = b'ABCDEFGHIJKLMNPQRSTUVWXYZ123456789'
|
2013-10-02 20:59:40 +02:00
|
|
|
|
|
|
|
def crc32(s):
|
|
|
|
return (~binascii.crc32(s,-1))&0xFFFFFFFF
|
|
|
|
|
|
|
|
def checksumPid(s):
|
2023-08-03 20:45:06 +02:00
|
|
|
crc = crc32(s)
|
2013-10-02 20:59:40 +02:00
|
|
|
crc = crc ^ (crc >> 16)
|
|
|
|
res = s
|
|
|
|
l = len(letters)
|
|
|
|
for i in (0,1):
|
|
|
|
b = crc & 0xff
|
|
|
|
pos = (b // l) ^ (b % l)
|
2023-08-03 20:14:33 +02:00
|
|
|
res += bytes(bytearray([letters[pos%l]]))
|
2013-10-02 20:59:40 +02:00
|
|
|
crc >>= 8
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
def pidFromSerial(s, l):
|
|
|
|
crc = crc32(s)
|
|
|
|
|
|
|
|
arr1 = [0]*l
|
2020-09-26 22:22:47 +02:00
|
|
|
for i in range(len(s)):
|
2023-08-03 20:14:33 +02:00
|
|
|
if sys.version_info[0] == 2:
|
|
|
|
arr1[i%l] ^= ord(s[i])
|
|
|
|
else:
|
|
|
|
arr1[i%l] ^= s[i]
|
2013-10-02 20:59:40 +02:00
|
|
|
|
|
|
|
crc_bytes = [crc >> 24 & 0xff, crc >> 16 & 0xff, crc >> 8 & 0xff, crc & 0xff]
|
2020-09-26 22:22:47 +02:00
|
|
|
for i in range(l):
|
2013-10-02 20:59:40 +02:00
|
|
|
arr1[i] ^= crc_bytes[i&3]
|
|
|
|
|
2023-08-03 20:14:33 +02:00
|
|
|
pid = b""
|
2020-09-26 22:22:47 +02:00
|
|
|
for i in range(l):
|
2013-10-02 20:59:40 +02:00
|
|
|
b = arr1[i] & 0xff
|
2023-08-03 20:14:33 +02:00
|
|
|
pid+=bytes(bytearray([letters[(b >> 7) + ((b >> 5 & 3) ^ (b & 0x1f))]]))
|
2013-10-02 20:59:40 +02:00
|
|
|
|
|
|
|
return pid
|
|
|
|
|
|
|
|
def cli_main():
|
2020-09-27 12:54:49 +02:00
|
|
|
print("Mobipocket PID calculator for Amazon Kindle. Copyright © 2007, 2009 Igor Skochinsky")
|
2022-08-06 20:19:18 +02:00
|
|
|
argv=unicode_argv("kindlepid.py")
|
2013-10-02 20:59:40 +02:00
|
|
|
if len(argv)==2:
|
|
|
|
serial = argv[1]
|
|
|
|
else:
|
2020-09-27 12:54:49 +02:00
|
|
|
print("Usage: kindlepid.py <Kindle Serial Number>/<iPhone/iPod Touch UDID>")
|
2013-10-02 20:59:40 +02:00
|
|
|
return 1
|
|
|
|
if len(serial)==16:
|
|
|
|
if serial.startswith("B") or serial.startswith("9"):
|
2020-09-27 12:54:49 +02:00
|
|
|
print("Kindle serial number detected")
|
2013-10-02 20:59:40 +02:00
|
|
|
else:
|
2020-09-27 12:54:49 +02:00
|
|
|
print("Warning: unrecognized serial number. Please recheck input.")
|
2013-10-02 20:59:40 +02:00
|
|
|
return 1
|
|
|
|
pid = pidFromSerial(serial.encode("utf-8"),7)+'*'
|
2020-09-27 12:54:49 +02:00
|
|
|
print("Mobipocket PID for Kindle serial#{0} is {1}".format(serial,checksumPid(pid)))
|
2013-10-02 20:59:40 +02:00
|
|
|
return 0
|
|
|
|
elif len(serial)==40:
|
2020-09-27 12:54:49 +02:00
|
|
|
print("iPhone serial number (UDID) detected")
|
2013-10-02 20:59:40 +02:00
|
|
|
pid = pidFromSerial(serial.encode("utf-8"),8)
|
2020-09-27 12:54:49 +02:00
|
|
|
print("Mobipocket PID for iPhone serial#{0} is {1}".format(serial,checksumPid(pid)))
|
2013-10-02 20:59:40 +02:00
|
|
|
return 0
|
2020-09-27 12:54:49 +02:00
|
|
|
print("Warning: unrecognized serial number. Please recheck input.")
|
2013-10-02 20:59:40 +02:00
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2020-10-14 17:23:49 +02:00
|
|
|
sys.stdout=SafeUnbuffered(sys.stdout)
|
|
|
|
sys.stderr=SafeUnbuffered(sys.stderr)
|
2013-10-02 20:59:40 +02:00
|
|
|
sys.exit(cli_main())
|