Merge pull request #2090 from Exiv2/main_WinUtf8

Get argv from main entry point encoded as UTF-8
main
Luis Díaz Más 3 years ago committed by GitHub
commit e450c49b07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -31,5 +31,5 @@ jobs:
run: | run: |
mkdir build && cd build mkdir build && cd build
cmake $CMAKE_FLAGS -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DBUILD_SHARED_LIBS=${{ matrix.shared_libraries }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} .. cmake $CMAKE_FLAGS -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DBUILD_SHARED_LIBS=${{ matrix.shared_libraries }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} ..
make -j $(nproc) cmake --build . --parallel
make install cmake --install .

@ -33,7 +33,7 @@ jobs:
-DEXIV2_BUILD_FUZZ_TESTS=ON \ -DEXIV2_BUILD_FUZZ_TESTS=ON \
-DEXIV2_TEAM_USE_SANITIZERS=ON \ -DEXIV2_TEAM_USE_SANITIZERS=ON \
.. && \ .. && \
cmake --build . cmake --build . --parallel
- name: Fuzz - name: Fuzz
run: | run: |

@ -49,12 +49,12 @@ jobs:
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \ -DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DCMAKE_INSTALL_PREFIX=install \ -DCMAKE_INSTALL_PREFIX=install \
.. && \ .. && \
cmake --build . cmake --build . --parallel
- name: Install - name: Install
run: | run: |
cd build cd build
cmake --build . --target install cmake --install .
tree install tree install
- name: Test - name: Test

@ -49,7 +49,7 @@ jobs:
-DBUILD_WITH_COVERAGE=ON \ -DBUILD_WITH_COVERAGE=ON \
-DCMAKE_INSTALL_PREFIX=install \ -DCMAKE_INSTALL_PREFIX=install \
.. && \ .. && \
cmake --build . cmake --build . --parallel
- name: Tests + Upload coverage - name: Tests + Upload coverage
run: | run: |
@ -96,7 +96,7 @@ jobs:
run: | run: |
cd build cd build
cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DEXIV2_ENABLE_PNG=ON -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_ENABLE_CURL=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DEXIV2_ENABLE_BMFF=ON -DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON -DBUILD_WITH_COVERAGE=OFF -DCMAKE_INSTALL_PREFIX=install .. cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DEXIV2_ENABLE_PNG=ON -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_ENABLE_CURL=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DEXIV2_ENABLE_BMFF=ON -DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON -DBUILD_WITH_COVERAGE=OFF -DCMAKE_INSTALL_PREFIX=install ..
cmake --build . cmake --build . --parallel
- name: Tests with valgrind - name: Tests with valgrind
run: | run: |
@ -145,7 +145,7 @@ jobs:
-DEXIV2_TEAM_USE_SANITIZERS=ON \ -DEXIV2_TEAM_USE_SANITIZERS=ON \
-DCMAKE_INSTALL_PREFIX=install \ -DCMAKE_INSTALL_PREFIX=install \
.. && \ .. && \
cmake --build . cmake --build . --parallel
- name: Tests - name: Tests
run: | run: |
@ -194,7 +194,7 @@ jobs:
-DEXIV2_ENABLE_NLS=ON \ -DEXIV2_ENABLE_NLS=ON \
-DCMAKE_CXX_FLAGS="-DEXIV2_DEBUG_MESSAGES" \ -DCMAKE_CXX_FLAGS="-DEXIV2_DEBUG_MESSAGES" \
.. && \ .. && \
make -j cmake --build . --parallel
- name: Generate documentation - name: Generate documentation
run: | run: |

@ -44,12 +44,12 @@ jobs:
-DCMAKE_INSTALL_PREFIX=install \ -DCMAKE_INSTALL_PREFIX=install \
-DCMAKE_CXX_FLAGS="-Wno-deprecated-declarations" \ -DCMAKE_CXX_FLAGS="-Wno-deprecated-declarations" \
.. && \ .. && \
cmake --build . cmake --build . --parallel
- name: Install - name: Install
run: | run: |
cd build cd build
cmake --build . --target install cmake --install .
- name: Test - name: Test
run: | run: |

@ -73,14 +73,13 @@ jobs:
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} ` -DCMAKE_BUILD_TYPE=${{matrix.build_type}} `
-DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} ` -DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} `
-DEXIV2_ENABLE_NLS=OFF ` -DEXIV2_ENABLE_NLS=OFF `
-DEXIV2_ENABLE_WIN_UNICODE=OFF `
-DEXIV2_ENABLE_WEBREADY=ON ` -DEXIV2_ENABLE_WEBREADY=ON `
-DEXIV2_ENABLE_BMFF=ON ` -DEXIV2_ENABLE_BMFF=ON `
-DEXIV2_BUILD_UNIT_TESTS=ON ` -DEXIV2_BUILD_UNIT_TESTS=ON `
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON ` -DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON `
-DCMAKE_INSTALL_PREFIX=install ` -DCMAKE_INSTALL_PREFIX=install `
-S . -B build && ` -S . -B build && `
cmake --build build cmake --build build --parallel
- name: Install - name: Install
run: | run: |
@ -95,22 +94,25 @@ jobs:
msys2: msys2:
runs-on: windows-latest runs-on: windows-latest
timeout-minutes: 40
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
build_type: [Release, Debug] build_type: [Release, Debug]
shared_libraries: [ON, OFF] shared_libraries: [ON, OFF]
sys: [MINGW64] sys: [UCRT64]
name: MSYS2 ${{matrix.sys}} - BuildType:${{matrix.build_type}} - SHARED:${{matrix.shared_libraries}} name: MSYS2 ${{matrix.sys}} - BuildType:${{matrix.build_type}} - SHARED:${{matrix.shared_libraries}}
defaults: defaults:
run: run:
shell: msys2 {0} shell: msys2 {0}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Set up MSYS2 - name: Set up MSYS2
uses: msys2/setup-msys2@v2 uses: msys2/setup-msys2@v2
with: with:
path-type: strict
msystem: ${{matrix.sys}} msystem: ${{matrix.sys}}
update: true update: true
install: >- install: >-
@ -118,28 +120,25 @@ jobs:
pacboy: >- pacboy: >-
toolchain:p toolchain:p
cmake:p cmake:p
ninja:p
expat:p expat:p
gettext:p gettext:p
gtest:p gtest:p
libiconv:p libiconv:p
python-lxml:p
zlib:p zlib:p
- name: Build - name: Build
run: | run: |
cmake -GNinja \ cmake -G"MSYS Makefiles" \
-DCMAKE_CXX_FLAGS=-Wno-deprecated \ -DCMAKE_CXX_FLAGS=-Wno-deprecated \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \ -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} \ -DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} \
-DEXIV2_BUILD_SAMPLES=ON \ -DEXIV2_BUILD_SAMPLES=ON \
-DEXIV2_ENABLE_NLS=ON \ -DEXIV2_ENABLE_NLS=OFF \
-DEXIV2_ENABLE_WIN_UNICODE=ON \
-DEXIV2_ENABLE_WEBREADY=ON \ -DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_BMFF=ON \ -DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_BUILD_UNIT_TESTS=ON \ -DEXIV2_BUILD_UNIT_TESTS=ON \
-S . -B build && \ -S . -B build && \
cmake --build build cmake --build build --parallel
- name: Test - name: Test
run: | run: |
@ -190,7 +189,7 @@ jobs:
-DEXIV2_ENABLE_BMFF=ON \ -DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_BUILD_UNIT_TESTS=OFF \ -DEXIV2_BUILD_UNIT_TESTS=OFF \
-S . -B build && \ -S . -B build && \
cmake --build build cmake --build build --parallel
- name: Test - name: Test
run: | run: |

@ -66,7 +66,7 @@ jobs:
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON ` -DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON `
-DCMAKE_INSTALL_PREFIX=install .. ` -DCMAKE_INSTALL_PREFIX=install .. `
-S . -B build && ` -S . -B build && `
cmake --build build cmake --build build --parallel
- name: Test - name: Test
@ -109,7 +109,7 @@ jobs:
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \ -DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DCMAKE_INSTALL_PREFIX=install \ -DCMAKE_INSTALL_PREFIX=install \
.. && \ .. && \
cmake --build . cmake --build . --parallel
- name: Test - name: Test
run: | run: |
@ -151,7 +151,7 @@ jobs:
-DCMAKE_INSTALL_PREFIX=install \ -DCMAKE_INSTALL_PREFIX=install \
-DCMAKE_CXX_FLAGS="-Wno-deprecated-declarations" \ -DCMAKE_CXX_FLAGS="-Wno-deprecated-declarations" \
.. && \ .. && \
cmake --build . cmake --build . --parallel
- name: Test - name: Test
run: | run: |

@ -47,7 +47,7 @@ jobs:
-DBUILD_WITH_COVERAGE=ON \ -DBUILD_WITH_COVERAGE=ON \
-DCMAKE_INSTALL_PREFIX=install \ -DCMAKE_INSTALL_PREFIX=install \
.. && \ .. && \
make -j cmake --build . --parallel
- name: Tests + Upload coverage - name: Tests + Upload coverage
run: | run: |

@ -9,7 +9,7 @@ project(exiv2 # use TWEAK to categorize the build
# 1.00.0.20 = RC2 Preview # 1.00.0.20 = RC2 Preview
# 1.00.0.29 = RC2 Development # 1.00.0.29 = RC2 Development
DESCRIPTION "Exif/IPTC/Xmp C++ metadata library and tools plus ICC Profiles, Previews and more." DESCRIPTION "Exif/IPTC/Xmp C++ metadata library and tools plus ICC Profiles, Previews and more."
LANGUAGES CXX LANGUAGES C CXX
) )
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
@ -24,10 +24,8 @@ option( EXIV2_ENABLE_XMP "Build with XMP metadata support"
option( EXIV2_ENABLE_EXTERNAL_XMP "Use external version of XMP" OFF ) option( EXIV2_ENABLE_EXTERNAL_XMP "Use external version of XMP" OFF )
option( EXIV2_ENABLE_PNG "Build with png support (requires libz)" ON ) option( EXIV2_ENABLE_PNG "Build with png support (requires libz)" ON )
option( EXIV2_ENABLE_NLS "Build native language support (requires gettext)" OFF ) option( EXIV2_ENABLE_NLS "Build native language support (requires gettext)" OFF )
option( EXIV2_ENABLE_PRINTUCS2 "Build with Printucs2" ON )
option( EXIV2_ENABLE_LENSDATA "Build including lens data" ON ) option( EXIV2_ENABLE_LENSDATA "Build including lens data" ON )
option( EXIV2_ENABLE_DYNAMIC_RUNTIME "Use dynamic runtime (used for static libs)" ON ) option( EXIV2_ENABLE_DYNAMIC_RUNTIME "Use dynamic runtime (used for static libs)" ON )
option( EXIV2_ENABLE_WIN_UNICODE "Use Unicode paths (wstring) on Windows" OFF )
option( EXIV2_ENABLE_WEBREADY "Build webready support into library" OFF ) option( EXIV2_ENABLE_WEBREADY "Build webready support into library" OFF )
option( EXIV2_ENABLE_CURL "USE Libcurl for HttpIo (WEBREADY)" OFF ) option( EXIV2_ENABLE_CURL "USE Libcurl for HttpIo (WEBREADY)" OFF )
option( EXIV2_ENABLE_BMFF "Build with BMFF support" ON ) option( EXIV2_ENABLE_BMFF "Build with BMFF support" ON )

@ -1114,53 +1114,45 @@ I recommend that you build and install CMake from source.
## MinGW/msys2 ## MinGW/msys2
Please note that the platform MinGW/msys2 32 is obsolete and superceded by MinGW/msys2 64. Please note that the platform MinGW/msys2 32 is obsolete and superceded by MinGW/msys2 64. It is important to highlight that we rely on using the Universal C Runtime (UCRT) and its relatively new support for UTF-8. Check this [PR](https://github.com/Exiv2/exiv2/pull/2090) for more information. Therefore you will need to use the [URCT MSYS environment](https://www.msys2.org/docs/environments/).
### MinGW/msys2 64 bit Install the latest version of [MSYS2](https://repo.msys2.org/distrib/msys2-x86_64-latest.exe), and follow the installation instructions available [here](https://www.msys2.org/).
Install the latest version of [MSYS2](https://repo.msys2.org/distrib/msys2-x86_64-latest.exe)
The CI workflow file `.github/workflows/on_PR_windows_matrix.yml` has a build job named `msys2` with instructions showing how to configure Exiv2 on MinGW/msys2. The CI workflow file `.github/workflows/on_PR_windows_matrix.yml` has a build job named `msys2` with instructions showing how to configure Exiv2 on MinGW/msys2.
I use the following batch file to start the MinGW/msys2 64 bit bash shell from the Dos Command Prompt (cmd.exe) ### Install exiv2 Dependencies
```bat Please note that you will need to install the `ucrt` package version of the exiv2 dependencies:
@echo off
setlocal
set "PATH=c:\msys64\mingw64\bin;c:\msys64\usr\bin;c:\msys64\usr\local\bin;"
set "PS1=\! MSYS \u@\h:\w \$ "
set "HOME=c:\msys64\home\rmills"
if NOT EXIST %HOME% mkdir %HOME%
cd %HOME%
color 1f
c:\msys64\usr\bin\bash.exe -norc
endlocal
```
### Install MinGW Dependencies
Install tools and dependencies:
```bash ```bash
for i in base-devel git coreutils dos2unix tar diffutils make \ pacman -S mingw-w64-ucrt-x86_64-binutils mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-curl mingw-w64-ucrt-x86_64-expat mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-gettext mingw-w64-ucrt-x86_64-gtest mingw-w64-ucrt-x86_64-libiconv mingw-w64-ucrt-x86_64-make mingw-w64-ucrt-x86_64-zlib
mingw-w64-x86_64-toolchain mingw-w64-x86_64-gcc mingw-w64-x86_64-gdb \
mingw-w64-x86_64-cmake mingw-w64-x86_64-gettext mingw-w64-x86_64-python3 \
mingw-w64-x86_64-libexpat mingw-w64-x86_64-libiconv mingw-w64-x86_64-zlib \
mingw-w64-x86_64-gtest
do (echo y | pacman -S $i) ; done
``` ```
### Download exiv2 from github and build ### Download exiv2 from github and build
Use the Windows start menu to open the terminal customized for the UCRT environment: `MSYS2 MinGW UCRT x64`. Then run the following commands to download exiv2, configure the project and build it:
```bash ```bash
$ mkdir -p ~/gnu/github/exiv2 mkdir -p ~/gnu/github/exiv2
$ cd ~/gnu/github/exiv2 cd ~/gnu/github/exiv2
$ git clone https://github.com/exiv2/exiv2 git clone https://github.com/exiv2/exiv2
$ cd exiv2 cd exiv2
$ mkdir build ; cd build ; mkdir build && cd build
$ cmake .. -G "Unix Makefiles" # or "MSYS Makefiles" cmake -G "MSYS Makefiles"
$ make -DCMAKE_CXX_FLAGS=-Wno-deprecated
``` -DCMAKE_BUILD_TYPE=Release
-DBUILD_SHARED_LIBS=ON
-DEXIV2_BUILD_SAMPLES=ON
-DEXIV2_ENABLE_NLS=OFF
-DEXIV2_ENABLE_WEBREADY=ON
-DEXIV2_ENABLE_BMFF=ON
-DEXIV2_BUILD_UNIT_TESTS=ON
..
cmake --build . --parallel
```
The binaries generated at this point can be executed from the MSYS2 UCRT terminal, but they will not run from a Windows Command Prompt or PowerShell. The reason is that the MSYS2 UCRT terminal is properly configured to find some needed DLLs. In case you want to be able to run the generated **exiv2** binary from any Windows terminal, you'll need to deploy the needed DLLs with the application.
[TOC](#TOC) [TOC](#TOC)
<div id="PlatformCygwin"> <div id="PlatformCygwin">
@ -1197,7 +1189,7 @@ endlocal
## Visual Studio ## Visual Studio
We recommend that you use Conan to build Exiv2 using Visual Studio. Exiv2 v0.27 can be built with Visual Studio versions 2008 and later. We actively support and build with Visual Studio 2015, 2017 and 2019. We recommend that you use Conan to get the Exiv2 dependencies when using Visual Studio. Exiv2 v0.27 can be built with Visual Studio versions 2008 and later. For the `main` branch we actively support and build with Visual Studio 2019 and 2022.
As well as Visual Studio, you will need to install CMake, Python3, and Conan. As well as Visual Studio, you will need to install CMake, Python3, and Conan.
@ -1212,6 +1204,8 @@ As well as Visual Studio, you will need to install CMake, Python3, and Conan.
The python3 interpreter must be on your PATH. The python3 interpreter must be on your PATH.
It is important to highlight that we rely on using of the Universal C Runtime (UCRT) and its relatively new support for UTF-8. Check this [PR](https://github.com/Exiv2/exiv2/pull/2090) for more information.
[TOC](#TOC) [TOC](#TOC)
<div id="PlatformUnix"> <div id="PlatformUnix">

@ -167,13 +167,7 @@ if(MSVC)
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif () endif ()
# Object Level Parallelism add_compile_options(/MP) # Object Level Parallelism
add_compile_options(/MP) add_compile_options(/utf-8) # Set source and execution character sets to UTF-8
add_definitions(-DNOMINMAX) # This definition is not only needed for Exiv2 but also for xmpsdk add_definitions(-DNOMINMAX) # This definition is not only needed for Exiv2 but also for xmpsdk
# https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
if (MSVC_VERSION GREATER_EQUAL "1910") # VS2017 and up
add_compile_options("/Zc:__cplusplus")
endif()
endif() endif()

@ -24,9 +24,6 @@
// Define if the strerror_r function returns char*. // Define if the strerror_r function returns char*.
#cmakedefine EXV_STRERROR_R_CHAR_P #cmakedefine EXV_STRERROR_R_CHAR_P
// Define to enable the Windows unicode path support.
#cmakedefine EXV_UNICODE_PATH
/* Define to `const' or to empty, depending on the second argument of `iconv'. */ /* Define to `const' or to empty, depending on the second argument of `iconv'. */
#cmakedefine ICONV_ACCEPTS_CONST_INPUT #cmakedefine ICONV_ACCEPTS_CONST_INPUT
#if defined(ICONV_ACCEPTS_CONST_INPUT) || defined(__NetBSD__) #if defined(ICONV_ACCEPTS_CONST_INPUT) || defined(__NetBSD__)
@ -76,7 +73,4 @@
// Define if you have the iconv function. // Define if you have the iconv function.
#cmakedefine EXV_HAVE_ICONV #cmakedefine EXV_HAVE_ICONV
// Definition to enable conversion of UCS2 encoded Windows tags to UTF-8.
#cmakedefine EXV_HAVE_PRINTUCS2
#endif /* !_EXV_CONF_H_ */ #endif /* !_EXV_CONF_H_ */

