hexconv 0.1.0__tar.gz → 0.2.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.
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hexconv
3
- Version: 0.1.0
4
- Summary: Pythonic CTF-friendly conversions between bytes, hex, integers, arrays, and text.
3
+ Version: 0.2.0
4
+ Summary: Pythonic conversion toolkit for bytes, hex, integers, arrays, binary strings, base64, and text.
5
5
  Author: hexconv contributors
6
6
  License-Expression: MIT
7
- Keywords: ctf,hex,bytes,conversion,pwn,crypto
7
+ Keywords: hex,bytes,binary,base64,conversion,encoding,toolkit
8
8
  Classifier: Development Status :: 3 - Alpha
9
9
  Classifier: Intended Audience :: Developers
10
10
  Classifier: Operating System :: OS Independent
@@ -15,8 +15,8 @@ Classifier: Programming Language :: Python :: 3.11
15
15
  Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Programming Language :: Python :: 3.13
17
17
  Classifier: Programming Language :: Python :: 3.14
18
- Classifier: Topic :: Security
19
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Topic :: Utilities
20
20
  Classifier: Typing :: Typed
21
21
  Requires-Python: >=3.10
22
22
  Description-Content-Type: text/markdown
@@ -29,9 +29,9 @@ Dynamic: license-file
29
29
 
30
30
  # hexconv
31
31
 
32
- `hexconv` is a small, dependency-free Python library for CTF-style conversions between
33
- bytes, byte arrays, hex strings, hex arrays, integers, integer arrays, bytes literals,
34
- binary strings, base64, and raw text.
32
+ `hexconv` is a small, dependency-free Python conversion toolkit for working with
33
+ bytes, byte arrays, hex strings, hex arrays, integers, integer arrays, bytes
34
+ literals, binary strings, base64, and raw text.
35
35
 
36
36
  The main idea is: explicitly state what you have, then ask for what you want.
37
37
 
@@ -50,8 +50,8 @@ hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).to_hex()
50
50
  hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).hex
51
51
  # 'deadbeef'
52
52
 
53
- hx.from_text("flag").to_hex_array(prefix=True)
54
- # ['0x66', '0x6c', '0x61', '0x67']
53
+ hx.from_text("data").to_hex_array(prefix=True)
54
+ # ['0x64', '0x61', '0x74', '0x61']
55
55
 
56
56
  hx.from_int(0xdeadbeef).to_bytes()
57
57
  # b'\xde\xad\xbe\xef'
@@ -60,6 +60,72 @@ hx.from_int_array([0x1234, 0x5678], width=2).to_hex_array(width=2)
60
60
  # ['1234', '5678']
