2 # -*- coding: utf-8 -*-
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 $
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
26 def handler(signum
, frame
):
27 pycatfile
.VerbosePrintOut("Received SIGPIPE, exiting gracefully.","info");
29 signal
.signal(signal
.SIGPIPE
, handler
);
31 rarfile_support
= pycatfile
.rarfile_support
;
32 py7zr_support
= pycatfile
.py7zr_support
;
34 if(sys
.version
[0]=="2"):
36 from io
import StringIO
, BytesIO
;
39 from cStringIO
import StringIO
;
40 from cStringIO
import StringIO
as BytesIO
;
42 from StringIO
import StringIO
;
43 from StringIO
import StringIO
as BytesIO
;
44 elif(sys
.version
[0]>="3"):
45 from io
import StringIO
, BytesIO
;
50 from cStringIO
import StringIO
as BytesIO
;
56 from StringIO
import StringIO
as BytesIO
;
62 from io
import BytesIO
;
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);
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.");
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.");
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();
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
137 if active_action
=='create':
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);
143 tmpout
= pycatfile
.PackArchiveFileFromInFile(getargs
.input, getargs
.output
, getargs
.compression
, getargs
.wholefile
, getargs
.level
, getargs
.checksum
, [], fnamedict
, getargs
.verbose
, False);
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':
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);
154 pycatfile
.PackArchiveFileFromInFile(getargs
.input, getargs
.output
, getargs
.compression
, getargs
.wholefile
, getargs
.level
, getargs
.checksum
, [], fnamedict
, getargs
.verbose
, False);
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':
161 checkcompressfile
= pycatfile
.CheckCompressionSubType(getargs
.input, fnamedict
, True);
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);
166 tmpout
= pycatfile
.PackArchiveFileFromInFile(getargs
.input, tempout
, getargs
.compression
, getargs
.wholefile
, getargs
.level
, getargs
.checksum
, [], fnamedict
, getargs
.verbose
, False);
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':
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);
177 tmpout
= pycatfile
.InFileListFiles(getargs
.input, getargs
.verbose
, fnamedict
, False);
181 pycatfile
.ArchiveFileListFiles(getargs
.input, 0, 0, getargs
.skipchecksum
, fnamedict
, getargs
.verbose
, False);
182 elif active_action
=='validate':
184 checkcompressfile
= pycatfile
.CheckCompressionSubType(getargs
.input, fnamedict
, True);
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);
189 tmpout
= pycatfile
.PackArchiveFileFromInFile(getargs
.input, tempout
, getargs
.compression
, getargs
.wholefile
, getargs
.level
, getargs
.checksum
, [], fnamedict
, getargs
.verbose
, False);
190 getargs
.input = tempout
;
193 fvalid
= pycatfile
.ArchiveFileValidate(getargs
.input, fnamedict
, getargs
.verbose
, False);
194 if(not getargs
.verbose
):
196 logging
.basicConfig(format
="%(message)s", stream
=sys
.stdout
, level
=logging
.DEBUG
);
198 pycatfile
.VerbosePrintOut("File is valid: \n" + str(getargs
.input));
200 pycatfile
.VerbosePrintOut("File is invalid: \n" + str(getargs
.input));