@ -9,7 +9,6 @@ endif()
set(EXV_ENABLE_BMFF ${EXIV2_ENABLE_BMFF}) set(EXV_ENABLE_BMFF ${EXIV2_ENABLE_BMFF})
set(EXV_ENABLE_WEBREADY ${EXIV2_ENABLE_WEBREADY}) set(EXV_ENABLE_WEBREADY ${EXIV2_ENABLE_WEBREADY})
set(EXV_HAVE_LENSDATA ${EXIV2_ENABLE_LENSDATA}) set(EXV_HAVE_LENSDATA ${EXIV2_ENABLE_LENSDATA})
set(EXV_HAVE_PRINTUCS2 ${EXIV2_ENABLE_PRINTUCS2})
set(EXV_PACKAGE_NAME ${PROJECT_NAME}) set(EXV_PACKAGE_NAME ${PROJECT_NAME})
set(EXV_PACKAGE_VERSION ${PROJECT_VERSION}) set(EXV_PACKAGE_VERSION ${PROJECT_VERSION})
@ -21,7 +20,6 @@ else()
endif() endif()
set(EXV_HAVE_ICONV ${ICONV_FOUND}) set(EXV_HAVE_ICONV ${ICONV_FOUND})
set(EXV_HAVE_LIBZ ${ZLIB_FOUND}) set(EXV_HAVE_LIBZ ${ZLIB_FOUND})
set(EXV_UNICODE_PATH ${EXIV2_ENABLE_WIN_UNICODE})
check_cxx_symbol_exists(mmap sys/mman.h EXV_HAVE_MMAP ) check_cxx_symbol_exists(mmap sys/mman.h EXV_HAVE_MMAP )
check_cxx_symbol_exists(munmap sys/mman.h EXV_HAVE_MUNMAP ) check_cxx_symbol_exists(munmap sys/mman.h EXV_HAVE_MUNMAP )

@ -52,7 +52,6 @@ else()
endif() endif()
OptionOutput( "Building BMFF support: " EXIV2_ENABLE_BMFF ) OptionOutput( "Building BMFF support: " EXIV2_ENABLE_BMFF )
OptionOutput( "Native language support: " EXIV2_ENABLE_NLS ) OptionOutput( "Native language support: " EXIV2_ENABLE_NLS )
OptionOutput( "Conversion of Windows XP tags: " EXIV2_ENABLE_PRINTUCS2 )
OptionOutput( "Nikon lens database: " EXIV2_ENABLE_LENSDATA ) OptionOutput( "Nikon lens database: " EXIV2_ENABLE_LENSDATA )
OptionOutput( "Building webready support: " EXIV2_ENABLE_WEBREADY ) OptionOutput( "Building webready support: " EXIV2_ENABLE_WEBREADY )
if ( EXIV2_ENABLE_WEBREADY ) if ( EXIV2_ENABLE_WEBREADY )
@ -61,7 +60,6 @@ endif ( EXIV2_ENABLE_WEBREADY )
if (WIN32) if (WIN32)
OptionOutput( "Dynamic runtime override: " EXIV2_ENABLE_DYNAMIC_RUNTIME) OptionOutput( "Dynamic runtime override: " EXIV2_ENABLE_DYNAMIC_RUNTIME)
OptionOutput( "Unicode paths (wstring): " EXIV2_ENABLE_WIN_UNICODE )
endif() endif()
OptionOutput( "Building exiv2 command: " EXIV2_BUILD_EXIV2_COMMAND ) OptionOutput( "Building exiv2 command: " EXIV2_BUILD_EXIV2_COMMAND )
OptionOutput( "Building samples: " EXIV2_BUILD_SAMPLES ) OptionOutput( "Building samples: " EXIV2_BUILD_SAMPLES )

@ -5,7 +5,7 @@
# *) install zlib for mingw: sudo apt install libz-mingw-w64-dev # *) install zlib for mingw: sudo apt install libz-mingw-w64-dev
# *) mkdir buildMinGWRelease && cd buildMinGWRelease # *) mkdir buildMinGWRelease && cd buildMinGWRelease
# *) cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain/Ubuntu20_04_mingw-w64-x86_64.cmake # *) cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain/Ubuntu20_04_mingw-w64-x86_64.cmake
# -DEXIV2_ENABLE_XMP=OFF -DEXIV2_TEAM_EXTRA_WARNINGS=ON -DEXIV2_ENABLE_WIN_UNICODE=ON # -DEXIV2_ENABLE_XMP=OFF -DEXIV2_TEAM_EXTRA_WARNINGS=ON
set(CMAKE_SYSTEM_NAME Windows) set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)

