Make win32 version file handling use wide character functions (for non-latin filenames)
This commit is contained in:
parent
840fe59997
commit
5b18d69d28
|
@ -201,7 +201,7 @@ int _conf_existdir(char *path) {
|
|||
|
||||
DPRINTF(E_DBG,L_CONF,"Checking existence of %s\n",path);
|
||||
|
||||
if(stat(path,&sb)) {
|
||||
if(os_stat(path,&sb)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -339,7 +339,7 @@ void config_handler(WS_CONNINFO *pwsc) {
|
|||
}
|
||||
|
||||
/* this is quite broken, but will work */
|
||||
stat(resolved_path,&sb);
|
||||
os_stat(resolved_path,&sb);
|
||||
if(sb.st_mode & S_IFDIR) {
|
||||
ws_addresponseheader(pwsc,"Location","/index.html");
|
||||
ws_returnerror(pwsc,302,"Moved");
|
||||
|
@ -806,7 +806,7 @@ void config_emit_include(WS_CONNINFO *pwsc, void *value, char *arg) {
|
|||
}
|
||||
|
||||
/* this should really return a 302:Found */
|
||||
stat(resolved_path,&sb);
|
||||
os_stat(resolved_path,&sb);
|
||||
if(sb.st_mode & S_IFDIR) {
|
||||
ws_writefd(pwsc,"<hr><i>error: cannot include dir %s</i><hr>",arg);
|
||||
return;
|
||||
|
|
|
@ -106,7 +106,7 @@ void err_reopen(void) {
|
|||
if(!(err_logdest & LOGDEST_LOGFILE))
|
||||
return;
|
||||
|
||||
_err_lock();
|
||||
// _err_lock();
|
||||
fclose(err_file);
|
||||
err_file = fopen(err_filename,"a");
|
||||
if(!err_file) {
|
||||
|
@ -122,7 +122,7 @@ void err_reopen(void) {
|
|||
strerror(err));
|
||||
return;
|
||||
}
|
||||
_err_unlock();
|
||||
// _err_unlock();
|
||||
DPRINTF(E_LOG,L_MISC,"Rotated logs\n");
|
||||
}
|
||||
|
||||
|
@ -257,7 +257,7 @@ int err_setlogfile(char *file) {
|
|||
if(strcmp(file,err_filename) == 0)
|
||||
return TRUE;
|
||||
*/
|
||||
_err_lock();
|
||||
// _err_lock();
|
||||
|
||||
if(err_file) {
|
||||
fclose(err_file);
|
||||
|
@ -279,7 +279,7 @@ int err_setlogfile(char *file) {
|
|||
result=FALSE;
|
||||
}
|
||||
|
||||
_err_unlock();
|
||||
// _err_unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -364,7 +364,7 @@ int scan_path(char *path) {
|
|||
mp3_path[0] = '\x0';
|
||||
realpath(relative_path,mp3_path);
|
||||
DPRINTF(E_DBG,L_SCAN,"Found %s\n",relative_path);
|
||||
if(stat(mp3_path,&sb)) {
|
||||
if(os_stat(mp3_path,&sb)) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Error statting: %s\n",strerror(errno));
|
||||
} else {
|
||||
if(sb.st_mode & S_IFDIR) { /* dir -- recurse */
|
||||
|
@ -411,7 +411,7 @@ int scan_static_playlist(char *path) {
|
|||
char *ptr;
|
||||
|
||||
DPRINTF(E_WARN,L_SCAN|L_PL,"Processing static playlist: %s\n",path);
|
||||
if(stat(path,&sb)) {
|
||||
if(os_stat(path,&sb)) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Error statting %s: %s\n",path,strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -567,7 +567,7 @@ void scan_filename(char *path, int compdir, char *extensions) {
|
|||
}
|
||||
|
||||
|
||||
if(stat(mp3_path,&sb)) {
|
||||
if(os_stat(mp3_path,&sb)) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Error statting: %s\n",strerror(errno));
|
||||
} else {
|
||||
/* we assume this is regular file */
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Win32 os functions that require unicode
|
||||
*/
|
||||
|
||||
#define _UNICODE
|
||||
#define UNICODE
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "daapd.h"
|
||||
#include "win32.h"
|
||||
#include "err.h"
|
||||
#include "os-win32.h"
|
||||
#include "util.h"
|
||||
|
||||
/* opendir/closedir/readdir emulation taken from emacs. Thanks. :) */
|
||||
DIR *os_opendir(char *filename) {
|
||||
DIR *dirp;
|
||||
|
||||
/* Opening is done by FindFirstFile. However, a read is inherent to
|
||||
this operation, so we defer the open until read time. */
|
||||
|
||||
if (!(dirp = (DIR *) malloc (sizeof (DIR))))
|
||||
return NULL;
|
||||
|
||||
dirp->dir_find_handle = INVALID_HANDLE_VALUE;
|
||||
dirp->dd_fd = 0;
|
||||
dirp->dd_loc = 0;
|
||||
dirp->dd_size = 0;
|
||||
|
||||
strncpy (dirp->dir_pathname, filename,PATH_MAX);
|
||||
dirp->dir_pathname[PATH_MAX] = '\0';
|
||||
|
||||
return dirp;
|
||||
}
|
||||
|
||||
void os_closedir(DIR *dirp) {
|
||||
/* If we have a find-handle open, close it. */
|
||||
if (dirp->dir_find_handle != INVALID_HANDLE_VALUE) {
|
||||
FindClose(dirp->dir_find_handle);
|
||||
}
|
||||
free((char *) dirp);
|
||||
}
|
||||
|
||||
|
||||
int os_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
|
||||
char filename[PATH_MAX + 1];
|
||||
WCHAR utf16[PATH_MAX + 1];
|
||||
int ln;
|
||||
|
||||
if (dirp->dir_find_handle == INVALID_HANDLE_VALUE) {
|
||||
/* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
|
||||
strncpy (filename, dirp->dir_pathname,PATH_MAX - 3);
|
||||
ln = (int) strlen (filename) - 1;
|
||||
if(filename[ln] != '\\')
|
||||
strcat (filename, "\\");
|
||||
strcat (filename, "*");
|
||||
|
||||
/* filename is utf-8... let's convert to unicode */
|
||||
util_utf8toutf16((unsigned char *)&utf16,sizeof(utf16),filename,(int)strlen(filename));
|
||||
|
||||
dirp->dir_find_handle = FindFirstFile(utf16, &dirp->dir_find_data);
|
||||
|
||||
if (dirp->dir_find_handle == INVALID_HANDLE_VALUE) {
|
||||
*result=NULL;
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (!FindNextFile (dirp->dir_find_handle, &dirp->dir_find_data)) {
|
||||
*result = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emacs never uses this value, so don't bother making it match
|
||||
value returned by stat(). */
|
||||
entry->d_ino = 1;
|
||||
|
||||
memset(entry->d_name,0,MAXNAMLEN+1);
|
||||
util_utf16toutf8(entry->d_name,MAXNAMLEN+1,
|
||||
(unsigned char *)&dirp->dir_find_data.cFileName,
|
||||
(int)wcslen(dirp->dir_find_data.cFileName)*2);
|
||||
entry->d_namlen = (int) strlen (entry->d_name);
|
||||
|
||||
entry->d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
|
||||
entry->d_namlen - entry->d_namlen % 4;
|
||||
|
||||
entry->d_type = 0;
|
||||
if(dirp->dir_find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
entry->d_type |= DT_DIR;
|
||||
} else if(dirp->dir_find_data.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) {
|
||||
entry->d_type |= DT_REG;
|
||||
}
|
||||
|
||||
/*
|
||||
if (dir_is_fat)
|
||||
_strlwr (dir_static.d_name);
|
||||
else if (!NILP (Vw32_downcase_file_names)) {
|
||||
register char *p;
|
||||
for (p = dir_static.d_name; *p; p++)
|
||||
if (*p >= 'a' && *p <= 'z')
|
||||
break;
|
||||
if (!*p)
|
||||
_strlwr (dir_static.d_name);
|
||||
}
|
||||
*/
|
||||
*result = entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int os_stat(const char *path, struct _stat *sb) {
|
||||
WCHAR utf16_path[PATH_MAX+1];
|
||||
|
||||
memset(utf16_path,0,sizeof(utf16_path));
|
||||
util_utf8toutf16((unsigned char *)&utf16_path,PATH_MAX * 2,(char*)path,(int)strlen(path));
|
||||
|
||||
return _wstat(utf16_path,sb);
|
||||
}
|
||||
|
||||
/* FIXME: mode */
|
||||
int os_open(const char *filename, int oflag) {
|
||||
WCHAR utf16_path[PATH_MAX+1];
|
||||
int fd;
|
||||
|
||||
memset(utf16_path,0,sizeof(utf16_path));
|
||||
util_utf8toutf16((unsigned char *)&utf16_path,PATH_MAX * 2,(char*)filename,(int)strlen(filename));
|
||||
|
||||
fd = _wopen(utf16_path, oflag | O_BINARY);
|
||||
return fd;
|
||||
}
|
||||
|
||||
FILE *os_fopen(const char *filename, const char *mode) {
|
||||
WCHAR utf16_path[PATH_MAX+1];
|
||||
WCHAR utf16_mode[10];
|
||||
|
||||
memset(utf16_path,0,sizeof(utf16_path));
|
||||
memset(utf16_mode,0,sizeof(utf16_mode));
|
||||
util_utf8toutf16((unsigned char *)&utf16_path,PATH_MAX * 2,(char*)filename,(int)strlen(filename));
|
||||
util_utf8toutf16((unsigned char *)&utf16_mode,10 * 2,(char*)mode,(int)strlen(mode));
|
||||
return _wfopen((wchar_t *)&utf16_path, (wchar_t *)&utf16_mode);
|
||||
}
|
||||
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
/* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
@ -19,6 +18,7 @@
|
|||
#include "plugin.h"
|
||||
#include "w32-eventlog.h"
|
||||
#include "w32-service.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Globals */
|
||||
static WSADATA w32_wsadata;
|
||||
|
@ -425,13 +425,6 @@ int os_shutdown(int fd, int how) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: mode */
|
||||
int os_open(const char *filename, int oflag) {
|
||||
int fd;
|
||||
|
||||
fd = _open(filename, oflag | O_BINARY);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int os_close(int fd) {
|
||||
if(NOTSOCK) {
|
||||
|
@ -470,7 +463,7 @@ char *os_realpath(const char *pathname, char *resolved_path) {
|
|||
|
||||
ptr = resolved_path;
|
||||
while(*ptr) {
|
||||
*ptr = tolower(*ptr);
|
||||
// *ptr = tolower(*ptr);
|
||||
if(*ptr == '/')
|
||||
*ptr = '\\';
|
||||
ptr++;
|
||||
|
@ -524,92 +517,6 @@ void _os_socket_shutdown(void) {
|
|||
|
||||
/* COMPAT FUNCTIONS */
|
||||
|
||||
/* opendir/closedir/readdir emulation taken from emacs. Thanks. :) */
|
||||
DIR *os_opendir(char *filename) {
|
||||
DIR *dirp;
|
||||
|
||||
/* Opening is done by FindFirstFile. However, a read is inherent to
|
||||
this operation, so we defer the open until read time. */
|
||||
|
||||
if (!(dirp = (DIR *) malloc (sizeof (DIR))))
|
||||
return NULL;
|
||||
|
||||
dirp->dir_find_handle = INVALID_HANDLE_VALUE;
|
||||
dirp->dd_fd = 0;
|
||||
dirp->dd_loc = 0;
|
||||
dirp->dd_size = 0;
|
||||
|
||||
strncpy (dirp->dir_pathname, filename,_MAX_PATH);
|
||||
dirp->dir_pathname[_MAX_PATH] = '\0';
|
||||
|
||||
return dirp;
|
||||
}
|
||||
|
||||
void os_closedir(DIR *dirp) {
|
||||
/* If we have a find-handle open, close it. */
|
||||
if (dirp->dir_find_handle != INVALID_HANDLE_VALUE) {
|
||||
FindClose(dirp->dir_find_handle);
|
||||
}
|
||||
free((char *) dirp);
|
||||
}
|
||||
|
||||
|
||||
int os_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
|
||||
if (dirp->dir_find_handle == INVALID_HANDLE_VALUE) {
|
||||
/* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
|
||||
char filename[MAXNAMLEN + 3];
|
||||
int ln;
|
||||
|
||||
strcpy (filename, dirp->dir_pathname);
|
||||
ln = (int) strlen (filename) - 1;
|
||||
if(filename[ln] != '\\')
|
||||
strcat (filename, "\\");
|
||||
strcat (filename, "*");
|
||||
|
||||
dirp->dir_find_handle = FindFirstFile (filename, &dirp->dir_find_data);
|
||||
|
||||
if (dirp->dir_find_handle == INVALID_HANDLE_VALUE) {
|
||||
*result=NULL;
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (!FindNextFile (dirp->dir_find_handle, &dirp->dir_find_data)) {
|
||||
*result = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emacs never uses this value, so don't bother making it match
|
||||
value returned by stat(). */
|
||||
entry->d_ino = 1;
|
||||
|
||||
entry->d_namlen = (int) strlen (dirp->dir_find_data.cFileName);
|
||||
entry->d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
|
||||
entry->d_namlen - entry->d_namlen % 4;
|
||||
strcpy (entry->d_name, dirp->dir_find_data.cFileName);
|
||||
|
||||
entry->d_type = 0;
|
||||
if(dirp->dir_find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
entry->d_type |= DT_DIR;
|
||||
} else if(dirp->dir_find_data.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) {
|
||||
entry->d_type |= DT_REG;
|
||||
}
|
||||
|
||||
/*
|
||||
if (dir_is_fat)
|
||||
_strlwr (dir_static.d_name);
|
||||
else if (!NILP (Vw32_downcase_file_names)) {
|
||||
register char *p;
|
||||
for (p = dir_static.d_name; *p; p++)
|
||||
if (*p >= 'a' && *p <= 'z')
|
||||
break;
|
||||
if (!*p)
|
||||
_strlwr (dir_static.d_name);
|
||||
}
|
||||
*/
|
||||
*result = entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* can't be worse then strerror */
|
||||
char *os_strerror (int error_no) {
|
||||
|
|
|
@ -42,7 +42,7 @@ typedef struct {
|
|||
int dd_size; /* amount of valid data */
|
||||
char dd_buf[DIRBLKSIZ]; /* directory block */
|
||||
HANDLE dir_find_handle;
|
||||
char dir_pathname[_MAX_PATH+1];
|
||||
char dir_pathname[PATH_MAX+1];
|
||||
WIN32_FIND_DATA dir_find_data;
|
||||
} DIR;
|
||||
|
||||
|
@ -58,6 +58,8 @@ extern int os_shutdown(int fd, int how);
|
|||
extern int os_waitfdtimed(int fd, struct timeval end);
|
||||
extern int os_close(int fd);
|
||||
extern int os_open(const char *filename, int oflag);
|
||||
extern FILE *os_fopen(const char *filename, const char *mode);
|
||||
|
||||
extern int os_read(int fd,void *buffer,unsigned int count);
|
||||
extern int os_write(int fd, void *buffer, unsigned int count);
|
||||
extern int os_getuid(void);
|
||||
|
|
1
src/os.h
1
src/os.h
|
@ -39,6 +39,7 @@ extern void *os_libfunc(char **pe, void *handle, char *function);
|
|||
extern int os_unload(void *handle);
|
||||
|
||||
/* misc */
|
||||
extern int os_stat(const char *path, struct stat *sb);
|
||||
extern int os_islocaladdr(char *hostaddr);
|
||||
extern char *os_apppath(char *parm);
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#undef fopen
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
|
@ -291,6 +291,7 @@ int scan_mp3_get_mp3tags(char *file, MP3FILE *pmp3) {
|
|||
int err;
|
||||
int index;
|
||||
int used;
|
||||
int mp3_fd;
|
||||
char *utf8_text;
|
||||
int genre=WINAMP_GENRE_UNKNOWN;
|
||||
int have_utf8;
|
||||
|
@ -300,7 +301,13 @@ int scan_mp3_get_mp3tags(char *file, MP3FILE *pmp3) {
|
|||
int got_numeric_genre;
|
||||
int rating;
|
||||
|
||||
pid3file=id3_file_open(file,ID3_FILE_MODE_READONLY);
|
||||
mp3_fd = open(file,O_RDONLY);
|
||||
if(mp3_fd == -1) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Cannot open %s\n",file);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pid3file=id3_file_fdopen(mp3_fd,ID3_FILE_MODE_READONLY);
|
||||
if(!pid3file) {
|
||||
DPRINTF(E_WARN,L_SCAN,"Cannot open %s\n",file);
|
||||
return FALSE;
|
||||
|
|
|
@ -427,7 +427,6 @@ int wma_parse_extended_content_description(int fd,int size, MP3FILE *pmp3) {
|
|||
int fail=0;
|
||||
int track, tracknumber;
|
||||
char numbuff[40];
|
||||
int new_size;
|
||||
char *tmp;
|
||||
|
||||
|
||||
|
@ -528,8 +527,8 @@ int wma_parse_extended_content_description(int fd,int size, MP3FILE *pmp3) {
|
|||
pmp3->composer = descriptor_byte_value;
|
||||
descriptor_byte_value = NULL;
|
||||
} else {
|
||||
size = strlen(pmp3->composer) + 1 +
|
||||
strlen(descriptor_byte_value) + 1;
|
||||
size = (int)strlen(pmp3->composer) + 1 +
|
||||
(int)strlen(descriptor_byte_value) + 1;
|
||||
tmp = malloc(size);
|
||||
if(!tmp)
|
||||
DPRINTF(E_FATAL,L_SCAN,"malloc: wma_ext_content_descr\n");
|
||||
|
|
|
@ -159,7 +159,7 @@ int scan_xml_rb_compare(const void *pa, const void *pb, const void *cfg) {
|
|||
int scan_xml_is_file(char *path) {
|
||||
struct stat sb;
|
||||
|
||||
if(stat(path,&sb))
|
||||
if(os_stat(path,&sb))
|
||||
return 0;
|
||||
|
||||
if(sb.st_mode & S_IFREG)
|
||||
|
|
374
src/util.c
374
src/util.c
|
@ -14,8 +14,20 @@
|
|||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "daapd.h"
|
||||
//#include <iconv.h>
|
||||
|
||||
#include "daapd.h"
|
||||
#include "err.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Forwards */
|
||||
//int _util_xtoy(unsigned char *dbuffer, size_t dlen, unsigned char *sbuffer, size_t slen, char *from, char *to);
|
||||
void _util_hexdump(unsigned char *block, int len);
|
||||
|
||||
|
||||
/**
|
||||
* Simple hash generator
|
||||
*/
|
||||
uint32_t util_djb_hash_block(unsigned char *data, uint32_t len) {
|
||||
uint32_t hash = 5381;
|
||||
unsigned char *pstr = data;
|
||||
|
@ -27,7 +39,9 @@ uint32_t util_djb_hash_block(unsigned char *data, uint32_t len) {
|
|||
return hash;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* simple hash generator
|
||||
*/
|
||||
uint32_t util_djb_hash_str(char *str) {
|
||||
uint32_t len;
|
||||
|
||||
|
@ -35,6 +49,362 @@ uint32_t util_djb_hash_str(char *str) {
|
|||
return util_djb_hash_block((unsigned char *)str,len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumb utility function that should probably be somehwere else
|
||||
*/
|
||||
int util_must_exit(void) {
|
||||
return config.stop;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate how long a utf16le string will be once converted
|
||||
*/
|
||||
int util_utf16toutf8_len(unsigned char *utf16, int len) {
|
||||
char *src = utf16;
|
||||
int out_len = 0;
|
||||
uint16_t temp_word;
|
||||
|
||||
while(src+2 <= utf16 + len) {
|
||||
temp_word = src[1] << 8 | src[0];
|
||||
|
||||
if((temp_word & 0xFC00) == 0xD800) {
|
||||
src += 2;
|
||||
if(src + 2 <= utf16 + len) {
|
||||
out_len += 4;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if(temp_word <= 0x7F)
|
||||
out_len += 1;
|
||||
else if(temp_word <= 0x7FF)
|
||||
out_len += 2;
|
||||
else if(temp_word <= 0xFFFF)
|
||||
out_len += 3;
|
||||
}
|
||||
|
||||
src += 2;
|
||||
}
|
||||
return out_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert utf16 string to utf8. This is a bit naive, but...
|
||||
* Since utf-8 can't expand past 4 bytes per code point, and
|
||||
* we're converting utf-16, we can't be more than 2n+1 bytes, so
|
||||
* we'll just allocate that much.
|
||||
*
|
||||
* Probably it could be more efficiently calculated, but this will
|
||||
* always work. Besides, these are small strings, and will be freed
|
||||
* after the db insert.
|
||||
*
|
||||
* We assume this is utf-16LE, as it comes from windows
|
||||
*
|
||||
* @param utf16 utf-16 to convert
|
||||
* @param len length of utf-16 string
|
||||
*/
|
||||
|
||||
int util_utf16toutf8(unsigned char *utf8, int dlen, unsigned char *utf16, int len) {
|
||||
unsigned char *src=utf16;
|
||||
char *dst;
|
||||
unsigned int w1, w2;
|
||||
int bytes;
|
||||
int new_len;
|
||||
|
||||
if(!len)
|
||||
return FALSE;
|
||||
|
||||
new_len = util_utf16toutf8_len(utf16,len);
|
||||
if((new_len == -1) || (dlen <= new_len)) {
|
||||
DPRINTF(E_LOG,L_MISC,"Cannot convert %s to utf8; E2BIG (%d vs %d)\n",utf8,new_len,dlen);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dst=utf8;
|
||||
while((src+2) <= utf16+len) {
|
||||
w1=src[1] << 8 | src[0];
|
||||
src += 2;
|
||||
if((w1 & 0xFC00) == 0xD800) { // could be surrogate pair
|
||||
if(src+2 > utf16+len) {
|
||||
DPRINTF(E_INF,L_SCAN,"Invalid utf-16 in file\n");
|
||||
return FALSE;
|
||||
}
|
||||
w2 = src[3] << 8 | src[2];
|
||||
if((w2 & 0xFC00) != 0xDC00) {
|
||||
DPRINTF(E_INF,L_SCAN,"Invalid utf-16 in file\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// get bottom 10 of each
|
||||
w1 = w1 & 0x03FF;
|
||||
w1 = w1 << 10;
|
||||
w1 = w1 | (w2 & 0x03FF);
|
||||
|
||||
// add back the 0x10000
|
||||
w1 += 0x10000;
|
||||
}
|
||||
|
||||
// now encode the original code point in utf-8
|
||||
if (w1 < 0x80) {
|
||||
*dst++ = w1;
|
||||
bytes=0;
|
||||
} else if (w1 < 0x800) {
|
||||
*dst++ = 0xC0 | (w1 >> 6);
|
||||
bytes=1;
|
||||
} else if (w1 < 0x10000) {
|
||||
*dst++ = 0xE0 | (w1 >> 12);
|
||||
bytes=2;
|
||||
} else {
|
||||
*dst++ = 0xF0 | (w1 >> 18);
|
||||
bytes=3;
|
||||
}
|
||||
|
||||
while(bytes) {
|
||||
*dst++ = 0x80 | ((w1 >> (6*(bytes-1))) & 0x3f);
|
||||
bytes--;
|
||||
}
|
||||
}
|
||||
|
||||
*dst = '\x0';
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate how long a utf8 string will be once converted
|
||||
*/
|
||||
int util_utf8toutf16_len(unsigned char *utf8) {
|
||||
int len,out_len,trailing_bytes;
|
||||
unsigned char *src = utf8;
|
||||
|
||||
len=(int)strlen(utf8);
|
||||
out_len = 0;
|
||||
|
||||
while(src < utf8 + len) {
|
||||
trailing_bytes = 0;
|
||||
if((*src & 0xE0) == 0xC0) trailing_bytes = 1;
|
||||
else if((*src & 0xF0) == 0xE0) trailing_bytes = 2;
|
||||
else if((*src & 0xF8) == 0xF0) trailing_bytes = 3;
|
||||
|
||||
if(src + trailing_bytes > utf8 + len)
|
||||
return -1;
|
||||
|
||||
out_len += 2;
|
||||
if(trailing_bytes == 3) /* surrogate pair */
|
||||
out_len += 2;
|
||||
|
||||
src += (1 + trailing_bytes);
|
||||
}
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
unsigned char *util_utf8toutf16_alloc(unsigned char *utf8) {
|
||||
unsigned char *out;
|
||||
int new_len;
|
||||
|
||||
new_len = util_utf8toutf16_len(utf8);
|
||||
if(new_len == -1)
|
||||
return NULL;
|
||||
|
||||
out = calloc(1,new_len + 2);
|
||||
if(!util_utf8toutf16(out,new_len + 2,utf8,(int)strlen(utf8))) {
|
||||
free(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
unsigned char *util_utf16touft8_alloc(unsigned char *utf16, int len) {
|
||||
unsigned char *out;
|
||||
int new_len;
|
||||
|
||||
new_len = util_utf16toutf8_len(utf16,len);
|
||||
if(new_len == -1)
|
||||
return NULL;
|
||||
|
||||
out = calloc(1,new_len + 1);
|
||||
if(!util_utf16toutf8(out,new_len + 1,utf16,len)) {
|
||||
free(out);
|
||||
return NULL;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int util_utf8toutf16(unsigned char *utf16, int dlen, unsigned char *utf8, int len) {
|
||||
unsigned char *src=utf8;
|
||||
char *dst;
|
||||
int new_len;
|
||||
int trailing_bytes;
|
||||
uint32_t utf32;
|
||||
uint16_t temp_word;
|
||||
|
||||
len=(int)strlen(utf8); /* ignore passed length, might be wrong! */
|
||||
if(!len)
|
||||
return FALSE;
|
||||
|
||||
new_len = util_utf8toutf16_len(utf8);
|
||||
if((new_len == -1) || (dlen <= (new_len+1))) {
|
||||
DPRINTF(E_LOG,L_MISC,"Cannot convert %s to utf16; E2BIG (%d vs %d)\n",utf8,new_len,dlen);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dst=utf16;
|
||||
|
||||
while(src < utf8 + len) {
|
||||
utf32=0;
|
||||
trailing_bytes=0;
|
||||
|
||||
if((*src & 0xE0) == 0xC0) trailing_bytes = 1;
|
||||
else if((*src & 0xF0) == 0xE0) trailing_bytes = 2;
|
||||
else if((*src & 0xF8) == 0xF0) trailing_bytes = 3;
|
||||
|
||||
if(src + trailing_bytes > utf8 + len) {
|
||||
DPRINTF(E_LOG,L_SCAN,"Invalid UTF8 string\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch(trailing_bytes) {
|
||||
case 0:
|
||||
utf32 = *src;
|
||||
break;
|
||||
case 1:
|
||||
utf32 = ((src[0] & 0x1F) << 6) |
|
||||
(src[1] & 0x3F);
|
||||
break;
|
||||
case 2:
|
||||
utf32 = ((src[0] & 0x0F) << 12) |
|
||||
((src[1] & 0x3F) << 6) |
|
||||
((src[2] & 0x3F));
|
||||
break;
|
||||
case 3:
|
||||
utf32 = ((src[0] & 0x07) << 18) |
|
||||
((src[1] & 0x3F) << 12) |
|
||||
((src[2] & 0x3F) << 6) |
|
||||
((src[3] & 0x3F));
|
||||
break;
|
||||
}
|
||||
|
||||
if(utf32 <= 0xFFFF) {
|
||||
/* we are encoding LE style... */
|
||||
*dst++ = utf32 & 0xFF;
|
||||
*dst++ = (utf32 & 0xFF00) >> 8;
|
||||
} else {
|
||||
/* Encode with surrogates */
|
||||
temp_word = 0xD800 | ((utf32 & 0x0FFC00) >> 10);
|
||||
*dst++ = temp_word & 0xFF;
|
||||
*dst++ = (temp_word & 0xFF00) >> 8;
|
||||
temp_word = 0xDC00 | (utf32 & 0x3FF);
|
||||
*dst++ = temp_word & 0xFF;
|
||||
*dst++ = (temp_word & 0xFF00) >> 8;
|
||||
}
|
||||
|
||||
src += (trailing_bytes + 1);
|
||||
}
|
||||
|
||||
*dst++ = '\x0';
|
||||
*dst = '\x0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
int util_utf8toutf16(unsigned char *utf16, size_t dlen, unsigned char *utf8, size_t slen) {
|
||||
int result;
|
||||
DPRINTF(E_DBG,L_MISC,"Converting %s to utf-16le (slen=%d, dlen=%d)\n",utf8,slen,dlen);
|
||||
|
||||
result=_util_xtoy(utf16, dlen, utf8, slen, "UTF-8","UTF-16LE");
|
||||
DPRINTF(E_DBG,L_MISC,"Result: %d\n",result);
|
||||
_util_hexdump(utf16,32);
|
||||
return result;
|
||||
}
|
||||
|
||||
int util_utf16toutf8(unsigned char *utf8, size_t dlen, unsigned char *utf16, size_t slen) {
|
||||
int result;
|
||||
|
||||
DPRINTF(E_DBG,L_MISC,"Converting *something* to utf-8 (slen=%d, dlen=%d)\n",slen,dlen);
|
||||
_util_hexdump(utf16,32);
|
||||
result = _util_xtoy(utf8, dlen, utf16, slen, "UTF-16LE","UTF-8");
|
||||
|
||||
DPRINTF(E_DBG,L_MISC,"Converted to %s\n",utf8);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned char *util_alloc_utf16toutf8(unsigned char *utf16, size_t slen) {
|
||||
char *utf8;
|
||||
|
||||
utf8=calloc(1, slen * 2 + 1);
|
||||
if(_util_xtoy(utf8,slen * 2 + 1,utf16,slen,"UTF-16LE","UTF-8")) {
|
||||
return utf8;
|
||||
}
|
||||
|
||||
free(utf8);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int _util_xtoy(unsigned char *dbuffer, size_t dlen, unsigned char *sbuffer, size_t slen, char *from, char *to) {
|
||||
iconv_t iv;
|
||||
size_t csize;
|
||||
|
||||
iv=iconv_open(to,from);
|
||||
if(iv == (iconv_t)-1) {
|
||||
DPRINTF(E_LOG,L_MISC,"iconv error: iconv_open failed with %d\n",errno);
|
||||
}
|
||||
|
||||
csize = iconv(iv,&sbuffer,&slen,&dbuffer,&dlen);
|
||||
if(csize == (size_t)-1) {
|
||||
switch(errno) {
|
||||
case EILSEQ:
|
||||
DPRINTF(E_LOG,L_MISC,"iconv error: Invalid multibyte sequence\n");
|
||||
break;
|
||||
case EINVAL:
|
||||
DPRINTF(E_LOG,L_MISC,"iconv error: Incomplete multibyte sequence\n");
|
||||
break;
|
||||
case E2BIG:
|
||||
DPRINTF(E_LOG,L_MISC,"iconv error: Insufficient buffer size\n");
|
||||
break;
|
||||
default:
|
||||
DPRINTF(E_LOG,L_MISC,"iconv error: unknown (%d)\n",errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
iconv_close(iv);
|
||||
|
||||
return (csize != (size_t)-1);
|
||||
}
|
||||
*/
|
||||
|
||||
void _util_hexdump(unsigned char *block, int len) {
|
||||
char charmap[256];
|
||||
int index;
|
||||
int row, offset;
|
||||
char output[80];
|
||||
char tmp[20];
|
||||
|
||||
memset(charmap,'.',sizeof(charmap));
|
||||
|
||||
for(index=' ';index<'~';index++) charmap[index]=index;
|
||||
for(row=0;row<(len+15)/16;row++) {
|
||||
sprintf(output,"%04X: ",row*16);
|
||||
for(offset=0; offset < 16; offset++) {
|
||||
if(row * 16 + offset < len) {
|
||||
sprintf(tmp,"%02X ",block[row*16 + offset]);
|
||||
} else {
|
||||
sprintf(tmp," ");
|
||||
}
|
||||
strcat(output,tmp);
|
||||
}
|
||||
|
||||
for(offset=0; offset < 16; offset++) {
|
||||
if(row * 16 + offset < len) {
|
||||
sprintf(tmp,"%c",charmap[block[row*16 + offset]]);
|
||||
} else {
|
||||
sprintf(tmp," ");
|
||||
}
|
||||
strcat(output,tmp);
|
||||
}
|
||||
|
||||
fprintf(stderr,"%s\n",output);
|
||||
}
|
||||
}
|
||||
|
|
14
src/util.h
14
src/util.h
|
@ -21,5 +21,19 @@ extern uint32_t util_djb_hash_str(char *str);
|
|||
|
||||
extern int util_must_exit(void);
|
||||
|
||||
//extern char *util_utf16toutf8(unsigned char *utf16, int len);
|
||||
//int util_utf8toutf16(unsigned char *utf16, size_t dlen, unsigned char *utf8, size_t slen);
|
||||
//int util_utf16toutf8(unsigned char *utf8, size_t dlen, unsigned char *utf16, size_t slen);
|
||||
//unsigned char *util_alloc_utf16toutf8(unsigned char *utf16, int slen);
|
||||
|
||||
extern unsigned char *util_utf8toutf16_alloc(unsigned char *utf8);
|
||||
extern unsigned char *util_utf16touft8_alloc(unsigned char *utf16, int len);
|
||||
extern int util_utf8toutf16_len(unsigned char *utf8);
|
||||
extern int util_utf16toutf8_len(unsigned char *utf16, int len);
|
||||
extern int util_utf8toutf16(unsigned char *utf16, int dlen, unsigned char *utf8, int len);
|
||||
extern int util_utf16toutf8(unsigned char *utf8, int dlen, unsigned char *utf16, int len);
|
||||
|
||||
|
||||
|
||||
#endif /* _UTIL_H_ */
|
||||
|
||||
|
|
34
src/win32.h
34
src/win32.h
|
@ -25,6 +25,23 @@
|
|||
#include <direct.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Type fixups */
|
||||
#define mode_t int
|
||||
#define ssize_t int
|
||||
#define socklen_t int
|
||||
|
||||
/* Consts */
|
||||
#define PIPE_BUF 256 /* What *should* this be on win32? */
|
||||
#define MAXDESC 512 /* http://msdn.microsoft.com/en-us/library/kdfaxaay.aspx */
|
||||
#define SHUT_RDWR 2
|
||||
#define ETIME 101
|
||||
#define PATH_MAX 512 /* it's clearly not _MAX_PATH... other projects seem to use 512 */
|
||||
#define MAX_NAME_LEN _MAX_PATH
|
||||
#define EADDRINUSE WSAEADDRINUSE
|
||||
|
||||
#define HOST "unknown-windows-ick"
|
||||
#define SERVICENAME "Firefly Media Server"
|
||||
|
||||
#include "os-win32.h"
|
||||
|
||||
#ifndef TRUE
|
||||
|
@ -65,6 +82,7 @@ typedef INT32 int32_t;
|
|||
#define strsep os_strsep
|
||||
#define open os_open
|
||||
#define waitfdtimed os_waitfdtimed
|
||||
#define fopen os_fopen
|
||||
|
||||
#define readdir_r os_readdir_r
|
||||
#define closedir os_closedir
|
||||
|
@ -80,22 +98,6 @@ typedef INT32 int32_t;
|
|||
/* privately implemented functions: @see os-win32.c */
|
||||
#define gettimeofday os_gettimeofday
|
||||
|
||||
/* Type fixups */
|
||||
#define mode_t int
|
||||
#define ssize_t int
|
||||
#define socklen_t int
|
||||
|
||||
/* Consts */
|
||||
#define PIPE_BUF 256 /* What *should* this be on win32? */
|
||||
#define MAXDESC 512 /* http://msdn.microsoft.com/en-us/library/kdfaxaay.aspx */
|
||||
#define SHUT_RDWR 2
|
||||
#define MAX_NAME_LEN _MAX_PATH
|
||||
#define ETIME 101
|
||||
#define PATH_MAX 512 /* it's clearly not _MAX_PATH... other projects seem to use 512 */
|
||||
#define EADDRINUSE WSAEADDRINUSE
|
||||
|
||||
#define HOST "unknown-windows-ick"
|
||||
#define SERVICENAME "Firefly Media Server"
|
||||
|
||||
#define CONFFILE os_configpath()
|
||||
|
||||
|
|
|
@ -168,6 +168,9 @@
|
|||
<File
|
||||
RelativePath="..\src\mp3-scanner.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\os-win32-u.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\os-win32.c">
|
||||
</File>
|
||||
|
@ -287,6 +290,9 @@
|
|||
<File
|
||||
RelativePath="..\src\uici.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\util.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\w32-eventlog.h">
|
||||
</File>
|
||||
|
|
Loading…
Reference in New Issue