node.jsunzipzipadm-zip

How to compute the value for `version made by` in zip header?


I'm struggling to compute the correct value for version made by in adm-zip.

The Zip Spec is unclear in my opinion how to find the binary or int value to set an option (e.g. Option 3 Unix) to the depending 2 Bytes in the central header.

The docs from adm-zip for the header setting does not help at all.

Mapping from the zip spec (4.4.2):

4.4.2.2 The current mappings are:

0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)
1 - Amiga                     2 - OpenVMS
3 - UNIX                      4 - VM/CMS

I have found one possible solution by setting the entry.header.made property to 788.

(entry.header as any).made = 788;

(This value was only found by importing a zip created by another zip util.)

Can anyone explain how to compute this value 788 starting from the desired option 3?

Or how to compute this value for another option e.g. 10 - Windows NTFS?


Solution

  • Short description:

    According to the specification the upper byte represents the OS which created the ZIP file. The lower byte is the version of the used ZIP specification.

    In your example:

    788 = 0x0314

    OS which created the ZIP file:
    0x03 (Upper Byte): UNIX

    4.4.2.1 The upper byte indicates the compatibility of the file attribute information. If the external file attributes are compatible with MS-DOS and can be read by PKZIP for DOS version 2.04g then this value will be zero. If these attributes are not compatible, then this value will identify the host system on which the attributes are compatible. Software can use this information to determine the line record format for text files etc.

    ZIP specification version:
    0x14 (Lower Byte): Version 2.0

    0x14 / 10 = 2 (Major version number)
    0x14 % 10 = 0 (Minor version number)

    4.4.2.3 The lower byte indicates the ZIP specification version (the version of this document) supported by the software used to encode the file. The value/10 indicates the major version number, and the value mod 10 is the minor version number.

    For Windows NTFS, the correct "version made by" value should be:

    0x0A14 = 2580

    0x0A (Upper Byte): Windows NTFS (Win32)
    0x14 (Lower Byte): Version 2.0

    Extract from adm-zip source:

    var _verMade = 0x14,
            _version = 0x0A,
            _flags = 0,
            _method = 0,
            _time = 0,
            _crc = 0,
            _compressedSize = 0,
            _size = 0,
            _fnameLen = 0,
            _extraLen = 0,
    
            _comLen = 0,
            _diskStart = 0,
            _inattr = 0,
            _attr = 0,
            _offset = 0;
    
        switch(process.platform){
            case 'win32':
                _verMade |= 0x0A00;
            case 'darwin':
                _verMade |= 0x1300;
            default:
                _verMade |= 0x0300;
        }
    

    Here you can see, that the version 2.0 (0x14) from the ZIP specification is used and there is a simple OR with the left shifted OS which created the ZIP file.

    UPDATE:
    I wrote a few simple JavaScript example functions which returns the right value for verMade and which returns the OS, major and minor version number from verMade.

    Set version:

    function zip_version_set(os, spec_major, spec_minor)
    {
        var ret = (parseInt(spec_major, 10) * 10) + parseInt(spec_minor, 10);
        
        switch (os) {
        case "dos":
            ret |= 0x0000;
            break;
        case "win32":
            ret |= 0x0A00;
            break;
        case "darwin":
            ret |= 0x1300;
            break;
        default:
            ret |= 0x0300;
        }
        
        return ret;
    }
    

    Usage:
    Argument os:
    Put her the OS string. Currently possible values are dos (MS-DOS), win32 (Windows NTFS), darwin (OS X) and the default is unix.

    Argument spec_major:
    Put here the major version number from the used ZIP specification.

    Argument spec_minor:
    Put here the minor version number from the used ZIP specification.

    Return:
    Returns verMade.

    Get OS:

    function zip_version_get_os(verMade)
    {
        var tmp;
        var ret;
        
        tmp = (verMade & 0xFF00) >> 8;
        
        switch (tmp) {
        case 0x00:
            ret = "dos";
            break;
        case 0x03:
            ret = "unix";
            break;
        case 0x0A:
            ret = "win32";
            break;
        case 0x13:
            ret = "darwin";
            break;
        default:
            ret = "unimplemented";
        }
        
        return ret;
    }
    

    Usage:
    Argument verMade:
    Put here the verMade value.

    Return:
    Returns the OS as string.

    Get major version number (ZIP specification):

    function zip_version_get_major(verMade)
    {
        return ((verMade & 0xFF) / 10);
    }
    

    Usage:
    Argument verMade:
    Put here the verMade value.

    Return:
    Returns the major version from the used ZIP specification.

    Get minor version number (ZIP specification):

    function zip_version_get_minor(verMade)
    {
        return ((verMade & 0xFF) % 10);
    }
    

    Usage:
    Argument verMade:
    Put here the verMade value.

    Return:
    Returns the minor version from the used ZIP specification.