Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using zlib with Unicode file paths on Windows

Tags:

c

unicode

zlib

I'm reading gzip compressed files using zlib. Then you open a file using

gzFile gzopen(const char *filepath, const char *mode);

How do you handle Unicode file paths that are stored as const wchar_t* on Windows?

On UNIX-like platforms you can just convert the file path to UTF-8 and call gzopen(), but that will not work on Windows.

like image 452
Johan Råde Avatar asked Mar 15 '12 09:03

Johan Råde


2 Answers

The next version of zlib will include this function where _WIN32 is #defined:

gzFile gzopen_w(const wchar_t *path, char *mode);

It works exactly like gzopen(), except it uses _wopen() instead of open().

I purposely did not duplicate the second argument of _wfopen(), and as a result I did not call it _wgzopen() to avoid possible confusion with that function's arguments. Hence the name gzopen_w(). That also avoids the use of the C-reserved name space.

like image 100
Mark Adler Avatar answered Sep 21 '22 18:09

Mark Adler


Here is my own version of unicode helper function, tested slightly better than version above.

static void GetFlags(const char* mode, int& flags, int& pmode)
{
    const char* _mode = mode;

    flags = 0;      // == O_RDONLY
    pmode = 0;      // pmode needs to be obtained, otherwise file gets read-only attribute, see 
                    // http://stackoverflow.com/questions/1412625/why-is-the-read-only-attribute-set-sometimes-for-files-created-by-my-service

    for( ; *_mode ; _mode++ )
    {
        switch( tolower(*_mode) )
        {
            case 'w':
                flags |= O_CREAT | O_TRUNC;
                pmode |= _S_IWRITE;
                break;
            case 'a':
                flags |= O_CREAT | O_APPEND;
                pmode |= _S_IREAD | _S_IWRITE;
                break;
            case 'r':
                pmode |= _S_IREAD;
                break;
            case 'b':
                flags |= O_BINARY;
                break;
            case '+':
                flags |= O_RDWR;
                pmode |= _S_IREAD | _S_IWRITE;
                break;
        }
    }

    if( (flags & O_CREAT) != 0 && (flags & O_RDWR) == 0 )
        flags |= O_WRONLY;
} //GetFlags


gzFile wgzopen(const wchar_t* fileName, const char* mode)
{
    gzFile gzstream = NULL;
    int f = 0;
    int flags = 0;
    int pmode = 0;

    GetFlags(mode, flags, pmode);

    f = _wopen(fileName, flags, pmode );

    if( f == -1 )
        return NULL;

    // gzdopen will also close file handle.
    gzstream = gzdopen(f, mode);
    if(!gzstream)
        _close(f);
    return gzstream;
}
like image 23
TarmoPikaro Avatar answered Sep 18 '22 18:09

TarmoPikaro