61
61
  ```
62
62
 
63
+ ## Configurable formats
64
+
65
+ For reusable conversions, construct format specs with options:
66
+
67
+ ```python
68
+ hx.convert("de ad be ef", from_=hx.Hex(), to=hx.Bytes())
69
+ # b'\xde\xad\xbe\xef'
70
+
71
+ hx.convert("data", from_=hx.Text(), to=hx.Hex(prefix=True))
72
+ # '0x64617461'
73
+
74
+ hx.convert("π", from_=hx.Text(encoding="utf-8"), to=hx.Hex())
75
+ # 'cf80'
76
+
77
+ hx.convert("-_8", from_=hx.Base64(urlsafe=True, padding=False), to=hx.Hex())
78
+ # 'fbff'
79
+ ```
80
+
81
+ Old marker-style conversions still work:
82
+
83
+ ```python
84
+ hx.convert("data", from_=hx.Text, to=hx.HexString)
85
+ # '64617461'
86
+ ```
87
+
88
+ ## Composable pipelines
89
+
90
+ Use `pipeline()` when you want a readable builder:
91
+
92
+ ```python
93
+ conv = (
94
+ hx.pipeline()
95
+ .from_(hx.Hex())
96
+ .chunk(2)
97
+ .to(hx.IntArray(width=2))
98
+ )
99
+
100
+ conv("12345678")
101
+ # [4660, 22136]
102
+ ```
103
+
104
+ Use `>>` when you want compact composition:
105
+
106
+ ```python
107
+ conv = hx.Hex() >> hx.Chunk(2) >> hx.HexArray()
108
+
109
+ conv("12345678")
110
+ # ['1234', '5678']
111
+ ```
112
+
113
+ Available transforms:
114
+
115
+ - `Chunk(width, strict=True)` / `Group(width, strict=True)` — set downstream grouping.
116
+ - `Pad.left(width=..., byte=0)` / `Pad.right(block_size=..., byte=0)` — pad bytes.
117
+ - `Reverse()` — reverse byte order.
118
+
119
+ Examples:
120
+
121
+ ```python
122
+ (hx.Hex() >> hx.Pad.left(width=4) >> hx.Hex())("dead")
123
+ # '0000dead'
124
+
125
+ (hx.Hex() >> hx.Reverse() >> hx.Hex())("deadbeef")
126
+ # 'efbeadde'
127
+ ```
128
+
63
129
  ## Why explicit source helpers?
64
130
 
65
131
  Some inputs are impossible to infer safely:
@@ -95,8 +161,8 @@ conv = hx.Converter(hx.BytesArray, hx.HexArray)
95
161
  conv([0xde, 0xad, 0xbe, 0xef])
96
162
  # ['de', 'ad', 'be', 'ef']
97
163
 
98
- hx.convert("flag", from_=hx.Text, to=hx.HexString)
99
- # '666c6167'
164
+ hx.convert("data", from_=hx.Text, to=hx.HexString)
165
+ # '64617461'
100
166
  ```
101
167
 
102
168
  For conversions with options, pass input and output option dictionaries:
@@ -113,6 +179,67 @@ conv([4660, 22136])
113
179
  # ['0x1234', '0x5678']
