Sebagai salah satu bahasa yang kurang populer, sulit untuk menemukan literatur tentang avant garde dari peretasan postscript. Jadi, penemuan apa yang dilakukan pegolf di sini untuk mengeksploitasi model tumpukan (atau fitur lainnya) untuk mengatasi verbositas inheren Postscript?
14
Jawaban:
Decoder Tertanam
Program Postscript memiliki kemampuan unik (?) Untuk membaca teks program itu sendiri sebagai data. Hal ini biasanya digunakan oleh
image
operator yang yang menerima data akuisisi-prosedur sebagai masukan, dan prosedur ini sering menggunakancurrentfile
diikuti olehreadline
,readstring
ataureadhexstring
. Tapi melihat cara lain,image
hanyalah operator pengulangan, sehingga setiap pengulangan dapat membaca-depan . Contohnya adalah emulator line-printer dari Green Book.Menggunakan
token
operator memanggil pemindai pada file atau string, menarik nomor atau spasi- (atau sebaliknya-: lihat jawaban lain) -nama awal.Penerjemah PS sederhana dalam PS:
Decoder Operator Biner
Karena saya sepertinya tidak bisa mendapatkan token biner mentah untuk bekerja untuk saya (lihat jawaban lain), saya telah menggunakan ide "decoding tertanam" untuk mengeksploitasi mekanisme token biner untuk mengemas kode menjadi string 8-bit, dan kemudian memanipulasi dan mengurai perintah dari string dengan cepat .
The
.
Prosedur mengambil nomor dari stack dan sisipan sebagai byte kedua dalam serangkaian dua-byte, byte pertama menjadi awalan-byte untuk token biner, menentukan nama sistem executable. Kami menyimpan byte dalam hexstring dengan menggunakan aturan pemindai bahwa jumlah aneh gigitan dalam hexstring diisi dengan 0 gigitan tambahan, sehingga 3 hex gigitan menghasilkan string 2-byte. String kemudian ditandai dapat dieksekusi dan dipanggil denganexec
yang memanggil pemindai, menghasilkan nama sistem yang dapat dieksekusi yang diinginkan, dan kemudian memuat nama dan mengeksekusi operator. The$
melakukan ini pada setiap byte dari string di stack, dengan menggunakan.
prosedur dua kali , sekali sebagai tubuh loop, dan kemudian mengeksekusi operator perulanganforall
dengan nomor.Lebih ringkasnya, prosedur ini terlihat seperti ini:
Jadi, 55 karakter membeli string token biner. Atau, untuk 6 (mungkin 7, jika Anda mengakhirinya dengan spasi) karakter, Anda dapat memuat perpustakaan G dengan
(G)run
yang mendefinisikan.
dan$
seperti di atas (+ beberapa orang lain untuk memperluas jangkauan dari kode ascii-terjangkau).Lebih lanjut diilustrasikan dalam jawaban teka-teki silang saya .
sumber
Saat menghasilkan output grafis dan output konsol tidak masalah, gunakan
=
sebagai gantinyapop
.sumber
Ganti hexstrings dengan ASCII85
Mungkin berita lama, tapi saya baru mempelajarinya. :)
Anda dapat melakukannya menggunakan juru bahasa postscript secara interaktif dengan filter penyandian dan cut-and-paste. Tapi saya akan menunjukkan cara menggunakannya
dc
untuk melakukannya "dengan tangan".Jadi, inilah string hex. Kami membaginya menjadi potongan 4-byte.
Mengaktifkan dc, kami memasukannya sebagai nomor pesanan big-endian-byte-32-bit (tidak ditandatangani). Kemudian mod -off base-85 digit (harus ada 5 sampai Anda mendapatkan 0).
Padding potongan terakhir dengan
00 00
, menghasilkan (desimal), menghilangkan jumlah byte yang sama dengan yang kita empuk.Tambahkan 33 untuk beralih ke kisaran ASCII dan poof yang dapat dicetak! ASCII85.
Bungkus
<~
...~>
, dan Postscript Level-2 dapat mengakses data 8-bit, lebih murah daripada hex.sumber
Ini quickie: masukkan beberapa definisi
[...>>begin
untuk menghilangkan kata kuncidef
(nb.[
Sama dengan<<
).Jadi ingat: lebih dari
tigadua ... berkumpul bersama ! ;)sumber
/a 1 def/b 2 def/c 3 def
dengan<</a 1/b 2/c 3>>begin
. Kami membutuhkan lebih banyak ruang untuk def.[/a 1/b 2/c 3>>begin
/a{pop 2 mul}def
atau\b[2 3]def
,def
satu - satunya biaya 3 karakter, bukan 4.Sementara sebagian besar operator postscript sintaksis pengidentifikasi (dan karena itu harus ruang-(atau otherwise-) delimited), nama-nama
[
,]
,<<
, dan>>
yang self-pembatasan dan scanner akan mendeteksi mereka tanpa intervensi ruang. Untuk alasan yang sama, Anda tidak dapat merujuk nama-nama ini dengan/literal
sintaksis yang biasa (mis./[
Adalah dua token: nama literal kosong yang setara dengan()cvn cvlit
, dan nama yang dapat dieksekusi[
setara dengan([)cvn cvx exec
).Untuk mendefinisikan kembali nama-nama ini, yang tidak dapat disebutkan namanya, kita dapat menggunakan string yang secara implisit dikonversi menjadi nama saat digunakan sebagai kunci dalam kamus (nyaman!).
Contoh ini menggambarkan penyalahgunaan operator ini untuk melakukan aritmatika.
Juga
<<
dan[
(danmark
) semua memiliki arti yang sama.Penerjemah postscript saya sendiri, xpost , juga membuat kurung kurawal yang tepat tersedia dengan beberapa batasan. diskusi
sumber
/
akhiri token sebelumnya sehingga Anda tidak perlu spasi sebelum itu.Pemakaian faktor-faktor berulang dari operator yang panjang
Jika Anda sudah menggunakan
<<>>begin
kamus, ada overhead konstan/?{}
4 karakter per redefinisi. Jadi operator dengan panjang n yang diulang N kali akan menghasilkan perubahan karakter-hitung(4 + n ) - ( N * ( n - 1)).
Menyetel rumus ini sama dengan 0 memberikan persamaan titik impas . Dari sini kita dapat menyelesaikan untuk setiap variabel dalam hal yang lain, menghasilkan
n = - ( N - 4) / (1 - N ) dan
N = (4 + n ) / ( n - 1).
Tidak, kami dapat menjawab pertanyaan seperti, "Untuk berapa banyak penggunaan 'cetak' yang layak disingkat?" n = 5, jadi N = 9/4. Ambillah plafon, karena Anda tidak dapat secara efektif memanggil cetak 1/4 kali. Jadi, 3. 3 menggunakan. Dan memang,
(dengan asumsi Anda sudah membayar overhead
<<>>begin
untuk mengaktifkan definisi, tentu saja).Tentu saja, token biner membuat jenis ini dapat diperdebatkan, memberi Anda 255 nama pertama dari tabel nama sistem sebagai 2-byte: 0x92, 0x ??. Dan token biner juga membatasi sendiri, tidak memerlukan spasi putih sebelum atau sesudah, karena bit tinggi dari byte pertama berada di luar rentang ascii.
sumber
Token Biner
Untuk yang terakhir zip-up akhir dari program PostScript yang perbatasan akhir adalah token biner yang memungkinkan Anda untuk menghapus nama operator yang panjang sepenuhnya, dengan biaya tidak lagi memiliki program ASCII-clean.
Jadi dimulai dengan blok kode postscript yang dipadatkan
Kami mencari semua nama di belakang PLRM (Lampiran F, hal. 795-797)
Dan kemudian ketik di awalan oleh
146
byte (desimal). bantuan vim untuk memasukkan byte acakKemudian dalam vim, file yang diringkas dapat diketik langsung, jadi:
... Anda harus memasukkan spasi di sini untuk mengakhiri
^V
-62 dan memulai 1, tetapi Anda dapat mencadangkan dan menghapusnya nanti ...... harus memasukkan spasi di sini untuk mengakhiri
^V
-85 dan memulai 1, tetapi Anda dapat mencadangkan dan menghapusnya nanti ...... Digit ke-3 dari kode 3 digit mengakhiri byte-entry jadi berikut ini
0
ini normal, dengan mudah ...Yang akan terlihat seperti ini di layar (dalam vim):
Yang ini sering dapat dihilangkan seluruhnya jika tujuannya hanya untuk menunjukkan gambar. Ghostscript melukis sebagian besar hal ke layar tanpa perlu
showpage
.[ Ini sebenarnya tidak berhasil. Ghostscript memberi saya
undefined
dansyntaxerror
untuk token ini. Mungkin ada beberapa mode yang perlu saya aktifkan. ]sumber
Ubah gulungan negatif menjadi positif
Gulungan negatif selalu dapat diubah menjadi gulungan positif .
sumber
3 -1 roll
atau3 2 roll
? Dalam model mental saya, yang pertama harus lebih efisien karena hanya perlu satu langkah. Apakah model mental saya benar?roll
operator.Gunakan perpustakaan G saya
https://github.com/luser-dr00g/G
Ini file teks. Tanpa ekstensi, untuk sintaks yang sesingkat mungkin untuk memuatnya.
Itu memungkinkan program 203-char Sierpinksi Triangle ini
untuk ditulis ulang dalam 151 byte sebagai
workfile dengan komentar
Menggunakan fitur nama sistem yang disingkat,
1(G)run
sepenuhnya menghilangkan beban nama operator yang panjang. Nama operator hanya perlu cukup panjang untuk membedakannya dari yang lain.Begitu
add
menjadiad
mul
menjadimu
index
menjadii
Menggunakan PLRM Apendiks F untuk tabel standar nama operator.
Dan fitur Operator Strings tersedia bahkan jika nama yang disingkat tidak dipilih. Pustaka kosong memiliki "level dasar" yang dipilih dengan menambahkan secara sederhana
(G)run
tanpa dekorasi lebih lanjut.Level dasar mencakup fungsi baru
.
yang menerima kode integer untuk operator (Lampiran F yang sama yang disebutkan di atas) dan menjalankannya.Fungsi baru ini
$
dijalankan melalui sebuah string dan panggilan.
masing-masing. Jadi kode ascii langsung memilih operator dengan nomor.Fungsi baru
@
memungkinkan Anda menjangkau ke bawah tabel di Lampiran F dengan memperlakukan karakter spasi (Ascii 0x20) sebagai 0.Fungsi baru
#
memungkinkan Anda menjangkau lebih jauh ke dalam tabel dengan terlebih dahulu menambahkan 95 (0x5F) sehingga spasi 0x20 diperlakukan sebagai 127 (0x7F), kode berikutnya setelah karakter ascii terakhir yang dapat dicetak.~
126 (0x7E).Dua fungsi baru
!
memungkinkan Anda mengakses struktur array dan / atau dict yang bersarang dengan array indeks indeks / kunci, daripada ekspresi yang membosankan dari banyakget
(danput
) operator.(G)run
7 karakter membeli level dasar.1(G)run
8 karakter membeli dan nama sistem disingkat.3(G)run $
9 karakter segera memulai prosedur implisit blok sumber pemindaian baris sampai baris kosong berikutnya, dan mendefinisikan baris pertama sebagai prosedur yang disebutA
, baris berikutnya didefinisikan sebagai prosedur yang disebutB
, dll. Ini harus menghapus sebagian besar yangdef
diperlukan untuk mendefinisikan banyak hal, tanpa perlu membungkusnya dalam kamus, atau bahkan secara eksplisit memberi mereka nama.sumber