HotXLS documentation

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.
AreaNative core contract
Workbook filesCreate, 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 namesWorkbook 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
InfrastructureNative 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 cryptographyBundled 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 functionsThe 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 servicesClipboard 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 componentsThe 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 formulasFunctions 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