Free Pascal and Lazarus support
HotXLS supports Free Pascal 3.2.2 with Lazarus/LCL on Windows Win32 and Win64, including XLS/XLSX workbook APIs, formulas, formatting, direct streaming, the TDataToXLS and TGridToXLS export components and rendering helpers
Native Linux and macOS workbook core
See compound file storage for scoped directory APIs, explicit native storage ownership, timestamps and canonical Classic identifier keys
The opt-in LX_PORTABLE_CORE profile exposes TXLSWorkbook and TXLSXWorkbook without LCL on Linux and macOS. Native Linux x64 and macOS ARM64 have been compiled and executed with Free Pascal 3.3.1; the source version guard requires at least 3.2.2, but that minimum is not a claim that every native compiler and target combination has been validated
Put cthreads and cwstring before the HotXLS units, add Lib to the unit and include paths, and define LX_PORTABLE_CORE for the entire build. A native console application does not require Interfaces or an LCL widgetset
Select an installed UTF-8 locale in the application environment when working with Unicode filesystem paths. An invalid or non-UTF-8 locale can make the native RTL filename conversion lossy; the validation helper rejects that environment explicitly instead of changing the locale or guessing a codepage
program NativeWorkbookExample;
{$mode delphiunicode}
uses
cthreads, cwstring, SysUtils, lxHandleX;
var
Workbook: TXLSXWorkbook;
begin
Workbook:= TXLSXWorkbook.Create;
try
Workbook.Sheets.Add('Data').Cells[1, 1].Value:= 5;
Workbook.Sheets[1].Cells[1, 2].Formula:= 'A1*2';
if Workbook.Recalculate<> 1 then
raise Exception.Create('Workbook calculation failed');
if Workbook.SaveAs('native.xlsx')<> 1 then
raise Exception.Create('Workbook save failed');
finally
Workbook.Free;
end;
end.
| Area | Native core contract |
|---|---|
| Workbook files | Create, open, edit, calculate and save Classic BIFF8 XLS, XLSX, the supported expanded XLSB subset and the supported ODS subset through the public workbook APIs, with their existing conversion checks and format boundaries. Classic BIFF2 records with explicitly declared CP1252 and CP932 encodings have also been validated through import and Unicode BIFF8 export |
| Unicode and names | Workbook text retains UTF-16 semantics and filesystem paths use UTF-8 at native boundaries. Defined-name identity uses pinned Unicode 16 canonical normalization and BMP full case folding, preserving symbols, accents, Turkish distinctions and astral case identity independently of the host locale; qualified formulas retain their exact sheet scope. Ordinary worksheet text ordering still uses the native RTL locale comparison |
| Infrastructure | Native critical sections, full-width thread identifiers, real worker threads, registered exclusive temporary files, atomic sibling-file replacement and operating-system random bytes are used without Windows emulation |
| Compression and cryptography | Bundled Pascal ZIP/compression and AES remain available. Classic RC4 and RC4 CryptoAPI XLS files can be read and written natively using operating-system random bytes. Native encrypted OOXML reads use the pure compound-file reader; writing an encrypted OOXML compound file requires Windows and raises an explicit platform exception on native Unix |
| Formula REGEX functions | The pinned static PCRE2 UTF-16 backend is compiled on the native target with its C compiler. Run sh Lib/thirdparty/build-pcre2-unix.sh before compiling applications that include the formula engine; Linux x64 and macOS ARM64 static targets are provided |
| Windows services | Clipboard access, Windows COM activation, built-in ADO/WinHTTP query providers, GDI geometry capture, HTML background image decoding and legacy PDF export raise EXLSPlatformUnsupported at their explicit boundaries. Custom query providers and text providers remain usable |
| Legacy components | The Classic workbook model and BIFF reader/writer are available in the native core. The LCL runtime package, dataset/grid export components and visual controls remain Windows/LCL components. Classic clipboard methods, HTML export and legacy PDF export raise explicit platform exceptions on native Unix |
| Byte-oriented text formulas | Functions that require the Windows active ANSI/DBCS codepage return an explicit unsupported formula result (#NAME?) on native Unix; no implicit locale or codepage substitute is chosen |
Open and save methods retain their normal result-code and diagnostic contracts. Direct platform-boundary calls can raise EXLSPlatformUnsupported; handle this exception when invoking a Windows-only service from shared application code
Reproducible native validation
Run the validation helper on the native guest with an existing Free Pascal toolchain, Python 3 and a native C compiler. Choose a new or empty output directory outside the source checkout on the guest filesystem
python3 Tests/Lazarus/run_native_core.py --fpc /path/to/fpc --output /guest-local/hotxls-validation
python3 Tests/Lazarus/run_native_core.py --fpc /path/to/fpc --config /path/to/fpc.cfg --output /guest-local/hotxls-validation-2
The helper copies and hashes the source inputs, normalizes Pascal unit filenames in the private build copy for FPC's case-sensitive filename search, builds PCRE2 locally, and runs core, AES, compression, REGEX, public workbook and integration witnesses. It preserves source manifests, compiler logs, artifacts and failures without changing the checkout, installing tools or editing compiler configuration. macOS ARM64 builds explicitly target macOS 11 or later
The integration witnesses include Unicode paths, Excel-authored XLSB fixtures, formula caches and recalculation, repeated opens, sparse ODS notes and protection, checked conversion rejection, cancellation that preserves caller destinations, invariant scoped name lookup, real worker failure containment and cryptographic random bytes
Native Classic XLS contracts
Use lxHandle for Classic TXLSWorkbook and lxHandleX for TXLSXWorkbook. Classic Recalculate returns an error count, so zero means success; its Calculate method returns a formula result. Classic cell Formula assignments require a leading =. Workbook open and save methods keep their established success result of 1
The native Classic storage implementation uses real compound-file hierarchy and stream identities, preserving nested scopes, MiniFAT data and extended DIFAT chains. Stream payloads are materialized and the writer rejects aggregate output beyond its supported signed 32-bit buffer/sector bounds before emitting it; this is not a multi-gigabyte streaming storage implementation
Native compound storage provides direct stream operations, enumeration, metadata and copy operations. Transaction rollback, region locking, move and unsupported exclusion modes return explicit storage errors. It does not emulate Windows COM, clipboard or GDI services
Classic native file saves serialize before atomically replacing a registered sibling file. Caller stream saves stage the complete compound file before copying at the original position, preserving prefixes and cancellation failures before commit. The final progress notification remains non-cancellable. Direct compound-storage helper writes follow their ordinary direct-write contract rather than the public workbook save transaction
Ordinary summary and document-summary properties use bounded standard OLE property sets with Unicode text and UTC FILETIME timestamps. These property streams remain plaintext when Classic workbook data is encrypted, and the RC4 CryptoAPI header explicitly records that choice. Defined names share the pinned canonical identifier keys used by the XLSX facade, while retaining their original spelling and explicit worksheet scope. Encoded PNG/JPEG drawing data remains available to the model; native bitmap/metafile conversion requires a separate supported renderer and otherwise raises EXLSPlatformUnsupported
Compile Tests/Lazarus/HotXLSNativeClassicWorkbookSmoke.lpr with the same native core options, then pass Tests/Fixtures/classic-native/native-classic.xls, a disposable guest-local output path and Tests/Fixtures/classic-native/native-classic-encrypted.xls. The controls cover Excel-authored caches, recalculation, exact Unicode names, plain and encrypted round trips, independently decoded property timestamps, repeated opens, more than 16 MB of SST data and caller output preservation
Legacy BIFF byte encoding
TXLSWorkbook.SetCodePage selects the explicit byte encoding used by SaveAs(..., xlExcel5), with CP1252 as the default; importing a BIFF2–BIFF5 file with a usable nonzero CODEPAGE record also selects that page for later legacy saves
Legacy cell labels, formula text constants and arrays, cached formula strings, defined names, worksheet names and references, font names, number formats, style names, headers, footers, and ordinary comment text use that declared page rather than the operating system locale or UTF-8
Record lengths and worksheet stream offsets count encoded bytes; the existing 255-byte legacy label and formula-literal limits truncate only at a whole character boundary, so a CP932 double-byte character is never split; names and metadata with a one-byte length reject encoded text longer than their representable length instead of emitting an invalid length
Text that cannot round-trip through the selected code page raises EConvertError before it can silently become a replacement or best-fit character; select a page that represents the document text, or save as BIFF8 for Unicode strings
Formula-cache strings spanning CONTINUE records are assembled as bytes before decoding, so a record boundary can split a double-byte character without corrupting the cached value
Changing the selected page rebuilds typed legacy formula and defined-name bytes from their Unicode model; BIFF8 saves continue to use Unicode and their on-disk CODEPAGE value remains 1200
Imported BIFF5 chart records retain their original code page for typed series and attached-title inspection, including after a workbook codepage edit or chart copy; saving to a different page explicitly transcodes supported SeriesText, plain cached labels and formula strings, headers, footers, and current-workbook external-sheet names rather than reinterpreting preserved bytes under the new declaration
Continued chart text, unmodeled legacy external-sheet encodings and opaque legacy byte-text records reject a codepage migration with EConvertError; unrepresentable supported text also rejects, and the public workbook save preserves the caller destination before commit; this text contract does not promise full native chart appearance conversion
BIFF5 custom style names begin immediately after the one-byte encoded length, while BIFF5 SeriesText has an identifier and one-byte encoded length without a Unicode flag; BIFF8 SeriesText adds its Unicode flag, and converting supported chart text updates that record and the chart BOF version together
Nonempty BIFF5 chart headers and footers use a one-byte encoded length with a 255-byte maximum; cached LABEL and STRING records use two-byte lengths, while BIFF8 headers and footers use a two-byte UTF-16 length plus their Unicode flag; migration checks each record's actual layout and rejects an oversized legacy header or footer with ERangeError before appending it
HotXLS interprets legacy bytes using their declared page on Windows, Linux, and macOS; the installed Excel 16.0 build 20430 independently demonstrated a recipient limitation: it interpreted legacy bytes using its local Windows CP936 even after a native file's CODEPAGE record alone was changed to CP1252 or CP932, so correct declared bytes do not guarantee matching text in that recipient configuration
Preserve the document's actual encoding declaration and test the receiving application when distributing BIFF5 across different locale configurations; Unicode BIFF8 avoids this particular legacy-byte interoperability boundary
This byte-encoding correction retains the existing BIFF5 ordinary-comment record size limit; it does not add comment author, rich-text formatting or shape geometry fields to the legacy record
VBA module source editing uses the project's declared byte codepage and preserves the binary prefix before the source offset, including embedded null bytes; this changes stored source text and does not execute macros
BIFF8 compressed Unicode with fHighByte = 0 maps each byte directly to a U+0000 through U+00FF UTF-16 code unit; it is not CP1252, UTF-8 or the file's legacy code page, even when a nonstandard CODEPAGE record appears in an otherwise BIFF8 file
Native text formulas retain UTF-16 lengths and positions, including surrogate-pair code units; Unicode LOWER, UPPER, SEARCH, TEXTBEFORE/TEXTAFTER case-insensitive delimiters, database field headers, case-insensitive criteria and dynamic text keys use the native compiler's Unicode character data rather than the host C locale's ASCII-only casing functions, while ordinary worksheet ordering retains its existing locale comparison
Native LET/LAMBDA local-name matching and local-array storage classification use the same Unicode-aware casing, so case counterparts resolve the correct captured binding and retain its array shape; this does not change the pinned public defined-name identity contract
Classic case-insensitive FindText and ReplaceText retain Unicode character matching for literal and Excel wildcard searches on native FPC; MatchCase still distinguishes case, literal replacement keeps its replace-all behavior, wildcard replacement keeps its existing leftmost-span behavior, and formula cells remain excluded
Compile Tests/Lazarus/HotXLSNativeLegacyEncodingSmoke.lpr with the native core options and pass a disposable output directory followed by Tests/Fixtures/legacy-encoding/native-biff5-cp936-chart.xls; the witness checks declared CP1252, CP932 and CP936 bytes independently, every worksheet offset, codepage changes, double-byte continuation boundaries, compressed BIFF8 import, formula calculation, native-authored chart text and failed-save destination preservation
Full installer
The full installer detects Lazarus and supports installation without RAD Studio. Select Lazarus / Free Pascal on the IDE Integration page to install the runtime package, compatibility units and build scripts; this option is selected by default when Lazarus is the only detected IDE
On the Post-install Compilation page, select the Free Pascal runtime package for Win32 or Win64. A target is available when its compiler, RTL, LCL and LazUtils units are detected; you can still install the package sources when a target is unavailable and compile them later
The package is runtime-only and is added as a project dependency in Lazarus. The installer does not compile VCL demos with Free Pascal
Build and test
Open Lib/FPC/HotXLSLaz.lpk in Lazarus and compile the runtime package, or run these commands from the HotXLS directory
build-FPC-Lib.cmd Win64
Tests\Lazarus\Run-HotXLSLazarusSmoke.cmd Win64
build-FPC-Lib.cmd Win32
Tests\Lazarus\Run-HotXLSLazarusSmoke.cmd Win32
Set LAZARUS_DIR to select an installation; FPC_EXE and LAZBUILD_EXE can select explicit compiler and package-builder executables when needed
The selected installation must contain FPC and compiled LCL/LazUtils units for the target architecture; outputs and package-builder configuration are kept in separate architecture directories
Application setup
Add Lib and Lib/FPC to the unit search path and Lib to the include search path, or add the runtime package as a Lazarus project dependency
Put Interfaces before the HotXLS units in the application uses list, including console applications; this initializes the LCL widgetset and UTF-8 conversion at RTL/LCL boundaries
program WorkbookExample;
{$mode delphiunicode}
uses
Interfaces, SysUtils, lxHandleX;
var
Workbook: TXLSXWorkbook;
begin
Workbook:= TXLSXWorkbook.Create;
try
Workbook.AddSheet('Data');
Workbook.Sheets[1].Cells[1, 1].Value:= 'Hello';
if Workbook.SaveAs('example.xlsx')<> 1 then
raise Exception.Create('Workbook save failed');
finally
Workbook.Free;
end;
end.
HotXLS source units select Delphi Unicode semantics internally so strings, characters and formula text retain UTF-16 behavior; application code may use its preferred Pascal mode
Compatibility details
- The runtime package requires Windows and LCL;
TDataToXLSexports LCL datasets andTGridToXLSexports aTDBGrid, with or without explicit columns, while Linux, macOS, VCL demo forms, the VCL workbook viewer and the DevExpress grid adapter are outside this package - ZIP and compression streams use the bundled Pascal backend and do not require a separate zlib DLL
- AES uses a Pascal backend for both architectures, including password-protected XLSX files
- PNG preserves alpha, EMF uses Windows metafile recording and playback, and multipage TIFF uses the Windows GDI+ runtime
- Direct text reading accepts UTF-8 and BOM-marked UTF-16/UTF-32, handles streamed input and keeps the caller's stream ownership
- Initialize
TXlsCsvImportOptionswithTXlsCsvImportOptions.Defaultbefore changing individual fields - FPC report expressions and import patterns use Unicode
URegExprsyntax rather than Delphi's PCRE backend. Empty input is answered the wayTRegExanswers it: a pattern that accepts an empty string, such as^$or.*, matches it while[0-9]+does not, and replacing an empty string yields the replacement text only when the pattern accepts it; unsupported patterns and empty patterns raiseERegularExpressionError, which report expressions expose asREPORT_EXPRESSION_INVALID_REGEX