Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions PDFTronGo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,70 @@ execute_process(
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)

# ------------------------------------------------------------------------------
# HACK: Post-processing of SWIG-generated Go bindings
#
# The C++ API uses ElementRef<T> as a value-type wrapper representing an optional
# reference (IsValid() + GetElement()).
#
# Attempts to erase or re-map ElementRef<T> using SWIG Go typemaps (gotype,
# ctype, imtype, etc.) lead to unstable or invalid generated code, including:
# - incorrect C wrapper signatures (value return vs pointer return)
# - broken Go code (C++ typedefs emitted into .go files)
# - ABI mismatches and compilation errors
#
# To produce a stable and idiomatic Go API, we intentionally:
# 1) Let SWIG generate bindings using ElementRef<T> internally
# 2) Use Go-side typemaps only for final semantic conversion (Ref -> T | nil)
# 3) Post-process the generated *.go files to erase the use of artificial '*Ref'
# types from the public Go API
#
# This post-processing step rewrites:
# - function return types (e.g. FooRef -> Foo)
# - local variables using Ref types
# ------------------------------------------------------------------------------
file(GLOB_RECURSE GO_FILES "${BUILD_DIR}/*.go")

set(ELEMENT_REF_TYPES
ContentNode
Paragraph
TextRun
Table
TableRow
TableCell
List
ListItem
)

file(GLOB_RECURSE GO_FILES "${BUILD_DIR}/*.go")

foreach(GO_FILE ${GO_FILES})
file(READ "${GO_FILE}" GO_FILE_CONTENT)

foreach(TYPE ${ELEMENT_REF_TYPES})
# Fix function return types:
# (_swig_ret ContentNodeRef) -> (_swig_ret ContentNode)
string(REPLACE
"As${TYPE}() (_swig_ret ${TYPE}Ref)"
"As${TYPE}() (_swig_ret ${TYPE})"
GO_FILE_CONTENT
"${GO_FILE_CONTENT}"
)

# Fix local variable declarations:
# var swig_r_1 ContentNodeRef -> var swig_r_1 ContentNode
string(REPLACE
"var swig_r_1 ${TYPE}Ref"
"var swig_r_1 ${TYPE}"
GO_FILE_CONTENT
"${GO_FILE_CONTENT}"
)
endforeach()

file(WRITE "${GO_FILE}" "${GO_FILE_CONTENT}")
endforeach()


if ("${SOURCE_GEN_RESULT}" STREQUAL "0")
message(STATUS "Generating sources for Go bindings using swig... OK")
else ()
Expand Down
52 changes: 52 additions & 0 deletions PDFTronGo/pdftron.i
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@
#include "SDF/ResultSnapshot.h"
#include "SDF/DocSnapshot.h"

// header files in /PDFNetC/Headers/Layout
#include "Layout/FlowDocument.h"
#include "Layout/ContentTree.h"

using namespace pdftron;
using namespace FDF;
using namespace Filters;
Expand Down Expand Up @@ -378,6 +382,7 @@ namespace pdftron {
%template (FieldIterator) pdftron::Common::Iterator<pdftron::PDF::Field>;
%template (CharIterator) pdftron::Common::Iterator<TRN_CharData>;
%template (DigitalSignatureFieldIterator) pdftron::Common::Iterator<pdftron::PDF::DigitalSignatureField>;
%template (ContentNodeIterator) pdftron::Common::Iterator<pdftron::Layout::ContentElement>;

//----------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -548,6 +553,53 @@ namespace pdftron {
%include "PDF/WebFontDownloader.h"
%include "PDF/PDFNetInternalTools.h"

/*
* Attempting to handle ElementRef<T> via SWIG typemaps (gotype/ctype/imtype)
* causes the SWIG Go backend to generate invalid or unstable code:
* - incorrect C wrapper signatures (value vs pointer returns)
* - broken Go code (C++ typedefs leaked into .go files)
* - ABI mismatches and undefined behavior
*
* This typemap exists only to perform the last-step conversion from
* ElementRef<T> semantics to idiomatic Go semantics:
*
* ElementRef<T> -> T | nil
*
* The remaining cleanup (removing Ref suffixes, fixing return types, etc.)
* is handled by a controlled post-processing step on the generated Go code
* in CMakeLists.txt.
*/
%define ELEMENT_REF_GOOUT(T)
%typemap(goout) pdftron::Layout::ElementRef<T> {
if (!($1).IsValid()) {
$result = nil
} else {
$result = ($1).GetElement()
}
}
%enddef

ELEMENT_REF_GOOUT(pdftron::Layout::ContentNode)
ELEMENT_REF_GOOUT(pdftron::Layout::Paragraph)
ELEMENT_REF_GOOUT(pdftron::Layout::TextRun)
ELEMENT_REF_GOOUT(pdftron::Layout::Table)
ELEMENT_REF_GOOUT(pdftron::Layout::TableRow)
ELEMENT_REF_GOOUT(pdftron::Layout::TableCell)
ELEMENT_REF_GOOUT(pdftron::Layout::List)
ELEMENT_REF_GOOUT(pdftron::Layout::ListItem)

%include "Layout/ContentTree.h"
%include "Layout/FlowDocument.h"

%template(ContentNodeRef) pdftron::Layout::ElementRef<pdftron::Layout::ContentNode>;
%template(ParagraphRef) pdftron::Layout::ElementRef<pdftron::Layout::Paragraph>;
%template(TextRunRef) pdftron::Layout::ElementRef<pdftron::Layout::TextRun>;
%template(TableRef) pdftron::Layout::ElementRef<pdftron::Layout::Table>;
%template(TableRowRef) pdftron::Layout::ElementRef<pdftron::Layout::TableRow>;
%template(TableCellRef) pdftron::Layout::ElementRef<pdftron::Layout::TableCell>;
%template(ListRef) pdftron::Layout::ElementRef<pdftron::Layout::List>;
%template(ListItemRef) pdftron::Layout::ElementRef<pdftron::Layout::ListItem>;

//Extend Initialize method to call overloaded one internally
%extend pdftron::PDFNet{
public:
Expand Down
Loading