Erster Commit: nativer Linux-Port aus macOS-Bytecode
Läuft die Voice Acoustic VA-Remotecontrol (AllDSP AllControl) nativ unter Linux auf echtem wxGTK 3.0 — ohne Wine und ohne dekompilierten App-Code. Ausgeführt wird das unveränderte Python-2.7-Bytecode aus dem macOS-.app; C-Extensions (wxGTK/numpy/ scipy/PortAudio) kommen nativ aus Debian stretch. Enthält: va/ (Original-.pyc + pure-Python-Libs + Assets + launch.py mit den drei Linux-Fixes), Dockerfile/run.sh/entrypoint.sh, reference/ (dekompilierter Quellcode zum Debuggen) und README/STATUS. img.cache (378 MB, regenerierbar) ist per .gitignore ausgeschlossen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
#/****************************************************************************
|
||||
#* Software: FPDF_Protection *
|
||||
#* Version: 1.02 *
|
||||
#* Date: 2005/05/08 *
|
||||
#* Author: Klemen VODOPIVEC *
|
||||
#* License: Freeware *
|
||||
#* *
|
||||
#* You may use and modify this software as you wish as stated in original *
|
||||
#* FPDF package. *
|
||||
#* *
|
||||
#* Thanks: Cpdf (http:#www.ros.co.nz/pdf) was my working sample of how to *
|
||||
#* implement protection in pdf. *
|
||||
#****************************************************************************/
|
||||
from FPDF import *
|
||||
import random, struct, md5, copy, array
|
||||
|
||||
class Protection(FPDF):
|
||||
def __init__(this, orientation='P',unit='mm',format='A4'):
|
||||
FPDF.__init__(this,orientation,unit,format)
|
||||
this.encrypted=0 #whether document is protected
|
||||
this.Uvalue='' #U entry in pdf document
|
||||
this.Ovalue='' #O entry in pdf document
|
||||
this.Pvalue='' #P entry in pdf document
|
||||
this.enc_obj_id=0 #encryption object id
|
||||
this.last_rc4_key='' #last RC4 key encrypted (cached for optimisation)
|
||||
this.last_rc4_key_c='' #last RC4 computed key
|
||||
this.encrypted=0
|
||||
this.padding="\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A"
|
||||
|
||||
|
||||
#/**
|
||||
#* Function to set permissions as well as user and owner passwords
|
||||
#*
|
||||
#* - permissions is an array with values taken from the following list:
|
||||
#* copy, print, modify, annot-forms
|
||||
#* If a value is present it means that the permission is granted
|
||||
#* - If a user password is set, user will be prompted before document is opened
|
||||
#* - If an owner password is set, document can be opened in privilege mode with no
|
||||
#* restriction if that password is entered
|
||||
#*/
|
||||
def SetProtection(this,permissions=[],user_pass='',owner_pass=None):
|
||||
options={'print':4, 'modify':8, 'copy':16, 'annot-forms':32}
|
||||
protection = 192
|
||||
for permission in permissions:
|
||||
if permission not in options:
|
||||
this.Error('Incorrect permission: '+permission)
|
||||
protection += options[permission]
|
||||
|
||||
if (owner_pass == None):
|
||||
owner_pass=''
|
||||
for i in range(13):
|
||||
owner_pass += chr(random.randint(0,255))
|
||||
this.encrypted = 1
|
||||
this._generateencryptionkey(user_pass, owner_pass, protection)
|
||||
|
||||
|
||||
#/****************************************************************************
|
||||
#* *
|
||||
#* Private methods *
|
||||
#* *
|
||||
#****************************************************************************/
|
||||
def _putstream(this,s):
|
||||
if (this.encrypted):
|
||||
s = this._RC4(this._objectkey(this.n), s)
|
||||
FPDF._putstream(this,s)
|
||||
|
||||
def _textstring(this,s):
|
||||
if (this.encrypted):
|
||||
s = this._RC4(this._objectkey(this.n), s)
|
||||
return FPDF._textstring(this,s)
|
||||
|
||||
#/**
|
||||
#* Compute key depending on object number where the encrypted data is stored
|
||||
#*/
|
||||
def _objectkey(this,n):
|
||||
return substr(this._md5_16(this.encryption_key+struct.pack('L',n)[:-1]+'\x00\x00'),0,10)
|
||||
|
||||
#/**
|
||||
#* Escape special characters
|
||||
#*/
|
||||
def _escape(this,s):
|
||||
s=str_replace('\\','\\\\',s)
|
||||
s=str_replace(')','\\)',s)
|
||||
s=str_replace('(','\\(',s)
|
||||
s=str_replace("\r",'\\r',s)
|
||||
return s
|
||||
|
||||
def _putresources(this):
|
||||
FPDF._putresources(this)
|
||||
if (this.encrypted):
|
||||
this._newobj()
|
||||
this.enc_obj_id = this.n
|
||||
this._out('<<')
|
||||
this._putencryption()
|
||||
this._out('>>')
|
||||
this._out('endobj')
|
||||
|
||||
def _putencryption(this):
|
||||
this._out('/Filter /Standard')
|
||||
this._out('/V 1')
|
||||
this._out('/R 2')
|
||||
this._out('/O ('+this._escape(this.Ovalue)+')')
|
||||
this._out('/U ('+this._escape(this.Uvalue)+')')
|
||||
this._out('/P '+str(this.Pvalue))
|
||||
|
||||
def _puttrailer(this):
|
||||
FPDF._puttrailer(this)
|
||||
if (this.encrypted):
|
||||
this._out('/Encrypt '+str(this.enc_obj_id)+' 0 R')
|
||||
this._out('/ID [()()]')
|
||||
|
||||
#/**
|
||||
#* RC4 is the standard encryption algorithm used in PDF format
|
||||
#*/
|
||||
def _RC4(this, key, text):
|
||||
if (this.last_rc4_key != key):
|
||||
k = str_repeat(key, 256/strlen(key)+1)
|
||||
rc4 = array.array('B',range(256))
|
||||
j = 0
|
||||
for i in range(256):
|
||||
t = rc4[i]
|
||||
j = (j + t + ord(k[i])) % 256
|
||||
rc4[i] = rc4[j]
|
||||
rc4[j] = t
|
||||
this.last_rc4_key = key
|
||||
this.last_rc4_key_c = copy.copy(rc4)
|
||||
else:
|
||||
rc4 = copy.copy(this.last_rc4_key_c)
|
||||
len = strlen(text)
|
||||
a = 0
|
||||
b = 0
|
||||
out = ''
|
||||
for i in range(len):
|
||||
a = (a+1)%256
|
||||
t= rc4[a]
|
||||
b = (b+t)%256
|
||||
rc4[a] = rc4[b]
|
||||
rc4[b] = t
|
||||
k = rc4[(rc4[a]+rc4[b])%256]
|
||||
out+=chr(ord(text[i]) ^ k)
|
||||
return out
|
||||
|
||||
#/**
|
||||
#* Get MD5 as binary string
|
||||
#*/
|
||||
def _md5_16(this,string):
|
||||
return md5.new(string).digest()
|
||||
|
||||
#/**
|
||||
#* Compute O value
|
||||
#*/
|
||||
def _Ovalue(this, user_pass, owner_pass):
|
||||
tmp = this._md5_16(owner_pass)
|
||||
owner_RC4_key = substr(tmp,0,5)
|
||||
return this._RC4(owner_RC4_key, user_pass)
|
||||
|
||||
#/**
|
||||
#* Compute U value
|
||||
#*/
|
||||
def _Uvalue(this):
|
||||
return this._RC4(this.encryption_key, this.padding)
|
||||
|
||||
#/**
|
||||
#* Compute encryption key
|
||||
#*/
|
||||
def _generateencryptionkey(this, user_pass, owner_pass, protection):
|
||||
# Pad passwords
|
||||
user_pass = substr(user_pass+this.padding,0,32)
|
||||
owner_pass = substr(owner_pass+this.padding,0,32)
|
||||
# Compute O value
|
||||
this.Ovalue = this._Ovalue(user_pass,owner_pass)
|
||||
# Compute encyption key
|
||||
tmp = this._md5_16(user_pass+this.Ovalue+chr(protection)+"\xFF\xFF\xFF")
|
||||
this.encryption_key = substr(tmp,0,5)
|
||||
# Compute U value
|
||||
this.Uvalue = this._Uvalue()
|
||||
# Compute P value
|
||||
this.Pvalue = -((protection^255)+1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
pdf=Protection()
|
||||
pdf.SetProtection(['print'])
|
||||
pdf.Open()
|
||||
pdf.AddPage()
|
||||
pdf.SetFont('Arial')
|
||||
pdf.Write(10,'You can print me but not copy my text.')
|
||||
pdf.Output('Protected.pdf','F')
|
||||
Reference in New Issue
Block a user