@ -241,13 +241,6 @@ namespace Exiv2 {
available. available.
*/ */
virtual std::string path() const =0; virtual std::string path() const =0;
#ifdef EXV_UNICODE_PATH
/*!
@brief Like path() but returns a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
virtual std::wstring wpath() const =0;
#endif
/*! /*!
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory @brief Mark all the bNone blocks to bKnow. This avoids allocating memory
@ -314,14 +307,7 @@ namespace Exiv2 {
@param path The full path of a file @param path The full path of a file
*/ */
explicit FileIo(const std::string& path); explicit FileIo(const std::string& path);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like FileIo(const std::string& path) but accepts a
unicode path in an std::wstring.
@note This constructor is only available on Windows.
*/
FileIo(const std::wstring& wpath);
#endif
//! Destructor. Flushes and closes an open file. //! Destructor. Flushes and closes an open file.
~FileIo() override; ~FileIo() override;
//@} //@}
@ -462,14 +448,7 @@ namespace Exiv2 {
@brief close the file source and set a new path. @brief close the file source and set a new path.
*/ */
virtual void setPath(const std::string& path); virtual void setPath(const std::string& path);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like setPath(const std::string& path) but accepts a
unicode path in an std::wstring.
@note This method is only available on Windows.
*/
virtual void setPath(const std::wstring& wpath);
#endif
//@} //@}
//! @name Accessors //! @name Accessors
//@{ //@{
@ -494,13 +473,6 @@ namespace Exiv2 {
bool eof() const override; bool eof() const override;
//! Returns the path of the file //! Returns the path of the file
std::string path() const override; std::string path() const override;
#ifdef EXV_UNICODE_PATH
/*
@brief Like path() but returns the unicode path of the file in an std::wstring.
@note This function is only available on Windows.
*/
virtual std::wstring wpath() const;
#endif
/*! /*!
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory @brief Mark all the bNone blocks to bKnow. This avoids allocating memory
@ -683,13 +655,6 @@ namespace Exiv2 {
bool eof() const override; bool eof() const override;
//! Returns a dummy path, indicating that memory access is used //! Returns a dummy path, indicating that memory access is used
std::string path() const override; std::string path() const override;
#ifdef EXV_UNICODE_PATH
/*
@brief Like path() but returns a unicode dummy path in an std::wstring.
@note This function is only available on Windows.
*/
virtual std::wstring wpath() const;
#endif
/*! /*!
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory @brief Mark all the bNone blocks to bKnow. This avoids allocating memory
@ -725,14 +690,6 @@ namespace Exiv2 {
//@{ //@{
//! Default constructor //! Default constructor
XPathIo(const std::string& path); XPathIo(const std::string& path);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like XPathIo(const std::string& path) but accepts a
unicode url in an std::wstring.
@note This constructor is only available on Windows.
*/
XPathIo(const std::wstring& wpath);
#endif
//@} //@}
private: private:
/*! /*!
@ -765,14 +722,7 @@ namespace Exiv2 {
//@{ //@{
//! Default constructor that reads data from stdin/data uri path and writes them to the temp file. //! Default constructor that reads data from stdin/data uri path and writes them to the temp file.
explicit XPathIo(const std::string& orgPath); explicit XPathIo(const std::string& orgPath);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like XPathIo(const std::string& orgPath) but accepts a
unicode url in an std::wstring.
@note This constructor is only available on Windows.
*/
XPathIo(const std::wstring& wOrgPathpath);
#endif
//! Destructor. Releases all managed memory and removes the temp file. //! Destructor. Releases all managed memory and removes the temp file.
~XPathIo() override; ~XPathIo() override;
//@} //@}
@ -796,14 +746,6 @@ namespace Exiv2 {
@throw Error if it fails. @throw Error if it fails.
*/ */
static std::string writeDataToFile(const std::string& orgPath); static std::string writeDataToFile(const std::string& orgPath);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like writeDataToFile(const std::string& orgPath) but accepts a
unicode url in an std::wstring.
@note This constructor is only available on Windows.
*/
static std::string writeDataToFile(const std::wstring& wOrgPath);
#endif
//@} //@}
private: private:
@ -957,13 +899,6 @@ namespace Exiv2 {
bool eof() const override; bool eof() const override;
//!Returns the URL of the file. //!Returns the URL of the file.
std::string path() const override; std::string path() const override;
#ifdef EXV_UNICODE_PATH
/*
@brief Like path() but returns a unicode URL path in an std::wstring.
@note This function is only available on Windows.
*/
virtual std::wstring wpath() const;
#endif
/*! /*!
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory @brief Mark all the bNone blocks to bKnow. This avoids allocating memory
@ -1001,14 +936,7 @@ namespace Exiv2 {
on demand from the server, so it avoids copying the complete file. on demand from the server, so it avoids copying the complete file.
*/ */
explicit HttpIo(const std::string& url, size_t blockSize = 1024); explicit HttpIo(const std::string& url, size_t blockSize = 1024);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like HttpIo(const std::string& url, size_t blockSize = 1024) but accepts a
unicode url in an std::wstring.
@note This constructor is only available on Windows.
*/
HttpIo(const std::wstring& wurl, size_t blockSize = 1024);
#endif
// NOT IMPLEMENTED // NOT IMPLEMENTED
//! Copy constructor //! Copy constructor
HttpIo(HttpIo& rhs) = delete; HttpIo(HttpIo& rhs) = delete;
@ -1039,14 +967,7 @@ namespace Exiv2 {
@throw Error if it is unable to init curl pointer. @throw Error if it is unable to init curl pointer.
*/ */
explicit CurlIo(const std::string& url, size_t blockSize = 0); explicit CurlIo(const std::string& url, size_t blockSize = 0);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like CurlIo(const std::string& url, size_t blockSize = 0) but accepts a
unicode url in an std::wstring.
@note This constructor is only available on Windows.
*/
CurlIo(const std::wstring& wurl, size_t blockSize = 0);
#endif
/*! /*!
@brief Write access is only available for some protocols. This method @brief Write access is only available for some protocols. This method
will call RemoteIo::write(const byte* data, long wcount) if the write will call RemoteIo::write(const byte* data, long wcount) if the write
@ -1081,41 +1002,18 @@ namespace Exiv2 {
@throw Error In case of failure. @throw Error In case of failure.
*/ */
EXIV2API DataBuf readFile(const std::string& path); EXIV2API DataBuf readFile(const std::string& path);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like readFile() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
EXIV2API DataBuf readFile(const std::wstring& wpath);
#endif
/*! /*!
@brief Write DataBuf \em buf to file \em path. @brief Write DataBuf \em buf to file \em path.
@return Return the number of bytes written. @return Return the number of bytes written.
@throw Error In case of failure. @throw Error In case of failure.
*/ */
EXIV2API long writeFile(const DataBuf& buf, const std::string& path); EXIV2API long writeFile(const DataBuf& buf, const std::string& path);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like writeFile() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
EXIV2API long writeFile(const DataBuf& buf, const std::wstring& wpath);
#endif
/*! /*!
@brief replace each substring of the subject that matches the given search string with the given replacement. @brief replace each substring of the subject that matches the given search string with the given replacement.
@return the subject after replacing. @return the subject after replacing.
*/ */
EXIV2API std::string ReplaceStringInPlace(std::string subject, const std::string& search, EXIV2API std::string ReplaceStringInPlace(std::string subject, const std::string& search,
const std::string& replace); const std::string& replace);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like ReplaceStringInPlace() but accepts a unicode path in an std::wstring.
@return the subject after replacing.
@note This function is only available on Windows.
*/
EXIV2API std::wstring ReplaceStringInPlace(std::wstring subject, const std::wstring& search,
const std::wstring& replace);
#endif
#ifdef EXV_USE_CURL #ifdef EXV_USE_CURL
/*! /*!
@brief The callback function is called by libcurl to write the data @brief The callback function is called by libcurl to write the data

@ -292,13 +292,6 @@ namespace Exiv2 {
is valid only as long as the BasicError object exists. is valid only as long as the BasicError object exists.
*/ */
inline const char* what() const noexcept override; inline const char* what() const noexcept override;
#ifdef EXV_UNICODE_PATH
/*!
@brief Return the error message as a wchar_t-string. The pointer returned by
wwhat() is valid only as long as the BasicError object exists.
*/
virtual inline const wchar_t* wwhat() const throw();
#endif
//@} //@}
private: private:
@ -315,17 +308,10 @@ namespace Exiv2 {
std::basic_string<charT> arg2_; //!< Second argument std::basic_string<charT> arg2_; //!< Second argument
std::basic_string<charT> arg3_; //!< Third argument std::basic_string<charT> arg3_; //!< Third argument
std::string msg_; //!< Complete error message std::string msg_; //!< Complete error message
#ifdef EXV_UNICODE_PATH
std::wstring wmsg_; //!< Complete error message as a wide string
#endif
}; // class BasicError }; // class BasicError
//! Error class used for exceptions (std::string based) //! Error class used for exceptions (std::string based)
typedef BasicError<char> Error; typedef BasicError<char> Error;
#ifdef EXV_UNICODE_PATH
//! Error class used for exceptions (std::wstring based)
typedef BasicError<wchar_t> WError;
#endif
// ***************************************************************************** // *****************************************************************************
// free functions, template and inline definitions // free functions, template and inline definitions
@ -381,14 +367,6 @@ namespace Exiv2 {
return msg_.c_str(); return msg_.c_str();
} }
#ifdef EXV_UNICODE_PATH
template<typename charT>
const wchar_t* BasicError<charT>::wwhat() const throw()
{
return wmsg_.c_str();
}
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma warning( default : 4275 ) # pragma warning( default : 4275 )
#endif #endif

@ -255,13 +255,6 @@ namespace Exiv2 {
@return The number of bytes written. @return The number of bytes written.
*/ */
long writeFile(const std::string& path) const; long writeFile(const std::string& path) const;
#ifdef EXV_UNICODE_PATH
/*!
@brief Like writeFile() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
long writeFile(const std::wstring& wpath) const;
#endif
/*! /*!
@brief Return the MIME type of the thumbnail, either \c "image/tiff" @brief Return the MIME type of the thumbnail, either \c "image/tiff"
or \c "image/jpeg". or \c "image/jpeg".
@ -272,13 +265,6 @@ namespace Exiv2 {
(".tif" or ".jpg"). (".tif" or ".jpg").
*/ */
const char* extension() const; const char* extension() const;
#ifdef EXV_UNICODE_PATH
/*!
@brief Like extension() but returns the extension in a wchar_t.
@note This function is only available on Windows.
*/
const wchar_t* wextension() const;
#endif
//@} //@}
private: private:
@ -331,19 +317,6 @@ namespace Exiv2 {
URational yres, URational yres,
uint16_t unit uint16_t unit
); );
#ifdef EXV_UNICODE_PATH
/*!
@brief Like setJpegThumbnail() but accepts a unicode path in an
std::wstring.
@note This function is only available on Windows.
*/
void setJpegThumbnail(
const std::wstring& wpath,
URational xres,
URational yres,
uint16_t unit
);
#endif
/*! /*!
@brief Set the Exif thumbnail to the JPEG image pointed to by \em buf, @brief Set the Exif thumbnail to the JPEG image pointed to by \em buf,
and size \em size. Set XResolution, YResolution and and size \em size. Set XResolution, YResolution and
@ -382,14 +355,6 @@ namespace Exiv2 {
@note Additional existing Exif thumbnail tags are not modified. @note Additional existing Exif thumbnail tags are not modified.
*/ */
void setJpegThumbnail(const std::string& path); void setJpegThumbnail(const std::string& path);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like setJpegThumbnail(const std::string& path) but accepts a
unicode path in an std::wstring.
@note This function is only available on Windows.
*/
void setJpegThumbnail(const std::wstring& wpath);
#endif
/*! /*!
@brief Set the Exif thumbnail to the JPEG image pointed to by \em buf, @brief Set the Exif thumbnail to the JPEG image pointed to by \em buf,
and size \em size. and size \em size.

@ -113,14 +113,6 @@ namespace Exiv2
*/ */
EXIV2API Protocol fileProtocol(const std::string& path); EXIV2API Protocol fileProtocol(const std::string& path);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like fileProtocol() but accept a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
EXIV2API Protocol fileProtocol(const std::wstring& wpath);
#endif
/*! /*!
@brief Test if a file exists. @brief Test if a file exists.
@ -135,15 +127,6 @@ namespace Exiv2
*/ */
EXIV2API bool fileExists(const std::string& path, bool ct = false); EXIV2API bool fileExists(const std::string& path, bool ct = false);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like fileExists(const std::string& path, bool ct =false) but
accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
EXIV2API bool fileExists(const std::wstring& wpath, bool ct = false);
#endif
/*! /*!
@brief Get the path of file URL. @brief Get the path of file URL.
@ -152,14 +135,6 @@ namespace Exiv2
*/ */
EXIV2API std::string pathOfFileUrl(const std::string& url); EXIV2API std::string pathOfFileUrl(const std::string& url);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like pathOfFileUrl(const std::string& url) but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
EXIV2API std::wstring pathOfFileUrl(const std::wstring& wurl);
#endif
/*! /*!
@brief Return a system error message and the error code (errno). @brief Return a system error message and the error code (errno).
See %strerror(3). See %strerror(3).

@ -548,13 +548,7 @@ namespace Exiv2 {
read the remote file. read the remote file.
*/ */
static BasicIo::UniquePtr createIo(const std::string& path, bool useCurl = true); static BasicIo::UniquePtr createIo(const std::string& path, bool useCurl = true);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like createIo() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
static BasicIo::UniquePtr createIo(const std::wstring& wpath, bool useCurl = true);
#endif
/*! /*!
@brief Create an Image subclass of the appropriate type by reading @brief Create an Image subclass of the appropriate type by reading
the specified file. %Image type is derived from the file the specified file. %Image type is derived from the file
@ -569,13 +563,7 @@ namespace Exiv2 {
unknown image type. unknown image type.
*/ */
static Image::UniquePtr open(const std::string& path, bool useCurl = true); static Image::UniquePtr open(const std::string& path, bool useCurl = true);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like open() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
static Image::UniquePtr open(const std::wstring& wpath, bool useCurl = true);
#endif
/*! /*!
@brief Create an Image subclass of the appropriate type by reading @brief Create an Image subclass of the appropriate type by reading
the provided memory. %Image type is derived from the memory the provided memory. %Image type is derived from the memory
@ -616,13 +604,7 @@ namespace Exiv2 {
@throw Error If the image type is not supported. @throw Error If the image type is not supported.
*/ */
static Image::UniquePtr create(int type, const std::string& path); static Image::UniquePtr create(int type, const std::string& path);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like create() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
static Image::UniquePtr create(int type, const std::wstring& wpath);
#endif
/*! /*!
@brief Create an Image subclass of the requested type by creating a @brief Create an Image subclass of the requested type by creating a
new image in memory. new image in memory.
@ -654,13 +636,7 @@ namespace Exiv2 {
@return %Image type or Image::none if the type is not recognized. @return %Image type or Image::none if the type is not recognized.
*/ */
static int getType(const std::string& path); static int getType(const std::string& path);
#ifdef EXV_UNICODE_PATH
/*!
@brief Like getType() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
static int getType(const std::wstring& wpath);
#endif
/*! /*!
@brief Returns the image type of the provided data buffer. @brief Returns the image type of the provided data buffer.
@param data Pointer to a data buffer containing an image. The contents @param data Pointer to a data buffer containing an image. The contents

@ -43,10 +43,6 @@ namespace Exiv2 {
std::string mimeType_; std::string mimeType_;
//! Preview image extension. //! Preview image extension.
std::string extension_; std::string extension_;
#ifdef EXV_UNICODE_PATH
//! Unicode preview image extension in an std::wstring
std::wstring wextension_;
#endif
//! Preview image size in bytes. //! Preview image size in bytes.
uint32_t size_; uint32_t size_;
//! Preview image width in pixels or 0 for unknown width. //! Preview image width in pixels or 0 for unknown width.
@ -104,13 +100,6 @@ namespace Exiv2 {
@return The number of bytes written. @return The number of bytes written.
*/ */
long writeFile(const std::string& path) const; long writeFile(const std::string& path) const;
#ifdef EXV_UNICODE_PATH
/*!
@brief Like writeFile() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
long writeFile(const std::wstring& wpath) const;
#endif
/*! /*!
@brief Return the MIME type of the preview image, usually either @brief Return the MIME type of the preview image, usually either
\c "image/tiff" or \c "image/jpeg". \c "image/tiff" or \c "image/jpeg".
@ -121,14 +110,6 @@ namespace Exiv2 {
(".tif" or ".jpg"). (".tif" or ".jpg").
*/ */
std::string extension() const; std::string extension() const;
#ifdef EXV_UNICODE_PATH
/*!
@brief Like extension() but returns the unicode encoded extension in
an std::wstring.
@note This function is only available on Windows.
*/
std::wstring wextension() const;
#endif
/*! /*!
@brief Return the width of the preview image in pixels. @brief Return the width of the preview image in pixels.
*/ */

@ -34,10 +34,6 @@
#include <algorithm> #include <algorithm>
#include <sstream> #include <sstream>
// MSVC macro to convert a string to a wide string
#ifdef EXV_UNICODE_PATH
# define EXV_WIDEN(t) L ## t
#endif
/*! /*!
@brief Macro to make calls to member functions through a pointer more readable. @brief Macro to make calls to member functions through a pointer more readable.
@ -373,12 +369,6 @@ namespace Exiv2 {
*/ */
EXIV2API const char* exvGettext(const char* str); EXIV2API const char* exvGettext(const char* str);
#ifdef EXV_UNICODE_PATH
//! Convert an std::string s to a unicode string returned as a std::wstring.
EXIV2API std::wstring s2ws(const std::string& s);
//! Convert a unicode std::wstring s to an std::string.
EXIV2API std::string ws2s(const std::wstring& s);
#endif
/*! /*!
@brief Return a \em int64_t set to the value represented by \em s. @brief Return a \em int64_t set to the value represented by \em s.

@ -114,11 +114,20 @@ list(APPEND APPLICATIONS remotetest)
# ****************************************************************************** # ******************************************************************************
foreach(application ${APPLICATIONS}) foreach(application ${APPLICATIONS})
target_link_libraries(${application} PRIVATE exiv2lib) target_link_libraries(${application} PRIVATE exiv2lib)
if(MSVC)
target_link_libraries(${application} PRIVATE wmain)
target_link_options(${application} PRIVATE "/ENTRY:wWinMainCRTStartup")
endif()
if (MINGW)
target_link_libraries(${application} PRIVATE wmain)
target_compile_options(${application} PRIVATE -municode)
target_link_options(${application} PRIVATE -municode)
endif()
if( EXIV2_ENABLE_PNG ) if( EXIV2_ENABLE_PNG )
target_link_libraries(${application} PRIVATE ${ZLIB_LIBRARIES} ) target_link_libraries(${application} PRIVATE ${ZLIB_LIBRARIES} )
if (MSVC) if (MSVC)
set_target_properties(${application} PROPERTIES LINK_FLAGS "/ignore:4099") # Ignore missing PDBs set_target_properties(${application} PROPERTIES LINK_FLAGS "/ignore:4099") # Ignore missing PDBs
endif() endif()
endif() endif()
endforeach() endforeach()

@ -25,25 +25,6 @@
#include <cassert> #include <cassert>
#include <regex> #include <regex>
// https://github.com/Exiv2/exiv2/issues/468
#if defined(EXV_UNICODE_PATH) && defined(__MINGW__)
#undef EXV_UNICODE_PATH
#endif
#ifdef EXV_UNICODE_PATH
#define _tchar wchar_t
#define _tstrcmp wcscmp
#define _t(s) L##s
#define _tcout wcout
#define _tmain wmain
#else
#define _tchar char
#define _tstrcmp strcmp
#define _t(s) s
#define _tcout cout
#define _tmain main
#endif
// copied from src/tiffvisitor_int.cpp // copied from src/tiffvisitor_int.cpp
static const Exiv2::TagInfo* findTag(const Exiv2::TagInfo* pList,uint16_t tag) static const Exiv2::TagInfo* findTag(const Exiv2::TagInfo* pList,uint16_t tag)
{ {
@ -52,31 +33,32 @@ static const Exiv2::TagInfo* findTag(const Exiv2::TagInfo* pList,uint16_t tag)
} }
int _tmain(int argc, _tchar* const argv[]) int main(int argc, char* const argv[])
try { try {
setlocale(LC_CTYPE, ".utf8");
Exiv2::XmpParser::initialize(); Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate); ::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF #ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF(); Exiv2::enableBMFF();
#endif #endif
const _tchar* prog = argv[0]; const char* prog = argv[0];
if (argc == 1) { if (argc == 1) {
std::_tcout << _t("Usage: ") << prog << _t(" [ [--lint] path | --version | --version-test ]") << std::endl; std::cout << "Usage: " << prog << " [ [--lint] path | --version | --version-test ]" << std::endl;
return 1; return 1;
} }
int rc = 0 ; int rc = 0 ;
const _tchar* file = argv[1]; const char* file = argv[1];
bool bLint = _tstrcmp(file,_t("--lint")) == 0 && argc == 3; bool bLint = strcmp(file, "--lint") == 0 && argc == 3;
if ( bLint ) file= argv[2]; if ( bLint ) file= argv[2];
if ( _tstrcmp(file,_t("--version")) == 0 ) { if ( strcmp(file,"--version") == 0 ) {
std::vector<std::regex> keys; std::vector<std::regex> keys;
Exiv2::dumpLibraryInfo(std::cout,keys); Exiv2::dumpLibraryInfo(std::cout,keys);
return rc; return rc;
} else if ( _tstrcmp(file,_t("--version-test")) == 0 ) { } else if ( strcmp(file,"--version-test") == 0 ) {
// verifies/test macro EXIV2_TEST_VERSION // verifies/test macro EXIV2_TEST_VERSION
// described in include/exiv2/version.hpp // described in include/exiv2/version.hpp
std::cout << "EXV_PACKAGE_VERSION " << EXV_PACKAGE_VERSION << std::endl std::cout << "EXV_PACKAGE_VERSION " << EXV_PACKAGE_VERSION << std::endl

@ -23,6 +23,7 @@
#include <exiv2/exiv2.hpp> #include <exiv2/exiv2.hpp>
#include "Jzon.h" #include "Jzon.h"
#include <filesystem>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <cassert> #include <cassert>
@ -41,20 +42,6 @@
# endif # endif
#endif #endif
#if defined(_MSC_VER) || defined(__MINGW__)
#include <windows.h>
#ifndef PATH_MAX
# define PATH_MAX 512
#endif
const char* realpath(const char* file,char* path)
{
GetFullPathName(file,PATH_MAX,path,NULL);
return path;
}
#else
#include <unistd.h>
#endif
struct Token { struct Token {
std::string n; // the name eg "History" std::string n; // the name eg "History"
bool a; // name is an array eg History[] bool a; // name is an array eg History[]
@ -249,8 +236,7 @@ void fileSystemPush(const char* path,Jzon::Node& nfs)
{ {
auto& fs = dynamic_cast<Jzon::Object&>(nfs); auto& fs = dynamic_cast<Jzon::Object&>(nfs);
fs.Add("path",path); fs.Add("path",path);
char resolved_path[2000]; // PATH_MAX]; fs.Add("realpath", std::filesystem::absolute(std::filesystem::path(path)).string());
fs.Add("realpath",realpath(path,resolved_path));
struct stat buf; struct stat buf;
memset(&buf,0,sizeof(buf)); memset(&buf,0,sizeof(buf));

@ -24,6 +24,7 @@
#include <exiv2/exiv2.hpp> #include <exiv2/exiv2.hpp>
#include "unused.h" #include "unused.h"
#include <filesystem>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <cassert> #include <cassert>
@ -84,17 +85,6 @@ string getExifTime(time_t t);
time_t parseTime(const char* ,bool bAdjust=false); time_t parseTime(const char* ,bool bAdjust=false);
int timeZoneAdjust(); int timeZoneAdjust();
// platform specific code
#if defined(_MSC_VER) || defined(__MINGW__)
char* realpath(const char* file,char* path)
{
char* result = (char*) malloc(_MAX_PATH);
if (result) GetFullPathName(file,_MAX_PATH,result,NULL);
return result ;
UNUSED(path);
}
#endif
// Command-line parser // Command-line parser
class Options { class Options {
public: public:
@ -838,19 +828,13 @@ int main(int argc,const char* argv[])
if ( options.verbose ) printf("%s %s ",arg,types[type]) ; if ( options.verbose ) printf("%s %s ",arg,types[type]) ;
if ( type == typeImage ) { if ( type == typeImage ) {
time_t t = readImageTime(std::string(arg)) ; time_t t = readImageTime(std::string(arg)) ;
#ifdef __APPLE__ auto p = std::filesystem::absolute(std::filesystem::path(arg));
char buffer[1024]; std::string path = p.string();
#else if ( t && !path.empty() ) {
char* buffer = nullptr;
#endif
char* path = realpath(arg,buffer);
if ( t && path ) {
if (options.verbose) if (options.verbose)
printf("%s %ld %s", path, static_cast<long int>(t), asctime(localtime(&t))); printf("%s %ld %s", path.c_str(), static_cast<long int>(t), asctime(localtime(&t)));
gFiles.push_back(path); gFiles.push_back(path);
} }
if (path && path != buffer)
::free(path);
} }
if ( type == typeUnknown ) { if ( type == typeUnknown ) {
fprintf(stderr,"error: illegal syntax %s\n",arg); fprintf(stderr,"error: illegal syntax %s\n",arg);

@ -40,16 +40,5 @@ int main()
std::cout << "Caught Error '" << e.what() << "'\n"; std::cout << "Caught Error '" << e.what() << "'\n";
} }
#ifdef EXV_UNICODE_PATH
try {
throw Exiv2::WError(Exiv2::kerGeneralError, L"WARG1", L"WARG2", L"WARG3");
}
catch (const Exiv2::WError& e) {
std::wstring wmsg = e.wwhat();
std::string msg(wmsg.begin(), wmsg.end());
std::cout << "Caught WError '" << msg << "'\n";
}
#endif
return 0; return 0;
} }

@ -287,6 +287,23 @@ if(EXIV2_BUILD_EXIV2_COMMAND)
target_include_directories(exiv2 PRIVATE ${Intl_INCLUDE_DIRS}) target_include_directories(exiv2 PRIVATE ${Intl_INCLUDE_DIRS})
endif() endif()
if(MSVC OR MINGW)
# Trick to get properly UTF-8 encoded argv
# More info at: https://github.com/huangqinjin/wmain
add_library(wmain STATIC wmain.c)
target_link_libraries(exiv2 PRIVATE wmain)
endif()
if (MSVC)
target_link_options(wmain INTERFACE /WHOLEARCHIVE:$<TARGET_FILE:wmain>)
target_link_options(exiv2 PRIVATE "/ENTRY:wWinMainCRTStartup")
endif()
if (MINGW)
target_compile_options(exiv2 PRIVATE -municode)
target_link_options(exiv2 PRIVATE -municode)
endif()
if (USING_CONAN AND WIN32 AND EXISTS ${PROJECT_BINARY_DIR}/conanDlls) if (USING_CONAN AND WIN32 AND EXISTS ${PROJECT_BINARY_DIR}/conanDlls)
# In case of using conan recipes with their 'shared' option turned on, we will have dlls of # In case of using conan recipes with their 'shared' option turned on, we will have dlls of
# the 3rd party dependencies in the conanDlls folder. # the 3rd party dependencies in the conanDlls folder.

@ -40,6 +40,7 @@
#include "i18n.h" // NLS support. #include "i18n.h" // NLS support.
// + standard includes // + standard includes
#include <filesystem>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
@ -69,6 +70,8 @@
#define _setmode(a,b) #define _setmode(a,b)
#endif #endif
namespace fs = std::filesystem;
// ***************************************************************************** // *****************************************************************************
// local declarations // local declarations
namespace { namespace {
@ -1786,29 +1789,25 @@ namespace {
return os.str(); return os.str();
} // tm2Str } // tm2Str
std::string temporaryPath() std::string temporaryPath()
{ {
static int count = 0; static int count = 0;
std::lock_guard<std::mutex> guard(cs); std::lock_guard<std::mutex> guard(cs);
#if defined(_MSC_VER) || defined(__MINGW__) #if defined(_MSC_VER) || defined(__MINGW__)
char lpTempPathBuffer[MAX_PATH];
GetTempPath(MAX_PATH,lpTempPathBuffer);
std::string tmp(lpTempPathBuffer);
tmp += "\\";
HANDLE process=0; HANDLE process=0;
DWORD pid = ::GetProcessId(process); DWORD pid = ::GetProcessId(process);
#else #else
pid_t pid = ::getpid(); pid_t pid = ::getpid();
std::string tmp = "/tmp/";
#endif #endif
std::string result = tmp + Exiv2::toString(pid) + "_" + std::to_string(count); /// \todo check if we can use std::tmpnam
if (Exiv2::fileExists(result)) { auto p = fs::temp_directory_path() / (Exiv2::toString(pid) + "_" + std::to_string(count));
std::remove(result.c_str()); if (fs::exists(p)) {
} fs::remove(p);
}
return result; return p.string();
} }
int metacopy(const std::string& source, int metacopy(const std::string& source,
const std::string& tgt, const std::string& tgt,

@ -94,23 +94,11 @@ namespace Exiv2 {
public: public:
//! Constructor //! Constructor
explicit Impl(std::string path); explicit Impl(std::string path);
#ifdef EXV_UNICODE_PATH
//! Constructor accepting a unicode path in an std::wstring
Impl(const std::wstring& wpath);
#endif
// Enumerations // Enumerations
//! Mode of operation //! Mode of operation
enum OpMode { opRead, opWrite, opSeek }; enum OpMode { opRead, opWrite, opSeek };
#ifdef EXV_UNICODE_PATH
//! Used to indicate if the path is stored as a standard or unicode string
enum WpMode { wpStandard, wpUnicode };
#endif
// DATA // DATA
std::string path_; //!< (Standard) path std::string path_; //!< (Standard) path
#ifdef EXV_UNICODE_PATH
std::wstring wpath_; //!< Unicode path
WpMode wpMode_; //!< Indicates which path is in use
#endif
std::string openMode_; //!< File open mode std::string openMode_; //!< File open mode
FILE *fp_; //!< File stream pointer FILE *fp_; //!< File stream pointer
OpMode opMode_; //!< File open mode OpMode opMode_; //!< File open mode
@ -155,9 +143,6 @@ namespace Exiv2 {
FileIo::Impl::Impl(std::string path) FileIo::Impl::Impl(std::string path)
: path_(std::move(path)), : path_(std::move(path)),
#ifdef EXV_UNICODE_PATH
wpMode_(wpStandard),
#endif
fp_(nullptr), fp_(nullptr),
opMode_(opSeek), opMode_(opSeek),
#if defined WIN32 && !defined __CYGWIN__ #if defined WIN32 && !defined __CYGWIN__
@ -171,19 +156,6 @@ namespace Exiv2 {
{ {
} }
#ifdef EXV_UNICODE_PATH
FileIo::Impl::Impl(const std::wstring& wpath)
: wpath_(wpath),
wpMode_(wpUnicode),
fp_(0), opMode_(opSeek),
#if defined WIN32 && !defined __CYGWIN__
hFile_(0), hMap_(0),
#endif
pMappedArea_(0), mappedLength_(0), isMalloced_(false), isWriteable_(false)
{
}
#endif
int FileIo::Impl::switchMode(OpMode opMode) int FileIo::Impl::switchMode(OpMode opMode)
{ {
assert(fp_ != 0); assert(fp_ != 0);
@ -227,15 +199,7 @@ namespace Exiv2 {
} }
openMode_ = "r+b"; openMode_ = "r+b";
opMode_ = opSeek; opMode_ = opSeek;
#ifdef EXV_UNICODE_PATH fp_ = std::fopen(path_.c_str(), openMode_.c_str());
if (wpMode_ == wpUnicode) {
fp_ = ::_wfopen(wpath_.c_str(), s2ws(openMode_).c_str());
}
else
#endif
{
fp_ = std::fopen(path_.c_str(), openMode_.c_str());
}
if (!fp_) return 1; if (!fp_) return 1;
return std::fseek(fp_, offset, SEEK_SET); return std::fseek(fp_, offset, SEEK_SET);
} // FileIo::Impl::switchMode } // FileIo::Impl::switchMode
@ -243,36 +207,12 @@ namespace Exiv2 {
int FileIo::Impl::stat(StructStat& buf) const int FileIo::Impl::stat(StructStat& buf) const
{ {
int ret = 0; int ret = 0;
#ifdef EXV_UNICODE_PATH struct stat st;
#ifdef _WIN64 ret = ::stat(path_.c_str(), &st);
struct _stat64 st; if (0 == ret) {
ret = ::_wstati64(wpath_.c_str(), &st); buf.st_size = st.st_size;
buf.st_nlink = st.st_nlink;
if (0 == ret) { buf.st_mode = st.st_mode;
buf.st_size = static_cast<long>(st.st_size);
buf.st_mode = st.st_mode;
buf.st_nlink = st.st_nlink;
}
#else
struct _stat st;
ret = ::_wstat(wpath_.c_str(), &st);
if (0 == ret) {
buf.st_size = st.st_size;
buf.st_mode = st.st_mode;
buf.st_nlink = st.st_nlink;
}
#endif
else
#endif
{
struct stat st;
ret = ::stat(path_.c_str(), &st);
if (0 == ret) {
buf.st_size = st.st_size;
buf.st_nlink = st.st_nlink;
buf.st_mode = st.st_mode;
}
} }
return ret; return ret;
} // FileIo::Impl::stat } // FileIo::Impl::stat
@ -284,9 +224,6 @@ namespace Exiv2 {
#endif #endif
{ {
#if defined(__APPLE__) #if defined(__APPLE__)
# if defined(EXV_UNICODE_PATH)
# error No xattr API for macOS with unicode support
# endif
ssize_t namebufSize = ::listxattr(src.p_->path_.c_str(), 0, 0, 0); ssize_t namebufSize = ::listxattr(src.p_->path_.c_str(), 0, 0, 0);
if (namebufSize < 0) { if (namebufSize < 0) {
throw Error(kerCallFailed, src.p_->path_, strError(), "listxattr"); throw Error(kerCallFailed, src.p_->path_, strError(), "listxattr");
@ -369,13 +306,6 @@ namespace Exiv2 {
{ {
} }
#ifdef EXV_UNICODE_PATH
FileIo::FileIo(const std::wstring& wpath)
: p_(new Impl(wpath))
{
}
#endif
FileIo::~FileIo() FileIo::~FileIo()
{ {
close(); close();
@ -420,28 +350,12 @@ namespace Exiv2 {
{ {
assert(p_->fp_ != 0); assert(p_->fp_ != 0);
if (munmap() != 0) { if (munmap() != 0) {
#ifdef EXV_UNICODE_PATH throw Error(kerCallFailed, path(), strError(), "munmap");
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerCallFailed, wpath(), strError().c_str(), "munmap");
}
else
#endif
{
throw Error(kerCallFailed, path(), strError(), "munmap");
}
} }
p_->mappedLength_ = size(); p_->mappedLength_ = size();
p_->isWriteable_ = isWriteable; p_->isWriteable_ = isWriteable;
if (p_->isWriteable_ && p_->switchMode(Impl::opWrite) != 0) { if (p_->isWriteable_ && p_->switchMode(Impl::opWrite) != 0) {
#ifdef EXV_UNICODE_PATH throw Error(kerFailedToMapFileForReadWrite, path(), strError());
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerFailedToMapFileForReadWrite, wpath(), strError().c_str());
}
else
#endif
{
throw Error(kerFailedToMapFileForReadWrite, path(), strError());
}
} }
#if defined EXV_HAVE_MMAP && defined EXV_HAVE_MUNMAP #if defined EXV_HAVE_MMAP && defined EXV_HAVE_MUNMAP
int prot = PROT_READ; int prot = PROT_READ;
@ -450,15 +364,7 @@ namespace Exiv2 {
} }
void* rc = ::mmap(nullptr, p_->mappedLength_, prot, MAP_SHARED, fileno(p_->fp_), 0); void* rc = ::mmap(nullptr, p_->mappedLength_, prot, MAP_SHARED, fileno(p_->fp_), 0);
if (MAP_FAILED == rc) { if (MAP_FAILED == rc) {
#ifdef EXV_UNICODE_PATH throw Error(kerCallFailed, path(), strError(), "mmap");
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerCallFailed, wpath(), strError().c_str(), "mmap");
}
else
#endif
{
throw Error(kerCallFailed, path(), strError(), "mmap");
}
} }
p_->pMappedArea_ = static_cast<byte*>(rc); p_->pMappedArea_ = static_cast<byte*>(rc);
@ -479,76 +385,28 @@ namespace Exiv2 {
HANDLE hPh = GetCurrentProcess(); HANDLE hPh = GetCurrentProcess();
HANDLE hFd = (HANDLE)_get_osfhandle(fileno(p_->fp_)); HANDLE hFd = (HANDLE)_get_osfhandle(fileno(p_->fp_));
if (hFd == INVALID_HANDLE_VALUE) { if (hFd == INVALID_HANDLE_VALUE) {
#ifdef EXV_UNICODE_PATH throw Error(kerCallFailed, path(), "MSG1", "_get_osfhandle");
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerCallFailed, wpath(), "MSG1", "_get_osfhandle");
}
else
#endif
{
throw Error(kerCallFailed, path(), "MSG1", "_get_osfhandle");
}
} }
if (!DuplicateHandle(hPh, hFd, hPh, &p_->hFile_, 0, false, DUPLICATE_SAME_ACCESS)) { if (!DuplicateHandle(hPh, hFd, hPh, &p_->hFile_, 0, false, DUPLICATE_SAME_ACCESS)) {
#ifdef EXV_UNICODE_PATH throw Error(kerCallFailed, path(), "MSG2", "DuplicateHandle");
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerCallFailed, wpath(), "MSG2", "DuplicateHandle");
}
else
#endif
{
throw Error(kerCallFailed, path(), "MSG2", "DuplicateHandle");
}
} }
p_->hMap_ = CreateFileMapping(p_->hFile_, 0, flProtect, 0, (DWORD) p_->mappedLength_, 0); p_->hMap_ = CreateFileMapping(p_->hFile_, 0, flProtect, 0, (DWORD) p_->mappedLength_, 0);
if (p_->hMap_ == 0 ) { if (p_->hMap_ == 0 ) {
#ifdef EXV_UNICODE_PATH throw Error(kerCallFailed, path(), "MSG3", "CreateFileMapping");
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerCallFailed, wpath(), "MSG3", "CreateFileMapping");
}
else
#endif
{
throw Error(kerCallFailed, path(), "MSG3", "CreateFileMapping");
}
} }
void* rc = MapViewOfFile(p_->hMap_, dwAccess, 0, 0, 0); void* rc = MapViewOfFile(p_->hMap_, dwAccess, 0, 0, 0);
if (rc == 0) { if (rc == 0) {
#ifdef EXV_UNICODE_PATH throw Error(kerCallFailed, path(), "MSG4", "CreateFileMapping");
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerCallFailed, wpath(), "MSG4", "CreateFileMapping");
}
else
#endif
{
throw Error(kerCallFailed, path(), "MSG4", "CreateFileMapping");
}
} }
p_->pMappedArea_ = static_cast<byte*>(rc); p_->pMappedArea_ = static_cast<byte*>(rc);
#else #else
// Workaround for platforms without mmap: Read the file into memory // Workaround for platforms without mmap: Read the file into memory
DataBuf buf(static_cast<long>(p_->mappedLength_)); DataBuf buf(static_cast<long>(p_->mappedLength_));
if (read(buf.data(), buf.size()) != buf.size()) { if (read(buf.data(), buf.size()) != buf.size()) {
#ifdef EXV_UNICODE_PATH throw Error(kerCallFailed, path(), strError(), "FileIo::read");
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerCallFailed, wpath(), strError().c_str(), "FileIo::read");
}
else
#endif
{
throw Error(kerCallFailed, path(), strError(), "FileIo::read");
}
} }
if (error()) { if (error()) {
#ifdef EXV_UNICODE_PATH throw Error(kerCallFailed, path(), strError(), "FileIo::mmap");
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerCallFailed, wpath(), strError().c_str(), "FileIo::mmap");
}
else
#endif
{
throw Error(kerCallFailed, path(), strError(), "FileIo::mmap");
}
} }
p_->pMappedArea_ = buf.release().first; p_->pMappedArea_ = buf.release().first;
p_->isMalloced_ = true; p_->isMalloced_ = true;
@ -558,31 +416,9 @@ namespace Exiv2 {
void FileIo::setPath(const std::string& path) { void FileIo::setPath(const std::string& path) {
close(); close();
#ifdef EXV_UNICODE_PATH
if (p_->wpMode_ == Impl::wpUnicode) {
std::wstring wpath;
wpath.assign(path.begin(), path.end());
p_->wpath_ = wpath;
}
p_->path_ = path;
#else
p_->path_ = path; p_->path_ = path;
#endif
} }
#ifdef EXV_UNICODE_PATH
void FileIo::setPath(const std::wstring& wpath) {
close();
if (p_->wpMode_ == Impl::wpStandard) {
std::string path;
path.assign(wpath.begin(), wpath.end());
p_->path_ = path;
} else {
p_->wpath_ = wpath;
}
}
#endif
long FileIo::write(const byte* data, long wcount) long FileIo::write(const byte* data, long wcount)
{ {
assert(p_->fp_ != 0); assert(p_->fp_ != 0);
@ -626,24 +462,8 @@ namespace Exiv2 {
if (open("a+b") != 0) { if (open("a+b") != 0) {
/// \todo Use std::filesystem once C++17 can be used /// \todo Use std::filesystem once C++17 can be used
// Remove the (temporary) file // Remove the (temporary) file
#ifdef EXV_UNICODE_PATH ::remove(fileIo->path().c_str());
if (fileIo->p_->wpMode_ == Impl::wpUnicode) { throw Error(kerFileOpenFailed, path(), "a+b", strError());
::_wremove(fileIo->wpath().c_str());
}
else
#endif
{
::remove(fileIo->path().c_str());
}
#ifdef EXV_UNICODE_PATH
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerFileOpenFailed, wpath(), "a+b", strError().c_str());
}
else
#endif
{
throw Error(kerFileOpenFailed, path(), "a+b", strError());
}
} }
close(); close();
@ -651,26 +471,12 @@ namespace Exiv2 {
mode_t origStMode = 0; mode_t origStMode = 0;
std::string spf; std::string spf;
char* pf = nullptr; char* pf = nullptr;
#ifdef EXV_UNICODE_PATH spf = path();
std::wstring wspf; pf = const_cast<char*>(spf.c_str());
wchar_t* wpf = 0;
if (p_->wpMode_ == Impl::wpUnicode) {
wspf = wpath();
wpf = const_cast<wchar_t*>(wspf.c_str());
}
else
#endif
{
spf = path();
pf = const_cast<char*>(spf.c_str());
}
// Get the permissions of the file, or linked-to file, on platforms which have lstat // Get the permissions of the file, or linked-to file, on platforms which have lstat
#ifdef EXV_HAVE_LSTAT #ifdef EXV_HAVE_LSTAT
# ifdef EXV_UNICODE_PATH
# error EXV_UNICODE_PATH and EXV_HAVE_LSTAT are not compatible. Stop.
# endif
struct stat buf1; struct stat buf1;
if (::lstat(pf, &buf1) == -1) { if (::lstat(pf, &buf1) == -1) {
statOk = false; statOk = false;
@ -705,71 +511,6 @@ namespace Exiv2 {
origStMode = buf1.st_mode; origStMode = buf1.st_mode;
#endif // !EXV_HAVE_LSTAT #endif // !EXV_HAVE_LSTAT
// MSVCRT rename that does not overwrite existing files
#ifdef EXV_UNICODE_PATH
if (p_->wpMode_ == Impl::wpUnicode) {
#if defined(WIN32) && defined(REPLACEFILE_IGNORE_MERGE_ERRORS)
// Windows implementation that deals with the fact that ::rename fails
// if the target filename still exists, which regularly happens when
// that file has been opened with FILE_SHARE_DELETE by another process,
// like a virus scanner or disk indexer
// (see also http://stackoverflow.com/a/11023068)
using ReplaceFileW_t = BOOL(WINAPI*)(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPVOID, LPVOID);
HMODULE hKernel = ::GetModuleHandleA("kernel32.dll");
if (hKernel) {
ReplaceFileW_t pfcn_ReplaceFileW = (ReplaceFileW_t)GetProcAddress(hKernel, "ReplaceFileW");
if (pfcn_ReplaceFileW) {
BOOL ret = pfcn_ReplaceFileW(wpf, fileIo->wpath().c_str(), NULL, REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL);
if (ret == 0) {
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
if (::_wrename(fileIo->wpath().c_str(), wpf) == -1) {
throw WError(kerFileRenameFailed, fileIo->wpath(), wpf, strError().c_str());
}
::_wremove(fileIo->wpath().c_str());
}
else {
throw WError(kerFileRenameFailed, fileIo->wpath(), wpf, strError().c_str());
}
}
}
else {
if (fileExists(wpf) && ::_wremove(wpf) != 0) {
throw WError(kerCallFailed, wpf, strError().c_str(), "::_wremove");
}
if (::_wrename(fileIo->wpath().c_str(), wpf) == -1) {
throw WError(kerFileRenameFailed, fileIo->wpath(), wpf, strError().c_str());
}
::_wremove(fileIo->wpath().c_str());
}
}
#else
if (fileExists(wpf) && ::_wremove(wpf) != 0) {
throw WError(kerCallFailed, wpf, strError().c_str(), "::_wremove");
}
if (::_wrename(fileIo->wpath().c_str(), wpf) == -1) {
throw WError(kerFileRenameFailed, fileIo->wpath(), wpf, strError().c_str());
}
::_wremove(fileIo->wpath().c_str());
#endif
// Check permissions of new file
struct _stat buf2;
if (statOk && ::_wstat(wpf, &buf2) == -1) {
statOk = false;
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << Error(kerCallFailed, wpf, strError(), "::_wstat") << "\n";
#endif
}
if (statOk && origStMode != buf2.st_mode) {
// Set original file permissions
if (::_wchmod(wpf, origStMode) == -1) {
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << Error(kerCallFailed, wpf, strError(), "::_wchmod") << "\n";
#endif
}
}
} // if (p_->wpMode_ == Impl::wpUnicode)
else
#endif // EXV_UNICODE_PATH
{ {
#if defined(WIN32) && defined(REPLACEFILE_IGNORE_MERGE_ERRORS) #if defined(WIN32) && defined(REPLACEFILE_IGNORE_MERGE_ERRORS)
// Windows implementation that deals with the fact that ::rename fails // Windows implementation that deals with the fact that ::rename fails
@ -835,26 +576,10 @@ namespace Exiv2 {
else { else {
// Generic handling, reopen both to reset to start // Generic handling, reopen both to reset to start
if (open("w+b") != 0) { if (open("w+b") != 0) {
#ifdef EXV_UNICODE_PATH throw Error(kerFileOpenFailed, path(), "w+b", strError());
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerFileOpenFailed, wpath(), "w+b", strError().c_str());
}
else
#endif
{
throw Error(kerFileOpenFailed, path(), "w+b", strError());
}
} }
if (src.open() != 0) { if (src.open() != 0) {
#ifdef EXV_UNICODE_PATH throw Error(kerDataSourceOpenFailed, src.path(), strError());
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerDataSourceOpenFailed, src.wpath(), strError().c_str());
}
else
#endif
{
throw Error(kerDataSourceOpenFailed, src.path(), strError());
}
} }
write(src); write(src);
src.close(); src.close();
@ -862,29 +587,13 @@ namespace Exiv2 {
if (wasOpen) { if (wasOpen) {
if (open(lastMode) != 0) { if (open(lastMode) != 0) {
#ifdef EXV_UNICODE_PATH throw Error(kerFileOpenFailed, path(), lastMode, strError());
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerFileOpenFailed, wpath(), lastMode.c_str(), strError().c_str());
}
else
#endif
{
throw Error(kerFileOpenFailed, path(), lastMode, strError());
}
} }
} }
else close(); else close();
if (error() || src.error()) { if (error() || src.error()) {
#ifdef EXV_UNICODE_PATH throw Error(kerTransferFailed, path(), strError());
if (p_->wpMode_ == Impl::wpUnicode) {
throw WError(kerTransferFailed, wpath(), strError().c_str());
}
else
#endif
{
throw Error(kerTransferFailed, path(), strError());
}
} }
} // FileIo::transfer } // FileIo::transfer
@ -949,16 +658,9 @@ namespace Exiv2 {
close(); close();
p_->openMode_ = mode; p_->openMode_ = mode;
p_->opMode_ = Impl::opSeek; p_->opMode_ = Impl::opSeek;
#ifdef EXV_UNICODE_PATH p_->fp_ = ::fopen(path().c_str(), mode.c_str());
if (p_->wpMode_ == Impl::wpUnicode) { if (!p_->fp_)
p_->fp_ = ::_wfopen(wpath().c_str(), s2ws(mode).c_str()); return 1;
}
else
#endif
{
p_->fp_ = ::fopen(path().c_str(), mode.c_str());
}
if (!p_->fp_) return 1;
return 0; return 0;
} }
@ -1020,25 +722,9 @@ namespace Exiv2 {
std::string FileIo::path() const std::string FileIo::path() const
{ {
#ifdef EXV_UNICODE_PATH
if (p_->wpMode_ == Impl::wpUnicode) {
return ws2s(p_->wpath_);
}
#endif
return p_->path_; return p_->path_;
} }
#ifdef EXV_UNICODE_PATH
std::wstring FileIo::wpath() const
{
if (p_->wpMode_ == Impl::wpStandard) {
return s2ws(p_->path_);
}
return p_->wpath_;
}
#endif
void FileIo::populateFakeData() { void FileIo::populateFakeData() {
} }
@ -1363,13 +1049,6 @@ namespace Exiv2 {
return "MemIo"; return "MemIo";
} }
#ifdef EXV_UNICODE_PATH
std::wstring MemIo::wpath() const
{
return EXV_WIDEN("MemIo");
}
#endif
void MemIo::populateFakeData() { void MemIo::populateFakeData() {
} }
@ -1381,15 +1060,6 @@ namespace Exiv2 {
if (prot == pStdin) ReadStdin(); if (prot == pStdin) ReadStdin();
else if (prot == pDataUri) ReadDataUri(path); else if (prot == pDataUri) ReadDataUri(path);
} }
#ifdef EXV_UNICODE_PATH
XPathIo::XPathIo(const std::wstring& wpath) {
std::string path;
path.assign(wpath.begin(), wpath.end());
Protocol prot = fileProtocol(path);
if (prot == pStdin) ReadStdin();
else if (prot == pDataUri) ReadDataUri(path);
}
#endif
void XPathIo::ReadStdin() { void XPathIo::ReadStdin() {
if (isatty(fileno(stdin))) if (isatty(fileno(stdin)))
@ -1436,14 +1106,6 @@ namespace Exiv2 {
tempFilePath_ = path(); tempFilePath_ = path();
} }
#ifdef EXV_UNICODE_PATH
XPathIo::XPathIo(const std::wstring& wOrgPathpath) : FileIo(XPathIo::writeDataToFile(wOrgPathpath)), isTemp_(true)
{
isTemp_ = true;
tempFilePath_ = path();
}
#endif
XPathIo::~XPathIo() { XPathIo::~XPathIo() {
if (isTemp_ && remove(tempFilePath_.c_str()) != 0) { if (isTemp_ && remove(tempFilePath_.c_str()) != 0) {
// error when removing file // error when removing file
@ -1520,13 +1182,6 @@ namespace Exiv2 {
return path; return path;
} }
#ifdef EXV_UNICODE_PATH
std::string XPathIo::writeDataToFile(const std::wstring& wOrgPath) {
std::string orgPath;
orgPath.assign(wOrgPath.begin(), wOrgPath.end());
return XPathIo::writeDataToFile(orgPath);
}
#endif
#endif #endif
@ -1535,18 +1190,11 @@ namespace Exiv2 {
public: public:
//! Constructor //! Constructor
Impl(const std::string& url, size_t blockSize); Impl(const std::string& url, size_t blockSize);
#ifdef EXV_UNICODE_PATH
//! Constructor accepting a unicode path in an std::wstring
Impl(const std::wstring& wpath, size_t blockSize);
#endif
//! Destructor. Releases all managed memory. //! Destructor. Releases all managed memory.
virtual ~Impl(); virtual ~Impl();
// DATA // DATA
std::string path_; //!< (Standard) path std::string path_; //!< (Standard) path
#ifdef EXV_UNICODE_PATH
std::wstring wpath_; //!< Unicode path
#endif
size_t blockSize_; //!< Size of the block memory. size_t blockSize_; //!< Size of the block memory.
BlockMap* blocksMap_; //!< An array contains all blocksMap BlockMap* blocksMap_; //!< An array contains all blocksMap
size_t size_; //!< The file size size_t size_; //!< The file size
@ -1607,13 +1255,6 @@ namespace Exiv2 {
totalRead_(0) totalRead_(0)
{ {
} }
#ifdef EXV_UNICODE_PATH
RemoteIo::Impl::Impl(const std::wstring& wurl, size_t blockSize)
: wpath_(wurl), blockSize_(blockSize), blocksMap_(0), size_(0),
idx_(0), isMalloced_(false), eof_(false), protocol_(fileProtocol(wurl))
{
}
#endif
size_t RemoteIo::Impl::populateBlocks(size_t lowBlock, size_t highBlock) size_t RemoteIo::Impl::populateBlocks(size_t lowBlock, size_t highBlock)
{ {
@ -1949,13 +1590,6 @@ namespace Exiv2 {
return p_->path_; return p_->path_;
} }
#ifdef EXV_UNICODE_PATH
std::wstring RemoteIo::wpath() const
{
return p_->wpath_;
}
#endif
void RemoteIo::populateFakeData() void RemoteIo::populateFakeData()
{ {
assert(p_->isMalloced_); assert(p_->isMalloced_);
@ -1972,10 +1606,6 @@ namespace Exiv2 {
public: public:
//! Constructor //! Constructor
HttpImpl(const std::string& url, size_t blockSize); HttpImpl(const std::string& url, size_t blockSize);
#ifdef EXV_UNICODE_PATH
//! Constructor accepting a unicode path in an std::wstring
HttpImpl(const std::wstring& wpath, size_t blockSize);
#endif
Exiv2::Uri hostInfo_; //!< the host information extracted from the path Exiv2::Uri hostInfo_; //!< the host information extracted from the path
// METHODS // METHODS
@ -2019,17 +1649,6 @@ namespace Exiv2 {
hostInfo_ = Exiv2::Uri::Parse(url); hostInfo_ = Exiv2::Uri::Parse(url);
Exiv2::Uri::Decode(hostInfo_); Exiv2::Uri::Decode(hostInfo_);
} }
#ifdef EXV_UNICODE_PATH
HttpIo::HttpImpl::HttpImpl(const std::wstring& wurl, size_t blockSize):Impl(wurl, blockSize)
{
std::string url;
url.assign(wurl.begin(), wurl.end());
path_ = url;
hostInfo_ = Exiv2::Uri::Parse(url);
Exiv2::Uri::Decode(hostInfo_);
}
#endif
long HttpIo::HttpImpl::getFileLength() long HttpIo::HttpImpl::getFileLength()
{ {
@ -2128,12 +1747,6 @@ namespace Exiv2 {
{ {
p_ = new HttpImpl(url, blockSize); p_ = new HttpImpl(url, blockSize);
} }
#ifdef EXV_UNICODE_PATH
HttpIo::HttpIo(const std::wstring& wurl, size_t blockSize)
{
p_ = new HttpImpl(wurl, blockSize);
}
#endif
#ifdef EXV_USE_CURL #ifdef EXV_USE_CURL
//! Internal Pimpl structure of class RemoteIo. //! Internal Pimpl structure of class RemoteIo.
@ -2141,10 +1754,6 @@ namespace Exiv2 {
public: public:
//! Constructor //! Constructor
CurlImpl(const std::string& path, size_t blockSize); CurlImpl(const std::string& path, size_t blockSize);
#ifdef EXV_UNICODE_PATH
//! Constructor accepting a unicode path in an std::wstring
CurlImpl(const std::wstring& wpath, size_t blockSize);
#endif
//! Destructor. Cleans up the curl pointer and releases all managed memory. //! Destructor. Cleans up the curl pointer and releases all managed memory.
~CurlImpl() override; ~CurlImpl() override;
@ -2208,27 +1817,6 @@ namespace Exiv2 {
throw Error(kerErrorMessage, "Timeout Environmental Variable must be a positive integer."); throw Error(kerErrorMessage, "Timeout Environmental Variable must be a positive integer.");
} }
} }
#ifdef EXV_UNICODE_PATH
CurlIo::CurlImpl::CurlImpl(const std::wstring& wurl, size_t blockSize):Impl(wurl, blockSize)
{
std::string url;
url.assign(wurl.begin(), wurl.end());
path_ = url;
// init curl pointer
curl_ = curl_easy_init();
if(!curl_) {
throw Error(kerErrorMessage, "Unable to init libcurl.");
}
// The default block size for FTP is much larger than other protocols
// the reason is that getDataByRange() in FTP always creates the new connection,
// so we need the large block size to reduce the overhead of creating the connection.
if (blockSize_ == 0) {
blockSize_ = protocol_ == pFtp ? 102400 : 1024;
}
}
#endif
long CurlIo::CurlImpl::getFileLength() long CurlIo::CurlImpl::getFileLength()
{ {
@ -2368,12 +1956,6 @@ namespace Exiv2 {
{ {
p_ = new CurlImpl(url, blockSize); p_ = new CurlImpl(url, blockSize);
} }
#ifdef EXV_UNICODE_PATH
CurlIo::CurlIo(const std::wstring& wurl, size_t blockSize)
{
p_ = new CurlImpl(wurl, blockSize);
}
#endif
#endif #endif
@ -2398,26 +1980,6 @@ namespace Exiv2 {
return buf; return buf;
} }
#ifdef EXV_UNICODE_PATH
DataBuf readFile(const std::wstring& wpath)
{
FileIo file(wpath);
if (file.open("rb") != 0) {
throw WError(kerFileOpenFailed, wpath, "rb", strError().c_str());
}
struct _stat st;
if (0 != ::_wstat(wpath.c_str(), &st)) {
throw WError(kerCallFailed, wpath, strError().c_str(), "::_wstat");
}
DataBuf buf(st.st_size);
long len = file.read(buf.data(), buf.size());
if (len != buf.size()) {
throw WError(kerCallFailed, wpath, strError().c_str(), "FileIo::read");
}
return buf;
}
#endif
long writeFile(const DataBuf& buf, const std::string& path) long writeFile(const DataBuf& buf, const std::string& path)
{ {
FileIo file(path); FileIo file(path);
@ -2427,17 +1989,6 @@ namespace Exiv2 {
return file.write(buf.c_data(), buf.size()); return file.write(buf.c_data(), buf.size());
} }
#ifdef EXV_UNICODE_PATH
long writeFile(const DataBuf& buf, const std::wstring& wpath)
{
FileIo file(wpath);
if (file.open("wb") != 0) {
throw WError(kerFileOpenFailed, wpath, "wb", strError().c_str());
}
return file.write(buf.c_data(), buf.size());
}
#endif
std::string ReplaceStringInPlace(std::string subject, const std::string& search, std::string ReplaceStringInPlace(std::string subject, const std::string& search,
const std::string& replace) { const std::string& replace) {
size_t pos = 0; size_t pos = 0;
@ -2448,18 +1999,6 @@ namespace Exiv2 {
return subject; return subject;
} }
#ifdef EXV_UNICODE_PATH
std::wstring ReplaceStringInPlace(std::wstring subject, const std::wstring& search,
const std::wstring& replace) {
std::wstring::size_type pos = 0;
while((pos = subject.find(search, pos)) != std::wstring::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
#endif
#ifdef EXV_USE_CURL #ifdef EXV_USE_CURL
size_t curlWriter(char* data, size_t size, size_t nmemb, size_t curlWriter(char* data, size_t size, size_t nmemb,
std::string* writerData) std::string* writerData)

@ -238,49 +238,11 @@ namespace Exiv2 {
} }
} }
msg_ = msg; msg_ = msg;
#ifdef EXV_UNICODE_PATH
wmsg_ = s2ws(msg);
#endif
} }
#ifdef __APPLE__ #ifdef __APPLE__
template class EXIV2API BasicError<char>; template class EXIV2API BasicError<char>;
#endif #endif
#ifdef EXV_UNICODE_PATH
template<>
void EXIV2API BasicError<wchar_t>::setMsg()
{
std::string s = _(errMsg(code_));
std::wstring wmsg(s.begin(), s.end());
std::wstring::size_type pos;
pos = wmsg.find(L"%0");
if (pos != std::wstring::npos) {
wmsg.replace(pos, 2, toBasicString<wchar_t>(code_));
}
if (count_ > 0) {
pos = wmsg.find(L"%1");
if (pos != std::wstring::npos) {
wmsg.replace(pos, 2, arg1_);
}
}
if (count_ > 1) {
pos = wmsg.find(L"%2");
if (pos != std::wstring::npos) {
wmsg.replace(pos, 2, arg2_);
}
}
if (count_ > 2) {
pos = wmsg.find(L"%3");
if (pos != std::wstring::npos) {
wmsg.replace(pos, 2, arg3_);
}
}
wmsg_ = wmsg;
msg_ = ws2s(wmsg);
}
template class EXIV2API BasicError<wchar_t>;
#endif
const char* errMsg(int code) const char* errMsg(int code)
{ {
const ErrMsg* em = find(errList, code); const ErrMsg* em = find(errList, code);

@ -110,13 +110,6 @@ namespace {
(".tif", ".jpg"). (".tif", ".jpg").
*/ */
virtual const char* extension() const =0; virtual const char* extension() const =0;
#ifdef EXV_UNICODE_PATH
/*!
@brief Like extension() but returns the extension in a wchar_t.
@note This function is only available on Windows.
*/
virtual const wchar_t* wextension() const =0;
#endif
//@} //@}
}; // class Thumbnail }; // class Thumbnail
@ -138,9 +131,6 @@ namespace {
Exiv2::DataBuf copy(const Exiv2::ExifData& exifData) const override; Exiv2::DataBuf copy(const Exiv2::ExifData& exifData) const override;
const char* mimeType() const override; const char* mimeType() const override;
const char* extension() const override; const char* extension() const override;
#ifdef EXV_UNICODE_PATH
const wchar_t* wextension() const;
#endif
//@} //@}
}; // class TiffThumbnail }; // class TiffThumbnail
@ -162,9 +152,6 @@ namespace {
Exiv2::DataBuf copy(const Exiv2::ExifData& exifData) const override; Exiv2::DataBuf copy(const Exiv2::ExifData& exifData) const override;
const char* mimeType() const override; const char* mimeType() const override;
const char* extension() const override; const char* extension() const override;
#ifdef EXV_UNICODE_PATH
const wchar_t* wextension() const;
#endif
//@} //@}
}; // class JpegThumbnail }; // class JpegThumbnail
@ -475,19 +462,6 @@ namespace Exiv2 {
return Exiv2::writeFile(buf, name); return Exiv2::writeFile(buf, name);
} }
#ifdef EXV_UNICODE_PATH
long ExifThumbC::writeFile(const std::wstring& wpath) const
{
auto thumbnail = Thumbnail::create(exifData_);
if (!thumbnail)
return 0;
std::wstring name = wpath + thumbnail->wextension();
DataBuf buf(thumbnail->copy(exifData_));
if (buf.size() == 0) return 0;
return Exiv2::writeFile(buf, name);
}
#endif
const char* ExifThumbC::mimeType() const const char* ExifThumbC::mimeType() const
{ {
auto thumbnail = Thumbnail::create(exifData_); auto thumbnail = Thumbnail::create(exifData_);
@ -504,16 +478,6 @@ namespace Exiv2 {
return thumbnail->extension(); return thumbnail->extension();
} }
#ifdef EXV_UNICODE_PATH
const wchar_t* ExifThumbC::wextension() const
{
auto thumbnail = Thumbnail::create(exifData_);
if (!thumbnail)
return EXV_WIDEN("");
return thumbnail->wextension();
}
#endif
ExifThumb::ExifThumb(ExifData& exifData) ExifThumb::ExifThumb(ExifData& exifData)
: ExifThumbC(exifData), exifData_(exifData) : ExifThumbC(exifData), exifData_(exifData)
{ {
@ -530,19 +494,6 @@ namespace Exiv2 {
setJpegThumbnail(thumb.c_data(), thumb.size(), xres, yres, unit); setJpegThumbnail(thumb.c_data(), thumb.size(), xres, yres, unit);
} }
#ifdef EXV_UNICODE_PATH
void ExifThumb::setJpegThumbnail(
const std::wstring& wpath,
URational xres,
URational yres,
uint16_t unit
)
{
DataBuf thumb = readFile(wpath); // may throw
setJpegThumbnail(thumb.c_data(), thumb.size(), xres, yres, unit);
}
#endif
void ExifThumb::setJpegThumbnail( void ExifThumb::setJpegThumbnail(
const byte* buf, const byte* buf,
long size, long size,
@ -563,14 +514,6 @@ namespace Exiv2 {
setJpegThumbnail(thumb.c_data(), thumb.size()); setJpegThumbnail(thumb.c_data(), thumb.size());
} }
#ifdef EXV_UNICODE_PATH
void ExifThumb::setJpegThumbnail(const std::wstring& wpath)
{
DataBuf thumb = readFile(wpath); // may throw
setJpegThumbnail(thumb.c_data(), thumb.size());
}
#endif
void ExifThumb::setJpegThumbnail(const byte* buf, long size) void ExifThumb::setJpegThumbnail(const byte* buf, long size)
{ {
exifData_["Exif.Thumbnail.Compression"] = uint16_t(6); exifData_["Exif.Thumbnail.Compression"] = uint16_t(6);
@ -909,13 +852,6 @@ namespace {
return ".tif"; return ".tif";
} }
#ifdef EXV_UNICODE_PATH
const wchar_t* TiffThumbnail::wextension() const
{
return EXV_WIDEN(".tif");
}
#endif
Exiv2::DataBuf TiffThumbnail::copy(const Exiv2::ExifData& exifData) const Exiv2::DataBuf TiffThumbnail::copy(const Exiv2::ExifData& exifData) const
{ {
Exiv2::ExifData thumb; Exiv2::ExifData thumb;
@ -944,13 +880,6 @@ namespace {
return ".jpg"; return ".jpg";
} }
#ifdef EXV_UNICODE_PATH
const wchar_t* JpegThumbnail::wextension() const
{
return EXV_WIDEN(".jpg");
}
#endif
Exiv2::DataBuf JpegThumbnail::copy(const Exiv2::ExifData& exifData) const Exiv2::DataBuf JpegThumbnail::copy(const Exiv2::ExifData& exifData) const
{ {
Exiv2::ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat"); Exiv2::ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat");

@ -120,6 +120,8 @@ namespace {
// Main // Main
int main(int argc, char* const argv[]) int main(int argc, char* const argv[])
{ {
setlocale(LC_CTYPE, ".utf8");
Exiv2::XmpParser::initialize(); Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate); ::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF #ifdef EXV_ENABLE_BMFF

@ -251,35 +251,7 @@ namespace Exiv2 {
return result; return result;
} // fileProtocol } // fileProtocol
#ifdef EXV_UNICODE_PATH
Protocol fileProtocol(const std::wstring& path) {
Protocol result = pFile ;
struct {
std::wstring name ;
Protocol prot ;
bool isUrl; // path.size() > name.size()
} prots[] =
{ { L"http://" ,pHttp , true }
, { L"https://" ,pHttps , true }
, { L"ftp://" ,pFtp , true }
, { L"sftp://" ,pSftp , true }
, { L"file://" ,pFileUri , true }
, { L"data://" ,pDataUri , true }
, { L"-" ,pStdin , false }
};
for (auto&& prot : prots) {
if (result != pFile)
break;
if (path.rfind(prot.name, 0) == 0)
// URL's require data. Stdin == "-" and no further data
if (prot.isUrl ? path.size() > prot.name.size() : path.size() == prot.name.size())
result = prot.prot;
}
return result;
} // fileProtocol
#endif
bool fileExists(const std::string& path, bool ct) bool fileExists(const std::string& path, bool ct)
{ {
// special case: accept "-" (means stdin) // special case: accept "-" (means stdin)
@ -294,36 +266,12 @@ namespace Exiv2 {
return true; return true;
} // fileExists } // fileExists
#ifdef EXV_UNICODE_PATH
bool fileExists(const std::wstring& wpath, bool ct)
{
// special case: accept "-" (means stdin)
if (wpath.compare(L"-") == 0 || fileProtocol(wpath) != pFile) {
return true;
}
struct _stat buf;
int ret = _wstat(wpath.c_str(), &buf);
if (0 != ret) return false;
if (ct && !S_ISREG(buf.st_mode)) return false;
return true;
} // fileExists
#endif
std::string pathOfFileUrl(const std::string& url) { std::string pathOfFileUrl(const std::string& url) {
std::string path = url.substr(7); std::string path = url.substr(7);
size_t found = path.find('/'); size_t found = path.find('/');
if (found == std::string::npos) return path; if (found == std::string::npos) return path;
return path.substr(found); return path.substr(found);
} }
#ifdef EXV_UNICODE_PATH
std::wstring pathOfFileUrl(const std::wstring& wurl) {
std::wstring path = wurl.substr(7);
size_t found = path.find('/');
if (found == std::wstring::npos) return path;
else return path.substr(found);
}
#endif
std::string strError() std::string strError()
{ {

@ -818,14 +818,6 @@ namespace Exiv2 {
return getType(fileIo); return getType(fileIo);
} }
#ifdef EXV_UNICODE_PATH
int ImageFactory::getType(const std::wstring& wpath)
{
FileIo fileIo(wpath);
return getType(fileIo);
}
#endif
int ImageFactory::getType(const byte* data, long size) int ImageFactory::getType(const byte* data, long size)
{ {
MemIo memIo(data, size); MemIo memIo(data, size);
@ -866,24 +858,6 @@ namespace Exiv2 {
(void)(useCurl); (void)(useCurl);
} // ImageFactory::createIo } // ImageFactory::createIo
#ifdef EXV_UNICODE_PATH
BasicIo::UniquePtr ImageFactory::createIo(const std::wstring& wpath, bool useCurl)
{
Protocol fProt = fileProtocol(wpath);
#ifdef EXV_USE_CURL
if (useCurl && (fProt == pHttp || fProt == pHttps || fProt == pFtp)) {
return std::make_unique<CurlIo>(wpath);
}
#endif
if (fProt == pHttp)
return std::make_unique<HttpIo>(wpath);
if (fProt == pFileUri)
return std::make_unique<FileIo>(pathOfFileUrl(wpath));
if (fProt == pStdin || fProt == pDataUri)
return std::make_unique<XPathIo>(wpath); // may throw
return std::make_unique<FileIo>(wpath);
}
#endif
Image::UniquePtr ImageFactory::open(const std::string& path, bool useCurl) Image::UniquePtr ImageFactory::open(const std::string& path, bool useCurl)
{ {
auto image = open(ImageFactory::createIo(path, useCurl)); // may throw auto image = open(ImageFactory::createIo(path, useCurl)); // may throw
@ -892,16 +866,6 @@ namespace Exiv2 {
return image; return image;
} }
#ifdef EXV_UNICODE_PATH
Image::UniquePtr ImageFactory::open(const std::wstring& wpath, bool useCurl)
{
auto image = open(ImageFactory::createIo(wpath, useCurl)); // may throw
if (!image)
throw WError(kerFileContainsUnknownImageType, wpath);
return image;
}
#endif
Image::UniquePtr ImageFactory::open(const byte* data, long size) Image::UniquePtr ImageFactory::open(const byte* data, long size)
{ {
auto io = std::make_unique<MemIo>(data, size); auto io = std::make_unique<MemIo>(data, size);
@ -940,25 +904,6 @@ namespace Exiv2 {
return image; return image;
} }
#ifdef EXV_UNICODE_PATH
Image::UniquePtr ImageFactory::create(int type,
const std::wstring& wpath)
{
auto fileIo = std::make_unique<FileIo>(wpath);
// Create or overwrite the file, then close it
if (fileIo->open("w+b") != 0) {
throw WError(kerFileOpenFailed, wpath, "w+b", strError().c_str());
}
fileIo->close();
BasicIo::UniquePtr io(std::move(fileIo));
auto image = create(type, std::move(io));
if (!image)
throw Error(kerUnsupportedImageType, type);
return image;
}
#endif
Image::UniquePtr ImageFactory::create(int type) Image::UniquePtr ImageFactory::create(int type)
{ {
auto io = std::make_unique<MemIo>(); auto io = std::make_unique<MemIo>();

@ -450,9 +450,6 @@ namespace {
#endif #endif
prop.extension_ = ".dat"; prop.extension_ = ".dat";
} }
#ifdef EXV_UNICODE_PATH
prop.wextension_ = s2ws(prop.extension_);
#endif
return prop; return prop;
} }
@ -559,9 +556,6 @@ namespace {
PreviewProperties prop = Loader::getProperties(); PreviewProperties prop = Loader::getProperties();
prop.mimeType_ = "image/jpeg"; prop.mimeType_ = "image/jpeg";
prop.extension_ = ".jpg"; prop.extension_ = ".jpg";
#ifdef EXV_UNICODE_PATH
prop.wextension_ = EXV_WIDEN(".jpg");
#endif
return prop; return prop;
} }
@ -638,9 +632,6 @@ namespace {
PreviewProperties prop = Loader::getProperties(); PreviewProperties prop = Loader::getProperties();
prop.mimeType_ = "image/jpeg"; prop.mimeType_ = "image/jpeg";
prop.extension_ = ".jpg"; prop.extension_ = ".jpg";
#ifdef EXV_UNICODE_PATH
prop.wextension_ = EXV_WIDEN(".jpg");
#endif
return prop; return prop;
} }
@ -751,9 +742,6 @@ namespace {
PreviewProperties prop = Loader::getProperties(); PreviewProperties prop = Loader::getProperties();
prop.mimeType_ = "image/tiff"; prop.mimeType_ = "image/tiff";
prop.extension_ = ".tif"; prop.extension_ = ".tif";
#ifdef EXV_UNICODE_PATH
prop.wextension_ = EXV_WIDEN(".tif");
#endif
return prop; return prop;
} }
@ -881,9 +869,6 @@ namespace {
PreviewProperties prop = Loader::getProperties(); PreviewProperties prop = Loader::getProperties();
prop.mimeType_ = "image/jpeg"; prop.mimeType_ = "image/jpeg";
prop.extension_ = ".jpg"; prop.extension_ = ".jpg";
#ifdef EXV_UNICODE_PATH
prop.wextension_ = EXV_WIDEN(".jpg");
#endif
return prop; return prop;
} }
@ -1065,16 +1050,6 @@ namespace Exiv2 {
return Exiv2::writeFile(buf, name); return Exiv2::writeFile(buf, name);
} }
#ifdef EXV_UNICODE_PATH
long PreviewImage::writeFile(const std::wstring& wpath) const
{
std::wstring name = wpath + wextension();
// Todo: Creating a DataBuf here unnecessarily copies the memory
DataBuf buf(pData(), size());
return Exiv2::writeFile(buf, name);
}
#endif
DataBuf PreviewImage::copy() const DataBuf PreviewImage::copy() const
{ {
return DataBuf(pData(), size()); return DataBuf(pData(), size());
@ -1100,13 +1075,6 @@ namespace Exiv2 {
return properties_.extension_; return properties_.extension_;
} }
#ifdef EXV_UNICODE_PATH
std::wstring PreviewImage::wextension() const
{
return properties_.wextension_;
}
#endif
uint32_t PreviewImage::width() const uint32_t PreviewImage::width() const
{ {
return properties_.width_; return properties_.width_;

@ -2731,7 +2731,7 @@ namespace Exiv2 {
} }
if (!cnv) os << value; if (!cnv) os << value;
return os; return os;
} // printUcs2 }
std::ostream& printExifUnit(std::ostream& os, const Value& value, const ExifData* metadata) std::ostream& printExifUnit(std::ostream& os, const Value& value, const ExifData* metadata)
{ {

@ -133,19 +133,11 @@ namespace Exiv2 {
bool isTgaType(BasicIo& iIo, bool /*advance*/) bool isTgaType(BasicIo& iIo, bool /*advance*/)
{ {
// not all TARGA files have a signature string, so first just try to match the file name extension // not all TARGA files have a signature string, so first just try to match the file name extension
#ifdef EXV_UNICODE_PATH
std::wstring wpath = iIo.wpath();
if( wpath.rfind(EXV_WIDEN(".tga")) != std::wstring::npos
|| wpath.rfind(EXV_WIDEN(".TGA")) != std::wstring::npos) {
return true;
}
#else
std::string path = iIo.path(); std::string path = iIo.path();
if( path.rfind(".tga") != std::string::npos if( path.rfind(".tga") != std::string::npos
|| path.rfind(".TGA") != std::string::npos) { || path.rfind(".TGA") != std::string::npos) {
return true; return true;
} }
#endif
byte buf[26]; byte buf[26];
long curPos = iIo.tell(); long curPos = iIo.tell();
if ( curPos < 26 ) return false; if ( curPos < 26 ) return false;

@ -27,9 +27,6 @@
#include "unused.h" #include "unused.h"
// + standard includes // + standard includes
#ifdef EXV_UNICODE_PATH
# include <windows.h> // for MultiByteToWideChar etc
#endif
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
@ -667,32 +664,6 @@ namespace Exiv2 {
#endif #endif
} }
#ifdef EXV_UNICODE_PATH
std::string ws2s(const std::wstring& s)
{
int len;
int slength = (int)s.length() + 1;
len = WideCharToMultiByte(CP_ACP, 0, s.c_str(), slength, 0, 0, 0, 0);
char* buf = new char[len];
WideCharToMultiByte(CP_ACP, 0, s.c_str(), slength, buf, len, 0, 0);
std::string r(buf);
delete[] buf;
return r;
}
std::wstring s2ws(const std::string& s)
{
int len;
int slength = (int)s.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
std::wstring r(buf);
delete[] buf;
return r;
}
#endif // EXV_UNICODE_PATH
template<> template<>
bool stringTo<bool>(const std::string& s, bool& ok) bool stringTo<bool>(const std::string& s, bool& ok)
{ {

@ -332,7 +332,6 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const std::vector<std::regex>& keys
int have_strings =0; int have_strings =0;
int have_sys_types =0; int have_sys_types =0;
int have_unistd =0; int have_unistd =0;
int have_unicode_path=0;
int enable_bmff =0; int enable_bmff =0;
int enable_webready =0; int enable_webready =0;
@ -437,10 +436,6 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const std::vector<std::regex>& keys
have_unistd=1; have_unistd=1;
#endif #endif
#ifdef EXV_UNICODE_PATH
have_unicode_path=1;
#endif
#ifdef EXV_ENABLE_BMFF #ifdef EXV_ENABLE_BMFF
enable_bmff=1; enable_bmff=1;
#endif #endif
@ -516,7 +511,6 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const std::vector<std::regex>& keys
output(os,keys,"have_strings" ,have_strings ); output(os,keys,"have_strings" ,have_strings );
output(os,keys,"have_sys_types" ,have_sys_types ); output(os,keys,"have_sys_types" ,have_sys_types );
output(os,keys,"have_unistd" ,have_unistd ); output(os,keys,"have_unistd" ,have_unistd );
output(os,keys,"have_unicode_path" ,have_unicode_path);
output(os,keys,"enable_bmff" ,enable_bmff ); output(os,keys,"enable_bmff" ,enable_bmff );
output(os,keys,"enable_webready" ,enable_webready ); output(os,keys,"enable_webready" ,enable_webready );
output(os,keys,"enable_nls" ,enable_nls ); output(os,keys,"enable_nls" ,enable_nls );

@ -0,0 +1,40 @@
#include <windows.h>
extern int __cdecl main();
int wmain(int argc, wchar_t* argv[])
{
char** args;
int nbytes = (int)(sizeof(char*) * (argc + 1));
HANDLE heap = GetProcessHeap();
for (int i = 0; i < argc; ++i)
nbytes += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL);
args = HeapAlloc(heap, 0, nbytes);
args[0] = (char*)(args + argc + 1);
for (int i = 0; i < argc; ++i)
args[i+1] = args[i] + WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, args[i], nbytes, NULL, NULL);
args[argc] = NULL;
argc = main(argc, args);
HeapFree(heap, 0, args);
return argc;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
(void) hInstance;
(void) hPrevInstance;
(void) lpCmdLine;
(void) nCmdShow;
int argc;
wchar_t** argv;
argv = CommandLineToArgvW(GetCommandLineW(), &argc);
argc = wmain(argc, argv);
LocalFree(argv);
return argc;
}

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
import shutil
import system_tests
import os
@system_tests.CopyTmpFiles("$data_path/Stonehenge.heic")
class Exiv2FilePathsWithSpecialCharacters(metaclass=system_tests.CaseMeta):
url = "https://github.com/Exiv2/exiv2/issues/1996"
# Rename temporary file so that the path contains special Greek characters
original_file = system_tests.path("$tmp_path/Stonehenge.heic")
dst_file = system_tests.path("$tmp_path/Εκκρεμότητες.heic")
def setUp(self):
shutil.copyfile(self.original_file, self.dst_file)
def tearDown(self):
os.remove(self.original_file)
os.remove(self.dst_file)
commands = ["$exiv2 -K Xmp.cm2e.Father $dst_file"]
stdout = ["Xmp.cm2e.Father XmpText 11 Robin Mills\n"]
stderr = [""]
retval = [0]
Loading…
Cancel
Save