@@ -822,6 +822,42 @@ def isModeExecChanged(src_mode, dst_mode):
822822 return isModeExec (src_mode ) != isModeExec (dst_mode )
823823
824824
825+ def p4KeysContainingNonUtf8Chars ():
826+ """Returns all keys which may contain non UTF-8 encoded strings
827+ for which a fallback strategy has to be applied.
828+ """
829+ return ['desc' , 'client' , 'FullName' ]
830+
831+
832+ def p4KeysContainingBinaryData ():
833+ """Returns all keys which may contain arbitrary binary data
834+ """
835+ return ['data' ]
836+
837+
838+ def p4KeyContainsFilePaths (key ):
839+ """Returns True if the key contains file paths. These are handled by decode_path().
840+ Otherwise False.
841+ """
842+ return key .startswith ('depotFile' ) or key in ['path' , 'clientFile' ]
843+
844+
845+ def p4KeyWhichCanBeDirectlyDecoded (key ):
846+ """Returns True if the key can be directly decoded as UTF-8 string
847+ Otherwise False.
848+
849+ Keys which can not be encoded directly:
850+ - `data` which may contain arbitrary binary data
851+ - `desc` or `client` or `FullName` which may contain non-UTF8 encoded text
852+ - `depotFile[0-9]*`, `path`, or `clientFile` which may contain non-UTF8 encoded text, handled by decode_path()
853+ """
854+ if key in p4KeysContainingNonUtf8Chars () or \
855+ key in p4KeysContainingBinaryData () or \
856+ p4KeyContainsFilePaths (key ):
857+ return False
858+ return True
859+
860+
825861def p4CmdList (cmd , stdin = None , stdin_mode = 'w+b' , cb = None , skip_info = False ,
826862 errors_as_exceptions = False , * k , ** kw ):
827863
@@ -851,15 +887,13 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
851887 try :
852888 while True :
853889 entry = marshal .load (p4 .stdout )
890+
854891 if bytes is not str :
855- # Decode unmarshalled dict to use str keys and values, except for:
856- # - `data` which may contain arbitrary binary data
857- # - `desc` or `FullName` which may contain non-UTF8 encoded text handled below, eagerly converted to bytes
858- # - `depotFile[0-9]*`, `path`, or `clientFile` which may contain non-UTF8 encoded text, handled by decode_path()
892+ # Decode unmarshalled dict to use str keys and values. Special cases are handled below.
859893 decoded_entry = {}
860894 for key , value in entry .items ():
861895 key = key .decode ()
862- if isinstance (value , bytes ) and not (key in ( 'data' , 'desc' , 'FullName' , 'path' , 'clientFile' ) or key . startswith ( 'depotFile' ) ):
896+ if isinstance (value , bytes ) and p4KeyWhichCanBeDirectlyDecoded (key ):
863897 value = value .decode ()
864898 decoded_entry [key ] = value
865899 # Parse out data if it's an error response
@@ -869,10 +903,9 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
869903 if skip_info :
870904 if 'code' in entry and entry ['code' ] == 'info' :
871905 continue
872- if 'desc' in entry :
873- entry ['desc' ] = metadata_stream_to_writable_bytes (entry ['desc' ])
874- if 'FullName' in entry :
875- entry ['FullName' ] = metadata_stream_to_writable_bytes (entry ['FullName' ])
906+ for key in p4KeysContainingNonUtf8Chars ():
907+ if key in entry :
908+ entry [key ] = metadata_stream_to_writable_bytes (entry [key ])
876909 if cb is not None :
877910 cb (entry )
878911 else :
0 commit comments