''' Extra information to customise how we wrap MuPDF structs into C++ classes. ''' import textwrap import jlib from . import rename from . import state from . import util class ExtraMethod: ''' Defines a prototype and implementation of a custom method in a generated class. ''' def __init__( self, return_, name_args, body, comment, overload=None): ''' return_: Return type as a string. name_args: A string describing name and args of the method: () body: Implementation code including the enclosing '{...}'. comment: Optional comment; should include /* and */ or //. overload: If true, we allow auto-generation of methods with same name. ''' assert name_args self.return_ = return_ self.name_args = name_args self.body = body self.comment = comment self.overload = overload assert '\t' not in body def __str__(self): return f'{self.name_args} => {self.return_}' class ExtraConstructor: ''' Defines a prototype and implementation of a custom constructor in a generated class. ''' def __init__( self, name_args, body, comment): ''' name_args: A string of the form: () body: Implementation code including the enclosing '{...}'. comment: Optional comment; should include /* and */ or //. ''' self.return_ = '' self.name_args = name_args self.body = body self.comment = comment assert '\t' not in body class ClassExtra: ''' Extra methods/features when wrapping a particular MuPDF struct into a C++ class. ''' def __init__( self, accessors=None, class_bottom='', class_post='', class_pre='', class_top='', constructor_default=True, constructor_excludes=None, constructor_prefixes=None, constructor_raw=True, constructors_extra=None, constructors_wrappers=None, copyable=True, extra_cpp='', iterator_next=None, methods_extra=None, method_wrappers=None, method_wrappers_static=None, opaque=False, pod=False, virtual_fnptrs=False, ): ''' accessors: If true, we generate accessors methods for all items in the underlying struct. Defaults to True if pod is True, else False. class_bottom: Extra text at end of class definition, e.g. for member variables. class_post: Extra text after class definition, e.g. complete definition of iterator class. class_pre: Extra text before class definition, e.g. forward declaration of iterator class. class_top: Extra text at start of class definition, e.g. for enums. constructor_default: If None we set to true if `pod` is true, otherwise false. If true, we create a default constructor. If `pod` is true this constructor will default-initialise each member, otherwise it will set `m_internal` to null. constructor_excludes: Lists of constructor functions to ignore. constructor_prefixes: Extra fz_*() function name prefixes that can be used by class constructors_wrappers. We find all functions whose name starts with one of the specified prefixes and which returns a pointer to the relevant fz struct. For each function we find, we make a constructor that takes the required arguments and set m_internal to what this function returns. If there is a '-' item, we omit the default 'fz_new_' prefix. constructor_raw: If true, create a constructor that takes a pointer to an instance of the wrapped fz_ struct. If 'default', this constructor arg defaults to NULL. If 'declaration_only' we declare the constructor but do not write out the function definition - typically this will be instead specified as custom code in . constructors_extra: List of ExtraConstructor's, allowing arbitrary constructors_wrappers to be specified. constructors_wrappers: List of fns to use as constructors_wrappers. copyable: If 'default' we allow default copy constructor to be created by C++ compiler. This is useful for plain structs that are not referenced counted but can still be copied, but which we don't want to specify pod=True. Otherwise if true, generated wrapper class must be copyable. If pod is false, we generate a copy constructor by looking for a fz_keep_*() function; it's an error if we can't find this function. Otherwise if false we create a private copy constructor. [todo: need to check docs for interaction of pod/copyable.] extra_cpp: Extra text for .cpp file, e.g. implementation of iterator class methods. iterator_next: Support for iterating forwards over linked list. Should be (first, last). first: Name of element within the wrapped class that points to the first item in the linked list. We assume that this element will have 'next' pointers that terminate in NULL. If is '', the container is itself the first element in the linked list. last: Currently unused, but could be used for reverse iteration in the future. We generate begin() and end() methods, plus a separate iterator class, to allow iteration over the linked list starting at :: and iterating to ->next until we reach NULL. methods_extra: List of ExtraMethod's, allowing arbitrary methods to be specified. method_wrappers: Extra fz_*() function names that should be wrapped in class methods. E.g. 'fz_foo_bar' is converted to a method called foo_bar() that takes same parameters as fz_foo_bar() except context and any pointer to struct and fz_context*. The implementation calls fz_foo_bar(), converting exceptions etc. The first arg that takes underlying fz_*_s type is omitted and implementation passes . method_wrappers_static: Like , but generates static methods, where no args are replaced by . opaque: If true, we generate a wrapper even if there's no definition available for the struct, i.e. it's only available as a forward declaration. pod: If 'inline', there is no m_internal; instead, each member of the underlying class is placed in the wrapper class and special method `internal()` returns a fake pointer to underlying class. If 'none', there is no m_internal member at all. Typically could be used to add in custom members. If True, underlying class is POD and m_internal is an instance of the underlying class instead of a pointer to it. virtual_fnptrs: If true, should be a dict with these keys: self_: A callable taking single arg that is the name of a pointer to an instance of the MuPDF struct; should return C++ code that converts the specified name into a pointer to the corresponding virtual_fnptrs wrapper class. self_n: Index of arg that is the void* that should be passed to `virtual_fnptrs['self_']` to recover the virtual_fnptrs wrapper class. Note that we assume/require that all virtual fns have the same `self_n`. If not specified, default is 1 (we generally expect args to be (fz_context* ctx, void*, ...). alloc: Code for embedding in the virtual_fnptrs wrapper class's constructor that creates a new instances of the MuPDF struct and virtual_fnptrs wrapper class, and sets m_internal to point to the MuPDF struct. It should also ensure that can convert m_internal to the instance of the virtual_fnptrs wrapper class. free: Optional code for freeing the virtual_fnptrs wrapper class. We generate a virtual_fnptrs wrapper class, derived from the main wrapper class, where the main wrapper class's function pointers end up calling the virtual_fnptrs wrapper class's virtual methods. We then use SWIG's 'Director' support to allow these virtual methods to be overridden in Python/C#. Thus one can make MuPDF function pointers call Python/C# code. ''' if accessors is None and pod is True: accessors = True if constructor_default is None: constructor_default = pod self.accessors = accessors self.class_bottom = class_bottom self.class_post = class_post self.class_pre = class_pre self.class_top = class_top self.constructor_default = constructor_default self.constructor_excludes = constructor_excludes or [] self.constructor_prefixes = constructor_prefixes or [] self.constructor_raw = constructor_raw self.constructors_extra = constructors_extra or [] self.constructors_wrappers = constructors_wrappers or [] self.copyable = copyable self.extra_cpp = extra_cpp self.iterator_next = iterator_next self.methods_extra = methods_extra or [] self.method_wrappers = method_wrappers or [] self.method_wrappers_static = method_wrappers_static or [] self.opaque = opaque self.pod = pod self.virtual_fnptrs = virtual_fnptrs assert self.pod in (False, True, 'inline', 'none'), f'{self.pod}' def assert_list_of( items, type_): assert isinstance( items, list) for item in items: assert isinstance( item, type_) assert_list_of( self.constructor_prefixes, str) assert_list_of( self.method_wrappers, str) assert_list_of( self.method_wrappers_static, str) assert_list_of( self.methods_extra, ExtraMethod) assert_list_of( self.constructors_extra, ExtraConstructor) if virtual_fnptrs: assert isinstance(virtual_fnptrs, dict), f'virtual_fnptrs={virtual_fnptrs!r}' def __str__( self): ret = '' ret += f' accessors={self.accessors}' ret += f' class_bottom={self.class_bottom}' ret += f' class_post={self.class_post}' ret += f' class_pre={self.class_pre}' ret += f' class_top={self.class_top}' ret += f' constructor_default={self.constructor_default}' ret += f' constructor_excludes={self.constructor_excludes}' ret += f' constructor_prefixes={self.constructor_prefixes}' ret += f' constructor_raw={self.constructor_raw}' ret += f' constructors_extra={self.constructors_extra}' ret += f' constructors_wrappers={self.constructors_wrappers}' ret += f' copyable={self.copyable}' ret += f' extra_cpp={self.extra_cpp}' ret += f' iterator_next={self.iterator_next}' ret += f' methods_extra={self.methods_extra}' ret += f' method_wrappers={self.method_wrappers}' ret += f' method_wrappers_static={self.method_wrappers_static}' ret += f' opaque={self.opaque}' ret += f' pod={self.pod}' ret += f' virtual_fnptrs={self.virtual_fnptrs}' return ret class ClassExtras: ''' Extra methods/features for each of our auto-generated C++ wrapper classes. ''' def __init__( self, **namevalues): ''' namevalues: Named args mapping from struct name (e.g. fz_document) to a ClassExtra. ''' self.items = dict() for name, value in namevalues.items(): self.items[ name] = value def get( self, tu, name): ''' Searches for and returns a ClassExtra instance. If is not found, we insert an empty ClassExtra instance and return it. We do this for any name, e.g. name could be 'foo *'. We return None if is a known enum. ''' verbose = state.state_.show_details( name) if 0 and verbose: jlib.log( 'ClassExtras.get(): {=name}') name = util.clip( name, ('const ', 'struct ')) if 0 and verbose: jlib.log( 'ClassExtras.get(): {=name}') if not name.startswith( ('fz_', 'pdf_')): return ret = self.items.setdefault( name, ClassExtra()) if name in state.state_.enums[ tu]: #jlib.log( '*** name is an enum: {name=}') return None if ' ' not in name and not ret.pod and ret.copyable and ret.copyable != 'default': # Check whether there is a _keep() fn. keep_name = f'fz_keep_{name[3:]}' if name.startswith( 'fz_') else f'pdf_keep_{name[4:]}' keep_cursor = state.state_.find_function( tu, keep_name, method=True) if not keep_cursor: if ret.copyable: if 0: jlib.log( '*** Changing .copyable to False for {=name keep_name}') ret.copyable = False return ret def get_or_none( self, name): return self.items.get( name) # Customisation information for selected wrapper classes. # # We use MuPDF struct names as keys. # classextras = ClassExtras( fz_aa_context = ClassExtra( pod='inline', ), fz_band_writer = ClassExtra( class_top = ''' /* We use these enums to support construction via all the relevent MuPDF functions. */ enum Cm { MONO, COLOR, }; enum P { PNG, PNM, PAM, PBM, PKM, PS, PSD, }; ''', constructors_extra = [ ExtraConstructor( f'({rename.class_("fz_output")}& out, Cm cm, const {rename.class_("fz_pcl_options")}& options)', f''' {{ ::fz_output* out2 = out.m_internal; const ::fz_pcl_options* options2 = options.m_internal; if (0) {{}} else if (cm == MONO) m_internal = {rename.ll_fn('fz_new_mono_pcl_band_writer' )}( out2, options2); else if (cm == COLOR) m_internal = {rename.ll_fn('fz_new_color_pcl_band_writer')}( out2, options2); else throw std::runtime_error( "Unrecognised fz_band_writer_s Cm type"); }} ''', comment = f'/* Constructor using fz_new_mono_pcl_band_writer() or fz_new_color_pcl_band_writer(). */', ), ExtraConstructor( f'({rename.class_("fz_output")}& out, P p)', f''' {{ ::fz_output* out2 = out.m_internal; if (0) {{}} else if (p == PNG) m_internal = {rename.ll_fn('fz_new_png_band_writer')}( out2); else if (p == PNM) m_internal = {rename.ll_fn('fz_new_pnm_band_writer')}( out2); else if (p == PAM) m_internal = {rename.ll_fn('fz_new_pam_band_writer')}( out2); else if (p == PBM) m_internal = {rename.ll_fn('fz_new_pbm_band_writer')}( out2); else if (p == PKM) m_internal = {rename.ll_fn('fz_new_pkm_band_writer')}( out2); else if (p == PS) m_internal = {rename.ll_fn('fz_new_ps_band_writer' )}( out2); else if (p == PSD) m_internal = {rename.ll_fn('fz_new_psd_band_writer')}( out2); else throw std::runtime_error( "Unrecognised fz_band_writer_s P type"); }} ''', comment = f'/* Constructor using fz_new_p*_band_writer(). */', ), ExtraConstructor( f'({rename.class_("fz_output")}& out, Cm cm, const {rename.class_("fz_pwg_options")}& options)', f''' {{ ::fz_output* out2 = out.m_internal; const ::fz_pwg_options* options2 = &options.m_internal; if (0) {{}} else if (cm == MONO) m_internal = {rename.ll_fn('fz_new_mono_pwg_band_writer' )}( out2, options2); else if (cm == COLOR) m_internal = {rename.ll_fn('fz_new_pwg_band_writer')}( out2, options2); else throw std::runtime_error( "Unrecognised fz_band_writer_s Cm type"); }} ''', comment = f'/* Constructor using fz_new_mono_pwg_band_writer() or fz_new_pwg_band_writer(). */', ), ], copyable = False, ), fz_bitmap = ClassExtra( accessors = True, ), fz_buffer = ClassExtra( constructor_raw = 'default', constructors_wrappers = [ 'fz_read_file', ], ), fz_color_params = ClassExtra( pod='inline', constructors_extra = [ ExtraConstructor('()', f''' {{ this->ri = fz_default_color_params.ri; this->bp = fz_default_color_params.bp; this->op = fz_default_color_params.op; this->opm = fz_default_color_params.opm; }} ''', comment = '/* Equivalent to fz_default_color_params. */', ), ], ), fz_colorspace = ClassExtra( constructors_extra = [ ExtraConstructor( '(Fixed fixed)', f''' {{ if (0) {{}} else if ( fixed == Fixed_GRAY) m_internal = {rename.ll_fn( 'fz_device_gray')}(); else if ( fixed == Fixed_RGB) m_internal = {rename.ll_fn( 'fz_device_rgb' )}(); else if ( fixed == Fixed_BGR) m_internal = {rename.ll_fn( 'fz_device_bgr' )}(); else if ( fixed == Fixed_CMYK) m_internal = {rename.ll_fn( 'fz_device_cmyk')}(); else if ( fixed == Fixed_LAB) m_internal = {rename.ll_fn( 'fz_device_lab' )}(); else {{ std::string message = "Unrecognised fixed colorspace id"; throw {rename.error_class("FZ_ERROR_GENERIC")}(message.c_str()); }} {rename.ll_fn('fz_keep_colorspace')}(m_internal); }} ''', comment = '/* Construct using one of: fz_device_gray(), fz_device_rgb(), fz_device_bgr(), fz_device_cmyk(), fz_device_lab(). */', ), ], constructor_raw=1, class_top = ''' /* We use this enums to support construction via all the relevent MuPDF functions. */ enum Fixed { Fixed_GRAY, Fixed_RGB, Fixed_BGR, Fixed_CMYK, Fixed_LAB, }; ''', ), fz_context = ClassExtra( copyable = False, ), fz_cookie = ClassExtra( constructors_extra = [ ExtraConstructor( '()', ''' { this->m_internal.abort = 0; this->m_internal.progress = 0; this->m_internal.progress_max = (size_t) -1; this->m_internal.errors = 0; this->m_internal.incomplete = 0; } ''', comment = '/* Default constructor sets all fields to default values. */', ), ], constructor_raw = False, methods_extra = [ ExtraMethod( 'void', 'set_abort()', '{ m_internal.abort = 1; }\n', '/* Sets m_internal.abort to 1. */', ), ExtraMethod( 'void', 'increment_errors(int delta)', '{ m_internal.errors += delta; }\n', '/* Increments m_internal.errors by . */', ), ], pod = True, # Other code asyncronously writes to our fields, so we are not # copyable. todo: maybe tie us to all objects to which we have # been associated? # copyable=False, ), fz_device = ClassExtra( virtual_fnptrs = dict( self_ = lambda name: f'(*({rename.class_("fz_device")}2**) ({name} + 1))', alloc = textwrap.dedent( f''' m_internal = {rename.ll_fn("fz_new_device_of_size")}( sizeof(*m_internal) + sizeof({rename.class_("fz_device")}2*) ); *(({rename.class_("fz_device")}2**) (m_internal + 1)) = this; '''), ), constructor_raw = True, ), fz_document = ClassExtra( constructor_excludes = [ 'fz_new_xhtml_document_from_document', ], constructor_prefixes = [ 'fz_open_accelerated_document', 'fz_open_document', ], constructors_extra = [ ExtraConstructor( f'({rename.class_("pdf_document")}& pdfdocument)', f''' {{ m_internal = {rename.ll_fn('fz_keep_document')}(&pdfdocument.m_internal->super); }} ''', f'/* Returns a {rename.class_("fz_document")} for pdfdocument.m_internal.super. */', ), ], constructor_raw = 'default', method_wrappers = [ 'fz_load_outline', ], method_wrappers_static = [ 'fz_new_xhtml_document_from_document', ], methods_extra = [ # This duplicates our creation of extra fz_lookup_metadata() # function in make_function_wrappers(). Maybe we could # parse the generated functions.h instead of fitz.h so that # we pick up extra C++ wrappers automatically, but this # would be a fairly major change. # ExtraMethod( 'std::string', f'{rename.method( "fz_document", "fz_lookup_metadata")}(const char* key, int* o_out=NULL)', f''' {{ return {rename.ll_fn("fz_lookup_metadata")}(m_internal, key, o_out); }} ''', textwrap.dedent(''' /* Wrapper for fz_lookup_metadata() that returns a std::string and sets *o_out to length of string plus one. If is not found, returns empty string with *o_out=-1. can be NULL if caller is not interested in error information. */ ''') ), ], ), # This is a little complicated. Many of the functions that we would # like to wrap to form constructors, have the same set of args. C++ # does not support named constructors so we differentiate between # constructors with identical args using enums. # # Also, fz_document_writer is not reference counted so the wrapping # class is not copyable or assignable, so our normal approach of making # static class functions that return a newly constructed instance by # value, does not work. # # So instead we define enums that are passed to our constructors, # allowing the constructor to decide which fz_ function to use to # create the new fz_document_writer. # # There should be no commented-out constructors in the generated code # marked as 'Disabled because same args as ...'. # fz_document_writer = ClassExtra( class_top = ''' /* Used for constructor that wraps fz_ functions taking (const char *path, const char *options). */ enum PathType { PathType_CBZ, PathType_DOCX, PathType_ODT, PathType_PAM_PIXMAP, PathType_PBM_PIXMAP, PathType_PCL, PathType_PCLM, PathType_PDF, PathType_PDFOCR, PathType_PGM_PIXMAP, PathType_PKM_PIXMAP, PathType_PNG_PIXMAP, PathType_PNM_PIXMAP, PathType_PPM_PIXMAP, PathType_PS, PathType_PWG, PathType_SVG, }; /* Used for constructor that wraps fz_ functions taking (Output& out, const char *options). */ enum OutputType { OutputType_CBZ, OutputType_DOCX, OutputType_ODT, OutputType_PCL, OutputType_PCLM, OutputType_PDF, OutputType_PDFOCR, OutputType_PS, OutputType_PWG, }; /* Used for constructor that wraps fz_ functions taking (const char *format, const char *path, const char *options). */ enum FormatPathType { FormatPathType_DOCUMENT, FormatPathType_TEXT, }; ''', # These excludes should match the functions called by the # extra constructors defined below. This ensures that we don't # generate commented-out constructors with a comment saying # 'Disabled because same args as ...'. constructor_excludes = [ 'fz_new_cbz_writer', 'fz_new_docx_writer', 'fz_new_odt_writer', 'fz_new_pam_pixmap_writer', 'fz_new_pbm_pixmap_writer', 'fz_new_pcl_writer', 'fz_new_pclm_writer', 'fz_new_pdfocr_writer', 'fz_new_pdf_writer', 'fz_new_pgm_pixmap_writer', 'fz_new_pkm_pixmap_writer', 'fz_new_png_pixmap_writer', 'fz_new_pnm_pixmap_writer', 'fz_new_ppm_pixmap_writer', 'fz_new_ps_writer', 'fz_new_pwg_writer', 'fz_new_svg_writer', 'fz_new_cbz_writer_with_output', 'fz_new_docx_writer_with_output', 'fz_new_odt_writer_with_output', 'fz_new_pcl_writer_with_output', 'fz_new_pclm_writer_with_output', 'fz_new_pdf_writer_with_output', 'fz_new_pdfocr_writer_with_output', 'fz_new_ps_writer_with_output', 'fz_new_pwg_writer_with_output', 'fz_new_document_writer', 'fz_new_text_writer', 'fz_new_document_writer_with_output', 'fz_new_text_writer_with_output', ], copyable=False, methods_extra = [ # 2022-08-26: we used to provide a custom wrapper of # fz_begin_page(), but this is not longer necessary # because function_wrapper_class_aware_body() knows # that fz_begin_page() returns a borrowed reference. # ], constructors_extra = [ ExtraConstructor( '(const char *path, const char *options, PathType path_type)', f''' {{ if (0) {{}} else if (path_type == PathType_CBZ) m_internal = {rename.ll_fn( 'fz_new_cbz_writer')}(path, options); else if (path_type == PathType_DOCX) m_internal = {rename.ll_fn( 'fz_new_docx_writer')}(path, options); else if (path_type == PathType_ODT) m_internal = {rename.ll_fn( 'fz_new_odt_writer')}(path, options); else if (path_type == PathType_PAM_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_pam_pixmap_writer')}(path, options); else if (path_type == PathType_PBM_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_pbm_pixmap_writer')}(path, options); else if (path_type == PathType_PCL) m_internal = {rename.ll_fn( 'fz_new_pcl_writer')}(path, options); else if (path_type == PathType_PCLM) m_internal = {rename.ll_fn( 'fz_new_pclm_writer')}(path, options); else if (path_type == PathType_PDF) m_internal = {rename.ll_fn( 'fz_new_pdf_writer')}(path, options); else if (path_type == PathType_PDFOCR) m_internal = {rename.ll_fn( 'fz_new_pdfocr_writer')}(path, options); else if (path_type == PathType_PGM_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_pgm_pixmap_writer')}(path, options); else if (path_type == PathType_PKM_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_pkm_pixmap_writer')}(path, options); else if (path_type == PathType_PNG_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_png_pixmap_writer')}(path, options); else if (path_type == PathType_PNM_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_pnm_pixmap_writer')}(path, options); else if (path_type == PathType_PPM_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_ppm_pixmap_writer')}(path, options); else if (path_type == PathType_PS) m_internal = {rename.ll_fn( 'fz_new_ps_writer')}(path, options); else if (path_type == PathType_PWG) m_internal = {rename.ll_fn( 'fz_new_pwg_writer')}(path, options); else if (path_type == PathType_SVG) m_internal = {rename.ll_fn( 'fz_new_svg_writer')}(path, options); else throw {rename.error_class('FZ_ERROR_ABORT')}( "Unrecognised Type value"); }} ''', comment = textwrap.dedent(''' /* Constructor using one of: fz_new_cbz_writer() fz_new_docx_writer() fz_new_odt_writer() fz_new_pam_pixmap_writer() fz_new_pbm_pixmap_writer() fz_new_pcl_writer() fz_new_pclm_writer() fz_new_pdf_writer() fz_new_pdfocr_writer() fz_new_pgm_pixmap_writer() fz_new_pkm_pixmap_writer() fz_new_png_pixmap_writer() fz_new_pnm_pixmap_writer() fz_new_ppm_pixmap_writer() fz_new_ps_writer() fz_new_pwg_writer() fz_new_svg_writer() */'''), ), ExtraConstructor( f'({rename.class_("fz_output")}& out, const char *options, OutputType output_type)', f''' {{ /* All fz_new_*_writer_with_output() functions take ownership of the fz_output, even if they throw an exception. So we need to set out.m_internal to null here so its destructor does nothing. */ ::fz_output* out2 = out.m_internal; out.m_internal = NULL; if (0) {{}} else if (output_type == OutputType_CBZ) m_internal = {rename.ll_fn( 'fz_new_cbz_writer_with_output')}(out2, options); else if (output_type == OutputType_DOCX) m_internal = {rename.ll_fn( 'fz_new_docx_writer_with_output')}(out2, options); else if (output_type == OutputType_ODT) m_internal = {rename.ll_fn( 'fz_new_odt_writer_with_output')}(out2, options); else if (output_type == OutputType_PCL) m_internal = {rename.ll_fn( 'fz_new_pcl_writer_with_output')}(out2, options); else if (output_type == OutputType_PCLM) m_internal = {rename.ll_fn( 'fz_new_pclm_writer_with_output')}(out2, options); else if (output_type == OutputType_PDF) m_internal = {rename.ll_fn( 'fz_new_pdf_writer_with_output')}(out2, options); else if (output_type == OutputType_PDFOCR) m_internal = {rename.ll_fn( 'fz_new_pdfocr_writer_with_output')}(out2, options); else if (output_type == OutputType_PS) m_internal = {rename.ll_fn( 'fz_new_ps_writer_with_output')}(out2, options); else if (output_type == OutputType_PWG) m_internal = {rename.ll_fn( 'fz_new_pwg_writer_with_output')}(out2, options); else {{ /* Ensure that out2 is dropped before we return. */ {rename.ll_fn( 'fz_drop_output')}(out2); throw {rename.error_class('FZ_ERROR_ABORT')}( "Unrecognised OutputType value"); }} }} ''', comment = textwrap.dedent(''' /* Constructor using one of: fz_new_cbz_writer_with_output() fz_new_docx_writer_with_output() fz_new_odt_writer_with_output() fz_new_pcl_writer_with_output() fz_new_pclm_writer_with_output() fz_new_pdf_writer_with_output() fz_new_pdfocr_writer_with_output() fz_new_ps_writer_with_output() fz_new_pwg_writer_with_output() This constructor takes ownership of - out.m_internal is set to NULL after this constructor returns so must not be used again. */ '''), ), ExtraConstructor( '(const char *format, const char *path, const char *options, FormatPathType format_path_type)', f''' {{ if (0) {{}} else if (format_path_type == FormatPathType_DOCUMENT) m_internal = {rename.ll_fn( 'fz_new_document_writer')}(format, path, options); else if (format_path_type == FormatPathType_TEXT) m_internal = {rename.ll_fn( 'fz_new_text_writer')}(format, path, options); else throw {rename.error_class('FZ_ERROR_ABORT')}( "Unrecognised OutputType value"); }} ''', comment = textwrap.dedent(''' /* Constructor using one of: fz_new_document_writer() fz_new_text_writer() */'''), ), ExtraConstructor( f'({rename.class_("fz_output")}& out, const char *format, const char *options)', f''' {{ /* Need to transfer ownership of . */ ::fz_output* out2 = out.m_internal; out.m_internal = NULL; m_internal = {rename.ll_fn( 'fz_new_document_writer_with_output')}(out2, format, options); }} ''', comment = textwrap.dedent(''' /* Constructor using fz_new_document_writer_with_output(). This constructor takes ownership of - out.m_internal is set to NULL after this constructor returns so must not be used again. */'''), ), ExtraConstructor( f'(const char *format, {rename.class_("fz_output")}& out, const char *options)', f''' {{ /* Need to transfer ownership of . */ ::fz_output* out2 = out.m_internal; out.m_internal = NULL; m_internal = {rename.ll_fn( 'fz_new_text_writer_with_output')}(format, out2, options); }} ''', comment = textwrap.dedent(''' /* Constructor using fz_new_text_writer_with_output(). This constructor takes ownership of - out.m_internal is set to NULL after this constructor returns so must not be used again. */'''), ), ], ), fz_draw_options = ClassExtra( constructors_wrappers = [ 'fz_parse_draw_options', ], copyable=False, pod='inline', ), fz_halftone = ClassExtra( constructor_raw = 'default', ), fz_image = ClassExtra( accessors=True, ), fz_irect = ClassExtra( constructor_prefixes = [ 'fz_irect_from_rect', 'fz_make_irect', ], pod='inline', constructor_raw = True, ), fz_link = ClassExtra( constructors_extra = [ ExtraConstructor( f'({rename.class_("fz_rect")}& rect, const char *uri)', f''' {{ m_internal = {rename.ll_fn('fz_new_link_of_size')}( sizeof(fz_link), *rect.internal(), uri); }} ''', '/* Construct by calling fz_new_link_of_size() with size=sizeof(fz_link). */', ) ], accessors = True, iterator_next = ('', ''), constructor_raw = 'default', copyable = True, ), fz_location = ClassExtra( constructor_prefixes = [ 'fz_make_location', ], pod='inline', constructor_raw = True, ), fz_matrix = ClassExtra( constructor_prefixes = [ 'fz_make_matrix', ], method_wrappers_static = [ 'fz_concat', 'fz_scale', 'fz_shear', 'fz_rotate', 'fz_translate', 'fz_transform_page', ], constructors_extra = [ ExtraConstructor( '()', ''' : a(1), b(0), c(0), d(1), e(0), f(0) { } ''', comment = '/* Constructs identity matrix (like fz_identity). */'), ], pod='inline', constructor_raw = True, ), fz_md5 = ClassExtra( pod = True, constructors_extra = [ ExtraConstructor( '()', f''' {{ {rename.ll_fn( 'fz_md5_init')}( &m_internal); }} ''', '/* Default constructor calls md5_init(). */', ) ], methods_extra = [ ExtraMethod( 'std::vector', f'{rename.method("fz_md5", "fz_md5_final2")}()', f''' {{ std::vector ret(16); {rename.ll_fn( 'fz_md5_final')}( &m_internal, &ret[0]); return ret; }} ''', f'/* Wrapper for fz_md5_final() that returns the digest by value. */', ), ], ), fz_outline = ClassExtra( # We add various methods to give depth-first iteration of outlines. # constructor_prefixes = [ 'fz_load_outline', ], accessors=True, ), fz_outline_item = ClassExtra( class_top = f''' FZ_FUNCTION bool valid() const; FZ_FUNCTION const std::string& title() const; /* Will throw if valid() is not true. */ FZ_FUNCTION const std::string& uri() const; /* Will throw if valid() is not true. */ FZ_FUNCTION int is_open() const; /* Will throw if valid() is not true. */ ''', class_bottom = f''' private: bool m_valid; std::string m_title; std::string m_uri; int m_is_open; ''', constructors_extra = [ ], constructor_raw = 'declaration_only', copyable = 'default', pod = 'none', extra_cpp = f''' FZ_FUNCTION {rename.class_("fz_outline_item")}::{rename.class_("fz_outline_item")}(const ::fz_outline_item* item) {{ if (item) {{ m_valid = true; m_title = item->title; m_uri = item->uri; m_is_open = item->is_open; }} else {{ m_valid = false; }} }} FZ_FUNCTION bool {rename.class_("fz_outline_item")}::valid() const {{ return m_valid; }} FZ_FUNCTION const std::string& {rename.class_("fz_outline_item")}::title() const {{ if (!m_valid) throw {rename.error_class("FZ_ERROR_GENERIC")}("fz_outline_item is invalid"); return m_title; }} FZ_FUNCTION const std::string& {rename.class_("fz_outline_item")}::uri() const {{ if (!m_valid) throw {rename.error_class("FZ_ERROR_GENERIC")}("fz_outline_item is invalid"); return m_uri; }} FZ_FUNCTION int {rename.class_("fz_outline_item")}::is_open() const {{ if (!m_valid) throw {rename.error_class("FZ_ERROR_GENERIC")}("fz_outline_item is invalid"); return m_is_open; }} ''', ), fz_outline_iterator = ClassExtra( copyable = False, methods_extra = [ ExtraMethod( 'int', f'{rename.method("fz_outline_iterator", "fz_outline_iterator_insert")}({rename.class_("fz_outline_item")}& item)', f''' {{ /* Create a temporary fz_outline_item. */ ::fz_outline_item item2; item2.title = (char*) item.title().c_str(); item2.uri = (char*) item.uri().c_str(); item2.is_open = item.is_open(); return {rename.ll_fn("fz_outline_iterator_insert")}(m_internal, &item2); }} ''', comment = '/* Custom wrapper for fz_outline_iterator_insert(). */', ), ExtraMethod( 'void', f'{rename.method("fz_outline_iterator", "fz_outline_iterator_update")}({rename.class_("fz_outline_item")}& item)', f''' {{ /* Create a temporary fz_outline_item. */ ::fz_outline_item item2; item2.title = (char*) item.title().c_str(); item2.uri = (char*) item.uri().c_str(); item2.is_open = item.is_open(); return {rename.ll_fn("fz_outline_iterator_update")}(m_internal, &item2); }} ''', comment = '/* Custom wrapper for fz_outline_iterator_update(). */', ), ], ), fz_output = ClassExtra( virtual_fnptrs = dict( self_ = lambda name: f'({rename.class_("fz_output")}2*) {name}', alloc = f'm_internal = {rename.ll_fn("fz_new_output")}(0 /*bufsize*/, this /*state*/, nullptr /*write*/, nullptr /*close*/, nullptr /*drop*/);\n', ), constructor_raw = 'default', constructor_excludes = [ # These all have the same prototype, so are used by # constructors_extra below. 'fz_new_asciihex_output', 'fz_new_ascii85_output', 'fz_new_rle_output', ], constructors_extra = [ ExtraConstructor( '(Fixed out)', f''' {{ if (0) {{}} else if (out == Fixed_STDOUT) {{ m_internal = {rename.ll_fn('fz_stdout')}(); }} else if (out == Fixed_STDERR) {{ m_internal = {rename.ll_fn('fz_stderr')}(); }} else {{ throw {rename.error_class('FZ_ERROR_ABORT')}("Unrecognised Fixed value"); }} }} ''', '/* Uses fz_stdout() or fz_stderr(). */', # Note that it's ok to call fz_drop_output() on fz_stdout and fz_stderr. ), ExtraConstructor( f'(const {rename.class_("fz_output")}& chain, Filter filter)', f''' {{ if (0) {{}} else if (filter == Filter_HEX) {{ m_internal = {rename.ll_fn('fz_new_asciihex_output')}(chain.m_internal); }} else if (filter == Filter_85) {{ m_internal = {rename.ll_fn('fz_new_ascii85_output')}(chain.m_internal); }} else if (filter == Filter_RLE) {{ m_internal = {rename.ll_fn('fz_new_rle_output')}(chain.m_internal); }} else {{ throw {rename.error_class('FZ_ERROR_ABORT')}("Unrecognised Filter value"); }} }} ''', comment = '/* Calls one of: fz_new_asciihex_output(), fz_new_ascii85_output(), fz_new_rle_output(). */', ), ], class_top = ''' enum Fixed { Fixed_STDOUT=1, Fixed_STDERR=2, }; enum Filter { Filter_HEX, Filter_85, Filter_RLE, }; ''' , copyable=False, # No fz_keep_output() fn? ), fz_page = ClassExtra( constructor_prefixes = [ 'fz_load_page', 'fz_load_chapter_page', ], constructors_extra = [ ExtraConstructor( f'({rename.class_("pdf_page")}& pdfpage)', f''' {{ m_internal = {rename.ll_fn('fz_keep_page')}(&pdfpage.m_internal->super); }} ''', f'/* Return {rename.class_("fz_page")} for pdfpage.m_internal.super. */', ), ], methods_extra = [ ExtraMethod( f'std::vector<{rename.class_("fz_quad")}>', f'{rename.method("fz_page", "fz_search_page")}(const char* needle, int *hit_mark, int max)', f''' {{ std::vector<{rename.class_("fz_quad")}> ret(max); ::fz_quad* hit_bbox = ret[0].internal(); int n = {rename.ll_fn('fz_search_page')}(m_internal, needle, hit_mark, hit_bbox, (int) ret.size()); ret.resize(n); return ret; }} ''', comment=f'/* Wrapper for fz_search_page(). */', ), ExtraMethod( f'{rename.class_("fz_document")}', 'doc()', f''' {{ return {rename.class_("fz_document")}( {rename.ll_fn('fz_keep_document')}( m_internal->doc)); }} ''', f'/* Returns wrapper for .doc member. */', ), ], constructor_raw = True, ), fz_path_walker = ClassExtra( constructor_raw = 'default', virtual_fnptrs = dict( self_ = lambda name: f'*({rename.class_("fz_path_walker")}2**) ((fz_path_walker*) {name} + 1)', alloc = textwrap.dedent( f''' m_internal = (::fz_path_walker*) {rename.ll_fn("fz_calloc")}( 1, sizeof(*m_internal) + sizeof({rename.class_("fz_path_walker")}2*) ); *({rename.class_("fz_path_walker")}2**) (m_internal + 1) = this; '''), free = f'{rename.ll_fn("fz_free")}(m_internal);\n', ), ), fz_pcl_options = ClassExtra( constructors_wrappers = [ 'fz_parse_pcl_options', ], copyable=False, ), fz_pclm_options = ClassExtra( constructor_prefixes = [ 'fz_parse_pclm_options', ], copyable=False, constructors_extra = [ ExtraConstructor( '(const char *args)', f''' {{ {rename.ll_fn('fz_parse_pclm_options')}(m_internal, args); }} ''', '/* Construct using fz_parse_pclm_options(). */', ) ], ), fz_pdfocr_options = ClassExtra( pod = 'inline', methods_extra = [ ExtraMethod( 'void', 'language_set2(const char* language)', f''' {{ fz_strlcpy(this->language, language, sizeof(this->language)); }} ''', '/* Copies into this->language, truncating if necessary. */', ), ExtraMethod( 'void', 'datadir_set2(const char* datadir)', f''' {{ fz_strlcpy(this->datadir, datadir, sizeof(this->datadir)); }} ''', '/* Copies into this->datadir, truncating if necessary. */', ), ], ), fz_pixmap = ClassExtra( methods_extra = [ ExtraMethod( 'std::vector', f'{rename.method( "fz_pixmap", "fz_md5_pixmap")}()', f''' {{ std::vector ret(16); {rename.ll_fn( 'fz_md5_pixmap')}( m_internal, &ret[0]); return ret; }} ''', f'/* Wrapper for fz_md5_pixmap(). */', ), ExtraMethod( 'long long', f'{rename.method( "fz_pixmap", "fz_pixmap_samples_int")}()', f''' {{ long long ret = (intptr_t) samples(); return ret; }} ''', f'/* Alternative to pixmap_samples() that returns pointer as integer. */', ), ExtraMethod( 'int', f'{rename.method( "fz_pixmap", "fz_samples_get")}(int offset)', f''' {{ return m_internal->samples[offset]; }} ''', f'/* Returns m_internal->samples[offset]. */', ), ExtraMethod( 'void', f'{rename.method( "fz_pixmap", "fz_samples_set")}(int offset, int value)', f''' {{ m_internal->samples[offset] = value; }} ''', f'/* Sets m_internal->samples[offset] to value. */', ), ], constructor_raw = True, accessors = True, ), fz_point = ClassExtra( method_wrappers_static = [ 'fz_transform_point', 'fz_transform_point_xy', 'fz_transform_vector', ], constructors_extra = [ ExtraConstructor( '(float x, float y)', ''' : x(x), y(y) { } ''', comment = '/* Construct using specified values. */', ), ], methods_extra = [ ExtraMethod( f'{rename.class_("fz_point")}&', f'transform(const {rename.class_("fz_matrix")}& m)', ''' { double old_x = x; x = old_x * m.a + y * m.c + m.e; y = old_x * m.b + y * m.d + m.f; return *this; } ''', comment = '/* Post-multiply *this by and return *this. */', ), ], pod='inline', constructor_raw = True, ), fz_pwg_options = ClassExtra( pod=True, ), fz_quad = ClassExtra( constructor_prefixes = [ 'fz_transform_quad', 'fz_quad_from_rect' ], pod='inline', constructor_raw = True, ), fz_rect = ClassExtra( constructor_prefixes = [ 'fz_transform_rect', 'fz_bound_display_list', 'fz_rect_from_irect', 'fz_rect_from_quad', ], method_wrappers_static = [ 'fz_intersect_rect', 'fz_union_rect', ], constructors_extra = [ ExtraConstructor( '(double x0, double y0, double x1, double y1)', ''' : x0(x0), x1(x1), y0(y0), y1(y1) { } ''', comment = '/* Construct from specified values. */', ), ExtraConstructor( f'(const {rename.class_("fz_rect")}& rhs)', ''' : x0(rhs.x0), x1(rhs.x1), y0(rhs.y0), y1(rhs.y1) { } ''', comment = '/* Copy constructor using plain copy. */', ), ExtraConstructor( '(Fixed fixed)', f''' {{ if (0) {{}} else if (fixed == Fixed_UNIT) *this->internal() = {rename.c_fn('fz_unit_rect')}; else if (fixed == Fixed_EMPTY) *this->internal() = {rename.c_fn('fz_empty_rect')}; else if (fixed == Fixed_INFINITE) *this->internal() = {rename.c_fn('fz_infinite_rect')}; else throw {rename.error_class('FZ_ERROR_ABORT')}( "Unrecognised From value"); }} ''', comment = '/* Construct from fz_unit_rect, fz_empty_rect or fz_infinite_rect. */', ), ], methods_extra = [ ExtraMethod( 'void', f'transform(const {rename.class_("fz_matrix")}& m)', f''' {{ *(::fz_rect*) &this->x0 = {rename.c_fn('fz_transform_rect')}(*(::fz_rect*) &this->x0, *(::fz_matrix*) &m.a); }} ''', comment = '/* Transforms *this using fz_transform_rect() with . */', ), ExtraMethod( 'bool', 'contains(double x, double y)', ''' { if (is_empty()) { return false; } return true && x >= x0 && x < x1 && y >= y0 && y < y1 ; } ''', comment = '/* Convenience method using fz_contains_rect(). */', ), ExtraMethod( 'bool', f'contains({rename.class_("fz_rect")}& rhs)', f''' {{ return {rename.c_fn('fz_contains_rect')}(*(::fz_rect*) &x0, *(::fz_rect*) &rhs.x0); }} ''', comment = '/* Uses fz_contains_rect(*this, rhs). */', ), ExtraMethod( 'bool', 'is_empty()', f''' {{ return {rename.c_fn('fz_is_empty_rect')}(*(::fz_rect*) &x0); }} ''', comment = '/* Uses fz_is_empty_rect(). */', ), ExtraMethod( 'void', f'union_({rename.class_("fz_rect")}& rhs)', f''' {{ *(::fz_rect*) &x0 = {rename.c_fn('fz_union_rect')}(*(::fz_rect*) &x0, *(::fz_rect*) &rhs.x0); }} ''', comment = '/* Updates *this using fz_union_rect(). */', ), ], pod='inline', constructor_raw = True, copyable = True, class_top = ''' enum Fixed { Fixed_UNIT, Fixed_EMPTY, Fixed_INFINITE, }; ''', ), fz_separations = ClassExtra( constructor_raw = 'default', opaque = True, ), fz_shade = ClassExtra( methods_extra = [ ExtraMethod( 'void', f'{rename.method( "fz_shade", "fz_paint_shade_no_cache")}(' + f' const {rename.class_("fz_colorspace")}& override_cs' + f', {rename.class_("fz_matrix")}& ctm' + f', const {rename.class_("fz_pixmap")}& dest' + f', {rename.class_("fz_color_params")}& color_params' + f', {rename.class_("fz_irect")}& bbox' + f', const {rename.class_("fz_overprint")}& eop' + f')' , f''' {{ return {rename.ll_fn('fz_paint_shade')}( this->m_internal, override_cs.m_internal, *(::fz_matrix*) &ctm.a, dest.m_internal, *(::fz_color_params*) &color_params.ri, *(::fz_irect*) &bbox.x0, eop.m_internal, NULL /*cache*/ ); }} ''', comment = f'/* Extra wrapper for fz_paint_shade(), passing cache=NULL. */', ), ], ), fz_shade_color_cache = ClassExtra( ), # Our wrappers of the fz_stext_* structs all have a default copy # constructor - there are no fz_keep_stext_*() functions. # # We define explicit accessors for fz_stext_block::u.i.* because SWIG # does not handle nested unions. # fz_stext_block = ClassExtra( iterator_next = ('u.t.first_line', 'u.t.last_line'), copyable='default', methods_extra = [ ExtraMethod( f'{rename.class_("fz_matrix")}', 'i_transform()', f''' {{ if (m_internal->type != FZ_STEXT_BLOCK_IMAGE) {{ throw std::runtime_error("Not an image"); }} return m_internal->u.i.transform; }} ''', comment=f'/* Returns m_internal.u.i.transform if m_internal->type is FZ_STEXT_BLOCK_IMAGE, else throws. */', ), ExtraMethod( f'{rename.class_("fz_image")}', 'i_image()', f''' {{ if (m_internal->type != FZ_STEXT_BLOCK_IMAGE) {{ throw std::runtime_error("Not an image"); }} return {rename.ll_fn('fz_keep_image')}(m_internal->u.i.image); }} ''', comment=f'/* Returns m_internal.u.i.image if m_internal->type is FZ_STEXT_BLOCK_IMAGE, else throws. */', ), ], ), fz_stext_char = ClassExtra( copyable='default', ), fz_stext_line = ClassExtra( iterator_next = ('first_char', 'last_char'), copyable='default', constructor_raw=True, ), fz_stext_options = ClassExtra( constructors_extra = [ ExtraConstructor( '(int flags)', ''' : flags( flags) { } ''', comment = '/* Construct with .flags set to . */', ), ], pod='inline', ), fz_stext_page = ClassExtra( methods_extra = [ ExtraMethod( 'std::string', f'{rename.method( "fz_stext_page", "fz_copy_selection")}(' + f'{rename.class_("fz_point")}& a' + f', {rename.class_("fz_point")}& b' + f', int crlf' + f')', f''' {{ char* text = {rename.ll_fn('fz_copy_selection')}(m_internal, *(::fz_point *) &a.x, *(::fz_point *) &b.x, crlf); std::string ret(text); {rename.ll_fn('fz_free')}(text); return ret; }} ''', comment = f'/* Wrapper for fz_copy_selection() that returns std::string. */', ), ExtraMethod( 'std::string', f'{rename.method( "fz_stext_page", "fz_copy_rectangle")}({rename.class_("fz_rect")}& area, int crlf)', f''' {{ char* text = {rename.ll_fn('fz_copy_rectangle')}(m_internal, *(::fz_rect*) &area.x0, crlf); std::string ret(text); {rename.ll_fn('fz_free')}(text); return ret; }} ''', comment = f'/* Wrapper for fz_copy_rectangle() that returns a std::string. */', ), ExtraMethod( f'std::vector<{rename.class_("fz_quad")}>', f'{rename.method( "fz_stext_page", "search_stext_page")}(const char* needle, int *hit_mark, int max_quads)', f''' {{ std::vector<{rename.class_("fz_quad")}> ret(max_quads); int n = {rename.ll_fn('fz_search_stext_page')}(m_internal, needle, hit_mark, ret[0].internal(), max_quads); ret.resize(n); return ret; }} ''', '/* Wrapper for fz_search_stext_page() that returns std::vector of Quads. */', ) ], iterator_next = ('first_block', 'last_block'), copyable=False, constructor_raw = True, ), fz_text_span = ClassExtra( copyable=False, methods_extra = [ # We provide class-aware accessors where possible. (Some # types' wrapper classes are not copyable so we can't do # this for all data). ExtraMethod( f'{rename.class_("fz_font")}', f'font()', f''' {{ return {rename.class_("fz_font")}( ll_fz_keep_font( m_internal->font)); }} ''', f'/* Gives class-aware access to m_internal->font. */', ), ExtraMethod( f'{rename.class_("fz_matrix")}', f'trm()', f''' {{ return {rename.class_("fz_matrix")}( m_internal->trm); }} ''', f'/* Gives class-aware access to m_internal->trm. */', ), ExtraMethod( f'fz_text_item&', f'items( int i)', f''' {{ assert( i < m_internal->len); return m_internal->items[i]; }} ''', ''' /* Gives access to m_internal->items[i]. Returned reference is only valid as long as `this`. Provided mainly for use by SWIG bindings. */ ''', ), ], ), fz_stream = ClassExtra( constructor_prefixes = [ 'fz_open_file', 'fz_open_memory', ], constructors_extra = [ ExtraConstructor( '(const std::string& filename)', f''' : m_internal({rename.ll_fn('fz_open_file')}(filename.c_str())) {{ }} ''', comment = '/* Construct using fz_open_file(). */', ) ], ), fz_story_element_position = ClassExtra( pod='inline', ), fz_transition = ClassExtra( pod='inline', constructor_raw = True, ), pdf_annot = ClassExtra( constructor_raw = 'default', ), pdf_document = ClassExtra( constructor_prefixes = [ 'pdf_open_document', 'pdf_create_document', 'pdf_document_from_fz_document', ], methods_extra = [ # This duplicates our creation of extra lookup_metadata() # function in make_function_wrappers(). Maybe we could # parse the generated functions.h instead of fitz.h so that # we pick up extra C++ wrappers automatically, but this # would be a fairly major change. # ExtraMethod( 'std::string', f'{rename.method("pdf_document", "pdf_lookup_metadata")}(const char* key, int* o_out=NULL)', f''' {{ return {rename.ll_fn("pdf_lookup_metadata")}(m_internal, key, o_out); }} ''', textwrap.dedent(''' /* Wrapper for pdf_lookup_metadata() that returns a std::string and sets *o_out to length of string plus one. If is not found, returns empty string with *o_out=-1. can be NULL if caller is not interested in error information. */ ''') ), ExtraMethod( f'{rename.class_("fz_document")}', 'super()', f''' {{ return {rename.class_("fz_document")}( {rename.ll_fn('fz_keep_document')}( &m_internal->super)); }} ''', f'/* Returns wrapper for .super member. */', ), ], ), pdf_filter_factory = ClassExtra( pod = 'inline', virtual_fnptrs = dict( self_ = lambda name: f'({rename.class_("pdf_filter_factory")}2*) {name}', self_n = 6, alloc = f'this->options = this;\n', ), ), pdf_filter_options = ClassExtra( pod = 'inline', # We don't need to allocate extra space, and because we are a # POD class, we can simply let our default constructor run. # virtual_fnptrs = dict( self_ = lambda name: f'({rename.class_("pdf_filter_options")}2*) {name}', self_n = 2, alloc = f'this->opaque = this;\n', ), constructors_extra = [ ExtraConstructor( '()', f''' {{ this->recurse = 0; this->instance_forms = 0; this->ascii = 0; this->opaque = nullptr; this->complete = nullptr; this->filters = nullptr; pdf_filter_factory eof = {{ nullptr, nullptr}}; m_filters.push_back( eof); }} ''', comment = '/* Default constructor initialises all fields to null/zero. */', ) ], methods_extra = [ ExtraMethod( 'void', f'add_factory( const pdf_filter_factory& factory)', textwrap.dedent( f''' {{ this->m_filters.back() = factory; pdf_filter_factory eof = {{ nullptr, nullptr}}; this->m_filters.push_back( eof); this->filters = &this->m_filters[0]; }} '''), comment = f'/* Appends `factory` to internal vector and updates this->filters. */', ), ], class_bottom = textwrap.dedent( f''' std::vector< pdf_filter_factory> m_filters; '''), ), pdf_lexbuf = ClassExtra( constructors_extra = [ ExtraConstructor( '(int size)', f''' {{ m_internal = new ::pdf_lexbuf; {rename.ll_fn('pdf_lexbuf_init')}(m_internal, size); }} ''', comment = '/* Constructor that calls pdf_lexbuf_init(size). */', ), ], methods_extra = [ ExtraMethod( '', '~()', f''' {{ {rename.ll_fn('pdf_lexbuf_fin')}(m_internal); delete m_internal; }} ''', comment = '/* Destructor that calls pdf_lexbuf_fin(). */', ), ], ), pdf_layer_config = ClassExtra( pod = 'inline', ), pdf_layer_config_ui = ClassExtra( pod = 'inline', constructors_extra = [ ExtraConstructor( '()', f''' {{ this->text = nullptr; this->depth = 0; this->type = PDF_LAYER_UI_LABEL; this->selected = 0; this->locked = 0; }} ''', comment = '/* Default constructor sets .text to null, .type to PDF_LAYER_UI_LABEL, and other fields to zero. */', ), ], ), pdf_obj = ClassExtra( constructor_raw = 'default', methods_extra = [ ExtraMethod( f'{rename.class_("pdf_obj")}', f'{rename.method( "pdf_obj", "pdf_dict_get")}(int key)', f''' {{ ::pdf_obj* temp = {rename.ll_fn('pdf_dict_get')}(this->m_internal, (::pdf_obj*)(uintptr_t) key); {rename.ll_fn('pdf_keep_obj')}(temp); auto ret = {rename.class_('pdf_obj')}(temp); return ret; }} ''', comment = '/* Typesafe wrapper for looking up things such as PDF_ENUM_NAME_Annots. */', overload=True, ), ExtraMethod( f'std::string', f'{rename.method( "pdf_obj", "pdf_field_name2")}()', f''' {{ return {rename.namespace_fn('pdf_field_name2')}( *this); }} ''', comment = f'/* Alternative to `{rename.fn("pdf_field_name")}()` that returns a std::string. */', ), ] ), pdf_page = ClassExtra( methods_extra = [ ExtraMethod( f'{rename.class_("fz_page")}', 'super()', f''' {{ return {rename.class_("fz_page")}( {rename.ll_fn('fz_keep_page')}( &m_internal->super)); }} ''', f'/* Returns wrapper for .super member. */', ), ExtraMethod( f'{rename.class_("pdf_document")}', 'doc()', f''' {{ return {rename.class_("pdf_document")}( {rename.ll_fn('pdf_keep_document')}( m_internal->doc)); }} ''', f'/* Returns wrapper for .doc member. */', ), ExtraMethod( f'{rename.class_("pdf_obj")}', 'obj()', f''' {{ return {rename.class_("pdf_obj")}( {rename.ll_fn('pdf_keep_obj')}( m_internal->obj)); }} ''', f'/* Returns wrapper for .obj member. */', ), ], copyable = 'default', ), pdf_processor = ClassExtra( virtual_fnptrs = dict( self_ = lambda name: f'(*({rename.class_("pdf_processor")}2**) ({name} + 1))', alloc = textwrap.dedent( f''' m_internal = (::pdf_processor*) {rename.ll_fn("pdf_new_processor")}( sizeof(*m_internal) + sizeof({rename.class_("pdf_processor")}2*) ); *(({rename.class_("pdf_processor")}2**) (m_internal + 1)) = this; '''), ), ), pdf_redact_options = ClassExtra( pod = 'inline', ), pdf_sanitize_filter_options = ClassExtra( pod = 'inline', # We don't need to allocate extra space, and because we are a # POD class, we can simply let our default constructor run. # virtual_fnptrs = dict( self_ = lambda name: f'({rename.class_("pdf_sanitize_filter_options")}2*) {name}', alloc = f'this->opaque = this;\n', ), ), pdf_write_options = ClassExtra( constructors_extra = [ ExtraConstructor( '()', f''' {{ /* Use memcpy() otherwise we get 'invalid array assignment' errors. */ memcpy(this->internal(), &pdf_default_write_options, sizeof(*this->internal())); }} ''', comment = '/* Default constructor, makes copy of pdf_default_write_options. */' ), ExtraConstructor( f'(const {rename.class_("pdf_write_options")}& rhs)', f''' {{ *this = rhs; }} ''', comment = '/* Copy constructor using raw memcopy(). */' ), ], methods_extra = [ ExtraMethod( f'{rename.class_("pdf_write_options")}&', f'operator=(const {rename.class_("pdf_write_options")}& rhs)', f''' {{ memcpy(this->internal(), rhs.internal(), sizeof(*this->internal())); return *this; }} ''', comment = '/* Assignment using plain memcpy(). */', ), ExtraMethod( # Would prefer to call this opwd_utf8_set() but # this conflicts with SWIG-generated accessor for # opwd_utf8. f'void', f'opwd_utf8_set_value(const std::string& text)', f''' {{ size_t len = std::min(text.size(), sizeof(opwd_utf8) - 1); memcpy(opwd_utf8, text.c_str(), len); opwd_utf8[len] = 0; }} ''', '/* Copies into opwd_utf8[]. */', ), ExtraMethod( f'void', f'upwd_utf8_set_value(const std::string& text)', f''' {{ size_t len = std::min(text.size(), sizeof(upwd_utf8) - 1); memcpy(upwd_utf8, text.c_str(), len); upwd_utf8[len] = 0; }} ''', '/* Copies into upwd_utf8[]. */', ), ], pod = 'inline', copyable = 'default', ) )