Esempio n. 1
0
def _insert_or_get_field_at(writer: BasePdfFileWriter,
                            fields,
                            path,
                            parent_ref=None,
                            modified=False,
                            field_obj=None):

    current_partial, tail = path[0], path[1:]

    for field_ref in fields:
        assert isinstance(field_ref, generic.IndirectObject)
        field = field_ref.get_object()
        if field.get('/T', None) == current_partial:
            break
    else:
        # have to insert a new element into the fields array
        if field_obj is not None and not tail:
            field = field_obj
        else:
            # create a generic field
            field = generic.DictionaryObject()
        field['/T'] = pdf_string(current_partial)
        if parent_ref is not None:
            field['/Parent'] = parent_ref
        field_ref = writer.add_object(field)
        fields.append(field_ref)
        writer.update_container(fields)
        modified = True

    if not tail:
        return modified, field_ref
    # check for /Kids, and create it if necessary
    try:
        kids = field['/Kids']
    except KeyError:
        kids = field['/Kids'] = generic.ArrayObject()
        writer.update_container(field)
        modified = True

    # recurse in to /Kids array
    return _insert_or_get_field_at(writer,
                                   kids,
                                   tail,
                                   parent_ref=field_ref,
                                   modified=modified,
                                   field_obj=field_obj)
Esempio n. 2
0
def _prepare_sig_field(sig_field_name,
                       root,
                       update_writer: BasePdfFileWriter,
                       existing_fields_only=False,
                       lock_sig_flags=True,
                       **kwargs):
    """
    Returns a tuple of a boolean and a reference to a signature field.
    The boolean is ``True`` if the field was created, and ``False`` otherwise.
    """
    if sig_field_name is None:  # pragma: nocover
        raise ValueError

    try:
        form = root['/AcroForm']

        try:
            fields = form['/Fields']
        except KeyError:
            raise ValueError('/AcroForm has no /Fields')

        candidates = enumerate_sig_fields_in(fields, with_name=sig_field_name)
        sig_field_ref = None
        try:
            field_name, value, sig_field_ref = next(candidates)
            if value is not None:
                raise SigningError(
                    'Signature field with name %s appears to be filled already.'
                    % sig_field_name)
        except StopIteration:
            if existing_fields_only:
                raise SigningError(
                    'No empty signature field with name %s found.' %
                    sig_field_name)
        form_created = False
    except KeyError:
        # we have to create the form
        if existing_fields_only:
            raise SigningError('This file does not contain a form.')
        # no AcroForm present, so create one
        form = generic.DictionaryObject()
        root[pdf_name('/AcroForm')] = update_writer.add_object(form)
        fields = generic.ArrayObject()
        form[pdf_name('/Fields')] = fields
        # now we need to mark the root as updated
        update_writer.update_root()
        form_created = True
        sig_field_ref = None

    if sig_field_ref is not None:
        return False, sig_field_ref

    # no signature field exists, so create one
    # default: grab a reference to the first page
    page_ref = update_writer.find_page_for_modification(0)[0]
    sig_form_kwargs = {'include_on_page': page_ref}
    sig_form_kwargs.update(**kwargs)
    sig_field = SignatureFormField(sig_field_name, **sig_form_kwargs)
    created, sig_field_ref = _insert_or_get_field_at(
        update_writer,
        fields,
        path=sig_field_name.split('.'),
        field_obj=sig_field)
    update_writer.register_annotation(page_ref, sig_field_ref)

    # make sure /SigFlags is present. If not, create it
    sig_flags = 3 if lock_sig_flags else 1
    form.setdefault(pdf_name('/SigFlags'), generic.NumberObject(sig_flags))
    # if a field was added to an existing form, register an extra update
    if not form_created:
        update_writer.update_container(fields)
    return True, sig_field_ref