114
180
  ```
115
181
 
182
+ ## Extra formats
183
+
184
+ Base encodings:
185
+
186
+ ```python
187
+ hx.from_text("data").to(hx.Base32(padding=False))
188
+ # 'MRQXIYI'
189
+
190
+ hx.from_text("data").to(hx.Base85())
191
+ # 'WMOn+'
192
+
193
+ hx.from_text("data").to(hx.Ascii85())
194
+ # 'A79Rg'
195
+ ```
196
+
197
+ Escaped byte strings:
198
+
199
+ ```python
200
+ hx.from_escaped(r"\xde\xad").hex
201
+ # 'dead'
202
+
203
+ hx.from_hex("dead").to(hx.Escaped())
204
+ # '\\xde\\xad'
205
+ ```
206
+
207
+ Hexdump:
208
+
209
+ ```python
210
+ dump = hx.from_hex("deadbeef").to(hx.Hexdump(width=2))
211
+ hx.from_hexdump(dump).hex
212
+ # 'deadbeef'
213
+ ```
214
+
215
+ Python `struct` packing/unpacking:
216
+
217
+ ```python
218
+ hx.from_struct((0x1234, 0x5678), fmt=">HH").hex
219
+ # '12345678'
220
+
221
+ hx.from_hex("12345678").to(hx.Struct(">HH"))
222
+ # (4660, 22136)
223
+ ```
224
+
225
+ Bits:
226
+
227
+ ```python
228
+ hx.from_bits([1, 0, 1]).hex
229
+ # '05'
230
+
231
+ hx.from_hex("05").to(hx.Bits())
232
+ # [0, 0, 0, 0, 0, 1, 0, 1]
233
+ ```
234
+
235
+ Automatic inference with explanations:
236
+
237
+ ```python
238
+ result = hx.infer("0xdead")
239
+ result.format, result.confidence, result.value.hex
240
+ # (<class 'hexconv._core.HexString'>, 0.75, 'dead')
241
+ ```
242
+
116
243
  ## Supported source helpers
117
244
 
118
245
  - `from_bytes(value)`
@@ -126,7 +253,15 @@ conv([4660, 22136])
126
253
  - `from_text(value)`
127
254
  - `from_binary(value)`
128
255
  - `from_base64(value)`
256
+ - `from_base32(value)`
257
+ - `from_base85(value)`
258
+ - `from_ascii85(value)`
259
+ - `from_escaped(value)`
260
+ - `from_hexdump(value)`
261
+ - `from_struct(value, fmt=...)`
262
+ - `from_bits(value)`
129
263
  - `from_auto(value)`
264
+ - `infer(value)`
130
265
 
131
266
  ## Common output methods
132
267
 
@@ -142,4 +277,11 @@ conv([4660, 22136])
142
277
  - `to_text(encoding="ascii", errors="strict")`
143
278
  - `to_binary(sep="")`
144
279
  - `to_base64()`
280
+ - `to_base32()`
281
+ - `to_base85()`
282
+ - `to_ascii85()`
283
+ - `to_escaped()`
284
+ - `to_hexdump()`
285
+ - `to_struct(fmt)`
286
+ - `to_bits()`
145
287
  - `to(format_marker, **options)`
@@ -0,0 +1,258 @@
1
+ # hexconv
2
+
3
+ `hexconv` is a small, dependency-free Python conversion toolkit for working with
4
+ bytes, byte arrays, hex strings, hex arrays, integers, integer arrays, bytes
5
+ literals, binary strings, base64, and raw text.
6
+
7
+ The main idea is: explicitly state what you have, then ask for what you want.
8
+
9
+ ```python
10
+ import hexconv as hx
11
+
12
+ hx.from_hex("dead beef").to_bytes()
13
+ # b'\xde\xad\xbe\xef'
14
+
15
+ hx.from_hex("dead beef").bytes
16
+ # b'\xde\xad\xbe\xef'
17
+
18
+ hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).to_hex()
19
+ # 'deadbeef'
20
+
21
+ hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).hex
22
+ # 'deadbeef'
23
+
24
+ hx.from_text("data").to_hex_array(prefix=True)
25
+ # ['0x64', '0x61', '0x74', '0x61']
26
+
27
+ hx.from_int(0xdeadbeef).to_bytes()
28
+ # b'\xde\xad\xbe\xef'
29
+
30
+ hx.from_int_array([0x1234, 0x5678], width=2).to_hex_array(width=2)
31
+ # ['1234', '5678']
32
+ ```
33
+
34
+ ## Configurable formats
35
+
36
+ For reusable conversions, construct format specs with options:
37
+
38
+ ```python
39
+ hx.convert("de ad be ef", from_=hx.Hex(), to=hx.Bytes())
40
+ # b'\xde\xad\xbe\xef'
41
+
42
+ hx.convert("data", from_=hx.Text(), to=hx.Hex(prefix=True))
43
+ # '0x64617461'
44
+
45
+ hx.convert("π", from_=hx.Text(encoding="utf-8"), to=hx.Hex())
46
+ # 'cf80'
47
+
48
+ hx.convert("-_8", from_=hx.Base64(urlsafe=True, padding=False), to=hx.Hex())
49
+ # 'fbff'
50
+ ```
51
+
52
+ Old marker-style conversions still work:
53
+
54
+ ```python
55
+ hx.convert("data", from_=hx.Text, to=hx.HexString)
56
+ # '64617461'
57
+ ```
58
+
59
+ ## Composable pipelines
60
+
61
+ Use `pipeline()` when you want a readable builder:
62
+
63
+ ```python
64
+ conv = (
65
+ hx.pipeline()
66
+ .from_(hx.Hex())
67
+ .chunk(2)
68
+ .to(hx.IntArray(width=2))
69
+ )
70
+
71
+ conv("12345678")
72
+ # [4660, 22136]
73
+ ```
74
+
75
+ Use `>>` when you want compact composition:
76
+
77
+ ```python
78
+ conv = hx.Hex() >> hx.Chunk(2) >> hx.HexArray()
79
+
80
+ conv("12345678")
81
+ # ['1234', '5678']
82
+ ```
83
+
84
+ Available transforms:
85
+
86
+ - `Chunk(width, strict=True)` / `Group(width, strict=True)` — set downstream grouping.
87
+ - `Pad.left(width=..., byte=0)` / `Pad.right(block_size=..., byte=0)` — pad bytes.
88
+ - `Reverse()` — reverse byte order.
89
+
90
+ Examples:
91
+
92
+ ```python
93
+ (hx.Hex() >> hx.Pad.left(width=4) >> hx.Hex())("dead")
94
+ # '0000dead'
95
+
96
+ (hx.Hex() >> hx.Reverse() >> hx.Hex())("deadbeef")
97
+ # 'efbeadde'
98
+ ```
99
+
100
+ ## Why explicit source helpers?
101
+
102
+ Some inputs are impossible to infer safely:
103
+
104
+ ```python
105
+ "face"
106
+ ```
107
+
108
+ That could be ASCII text (`66 61 63 65`) or hex bytes (`fa ce`). So `hexconv`
109
+ keeps the safe path explicit:
110
+
111
+ ```python
112
+ hx.from_text("face").to_hex()
113
+ # '66616365'
114
+
115
+ hx.from_hex("face").to_bytes()
116
+ # b'\xfa\xce'
117
+ ```
118
+
119
+ If you do want convenience heuristics, use `from_auto`:
120
+
121
+ ```python
122
+ hx.from_auto("0xdeadbeef").to_int()
123
+ # 3735928559
124
+ ```
125
+
126
+ ## Converter API
127
+
128
+ If you prefer a reusable converter object, use marker classes:
129
+
130
+ ```python
131
+ conv = hx.Converter(hx.BytesArray, hx.HexArray)
132
+ conv([0xde, 0xad, 0xbe, 0xef])
133
+ # ['de', 'ad', 'be', 'ef']
134
+
135
+ hx.convert("data", from_=hx.Text, to=hx.HexString)
136
+ # '64617461'
137
+ ```
138
+
139
+ For conversions with options, pass input and output option dictionaries:
140
+
141
+ ```python
142
+ conv = hx.Converter(
143
+ hx.DecimalIntArray,
144
+ hx.HexArray,
145
+ input_options={"width": 2},
146
+ output_options={"width": 2, "prefix": True},
147
+ )
148
+
149
+ conv([4660, 22136])
150
+ # ['0x1234', '0x5678']
151
+ ```
152
+
153
+ ## Extra formats
154
+
155
+ Base encodings:
156
+
157
+ ```python
158
+ hx.from_text("data").to(hx.Base32(padding=False))
159
+ # 'MRQXIYI'
160
+
161
+ hx.from_text("data").to(hx.Base85())
162
+ # 'WMOn+'
163
+
164
+ hx.from_text("data").to(hx.Ascii85())
165
+ # 'A79Rg'
166
+ ```
167
+
168
+ Escaped byte strings:
169
+
170
+ ```python
171
+ hx.from_escaped(r"\xde\xad").hex
172
+ # 'dead'
173
+
174
+ hx.from_hex("dead").to(hx.Escaped())
175
+ # '\\xde\\xad'
176
+ ```
177
+
178
+ Hexdump:
179
+
180
+ ```python
181
+ dump = hx.from_hex("deadbeef").to(hx.Hexdump(width=2))
182
+ hx.from_hexdump(dump).hex
183
+ # 'deadbeef'
184
+ ```
185
+
186
+ Python `struct` packing/unpacking:
187
+
188
+ ```python
189
+ hx.from_struct((0x1234, 0x5678), fmt=">HH").hex
190
+ # '12345678'
191
+
192
+ hx.from_hex("12345678").to(hx.Struct(">HH"))
193
+ # (4660, 22136)
194
+ ```
195
+
196
+ Bits:
197
+
198
+ ```python
199
+ hx.from_bits([1, 0, 1]).hex
200
+ # '05'
201
+
202
+ hx.from_hex("05").to(hx.Bits())
203
+ # [0, 0, 0, 0, 0, 1, 0, 1]
204
+ ```
205
+
206
+ Automatic inference with explanations:
207
+
208
+ ```python
209
+ result = hx.infer("0xdead")
210
+ result.format, result.confidence, result.value.hex
211
+ # (<class 'hexconv._core.HexString'>, 0.75, 'dead')
212
+ ```
213
+
214
+ ## Supported source helpers
215
+
216
+ - `from_bytes(value)`
217
+ - `from_bytes_array(values)`
218
+ - `from_bytes_string(value)` for strings like `"b'\\xde\\xad'"`
219
+ - `from_hex(value)`
220
+ - `from_hex_array(values)`
221
+ - `from_hex_int(value)`
222
+ - `from_int(value)`
223
+ - `from_int_array(values, width=...)`
224
+ - `from_text(value)`
225
+ - `from_binary(value)`
226
+ - `from_base64(value)`
227
+ - `from_base32(value)`
228
+ - `from_base85(value)`
229
+ - `from_ascii85(value)`
230
+ - `from_escaped(value)`
231
+ - `from_hexdump(value)`
232
+ - `from_struct(value, fmt=...)`
233
+ - `from_bits(value)`
234
+ - `from_auto(value)`
235
+ - `infer(value)`
236
+
237
+ ## Common output methods
238
+
239
+ - `to_bytes()`
240
+ - `to_bytearray()`
241
+ - `to_bytes_array()`
242
+ - `to_bytes_string()`
243
+ - `to_hex(sep="", prefix=False, uppercase=False)`
244
+ - `to_hex_array(width=1, prefix=False, uppercase=False)`
245
+ - `to_hex_numbers(width=1)`
246
+ - `to_int(endian="big", signed=False)`
247
+ - `to_int_array(width=1, endian="big", signed=False)`
248
+ - `to_text(encoding="ascii", errors="strict")`
249
+ - `to_binary(sep="")`
250
+ - `to_base64()`
251
+ - `to_base32()`
252
+ - `to_base85()`
253
+ - `to_ascii85()`
254
+ - `to_escaped()`
255
+ - `to_hexdump()`
256
+ - `to_struct(fmt)`
257
+ - `to_bits()`
258
+ - `to(format_marker, **options)`
@@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "hexconv"
7
- version = "0.1.0"
8
- description = "Pythonic CTF-friendly conversions between bytes, hex, integers, arrays, and text."
7
+ version = "0.2.0"
8
+ description = "Pythonic conversion toolkit for bytes, hex, integers, arrays, binary strings, base64, and text."
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.10"
11
11
  license = "MIT"
12
12
  license-files = ["LICENSE"]
13
13
  authors = [{ name = "hexconv contributors" }]
14
- keywords = ["ctf", "hex", "bytes", "conversion", "pwn", "crypto"]
14
+ keywords = ["hex", "bytes", "binary", "base64", "conversion", "encoding", "toolkit"]
15
15
  classifiers = [
16
16
  "Development Status :: 3 - Alpha",
17
17
  "Intended Audience :: Developers",
@@ -23,8 +23,8 @@ classifiers = [
23
23
  "Programming Language :: Python :: 3.12",
24
24
  "Programming Language :: Python :: 3.13",
25
25
  "Programming Language :: Python :: 3.14",
26
- "Topic :: Security",
27
26
  "Topic :: Software Development :: Libraries :: Python Modules",
27
+ "Topic :: Utilities",
28
28
  "Typing :: Typed",
29
29
  ]
30
30
 
@@ -1,76 +1,141 @@
1
- """CTF-friendly conversions between bytes, hex, integers, arrays, and text."""
1
+ """Conversion toolkit for bytes, hex, integers, arrays, binary, base64, and text."""
2
2
 
3
3
  from ._core import (
4
4
  ASCIIText,
5
5
  Auto,
6
+ AutoResult,
7
+ Ascii85,
8
+ Ascii85String,
6
9
  Base64String,
10
+ Base64,
11
+ Base32,
12
+ Base32String,
13
+ Base85,
14
+ Base85String,
7
15
  BinaryString,
16
+ Binary,
17
+ BitArray,
18
+ Bits,
8
19
  Bytes,
9
20
  BytesArray,
10
21
  BytesString,
22
+ Chunk,
11
23
  Converter,
12
24
  DecimalInt,
13
25
  DecimalIntArray,
26
+ Escaped,
27
+ EscapedString,
28
+ Group,
29
+ Hex,
14
30
  HexArray,
15
31
  HexConvError,
32
+ HexDump,
33
+ Hexdump,
16
34
  HexInt,
17
35
  HexNumbersArray,
18
36
  HexString,
19
37
  Int,
20
38
  IntArray,
21
39
  LargeHexNumber,
40
+ Pad,
41
+ Pipeline,
22
42
  RawString,
43
+ Reverse,
44
+ Struct,
45
+ StructFormat,
23
46
  Text,
47
+ Transform,
24
48
  Value,
25
49
  convert,
50
+ from_ascii85,
26
51
  from_auto,
52
+ from_base32,
27
53
  from_base64,
54
+ from_base85,
28
55
  from_binary,
56
+ from_bits,
29
57
  from_bytes,
30
58
  from_bytes_array,
31
59
  from_bytes_string,
60
+ from_escaped,
32
61
  from_hex,
33
62
  from_hex_array,
34
63
  from_hex_int,
64
+ from_hexdump,
35
65
  from_int,
36
66
  from_int_array,
67
+ from_struct,
37
68
  from_text,
69
+ infer,
70
+ pipeline,
38
71
  )
39
72
 
40
73
  __all__ = [
41
74
  "ASCIIText",
42
75
  "Auto",
76
+ "AutoResult",
77
+ "Ascii85",
78
+ "Ascii85String",
79
+ "Base32",
80
+ "Base32String",
43
81
  "Base64String",
82
+ "Base64",
83
+ "Base85",
84
+ "Base85String",
85
+ "Binary",
44
86
  "BinaryString",
87
+ "BitArray",
88
+ "Bits",
45
89
  "Bytes",
46
90
  "BytesArray",
47
91
  "BytesString",
92
+ "Chunk",
48
93
  "Converter",
49
94
  "DecimalInt",
50
95
  "DecimalIntArray",
96
+ "Escaped",
97
+ "EscapedString",
98
+ "Group",
99
+ "Hex",
51
100
  "HexArray",
52
101
  "HexConvError",
102
+ "HexDump",
103
+ "Hexdump",
53
104
  "HexInt",
54
105
  "HexNumbersArray",
55
106
  "HexString",
56
107
  "Int",
57
108
  "IntArray",
58
109
  "LargeHexNumber",
110
+ "Pad",
111
+ "Pipeline",
59
112
  "RawString",
113
+ "Reverse",
114
+ "Struct",
115
+ "StructFormat",
60
116
  "Text",
117
+ "Transform",
61
118
  "Value",
62
119
  "convert",
120
+ "from_ascii85",
63
121
  "from_auto",
122
+ "from_base32",
64
123
  "from_base64",
124
+ "from_base85",
65
125
  "from_binary",
126
+ "from_bits",
66
127
  "from_bytes",
67
128
  "from_bytes_array",
68
129
  "from_bytes_string",
130
+ "from_escaped",
69
131
  "from_hex",
70
132
  "from_hex_array",
71
133
  "from_hex_int",
134
+ "from_hexdump",
72
135
  "from_int",
73
136
  "from_int_array",
137
+ "from_struct",
74
138
  "from_text",
139
+ "infer",
140
+ "pipeline",
75
141
  ]
76
-