Patches against trunk r7511 (git a96303ea), 2 patch files attached (git am or patch -p1):
0001-Support-installers-larger-than-2-GiB-up-to-4-GiB.patch (code)0002-Document-the-4-GiB-installer-size-limit.patch (documentation and changelog)All datablock offsets and lengths in the installer format are 32-bit values, but makensis and the exehead treat them as signed int (and use ftell, SetFilePointer without the high part, MulDiv, ...), which limits installers to 2 GiB. These patches handle them as unsigned values, which raises the limit to 4 GiB - 1 byte, the largest file Windows can execute.
/SOLID. The top bit of a block length is still the "compressed" flag, so a single non-solid block stays below 2 GiB./SOLID the uncompressed data is limited to 4 GiB as well, because the offsets in the instructions are 32-bit.exehead (fileform.c, fileform.h)
firstheader.length_of_all_following_data is UINT. NSIS_MAX_EXEDATASIZE is 0xffffffff; new NSIS_MAX_DATABLOCKSIZE (2 GiB - 1).SetFilePointer (SetFilePointerFromBegin()), so they are unsigned 32-bit. _dodecomp() uses offset != -1 as the "continue" sentinel instead of offset >= 0. -1 can never be a valid offset because the whole file is < 4 GiB.UINT. Differences are computed with __int64 (add/sub/compare only, no CRT helpers needed).DECOMP_RETVAL), so extracting a file > 2 GiB is not reported as an error.MulDiv().makensis
IMMap/MMapFile/MMapBuf use 64-bit offsets and sizes (CreateFileMapping/MapViewOfFile with high and low DWORD, off_t on POSIX). MMapBuf::getlen() (IGrowBuf, int) reports an internal error instead of silently overflowing when used on a buffer > 2 GiB.add_db_data() returns INT64 (-1 on error). datablock_optimize()/datablock_finddata() use 64-bit offsets. The new datablock_check_size() enforces the limit when data is added.ftell64()/fseek64() (_ftelli64/_fseeki64, ftello/fseeko) for the output file.NPRIu64 format macro (I64u on Windows, llu on POSIX) next to NPRIs.Docs: features list (4 GB), File, SetCompress, SetCompressor, changelog.
MSVC 2022, x86 stubs, scons (Windows 11):
SetCompressor /SOLID zlib: pass.Error: installer too large (4294967352 bytes) ..., no output file left./SOLID; clear error without /SOLID.Not tested: amd64/arm64 stubs, MinGW and POSIX builds of makensis. The code is prepared for them (off_t, ftello/fseeko, NPRIu64); 32-bit POSIX needs _FILE_OFFSET_BITS=64.
File documentation, so whichever is applied second needs a trivial doc merge; the code applies cleanly together.
I was going to mention the NSISBI project for big installers, but it looks like you are already aware of my fork. I've been developing it since 2016 (gosh it's been that long now!), and I have upstreamed several fixes from my side over the years. It supports stub mode, so you can have a small .exe and use an internet plugin to download the datablock file. I recently added support for multiple file output too (but not disk spanning), so if you have a 5.5GB installer and use OutFileSize 1024, it will create 5 1GB files and a partial 6th file. I had to implement on-the-fly crc checking to make this possible. I also implemented codec multithreading to speed up those big installers.
I have a reasonably important enablement patch coming up which I will release on my fork first, and I'll also show the dev team privately to get some feedback before I submit it for upstreaming.
Now that I have looked at the patch, there are some things I don't like in there, like using __int64 which is not supported on certain older compilers (should be INT64), and using size_t on offsets when it should be a fixed width, and the percentage overflow I fixed just by bit shifting the inputs down 1 so that the top bit is always zero. I also used a union on the datablock offsets to convert a 64 bit offset to two 32 bit values. In the exehead I also force typecast the datablock size (all_following_data) from int to unsigned int. I also left the uninstaller sizes alone, because who needs an uninstaller bigger than 2GB? I've already run into the issue of using fseek64/ftell64 on other platforms, I fixed it by writing my own helper that works on all platforms. There are other little issues, like splitting one line of code into two and creating an extra variable just for that call, when the existing line was just fine as it was. And instead of directly printing 64 bit integers to the screen, I used FriendlySize to give a much nicer output.
I do appreciate the effort put into this, but this code looks alot like what my code was when I first started developing NSISBI back in 2016.