@@ -483,64 +483,158 @@ def run_task_test():
483483
484484# -----------------------------------------------------------------------------
485485def run_task_test_wasmtime ():
486- import wasmtime
487- from wasmtime import Engine , Func , Instance , Linker , Module , Store
488- from wasmtime . loader import WasiConfig
486+ from pathlib import Path
487+
488+ from wasmtime import Engine , FuncType , Linker , Module , Store , WasiConfig
489489
490490 l .colored ("Testing with wasmtime..." , l .YELLOW )
491491
492492 current_dir = f .current_dir ()
493493
494- for target in c .targets_wasm :
495- # paths
496- relative_dir = os .path .join (
497- "build" ,
498- target ["target_os" ],
499- target ["target_cpu" ],
500- )
494+ for config in c .configurations_wasm :
495+ for target in c .targets_wasm :
496+ l .colored (
497+ 'Testing arch "{0}" and configuration "{1}"...' .format (
498+ target ["target_cpu" ], config
499+ ),
500+ l .YELLOW ,
501+ )
502+
503+ # paths
504+ relative_dir = os .path .join (
505+ "build" ,
506+ target ["target_os" ],
507+ target ["target_cpu" ],
508+ config ,
509+ )
510+
511+ root_dir = os .path .join (current_dir , relative_dir )
512+ node_dir = os .path .join (root_dir , "node" )
513+ wasm_file = os .path .join (node_dir , "pdfium.std.wasm" )
514+
515+ # check if wasm file exists
516+ if not f .file_exists (wasm_file ):
517+ l .e (f"WASM file not found: { wasm_file } " )
518+ continue
519+
520+ l .bullet (f"WASM file: { wasm_file } " , l .YELLOW )
521+
522+ # create engine and load the pdfium.wasm module
523+ engine = Engine ()
524+ module = Module .from_file (engine , wasm_file )
525+
526+ # create WASI context and store
527+ wasi_config = WasiConfig ()
528+ wasi_config .inherit_stdin ()
529+ wasi_config .inherit_stdout ()
530+ wasi_config .inherit_stderr ()
531+
532+ store = Store (engine )
533+ store .set_wasi (wasi_config )
534+
535+ # create a linker and add WASI support
536+ linker = Linker (engine )
537+ linker .define_wasi ()
538+
539+ # define stub functions for unknown imports
540+ for imp in module .imports :
541+ module_name = imp .module
542+ field_name = imp .name
543+
544+ # check if this is a function import
545+ if isinstance (imp .type , FuncType ):
546+ func_type = imp .type
547+
548+ # create a stub function that returns default values
549+ def make_stub (ft ):
550+ def stub_func (* _args ):
551+ # return default values (0 or None) based on results
552+ if ft .results :
553+ if len (ft .results ) == 1 :
554+ return 0
555+ return tuple (0 for _ in ft .results )
556+ return None
557+
558+ return stub_func
559+
560+ try :
561+ linker .define_func (
562+ module_name , field_name , func_type , make_stub (func_type )
563+ )
564+ except Exception :
565+ # already defined (e.g., by WASI)
566+ pass
567+
568+ # instantiate the module
569+ instance = linker .instantiate (store , module )
570+ exports = instance .exports (store )
571+
572+ # get and call FPDF_InitLibrary function
573+ try :
574+ init_library = exports ["FPDF_InitLibrary" ]
575+ init_library (store )
576+ l .bullet ("FPDF_InitLibrary successfully called" , l .GREEN )
577+ except KeyError :
578+ l .e ("Function 'FPDF_InitLibrary' not found" )
579+ continue
580+
581+ # test with a sample PDF file
582+ sample_pdf = os .path .join (
583+ current_dir , "sample-wasm" , "assets" , "web-assembly.pdf"
584+ )
585+
586+ if not f .file_exists (sample_pdf ):
587+ l .bullet ("Sample PDF not found, skipping document test" , l .PURPLE )
588+ continue
589+
590+ l .bullet (f"Testing with PDF: { sample_pdf } " , l .YELLOW )
591+
592+ # read PDF data
593+ pdf_path = Path (sample_pdf )
594+ pdf_data = pdf_path .read_bytes ()
595+
596+ # allocate memory for the PDF data
597+ malloc = exports ["malloc" ]
598+ memory = exports ["memory" ]
599+
600+ # allocate buffer in WASM memory
601+ buf_ptr = malloc (store , len (pdf_data ))
602+ mem_data = memory .data_ptr (store )
603+
604+ # copy PDF data to WASM memory
605+ for i , byte in enumerate (pdf_data ):
606+ mem_data [buf_ptr + i ] = byte
501607
502- root_dir = os .path .join (current_dir , relative_dir )
503- gen_dir = os .path .join (root_dir , "gen" )
504- gen_out_dir = os .path .join (gen_dir , "out" )
505- wasm_file = os .path .join (gen_out_dir , "pdfium.std.wasm" )
506-
507- # create the engine and store
508- engine = Engine ()
509- store = Store (engine )
510-
511- # load the WebAssembly module
512- module = Module .from_file (engine , wasm_file )
513-
514- # create a linker to provide the necessary imports
515- linker = Linker (engine )
516-
517- # WASI support using wasmtime.loader.WasiConfig
518- wasi_config = WasiConfig ()
519- wasi_config .inherit_stdin ()
520- wasi_config .inherit_stdout ()
521- wasi_config .inherit_stderr ()
522- store .set_wasi (wasi_config )
523-
524- # instantiate the WebAssembly module with linker
525- instance = linker .instantiate (store , module )
526-
527- # now we can invoke exported functions from the WebAssembly module
528- try :
529- init_library = instance .exports (store )["FPDF_InitLibrary" ]
530- init_library (store )
531- l .i ("FPDF_InitLibrary successfully called." )
532- except KeyError :
533- l .e ("Function 'FPDF_InitLibrary' not found." )
534-
535- # invoke 'FPDF_GetLastError'
536- try :
537- get_last_error = instance .exports (store )["FPDF_GetLastError" ]
538- result = get_last_error (store )
539- l .i (f"Result from FPDF_GetLastError: { result } " )
540- except KeyError :
541- l .e ("Function 'FPDF_GetLastError' not found." )
542-
543- l .i (f"Result: { result } " )
608+ # load the PDF document from memory
609+ fpdf_load_mem_document = exports ["FPDF_LoadMemDocument" ]
610+ doc = fpdf_load_mem_document (store , buf_ptr , len (pdf_data ), 0 )
611+
612+ if doc == 0 :
613+ get_last_error = exports ["FPDF_GetLastError" ]
614+ error = get_last_error (store )
615+ l .e (f"Failed to load PDF. Error code: { error } " )
616+
617+ # free the allocated memory
618+ free = exports ["free" ]
619+ free (store , buf_ptr )
620+ continue
621+
622+ # get page count
623+ fpdf_get_page_count = exports ["FPDF_GetPageCount" ]
624+ page_count = fpdf_get_page_count (store , doc )
625+
626+ l .bullet (f"PDF: { pdf_path .name } " , l .GREEN )
627+ l .bullet (f"Number of pages: { page_count } " , l .GREEN )
628+
629+ # close the document
630+ fpdf_close_document = exports ["FPDF_CloseDocument" ]
631+ fpdf_close_document (store , doc )
632+
633+ # free the allocated memory
634+ free = exports ["free" ]
635+ free (store , buf_ptr )
636+
637+ l .bullet ("Test completed successfully" , l .GREEN )
544638
545639 l .ok ()
546640
@@ -655,7 +749,8 @@ def run_task_generate():
655749 "{0}" .format ("-g" if config == "debug" else "-O2" ),
656750 "-s" ,
657751 f"EXPORTED_FUNCTIONS={ complete_functions_list } " ,
658- "-s" , "ALLOW_TABLE_GROWTH" ,
752+ "-s" ,
753+ "ALLOW_TABLE_GROWTH" ,
659754 "-s" ,
660755 'EXPORTED_RUNTIME_METHODS=\' ["ccall", "cwrap", "wasmExports", "HEAP8", "HEAP16", "HEAP32", "HEAPU8", "HEAPU16", "HEAPU32", "HEAPF32", "HEAPF64", "addFunction", "removeFunction", "setValue"]\' ' ,
661756 "custom.cpp" ,
@@ -848,7 +943,9 @@ def run_task_archive():
848943 )
849944
850945 # Create per config "npm install"-compatible tarball
851- per_config_tar = tarfile .open (os .path .join (current_dir , f"wasm-{ config } .tgz" ), "w:gz" )
946+ per_config_tar = tarfile .open (
947+ os .path .join (current_dir , f"wasm-{ config } .tgz" ), "w:gz"
948+ )
852949 per_config_tar .add (
853950 name = lib_dir ,
854951 # Use "package" as the root directory to be compatible with "npm install"
0 commit comments