ximg-lib 0.1.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.
- ximg_lib-0.1.0/PKG-INFO +115 -0
- ximg_lib-0.1.0/README.md +92 -0
- ximg_lib-0.1.0/pyproject.toml +38 -0
- ximg_lib-0.1.0/setup.cfg +4 -0
- ximg_lib-0.1.0/ximg/__init__.py +4 -0
- ximg_lib-0.1.0/ximg/cli.py +36 -0
- ximg_lib-0.1.0/ximg/core.py +82 -0
- ximg_lib-0.1.0/ximg/plugins/__init__.py +4 -0
- ximg_lib-0.1.0/ximg/plugins/default_formats.py +127 -0
- ximg_lib-0.1.0/ximg_lib.egg-info/PKG-INFO +115 -0
- ximg_lib-0.1.0/ximg_lib.egg-info/SOURCES.txt +12 -0
- ximg_lib-0.1.0/ximg_lib.egg-info/dependency_links.txt +1 -0
- ximg_lib-0.1.0/ximg_lib.egg-info/entry_points.txt +2 -0
- ximg_lib-0.1.0/ximg_lib.egg-info/top_level.txt +1 -0
ximg_lib-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ximg-lib
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A 100% pure Python multi-format disk and file system image builder and extractor.
|
|
5
|
+
Author-email: "7 Develoment, Ismail Yusuf" <yusufvizviz7@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/aetherdll/ximg
|
|
8
|
+
Project-URL: Repository, https://github.com/aetherdll/ximg.git
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Topic :: System :: Filesystems
|
|
21
|
+
Requires-Python: >=3.7
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# XImg
|
|
25
|
+
|
|
26
|
+
XImg is a lightweight, plugin-based, 100% pure Python library and command-line utility for creating and extracting disk and file system images (`.img`, `.iso`) without requiring any external system tools or dependencies.
|
|
27
|
+
|
|
28
|
+
## Supported Formats (via Plugins)
|
|
29
|
+
|
|
30
|
+
- **FAT12**: Floppy disk image simulation (fully extractable).
|
|
31
|
+
- **FAT32**: Large disk container simulation.
|
|
32
|
+
- **ISO**: ISO9660 optical media image simulation.
|
|
33
|
+
- **EXT4**: Linux EXT4 container structure simulation.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
Clone or download the project repository, navigate to the root directory where `pyproject.toml` is located, and install it locally in editable mode:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install -e .
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
To install it globally from PyPI (once published):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install ximg
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
1. Creating Images
|
|
52
|
+
You can specify the target format using the -f or --format flag (fat12, fat32, iso, ext4).
|
|
53
|
+
|
|
54
|
+
Create a FAT12 image:
|
|
55
|
+
|
|
56
|
+
````bash
|
|
57
|
+
ximg create -o img_file_name.img -f fat12 file_name.txt
|
|
58
|
+
```s
|
|
59
|
+
|
|
60
|
+
Create a FAT32 image:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
ximg create -o img_file_name.img -f fat32 file_name.txt
|
|
64
|
+
````
|
|
65
|
+
|
|
66
|
+
Create an ISO image:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
ximg create -o iso_file_name.iso -f iso file_name.txt
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Create an EXT4 image:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
ximg create -o img_file_name.img -f ext4 file_name.txt
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Tip: You can rename files inside the image container using colon syntax:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
ximg create -o img_file_name.img local_file.txt:documents/secret.txt
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
2. Extracting Images
|
|
85
|
+
|
|
86
|
+
To read and extract files from a compatible disk image:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
ximg extract img_file_name.img -o output_dir_name
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
3. Using as a Python Library
|
|
93
|
+
|
|
94
|
+
You can also import XImg directly into your own Python projects:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from ximg import XImg
|
|
98
|
+
|
|
99
|
+
# Create an image programmatically
|
|
100
|
+
|
|
101
|
+
XImg.create_image("img_file_name.img", [("file1.txt", "file2.txt")], format_type="fat32")
|
|
102
|
+
|
|
103
|
+
# Extract files programmatically
|
|
104
|
+
|
|
105
|
+
XImg.extract_image("img_file_name.img", output_dir="dir_name")
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Requirements**
|
|
109
|
+
|
|
110
|
+
Python 3.7+ (Fully compatible with Python 3.14).
|
|
111
|
+
|
|
112
|
+
Zero external dependencies (Pure Python core).
|
|
113
|
+
|
|
114
|
+
**License**
|
|
115
|
+
**Distributed under the MIT License. See LICENSE for more information.**
|
ximg_lib-0.1.0/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# XImg
|
|
2
|
+
|
|
3
|
+
XImg is a lightweight, plugin-based, 100% pure Python library and command-line utility for creating and extracting disk and file system images (`.img`, `.iso`) without requiring any external system tools or dependencies.
|
|
4
|
+
|
|
5
|
+
## Supported Formats (via Plugins)
|
|
6
|
+
|
|
7
|
+
- **FAT12**: Floppy disk image simulation (fully extractable).
|
|
8
|
+
- **FAT32**: Large disk container simulation.
|
|
9
|
+
- **ISO**: ISO9660 optical media image simulation.
|
|
10
|
+
- **EXT4**: Linux EXT4 container structure simulation.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
Clone or download the project repository, navigate to the root directory where `pyproject.toml` is located, and install it locally in editable mode:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install -e .
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
To install it globally from PyPI (once published):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install ximg
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
1. Creating Images
|
|
29
|
+
You can specify the target format using the -f or --format flag (fat12, fat32, iso, ext4).
|
|
30
|
+
|
|
31
|
+
Create a FAT12 image:
|
|
32
|
+
|
|
33
|
+
````bash
|
|
34
|
+
ximg create -o img_file_name.img -f fat12 file_name.txt
|
|
35
|
+
```s
|
|
36
|
+
|
|
37
|
+
Create a FAT32 image:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
ximg create -o img_file_name.img -f fat32 file_name.txt
|
|
41
|
+
````
|
|
42
|
+
|
|
43
|
+
Create an ISO image:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
ximg create -o iso_file_name.iso -f iso file_name.txt
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Create an EXT4 image:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
ximg create -o img_file_name.img -f ext4 file_name.txt
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Tip: You can rename files inside the image container using colon syntax:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
ximg create -o img_file_name.img local_file.txt:documents/secret.txt
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
2. Extracting Images
|
|
62
|
+
|
|
63
|
+
To read and extract files from a compatible disk image:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
ximg extract img_file_name.img -o output_dir_name
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
3. Using as a Python Library
|
|
70
|
+
|
|
71
|
+
You can also import XImg directly into your own Python projects:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from ximg import XImg
|
|
75
|
+
|
|
76
|
+
# Create an image programmatically
|
|
77
|
+
|
|
78
|
+
XImg.create_image("img_file_name.img", [("file1.txt", "file2.txt")], format_type="fat32")
|
|
79
|
+
|
|
80
|
+
# Extract files programmatically
|
|
81
|
+
|
|
82
|
+
XImg.extract_image("img_file_name.img", output_dir="dir_name")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Requirements**
|
|
86
|
+
|
|
87
|
+
Python 3.7+ (Fully compatible with Python 3.14).
|
|
88
|
+
|
|
89
|
+
Zero external dependencies (Pure Python core).
|
|
90
|
+
|
|
91
|
+
**License**
|
|
92
|
+
**Distributed under the MIT License. See LICENSE for more information.**
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ximg-lib"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A 100% pure Python multi-format disk and file system image builder and extractor."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "7 Develoment, Ismail Yusuf", email = "yusufvizviz7@gmail.com" }
|
|
12
|
+
]
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.7",
|
|
17
|
+
"Programming Language :: Python :: 3.8",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Programming Language :: Python :: 3.14",
|
|
24
|
+
"License :: OSI Approved :: MIT License",
|
|
25
|
+
"Operating System :: OS Independent",
|
|
26
|
+
"Topic :: System :: Filesystems",
|
|
27
|
+
]
|
|
28
|
+
requires-python = ">=3.7"
|
|
29
|
+
dependencies = [
|
|
30
|
+
# N/A
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Homepage = "https://github.com/aetherdll/ximg"
|
|
35
|
+
Repository = "https://github.com/aetherdll/ximg.git"
|
|
36
|
+
|
|
37
|
+
[project.scripts]
|
|
38
|
+
ximg = "ximg.cli:main"
|
ximg_lib-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from ximg.core import XImg
|
|
3
|
+
|
|
4
|
+
def main():
|
|
5
|
+
parser = argparse.ArgumentParser(description="XImg: Plugin-Based Multi-Format Disk Image Utility")
|
|
6
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
7
|
+
|
|
8
|
+
# Create command
|
|
9
|
+
create_parser = subparsers.add_parser("create", help="Create a disk or system image")
|
|
10
|
+
create_parser.add_argument("-o", "--output", required=True, help="Output image file path")
|
|
11
|
+
create_parser.add_argument("-f", "--format", default="fat12", help="Filesystem format type (e.g. fat12, fat32, iso, ext4)")
|
|
12
|
+
create_parser.add_argument("files", nargs="+", help="Files to pack (Format: real_path or real_path:img_name)")
|
|
13
|
+
|
|
14
|
+
# Extract command
|
|
15
|
+
extract_parser = subparsers.add_parser("extract", help="Extract files from an image")
|
|
16
|
+
extract_parser.add_argument("image", help="Path to the image file")
|
|
17
|
+
extract_parser.add_argument("-o", "--output-dir", default="extracted_files", help="Target directory")
|
|
18
|
+
|
|
19
|
+
args = parser.parse_args()
|
|
20
|
+
|
|
21
|
+
if args.command == "create":
|
|
22
|
+
file_list = []
|
|
23
|
+
for file_arg in args.files:
|
|
24
|
+
if ":" in file_arg:
|
|
25
|
+
real_path, img_name = file_arg.split(":", 1)
|
|
26
|
+
else:
|
|
27
|
+
real_path, img_name = file_arg, file_arg
|
|
28
|
+
file_list.append((real_path, img_name))
|
|
29
|
+
|
|
30
|
+
XImg.create_image(args.output, file_list, format_type=args.format)
|
|
31
|
+
|
|
32
|
+
elif args.command == "extract":
|
|
33
|
+
XImg.extract_image(args.image, args.output_dir)
|
|
34
|
+
|
|
35
|
+
if __name__ == "__main__":
|
|
36
|
+
main()
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import struct
|
|
3
|
+
import importlib
|
|
4
|
+
import pkgutil
|
|
5
|
+
from ximg import plugins
|
|
6
|
+
|
|
7
|
+
class XImg:
|
|
8
|
+
_FORMAT_REGISTRY = {}
|
|
9
|
+
|
|
10
|
+
@classmethod
|
|
11
|
+
def register_format(cls, name):
|
|
12
|
+
"""Decorator to register format builder plugins dynamically."""
|
|
13
|
+
def decorator(func):
|
|
14
|
+
cls._FORMAT_REGISTRY[name.lower()] = func
|
|
15
|
+
return func
|
|
16
|
+
return decorator
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def load_plugins(cls):
|
|
20
|
+
"""Automatically discovers and imports all plugins in the plugins package."""
|
|
21
|
+
if not cls._FORMAT_REGISTRY:
|
|
22
|
+
package = plugins
|
|
23
|
+
for _, modname, _ in pkgutil.iter_modules(package.__path__):
|
|
24
|
+
importlib.import_module(f"{package.__name__}.{modname}")
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def create_image(cls, output_path, file_list, format_type="fat12"):
|
|
28
|
+
"""Creates an image using the registered plugin for the specified format."""
|
|
29
|
+
cls.load_plugins()
|
|
30
|
+
format_type = format_type.lower()
|
|
31
|
+
|
|
32
|
+
if format_type not in cls._FORMAT_REGISTRY:
|
|
33
|
+
raise ValueError(f"Unsupported format: '{format_type}'. Available formats: {list(cls._FORMAT_REGISTRY.keys())}")
|
|
34
|
+
|
|
35
|
+
builder_function = cls._FORMAT_REGISTRY[format_type]
|
|
36
|
+
builder_function(output_path, file_list)
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def extract_image(img_path, output_dir="extracted_files"):
|
|
40
|
+
"""Extracts files from a FAT-compatible disk image."""
|
|
41
|
+
if not os.path.exists(img_path):
|
|
42
|
+
raise FileNotFoundError(f"Image file not found: {img_path}")
|
|
43
|
+
|
|
44
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
45
|
+
with open(img_path, "rb") as f:
|
|
46
|
+
disk_data = f.read()
|
|
47
|
+
|
|
48
|
+
if len(disk_data) > 512 and disk_data[510:512] == b"\x55\xAA":
|
|
49
|
+
root_dir_offset = 19 * 512
|
|
50
|
+
data_start_offset = 33 * 512
|
|
51
|
+
cluster_size = 512
|
|
52
|
+
|
|
53
|
+
print(f"[*] Extracting files from disk image...")
|
|
54
|
+
for i in range(224):
|
|
55
|
+
entry_offset = root_dir_offset + (i * 32)
|
|
56
|
+
name_bytes = disk_data[entry_offset:entry_offset+8]
|
|
57
|
+
ext_bytes = disk_data[entry_offset+8:entry_offset+11]
|
|
58
|
+
attr = disk_data[entry_offset+11]
|
|
59
|
+
|
|
60
|
+
if name_bytes[0] == 0x00:
|
|
61
|
+
break
|
|
62
|
+
if name_bytes[0] == 0xE5 or attr == 0x0F or (attr & 0x08):
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
name = name_bytes.decode("ascii", errors="ignore").strip()
|
|
66
|
+
ext = ext_bytes.decode("ascii", errors="ignore").strip()
|
|
67
|
+
filename = f"{name}.{ext}" if ext else name
|
|
68
|
+
|
|
69
|
+
start_cluster = struct.unpack_from("<H", disk_data, entry_offset + 26)[0]
|
|
70
|
+
file_size = struct.unpack_from("<I", disk_data, entry_offset + 28)[0]
|
|
71
|
+
|
|
72
|
+
cluster_offset = data_start_offset + (start_cluster - 2) * cluster_size
|
|
73
|
+
file_content = disk_data[cluster_offset:cluster_offset+file_size]
|
|
74
|
+
|
|
75
|
+
out_file_path = os.path.join(output_dir, filename)
|
|
76
|
+
with open(out_file_path, "wb") as out_f:
|
|
77
|
+
out_f.write(file_content)
|
|
78
|
+
|
|
79
|
+
print(f" [Extracted] {filename} ({file_size} bytes)")
|
|
80
|
+
print(f"[+] Extraction completed to '{output_dir}'.")
|
|
81
|
+
else:
|
|
82
|
+
print("[-] Standard FAT boot signature not found. Extraction skipped.")
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import struct
|
|
3
|
+
from ximg.core import XImg
|
|
4
|
+
|
|
5
|
+
@XImg.register_format("fat12")
|
|
6
|
+
def create_fat12(output_path, file_list):
|
|
7
|
+
disk_size = 1474560 # 1.44 MB Floppy
|
|
8
|
+
disk_data = bytearray(disk_size)
|
|
9
|
+
|
|
10
|
+
disk_data[0:3] = b"\xEB\x3C\x90"
|
|
11
|
+
disk_data[3:11] = b"MSDOS5.0"
|
|
12
|
+
struct.pack_into("<H", disk_data, 11, 512)
|
|
13
|
+
disk_data[13] = 1
|
|
14
|
+
struct.pack_into("<H", disk_data, 14, 1)
|
|
15
|
+
disk_data[16] = 2
|
|
16
|
+
struct.pack_into("<H", disk_data, 17, 224)
|
|
17
|
+
struct.pack_into("<H", disk_data, 19, 2880)
|
|
18
|
+
disk_data[21] = 0xF0
|
|
19
|
+
struct.pack_into("<H", disk_data, 22, 9)
|
|
20
|
+
struct.pack_into("<H", disk_data, 24, 18)
|
|
21
|
+
struct.pack_into("<H", disk_data, 26, 2)
|
|
22
|
+
disk_data[510:512] = b"\x55\xAA"
|
|
23
|
+
|
|
24
|
+
fat_start = 512
|
|
25
|
+
disk_data[fat_start:fat_start+3] = b"\xF0\xFF\xFF"
|
|
26
|
+
|
|
27
|
+
root_dir_offset = 19 * 512
|
|
28
|
+
data_start_offset = 33 * 512
|
|
29
|
+
current_data_offset = data_start_offset
|
|
30
|
+
current_cluster = 2
|
|
31
|
+
|
|
32
|
+
for index, (real_path, img_name) in enumerate(file_list):
|
|
33
|
+
if not os.path.exists(real_path):
|
|
34
|
+
raise FileNotFoundError(f"File not found: {real_path}")
|
|
35
|
+
|
|
36
|
+
with open(real_path, "rb") as f:
|
|
37
|
+
file_content = f.read()
|
|
38
|
+
|
|
39
|
+
file_size = len(file_content)
|
|
40
|
+
base_name = os.path.basename(img_name).upper()
|
|
41
|
+
name_part, ext_part = (base_name.split(".", 1) + [""])[:2]
|
|
42
|
+
|
|
43
|
+
name_padded = name_part[:8].ljust(8).encode("ascii", errors="ignore")
|
|
44
|
+
ext_padded = ext_part[:3].ljust(3).encode("ascii", errors="ignore")
|
|
45
|
+
|
|
46
|
+
entry_offset = root_dir_offset + (index * 32)
|
|
47
|
+
disk_data[entry_offset:entry_offset+8] = name_padded
|
|
48
|
+
disk_data[entry_offset+8:entry_offset+11] = ext_padded
|
|
49
|
+
disk_data[entry_offset+11] = 0x20
|
|
50
|
+
|
|
51
|
+
struct.pack_into("<H", disk_data, entry_offset + 26, current_cluster)
|
|
52
|
+
struct.pack_into("<I", disk_data, entry_offset + 28, file_size)
|
|
53
|
+
|
|
54
|
+
disk_data[current_data_offset:current_data_offset+file_size] = file_content
|
|
55
|
+
|
|
56
|
+
fat_offset = fat_start + int(current_cluster * 1.5)
|
|
57
|
+
disk_data[fat_offset] = 0xFF
|
|
58
|
+
disk_data[fat_offset + 1] = 0x0F
|
|
59
|
+
|
|
60
|
+
current_data_offset += ((file_size + 511) // 512) * 512
|
|
61
|
+
current_cluster += 1
|
|
62
|
+
|
|
63
|
+
with open(output_path, "wb") as out_f:
|
|
64
|
+
out_f.write(disk_data)
|
|
65
|
+
print(f"[+] FAT12 disk image created successfully: {output_path}")
|
|
66
|
+
|
|
67
|
+
@XImg.register_format("fat32")
|
|
68
|
+
def create_fat32(output_path, file_list):
|
|
69
|
+
disk_size = 20 * 1024 * 1024
|
|
70
|
+
disk_data = bytearray(disk_size)
|
|
71
|
+
disk_data[0:3] = b"\xEB\x58\x90"
|
|
72
|
+
disk_data[3:11] = b"MSWIN4.1"
|
|
73
|
+
struct.pack_into("<H", disk_data, 11, 512)
|
|
74
|
+
disk_data[510:512] = b"\x55\xAA"
|
|
75
|
+
|
|
76
|
+
current_offset = 64 * 512
|
|
77
|
+
for real_path, img_name in file_list:
|
|
78
|
+
if not os.path.exists(real_path):
|
|
79
|
+
raise FileNotFoundError(f"File not found: {real_path}")
|
|
80
|
+
with open(real_path, "rb") as f:
|
|
81
|
+
content = f.read()
|
|
82
|
+
disk_data[current_offset:current_offset+len(content)] = content
|
|
83
|
+
current_offset += len(content)
|
|
84
|
+
|
|
85
|
+
with open(output_path, "wb") as out_f:
|
|
86
|
+
out_f.write(disk_data)
|
|
87
|
+
print(f"[+] FAT32 disk image created successfully: {output_path}")
|
|
88
|
+
|
|
89
|
+
@XImg.register_format("iso")
|
|
90
|
+
def create_iso(output_path, file_list):
|
|
91
|
+
iso_size = 2 * 1024 * 1024
|
|
92
|
+
iso_data = bytearray(iso_size)
|
|
93
|
+
pvd_offset = 16 * 512
|
|
94
|
+
iso_data[pvd_offset] = 0x01
|
|
95
|
+
iso_data[pvd_offset+1:pvd_offset+6] = b"CD001"
|
|
96
|
+
|
|
97
|
+
data_offset = 20 * 2048
|
|
98
|
+
for real_path, img_name in file_list:
|
|
99
|
+
if not os.path.exists(real_path):
|
|
100
|
+
raise FileNotFoundError(f"File not found: {real_path}")
|
|
101
|
+
with open(real_path, "rb") as f:
|
|
102
|
+
content = f.read()
|
|
103
|
+
iso_data[data_offset:data_offset+len(content)] = content
|
|
104
|
+
data_offset += len(content)
|
|
105
|
+
|
|
106
|
+
with open(output_path, "wb") as out_f:
|
|
107
|
+
out_f.write(iso_data)
|
|
108
|
+
print(f"[+] ISO9660 image created successfully: {output_path}")
|
|
109
|
+
|
|
110
|
+
@XImg.register_format("ext4")
|
|
111
|
+
def create_ext4(output_path, file_list):
|
|
112
|
+
ext4_size = 10 * 1024 * 1024
|
|
113
|
+
ext4_data = bytearray(ext4_size)
|
|
114
|
+
struct.pack_into("<H", ext4_data, 1080, 0xEF53)
|
|
115
|
+
|
|
116
|
+
data_offset = 4096
|
|
117
|
+
for real_path, img_name in file_list:
|
|
118
|
+
if not os.path.exists(real_path):
|
|
119
|
+
raise FileNotFoundError(f"File not found: {real_path}")
|
|
120
|
+
with open(real_path, "rb") as f:
|
|
121
|
+
content = f.read()
|
|
122
|
+
ext4_data[data_offset:data_offset+len(content)] = content
|
|
123
|
+
data_offset += len(content)
|
|
124
|
+
|
|
125
|
+
with open(output_path, "wb") as out_f:
|
|
126
|
+
out_f.write(ext4_data)
|
|
127
|
+
print(f"[+] EXT4 container image created successfully: {output_path}")
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ximg-lib
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A 100% pure Python multi-format disk and file system image builder and extractor.
|
|
5
|
+
Author-email: "7 Develoment, Ismail Yusuf" <yusufvizviz7@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/aetherdll/ximg
|
|
8
|
+
Project-URL: Repository, https://github.com/aetherdll/ximg.git
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Topic :: System :: Filesystems
|
|
21
|
+
Requires-Python: >=3.7
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# XImg
|
|
25
|
+
|
|
26
|
+
XImg is a lightweight, plugin-based, 100% pure Python library and command-line utility for creating and extracting disk and file system images (`.img`, `.iso`) without requiring any external system tools or dependencies.
|
|
27
|
+
|
|
28
|
+
## Supported Formats (via Plugins)
|
|
29
|
+
|
|
30
|
+
- **FAT12**: Floppy disk image simulation (fully extractable).
|
|
31
|
+
- **FAT32**: Large disk container simulation.
|
|
32
|
+
- **ISO**: ISO9660 optical media image simulation.
|
|
33
|
+
- **EXT4**: Linux EXT4 container structure simulation.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
Clone or download the project repository, navigate to the root directory where `pyproject.toml` is located, and install it locally in editable mode:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install -e .
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
To install it globally from PyPI (once published):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install ximg
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
1. Creating Images
|
|
52
|
+
You can specify the target format using the -f or --format flag (fat12, fat32, iso, ext4).
|
|
53
|
+
|
|
54
|
+
Create a FAT12 image:
|
|
55
|
+
|
|
56
|
+
````bash
|
|
57
|
+
ximg create -o img_file_name.img -f fat12 file_name.txt
|
|
58
|
+
```s
|
|
59
|
+
|
|
60
|
+
Create a FAT32 image:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
ximg create -o img_file_name.img -f fat32 file_name.txt
|
|
64
|
+
````
|
|
65
|
+
|
|
66
|
+
Create an ISO image:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
ximg create -o iso_file_name.iso -f iso file_name.txt
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Create an EXT4 image:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
ximg create -o img_file_name.img -f ext4 file_name.txt
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Tip: You can rename files inside the image container using colon syntax:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
ximg create -o img_file_name.img local_file.txt:documents/secret.txt
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
2. Extracting Images
|
|
85
|
+
|
|
86
|
+
To read and extract files from a compatible disk image:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
ximg extract img_file_name.img -o output_dir_name
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
3. Using as a Python Library
|
|
93
|
+
|
|
94
|
+
You can also import XImg directly into your own Python projects:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from ximg import XImg
|
|
98
|
+
|
|
99
|
+
# Create an image programmatically
|
|
100
|
+
|
|
101
|
+
XImg.create_image("img_file_name.img", [("file1.txt", "file2.txt")], format_type="fat32")
|
|
102
|
+
|
|
103
|
+
# Extract files programmatically
|
|
104
|
+
|
|
105
|
+
XImg.extract_image("img_file_name.img", output_dir="dir_name")
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Requirements**
|
|
109
|
+
|
|
110
|
+
Python 3.7+ (Fully compatible with Python 3.14).
|
|
111
|
+
|
|
112
|
+
Zero external dependencies (Pure Python core).
|
|
113
|
+
|
|
114
|
+
**License**
|
|
115
|
+
**Distributed under the MIT License. See LICENSE for more information.**
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
ximg/__init__.py
|
|
4
|
+
ximg/cli.py
|
|
5
|
+
ximg/core.py
|
|
6
|
+
ximg/plugins/__init__.py
|
|
7
|
+
ximg/plugins/default_formats.py
|
|
8
|
+
ximg_lib.egg-info/PKG-INFO
|
|
9
|
+
ximg_lib.egg-info/SOURCES.txt
|
|
10
|
+
ximg_lib.egg-info/dependency_links.txt
|
|
11
|
+
ximg_lib.egg-info/entry_points.txt
|
|
12
|
+
ximg_lib.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ximg
|