diff --git a/include/cdio/bytesex.h b/include/cdio/bytesex.h index e1be483e..a85b965e 100644 --- a/include/cdio/bytesex.h +++ b/include/cdio/bytesex.h @@ -29,7 +29,7 @@ #define __CDIO_BYTESEX_H__ #include -#include +#include /* also defines CDIO_INLINE */ #include /** 16-bit big-endian to little-endian */ @@ -67,19 +67,19 @@ # define UINT64_SWAP_LE_BE UINT64_SWAP_LE_BE_C #endif -inline static +static CDIO_INLINE uint16_t uint16_swap_le_be (const uint16_t val) { return UINT16_SWAP_LE_BE (val); } -inline static +static CDIO_INLINE uint32_t uint32_swap_le_be (const uint32_t val) { return UINT32_SWAP_LE_BE (val); } -inline static +static CDIO_INLINE uint64_t uint64_swap_le_be (const uint64_t val) { return UINT64_SWAP_LE_BE (val); @@ -119,10 +119,10 @@ uint64_t uint64_swap_le_be (const uint64_t val) /** converter function template */ #define CVT_TO_FUNC(bits) \ - static inline uint ## bits ## _t \ + static CDIO_INLINE uint ## bits ## _t \ uint ## bits ## _to_be (uint ## bits ## _t val) \ { return UINT ## bits ## _TO_BE (val); } \ - static inline uint ## bits ## _t \ + static CDIO_INLINE uint ## bits ## _t \ uint ## bits ## _to_le (uint ## bits ## _t val) \ { return UINT ## bits ## _TO_LE (val); } \ @@ -163,14 +163,14 @@ CVT_TO_FUNC(64) #define from_722(i) uint16_from_be(i) /** Convert from uint16_t to ISO 9669 7.2.3 format */ -static inline uint32_t +static CDIO_INLINE uint32_t to_723(uint16_t i) { return uint32_swap_le_be(i) | i; } /** Convert from ISO 9660 7.2.3 format to uint16_t */ -static inline uint16_t +static CDIO_INLINE uint16_t from_723 (uint32_t p) { if (uint32_swap_le_be (p) != p) @@ -192,14 +192,14 @@ from_723 (uint32_t p) #define from_732(i) uint32_from_be(i) /** Convert from uint16_t to ISO 9669 7.3.3 format */ -static inline uint64_t +static CDIO_INLINE uint64_t to_733(uint32_t i) { return uint64_swap_le_be(i) | i; } /** Convert from ISO 9660 7.3.3 format to uint32_t */ -static inline uint32_t +static CDIO_INLINE uint32_t from_733 (uint64_t p) { if (uint64_swap_le_be (p) != p) diff --git a/include/cdio/bytesex_asm.h b/include/cdio/bytesex_asm.h index 7f1f131a..0ee1aaad 100644 --- a/include/cdio/bytesex_asm.h +++ b/include/cdio/bytesex_asm.h @@ -1,7 +1,5 @@ /* - $Id: bytesex_asm.h,v 1.3 2008/03/25 15:59:08 karl Exp $ - - Copyright (C) 2008 Rocky Bernstein + Copyright (C) 2008, 2012 Rocky Bernstein 2001, 2004, 2005 Herbert Valerio Riedel 2001 Sven Ottemann @@ -32,9 +30,21 @@ #include +#if !defined CDIO_INLINE +#if defined(__cplusplus) || defined(inline) +#define CDIO_INLINE inline +#elif defined(__GNUC__) +#define CDIO_INLINE __inline__ +#elif defined(_MSC_VER) +#define CDIO_INLINE __inline +#else +#define CDIO_INLINE +#endif +#endif /* CDIO_INLINE */ + #if defined(__powerpc__) && defined(__GNUC__) -inline static +static CDIO_INLINE uint32_t uint32_swap_le_be_asm(const uint32_t a) { uint32_t b; @@ -46,7 +56,7 @@ uint32_t uint32_swap_le_be_asm(const uint32_t a) return b; } -inline static +static CDIO_INLINE uint16_t uint16_swap_le_be_asm(const uint16_t a) { uint32_t b; @@ -63,7 +73,7 @@ uint16_t uint16_swap_le_be_asm(const uint16_t a) #elif defined(__mc68000__) && defined(__STORMGCC__) -inline static +static CDIO_INLINE uint32_t uint32_swap_le_be_asm(uint32_t a __asm__("d0")) { /* __asm__("rolw #8,%0; swap %0; rolw #8,%0" : "=d" (val) : "0" (val)); */ @@ -75,7 +85,7 @@ uint32_t uint32_swap_le_be_asm(uint32_t a __asm__("d0")) return(a); } -inline static +static CDIO_INLINE uint16_t uint16_swap_le_be_asm(uint16_t a __asm__("d0")) { __asm__("move.l %1,d0;rol.w #8,d0;move.l d0,%0" @@ -90,7 +100,7 @@ uint16_t uint16_swap_le_be_asm(uint16_t a __asm__("d0")) #elif 0 && defined(__i386__) && defined(__GNUC__) -inline static +static CDIO_INLINE uint32_t uint32_swap_le_be_asm(uint32_t a) { __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ @@ -102,7 +112,7 @@ uint32_t uint32_swap_le_be_asm(uint32_t a) return(a); } -inline static +static CDIO_INLINE uint16_t uint16_swap_le_be_asm(uint16_t a) { __asm__("xchgb %b0,%h0" /* swap bytes */ diff --git a/include/cdio/cdio.h b/include/cdio/cdio.h index 16ca9131..9792e942 100644 --- a/include/cdio/cdio.h +++ b/include/cdio/cdio.h @@ -29,17 +29,10 @@ /** Application Interface or Protocol version number. If the public * interface changes, we increase this number. */ -#define CDIO_API_VERSION 5 +#define CDIO_API_VERSION 6 #include #include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - #include #ifdef __cplusplus diff --git a/include/cdio/read.h b/include/cdio/read.h index 81e5148a..bc13b5f7 100644 --- a/include/cdio/read.h +++ b/include/cdio/read.h @@ -26,16 +26,7 @@ #ifndef __CDIO_READ_H__ #define __CDIO_READ_H__ -#ifndef EXTERNAL_LIBCDIO_CONFIG_H -#define EXTERNAL_LIBCDIO_CONFIG_H -/* Need for HAVE_SYS_TYPES_H */ -#include -#endif - -#ifdef HAVE_SYS_TYPES_H -/* Some systems need this for off_t and ssize. */ -#include -#endif +#include #ifdef __cplusplus extern "C" { diff --git a/include/cdio/rock.h b/include/cdio/rock.h index 480c7c63..3a24f911 100644 --- a/include/cdio/rock.h +++ b/include/cdio/rock.h @@ -35,16 +35,6 @@ extern "C" { #endif /* __cplusplus */ -/* MSYS 1.0.10 with MinGW 3.4.2 (and perhaps others) don't have - S_ISSOCK() or S_ISLNK() macros, so we'll roll our own. */ -#if !defined(HAVE_S_ISSOCK) && !defined(S_ISSOCK) -#define S_ISSOCK(st_mode) ((((st_mode)) & 0170000) == (0140000)) -#endif - -#if !defined(HAVE_S_ISLNK) && !defined(S_ISLNK) -#define S_ISLNK(st_mode) ((((st_mode)) & 0170000) == (0010000)) -#endif - /*! An enumeration for some of the ISO_ROCK_* \#defines below. This isn't really an enumeration one would really use in a program it is to be helpful in debuggers where wants just to refer to the ISO_ROCK_* diff --git a/include/cdio/types.h b/include/cdio/types.h index 9385b2c6..919d3cbe 100644 --- a/include/cdio/types.h +++ b/include/cdio/types.h @@ -29,37 +29,35 @@ extern "C" { #endif /* __cplusplus */ -#ifndef EXTERNAL_LIBCDIO_CONFIG_H -#define EXTERNAL_LIBCDIO_CONFIG_H -#include -#endif - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - - /* provide some C99 definitions */ - -#if defined(HAVE_SYS_TYPES_H) +/* If is not available on your platform please + contact the libcdio mailing list so that we can fix it! */ +#if !defined(ARE_THERE_STILL_ENVS_WITHOUT_SYS_TYPES) #include #endif -#if defined(HAVE_STDINT_H) -# include -#elif defined(HAVE_INTTYPES_H) -# include -#elif defined(AMIGA) || defined(__linux__) - typedef u_int8_t uint8_t; - typedef u_int16_t uint16_t; - typedef u_int32_t uint32_t; - typedef u_int64_t uint64_t; +#if defined(AMIGA) +typedef u_int8_t uint8_t; +typedef u_int16_t uint16_t; +typedef u_int32_t uint32_t; +typedef u_int64_t uint64_t; #else - /* warning ISO/IEC 9899:1999 was missing and even */ - /* fixme */ -#endif /* HAVE_STDINT_H */ - +/* If is not available on your platform please + contact the libcdio mailing list so that we can fix it! + For MSVC, you can find both a public domain stdint.h and + inttypes.h in the MSVC/missing directory of libcdio. */ +#include +#endif + typedef uint8_t ubyte; +/* MSVC does not define mode_t and ssize_t by default. The way + to compensate for missing UNIX types is to include a custom + unistd.h that defines them. Such a file is provided with + the libcdio source, in the MSVC/missing directory */ +#if defined(_MSC_VER) +#include +#endif + /* default HP/UX macros are broken */ #if defined(__hpux__) # undef UINT16_C @@ -106,15 +104,24 @@ typedef uint8_t ubyte; #endif #ifndef __cplusplus -# if defined(HAVE_STDBOOL_H) -# include -# else - /* ISO/IEC 9899:1999 missing -- enabling workaround */ - -# define false 0 -# define true 1 -# define bool uint8_t -# endif /*HAVE_STDBOOL_H*/ + +/* All the stdbool.h seem to define those */ +#ifndef __bool_true_false_are_defined +#define __bool_true_false_are_defined 1 + +#undef bool +#undef true +#undef false + +#ifdef _Bool +#define bool _Bool +#else +#define bool int +#endif +#define true 1 +#define false 0 + +#endif /* __bool_true_false_are_defined */ #endif /*C++*/ /* some GCC optimizations -- gcc 2.5+ */ @@ -148,18 +155,21 @@ typedef uint8_t ubyte; /* for GCC we try to use GNUC_PACKED */ # define PRAGMA_BEGIN_PACKED # define PRAGMA_END_PACKED -#elif defined(HAVE_ISOC99_PRAGMA) +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) /* should work with most EDG-frontend based compilers */ # define PRAGMA_BEGIN_PACKED _Pragma("pack(1)") # define PRAGMA_END_PACKED _Pragma("pack()") +#elif defined(_MSC_VER) +# define PRAGMA_BEGIN_PACKED __pragma(pack(push, 1)) +# define PRAGMA_END_PACKED __pragma(pack(pop)) #else /* neither gcc nor _Pragma() available... */ /* ...so let's be naive and hope the regression testsuite is run... */ # define PRAGMA_BEGIN_PACKED # define PRAGMA_END_PACKED #endif - /** - * user-directed static branch prediction gcc 2.96+ + /* + * user directed static branch prediction gcc 2.96+ */ #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 95) # define GNUC_LIKELY(x) __builtin_expect((x),true) diff --git a/lib/driver/utf8.c b/lib/driver/utf8.c index 9e7a9018..5ae9adc3 100644 --- a/lib/driver/utf8.c +++ b/lib/driver/utf8.c @@ -1,6 +1,7 @@ /* Copyright (C) 2006, 2008 Burkhard Plaum Copyright (C) 2011 Rocky Bernstein + Copyright (C) 2012 Pete Batard This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,19 +32,20 @@ #include #endif -#ifdef HAVE_ICONV -# include -#endif - #ifdef HAVE_ERRNO_H #include #endif #include +#include +#ifdef HAVE_STDIO_H #include +#endif - +// TODO: also remove the need for iconv on MinGW +#ifdef HAVE_ICONV +#include struct cdio_charset_coverter_s { iconv_t ic; @@ -142,13 +144,13 @@ do_convert(iconv_t cd, char * src, int src_len, ret = realloc(ret, alloc_size); if (ret == NULL) { - fprintf(stderr, "Can't realloc(%d).\n", alloc_size); + cdio_warn("Can't realloc(%d).", alloc_size); return false; } outbuf = ret + output_pos; break; default: - fprintf(stderr, "Iconv failed: %s\n", strerror(errno)); + cdio_warn("Iconv failed: %s", strerror(errno)); if (ret != NULL) free(ret); return false; @@ -207,4 +209,93 @@ bool cdio_charset_to_utf8(char *src, size_t src_len, cdio_utf8_t **dst, iconv_close(ic); return result; } +#elif defined(_WIN32) +#include + +#define wchar_to_utf8_no_alloc(wsrc, dest, dest_size) \ + WideCharToMultiByte(CP_UTF8, 0, wsrc, -1, dest, dest_size, NULL, NULL) +#define utf8_to_wchar_no_alloc(src, wdest, wdest_size) \ + MultiByteToWideChar(CP_UTF8, 0, src, -1, wdest, wdest_size) + +/* + * Converts an UTF-16 string to UTF8 (allocate returned string) + * Returns NULL on error + */ +static __inline char* wchar_to_utf8(const wchar_t* wstr) +{ + int size = 0; + char* str = NULL; + + /* Find out the size we need to allocate for our converted string */ + size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); + if (size <= 1) // An empty string would be size 1 + return NULL; + + if ((str = (char*)calloc(size, 1)) == NULL) + return NULL; + + if (wchar_to_utf8_no_alloc(wstr, str, size) != size) { + free(str); + return NULL; + } + + return str; +} + +/* + * Converts an UTF8 string to UTF-16 (allocate returned string) + * Returns NULL on error + */ +static __inline wchar_t* utf8_to_wchar(const char* str) +{ + int size = 0; + wchar_t* wstr = NULL; + + /* Find out the size we need to allocate for our converted string */ + size = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + if (size <= 1) // An empty string would be size 1 + return NULL; + + if ((wstr = (wchar_t*)calloc(size, sizeof(wchar_t))) == NULL) + return NULL; + + if (utf8_to_wchar_no_alloc(str, wstr, size) != size) { + free(wstr); + return NULL; + } + return wstr; +} + +bool cdio_charset_to_utf8(char *src, size_t src_len, cdio_utf8_t **dst, + const char * src_charset) +{ + wchar_t* le_src; + + if (src == NULL || dst == NULL || src_charset == NULL || strcmp(src_charset, "UCS-2BE") != 0) + return false; + + if (src_len == (size_t)-1) { + for (src_len = 0; ((uint16_t*)src)[src_len] !=0; src_len++); + src_len <<=2; + } + + /* zero lenght is a headache (LCMapString doesn't support it) + => eliminate this case first */ + if (src_len == 0) { + *dst = (cdio_utf8_t*)malloc(1); + *dst[0] = 0; + return true; + } + + le_src = (wchar_t*)malloc(src_len+2); + /* WideCharToMultiByte only takes UCS-2LE, and we are fed UCS-2BE + => perform byte reversal */ + LCMapStringW(0, LCMAP_BYTEREV, (LPCWSTR)src, src_len, le_src, src_len); + *dst = wchar_to_utf8(le_src); + free(le_src); + + return (*dst != NULL); +} +#endif /* HAVE_ICONV */ + #endif /* HAVE_JOLIET */ diff --git a/lib/udf/udf_fs.c b/lib/udf/udf_fs.c index e5900c78..b8209f17 100644 --- a/lib/udf/udf_fs.c +++ b/lib/udf/udf_fs.c @@ -46,6 +46,10 @@ # define __CDIO_CONFIG_H__ 1 #endif +#ifdef HAVE_STDIO_H +#include +#endif + #ifdef HAVE_STRING_H # include #endif @@ -68,6 +72,7 @@ const char VSD_STD_ID_TEA01[] = {'T', 'E', 'A', '0', '1'}; #include #include "udf_private.h" #include "udf_fs.h" +#include "cdio_assert.h" /* * The UDF specs are pretty clear on how each data structure is made @@ -236,7 +241,10 @@ udf_fopen(udf_dirent_t *p_udf_root, const char *psz_name) if (p_udf_root) { char tokenline[udf_MAX_PATHLEN]; char *psz_token; - + + /* file position must be reset when accessing a new file */ + p_udf_root->p_udf->i_position = 0; + strncpy(tokenline, psz_name, udf_MAX_PATHLEN); psz_token = strtok(tokenline, udf_PATH_DELIMITERS); if (psz_token) { @@ -284,11 +292,8 @@ static udf_dirent_t * udf_new_dirent(udf_file_entry_t *p_udf_fe, udf_t *p_udf, const char *psz_name, bool b_dir, bool b_parent) { - const unsigned int i_alloc_size = p_udf_fe->i_alloc_descs - + p_udf_fe->i_extended_attr; - udf_dirent_t *p_udf_dirent = (udf_dirent_t *) - calloc(1, sizeof(udf_dirent_t) + i_alloc_size); + calloc(1, sizeof(udf_dirent_t)); if (!p_udf_dirent) return NULL; p_udf_dirent->psz_name = strdup(psz_name); @@ -299,7 +304,7 @@ udf_new_dirent(udf_file_entry_t *p_udf_fe, udf_t *p_udf, p_udf_dirent->dir_left = uint64_from_le(p_udf_fe->info_len); memcpy(&(p_udf_dirent->fe), p_udf_fe, - sizeof(udf_file_entry_t) + i_alloc_size); + sizeof(udf_file_entry_t)); udf_get_lba( p_udf_fe, &(p_udf_dirent->i_loc), &(p_udf_dirent->i_loc_end) ); return p_udf_dirent; @@ -311,14 +316,21 @@ udf_new_dirent(udf_file_entry_t *p_udf_fe, udf_t *p_udf, */ driver_return_code_t udf_read_sectors (const udf_t *p_udf, void *ptr, lsn_t i_start, - long int i_blocks) + long i_blocks) { driver_return_code_t ret; - long int i_read; - long int i_byte_offset; + long i_read; + off_t i_byte_offset; if (!p_udf) return 0; - i_byte_offset = (i_start * UDF_BLOCKSIZE); + /* Without the cast, i_start * UDF_BLOCKSIZE may be evaluated as 32 bit */ + i_byte_offset = ((off_t)i_start) * UDF_BLOCKSIZE; + /* Since we're using SEEK_SET, the value must be positive */ + if (i_byte_offset < 0) { + if (sizeof(off_t) <= 4) /* probably missing LFS */ + cdio_warn("Large File Support is required to access streams of 2 GB or more"); + return DRIVER_OP_BAD_PARAMETER; + } if (p_udf->b_stream) { ret = cdio_stream_seek (p_udf->stream, i_byte_offset, SEEK_SET); @@ -346,6 +358,9 @@ udf_open (const char *psz_path) if (!p_udf) return NULL; + /* Sanity check */ + cdio_assert(sizeof(udf_file_entry_t) == UDF_BLOCKSIZE); + p_udf->cdio = cdio_open(psz_path, DRIVER_UNKNOWN); if (!p_udf->cdio) { /* Not a CD-ROM drive or CD Image. Maybe it's a UDF file not @@ -495,9 +510,9 @@ udf_get_root (udf_t *p_udf, bool b_any_partition, partition_num_t i_partition) Directory File Entry. */ for (i_lba = mvds_start; i_lba < mvds_end; i_lba++) { - uint8_t data[UDF_BLOCKSIZE]; + uint8_t data2[UDF_BLOCKSIZE]; - partition_desc_t *p_partition = (partition_desc_t *) &data; + partition_desc_t *p_partition = (partition_desc_t *) &data2; if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, p_partition, i_lba, 1) ) return NULL; @@ -513,7 +528,7 @@ udf_get_root (udf_t *p_udf, bool b_any_partition, partition_num_t i_partition) } } else if (!udf_checktag(&p_partition->tag, TAGID_LOGVOL)) { /* Get fileset descriptor */ - logical_vol_desc_t *p_logvol = (logical_vol_desc_t *) &data; + logical_vol_desc_t *p_logvol = (logical_vol_desc_t *) &data2; bool b_valid = UDF_BLOCKSIZE == uint32_from_le(p_logvol->logical_blocksize); @@ -582,19 +597,18 @@ udf_opendir(const udf_dirent_t *p_udf_dirent) { if (p_udf_dirent->b_dir && !p_udf_dirent->b_parent && p_udf_dirent->fid) { udf_t *p_udf = p_udf_dirent->p_udf; - uint8_t data[UDF_BLOCKSIZE]; - udf_file_entry_t *p_udf_fe = (udf_file_entry_t *) &data; + udf_file_entry_t udf_fe; driver_return_code_t i_ret = - udf_read_sectors(p_udf, p_udf_fe, p_udf->i_part_start + udf_read_sectors(p_udf, &udf_fe, p_udf->i_part_start + p_udf_dirent->fid->icb.loc.lba, 1); if (DRIVER_OP_SUCCESS == i_ret - && !udf_checktag(&p_udf_fe->tag, TAGID_FILE_ENTRY)) { + && !udf_checktag(&udf_fe.tag, TAGID_FILE_ENTRY)) { - if (ICBTAG_FILE_TYPE_DIRECTORY == p_udf_fe->icb_tag.file_type) { + if (ICBTAG_FILE_TYPE_DIRECTORY == udf_fe.icb_tag.file_type) { udf_dirent_t *p_udf_dirent_new = - udf_new_dirent(p_udf_fe, p_udf, p_udf_dirent->psz_name, true, true); + udf_new_dirent(&udf_fe, p_udf, p_udf_dirent->psz_name, true, true); return p_udf_dirent_new; } } @@ -612,7 +626,10 @@ udf_readdir(udf_dirent_t *p_udf_dirent) return NULL; } + /* file position must be reset when accessing a new file */ p_udf = p_udf_dirent->p_udf; + p_udf->i_position = 0; + if (p_udf_dirent->fid) { /* advance to next File Identifier Descriptor */ /* FIXME: need to advance file entry (fe) as well. */ @@ -655,16 +672,10 @@ udf_readdir(udf_dirent_t *p_udf_dirent) { const unsigned int i_len = p_udf_dirent->fid->i_file_id; - uint8_t data[UDF_BLOCKSIZE] = {0}; - udf_file_entry_t *p_udf_fe = (udf_file_entry_t *) &data; - if (DRIVER_OP_SUCCESS != udf_read_sectors(p_udf, p_udf_fe, p_udf->i_part_start + if (DRIVER_OP_SUCCESS != udf_read_sectors(p_udf, &p_udf_dirent->fe, p_udf->i_part_start + p_udf_dirent->fid->icb.loc.lba, 1)) return NULL; - - memcpy(&(p_udf_dirent->fe), p_udf_fe, - sizeof(udf_file_entry_t) + p_udf_fe->i_alloc_descs - + p_udf_fe->i_extended_attr ); if (strlen(p_udf_dirent->psz_name) < i_len) p_udf_dirent->psz_name = (char *)