pybase64 1.3.2__tar.gz → 1.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pybase64-1.3.2 → pybase64-1.4.1}/MANIFEST.in +3 -0
- {pybase64-1.3.2/src/pybase64.egg-info → pybase64-1.4.1}/PKG-INFO +27 -5
- {pybase64-1.3.2 → pybase64-1.4.1}/README.rst +13 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/.github/workflows/test.yml +108 -17
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/CMakeLists.txt +5 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/Makefile +14 -5
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/bin/base64.c +225 -25
- pybase64-1.4.1/base64/bin/base64.manifest +23 -0
- pybase64-1.4.1/base64/bin/base64.rc +2 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/avx/codec.c +6 -4
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/avx2/codec.c +6 -4
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/avx2/dec_loop.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/avx2/dec_reshuffle.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/avx2/enc_loop.c +2 -2
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/avx2/enc_reshuffle.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/avx2/enc_translate.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/avx512/codec.c +6 -4
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/avx512/enc_loop.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/avx512/enc_reshuffle_translate.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/generic/32/dec_loop.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/generic/32/enc_loop.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/generic/64/enc_loop.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/generic/codec.c +4 -2
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/neon32/codec.c +7 -5
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/neon32/dec_loop.c +3 -3
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/neon32/enc_loop.c +2 -2
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/neon32/enc_reshuffle.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/neon32/enc_translate.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/neon64/codec.c +7 -5
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/neon64/enc_loop.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/neon64/enc_reshuffle.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/sse41/codec.c +6 -4
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/sse42/codec.c +6 -4
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/ssse3/codec.c +6 -4
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/ssse3/dec_loop.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/ssse3/dec_reshuffle.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/ssse3/enc_loop.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/ssse3/enc_reshuffle.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/ssse3/enc_translate.c +1 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/codec_choose.c +14 -5
- pybase64-1.4.1/base64/lib/codecs.h +57 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/env.h +16 -6
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/test/CMakeLists.txt +4 -6
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/test/Makefile +3 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/test/benchmark.c +72 -17
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/test/ci/analysis.sh +2 -1
- pybase64-1.4.1/base64/test/ci/checksums.txt +1 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/test/ci/test.sh +4 -6
- pybase64-1.4.1/base64/test/ci//360/237/230/265/342/200/215/360/237/222/253.bin +2 -0
- pybase64-1.4.1/base64/test/codec_supported.c +40 -0
- pybase64-1.4.1/base64/test/codec_supported.h +3 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/test/test_base64.c +5 -7
- pybase64-1.4.1/pyproject.toml +109 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/setup.cfg +0 -3
- {pybase64-1.3.2 → pybase64-1.4.1}/setup.py +58 -50
- {pybase64-1.3.2 → pybase64-1.4.1}/src/pybase64/__init__.py +31 -8
- {pybase64-1.3.2 → pybase64-1.4.1}/src/pybase64/__main__.py +63 -50
- {pybase64-1.3.2 → pybase64-1.4.1}/src/pybase64/_fallback.py +28 -24
- pybase64-1.4.1/src/pybase64/_license.pyi +1 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/src/pybase64/_pybase64.c +135 -61
- pybase64-1.4.1/src/pybase64/_pybase64.pyi +16 -0
- pybase64-1.4.1/src/pybase64/_typing.py +35 -0
- pybase64-1.4.1/src/pybase64/_version.py +3 -0
- {pybase64-1.3.2 → pybase64-1.4.1/src/pybase64.egg-info}/PKG-INFO +27 -5
- {pybase64-1.3.2 → pybase64-1.4.1}/src/pybase64.egg-info/SOURCES.txt +8 -1
- pybase64-1.4.1/tests/test_benchmark.py +44 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/tests/test_main.py +46 -39
- {pybase64-1.3.2 → pybase64-1.4.1}/tests/test_pybase64.py +144 -177
- pybase64-1.3.2/base64/lib/codecs.h +0 -65
- pybase64-1.3.2/base64/test/codec_supported.c +0 -29
- pybase64-1.3.2/base64/test/codec_supported.h +0 -3
- pybase64-1.3.2/pyproject.toml +0 -19
- pybase64-1.3.2/src/pybase64/_version.py +0 -1
- {pybase64-1.3.2 → pybase64-1.4.1}/LICENSE +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/LICENSE +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/README.md +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/base64-benchmarks.png +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/cmake/Modules/TargetArch.cmake +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/cmake/Modules/TargetSIMDInstructionSet.cmake +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/cmake/base64-config.cmake.in +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/cmake/config.h.in +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/cmake/test-arch.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/include/libbase64.h +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/avx/enc_loop_asm.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/avx2/enc_loop_asm.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/generic/dec_head.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/generic/dec_tail.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/generic/enc_head.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/generic/enc_tail.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/neon64/dec_loop.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/neon64/enc_loop_asm.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/arch/ssse3/enc_loop_asm.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/exports.txt +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/lib.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/lib_openmp.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/tables/Makefile +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/tables/table_dec_32bit.h +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/tables/table_enc_12bit.h +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/tables/table_enc_12bit.py +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/tables/table_generator.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/tables/tables.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/lib/tables/tables.h +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/test/moby_dick.h +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/test/moby_dick_base64.txt +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/base64/test/moby_dick_plain.txt +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/src/pybase64/_license.py +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/src/pybase64/_pybase64_get_simd_flags.c +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/src/pybase64/_pybase64_get_simd_flags.h +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/src/pybase64/py.typed +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/src/pybase64.egg-info/dependency_links.txt +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/src/pybase64.egg-info/entry_points.txt +0 -0
- {pybase64-1.3.2 → pybase64-1.4.1}/src/pybase64.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: pybase64
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.1
|
|
4
4
|
Summary: Fast Base64 encoding/decoding
|
|
5
5
|
Home-page: https://github.com/mayeut/pybase64
|
|
6
6
|
Author: Matthieu Darbois
|
|
@@ -16,16 +16,25 @@ Classifier: Topic :: Utilities
|
|
|
16
16
|
Classifier: License :: OSI Approved :: BSD License
|
|
17
17
|
Classifier: Programming Language :: C
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
21
19
|
Classifier: Programming Language :: Python :: 3.8
|
|
22
20
|
Classifier: Programming Language :: Python :: 3.9
|
|
23
21
|
Classifier: Programming Language :: Python :: 3.10
|
|
24
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
25
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
-
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Requires-Python: >=3.8
|
|
27
26
|
Description-Content-Type: text/x-rst
|
|
28
27
|
License-File: LICENSE
|
|
28
|
+
Dynamic: author
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: description
|
|
31
|
+
Dynamic: description-content-type
|
|
32
|
+
Dynamic: home-page
|
|
33
|
+
Dynamic: keywords
|
|
34
|
+
Dynamic: license
|
|
35
|
+
Dynamic: project-url
|
|
36
|
+
Dynamic: requires-python
|
|
37
|
+
Dynamic: summary
|
|
29
38
|
|
|
30
39
|
.. SETUP VARIABLES
|
|
31
40
|
.. |license-status| image:: https://img.shields.io/badge/license-BSD%202--Clause-blue.svg
|
|
@@ -150,6 +159,19 @@ Running Python 3.7.2, Apple LLVM version 10.0.0 (clang-1000.11.45.5), Mac OS X 1
|
|
|
150
159
|
|
|
151
160
|
Changelog
|
|
152
161
|
=========
|
|
162
|
+
1.4.1
|
|
163
|
+
-----
|
|
164
|
+
- Publish PyPy 3.11 wheels
|
|
165
|
+
- Publish armv7l wheels
|
|
166
|
+
|
|
167
|
+
1.4.0
|
|
168
|
+
-----
|
|
169
|
+
- Publish python 3.13 wheels
|
|
170
|
+
- Add support for free-threaded builds
|
|
171
|
+
- Add MSYS2 support for C-extension
|
|
172
|
+
- Better logging on base64 build failure when C-extension build is optional
|
|
173
|
+
- Drop python 3.6 & 3.7 support
|
|
174
|
+
|
|
153
175
|
1.3.2
|
|
154
176
|
-----
|
|
155
177
|
- Update base64 library
|
|
@@ -121,6 +121,19 @@ Running Python 3.7.2, Apple LLVM version 10.0.0 (clang-1000.11.45.5), Mac OS X 1
|
|
|
121
121
|
|
|
122
122
|
Changelog
|
|
123
123
|
=========
|
|
124
|
+
1.4.1
|
|
125
|
+
-----
|
|
126
|
+
- Publish PyPy 3.11 wheels
|
|
127
|
+
- Publish armv7l wheels
|
|
128
|
+
|
|
129
|
+
1.4.0
|
|
130
|
+
-----
|
|
131
|
+
- Publish python 3.13 wheels
|
|
132
|
+
- Add support for free-threaded builds
|
|
133
|
+
- Add MSYS2 support for C-extension
|
|
134
|
+
- Better logging on base64 build failure when C-extension build is optional
|
|
135
|
+
- Drop python 3.6 & 3.7 support
|
|
136
|
+
|
|
124
137
|
1.3.2
|
|
125
138
|
-----
|
|
126
139
|
- Update base64 library
|
|
@@ -5,10 +5,10 @@ on: [push, pull_request]
|
|
|
5
5
|
jobs:
|
|
6
6
|
makefile-analysis:
|
|
7
7
|
name: makefile-analysis
|
|
8
|
-
runs-on: ubuntu-
|
|
8
|
+
runs-on: ubuntu-24.04
|
|
9
9
|
steps:
|
|
10
10
|
- name: Checkout
|
|
11
|
-
uses: actions/checkout@
|
|
11
|
+
uses: actions/checkout@v4
|
|
12
12
|
- name: "Install analysis tools"
|
|
13
13
|
run: |
|
|
14
14
|
sudo apt-get update
|
|
@@ -23,11 +23,11 @@ jobs:
|
|
|
23
23
|
strategy:
|
|
24
24
|
fail-fast: false
|
|
25
25
|
matrix:
|
|
26
|
-
runner: ["ubuntu-
|
|
26
|
+
runner: ["ubuntu-22.04"]
|
|
27
27
|
compiler: ["gcc", "clang"]
|
|
28
28
|
openmp: ["0", "1"]
|
|
29
29
|
include:
|
|
30
|
-
- runner: "macos-
|
|
30
|
+
- runner: "macos-13"
|
|
31
31
|
compiler: "clang"
|
|
32
32
|
openmp: "0"
|
|
33
33
|
env:
|
|
@@ -37,7 +37,12 @@ jobs:
|
|
|
37
37
|
OBJCOPY: ${{ (startsWith(matrix.runner, 'macos') && 'echo') || 'objcopy' }}
|
|
38
38
|
steps:
|
|
39
39
|
- name: Checkout
|
|
40
|
-
uses: actions/checkout@
|
|
40
|
+
uses: actions/checkout@v4
|
|
41
|
+
- name: Install Ubuntu libomp support
|
|
42
|
+
if: runner.os == 'Linux' && matrix.compiler == 'clang' && matrix.openmp == 1
|
|
43
|
+
run: |
|
|
44
|
+
sudo apt-get update
|
|
45
|
+
sudo apt-get install -y libomp-dev
|
|
41
46
|
- name: Run tests
|
|
42
47
|
run: ./test/ci/test.sh
|
|
43
48
|
|
|
@@ -48,14 +53,18 @@ jobs:
|
|
|
48
53
|
strategy:
|
|
49
54
|
fail-fast: false
|
|
50
55
|
matrix:
|
|
51
|
-
runner: ["ubuntu-
|
|
56
|
+
runner: ["ubuntu-22.04", "windows-2019"]
|
|
52
57
|
platform: ["x86_64", "i686"]
|
|
53
|
-
|
|
54
|
-
- runner: "macos-
|
|
55
|
-
platform: "
|
|
58
|
+
include:
|
|
59
|
+
- runner: "macos-13"
|
|
60
|
+
platform: "x86_64"
|
|
61
|
+
- runner: "macos-14"
|
|
62
|
+
platform: "arm64"
|
|
63
|
+
- runner: "ubuntu-22.04-arm"
|
|
64
|
+
platform: "aarch64"
|
|
56
65
|
steps:
|
|
57
66
|
- name: Checkout
|
|
58
|
-
uses: actions/checkout@
|
|
67
|
+
uses: actions/checkout@v4
|
|
59
68
|
- name: Install Ubuntu i686 support
|
|
60
69
|
if: runner.os == 'Linux' && matrix.platform == 'i686'
|
|
61
70
|
run: |
|
|
@@ -70,13 +79,13 @@ jobs:
|
|
|
70
79
|
-Werror=dev
|
|
71
80
|
-DBASE64_BUILD_TESTS=ON
|
|
72
81
|
${{ runner.os != 'Windows' && '-DCMAKE_BUILD_TYPE=Release' || '' }}
|
|
73
|
-
${{ runner.os == 'macOS' && '-DBASE64_WITH_AVX2=OFF' || '' }}
|
|
74
82
|
${{ runner.os == 'Windows' && matrix.platform == 'i686' && '-A Win32' || '' }}
|
|
75
|
-
-DBASE64_WITH_AVX512=OFF
|
|
76
83
|
- name: CMake Build
|
|
77
84
|
run: cmake --build out --config Release --verbose
|
|
78
85
|
- name: CTest
|
|
79
86
|
run: ctest --no-tests=error --test-dir out -VV --build-config Release
|
|
87
|
+
env:
|
|
88
|
+
BASE64_TEST_SKIP_AVX512: "1"
|
|
80
89
|
|
|
81
90
|
alpine-makefile-test:
|
|
82
91
|
name: makefile-alpine-amd64-gcc
|
|
@@ -90,7 +99,7 @@ jobs:
|
|
|
90
99
|
- name: Install deps
|
|
91
100
|
run: apk add --update bash build-base git
|
|
92
101
|
- name: Checkout
|
|
93
|
-
uses: actions/checkout@
|
|
102
|
+
uses: actions/checkout@v4
|
|
94
103
|
- name: Run tests
|
|
95
104
|
run: ./test/ci/test.sh
|
|
96
105
|
|
|
@@ -104,20 +113,21 @@ jobs:
|
|
|
104
113
|
- name: Install deps
|
|
105
114
|
run: apk add --update bash build-base cmake git
|
|
106
115
|
- name: Checkout
|
|
107
|
-
uses: actions/checkout@
|
|
116
|
+
uses: actions/checkout@v4
|
|
108
117
|
- name: CMake Configure
|
|
109
118
|
run: >
|
|
110
119
|
cmake
|
|
111
120
|
-B out
|
|
112
121
|
-Werror=dev
|
|
113
122
|
-DBASE64_BUILD_TESTS=ON
|
|
114
|
-
-DBASE64_WITH_AVX512=OFF
|
|
115
123
|
-DCMAKE_BUILD_TYPE=Release
|
|
116
124
|
- name: CMake Build
|
|
117
125
|
run: cmake --build out --config Release --verbose
|
|
118
126
|
- name: CTest
|
|
119
127
|
run: ctest --no-tests=error -VV --build-config Release
|
|
120
128
|
working-directory: ./out
|
|
129
|
+
env:
|
|
130
|
+
BASE64_TEST_SKIP_AVX512: "1"
|
|
121
131
|
|
|
122
132
|
alpine-alt-arch-makefile-test:
|
|
123
133
|
name: makefile-alpine-${{matrix.arch}}-${{matrix.cc}}
|
|
@@ -130,7 +140,7 @@ jobs:
|
|
|
130
140
|
cc: [gcc, clang]
|
|
131
141
|
steps:
|
|
132
142
|
- name: Checkout
|
|
133
|
-
uses: actions/checkout@
|
|
143
|
+
uses: actions/checkout@v4
|
|
134
144
|
- uses: uraimo/run-on-arch-action@v2
|
|
135
145
|
with:
|
|
136
146
|
arch: ${{matrix.arch}}
|
|
@@ -151,7 +161,7 @@ jobs:
|
|
|
151
161
|
cc: [gcc, clang]
|
|
152
162
|
steps:
|
|
153
163
|
- name: Checkout
|
|
154
|
-
uses: actions/checkout@
|
|
164
|
+
uses: actions/checkout@v4
|
|
155
165
|
- uses: uraimo/run-on-arch-action@v2
|
|
156
166
|
with:
|
|
157
167
|
arch: ${{matrix.arch}}
|
|
@@ -169,3 +179,84 @@ jobs:
|
|
|
169
179
|
echo "::group::CTest"
|
|
170
180
|
ctest --no-tests=error --test-dir out -VV --build-config Release
|
|
171
181
|
echo "::endgroup::CTest"
|
|
182
|
+
|
|
183
|
+
msys2-cmake-test:
|
|
184
|
+
name: msys2-cmake-${{ matrix.msystem }}
|
|
185
|
+
needs: makefile-analysis
|
|
186
|
+
runs-on: windows-2022
|
|
187
|
+
strategy:
|
|
188
|
+
fail-fast: false
|
|
189
|
+
matrix:
|
|
190
|
+
include:
|
|
191
|
+
- { msystem: msys, toolchain: "gcc" }
|
|
192
|
+
- { msystem: mingw32, env: mingw-w64-i686- }
|
|
193
|
+
- { msystem: mingw64, env: mingw-w64-x86_64- }
|
|
194
|
+
- { msystem: ucrt64, env: mingw-w64-ucrt-x86_64- }
|
|
195
|
+
- { msystem: clang64, env: mingw-w64-clang-x86_64- }
|
|
196
|
+
|
|
197
|
+
steps:
|
|
198
|
+
- name: Checkout
|
|
199
|
+
uses: actions/checkout@v4
|
|
200
|
+
- name: Setup MSYS2 ${{matrix.msystem}}
|
|
201
|
+
uses: msys2/setup-msys2@v2
|
|
202
|
+
with:
|
|
203
|
+
msystem: ${{matrix.msystem}}
|
|
204
|
+
update: true
|
|
205
|
+
install: >-
|
|
206
|
+
make
|
|
207
|
+
${{ matrix.env }}${{ matrix.toolchain || 'toolchain' }}
|
|
208
|
+
${{ matrix.env }}cmake
|
|
209
|
+
- name: CMake Configure
|
|
210
|
+
shell: msys2 {0}
|
|
211
|
+
run: >
|
|
212
|
+
cmake
|
|
213
|
+
-B out
|
|
214
|
+
-Werror=dev
|
|
215
|
+
-DBASE64_BUILD_TESTS=ON
|
|
216
|
+
-DCMAKE_BUILD_TYPE=Release
|
|
217
|
+
- name: CMake Build
|
|
218
|
+
shell: msys2 {0}
|
|
219
|
+
run: cmake --build out --config Release --verbose
|
|
220
|
+
- name: CTest
|
|
221
|
+
shell: msys2 {0}
|
|
222
|
+
run: ctest --no-tests=error --test-dir out -VV --build-config Release
|
|
223
|
+
env:
|
|
224
|
+
BASE64_TEST_SKIP_AVX512: "1"
|
|
225
|
+
- name: Test demo utility with unicode filenames and file contents on Windows
|
|
226
|
+
shell: msys2 {0}
|
|
227
|
+
run: |
|
|
228
|
+
out/bin/base64 test/ci/😵💫.bin > test/ci/😵💫.bin.b64
|
|
229
|
+
out/bin/base64 -d test/ci/😵💫.bin.b64 > test/ci/😵💫.bin
|
|
230
|
+
cd test/ci
|
|
231
|
+
sha256sum -c checksums.txt
|
|
232
|
+
|
|
233
|
+
msys2-makefile-test:
|
|
234
|
+
name: msys2-makefile-${{ matrix.msystem }}
|
|
235
|
+
needs: makefile-analysis
|
|
236
|
+
runs-on: windows-2022
|
|
237
|
+
strategy:
|
|
238
|
+
fail-fast: false
|
|
239
|
+
matrix:
|
|
240
|
+
include:
|
|
241
|
+
- { msystem: msys, toolchain: "gcc" }
|
|
242
|
+
- { msystem: mingw32, env: mingw-w64-i686- }
|
|
243
|
+
- { msystem: mingw64, env: mingw-w64-x86_64- }
|
|
244
|
+
- { msystem: ucrt64, env: mingw-w64-ucrt-x86_64- }
|
|
245
|
+
# - { msystem: clang32, env: mingw-w64-clang-i686- } disabled, lld does not support the "-r" option
|
|
246
|
+
# - { msystem: clang64, env: mingw-w64-clang-x86_64- } disabled, lld does not support the "-r" option
|
|
247
|
+
env:
|
|
248
|
+
CC: cc.exe
|
|
249
|
+
steps:
|
|
250
|
+
- name: Checkout
|
|
251
|
+
uses: actions/checkout@v4
|
|
252
|
+
- name: Setup MSYS2 ${{matrix.msystem}}
|
|
253
|
+
uses: msys2/setup-msys2@v2
|
|
254
|
+
with:
|
|
255
|
+
msystem: ${{matrix.msystem}}
|
|
256
|
+
update: true
|
|
257
|
+
install: >-
|
|
258
|
+
make
|
|
259
|
+
${{ matrix.env }}${{ matrix.toolchain || 'toolchain' }}
|
|
260
|
+
- name: Run tests
|
|
261
|
+
shell: msys2 {0}
|
|
262
|
+
run: ./test/ci/test.sh
|
|
@@ -17,7 +17,7 @@ if (POLICY CMP0127)
|
|
|
17
17
|
cmake_policy(SET CMP0127 NEW)
|
|
18
18
|
endif()
|
|
19
19
|
|
|
20
|
-
project(base64 LANGUAGES C VERSION 0.5.
|
|
20
|
+
project(base64 LANGUAGES C VERSION 0.5.2)
|
|
21
21
|
|
|
22
22
|
include(GNUInstallDirs)
|
|
23
23
|
include(CMakeDependentOption)
|
|
@@ -249,6 +249,10 @@ if (BASE64_BUILD_CLI)
|
|
|
249
249
|
set_target_properties(base64-bin PROPERTIES
|
|
250
250
|
OUTPUT_NAME base64
|
|
251
251
|
)
|
|
252
|
+
|
|
253
|
+
if (WIN32)
|
|
254
|
+
target_sources(base64-bin PRIVATE bin/base64.rc)
|
|
255
|
+
endif ()
|
|
252
256
|
endif()
|
|
253
257
|
|
|
254
258
|
########################################################################
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic
|
|
1
|
+
CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic -DBASE64_STATIC_DEFINE
|
|
2
2
|
|
|
3
3
|
# Set OBJCOPY if not defined by environment:
|
|
4
4
|
OBJCOPY ?= objcopy
|
|
@@ -56,6 +56,7 @@ ifdef OPENMP
|
|
|
56
56
|
CFLAGS += -fopenmp
|
|
57
57
|
endif
|
|
58
58
|
|
|
59
|
+
TARGET := $(shell $(CC) -dumpmachine)
|
|
59
60
|
|
|
60
61
|
.PHONY: all analyze clean
|
|
61
62
|
|
|
@@ -64,9 +65,17 @@ all: bin/base64 lib/libbase64.o
|
|
|
64
65
|
bin/base64: bin/base64.o lib/libbase64.o
|
|
65
66
|
$(CC) $(CFLAGS) -o $@ $^
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
# Workaround: mangle exported function names on MinGW32.
|
|
69
|
+
lib/exports.build.txt: lib/exports.txt
|
|
70
|
+
ifeq (i686-w64-mingw32, $(TARGET))
|
|
71
|
+
sed -e 's/^/_/' $< > $@
|
|
72
|
+
else
|
|
73
|
+
cp -f $< $@
|
|
74
|
+
endif
|
|
75
|
+
|
|
76
|
+
lib/libbase64.o: lib/exports.build.txt $(OBJS)
|
|
77
|
+
$(LD) -r -o $@ $(OBJS)
|
|
78
|
+
$(OBJCOPY) --keep-global-symbols=$< $@
|
|
70
79
|
|
|
71
80
|
lib/config.h:
|
|
72
81
|
@echo "#define HAVE_AVX512 $(HAVE_AVX512)" > $@
|
|
@@ -97,4 +106,4 @@ analyze: clean
|
|
|
97
106
|
scan-build --use-analyzer=`which clang` --status-bugs make
|
|
98
107
|
|
|
99
108
|
clean:
|
|
100
|
-
rm -f bin/base64 bin/base64.o lib/libbase64.o lib/config.h $(OBJS)
|
|
109
|
+
rm -f bin/base64 bin/base64.o lib/libbase64.o lib/config.h lib/exports.build.txt $(OBJS)
|
|
@@ -1,4 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
// Test for MinGW.
|
|
2
|
+
#if defined(__MINGW32__) || defined(__MINGW64__)
|
|
3
|
+
# define MINGW
|
|
4
|
+
#endif
|
|
5
|
+
|
|
6
|
+
// Test for Windows.
|
|
7
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
8
|
+
# define WIN
|
|
9
|
+
#endif
|
|
10
|
+
|
|
11
|
+
// Decide if the writev(2) system call needs to be emulated as a series of
|
|
12
|
+
// write(2) calls. At least MinGW does not support writev(2).
|
|
13
|
+
#ifdef MINGW
|
|
14
|
+
# define EMULATE_WRITEV
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
// Include the necessary system header when using the system's writev(2).
|
|
18
|
+
#ifndef EMULATE_WRITEV
|
|
19
|
+
# define _XOPEN_SOURCE // Unlock IOV_MAX
|
|
20
|
+
# include <sys/uio.h>
|
|
21
|
+
#endif
|
|
2
22
|
|
|
3
23
|
#include <stdbool.h>
|
|
4
24
|
#include <stdlib.h>
|
|
@@ -8,7 +28,13 @@
|
|
|
8
28
|
#include <getopt.h>
|
|
9
29
|
#include <errno.h>
|
|
10
30
|
#include <limits.h>
|
|
11
|
-
|
|
31
|
+
|
|
32
|
+
// Include Windows-specific headers.
|
|
33
|
+
#ifdef WIN
|
|
34
|
+
# include <io.h>
|
|
35
|
+
# include <fcntl.h>
|
|
36
|
+
#endif
|
|
37
|
+
|
|
12
38
|
#include "../include/libbase64.h"
|
|
13
39
|
|
|
14
40
|
// Size of the buffer for the "raw" (not base64-encoded) data in bytes.
|
|
@@ -38,6 +64,12 @@ struct config {
|
|
|
38
64
|
|
|
39
65
|
// Whether to just print the help text and exit.
|
|
40
66
|
bool print_help;
|
|
67
|
+
|
|
68
|
+
// Whether to strip newlines from the input when decoding.
|
|
69
|
+
bool strip_newlines;
|
|
70
|
+
|
|
71
|
+
// Whether to ignore any character not in the base64 alphabet.
|
|
72
|
+
bool ignore_garbage;
|
|
41
73
|
};
|
|
42
74
|
|
|
43
75
|
// Input/output buffer structure.
|
|
@@ -50,6 +82,59 @@ struct buffer {
|
|
|
50
82
|
char *enc;
|
|
51
83
|
};
|
|
52
84
|
|
|
85
|
+
// Optionally emulate writev(2) as a series of write calls.
|
|
86
|
+
#ifdef EMULATE_WRITEV
|
|
87
|
+
|
|
88
|
+
// Quick and dirty definition of IOV_MAX as it is probably not defined.
|
|
89
|
+
#ifndef IOV_MAX
|
|
90
|
+
# define IOV_MAX 1024
|
|
91
|
+
#endif
|
|
92
|
+
|
|
93
|
+
// Quick and dirty definition of this system struct, for local use only.
|
|
94
|
+
struct iovec {
|
|
95
|
+
|
|
96
|
+
// Opaque data pointer.
|
|
97
|
+
void *iov_base;
|
|
98
|
+
|
|
99
|
+
// Length of the data in bytes.
|
|
100
|
+
size_t iov_len;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
static ssize_t
|
|
104
|
+
writev (const int fd, const struct iovec *iov, int iovcnt)
|
|
105
|
+
{
|
|
106
|
+
ssize_t r, nwrite = 0;
|
|
107
|
+
|
|
108
|
+
// Reset the error marker.
|
|
109
|
+
errno = 0;
|
|
110
|
+
|
|
111
|
+
while (iovcnt-- > 0) {
|
|
112
|
+
|
|
113
|
+
// Write the vector; propagate errors back to the caller. Note
|
|
114
|
+
// that this loses information about how much vectors have been
|
|
115
|
+
// successfully written, but that also seems to be the case
|
|
116
|
+
// with the real function. The API is somewhat flawed.
|
|
117
|
+
if ((r = write(fd, iov->iov_base, iov->iov_len)) < 0) {
|
|
118
|
+
return r;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Update the total write count.
|
|
122
|
+
nwrite += r;
|
|
123
|
+
|
|
124
|
+
// Return early after a partial write; the caller should retry.
|
|
125
|
+
if ((size_t) r != iov->iov_len) {
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Move to the next vector.
|
|
130
|
+
iov++;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return nwrite;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
#endif // EMULATE_WRITEV
|
|
137
|
+
|
|
53
138
|
static bool
|
|
54
139
|
buffer_alloc (const struct config *config, struct buffer *buf)
|
|
55
140
|
{
|
|
@@ -272,10 +357,54 @@ encode (const struct config *config, struct buffer *buf)
|
|
|
272
357
|
return true;
|
|
273
358
|
}
|
|
274
359
|
|
|
275
|
-
static
|
|
360
|
+
static inline size_t
|
|
361
|
+
find_garbage (const char *p, const size_t avail)
|
|
362
|
+
{
|
|
363
|
+
// Use a lookup table to distinguish garbage from non-garbage.
|
|
364
|
+
static const char lut[256] = {
|
|
365
|
+
['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1,
|
|
366
|
+
['F'] = 1, ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1,
|
|
367
|
+
['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1,
|
|
368
|
+
['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1,
|
|
369
|
+
['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, ['Y'] = 1,
|
|
370
|
+
['Z'] = 1,
|
|
371
|
+
['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1,
|
|
372
|
+
['f'] = 1, ['g'] = 1, ['h'] = 1, ['i'] = 1, ['j'] = 1,
|
|
373
|
+
['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1,
|
|
374
|
+
['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1,
|
|
375
|
+
['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1,
|
|
376
|
+
['z'] = 1,
|
|
377
|
+
['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1,
|
|
378
|
+
['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1,
|
|
379
|
+
['+'] = 1, ['/'] = 1, ['"'] = 1,
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
for (size_t len = 0; len < avail; len++) {
|
|
383
|
+
if (lut[(unsigned char) p[len]] == 0) {
|
|
384
|
+
return len;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return avail;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
static inline size_t
|
|
392
|
+
find_newline (const char *p, const size_t avail)
|
|
393
|
+
{
|
|
394
|
+
// This is very naive and can probably be improved by vectorization.
|
|
395
|
+
for (size_t len = 0; len < avail; len++) {
|
|
396
|
+
if (p[len] == '\n') {
|
|
397
|
+
return len;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return avail;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
static bool
|
|
276
405
|
decode (const struct config *config, struct buffer *buf)
|
|
277
406
|
{
|
|
278
|
-
size_t
|
|
407
|
+
size_t avail;
|
|
279
408
|
struct base64_state state;
|
|
280
409
|
|
|
281
410
|
// Initialize the decoder's state structure.
|
|
@@ -283,18 +412,61 @@ decode (const struct config *config, struct buffer *buf)
|
|
|
283
412
|
|
|
284
413
|
// Read encoded data into the buffer. Use the smallest buffer size to
|
|
285
414
|
// be on the safe side: the decoded output will fit the raw buffer.
|
|
286
|
-
while ((
|
|
415
|
+
while ((avail = fread(buf->enc, 1, BUFFER_RAW_SIZE, config->fp)) > 0) {
|
|
416
|
+
char *start = buf->enc;
|
|
417
|
+
char *outbuf = buf->raw;
|
|
418
|
+
size_t ototal = 0;
|
|
419
|
+
|
|
420
|
+
// By popular demand, this utility tries to be bug-compatible
|
|
421
|
+
// with GNU `base64'. That includes silently ignoring newlines
|
|
422
|
+
// in the input. Tokenize the input on newline characters.
|
|
423
|
+
while (avail > 0) {
|
|
424
|
+
size_t outlen, len;
|
|
425
|
+
|
|
426
|
+
// When stripping garbage or newlines in the input,
|
|
427
|
+
// find the offset of the next garbage/newline
|
|
428
|
+
// character, which is also the length of the next
|
|
429
|
+
// chunk. Otherwise treat the entire input as a single
|
|
430
|
+
// chunk.
|
|
431
|
+
if (config->ignore_garbage) {
|
|
432
|
+
len = find_garbage(start, avail);
|
|
433
|
+
} else if (config->strip_newlines) {
|
|
434
|
+
len = find_newline(start, avail);
|
|
435
|
+
} else {
|
|
436
|
+
len = avail;
|
|
437
|
+
}
|
|
287
438
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
439
|
+
// Ignore empty chunks.
|
|
440
|
+
if (len == 0) {
|
|
441
|
+
start++;
|
|
442
|
+
avail--;
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Decode the chunk into the raw buffer.
|
|
447
|
+
if (base64_stream_decode(&state, start, len,
|
|
448
|
+
outbuf, &outlen) == 0) {
|
|
449
|
+
fprintf(stderr, "%s: %s: decoding error\n",
|
|
450
|
+
config->name, config->file);
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Update the output buffer pointer and total size.
|
|
455
|
+
outbuf += outlen;
|
|
456
|
+
ototal += outlen;
|
|
457
|
+
|
|
458
|
+
// Bail out if the whole string has been consumed.
|
|
459
|
+
if (len == avail) {
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Move the start pointer past the newline.
|
|
464
|
+
start += len + 1;
|
|
465
|
+
avail -= len + 1;
|
|
294
466
|
}
|
|
295
467
|
|
|
296
468
|
// Append the raw data to the output stream.
|
|
297
|
-
if (write_stdout(config, buf->raw,
|
|
469
|
+
if (write_stdout(config, buf->raw, ototal) == false) {
|
|
298
470
|
return false;
|
|
299
471
|
}
|
|
300
472
|
}
|
|
@@ -317,10 +489,17 @@ usage (FILE *fp, const struct config *config)
|
|
|
317
489
|
"If no FILE is given or is specified as '-', "
|
|
318
490
|
"read from standard input.\n"
|
|
319
491
|
"Options:\n"
|
|
320
|
-
" -d, --decode
|
|
321
|
-
" -h, --help
|
|
322
|
-
" -
|
|
323
|
-
"
|
|
492
|
+
" -d, --decode Decode a base64 stream.\n"
|
|
493
|
+
" -h, --help Print this help text.\n"
|
|
494
|
+
" -i, --ignore-garbage When decoding, ignore any "
|
|
495
|
+
"non-base64 data.\n"
|
|
496
|
+
" -n, --no-strip-newlines When decoding, do not strip "
|
|
497
|
+
"newlines. Speeds up\n"
|
|
498
|
+
" decoding of inputs that do not "
|
|
499
|
+
"contain newlines.\n"
|
|
500
|
+
" -w, --wrap=COLS Wrap encoded lines at this "
|
|
501
|
+
"column. Default 76, 0 to\n"
|
|
502
|
+
" disable.\n";
|
|
324
503
|
|
|
325
504
|
fprintf(fp, usage, config->name);
|
|
326
505
|
}
|
|
@@ -357,9 +536,11 @@ parse_opts (int argc, char **argv, struct config *config)
|
|
|
357
536
|
{
|
|
358
537
|
int c;
|
|
359
538
|
static const struct option opts[] = {
|
|
360
|
-
{ "decode",
|
|
361
|
-
{ "help",
|
|
362
|
-
{ "
|
|
539
|
+
{ "decode", no_argument, NULL, 'd' },
|
|
540
|
+
{ "help", no_argument, NULL, 'h' },
|
|
541
|
+
{ "ignore-garbage", no_argument, NULL, 'i' },
|
|
542
|
+
{ "no-strip-newlines", no_argument, NULL, 'n' },
|
|
543
|
+
{ "wrap", required_argument, NULL, 'w' },
|
|
363
544
|
{ NULL }
|
|
364
545
|
};
|
|
365
546
|
|
|
@@ -367,7 +548,7 @@ parse_opts (int argc, char **argv, struct config *config)
|
|
|
367
548
|
config->name = *argv;
|
|
368
549
|
|
|
369
550
|
// Parse command line options.
|
|
370
|
-
while ((c = getopt_long(argc, argv, ":
|
|
551
|
+
while ((c = getopt_long(argc, argv, ":dhinw:", opts, NULL)) != -1) {
|
|
371
552
|
switch (c) {
|
|
372
553
|
case 'd':
|
|
373
554
|
config->decode = true;
|
|
@@ -377,6 +558,14 @@ parse_opts (int argc, char **argv, struct config *config)
|
|
|
377
558
|
config->print_help = true;
|
|
378
559
|
return true;
|
|
379
560
|
|
|
561
|
+
case 'i':
|
|
562
|
+
config->ignore_garbage = true;
|
|
563
|
+
break;
|
|
564
|
+
|
|
565
|
+
case 'n':
|
|
566
|
+
config->strip_newlines = false;
|
|
567
|
+
break;
|
|
568
|
+
|
|
380
569
|
case 'w':
|
|
381
570
|
if (get_wrap(config, optarg) == false) {
|
|
382
571
|
fprintf(stderr,
|
|
@@ -433,11 +622,13 @@ main (int argc, char **argv)
|
|
|
433
622
|
{
|
|
434
623
|
// Default program config.
|
|
435
624
|
struct config config = {
|
|
436
|
-
.file
|
|
437
|
-
.fp
|
|
438
|
-
.wrap
|
|
439
|
-
.decode
|
|
440
|
-
.print_help
|
|
625
|
+
.file = "stdin",
|
|
626
|
+
.fp = stdin,
|
|
627
|
+
.wrap = 76,
|
|
628
|
+
.decode = false,
|
|
629
|
+
.print_help = false,
|
|
630
|
+
.strip_newlines = true,
|
|
631
|
+
.ignore_garbage = false,
|
|
441
632
|
};
|
|
442
633
|
struct buffer buf;
|
|
443
634
|
|
|
@@ -458,6 +649,15 @@ main (int argc, char **argv)
|
|
|
458
649
|
return 1;
|
|
459
650
|
}
|
|
460
651
|
|
|
652
|
+
#ifdef WIN
|
|
653
|
+
|
|
654
|
+
// On Windows, ensure that stdout is binary-clean, and does not
|
|
655
|
+
// silently convert newlines to CRLFs. This seems to be the portable
|
|
656
|
+
// way to do it; freopen() and SetConsoleMode() occasionally result in
|
|
657
|
+
// permission errors, whereas this always seems to work.
|
|
658
|
+
_setmode(1, _O_BINARY);
|
|
659
|
+
#endif
|
|
660
|
+
|
|
461
661
|
// Encode or decode the input based on the user's choice.
|
|
462
662
|
const bool ret = config.decode
|
|
463
663
|
? decode(&config, &buf)
|