@@ -288,7 +288,7 @@ def unpack_many(data, word_size = None):
288288# Make individual packers, e.g. _p8lu
289289#
290290ops = ['p' ,'u' ]
291- sizes = {8 :'b' , 16 :'h' , 32 :'i' , 64 :'q' }
291+ sizes = {8 :'b' , 16 :'h' , 32 :'i' , 40 : '' , 48 : '' , 56 : '' , 64 :'q' }
292292ends = ['b' ,'l' ]
293293signs = ['s' ,'u' ]
294294
@@ -298,6 +298,20 @@ def unpack_many(data, word_size = None):
298298def make_single (op ,size ,end ,sign ):
299299 name = '_%s%s%s%s' % (op , size , end , sign )
300300 fmt = sizes [size ]
301+
302+ # Handle non-standard sizes without the struct module.
303+ if fmt == '' :
304+ endianess = 'big' if end == 'b' else 'little'
305+ if op == 'u' :
306+ def routine (data , stacklevel = 1 ):
307+ data = _need_bytes (data , stacklevel )
308+ return unpack (data , size , endianness = endianess , sign = sign == 's' )
309+ else :
310+ def routine (data , stacklevel = None ):
311+ return pack (data , size , endianness = endianess , sign = sign == 's' )
312+ routine .__name__ = routine .__qualname__ = name
313+ return name , routine
314+
301315 end = '>' if end == 'b' else '<'
302316
303317 if sign == 'u' :
@@ -410,6 +424,81 @@ def p32(number, endianness = None, **kwargs):
410424 """
411425 return _do_packing ('p' , 32 , number , endianness )
412426
427+ @LocalNoarchContext
428+ def p40 (number , endianness = None , ** kwargs ):
429+ """p40(number, endianness, sign, ...) -> bytes
430+
431+ Packs an 40-bit integer
432+
433+ Arguments:
434+ number (int): Number to convert
435+ endianness (str): Endianness of the converted integer ("little"/"big")
436+ sign (str): Signedness of the converted integer ("unsigned"/"signed")
437+ kwargs (dict): Arguments passed to context.local(), such as
438+ ``endian`` or ``signed``.
439+
440+ Returns:
441+ The packed number as a byte string
442+
443+ Examples:
444+
445+ >>> p40(0x4142434445, 'big')
446+ b'ABCDE'
447+ >>> p40(0x4142434445, endianness='big')
448+ b'ABCDE'
449+ """
450+ return _do_packing ('p' , 40 , number , endianness )
451+
452+ @LocalNoarchContext
453+ def p48 (number , endianness = None , ** kwargs ):
454+ """p48(number, endianness, sign, ...) -> bytes
455+
456+ Packs an 48-bit integer
457+
458+ Arguments:
459+ number (int): Number to convert
460+ endianness (str): Endianness of the converted integer ("little"/"big")
461+ sign (str): Signedness of the converted integer ("unsigned"/"signed")
462+ kwargs (dict): Arguments passed to context.local(), such as
463+ ``endian`` or ``signed``.
464+
465+ Returns:
466+ The packed number as a byte string
467+
468+ Examples:
469+
470+ >>> p48(0x414243444546, 'big')
471+ b'ABCDEF'
472+ >>> p48(0x414243444546, endianness='big')
473+ b'ABCDEF'
474+ """
475+ return _do_packing ('p' , 48 , number , endianness )
476+
477+ @LocalNoarchContext
478+ def p56 (number , endianness = None , ** kwargs ):
479+ """p56(number, endianness, sign, ...) -> bytes
480+
481+ Packs an 56-bit integer
482+
483+ Arguments:
484+ number (int): Number to convert
485+ endianness (str): Endianness of the converted integer ("little"/"big")
486+ sign (str): Signedness of the converted integer ("unsigned"/"signed")
487+ kwargs (dict): Arguments passed to context.local(), such as
488+ ``endian`` or ``signed``.
489+
490+ Returns:
491+ The packed number as a byte string
492+
493+ Examples:
494+
495+ >>> p56(0x41424344454647, 'big')
496+ b'ABCDEFG'
497+ >>> p56(0x41424344454647, endianness='big')
498+ b'ABCDEFG'
499+ """
500+ return _do_packing ('p' , 56 , number , endianness )
501+
413502@LocalNoarchContext
414503def p64 (number , endianness = None , ** kwargs ):
415504 """p64(number, endianness, sign, ...) -> bytes
@@ -489,6 +578,60 @@ def u32(data, endianness = None, **kwargs):
489578 """
490579 return _do_packing ('u' , 32 , data , endianness )
491580
581+ @LocalNoarchContext
582+ def u40 (data , endianness = None , ** kwargs ):
583+ """u40(data, endianness, sign, ...) -> int
584+
585+ Unpacks an 40-bit integer
586+
587+ Arguments:
588+ data (bytes): Byte string to convert
589+ endianness (str): Endianness of the converted integer ("little"/"big")
590+ sign (str): Signedness of the converted integer ("unsigned"/"signed")
591+ kwargs (dict): Arguments passed to context.local(), such as
592+ ``endian`` or ``signed``.
593+
594+ Returns:
595+ The unpacked number
596+ """
597+ return _do_packing ('u' , 40 , data , endianness )
598+
599+ @LocalNoarchContext
600+ def u48 (data , endianness = None , ** kwargs ):
601+ """u48(data, endianness, sign, ...) -> int
602+
603+ Unpacks an 48-bit integer
604+
605+ Arguments:
606+ data (bytes): Byte string to convert
607+ endianness (str): Endianness of the converted integer ("little"/"big")
608+ sign (str): Signedness of the converted integer ("unsigned"/"signed")
609+ kwargs (dict): Arguments passed to context.local(), such as
610+ ``endian`` or ``signed``.
611+
612+ Returns:
613+ The unpacked number
614+ """
615+ return _do_packing ('u' , 48 , data , endianness )
616+
617+ @LocalNoarchContext
618+ def u56 (data , endianness = None , ** kwargs ):
619+ """u56(data, endianness, sign, ...) -> int
620+
621+ Unpacks an 56-bit integer
622+
623+ Arguments:
624+ data (bytes): Byte string to convert
625+ endianness (str): Endianness of the converted integer ("little"/"big")
626+ sign (str): Signedness of the converted integer ("unsigned"/"signed")
627+ kwargs (dict): Arguments passed to context.local(), such as
628+ ``endian`` or ``signed``.
629+
630+ Returns:
631+ The unpacked number
632+ """
633+ return _do_packing ('u' , 56 , data , endianness )
634+
492635@LocalNoarchContext
493636def u64 (data , endianness = None , ** kwargs ):
494637 """u64(data, endianness, sign, ...) -> int
0 commit comments