The parts of a modern RTL that Delphi 2007 never got: hash dictionaries, a fast StringBuilder, SHA-256 / MD5 / HMAC, Base64, a WinInet HTTP client and a JSON parser. Pure Pascal, no DLLs, no packages to register. Drop in a unit and go.
It targets Delphi 2007 first and stays clean from Delphi 7 all the way to 11.3, because rewriting a 300-unit legacy app just to get a TDictionary is not a plan. If you are stuck on an old compiler and keep reaching for things it does not have, help yourself to whatever is useful here.
Everything has DUnit tests, and the crypto and hash units are cross-checked against the Windows CryptoAPI and the XE6 RTL so the numbers actually match.
- TbpStrDictionary / TbpIntDictionary - real hash maps with string and Int64 keys, for compilers with no generics. Same engine as XE6's
TDictionary: open addressing, linear probing, power-of-two capacity, backward-shift deletion. Values are Variants, but the typed accessors (GetInt,TryGetStr,GetFloatDefand the rest) check the type instead of quietly coercing it. - TbpIntList - a list of integers that behaves like
TStringList: sorting, delimited text, the usual indexing.
- TbpStringBuilder - the XE6
TStringBuilderAPI, minus the slow part. The RTL routes every append through theLengthsetter; this one writes through a cached pointer, so it is quite a bit faster. - BpStrUtils -
Split,Join,StartsWith/EndsWith, and aFastStringReplacethat finds every match first and builds the result in one allocation.SysUtils.StringReplacerecopies the tail on each hit and goes quadratic; this one does not.
- BpSHA256 - SHA-256 (FIPS 180-4), pure Pascal. Stream it in chunks or call a one-shot class function for a buffer, string or file, hex or Base64 out. Checked against the FIPS vectors and CryptoAPI.
- BpMD5 - MD5 (RFC 1321), same shape as the SHA unit. It is broken for anything security-related, so keep it to legacy checksums, ETags and content fingerprints.
- BpHMACSHA256 - HMAC-SHA256 (RFC 2104) for API request signing and webhook verification.
- BpHashBobJenkins - the Bob Jenkins lookup3 hash, byte-for-byte identical to the XE+
BobJenkinsHash. It is what powers the string dictionary. - BpBase64 - Base64 and Base64url (RFC 4648). One allocation to encode; the decoder eats either alphabet, forgives missing padding and skips whitespace, so MIME-wrapped input just works.
- TbpHttpClient - HTTP and HTTPS over WinInet. TLS comes from Schannel, which means no OpenSSL DLLs shipping alongside your exe.
Get/Post/Put/Deletehand back a response record; bearer tokens, basic auth and persistent headers are one call each, andPostJsonsets the content type for you. - TbpJsonValue - a JSON reader and writer (RFC 8259). One class is the whole tree, tagged by
Kind. The parser is strict on purpose: leading zeros, raw control characters, trailing commas and junk after the value all fail, and the error tells you the line and column. Pull values out with the same typed accessors as the dictionaries, reach deep withFindPath('data.items[0].name'), and write it back withToJsonorToJsonPretty. No RTTI, no data binding, just the tree.
- TbpObjectComparer - diffs two objects by RTTI and tells you which published properties changed, collections included.
- BpVariantUtils - strict Variant-to-native conversions. It only succeeds when the Variant already holds that type; nothing is parsed or widened behind your back.
- BpSysUtils - small shims like
CharInSetfor the pre-2009 compilers. - StopWatch - a
QueryPerformanceCounterstopwatch for Delphi 7-2007, used by the benchmarks.
Do not want to add ten units to your project? Take one file from dist\ instead. Each bundle is self-contained:
- BpDictionaries.pas - both dictionaries, with the hash and Variant helpers baked in
- BpHashes.pas - SHA-256, MD5, HMAC-SHA256 and Base64
- BpHttpClientStandalone.pas - the HTTP client with Base64 baked in
- BpJsonStandalone.pas - the JSON reader/writer with the string builder baked in
These are generated from the modular units, SQLite amalgamation style, by tools\Amalgamate.ps1. They are build artifacts, so do not patch them by hand; fix the real unit and regenerate:
powershell -ExecutionPolicy Bypass -File tools\Amalgamate.ps1
One catch: use at most one bundle per project. Two bundles that embed the same helper would collide on duplicate identifiers. tools\VerifyBundles.cmd compiles each bundle on its own and runs a smoke test against known-answer vectors, so you can trust what ships.
The .cmd scripts at the repo root drive Delphi 2007 through MSBuild:
Build_Main_D2007.cmd Release
Build_Tests_D2007.cmd Debug
RunTests_D2007.cmd
The test project is DUnit and also carries benchmarks that pit the performance units against their RTL equivalents, so the speed claims above are not just talk.
If you send a patch, match the house style:
- Locals start with
lv, globals withgv, local constants withlc, global constants withgc. - Classes get the
Tbpprefix (Boost Pack), e.g.TbpStringBuilder. - One class per unit where it makes sense, and the unit is named after it (
TbpIntListlives inBpIntList.pas). - Comments are
//lines. Braces{ }are for compiler directives only.
Fork it, fix or add something, open a pull request. Bugs, new units and better docs are all fair game.
Official ISOs and web installers for the older Delphi and RAD Studio releases are collected here: