Skip to content

Commit e626c14

Browse files
committed
Support Apple's PCSC.framework
Although Apple's PCSC.framework is derived from pcsc-lite, it lacks various definitions and doesn't support PC/SC Part 10 features at all. It is therefore better to unset USE_PCSCLITE when compiling for Apple's PCSC.framework and skipping the PC/SC Part 10 features entirely.
1 parent 0fb40a5 commit e626c14

File tree

4 files changed

+52
-15
lines changed

4 files changed

+52
-15
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ Dependencies
6868
[MacOS / Windows](#macos--windows)). Use the `BUILD_EMV_DECODE` and
6969
`BUILD_EMV_TOOL` options to prevent `emv-decode` and `emv-tool` from being
7070
built and avoid the dependency on `argp`.
71-
* `emv-tool` requires PC/SC, either provided by `WinSCard` on Windows or by
72-
[PCSCLite](https://pcsclite.apdu.fr/) on Linux/MacOS. Use the
73-
`BUILD_EMV_TOOL` option to prevent `emv-tool` from being built and avoid the
74-
dependency on PC/SC.
71+
* `emv-tool` requires PC/SC, either provided by `WinSCard` on Windows, by
72+
PCSC.framework on MacOS, or by [PCSCLite](https://pcsclite.apdu.fr/) on
73+
Linux. Use the `BUILD_EMV_TOOL` option to prevent `emv-tool` from being built
74+
and avoid the dependency on PC/SC.
7575
* `emv-viewer` can _optionally_ be built if [Qt](https://www.qt.io/) (see
7676
[Qt](#qt) for details) is available at build-time. If it is not available,
7777
`emv-viewer` will not be built. Use the `BUILD_EMV_VIEWER` option to ensure

src/pcsc.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @file pcsc.c
33
* @brief PC/SC abstraction
44
*
5-
* Copyright 2021-2022, 2024 Leon Lynch
5+
* Copyright 2021-2022, 2024, 2026 Leon Lynch
66
*
77
* This library is free software; you can redistribute it and/or
88
* modify it under the terms of the GNU Lesser General Public
@@ -198,6 +198,11 @@ static int pcsc_reader_populate_features(struct pcsc_reader_t* reader)
198198
&protocol
199199
);
200200
if (result != SCARD_S_SUCCESS) {
201+
#ifdef __APPLE__
202+
// Apple's PCSC.framework does not support PC/SC Part 10 features at
203+
// all and there is little value in showing an error message
204+
return 1;
205+
#endif
201206
fprintf(stderr, "SCardConnect(SCARD_SHARE_DIRECT) failed; result=0x%x [%s]\n", (unsigned int)result, pcsc_stringify_error(result));
202207
return -2;
203208
}

src/pcsc_compat.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @file pcsc_compat.h
33
* @brief PC/SC compatibility helpers
44
*
5-
* Copyright 2024 Leon Lynch
5+
* Copyright 2024, 2026 Leon Lynch
66
*
77
* This library is free software; you can redistribute it and/or
88
* modify it under the terms of the GNU Lesser General Public
@@ -26,12 +26,22 @@
2626
#include <stdint.h>
2727
#include <stdio.h>
2828

29+
// Some pscs-lite implementations do not include this header by default
30+
#ifndef _WIN32
31+
#include <wintypes.h>
32+
#endif
33+
2934
__BEGIN_DECLS
3035

31-
#if !defined(SCARD_CTL_CODE) && defined(CTL_CODE)
36+
#ifndef SCARD_CTL_CODE
37+
#ifdef CTL_CODE
3238
// Not all implementations define SCARD_CTL_CODE but it can be derived
33-
// from CTL_CODE when available
39+
// from CTL_CODE when available (eg Windows)
3440
#define SCARD_CTL_CODE(code) CTL_CODE(FILE_DEVICE_SMARTCARD, (code), METHOD_BUFFERED, FILE_ANY_ACCESS)
41+
#else
42+
// All pcsc-lite derivates agree on this definition of SCARD_CTL_CODE
43+
#define SCARD_CTL_CODE(code) (0x42000000 + (code))
44+
#endif
3545
#endif
3646

3747
// See PC/SC Part 10 Rev 2.02.09, 2.2
@@ -69,13 +79,16 @@ typedef struct {
6979
} __attribute__((packed))
7080
PIN_PROPERTIES_STRUCTURE;
7181

72-
// Only PCSCLite provides pcsc_stringify_error()
82+
#ifndef __APPLE__
83+
// Apple's PCSC.framework is incomplete, requiring USE_PCSCLITE to be unset,
84+
// but nonetheless provides pcsc_stringify_error()
7385
static const char* pcsc_stringify_error(unsigned int result)
7486
{
7587
static char str[16];
7688
snprintf(str, sizeof(str), "0x%08X", result);
7789
return str;
7890
}
91+
#endif
7992

8093
#endif // USE_PCSCLITE
8194

tools/CMakeLists.txt

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
##############################################################################
2-
# Copyright 2022-2025 Leon Lynch
2+
# Copyright 2022-2026 Leon Lynch
33
#
44
# This file is licensed under the terms of the LGPL v2.1 license.
55
# See LICENSE file.
@@ -27,20 +27,33 @@ if(NOT argp_FOUND)
2727
endif()
2828
endif()
2929

30-
# Check for PC/SC API using PCSCLite on Linux and MacOS or Win32 API on Windows
30+
# Check for PC/SC API using Win32 API on Windows, PCSC.framework on MacOS,
31+
# and PCSCLite on Linux
3132
if(WIN32)
3233
include(CheckIncludeFile)
3334
check_include_file(winscard.h HAVE_WINSCARD_H)
3435
if(NOT HAVE_WINSCARD_H AND BUILD_EMV_TOOL)
3536
message(FATAL_ERROR "Could NOT find winscard.h. This is required to build emv-tool.")
3637
endif()
3738
set(PCSC_LIBRARIES WinSCard)
39+
elseif(APPLE)
40+
# Apple's PCSC framework is incompatible with upstream pcsc-lite
41+
find_library(PCSC_FRAMEWORK PCSC)
42+
if(NOT PCSC_FRAMEWORK AND BUILD_EMV_TOOL)
43+
message(FATAL_ERROR "Could NOT find PCSC.framework. This is required to build emv-tool.")
44+
endif()
45+
find_path(PCSC_FRAMEWORK_INCLUDE_DIR NAMES winscard.h)
46+
if(NOT PCSC_FRAMEWORK_INCLUDE_DIR AND BUILD_EMV_TOOL)
47+
message(FATAL_ERROR "Could NOT find winscard.h in PCSC.framework. This is required to build emv-tool.")
48+
endif()
49+
if(PCSC_FRAMEWORK AND PCSC_FRAMEWORK_INCLUDE_DIR)
50+
message(STATUS "Found PCSC.framework: ${PCSC_FRAMEWORK}")
51+
endif()
52+
set(PCSC_LIBRARIES "${PCSC_FRAMEWORK}")
3853
else()
3954
find_package(PCSCLite 1.8)
40-
if(NOT PCSCLite_FOUND)
41-
if(BUILD_EMV_TOOL)
42-
message(FATAL_ERROR "Could NOT find PCSCLite. This is required to build emv-tool.")
43-
endif()
55+
if(NOT PCSCLite_FOUND AND BUILD_EMV_TOOL)
56+
message(FATAL_ERROR "Could NOT find PCSCLite. This is required to build emv-tool.")
4457
endif()
4558
set(PCSC_LIBRARIES PCSCLite::PCSCLite)
4659
endif()
@@ -107,6 +120,12 @@ if(BUILD_EMV_TOOL)
107120
endif()
108121

109122
add_executable(emv-tool emv-tool.c ../src/pcsc.c)
123+
if(PCSC_FRAMEWORK_INCLUDE_DIR)
124+
# Avoid conflicts between Apple's PCSC.h and this project's pcsc.h by
125+
# adding the Apple PCSC framework as a system include directory to
126+
# allow the project include directories to take precedence.
127+
target_include_directories(emv-tool SYSTEM PRIVATE ${PCSC_FRAMEWORK_INCLUDE_DIR})
128+
endif()
110129
target_link_libraries(emv-tool PRIVATE print_helpers emv emv_strings)
111130
if(TARGET libargp::argp)
112131
target_link_libraries(emv-tool PRIVATE libargp::argp)

0 commit comments

Comments
 (0)