XPS document with 100,000 pages?

Once a simple document format like XPS is created, it takes on a life of its own. Seeing the beauty of XPS, people are converting documents from differenent sources to XPS. People are trying to create XPS document with 10,000 pages, and even pushing for 100,000 pages.

But if you're using Microsoft XPS Document Writer to create XPS document with more than 32,700 odd pages, you may run into a bug in the current implementation. The problem lies in the limitation of 32-bit ZIP file directory structure. The solution is to switch to 64-bit ZIP64 file directory structure.

If you're blocked by this issue, here is a simple-minded piece of code which tries to repair such XPS file.

 int ZipRepair(const wchar_t * pFileName)

{

HANDLE hFile = CreateFile(pFileName, GENERIC_READ | GENERIC_WRITE,

    FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hFile == INVALID_HANDLE_VALUE)

    {

        return -1;

    }

    DWORD sizeHigh;

    DWORD sizeLow = GetFileSize(hFile, & sizeHigh);

    DWORD buffer[25];

    DWORD read = 0;

    if (SetFilePointer(hFile, sizeLow - 22, NULL, SEEK_SET))

        if (ReadFile(hFile, buffer, 22, & read, NULL))

        {

            DWORD entry = (buffer[2] & 0xFFFF) + 0x10000;

            DWORD size = buffer[3];

            DWORD offset = buffer[4];

            memset(buffer, 0, sizeof(buffer));

            buffer[0] = 0x06064b50; // Zip64EndCentralDir

            buffer[1] = 44;

            buffer[3] = 0x002d002d;

   buffer[6] = entry;

            buffer[8] = entry;

            buffer[10] = size;

            buffer[12] = offset;

           

            buffer[14] = 0x07064b50; // Zip64EndCentralDirLocator

            buffer[16] = sizeLow - 22;

          buffer[18] = 1;

            buffer[19] = 0x06054b50; // EndCentralDir

            buffer[21] = 0xFFFFFFFF;

            buffer[22] = 0xFFFFFFFF;

            buffer[23] = 0xFFFFFFFF;

           

            if (SetFilePointer(hFile, sizeLow - 22, NULL, SEEK_SET))

            {

                if (WriteFile(hFile, buffer, 98, & read, NULL))

                {

                    printf("%S repaired\n", pFileName);

                }

            }

        }

    CloseHandle(hFile);

    return 0;

}

The code assumes the XPS document has between 65,536 .. 131,071 streams within it. It reads the original EndCentralDir structure at the end of the file, inserts two structures for ZIP64, and then adds a dummy EndCentralDir structure. It assumes there is no comment at the end of the document. For more informations, read the ZIP specification at https://www.pkware.com/documents/casestudies/APPNOTE.TXT

BTW, my car of 10 years just received 100,000 miles last Sunday.