pybase64 1.3.2__tar.gz → 1.4.0__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.
Files changed (110) hide show
  1. {pybase64-1.3.2 → pybase64-1.4.0}/MANIFEST.in +3 -0
  2. {pybase64-1.3.2/src/pybase64.egg-info → pybase64-1.4.0}/PKG-INFO +11 -4
  3. {pybase64-1.3.2 → pybase64-1.4.0}/README.rst +8 -0
  4. {pybase64-1.3.2 → pybase64-1.4.0}/base64/.github/workflows/test.yml +81 -0
  5. {pybase64-1.3.2 → pybase64-1.4.0}/base64/CMakeLists.txt +5 -1
  6. {pybase64-1.3.2 → pybase64-1.4.0}/base64/Makefile +14 -5
  7. {pybase64-1.3.2 → pybase64-1.4.0}/base64/bin/base64.c +225 -25
  8. pybase64-1.4.0/base64/bin/base64.manifest +23 -0
  9. pybase64-1.4.0/base64/bin/base64.rc +2 -0
  10. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/avx/codec.c +6 -4
  11. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/avx2/codec.c +6 -4
  12. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/avx2/dec_loop.c +1 -1
  13. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/avx2/dec_reshuffle.c +1 -1
  14. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/avx2/enc_loop.c +2 -2
  15. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/avx2/enc_reshuffle.c +1 -1
  16. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/avx2/enc_translate.c +1 -1
  17. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/avx512/codec.c +6 -4
  18. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/avx512/enc_loop.c +1 -1
  19. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/avx512/enc_reshuffle_translate.c +1 -1
  20. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/generic/32/dec_loop.c +1 -1
  21. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/generic/32/enc_loop.c +1 -1
  22. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/generic/64/enc_loop.c +1 -1
  23. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/generic/codec.c +4 -2
  24. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/neon32/codec.c +7 -5
  25. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/neon32/dec_loop.c +3 -3
  26. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/neon32/enc_loop.c +2 -2
  27. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/neon32/enc_reshuffle.c +1 -1
  28. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/neon32/enc_translate.c +1 -1
  29. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/neon64/codec.c +7 -5
  30. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/neon64/enc_loop.c +1 -1
  31. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/neon64/enc_reshuffle.c +1 -1
  32. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/sse41/codec.c +6 -4
  33. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/sse42/codec.c +6 -4
  34. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/ssse3/codec.c +6 -4
  35. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/ssse3/dec_loop.c +1 -1
  36. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/ssse3/dec_reshuffle.c +1 -1
  37. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/ssse3/enc_loop.c +1 -1
  38. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/ssse3/enc_reshuffle.c +1 -1
  39. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/ssse3/enc_translate.c +1 -1
  40. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/codec_choose.c +3 -3
  41. pybase64-1.4.0/base64/lib/codecs.h +57 -0
  42. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/env.h +16 -6
  43. {pybase64-1.3.2 → pybase64-1.4.0}/base64/test/CMakeLists.txt +4 -6
  44. {pybase64-1.3.2 → pybase64-1.4.0}/base64/test/Makefile +3 -1
  45. {pybase64-1.3.2 → pybase64-1.4.0}/base64/test/benchmark.c +66 -13
  46. pybase64-1.4.0/base64/test/ci/checksums.txt +1 -0
  47. pybase64-1.4.0/base64/test/ci//360/237/230/265/342/200/215/360/237/222/253.bin +2 -0
  48. pybase64-1.4.0/pyproject.toml +97 -0
  49. {pybase64-1.3.2 → pybase64-1.4.0}/setup.cfg +0 -3
  50. {pybase64-1.3.2 → pybase64-1.4.0}/setup.py +58 -50
  51. {pybase64-1.3.2 → pybase64-1.4.0}/src/pybase64/__init__.py +31 -8
  52. {pybase64-1.3.2 → pybase64-1.4.0}/src/pybase64/__main__.py +63 -50
  53. {pybase64-1.3.2 → pybase64-1.4.0}/src/pybase64/_fallback.py +28 -24
  54. pybase64-1.4.0/src/pybase64/_license.pyi +1 -0
  55. {pybase64-1.3.2 → pybase64-1.4.0}/src/pybase64/_pybase64.c +135 -61
  56. pybase64-1.4.0/src/pybase64/_pybase64.pyi +16 -0
  57. pybase64-1.4.0/src/pybase64/_typing.py +35 -0
  58. pybase64-1.4.0/src/pybase64/_version.py +3 -0
  59. {pybase64-1.3.2 → pybase64-1.4.0/src/pybase64.egg-info}/PKG-INFO +11 -4
  60. {pybase64-1.3.2 → pybase64-1.4.0}/src/pybase64.egg-info/SOURCES.txt +8 -1
  61. pybase64-1.4.0/tests/test_benchmark.py +43 -0
  62. {pybase64-1.3.2 → pybase64-1.4.0}/tests/test_main.py +49 -43
  63. {pybase64-1.3.2 → pybase64-1.4.0}/tests/test_pybase64.py +139 -173
  64. pybase64-1.3.2/base64/lib/codecs.h +0 -65
  65. pybase64-1.3.2/pyproject.toml +0 -19
  66. pybase64-1.3.2/src/pybase64/_version.py +0 -1
  67. {pybase64-1.3.2 → pybase64-1.4.0}/LICENSE +0 -0
  68. {pybase64-1.3.2 → pybase64-1.4.0}/base64/LICENSE +0 -0
  69. {pybase64-1.3.2 → pybase64-1.4.0}/base64/README.md +0 -0
  70. {pybase64-1.3.2 → pybase64-1.4.0}/base64/base64-benchmarks.png +0 -0
  71. {pybase64-1.3.2 → pybase64-1.4.0}/base64/cmake/Modules/TargetArch.cmake +0 -0
  72. {pybase64-1.3.2 → pybase64-1.4.0}/base64/cmake/Modules/TargetSIMDInstructionSet.cmake +0 -0
  73. {pybase64-1.3.2 → pybase64-1.4.0}/base64/cmake/base64-config.cmake.in +0 -0
  74. {pybase64-1.3.2 → pybase64-1.4.0}/base64/cmake/config.h.in +0 -0
  75. {pybase64-1.3.2 → pybase64-1.4.0}/base64/cmake/test-arch.c +0 -0
  76. {pybase64-1.3.2 → pybase64-1.4.0}/base64/include/libbase64.h +0 -0
  77. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/avx/enc_loop_asm.c +0 -0
  78. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/avx2/enc_loop_asm.c +0 -0
  79. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/generic/dec_head.c +0 -0
  80. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/generic/dec_tail.c +0 -0
  81. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/generic/enc_head.c +0 -0
  82. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/generic/enc_tail.c +0 -0
  83. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/neon64/dec_loop.c +0 -0
  84. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/neon64/enc_loop_asm.c +0 -0
  85. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/arch/ssse3/enc_loop_asm.c +0 -0
  86. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/exports.txt +0 -0
  87. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/lib.c +0 -0
  88. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/lib_openmp.c +0 -0
  89. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/tables/Makefile +0 -0
  90. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/tables/table_dec_32bit.h +0 -0
  91. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/tables/table_enc_12bit.h +0 -0
  92. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/tables/table_enc_12bit.py +0 -0
  93. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/tables/table_generator.c +0 -0
  94. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/tables/tables.c +0 -0
  95. {pybase64-1.3.2 → pybase64-1.4.0}/base64/lib/tables/tables.h +0 -0
  96. {pybase64-1.3.2 → pybase64-1.4.0}/base64/test/ci/analysis.sh +0 -0
  97. {pybase64-1.3.2 → pybase64-1.4.0}/base64/test/ci/test.sh +0 -0
  98. {pybase64-1.3.2 → pybase64-1.4.0}/base64/test/codec_supported.c +0 -0
  99. {pybase64-1.3.2 → pybase64-1.4.0}/base64/test/codec_supported.h +0 -0
  100. {pybase64-1.3.2 → pybase64-1.4.0}/base64/test/moby_dick.h +0 -0
  101. {pybase64-1.3.2 → pybase64-1.4.0}/base64/test/moby_dick_base64.txt +0 -0
  102. {pybase64-1.3.2 → pybase64-1.4.0}/base64/test/moby_dick_plain.txt +0 -0
  103. {pybase64-1.3.2 → pybase64-1.4.0}/base64/test/test_base64.c +0 -0
  104. {pybase64-1.3.2 → pybase64-1.4.0}/src/pybase64/_license.py +0 -0
  105. {pybase64-1.3.2 → pybase64-1.4.0}/src/pybase64/_pybase64_get_simd_flags.c +0 -0
  106. {pybase64-1.3.2 → pybase64-1.4.0}/src/pybase64/_pybase64_get_simd_flags.h +0 -0
  107. {pybase64-1.3.2 → pybase64-1.4.0}/src/pybase64/py.typed +0 -0
  108. {pybase64-1.3.2 → pybase64-1.4.0}/src/pybase64.egg-info/dependency_links.txt +0 -0
  109. {pybase64-1.3.2 → pybase64-1.4.0}/src/pybase64.egg-info/entry_points.txt +0 -0
  110. {pybase64-1.3.2 → pybase64-1.4.0}/src/pybase64.egg-info/top_level.txt +0 -0
