1
+ use std:: ops:: Deref ;
2
+
1
3
use super :: Primitive ;
2
4
3
- /// Additional methods for byte buffers.
4
- pub trait BufExt {
5
- fn push_val < T : Primitive > ( & mut self , value : T ) ;
6
- fn push_int ( & mut self , value : i32 ) ;
7
- fn push_float ( & mut self , value : f32 ) ;
8
- fn push_decimal ( & mut self , value : f32 ) ;
9
- fn push_hex ( & mut self , value : u8 ) ;
10
- fn push_hex_u16 ( & mut self , value : u16 ) ;
11
- fn push_octal ( & mut self , value : u8 ) ;
5
+ /// A buffer of arbitrary PDF content.
6
+ #[ derive( Debug , Clone , PartialEq ) ]
7
+ pub struct Buf {
8
+ pub ( crate ) inner : Vec < u8 > ,
9
+ pub ( crate ) limits : Limits ,
12
10
}
13
11
14
- impl BufExt for Vec < u8 > {
12
+ impl Buf {
13
+ pub ( crate ) fn new ( ) -> Self {
14
+ Self { inner : Vec :: new ( ) , limits : Limits :: new ( ) }
15
+ }
16
+
17
+ pub ( crate ) fn with_capacity ( capacity : usize ) -> Self {
18
+ Self {
19
+ inner : Vec :: with_capacity ( capacity) ,
20
+ limits : Limits :: new ( ) ,
21
+ }
22
+ }
23
+
24
+ /// Get the underlying bytes of the buffer.
25
+ pub fn into_vec ( self ) -> Vec < u8 > {
26
+ self . inner
27
+ }
28
+
29
+ /// Get the underlying bytes of the buffer as a slice.
30
+ pub fn as_slice ( & self ) -> & [ u8 ] {
31
+ self . inner . as_slice ( )
32
+ }
33
+
34
+ /// Return the limits of the buffer.
35
+ pub fn limits ( & self ) -> & Limits {
36
+ & self . limits
37
+ }
38
+
15
39
#[ inline]
16
- fn push_val < T : Primitive > ( & mut self , value : T ) {
40
+ pub ( crate ) fn push_val < T : Primitive > ( & mut self , value : T ) {
17
41
value. write ( self ) ;
18
42
}
19
43
20
44
#[ inline]
21
- fn push_int ( & mut self , value : i32 ) {
45
+ pub ( crate ) fn push_int ( & mut self , value : i32 ) {
46
+ self . limits . register_int ( value) ;
22
47
self . extend ( itoa:: Buffer :: new ( ) . format ( value) . as_bytes ( ) ) ;
23
48
}
24
49
25
50
#[ inline]
26
- fn push_float ( & mut self , value : f32 ) {
51
+ pub ( crate ) fn push_float ( & mut self , value : f32 ) {
27
52
// Don't write the decimal point if we don't need it.
28
53
// Also, integer formatting is way faster.
29
54
if value as i32 as f32 == value {
@@ -35,22 +60,35 @@ impl BufExt for Vec<u8> {
35
60
36
61
/// Like `push_float`, but forces the decimal point.
37
62
#[ inline]
38
- fn push_decimal ( & mut self , value : f32 ) {
63
+ pub ( crate ) fn push_decimal ( & mut self , value : f32 ) {
64
+ self . limits . register_real ( value) ;
65
+
39
66
if value == 0.0 || ( value. abs ( ) > 1e-6 && value. abs ( ) < 1e12 ) {
40
67
self . extend ( ryu:: Buffer :: new ( ) . format ( value) . as_bytes ( ) ) ;
41
68
} else {
42
69
#[ inline( never) ]
43
- fn write_extreme ( buf : & mut Vec < u8 > , value : f32 ) {
70
+ fn write_extreme ( buf : & mut Buf , value : f32 ) {
44
71
use std:: io:: Write ;
45
- write ! ( buf, "{}" , value) . unwrap ( ) ;
72
+ write ! ( buf. inner , "{}" , value) . unwrap ( ) ;
46
73
}
47
74
48
75
write_extreme ( self , value) ;
49
76
}
50
77
}
51
78
52
79
#[ inline]
53
- fn push_hex ( & mut self , value : u8 ) {
80
+ pub ( crate ) fn extend_buf ( & mut self , other : & Buf ) {
81
+ self . limits . merge ( & other. limits ) ;
82
+ self . inner . extend ( & other. inner ) ;
83
+ }
84
+
85
+ #[ inline]
86
+ pub ( crate ) fn push ( & mut self , b : u8 ) {
87
+ self . inner . push ( b) ;
88
+ }
89
+
90
+ #[ inline]
91
+ pub ( crate ) fn push_hex ( & mut self , value : u8 ) {
54
92
fn hex ( b : u8 ) -> u8 {
55
93
if b < 10 {
56
94
b'0' + b
@@ -64,13 +102,13 @@ impl BufExt for Vec<u8> {
64
102
}
65
103
66
104
#[ inline]
67
- fn push_hex_u16 ( & mut self , value : u16 ) {
105
+ pub ( crate ) fn push_hex_u16 ( & mut self , value : u16 ) {
68
106
self . push_hex ( ( value >> 8 ) as u8 ) ;
69
107
self . push_hex ( value as u8 ) ;
70
108
}
71
109
72
110
#[ inline]
73
- fn push_octal ( & mut self , value : u8 ) {
111
+ pub ( crate ) fn push_octal ( & mut self , value : u8 ) {
74
112
fn octal ( b : u8 ) -> u8 {
75
113
b'0' + b
76
114
}
@@ -79,4 +117,182 @@ impl BufExt for Vec<u8> {
79
117
self . push ( octal ( ( value >> 3 ) & 7 ) ) ;
80
118
self . push ( octal ( value & 7 ) ) ;
81
119
}
120
+
121
+ #[ inline]
122
+ pub ( crate ) fn reserve ( & mut self , additional : usize ) {
123
+ self . inner . reserve ( additional)
124
+ }
125
+ }
126
+
127
+ impl Deref for Buf {
128
+ type Target = [ u8 ] ;
129
+
130
+ fn deref ( & self ) -> & Self :: Target {
131
+ & self . inner
132
+ }
133
+ }
134
+
135
+ impl Extend < u8 > for Buf {
136
+ fn extend < T : IntoIterator < Item = u8 > > ( & mut self , iter : T ) {
137
+ self . inner . extend ( iter)
138
+ }
139
+ }
140
+
141
+ impl < ' a > Extend < & ' a u8 > for Buf {
142
+ fn extend < T : IntoIterator < Item = & ' a u8 > > ( & mut self , iter : T ) {
143
+ self . inner . extend ( iter)
144
+ }
145
+ }
146
+
147
+ /// Tracks the limits of data types used in a buffer.
148
+ #[ derive( Debug , Default , Clone , PartialEq ) ]
149
+ pub struct Limits {
150
+ int : i32 ,
151
+ real : f32 ,
152
+ name_len : usize ,
153
+ str_len : usize ,
154
+ array_len : usize ,
155
+ dict_entries : usize ,
156
+ }
157
+
158
+ impl Limits {
159
+ /// Create a new `Limits` struct with all values initialized to zero.
160
+ pub fn new ( ) -> Self {
161
+ Self :: default ( )
162
+ }
163
+
164
+ /// Get the absolute value of the largest positive/negative integer number.
165
+ pub fn int ( & self ) -> i32 {
166
+ self . int
167
+ }
168
+
169
+ /// Get the absolute value of the largest positive/negative real number.
170
+ pub fn real ( & self ) -> f32 {
171
+ self . real
172
+ }
173
+
174
+ /// Get the maximum length of any used name.
175
+ pub fn name_len ( & self ) -> usize {
176
+ self . name_len
177
+ }
178
+
179
+ /// Get the maximum length of any used string.
180
+ pub fn str_len ( & self ) -> usize {
181
+ self . str_len
182
+ }
183
+
184
+ /// Get the maximum length of any used array.
185
+ pub fn array_len ( & self ) -> usize {
186
+ self . array_len
187
+ }
188
+
189
+ /// Get the maximum number of entries in any dictionary.
190
+ pub fn dict_entries ( & self ) -> usize {
191
+ self . dict_entries
192
+ }
193
+
194
+ pub ( crate ) fn register_int ( & mut self , val : i32 ) {
195
+ self . int = self . int . max ( val. abs ( ) ) ;
196
+ }
197
+
198
+ pub ( crate ) fn register_real ( & mut self , val : f32 ) {
199
+ self . real = self . real . max ( val. abs ( ) ) ;
200
+ }
201
+
202
+ pub ( crate ) fn register_name_len ( & mut self , len : usize ) {
203
+ self . name_len = self . name_len . max ( len) ;
204
+ }
205
+
206
+ pub ( crate ) fn register_str_len ( & mut self , len : usize ) {
207
+ self . str_len = self . str_len . max ( len) ;
208
+ }
209
+
210
+ pub ( crate ) fn register_array_len ( & mut self , len : usize ) {
211
+ self . array_len = self . array_len . max ( len) ;
212
+ }
213
+
214
+ pub ( crate ) fn register_dict_entries ( & mut self , len : usize ) {
215
+ self . dict_entries = self . dict_entries . max ( len) ;
216
+ }
217
+
218
+ /// Merge two `Limits` with each other, taking the maximum
219
+ /// of each field from both.
220
+ pub fn merge ( & mut self , other : & Limits ) {
221
+ self . register_int ( other. int ) ;
222
+ self . register_real ( other. real ) ;
223
+ self . register_name_len ( other. name_len ) ;
224
+ self . register_str_len ( other. str_len ) ;
225
+ self . register_array_len ( other. array_len ) ;
226
+ self . register_dict_entries ( other. dict_entries ) ;
227
+ }
228
+ }
229
+
230
+ #[ cfg( test) ]
231
+ mod tests {
232
+ use super :: * ;
233
+ use crate :: { Chunk , Content , Finish , Name , Rect , Ref , Str , TextStr } ;
234
+
235
+ #[ test]
236
+ fn test_content_limits ( ) {
237
+ let mut limits = Limits :: default ( ) ;
238
+
239
+ let mut content = Content :: new ( ) ;
240
+ content. cubic_to ( 14.3 , 16.2 , 22.6 , 30.9 , 50.1 , 40.0 ) ;
241
+ content. show ( Str ( b"Some text" ) ) ;
242
+ content. set_font ( Name ( b"NotoSans" ) , 10.0 ) ;
243
+ let buf = content. finish ( ) ;
244
+ limits. merge ( buf. limits ( ) ) ;
245
+
246
+ let mut content = Content :: new ( ) ;
247
+ content. line_to ( 55.0 , -75.3 ) ;
248
+ content. set_font ( Name ( b"Noto" ) , 10.0 ) ;
249
+ content
250
+ . show_positioned ( )
251
+ . items ( )
252
+ . show ( Str ( b"A" ) )
253
+ . show ( Str ( b"B" ) )
254
+ . adjust ( 32.0 ) ;
255
+ content
256
+ . marked_content_point_with_properties ( Name ( b"Hi" ) )
257
+ . properties ( )
258
+ . actual_text ( TextStr ( "text" ) ) ;
259
+ let buf = content. finish ( ) ;
260
+ limits. merge ( buf. limits ( ) ) ;
261
+
262
+ assert_eq ! (
263
+ limits,
264
+ Limits {
265
+ int: 55 ,
266
+ real: 75.3 ,
267
+ name_len: 10 ,
268
+ str_len: 9 ,
269
+ array_len: 3 ,
270
+ dict_entries: 1 ,
271
+ }
272
+ )
273
+ }
274
+
275
+ #[ test]
276
+ fn test_chunk_limits ( ) {
277
+ let mut limits = Limits :: default ( ) ;
278
+
279
+ let mut chunk = Chunk :: new ( ) ;
280
+ let mut x_object = chunk. form_xobject ( Ref :: new ( 1 ) , & [ ] ) ;
281
+ x_object. bbox ( Rect :: new ( 4.0 , 6.0 , 22.1 , 31.0 ) ) ;
282
+ x_object. finish ( ) ;
283
+
284
+ limits. merge ( chunk. limits ( ) ) ;
285
+
286
+ assert_eq ! (
287
+ limits,
288
+ Limits {
289
+ int: 31 ,
290
+ real: 22.1 ,
291
+ name_len: 7 ,
292
+ str_len: 0 ,
293
+ array_len: 4 ,
294
+ dict_entries: 4 ,
295
+ }
296
+ )
297
+ }
82
298
}
0 commit comments