@@ -11,6 +11,8 @@ mod decl {
11
11
} ;
12
12
use itertools:: Itertools ;
13
13
14
+ const MAXLINESIZE : usize = 76 ;
15
+
14
16
#[ pyattr( name = "Error" , once) ]
15
17
fn error_type ( vm : & VirtualMachine ) -> PyTypeRef {
16
18
vm. ctx . new_exception_type (
@@ -176,13 +178,285 @@ mod decl {
176
178
// The 64 instead of the expected 63 is because
177
179
// there are a few uuencodes out there that use
178
180
// '`' as zero instead of space.
179
- if !( 0x20 ..=0x60 ) . contains ( c) {
181
+ if !( b' ' ..=( b' ' + 64 ) ) . contains ( c) {
180
182
if [ b'\r' , b'\n' ] . contains ( c) {
181
183
return Ok ( 0 ) ;
182
184
}
183
185
return Err ( vm. new_value_error ( "Illegal char" . to_string ( ) ) ) ;
184
186
}
185
- Ok ( ( * c - 0x20 ) & 0x3f )
187
+ Ok ( ( * c - b' ' ) & 0x3f )
188
+ }
189
+
190
+ #[ derive( FromArgs ) ]
191
+ struct A2bQpArgs {
192
+ #[ pyarg( any) ]
193
+ data : ArgAsciiBuffer ,
194
+ #[ pyarg( named, default = "false" ) ]
195
+ header : bool ,
196
+ }
197
+ #[ pyfunction]
198
+ fn a2b_qp ( args : A2bQpArgs ) -> PyResult < Vec < u8 > > {
199
+ let s = args. data ;
200
+ let header = args. header ;
201
+ s. with_ref ( |buffer| {
202
+ let len = buffer. len ( ) ;
203
+ let mut out_data = Vec :: with_capacity ( len) ;
204
+
205
+ let mut idx = 0 ;
206
+
207
+ while idx < len {
208
+ if buffer[ idx] == b'=' {
209
+ idx += 1 ;
210
+ if idx >= len {
211
+ break ;
212
+ }
213
+ // Soft line breaks
214
+ if ( buffer[ idx] == b'\n' ) || ( buffer[ idx] == b'\r' ) {
215
+ if buffer[ idx] != b'\n' {
216
+ while idx < len && buffer[ idx] != b'\n' {
217
+ idx += 1 ;
218
+ }
219
+ }
220
+ if idx < len {
221
+ idx += 1 ;
222
+ }
223
+ } else if buffer[ idx] == b'=' {
224
+ // roken case from broken python qp
225
+ out_data. push ( b'=' ) ;
226
+ idx += 1 ;
227
+ } else if idx + 1 < len
228
+ && ( ( buffer[ idx] >= b'A' && buffer[ idx] <= b'F' )
229
+ || ( buffer[ idx] >= b'a' && buffer[ idx] <= b'f' )
230
+ || ( buffer[ idx] >= b'0' && buffer[ idx] <= b'9' ) )
231
+ && ( ( buffer[ idx + 1 ] >= b'A' && buffer[ idx + 1 ] <= b'F' )
232
+ || ( buffer[ idx + 1 ] >= b'a' && buffer[ idx + 1 ] <= b'f' )
233
+ || ( buffer[ idx + 1 ] >= b'0' && buffer[ idx + 1 ] <= b'9' ) )
234
+ {
235
+ // hexval
236
+ if let ( Some ( ch1) , Some ( ch2) ) =
237
+ ( unhex_nibble ( buffer[ idx] ) , unhex_nibble ( buffer[ idx + 1 ] ) )
238
+ {
239
+ out_data. push ( ch1 << 4 | ch2) ;
240
+ }
241
+ idx += 2 ;
242
+ } else {
243
+ out_data. push ( b'=' ) ;
244
+ }
245
+ } else if header && buffer[ idx] == b'_' {
246
+ out_data. push ( b' ' ) ;
247
+ idx += 1 ;
248
+ } else {
249
+ out_data. push ( buffer[ idx] ) ;
250
+ idx += 1 ;
251
+ }
252
+ }
253
+
254
+ Ok ( out_data)
255
+ } )
256
+ }
257
+
258
+ #[ derive( FromArgs ) ]
259
+ struct B2aQpArgs {
260
+ #[ pyarg( any) ]
261
+ data : ArgAsciiBuffer ,
262
+ #[ pyarg( named, default = "false" ) ]
263
+ quotetabs : bool ,
264
+ #[ pyarg( named, default = "true" ) ]
265
+ istext : bool ,
266
+ #[ pyarg( named, default = "false" ) ]
267
+ header : bool ,
268
+ }
269
+
270
+ #[ pyfunction]
271
+ fn b2a_qp ( args : B2aQpArgs ) -> PyResult < Vec < u8 > > {
272
+ let s = args. data ;
273
+ let quotetabs = args. quotetabs ;
274
+ let istext = args. istext ;
275
+ let header = args. header ;
276
+ s. with_ref ( |buf| {
277
+ let buflen = buf. len ( ) ;
278
+ let mut linelen = 0 ;
279
+ let mut odatalen = 0 ;
280
+ let mut crlf = false ;
281
+ let mut ch;
282
+
283
+ let mut inidx;
284
+ let mut outidx;
285
+
286
+ inidx = 0 ;
287
+ while inidx < buflen {
288
+ if buf[ inidx] == b'\n' {
289
+ break ;
290
+ }
291
+ inidx += 1 ;
292
+ }
293
+ if buflen > 0 && inidx < buflen && buf[ inidx - 1 ] == b'\r' {
294
+ crlf = true ;
295
+ }
296
+
297
+ inidx = 0 ;
298
+ while inidx < buflen {
299
+ let mut delta = 0 ;
300
+ if ( buf[ inidx] > 126 )
301
+ || ( buf[ inidx] == b'=' )
302
+ || ( header && buf[ inidx] == b'_' )
303
+ || ( buf[ inidx] == b'.'
304
+ && linelen == 0
305
+ && ( inidx + 1 == buflen
306
+ || buf[ inidx + 1 ] == b'\n'
307
+ || buf[ inidx + 1 ] == b'\r'
308
+ || buf[ inidx + 1 ] == 0 ) )
309
+ || ( !istext && ( ( buf[ inidx] == b'\r' ) || ( buf[ inidx] == b'\n' ) ) )
310
+ || ( ( buf[ inidx] == b'\t' || buf[ inidx] == b' ' ) && ( inidx + 1 == buflen) )
311
+ || ( ( buf[ inidx] < 33 )
312
+ && ( buf[ inidx] != b'\r' )
313
+ && ( buf[ inidx] != b'\n' )
314
+ && ( quotetabs || ( ( buf[ inidx] != b'\t' ) && ( buf[ inidx] != b' ' ) ) ) )
315
+ {
316
+ if ( linelen + 3 ) >= MAXLINESIZE {
317
+ linelen = 0 ;
318
+ delta += if crlf { 3 } else { 2 } ;
319
+ }
320
+ linelen += 3 ;
321
+ delta += 3 ;
322
+ inidx += 1 ;
323
+ } else if istext
324
+ && ( ( buf[ inidx] == b'\n' )
325
+ || ( ( inidx + 1 < buflen)
326
+ && ( buf[ inidx] == b'\r' )
327
+ && ( buf[ inidx + 1 ] == b'\n' ) ) )
328
+ {
329
+ linelen = 0 ;
330
+ // Protect against whitespace on end of line
331
+ if ( inidx != 0 ) && ( ( buf[ inidx - 1 ] == b' ' ) || ( buf[ inidx - 1 ] == b'\t' ) ) {
332
+ delta += 2 ;
333
+ }
334
+ delta += if crlf { 2 } else { 1 } ;
335
+ inidx += if buf[ inidx] == b'\r' { 2 } else { 1 } ;
336
+ } else {
337
+ if ( inidx + 1 != buflen)
338
+ && ( buf[ inidx + 1 ] != b'\n' )
339
+ && ( linelen + 1 ) >= MAXLINESIZE
340
+ {
341
+ linelen = 0 ;
342
+ delta += if crlf { 3 } else { 2 } ;
343
+ }
344
+ linelen += 1 ;
345
+ delta += 1 ;
346
+ inidx += 1 ;
347
+ }
348
+ odatalen += delta;
349
+ }
350
+
351
+ let mut out_data = Vec :: with_capacity ( odatalen) ;
352
+ inidx = 0 ;
353
+ outidx = 0 ;
354
+ linelen = 0 ;
355
+
356
+ while inidx < buflen {
357
+ if ( buf[ inidx] > 126 )
358
+ || ( buf[ inidx] == b'=' )
359
+ || ( header && buf[ inidx] == b'_' )
360
+ || ( ( buf[ inidx] == b'.' )
361
+ && ( linelen == 0 )
362
+ && ( inidx + 1 == buflen
363
+ || buf[ inidx + 1 ] == b'\n'
364
+ || buf[ inidx + 1 ] == b'\r'
365
+ || buf[ inidx + 1 ] == 0 ) )
366
+ || ( !istext && ( ( buf[ inidx] == b'\r' ) || ( buf[ inidx] == b'\n' ) ) )
367
+ || ( ( buf[ inidx] == b'\t' || buf[ inidx] == b' ' ) && ( inidx + 1 == buflen) )
368
+ || ( ( buf[ inidx] < 33 )
369
+ && ( buf[ inidx] != b'\r' )
370
+ && ( buf[ inidx] != b'\n' )
371
+ && ( quotetabs || ( ( buf[ inidx] != b'\t' ) && ( buf[ inidx] != b' ' ) ) ) )
372
+ {
373
+ if ( linelen + 3 ) >= MAXLINESIZE {
374
+ // MAXLINESIZE = 76
375
+ out_data. push ( b'=' ) ;
376
+ outidx += 1 ;
377
+ if crlf {
378
+ out_data. push ( b'\r' ) ;
379
+ outidx += 1 ;
380
+ }
381
+ out_data. push ( b'\n' ) ;
382
+ outidx += 1 ;
383
+ linelen = 0 ;
384
+ }
385
+ out_data. push ( b'=' ) ;
386
+ outidx += 1 ;
387
+
388
+ ch = hex_nibble ( buf[ inidx] >> 4 ) ;
389
+ if ( b'a' ..=b'f' ) . contains ( & ch) {
390
+ ch -= b' ' ;
391
+ }
392
+ out_data. push ( ch) ;
393
+ ch = hex_nibble ( buf[ inidx] & 0xf ) ;
394
+ if ( b'a' ..=b'f' ) . contains ( & ch) {
395
+ ch -= b' ' ;
396
+ }
397
+ out_data. push ( ch) ;
398
+
399
+ outidx += 2 ;
400
+ inidx += 1 ;
401
+ linelen += 3 ;
402
+ } else if istext
403
+ && ( ( buf[ inidx] == b'\n' )
404
+ || ( ( inidx + 1 < buflen)
405
+ && ( buf[ inidx] == b'\r' )
406
+ && ( buf[ inidx + 1 ] == b'\n' ) ) )
407
+ {
408
+ linelen = 0 ;
409
+ if ( outidx != 0 )
410
+ && ( ( out_data[ outidx - 1 ] == b' ' ) || ( out_data[ outidx - 1 ] == b'\t' ) )
411
+ {
412
+ ch = hex_nibble ( out_data[ outidx - 1 ] >> 4 ) ;
413
+ if ( b'a' ..=b'f' ) . contains ( & ch) {
414
+ ch -= b' ' ;
415
+ }
416
+ out_data. push ( ch) ;
417
+ ch = hex_nibble ( out_data[ outidx - 1 ] & 0xf ) ;
418
+ if ( b'a' ..=b'f' ) . contains ( & ch) {
419
+ ch -= b' ' ;
420
+ }
421
+ out_data. push ( ch) ;
422
+ out_data[ outidx - 1 ] = b'=' ;
423
+ outidx += 2 ;
424
+ }
425
+
426
+ if crlf {
427
+ out_data. push ( b'\r' ) ;
428
+ outidx += 1 ;
429
+ }
430
+ out_data. push ( b'\n' ) ;
431
+ outidx += 1 ;
432
+ inidx += if buf[ inidx] == b'\r' { 2 } else { 1 } ;
433
+ } else {
434
+ if ( inidx + 1 != buflen) && ( buf[ inidx + 1 ] != b'\n' ) && ( linelen + 1 ) >= 76 {
435
+ // MAXLINESIZE = 76
436
+ out_data. push ( b'=' ) ;
437
+ outidx += 1 ;
438
+ if crlf {
439
+ out_data. push ( b'\r' ) ;
440
+ outidx += 1 ;
441
+ }
442
+ out_data. push ( b'\n' ) ;
443
+ outidx += 1 ;
444
+ linelen = 0 ;
445
+ }
446
+ linelen += 1 ;
447
+ if header && buf[ inidx] == b' ' {
448
+ out_data. push ( b'_' ) ;
449
+ outidx += 1 ;
450
+ inidx += 1 ;
451
+ } else {
452
+ out_data. push ( buf[ inidx] ) ;
453
+ outidx += 1 ;
454
+ inidx += 1 ;
455
+ }
456
+ }
457
+ }
458
+ Ok ( out_data)
459
+ } )
186
460
}
187
461
188
462
#[ pyfunction]
@@ -259,7 +533,7 @@ mod decl {
259
533
let length = if b. is_empty ( ) {
260
534
( ( -0x20i32 ) & 0x3fi32 ) as usize
261
535
} else {
262
- ( ( b[ 0 ] - 0x20 ) & 0x3f ) as usize
536
+ ( ( b[ 0 ] - b' ' ) & 0x3f ) as usize
263
537
} ;
264
538
265
539
// Allocate the buffer
@@ -316,7 +590,7 @@ mod decl {
316
590
if backtick && num != 0 {
317
591
0x60
318
592
} else {
319
- 0x20 + num
593
+ b' ' + num
320
594
}
321
595
}
322
596
0 commit comments