@@ -4,6 +4,9 @@ include LICENSE
4
4
  # Include headers
5
5
  include src/pybase64/_pybase64_get_simd_flags.h
6
6
 
7
+ # Include type stub for extension
8
+ include src/pybase64/_pybase64.pyi
9
+
7
10
  # Include full base64 folder
8
11
  graft base64
9
12
  # but the git folder
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pybase64
3
- Version: 1.3.2
3
+ Version: 1.4.0
4
4
  Summary: Fast Base64 encoding/decoding
5
5
  Home-page: https://github.com/mayeut/pybase64
6
6
  Author: Matthieu Darbois
@@ -16,14 +16,13 @@ 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
- Requires-Python: >=3.6
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
29
28
 
@@ -150,6 +149,14 @@ Running Python 3.7.2, Apple LLVM version 10.0.0 (clang-1000.11.45.5), Mac OS X 1
150
149
 
151
150
  Changelog
152
151
  =========
152
+ 1.4.0
153
+ -----
154
+ - Publish python 3.13 wheels
155
+ - Add support for free-threaded builds
156
+ - Add MSYS2 support for C-extension
157
+ - Better logging on base64 build failure when C-extension build is optional
158
+ - Drop python 3.6 & 3.7 support
159
+
153
160
  1.3.2
