@@ -3767,19 +3767,24 @@ def to_archive(self, stream: Any) -> None:
37673767
37683768 def _sign_internal (
37693769 self ,
3770- signer : Signer ,
37713770 format : str ,
37723771 source_stream : Stream ,
3773- dest_stream : Stream ) -> bytes :
3774- """Internal signing logic shared between sign() and sign_file() methods
3775- to use same native calls but expose different API surface.
3772+ dest_stream : Stream ,
3773+ signer : Optional [Signer ] = None ) -> bytes :
3774+ """Internal signing implementation used by both explicit-signer and
3775+ context-signer code paths.
3776+
3777+ When ``signer`` is provided, calls ``c2pa_builder_sign`` (explicit
3778+ signer). When ``signer`` is ``None``, calls
3779+ ``c2pa_builder_sign_context`` (context-based signer).
37763780
37773781 Args:
3778- signer: The signer to use
37793782 format: The MIME type or extension of the content
37803783 source_stream: The source stream
37813784 dest_stream: The destination stream,
3782- opened in w+b (write+read binary) mode.
3785+ opened in w+b (write+read binary) mode.
3786+ signer: Optional explicit signer. When None the context
3787+ signer is used instead.
37833788
37843789 Returns:
37853790 Manifest bytes
@@ -3789,31 +3794,34 @@ def _sign_internal(
37893794 """
37903795 self ._ensure_valid_state ()
37913796
3792- # Validate signer pointer before use
3793- if not signer or not hasattr (signer , '_signer' ) or not signer ._signer :
3794- raise C2paError ("Invalid or closed signer" )
3795-
3796- format_lower = format .lower ()
3797- if format_lower not in Builder .get_supported_mime_types ():
3798- raise C2paError .NotSupported (
3799- f"Builder does not support { format } " )
3797+ if signer is not None :
3798+ if not hasattr (signer , '_signer' ) or not signer ._signer :
3799+ raise C2paError ("Invalid or closed signer" )
38003800
3801- format_str = format .encode ('utf-8' )
3801+ format_bytes = _validate_and_encode_format (
3802+ format , Builder .get_supported_mime_types (), "Builder" )
38023803 manifest_bytes_ptr = ctypes .POINTER (ctypes .c_ubyte )()
38033804
3804- # c2pa_builder_sign uses streams
38053805 try :
3806- result = _lib .c2pa_builder_sign (
3807- self ._builder ,
3808- format_str ,
3809- source_stream ._stream ,
3810- dest_stream ._stream ,
3811- signer ._signer ,
3812- ctypes .byref (manifest_bytes_ptr )
3813- )
3806+ if signer is not None :
3807+ result = _lib .c2pa_builder_sign (
3808+ self ._builder ,
3809+ format_bytes ,
3810+ source_stream ._stream ,
3811+ dest_stream ._stream ,
3812+ signer ._signer ,
3813+ ctypes .byref (manifest_bytes_ptr )
3814+ )
3815+ else :
3816+ result = _lib .c2pa_builder_sign_context (
3817+ self ._builder ,
3818+ format_bytes ,
3819+ source_stream ._stream ,
3820+ dest_stream ._stream ,
3821+ ctypes .byref (manifest_bytes_ptr ),
3822+ )
38143823 except Exception as e :
3815- # Handle errors during the C function call
3816- raise C2paError (f"Error calling c2pa_builder_sign: { str (e )} " )
3824+ raise C2paError (f"Error during signing: { e } " )
38173825
38183826 if result < 0 :
38193827 error = _parse_operation_result_for_error (_lib .c2pa_error ())
@@ -3825,22 +3833,18 @@ def _sign_internal(
38253833 manifest_bytes = b""
38263834 if manifest_bytes_ptr and result > 0 :
38273835 try :
3828- # Convert the C pointer to Python bytes
38293836 temp_buffer = (ctypes .c_ubyte * result )()
38303837 ctypes .memmove (temp_buffer , manifest_bytes_ptr , result )
38313838 manifest_bytes = bytes (temp_buffer )
38323839 except Exception :
38333840 manifest_bytes = b""
38343841 finally :
3835- # Always free the C-allocated memory,
3836- # even if we failed to copy manifest bytes
38373842 try :
38383843 _lib .c2pa_manifest_bytes_free (manifest_bytes_ptr )
38393844 except Exception :
38403845 logger .error (
38413846 "Failed to release native manifest bytes memory"
38423847 )
3843- pass
38443848
38453849 return manifest_bytes
38463850
@@ -3863,32 +3867,35 @@ def _sign_common(
38633867 Manifest bytes
38643868 """
38653869 source_stream = Stream (source )
3870+ try :
3871+ if dest :
3872+ dest_stream = Stream (dest )
3873+ else :
3874+ mem_buffer = io .BytesIO ()
3875+ dest_stream = Stream (mem_buffer )
38663876
3867- if dest :
3868- dest_stream = Stream (dest )
3869- else :
3870- mem_buffer = io .BytesIO ()
3871- dest_stream = Stream (mem_buffer )
3872-
3873- if signer is not None :
3874- manifest_bytes = self ._sign_internal (
3875- signer , format ,
3876- source_stream , dest_stream ,
3877- )
3878- elif self ._has_context_signer :
3879- manifest_bytes = self ._sign_context_internal (
3880- format , source_stream , dest_stream ,
3881- )
3882- else :
3883- raise C2paError (
3884- "No signer provided. Either pass a"
3885- " signer parameter or create the"
3886- " Builder with a Context that has"
3887- " a signer."
3888- )
3889-
3890- if not dest :
3891- dest_stream .close ()
3877+ try :
3878+ if signer is not None :
3879+ manifest_bytes = self ._sign_internal (
3880+ format , source_stream , dest_stream ,
3881+ signer = signer ,
3882+ )
3883+ elif self ._has_context_signer :
3884+ manifest_bytes = self ._sign_internal (
3885+ format , source_stream , dest_stream ,
3886+ )
3887+ else :
3888+ raise C2paError (
3889+ "No signer provided. Either pass a"
3890+ " signer parameter or create the"
3891+ " Builder with a Context that has"
3892+ " a signer."
3893+ )
3894+ finally :
3895+ if not dest :
3896+ dest_stream .close ()
3897+ finally :
3898+ source_stream .close ()
38923899
38933900 return manifest_bytes
38943901
@@ -3947,85 +3954,6 @@ def sign_with_context(
39473954 """
39483955 return self ._sign_common (None , format , source , dest )
39493956
3950- def _sign_context_internal (
3951- self ,
3952- format : str ,
3953- source_stream : 'Stream' ,
3954- dest_stream : 'Stream' ,
3955- ) -> bytes :
3956- """Sign using the signer stored in the context.
3957-
3958- Uses c2pa_builder_sign_context instead of
3959- c2pa_builder_sign.
3960- """
3961- self ._ensure_valid_state ()
3962-
3963- format_lower = format .lower ()
3964- if (
3965- format_lower
3966- not in Builder .get_supported_mime_types ()
3967- ):
3968- raise C2paError .NotSupported (
3969- "Builder does not support"
3970- f" { format } "
3971- )
3972-
3973- format_str = format .encode ('utf-8' )
3974- manifest_bytes_ptr = (
3975- ctypes .POINTER (ctypes .c_ubyte )()
3976- )
3977-
3978- try :
3979- result = _lib .c2pa_builder_sign_context (
3980- self ._builder ,
3981- format_str ,
3982- source_stream ._stream ,
3983- dest_stream ._stream ,
3984- ctypes .byref (manifest_bytes_ptr ),
3985- )
3986- except Exception as e :
3987- raise C2paError (
3988- "Error calling"
3989- f" c2pa_builder_sign_context: { e } "
3990- )
3991-
3992- if result < 0 :
3993- error = _parse_operation_result_for_error (
3994- _lib .c2pa_error ()
3995- )
3996- if error :
3997- raise C2paError (error )
3998- raise C2paError (
3999- "Error during context-based signing"
4000- )
4001-
4002- manifest_bytes = b""
4003- if manifest_bytes_ptr and result > 0 :
4004- try :
4005- temp_buffer = (
4006- ctypes .c_ubyte * result
4007- )()
4008- ctypes .memmove (
4009- temp_buffer ,
4010- manifest_bytes_ptr ,
4011- result ,
4012- )
4013- manifest_bytes = bytes (temp_buffer )
4014- except Exception :
4015- manifest_bytes = b""
4016- finally :
4017- try :
4018- _lib .c2pa_manifest_bytes_free (
4019- manifest_bytes_ptr
4020- )
4021- except Exception :
4022- logger .error (
4023- "Failed to release native"
4024- " manifest bytes memory"
4025- )
4026-
4027- return manifest_bytes
4028-
40293957 @overload
40303958 def sign_file (
40313959 self ,
0 commit comments