Add files via upload
[PyCatFile.git] / catfile.py
blob7dbcde4cf476680d5f7781a78a8200d6d21c2316
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
4 '''
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the Revised BSD License.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 Revised BSD License for more details.
13 Copyright 2018-2024 Cool Dude 2k - http://idb.berlios.de/
14 Copyright 2018-2024 Game Maker 2k - http://intdb.sourceforge.net/
15 Copyright 2018-2024 Kazuki Przyborowski - https://github.com/KazukiPrzyborowski
17 $FileInfo: catfile.py - Last Update: 5/12/2024 Ver. 0.11.0 RC 1 - Author: cooldude2k $
18 '''
20 from __future__ import absolute_import, division, print_function, unicode_literals;
21 import os, sys, argparse, pycatfile, binascii;
23 # Conditional import and signal handling for Unix-like systems
24 if os.name != 'nt': # Not Windows
25 import signal;
26 def handler(signum, frame):
27 pycatfile.VerbosePrintOut("Received SIGPIPE, exiting gracefully.","info");
28 sys.exit(0);
29 signal.signal(signal.SIGPIPE, handler);
31 rarfile_support = pycatfile.rarfile_support;
32 py7zr_support = pycatfile.py7zr_support;
34 if(sys.version[0]=="2"):
35 try:
36 from io import StringIO, BytesIO;
37 except ImportError:
38 try:
39 from cStringIO import StringIO;
40 from cStringIO import StringIO as BytesIO;
41 except ImportError:
42 from StringIO import StringIO;
43 from StringIO import StringIO as BytesIO;
44 elif(sys.version[0]>="3"):
45 from io import StringIO, BytesIO;
46 else:
47 teststringio = 0;
48 if(teststringio<=0):
49 try:
50 from cStringIO import StringIO as BytesIO;
51 teststringio = 1;
52 except ImportError:
53 teststringio = 0;
54 if(teststringio<=0):
55 try:
56 from StringIO import StringIO as BytesIO;
57 teststringio = 2;
58 except ImportError:
59 teststringio = 0;
60 if(teststringio<=0):
61 try:
62 from io import BytesIO;
63 teststringio = 3;
64 except ImportError:
65 teststringio = 0;
67 __project__ = pycatfile.__project__;
68 __program_name__ = pycatfile.__program_name__;
69 __file_format_name__ = pycatfile.__file_format_name__;
70 __file_format_lower__ = pycatfile.__file_format_lower__;
71 __file_format_magic__ = pycatfile.__file_format_magic__;
72 __file_format_len__ = pycatfile.__file_format_len__;
73 __file_format_hex__ = pycatfile.__file_format_hex__;
74 __file_format_delimiter__ = pycatfile.__file_format_delimiter__;
75 __file_format_list__ = pycatfile.__file_format_list__;
76 __use_new_style__ = pycatfile.__use_new_style__;
77 __use_advanced_list__ = pycatfile.__use_advanced_list__;
78 __use_alt_inode__ = pycatfile.__use_alt_inode__;
79 __project_url__ = pycatfile.__project_url__;
80 __version_info__ = pycatfile.__version_info__;
81 __version_date_info__ = pycatfile.__version_date_info__;
82 __version_date__ = pycatfile.__version_date__;
83 __version_date_plusrc__ = pycatfile.__version_date_plusrc__;
84 __version__ = pycatfile.__version__;
86 # Initialize the argument parser
87 argparser = argparse.ArgumentParser(description="Manipulate concatenated files.", conflict_handler="resolve", add_help=True);
89 # Version information
90 argparser.add_argument("-V", "--version", action="version", version=__program_name__ + " " + __version__);
91 # Input and output specifications
92 argparser.add_argument("-i", "--input", help="Specify the file(s) to concatenate or the concatenated file to extract.", required=True);
93 argparser.add_argument("-o", "--output", default=None, help="Specify the name for the extracted or output concatenated files.");
94 # Operations
95 argparser.add_argument("-c", "--create", action="store_true", help="Perform only the concatenation operation.");
96 argparser.add_argument("-e", "--extract", action="store_true", help="Perform only the extraction operation.");
97 argparser.add_argument("-t", "--convert", action="store_true", help="Convert a tar/zip/rar/7zip file to a concatenated file.");
98 argparser.add_argument("-r", "--repack", action="store_true", help="Re-concatenate files, fixing checksum errors if any.");
99 # File manipulation options
100 argparser.add_argument("-F", "--format", default=__file_format_list__[0], help="Specify the format to use.");
101 argparser.add_argument("-D", "--delimiter", default=__file_format_list__[5], help="Specify the delimiter to use.");
102 argparser.add_argument("-m", "--formatver", default=__file_format_list__[6], help="Specify the format version.");
103 argparser.add_argument("-l", "--list", action="store_true", help="List files included in the concatenated file.");
104 # Compression options
105 argparser.add_argument("-P", "--compression", default="auto", help="Specify the compression method to use for concatenation.");
106 argparser.add_argument("-L", "--level", default=None, help="Specify the compression level for concatenation.");
107 argparser.add_argument("-W", "--wholefile", action="store_true", help="Whole file compression method to use for concatenation.");
108 # Checksum and validation
109 argparser.add_argument("-v", "--validate", action="store_true", help="Validate concatenated file checksums.");
110 argparser.add_argument("-C", "--checksum", default="crc32", help="Specify the type of checksum to use. The default is crc32.");
111 argparser.add_argument("-s", "--skipchecksum", action="store_true", help="Skip the checksum check of files.");
112 # Permissions and metadata
113 argparser.add_argument("-p", "--preserve", action="store_false", help="Do not preserve permissions and timestamps of files.");
114 # Miscellaneous
115 argparser.add_argument("-d", "--verbose", action="store_true", help="Enable verbose mode to display various debugging information.");
116 argparser.add_argument("-T", "--text", action="store_true", help="Read file locations from a text file.");
117 # Parse the arguments
118 getargs = argparser.parse_args();
120 fname = getargs.format;
121 fnamelower = fname.lower();
122 fnamemagic = fname;
123 fnamelen = len(fname);
124 fnamehex = binascii.hexlify(fname.encode("UTF-8")).decode("UTF-8");
125 fnamesty = __use_new_style__;
126 fnamelst = __use_advanced_list__;
127 fnameino = __use_alt_inode__;
128 fnamelist = [fname, fnamemagic, fnamelower, fnamelen, fnamehex, getargs.delimiter, getargs.formatver, fnamesty, fnamelst, fnameino];
129 fnamedict = {'format_name': fname, 'format_magic': fnamemagic, 'format_lower': fnamelower, 'format_len': fnamelen, 'format_hex': fnamehex, 'format_delimiter': getargs.delimiter, 'format_ver': getargs.formatver, 'new_style': fnamesty, 'use_advanced_list': fnamelst, 'use_alt_inode': fnameino};
131 # Determine the primary action based on user input
132 actions = ['create', 'extract', 'list', 'repack', 'validate'];
133 active_action = next((action for action in actions if getattr(getargs, action)), None);
135 # Execute the appropriate functions based on determined actions and arguments
136 if active_action:
137 if active_action=='create':
138 if getargs.convert:
139 checkcompressfile = pycatfile.CheckCompressionSubType(getargs.input, fnamedict, True);
140 if(checkcompressfile=="catfile"):
141 tmpout = pycatfile.RePackArchiveFile(getargs.input, getargs.output, getargs.compression, getargs.wholefile, getargs.level, False, 0, 0, getargs.checksum, getargs.skipchecksum, [], fnamedict, getargs.verbose, False);
142 else:
143 tmpout = pycatfile.PackArchiveFileFromInFile(getargs.input, getargs.output, getargs.compression, getargs.wholefile, getargs.level, getargs.checksum, [], fnamedict, getargs.verbose, False);
144 if(not tmpout):
145 sys.exit(1);
146 else:
147 pycatfile.PackArchiveFile(getargs.input, getargs.output, getargs.text, getargs.compression, getargs.wholefile, getargs.level, False, getargs.checksum, [], fnamedict, getargs.verbose, False);
148 elif active_action=='repack':
149 if getargs.convert:
150 checkcompressfile = pycatfile.CheckCompressionSubType(getargs.input, fnamedict, True);
151 if(checkcompressfile=="catfile"):
152 pycatfile.RePackArchiveFile(getargs.input, getargs.output, getargs.compression, getargs.wholefile, getargs.level, False, 0, 0, getargs.checksum, getargs.skipchecksum, [], fnamedict, getargs.verbose, False);
153 else:
154 pycatfile.PackArchiveFileFromInFile(getargs.input, getargs.output, getargs.compression, getargs.wholefile, getargs.level, getargs.checksum, [], fnamedict, getargs.verbose, False);
155 if(not tmpout):
156 sys.exit(1);
157 else:
158 pycatfile.RePackArchiveFile(getargs.input, getargs.output, getargs.compression, getargs.wholefile, getargs.level, False, 0, 0, getargs.checksum, getargs.skipchecksum, [], fnamedict, getargs.verbose, False);
159 elif active_action=='extract':
160 if getargs.convert:
161 checkcompressfile = pycatfile.CheckCompressionSubType(getargs.input, fnamedict, True);
162 tempout = BytesIO();
163 if(checkcompressfile=="catfile"):
164 tmpout = pycatfile.RePackArchiveFile(getargs.input, tempout, getargs.compression, getargs.wholefile, getargs.level, False, 0, 0, getargs.checksum, getargs.skipchecksum, [], fnamedict, getargs.verbose, False);
165 else:
166 tmpout = pycatfile.PackArchiveFileFromInFile(getargs.input, tempout, getargs.compression, getargs.wholefile, getargs.level, getargs.checksum, [], fnamedict, getargs.verbose, False);
167 if(not tmpout):
168 sys.exit(1);
169 getargs.input = tempout;
170 pycatfile.UnPackArchiveFile(getargs.input, getargs.output, False, 0, 0, getargs.skipchecksum, fnamedict, getargs.verbose, getargs.preserve, getargs.preserve, False);
171 elif active_action=='list':
172 if getargs.convert:
173 checkcompressfile = pycatfile.CheckCompressionSubType(getargs.input, fnamedict, True);
174 if(checkcompressfile=="catfile"):
175 tmpout = pycatfile.ArchiveFileListFiles(getargs.input, 0, 0, getargs.skipchecksum, fnamedict, getargs.verbose, False);
176 else:
177 tmpout = pycatfile.InFileListFiles(getargs.input, getargs.verbose, fnamedict, False);
178 if(not tmpout):
179 sys.exit(1);
180 else:
181 pycatfile.ArchiveFileListFiles(getargs.input, 0, 0, getargs.skipchecksum, fnamedict, getargs.verbose, False);
182 elif active_action=='validate':
183 if getargs.convert:
184 checkcompressfile = pycatfile.CheckCompressionSubType(getargs.input, fnamedict, True);
185 tempout = BytesIO();
186 if(checkcompressfile=="catfile"):
187 tmpout = pycatfile.RePackArchiveFile(getargs.input, tempout, getargs.compression, getargs.wholefile, getargs.level, False, 0, 0, getargs.checksum, getargs.skipchecksum, [], fnamedict, getargs.verbose, False);
188 else:
189 tmpout = pycatfile.PackArchiveFileFromInFile(getargs.input, tempout, getargs.compression, getargs.wholefile, getargs.level, getargs.checksum, [], fnamedict, getargs.verbose, False);
190 getargs.input = tempout;
191 if(not tmpout):
192 sys.exit(1);
193 fvalid = pycatfile.ArchiveFileValidate(getargs.input, fnamedict, getargs.verbose, False);
194 if(not getargs.verbose):
195 import sys, logging;
196 logging.basicConfig(format="%(message)s", stream=sys.stdout, level=logging.DEBUG);
197 if(fvalid):
198 pycatfile.VerbosePrintOut("File is valid: \n" + str(getargs.input));
199 else:
200 pycatfile.VerbosePrintOut("File is invalid: \n" + str(getargs.input));