154
161
  -----
155
162
  - Update base64 library
@@ -121,6 +121,14 @@ 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.0
125
+ -----
126
+ - Publish python 3.13 wheels
127
+ - Add support for free-threaded builds
128
+ - Add MSYS2 support for C-extension
129
+ - Better logging on base64 build failure when C-extension build is optional
130
+ - Drop python 3.6 & 3.7 support
131
+
124
132
  1.3.2
125
133
  -----
126
134
  - Update base64 library
@@ -169,3 +169,84 @@ jobs:
169
169
  echo "::group::CTest"
170
170
  ctest --no-tests=error --test-dir out -VV --build-config Release
171
171
  echo "::endgroup::CTest"
172
+
173
+ msys2-cmake-test:
174
+ name: msys2-cmake-${{ matrix.msystem }}
175
+ needs: makefile-analysis
176
+ runs-on: windows-2022
177
+ strategy:
178
+ fail-fast: false
179
+ matrix:
180
+ include:
181
+ - { msystem: msys, toolchain: "gcc" }
182
+ - { msystem: mingw32, env: mingw-w64-i686- }
183
+ - { msystem: mingw64, env: mingw-w64-x86_64- }
184
+ - { msystem: ucrt64, env: mingw-w64-ucrt-x86_64- }
185
+ - { msystem: clang32, env: mingw-w64-clang-i686- }
186
+ - { msystem: clang64, env: mingw-w64-clang-x86_64- }
187
+
188
+ steps:
189
+ - name: Checkout
190
+ uses: actions/checkout@v3
191
+ - name: Setup MSYS2 ${{matrix.msystem}}
192
+ uses: msys2/setup-msys2@v2
193
+ with:
194
+ msystem: ${{matrix.msystem}}
195
+ update: true
196
+ install: >-
197
+ make
198
+ ${{ matrix.env }}${{ matrix.toolchain || 'toolchain' }}
199
+ ${{ matrix.env }}cmake
200
+ - name: CMake Configure
201
+ shell: msys2 {0}
202
+ run: >
203
+ cmake
204
+ -B out
205
+ -Werror=dev
206
+ -DBASE64_BUILD_TESTS=ON
207
+ -DCMAKE_BUILD_TYPE=Release
208
+ -DBASE64_WITH_AVX512=OFF
209
+ - name: CMake Build
210
+ shell: msys2 {0}
211
+ run: cmake --build out --config Release --verbose
212
+ - name: CTest
213
+ shell: msys2 {0}
214
+ run: ctest --no-tests=error --test-dir out -VV --build-config Release
215
+ - name: Test demo utility with unicode filenames and file contents on Windows
216
+ shell: msys2 {0}
217
+ run: |
218
+ out/bin/base64 test/ci/😵‍💫.bin > test/ci/😵‍💫.bin.b64
219
+ out/bin/base64 -d test/ci/😵‍💫.bin.b64 > test/ci/😵‍💫.bin
220
+ cd test/ci
221
+ sha256sum -c checksums.txt
222
+
223
+ msys2-makefile-test:
224
+ name: msys2-makefile-${{ matrix.msystem }}
225
+ needs: makefile-analysis
226
+ runs-on: windows-2022
227
+ strategy:
228
+ fail-fast: false
229
+ matrix:
230
+ include:
231
+ - { msystem: msys, toolchain: "gcc" }
232
+ - { msystem: mingw32, env: mingw-w64-i686- }
233
+ - { msystem: mingw64, env: mingw-w64-x86_64- }
234
+ - { msystem: ucrt64, env: mingw-w64-ucrt-x86_64- }
235
+ # - { msystem: clang32, env: mingw-w64-clang-i686- } disabled, lld does not support the "-r" option
236
+ # - { msystem: clang64, env: mingw-w64-clang-x86_64- } disabled, lld does not support the "-r" option
237
+ env:
238
+ CC: cc.exe
239
+ steps:
240
+ - name: Checkout
241
+ uses: actions/checkout@v3
242
+ - name: Setup MSYS2 ${{matrix.msystem}}
243
+ uses: msys2/setup-msys2@v2
244
+ with:
245
+ msystem: ${{matrix.msystem}}
246
+ update: true
247
+ install: >-
248
+ make
249
+ ${{ matrix.env }}${{ matrix.toolchain || 'toolchain' }}
250
+ - name: Run tests
251
+ shell: msys2 {0}
252
+ 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.1)
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
- lib/libbase64.o: $(OBJS)
68
- $(LD) -r -o $@ $^
69
- $(OBJCOPY) --keep-global-symbols=lib/exports.txt $@
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
- #define _XOPEN_SOURCE // IOV_MAX
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
- #include <sys/uio.h>
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 int
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 nread, nout;
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 ((nread = fread(buf->enc, 1, BUFFER_RAW_SIZE, config->fp)) > 0) {
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
- // Decode the input into the raw buffer.
289
- if (base64_stream_decode(&state, buf->enc, nread,
290
- buf->raw, &nout) == 0) {
291
- fprintf(stderr, "%s: %s: decoding error\n",
292
- config->name, config->file);
293
- return false;
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, nout) == false) {
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 Decode a base64 stream.\n"
321
- " -h, --help Print this help text.\n"
322
- " -w, --wrap=COLS Wrap encoded lines at this column. "
323
- "Default 76, 0 to disable.\n";
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", no_argument, NULL, 'd' },
361
- { "help", no_argument, NULL, 'h' },
362
- { "wrap", required_argument, NULL, 'w' },
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, ":dhw:", opts, NULL)) != -1) {
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 = "stdin",
437
- .fp = stdin,
438
- .wrap = 76,
439
- .decode = false,
440
- .print_help = false,
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)
@@ -0,0 +1,23 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+ <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
3
+ <assemblyIdentity type="win32" name="base64" version="0.5.2.0" />
4
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
5
+ <security>
6
+ <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
7
+ <requestedExecutionLevel level="asInvoker" uiAccess="false" />
8
+ </requestedPrivileges>
9
+ </security>
10
+ </trustInfo>
11
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
12
+ <application>
13
+ <!-- Windows 10 and Windows 11 -->
14
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
15
+ </application>
16
+ </compatibility>
17
+ <application>
18
+ <windowsSettings>
19
+ <activeCodePage
20
+ xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
21
+ </windowsSettings>
22
+ </application>
23
+ </assembly>
@@ -0,0 +1,2 @@
1
+ #include "winuser.h"
2
+ CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "base64.manifest"
@@ -33,7 +33,8 @@
33
33
 
