mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-06-12 08:23:59 +00:00
added libraries: opus flac libsndfile updated: libvorbis libogg openal - Everything works as expected for now. Bare in mind libsndfile needed the check for whether or not it could find the xiph libraries removed in order for this to work.
1206 lines
27 KiB
C
1206 lines
27 KiB
C
/*
|
|
** Copyright (C) 2002-2014 Erik de Castro Lopo <erikd@mega-nerd.com>
|
|
** Copyright (C) 2003 Ross Bencina <rbencina@iprimus.com.au>
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify
|
|
** it under the terms of the GNU Lesser General Public License as published by
|
|
** the Free Software Foundation; either version 2.1 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU Lesser General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU Lesser General Public License
|
|
** along with this program; if not, write to the Free Software
|
|
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/*
|
|
** The file is split into three sections as follows:
|
|
** - The top section (USE_WINDOWS_API == 0) for Linux, Unix and MacOSX
|
|
** systems (including Cygwin).
|
|
** - The middle section (USE_WINDOWS_API == 1) for microsoft windows
|
|
** (including MinGW) using the native windows API.
|
|
** - A legacy windows section which attempted to work around grevious
|
|
** bugs in microsoft's POSIX implementation.
|
|
*/
|
|
|
|
/*
|
|
** The header file sfconfig.h MUST be included before the others to ensure
|
|
** that large file support is enabled correctly on Unix systems.
|
|
*/
|
|
|
|
#include "sfconfig.h"
|
|
|
|
#if USE_WINDOWS_API
|
|
|
|
/* Don't include rarely used headers, speed up build */
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#if HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#else
|
|
#include <io.h>
|
|
#endif
|
|
|
|
#if (HAVE_DECL_S_IRGRP == 0)
|
|
#include <sf_unistd.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "sndfile.h"
|
|
#include "common.h"
|
|
|
|
#define SENSIBLE_SIZE (0x40000000)
|
|
|
|
/*
|
|
** Neat solution to the Win32/OS2 binary file flage requirement.
|
|
** If O_BINARY isn't already defined by the inclusion of the system
|
|
** headers, set it to zero.
|
|
*/
|
|
#ifndef O_BINARY
|
|
#define O_BINARY 0
|
|
#endif
|
|
|
|
static void psf_log_syserr (SF_PRIVATE *psf, int error) ;
|
|
|
|
int
|
|
psf_copy_filename (SF_PRIVATE *psf, const char *path)
|
|
{ const char *ccptr ;
|
|
char *cptr ;
|
|
|
|
if (strlen (path) > 1 && strlen (path) - 1 >= sizeof (psf->file.path))
|
|
{ psf->error = SFE_FILENAME_TOO_LONG ;
|
|
return psf->error ;
|
|
} ;
|
|
|
|
snprintf (psf->file.path, sizeof (psf->file.path), "%s", path) ;
|
|
if ((ccptr = strrchr (path, '/')) || (ccptr = strrchr (path, '\\')))
|
|
ccptr ++ ;
|
|
else
|
|
ccptr = path ;
|
|
|
|
snprintf (psf->file.name, sizeof (psf->file.name), "%s", ccptr) ;
|
|
|
|
/* Now grab the directory. */
|
|
snprintf (psf->file.dir, sizeof (psf->file.dir), "%s", path) ;
|
|
if ((cptr = strrchr (psf->file.dir, '/')) || (cptr = strrchr (psf->file.dir, '\\')))
|
|
cptr [1] = 0 ;
|
|
else
|
|
psf->file.dir [0] = 0 ;
|
|
|
|
return 0 ;
|
|
} /* psf_copy_filename */
|
|
|
|
#if (USE_WINDOWS_API == 0)
|
|
|
|
/*------------------------------------------------------------------------------
|
|
** Win32 stuff at the bottom of the file. Unix and other sensible OSes here.
|
|
*/
|
|
|
|
static int psf_close_fd (int fd) ;
|
|
static int psf_open_fd (PSF_FILE * pfile) ;
|
|
static sf_count_t psf_get_filelen_fd (int fd) ;
|
|
|
|
int
|
|
psf_fopen (SF_PRIVATE *psf)
|
|
{
|
|
psf->error = 0 ;
|
|
psf->file.filedes = psf_open_fd (&psf->file) ;
|
|
|
|
if (psf->file.filedes == - SFE_BAD_OPEN_MODE)
|
|
{ psf->error = SFE_BAD_OPEN_MODE ;
|
|
psf->file.filedes = -1 ;
|
|
return psf->error ;
|
|
} ;
|
|
|
|
if (psf->file.filedes == -1)
|
|
psf_log_syserr (psf, errno) ;
|
|
|
|
return psf->error ;
|
|
} /* psf_fopen */
|
|
|
|
int
|
|
psf_fclose (SF_PRIVATE *psf)
|
|
{ int retval ;
|
|
|
|
if (psf->virtual_io)
|
|
return 0 ;
|
|
|
|
if (psf->file.do_not_close_descriptor)
|
|
{ psf->file.filedes = -1 ;
|
|
return 0 ;
|
|
} ;
|
|
|
|
if ((retval = psf_close_fd (psf->file.filedes)) == -1)
|
|
psf_log_syserr (psf, errno) ;
|
|
|
|
psf->file.filedes = -1 ;
|
|
|
|
return retval ;
|
|
} /* psf_fclose */
|
|
|
|
int
|
|
psf_open_rsrc (SF_PRIVATE *psf)
|
|
{ size_t count ;
|
|
|
|
if (psf->rsrc.filedes > 0)
|
|
return 0 ;
|
|
|
|
/* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */
|
|
count = snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s/..namedfork/rsrc", psf->file.path) ;
|
|
psf->error = SFE_NO_ERROR ;
|
|
if (count < sizeof (psf->rsrc.path))
|
|
{ if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0)
|
|
{ psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ;
|
|
if (psf->rsrclength > 0 || (psf->rsrc.mode & SFM_WRITE))
|
|
return SFE_NO_ERROR ;
|
|
psf_close_fd (psf->rsrc.filedes) ;
|
|
psf->rsrc.filedes = -1 ;
|
|
} ;
|
|
|
|
if (psf->rsrc.filedes == - SFE_BAD_OPEN_MODE)
|
|
{ psf->error = SFE_BAD_OPEN_MODE ;
|
|
return psf->error ;
|
|
} ;
|
|
} ;
|
|
|
|
/*
|
|
** Now try for a resource fork stored as a separate file in the same
|
|
** directory, but preceded with a dot underscore.
|
|
*/
|
|
count = snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s._%s", psf->file.dir, psf->file.name) ;
|
|
psf->error = SFE_NO_ERROR ;
|
|
if (count < sizeof (psf->rsrc.path) && (psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0)
|
|
{ psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ;
|
|
return SFE_NO_ERROR ;
|
|
} ;
|
|
|
|
/*
|
|
** Now try for a resource fork stored in a separate file in the
|
|
** .AppleDouble/ directory.
|
|
*/
|
|
count = snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s.AppleDouble/%s", psf->file.dir, psf->file.name) ;
|
|
psf->error = SFE_NO_ERROR ;
|
|
if (count < sizeof (psf->rsrc.path))
|
|
{ if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0)
|
|
{ psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ;
|
|
return SFE_NO_ERROR ;
|
|
} ;
|
|
|
|
/* No resource file found. */
|
|
if (psf->rsrc.filedes == -1)
|
|
psf_log_syserr (psf, errno) ;
|
|
}
|
|
else
|
|
{ psf->error = SFE_OPEN_FAILED ;
|
|
} ;
|
|
|
|
psf->rsrc.filedes = -1 ;
|
|
|
|
return psf->error ;
|
|
} /* psf_open_rsrc */
|
|
|
|
sf_count_t
|
|
psf_get_filelen (SF_PRIVATE *psf)
|
|
{ sf_count_t filelen ;
|
|
|
|
if (psf->virtual_io)
|
|
return psf->vio.get_filelen (psf->vio_user_data) ;
|
|
|
|
filelen = psf_get_filelen_fd (psf->file.filedes) ;
|
|
|
|
if (filelen == -1)
|
|
{ psf_log_syserr (psf, errno) ;
|
|
return (sf_count_t) -1 ;
|
|
} ;
|
|
|
|
if (filelen == -SFE_BAD_STAT_SIZE)
|
|
{ psf->error = SFE_BAD_STAT_SIZE ;
|
|
return (sf_count_t) -1 ;
|
|
} ;
|
|
|
|
switch (psf->file.mode)
|
|
{ case SFM_WRITE :
|
|
filelen = filelen - psf->fileoffset ;
|
|
break ;
|
|
|
|
case SFM_READ :
|
|
if (psf->fileoffset > 0 && psf->filelength > 0)
|
|
filelen = psf->filelength ;
|
|
break ;
|
|
|
|
case SFM_RDWR :
|
|
/*
|
|
** Cannot open embedded files SFM_RDWR so we don't need to
|
|
** subtract psf->fileoffset. We already have the answer we
|
|
** need.
|
|
*/
|
|
break ;
|
|
|
|
default :
|
|
/* Shouldn't be here, so return error. */
|
|
filelen = -1 ;
|
|
} ;
|
|
|
|
return filelen ;
|
|
} /* psf_get_filelen */
|
|
|
|
int
|
|
psf_close_rsrc (SF_PRIVATE *psf)
|
|
{ psf_close_fd (psf->rsrc.filedes) ;
|
|
psf->rsrc.filedes = -1 ;
|
|
return 0 ;
|
|
} /* psf_close_rsrc */
|
|
|
|
int
|
|
psf_set_stdio (SF_PRIVATE *psf)
|
|
{ int error = 0 ;
|
|
|
|
switch (psf->file.mode)
|
|
{ case SFM_RDWR :
|
|
error = SFE_OPEN_PIPE_RDWR ;
|
|
break ;
|
|
|
|
case SFM_READ :
|
|
psf->file.filedes = 0 ;
|
|
break ;
|
|
|
|
case SFM_WRITE :
|
|
psf->file.filedes = 1 ;
|
|
break ;
|
|
|
|
default :
|
|
error = SFE_BAD_OPEN_MODE ;
|
|
break ;
|
|
} ;
|
|
psf->filelength = 0 ;
|
|
|
|
return error ;
|
|
} /* psf_set_stdio */
|
|
|
|
void
|
|
psf_set_file (SF_PRIVATE *psf, int fd)
|
|
{ psf->file.filedes = fd ;
|
|
} /* psf_set_file */
|
|
|
|
int
|
|
psf_file_valid (SF_PRIVATE *psf)
|
|
{ return (psf->file.filedes >= 0) ? SF_TRUE : SF_FALSE ;
|
|
} /* psf_set_file */
|
|
|
|
sf_count_t
|
|
psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
|
|
{ sf_count_t absolute_position ;
|
|
|
|
if (psf->virtual_io)
|
|
return psf->vio.seek (offset, whence, psf->vio_user_data) ;
|
|
|
|
/* When decoding from pipes sometimes see seeks to the pipeoffset, which appears to mean do nothing. */
|
|
if (psf->is_pipe)
|
|
{ if (whence != SEEK_SET || offset != psf->pipeoffset)
|
|
psf_log_printf (psf, "psf_fseek : pipe seek to value other than pipeoffset\n") ;
|
|
return offset ;
|
|
}
|
|
|
|
switch (whence)
|
|
{ case SEEK_SET :
|
|
offset += psf->fileoffset ;
|
|
break ;
|
|
|
|
case SEEK_END :
|
|
break ;
|
|
|
|
case SEEK_CUR :
|
|
break ;
|
|
|
|
default :
|
|
/* We really should not be here. */
|
|
psf_log_printf (psf, "psf_fseek : whence is %d *****.\n", whence) ;
|
|
return 0 ;
|
|
} ;
|
|
|
|
absolute_position = lseek (psf->file.filedes, offset, whence) ;
|
|
|
|
if (absolute_position < 0)
|
|
psf_log_syserr (psf, errno) ;
|
|
|
|
return absolute_position - psf->fileoffset ;
|
|
} /* psf_fseek */
|
|
|
|
sf_count_t
|
|
psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
|
|
{ sf_count_t total = 0 ;
|
|
ssize_t count ;
|
|
|
|
if (psf->virtual_io)
|
|
return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
|
|
|
|
items *= bytes ;
|
|
|
|
/* Do this check after the multiplication above. */
|
|
if (items <= 0)
|
|
return 0 ;
|
|
|
|
while (items > 0)
|
|
{ /* Break the read down to a sensible size. */
|
|
count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
|
|
|
|
count = read (psf->file.filedes, ((char*) ptr) + total, (size_t) count) ;
|
|
|
|
if (count == -1)
|
|
{ if (errno == EINTR)
|
|
continue ;
|
|
|
|
psf_log_syserr (psf, errno) ;
|
|
break ;
|
|
} ;
|
|
|
|
if (count == 0)
|
|
break ;
|
|
|
|
total += count ;
|
|
items -= count ;
|
|
} ;
|
|
|
|
if (psf->is_pipe)
|
|
psf->pipeoffset += total ;
|
|
|
|
return total / bytes ;
|
|
} /* psf_fread */
|
|
|
|
sf_count_t
|
|
psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
|
|
{ sf_count_t total = 0 ;
|
|
ssize_t count ;
|
|
|
|
if (bytes == 0 || items == 0)
|
|
return 0 ;
|
|
|
|
if (psf->virtual_io)
|
|
return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ;
|
|
|
|
items *= bytes ;
|
|
|
|
/* Do this check after the multiplication above. */
|
|
if (items <= 0)
|
|
return 0 ;
|
|
|
|
while (items > 0)
|
|
{ /* Break the writes down to a sensible size. */
|
|
count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ;
|
|
|
|
count = write (psf->file.filedes, ((const char*) ptr) + total, count) ;
|
|
|
|
if (count == -1)
|
|
{ if (errno == EINTR)
|
|
continue ;
|
|
|
|
psf_log_syserr (psf, errno) ;
|
|
break ;
|
|
} ;
|
|
|
|
if (count == 0)
|
|
break ;
|
|
|
|
total += count ;
|
|
items -= count ;
|
|
} ;
|
|
|
|
if (psf->is_pipe)
|
|
psf->pipeoffset += total ;
|
|
|
|
return total / bytes ;
|
|
} /* psf_fwrite */
|
|
|
|
sf_count_t
|
|
psf_ftell (SF_PRIVATE *psf)
|
|
{ sf_count_t pos ;
|
|
|
|
if (psf->virtual_io)
|
|
return psf->vio.tell (psf->vio_user_data) ;
|
|
|
|
if (psf->is_pipe)
|
|
return psf->pipeoffset ;
|
|
|
|
pos = lseek (psf->file.filedes, 0, SEEK_CUR) ;
|
|
|
|
if (pos == ((sf_count_t) -1))
|
|
{ psf_log_syserr (psf, errno) ;
|
|
return -1 ;
|
|
} ;
|
|
|
|
return pos - psf->fileoffset ;
|
|
} /* psf_ftell */
|
|
|
|
static int
|
|
psf_close_fd (int fd)
|
|
{ int retval ;
|
|
|
|
if (fd < 0)
|
|
return 0 ;
|
|
|
|
while ((retval = close (fd)) == -1 && errno == EINTR)
|
|
/* Do nothing. */ ;
|
|
|
|
return retval ;
|
|
} /* psf_close_fd */
|
|
|
|
sf_count_t
|
|
psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf)
|
|
{ sf_count_t k = 0 ;
|
|
sf_count_t count ;
|
|
|
|
while (k < bufsize - 1)
|
|
{ count = read (psf->file.filedes, &(buffer [k]), 1) ;
|
|
|
|
if (count == -1)
|
|
{ if (errno == EINTR)
|
|
continue ;
|
|
|
|
psf_log_syserr (psf, errno) ;
|
|
break ;
|
|
} ;
|
|
|
|
if (count == 0 || buffer [k++] == '\n')
|
|
break ;
|
|
} ;
|
|
|
|
buffer [k] = 0 ;
|
|
|
|
return k ;
|
|
} /* psf_fgets */
|
|
|
|
int
|
|
psf_is_pipe (SF_PRIVATE *psf)
|
|
{ struct stat statbuf ;
|
|
|
|
if (psf->virtual_io)
|
|
return SF_FALSE ;
|
|
|
|
if (fstat (psf->file.filedes, &statbuf) == -1)
|
|
{ psf_log_syserr (psf, errno) ;
|
|
/* Default to maximum safety. */
|
|
return SF_TRUE ;
|
|
} ;
|
|
|
|
if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode))
|
|
return SF_TRUE ;
|
|
|
|
return SF_FALSE ;
|
|
} /* psf_is_pipe */
|
|
|
|
static sf_count_t
|
|
psf_get_filelen_fd (int fd)
|
|
{
|
|
#if (SIZEOF_OFF_T == 4 && HAVE_FSTAT64)
|
|
struct stat64 statbuf ;
|
|
|
|
if (fstat64 (fd, &statbuf) == -1)
|
|
return (sf_count_t) -1 ;
|
|
|
|
return statbuf.st_size ;
|
|
#else
|
|
struct stat statbuf ;
|
|
|
|
if (fstat (fd, &statbuf) == -1)
|
|
return (sf_count_t) -1 ;
|
|
|
|
return statbuf.st_size ;
|
|
#endif
|
|
} /* psf_get_filelen_fd */
|
|
|
|
int
|
|
psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
|
|
{ int retval ;
|
|
|
|
/* Returns 0 on success, non-zero on failure. */
|
|
if (len < 0)
|
|
return -1 ;
|
|
|
|
if ((sizeof (off_t) < sizeof (sf_count_t)) && len > 0x7FFFFFFF)
|
|
return -1 ;
|
|
|
|
retval = ftruncate (psf->file.filedes, len) ;
|
|
|
|
if (retval == -1)
|
|
psf_log_syserr (psf, errno) ;
|
|
|
|
return retval ;
|
|
} /* psf_ftruncate */
|
|
|
|
void
|
|
psf_init_files (SF_PRIVATE *psf)
|
|
{ psf->file.filedes = -1 ;
|
|
psf->rsrc.filedes = -1 ;
|
|
psf->file.savedes = -1 ;
|
|
} /* psf_init_files */
|
|
|
|
void
|
|
psf_use_rsrc (SF_PRIVATE *psf, int on_off)
|
|
{
|
|
if (on_off)
|
|
{ if (psf->file.filedes != psf->rsrc.filedes)
|
|
{ psf->file.savedes = psf->file.filedes ;
|
|
psf->file.filedes = psf->rsrc.filedes ;
|
|
} ;
|
|
}
|
|
else if (psf->file.filedes == psf->rsrc.filedes)
|
|
psf->file.filedes = psf->file.savedes ;
|
|
|
|
return ;
|
|
} /* psf_use_rsrc */
|
|
|
|
static int
|
|
psf_open_fd (PSF_FILE * pfile)
|
|
{ int fd, oflag, mode ;
|
|
|
|
/*
|
|
** Sanity check. If everything is OK, this test and the printfs will
|
|
** be optimised out. This is meant to catch the problems caused by
|
|
** "sfconfig.h" being included after <stdio.h>.
|
|
*/
|
|
if (sizeof (sf_count_t) != 8)
|
|
{ puts ("\n\n*** Fatal error : sizeof (sf_count_t) != 8") ;
|
|
puts ("*** This means that libsndfile was not configured correctly.\n") ;
|
|
exit (1) ;
|
|
} ;
|
|
|
|
switch (pfile->mode)
|
|
{ case SFM_READ :
|
|
oflag = O_RDONLY | O_BINARY ;
|
|
mode = 0 ;
|
|
break ;
|
|
|
|
case SFM_WRITE :
|
|
oflag = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ;
|
|
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ;
|
|
break ;
|
|
|
|
case SFM_RDWR :
|
|
oflag = O_RDWR | O_CREAT | O_BINARY ;
|
|
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ;
|
|
break ;
|
|
|
|
default :
|
|
return - SFE_BAD_OPEN_MODE ;
|
|
break ;
|
|
} ;
|
|
|
|
if (mode == 0)
|
|
fd = open (pfile->path, oflag) ;
|
|
else
|
|
fd = open (pfile->path, oflag, mode) ;
|
|
|
|
return fd ;
|
|
} /* psf_open_fd */
|
|
|
|
static void
|
|
psf_log_syserr (SF_PRIVATE *psf, int error)
|
|
{
|
|
/* Only log an error if no error has been set yet. */
|
|
if (psf->error == 0)
|
|
{ psf->error = SFE_SYSTEM ;
|
|
snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s.", strerror (error)) ;
|
|
} ;
|
|
|
|
return ;
|
|
} /* psf_log_syserr */
|
|
|
|
void
|
|
psf_fsync (SF_PRIVATE *psf)
|
|
{
|
|
#if HAVE_FSYNC
|
|
if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
|
|
fsync (psf->file.filedes) ;
|
|
#else
|
|
psf = NULL ;
|
|
#endif
|
|
} /* psf_fsync */
|
|
|
|
#else
|
|
|
|
/* Win32 file i/o functions implemented using native Win32 API */
|
|
|
|
#ifndef WINAPI_PARTITION_SYSTEM
|
|
#define WINAPI_PARTITION_SYSTEM 0
|
|
#endif
|
|
|
|
static int psf_close_handle (HANDLE handle) ;
|
|
static HANDLE psf_open_handle (PSF_FILE * pfile) ;
|
|
static sf_count_t psf_get_filelen_handle (HANDLE handle) ;
|
|
|
|
/* USE_WINDOWS_API */ int
|
|
psf_fopen (SF_PRIVATE *psf)
|
|
{
|
|
psf->error = 0 ;
|
|
psf->file.handle = psf_open_handle (&psf->file) ;
|
|
|
|
if (psf->file.handle == INVALID_HANDLE_VALUE)
|
|
psf_log_syserr (psf, GetLastError ()) ;
|
|
|
|
return psf->error ;
|
|
} /* psf_fopen */
|
|
|
|
/* USE_WINDOWS_API */ int
|
|
psf_fclose (SF_PRIVATE *psf)
|
|
{ int retval ;
|
|
|
|
if (psf->virtual_io)
|
|
return 0 ;
|
|
|
|
if (psf->file.do_not_close_descriptor)
|
|
{ psf->file.handle = INVALID_HANDLE_VALUE ;
|
|
return 0 ;
|
|
} ;
|
|
|
|
if ((retval = psf_close_handle (psf->file.handle)) == -1)
|
|
psf_log_syserr (psf, GetLastError ()) ;
|
|
|
|
psf->file.handle = INVALID_HANDLE_VALUE ;
|
|
|
|
return retval ;
|
|
} /* psf_fclose */
|
|
|
|
/* USE_WINDOWS_API */ int
|
|
psf_open_rsrc (SF_PRIVATE *psf)
|
|
{
|
|
if (psf->rsrc.handle != INVALID_HANDLE_VALUE)
|
|
return 0 ;
|
|
|
|
/* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */
|
|
snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s/rsrc", psf->file.path) ;
|
|
psf->error = SFE_NO_ERROR ;
|
|
if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != INVALID_HANDLE_VALUE)
|
|
{ psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
|
|
return SFE_NO_ERROR ;
|
|
} ;
|
|
|
|
/*
|
|
** Now try for a resource fork stored as a separate file in the same
|
|
** directory, but preceded with a dot underscore.
|
|
*/
|
|
snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s._%s", psf->file.dir, psf->file.name) ;
|
|
psf->error = SFE_NO_ERROR ;
|
|
if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != INVALID_HANDLE_VALUE)
|
|
{ psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
|
|
return SFE_NO_ERROR ;
|
|
} ;
|
|
|
|
/*
|
|
** Now try for a resource fork stored in a separate file in the
|
|
** .AppleDouble/ directory.
|
|
*/
|
|
snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s.AppleDouble/%s", psf->file.dir, psf->file.name) ;
|
|
psf->error = SFE_NO_ERROR ;
|
|
if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != INVALID_HANDLE_VALUE)
|
|
{ psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
|
|
return SFE_NO_ERROR ;
|
|
} ;
|
|
|
|
/* No resource file found. */
|
|
if (psf->rsrc.handle == INVALID_HANDLE_VALUE)
|
|
psf_log_syserr (psf, GetLastError ()) ;
|
|
|
|
return psf->error ;
|
|
} /* psf_open_rsrc */
|
|
|
|
/* USE_WINDOWS_API */ sf_count_t
|
|
psf_get_filelen (SF_PRIVATE *psf)
|
|
{ sf_count_t filelen ;
|
|
|
|
if (psf->virtual_io)
|
|
return psf->vio.get_filelen (psf->vio_user_data) ;
|
|
|
|
filelen = psf_get_filelen_handle (psf->file.handle) ;
|
|
|
|
if (filelen == -1)
|
|
{ psf_log_syserr (psf, errno) ;
|
|
return (sf_count_t) -1 ;
|
|
} ;
|
|
|
|
if (filelen == -SFE_BAD_STAT_SIZE)
|
|
{ psf->error = SFE_BAD_STAT_SIZE ;
|
|
return (sf_count_t) -1 ;
|
|
} ;
|
|
|
|
switch (psf->file.mode)
|
|
{ case SFM_WRITE :
|
|
filelen = filelen - psf->fileoffset ;
|
|
break ;
|
|
|
|
case SFM_READ :
|
|
if (psf->fileoffset > 0 && psf->filelength > 0)
|
|
filelen = psf->filelength ;
|
|
break ;
|
|
|
|
case SFM_RDWR :
|
|
/*
|
|
** Cannot open embedded files SFM_RDWR so we don't need to
|
|
** subtract psf->fileoffset. We already have the answer we
|
|
** need.
|
|
*/
|
|
break ;
|
|
|
|
default :
|
|
/* Shouldn't be here, so return error. */
|
|
filelen = -1 ;
|
|
} ;
|
|
|
|
return filelen ;
|
|
} /* psf_get_filelen */
|
|
|
|
/* USE_WINDOWS_API */ void
|
|
psf_init_files (SF_PRIVATE *psf)
|
|
{ psf->file.handle = INVALID_HANDLE_VALUE ;
|
|
psf->rsrc.handle = INVALID_HANDLE_VALUE ;
|
|
psf->file.hsaved = INVALID_HANDLE_VALUE ;
|
|
} /* psf_init_files */
|
|
|
|
/* USE_WINDOWS_API */ void
|
|
psf_use_rsrc (SF_PRIVATE *psf, int on_off)
|
|
{
|
|
if (on_off)
|
|
{ if (psf->file.handle != psf->rsrc.handle)
|
|
{ psf->file.hsaved = psf->file.handle ;
|
|
psf->file.handle = psf->rsrc.handle ;
|
|
} ;
|
|
}
|
|
else if (psf->file.handle == psf->rsrc.handle)
|
|
psf->file.handle = psf->file.hsaved ;
|
|
|
|
return ;
|
|
} /* psf_use_rsrc */
|
|
|
|
/* USE_WINDOWS_API */ static HANDLE
|
|
psf_open_handle (PSF_FILE * pfile)
|
|
{ DWORD dwDesiredAccess ;
|
|
DWORD dwShareMode ;
|
|
DWORD dwCreationDistribution ;
|
|
HANDLE handle ;
|
|
LPWSTR pwszPath = NULL ;
|
|
|
|
switch (pfile->mode)
|
|
{ case SFM_READ :
|
|
dwDesiredAccess = GENERIC_READ ;
|
|
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
|
|
dwCreationDistribution = OPEN_EXISTING ;
|
|
break ;
|
|
|
|
case SFM_WRITE :
|
|
dwDesiredAccess = GENERIC_WRITE ;
|
|
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
|
|
dwCreationDistribution = CREATE_ALWAYS ;
|
|
break ;
|
|
|
|
case SFM_RDWR :
|
|
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE ;
|
|
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
|
|
dwCreationDistribution = OPEN_ALWAYS ;
|
|
break ;
|
|
|
|
default :
|
|
return INVALID_HANDLE_VALUE ;
|
|
} ;
|
|
|
|
int nResult = MultiByteToWideChar (CP_UTF8, 0, pfile->path, -1, NULL, 0) ;
|
|
pwszPath = malloc (nResult * sizeof (WCHAR)) ;
|
|
if (!pwszPath)
|
|
return INVALID_HANDLE_VALUE ;
|
|
|
|
int nResult2 = MultiByteToWideChar (CP_UTF8, 0, pfile->path, -1, pwszPath, nResult) ;
|
|
if (nResult != nResult2)
|
|
{ free (pwszPath) ;
|
|
return INVALID_HANDLE_VALUE ;
|
|
} ;
|
|
|
|
#if defined (WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
|
CREATEFILE2_EXTENDED_PARAMETERS cfParams = { 0 } ;
|
|
cfParams.dwSize = sizeof (CREATEFILE2_EXTENDED_PARAMETERS) ;
|
|
cfParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL ;
|
|
|
|
handle = CreateFile2 (pwszPath, dwDesiredAccess, dwShareMode, dwCreationDistribution, &cfParams) ;
|
|
#else
|
|
handle = CreateFileW (
|
|
pwszPath, /* pointer to name of the file */
|
|
dwDesiredAccess, /* access (read-write) mode */
|
|
dwShareMode, /* share mode */
|
|
0, /* pointer to security attributes */
|
|
dwCreationDistribution, /* how to create */
|
|
FILE_ATTRIBUTE_NORMAL, /* file attributes (could use FILE_FLAG_SEQUENTIAL_SCAN) */
|
|
NULL /* handle to file with attributes to copy */
|
|
) ;
|
|
#endif
|
|
free (pwszPath) ;
|
|
|
|
return handle ;
|
|
} /* psf_open_handle */
|
|
|
|
/* USE_WINDOWS_API */ static void
|
|
psf_log_syserr (SF_PRIVATE *psf, int error)
|
|
{ LPVOID lpMsgBuf ;
|
|
|
|
/* Only log an error if no error has been set yet. */
|
|
if (psf->error == 0)
|
|
{ psf->error = SFE_SYSTEM ;
|
|
|
|
FormatMessage (
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
error,
|
|
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR) &lpMsgBuf,
|
|
0,
|
|
NULL
|
|
) ;
|
|
|
|
snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s", (char*) lpMsgBuf) ;
|
|
LocalFree (lpMsgBuf) ;
|
|
} ;
|
|
|
|
return ;
|
|
} /* psf_log_syserr */
|
|
|
|
|
|
/* USE_WINDOWS_API */ int
|
|
psf_close_rsrc (SF_PRIVATE *psf)
|
|
{ psf_close_handle (psf->rsrc.handle) ;
|
|
psf->rsrc.handle = INVALID_HANDLE_VALUE ;
|
|
return 0 ;
|
|
} /* psf_close_rsrc */
|
|
|
|
|
|
/* USE_WINDOWS_API */ int
|
|
psf_set_stdio (SF_PRIVATE *psf)
|
|
{ HANDLE handle = INVALID_HANDLE_VALUE ;
|
|
int error = 0 ;
|
|
|
|
switch (psf->file.mode)
|
|
{ case SFM_RDWR :
|
|
error = SFE_OPEN_PIPE_RDWR ;
|
|
break ;
|
|
|
|
case SFM_READ :
|
|
handle = GetStdHandle (STD_INPUT_HANDLE) ;
|
|
psf->file.do_not_close_descriptor = 1 ;
|
|
break ;
|
|
|
|
case SFM_WRITE :
|
|
handle = GetStdHandle (STD_OUTPUT_HANDLE) ;
|
|
psf->file.do_not_close_descriptor = 1 ;
|
|
break ;
|
|
|
|
default :
|
|
error = SFE_BAD_OPEN_MODE ;
|
|
break ;
|
|
} ;
|
|
|
|
psf->file.handle = handle ;
|
|
psf->filelength = 0 ;
|
|
|
|
return error ;
|
|
} /* psf_set_stdio */
|
|
|
|
/* USE_WINDOWS_API */ void
|
|
psf_set_file (SF_PRIVATE *psf, int fd)
|
|
{ HANDLE handle ;
|
|
intptr_t osfhandle ;
|
|
|
|
osfhandle = _get_osfhandle (fd) ;
|
|
handle = (HANDLE) osfhandle ;
|
|
|
|
psf->file.handle = handle ;
|
|
} /* psf_set_file */
|
|
|
|
/* USE_WINDOWS_API */ int
|
|
psf_file_valid (SF_PRIVATE *psf)
|
|
{ if (psf->file.handle == INVALID_HANDLE_VALUE)
|
|
return SF_FALSE ;
|
|
return SF_TRUE ;
|
|
} /* psf_set_file */
|
|
|
|
/* USE_WINDOWS_API */ sf_count_t
|
|
psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
|
|
{ sf_count_t new_position ;
|
|
LARGE_INTEGER liDistanceToMove, liNewFilePointer ;
|
|
DWORD dwMoveMethod ;
|
|
BOOL fResult ;
|
|
DWORD dwError ;
|
|
|
|
if (psf->virtual_io)
|
|
return psf->vio.seek (offset, whence, psf->vio_user_data) ;
|
|
|
|
switch (whence)
|
|
{ case SEEK_SET :
|
|
offset += psf->fileoffset ;
|
|
dwMoveMethod = FILE_BEGIN ;
|
|
break ;
|
|
|
|
case SEEK_END :
|
|
dwMoveMethod = FILE_END ;
|
|
break ;
|
|
|
|
default :
|
|
dwMoveMethod = FILE_CURRENT ;
|
|
break ;
|
|
} ;
|
|
|
|
liDistanceToMove.QuadPart = offset ;
|
|
|
|
fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, &liNewFilePointer, dwMoveMethod) ;
|
|
|
|
if (fResult == FALSE)
|
|
dwError = GetLastError () ;
|
|
else
|
|
dwError = NO_ERROR ;
|
|
|
|
if (dwError != NO_ERROR)
|
|
{ psf_log_syserr (psf, dwError) ;
|
|
return -1 ;
|
|
} ;
|
|
|
|
new_position = liNewFilePointer.QuadPart - psf->fileoffset ;
|
|
|
|
return new_position ;
|
|
} /* psf_fseek */
|
|
|
|
/* USE_WINDOWS_API */ sf_count_t
|
|
psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
|
|
{ sf_count_t total = 0 ;
|
|
ssize_t count ;
|
|
DWORD dwNumberOfBytesRead ;
|
|
|
|
if (psf->virtual_io)
|
|
return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
|
|
|
|
items *= bytes ;
|
|
|
|
/* Do this check after the multiplication above. */
|
|
if (items <= 0)
|
|
return 0 ;
|
|
|
|
while (items > 0)
|
|
{ /* Break the writes down to a sensible size. */
|
|
count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
|
|
|
|
if (ReadFile (psf->file.handle, ((char*) ptr) + total, count, &dwNumberOfBytesRead, 0) == 0)
|
|
{ psf_log_syserr (psf, GetLastError ()) ;
|
|
break ;
|
|
}
|
|
else
|
|
count = dwNumberOfBytesRead ;
|
|
|
|
if (count == 0)
|
|
break ;
|
|
|
|
total += count ;
|
|
items -= count ;
|
|
} ;
|
|
|
|
if (psf->is_pipe)
|
|
psf->pipeoffset += total ;
|
|
|
|
return total / bytes ;
|
|
} /* psf_fread */
|
|
|
|
/* USE_WINDOWS_API */ sf_count_t
|
|
psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
|
|
{ sf_count_t total = 0 ;
|
|
ssize_t count ;
|
|
DWORD dwNumberOfBytesWritten ;
|
|
|
|
if (psf->virtual_io)
|
|
return psf->vio.write (ptr, bytes * items, psf->vio_user_data) / bytes ;
|
|
|
|
items *= bytes ;
|
|
|
|
/* Do this check after the multiplication above. */
|
|
if (items <= 0)
|
|
return 0 ;
|
|
|
|
while (items > 0)
|
|
{ /* Break the writes down to a sensible size. */
|
|
count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
|
|
|
|
if (WriteFile (psf->file.handle, ((const char*) ptr) + total, count, &dwNumberOfBytesWritten, 0) == 0)
|
|
{ psf_log_syserr (psf, GetLastError ()) ;
|
|
break ;
|
|
}
|
|
else
|
|
count = dwNumberOfBytesWritten ;
|
|
|
|
if (count == 0)
|
|
break ;
|
|
|
|
total += count ;
|
|
items -= count ;
|
|
} ;
|
|
|
|
if (psf->is_pipe)
|
|
psf->pipeoffset += total ;
|
|
|
|
return total / bytes ;
|
|
} /* psf_fwrite */
|
|
|
|
/* USE_WINDOWS_API */ sf_count_t
|
|
psf_ftell (SF_PRIVATE *psf)
|
|
{ sf_count_t pos ;
|
|
LARGE_INTEGER liDistanceToMove, liNewFilePointer ;
|
|
BOOL fResult ;
|
|
DWORD dwError ;
|
|
|
|
if (psf->virtual_io)
|
|
return psf->vio.tell (psf->vio_user_data) ;
|
|
|
|
if (psf->is_pipe)
|
|
return psf->pipeoffset ;
|
|
|
|
liDistanceToMove.QuadPart = 0 ;
|
|
|
|
fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, &liNewFilePointer, FILE_CURRENT) ;
|
|
|
|
if (fResult == FALSE)
|
|
dwError = GetLastError () ;
|
|
else
|
|
dwError = NO_ERROR ;
|
|
|
|
if (dwError != NO_ERROR)
|
|
{ psf_log_syserr (psf, dwError) ;
|
|
return -1 ;
|
|
} ;
|
|
|
|
pos = liNewFilePointer.QuadPart ;
|
|
|
|
return pos - psf->fileoffset ;
|
|
} /* psf_ftell */
|
|
|
|
/* USE_WINDOWS_API */ static int
|
|
psf_close_handle (HANDLE handle)
|
|
{ if (handle == INVALID_HANDLE_VALUE)
|
|
return 0 ;
|
|
|
|
if (CloseHandle (handle) == 0)
|
|
return -1 ;
|
|
|
|
return 0 ;
|
|
} /* psf_close_handle */
|
|
|
|
/* USE_WINDOWS_API */ sf_count_t
|
|
psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf)
|
|
{ sf_count_t k = 0 ;
|
|
sf_count_t count ;
|
|
DWORD dwNumberOfBytesRead ;
|
|
|
|
while (k < bufsize - 1)
|
|
{ if (ReadFile (psf->file.handle, &(buffer [k]), 1, &dwNumberOfBytesRead, 0) == 0)
|
|
{ psf_log_syserr (psf, GetLastError ()) ;
|
|
break ;
|
|
}
|
|
else
|
|
{ count = dwNumberOfBytesRead ;
|
|
/* note that we only check for '\n' not other line endings such as CRLF */
|
|
if (count == 0 || buffer [k++] == '\n')
|
|
break ;
|
|
} ;
|
|
} ;
|
|
|
|
buffer [k] = 0 ;
|
|
|
|
return k ;
|
|
} /* psf_fgets */
|
|
|
|
/* USE_WINDOWS_API */ int
|
|
psf_is_pipe (SF_PRIVATE *psf)
|
|
{
|
|
if (psf->virtual_io)
|
|
return SF_FALSE ;
|
|
|
|
if (GetFileType (psf->file.handle) == FILE_TYPE_DISK)
|
|
return SF_FALSE ;
|
|
|
|
/* Default to maximum safety. */
|
|
return SF_TRUE ;
|
|
} /* psf_is_pipe */
|
|
|
|
/* USE_WINDOWS_API */ sf_count_t
|
|
psf_get_filelen_handle (HANDLE handle)
|
|
{ sf_count_t filelen ;
|
|
LARGE_INTEGER liFileSize ;
|
|
BOOL fResult ;
|
|
DWORD dwError = NO_ERROR ;
|
|
|
|
fResult = GetFileSizeEx (handle, &liFileSize) ;
|
|
|
|
if (fResult == FALSE)
|
|
dwError = GetLastError () ;
|
|
|
|
if (dwError != NO_ERROR)
|
|
return (sf_count_t) -1 ;
|
|
|
|
filelen = liFileSize.QuadPart ;
|
|
|
|
return filelen ;
|
|
} /* psf_get_filelen_handle */
|
|
|
|
/* USE_WINDOWS_API */ void
|
|
psf_fsync (SF_PRIVATE *psf)
|
|
{ FlushFileBuffers (psf->file.handle) ;
|
|
} /* psf_fsync */
|
|
|
|
|
|
/* USE_WINDOWS_API */ int
|
|
psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
|
|
{ int retval = 0 ;
|
|
LARGE_INTEGER liDistanceToMove ;
|
|
BOOL fResult ;
|
|
DWORD dwError = NO_ERROR ;
|
|
|
|
/* This implementation trashes the current file position.
|
|
** should it save and restore it? what if the current position is past
|
|
** the new end of file?
|
|
*/
|
|
|
|
/* Returns 0 on success, non-zero on failure. */
|
|
if (len < 0)
|
|
return 1 ;
|
|
|
|
liDistanceToMove.QuadPart = (sf_count_t) len ;
|
|
|
|
fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, NULL, FILE_BEGIN) ;
|
|
|
|
if (fResult == FALSE)
|
|
dwError = GetLastError () ;
|
|
|
|
if (dwError != NO_ERROR)
|
|
{ retval = -1 ;
|
|
psf_log_syserr (psf, dwError) ;
|
|
}
|
|
else
|
|
{ /* Note: when SetEndOfFile is used to extend a file, the contents of the
|
|
** new portion of the file is undefined. This is unlike chsize(),
|
|
** which guarantees that the new portion of the file will be zeroed.
|
|
** Not sure if this is important or not.
|
|
*/
|
|
if (SetEndOfFile (psf->file.handle) == 0)
|
|
{ retval = -1 ;
|
|
psf_log_syserr (psf, GetLastError ()) ;
|
|
} ;
|
|
} ;
|
|
|
|
return retval ;
|
|
} /* psf_ftruncate */
|
|
|
|
#endif
|
|
|