34
34
  #endif // HAVE_AVX
35
35
 
36
- BASE64_ENC_FUNCTION(avx)
36
+ void
37
+ base64_stream_encode_avx BASE64_ENC_PARAMS
37
38
  {
38
39
  #if HAVE_AVX
39
40
  #include "../generic/enc_head.c"
@@ -50,17 +51,18 @@ BASE64_ENC_FUNCTION(avx)
50
51
 
51
52
  #include "../generic/enc_tail.c"
52
53
  #else
53
- BASE64_ENC_STUB
54
+ base64_enc_stub(state, src, srclen, out, outlen);
54
55
  #endif
55
56
  }
56
57
 
57
- BASE64_DEC_FUNCTION(avx)
58
+ int
59
+ base64_stream_decode_avx BASE64_DEC_PARAMS
58
60
  {
59
61
  #if HAVE_AVX
60
62
  #include "../generic/dec_head.c"
61
63
  dec_loop_ssse3(&s, &slen, &o, &olen);
62
64
  #include "../generic/dec_tail.c"
63
65
  #else
64
- BASE64_DEC_STUB
66
+ return base64_dec_stub(state, src, srclen, out, outlen);
65
67
  #endif
66
68
  }
@@ -33,24 +33,26 @@
33
33
 
34
34
  #endif // HAVE_AVX2
35
35
 
36
- BASE64_ENC_FUNCTION(avx2)
36
+ void
37
+ base64_stream_encode_avx2 BASE64_ENC_PARAMS
37
38
  {
38
39
  #if HAVE_AVX2
39
40
  #include "../generic/enc_head.c"
40
41
  enc_loop_avx2(&s, &slen, &o, &olen);
41
42
  #include "../generic/enc_tail.c"
42
43
  #else
43
- BASE64_ENC_STUB
44
+ base64_enc_stub(state, src, srclen, out, outlen);
44
45
  #endif
45
46
  }
46
47
 
47
- BASE64_DEC_FUNCTION(avx2)
48
+ int
49
+ base64_stream_decode_avx2 BASE64_DEC_PARAMS
48
50
  {
49
51
  #if HAVE_AVX2
50
52
  #include "../generic/dec_head.c"
51
53
  dec_loop_avx2(&s, &slen, &o, &olen);
52
54
  #include "../generic/dec_tail.c"
53
55
  #else
54
- BASE64_DEC_STUB
56
+ return base64_dec_stub(state, src, srclen, out, outlen);
55
57
  #endif
56
58
  }
@@ -1,4 +1,4 @@
1
- static inline int
1
+ static BASE64_FORCE_INLINE int
2
2
  dec_loop_avx2_inner (const uint8_t **s, uint8_t **o, size_t *rounds)
3
3
  {
4
4
  const __m256i lut_lo = _mm256_setr_epi8(
@@ -1,4 +1,4 @@
1
- static inline __m256i
1
+ static BASE64_FORCE_INLINE __m256i
2
2
  dec_reshuffle (const __m256i in)
3
3
  {
4
4
  // in, lower lane, bits, upper case are most significant bits, lower
@@ -1,4 +1,4 @@
1
- static inline void
1
+ static BASE64_FORCE_INLINE void
2
2
  enc_loop_avx2_inner_first (const uint8_t **s, uint8_t **o)
3
3
  {
4
4
  // First load is done at s - 0 to not get a segfault:
@@ -17,7 +17,7 @@ enc_loop_avx2_inner_first (const uint8_t **s, uint8_t **o)
17
17
  *o += 32;
18
18
  }
19
19
 
20
- static inline void
20
+ static BASE64_FORCE_INLINE void
21
21
  enc_loop_avx2_inner (const uint8_t **s, uint8_t **o)
22
22
  {
23
23
  // Load input:
@@ -1,4 +1,4 @@
1
- static inline __m256i
1
+ static BASE64_FORCE_INLINE __m256i
2
2
  enc_reshuffle (const __m256i input)
3
3
  {
4
4
  // Translation of the SSSE3 reshuffling algorithm to AVX2. This one
@@ -1,4 +1,4 @@
1
- static inline __m256i
1
+ static BASE64_FORCE_INLINE __m256i
2
2
  enc_translate (const __m256i in)
3
3
  {
4
4
  // A lookup table containing the absolute offsets for all ranges: