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: 7/10/2024 Ver. 0.13.12 RC 1 - Author: cooldude2k $
20 from __future__
import absolute_import
, division
, print_function
, unicode_literals
, generators
, with_statement
, nested_scopes
27 # Conditional import and signal handling for Unix-like systems
28 if os
.name
!= 'nt': # Not Windows
31 def handler(signum
, frame
):
32 pycatfile
.VerbosePrintOut(
33 "Received SIGPIPE, exiting gracefully.", "info")
35 signal
.signal(signal
.SIGPIPE
, handler
)
37 rarfile_support
= pycatfile
.rarfile_support
38 py7zr_support
= pycatfile
.py7zr_support
40 if(sys
.version
[0] == "2"):
42 from io
import StringIO
, BytesIO
45 from cStringIO
import StringIO
46 from cStringIO
import StringIO
as BytesIO
48 from StringIO
import StringIO
49 from StringIO
import StringIO
as BytesIO
50 elif(sys
.version
[0] >= "3"):
51 from io
import StringIO
, BytesIO
54 if(teststringio
<= 0):
56 from cStringIO
import StringIO
as BytesIO
60 if(teststringio
<= 0):
62 from StringIO
import StringIO
as BytesIO
66 if(teststringio
<= 0):
68 from io
import BytesIO
73 __project__
= pycatfile
.__project
__
74 __program_name__
= pycatfile
.__program
_name
__
75 __file_format_name__
= pycatfile
.__file
_format
_name
__
76 __file_format_lower__
= pycatfile
.__file
_format
_lower
__
77 __file_format_magic__
= pycatfile
.__file
_format
_magic
__
78 __file_format_len__
= pycatfile
.__file
_format
_len
__
79 __file_format_hex__
= pycatfile
.__file
_format
_hex
__
80 __file_format_delimiter__
= pycatfile
.__file
_format
_delimiter
__
81 __file_format_list__
= pycatfile
.__file
_format
_list
__
82 __use_new_style__
= pycatfile
.__use
_new
_style
__
83 __use_advanced_list__
= pycatfile
.__use
_advanced
_list
__
84 __use_alt_inode__
= pycatfile
.__use
_alt
_inode
__
85 __project_url__
= pycatfile
.__project
_url
__
86 __version_info__
= pycatfile
.__version
_info
__
87 __version_date_info__
= pycatfile
.__version
_date
_info
__
88 __version_date__
= pycatfile
.__version
_date
__
89 __version_date_plusrc__
= pycatfile
.__version
_date
_plusrc
__
90 __version__
= pycatfile
.__version
__
92 # Initialize the argument parser
93 argparser
= argparse
.ArgumentParser(
94 description
="Manipulate concatenated files.", conflict_handler
="resolve", add_help
=True)
97 argparser
.add_argument("-V", "--version", action
="version",
98 version
=__program_name__
+ " " + __version__
)
99 # Input and output specifications
100 argparser
.add_argument(
101 "-i", "--input", help="Specify the file(s) to concatenate or the concatenated file to extract.", required
=True)
102 argparser
.add_argument("-o", "--output", default
=None,
103 help="Specify the name for the extracted or output concatenated files.")
105 argparser
.add_argument("-c", "--create", action
="store_true",
106 help="Perform only the concatenation operation.")
107 argparser
.add_argument("-e", "--extract", action
="store_true",
108 help="Perform only the extraction operation.")
109 argparser
.add_argument("-t", "--convert", action
="store_true",
110 help="Convert a tar/zip/rar/7zip file to a concatenated file.")
111 argparser
.add_argument("-r", "--repack", action
="store_true",
112 help="Re-concatenate files, fixing checksum errors if any.")
113 # File manipulation options
114 argparser
.add_argument(
115 "-F", "--format", default
=__file_format_list__
[0], help="Specify the format to use.")
116 argparser
.add_argument(
117 "-D", "--delimiter", default
=__file_format_list__
[5], help="Specify the delimiter to use.")
118 argparser
.add_argument(
119 "-m", "--formatver", default
=__file_format_list__
[6], help="Specify the format version.")
120 argparser
.add_argument("-l", "--list", action
="store_true",
121 help="List files included in the concatenated file.")
122 # Compression options
123 argparser
.add_argument("-P", "--compression", default
="auto",
124 help="Specify the compression method to use for concatenation.")
125 argparser
.add_argument("-L", "--level", default
=None,
126 help="Specify the compression level for concatenation.")
127 argparser
.add_argument("-W", "--wholefile", action
="store_true",
128 help="Whole file compression method to use for concatenation.")
129 # Checksum and validation
130 argparser
.add_argument("-v", "--validate", action
="store_true",
131 help="Validate concatenated file checksums.")
132 argparser
.add_argument("-C", "--checksum", default
="crc32",
133 help="Specify the type of checksum to use. The default is crc32.")
134 argparser
.add_argument("-s", "--skipchecksum", action
="store_true",
135 help="Skip the checksum check of files.")
136 # Permissions and metadata
137 argparser
.add_argument("-p", "--preserve", action
="store_false",
138 help="Do not preserve permissions and timestamps of files.")
140 argparser
.add_argument("-d", "--verbose", action
="store_true",
141 help="Enable verbose mode to display various debugging information.")
142 argparser
.add_argument("-T", "--text", action
="store_true",
143 help="Read file locations from a text file.")
144 # Parse the arguments
145 getargs
= argparser
.parse_args()
147 fname
= getargs
.format
148 fnamelower
= fname
.lower()
150 fnamelen
= len(fname
)
151 fnamehex
= binascii
.hexlify(fname
.encode("UTF-8")).decode("UTF-8")
152 fnamesty
= __use_new_style__
153 fnamelst
= __use_advanced_list__
154 fnameino
= __use_alt_inode__
155 fnamelist
= [fname
, fnamemagic
, fnamelower
, fnamelen
, fnamehex
,
156 getargs
.delimiter
, getargs
.formatver
, fnamesty
, fnamelst
, fnameino
]
157 fnamedict
= {'format_name': fname
, 'format_magic': fnamemagic
, 'format_lower': fnamelower
, 'format_len': fnamelen
, 'format_hex': fnamehex
,
158 'format_delimiter': getargs
.delimiter
, 'format_ver': getargs
.formatver
, 'new_style': fnamesty
, 'use_advanced_list': fnamelst
, 'use_alt_inode': fnameino
}
160 # Determine the primary action based on user input
161 actions
= ['create', 'extract', 'list', 'repack', 'validate']
162 active_action
= next(
163 (action
for action
in actions
if getattr(getargs
, action
)), None)
165 # Execute the appropriate functions based on determined actions and arguments
167 if active_action
== 'create':
169 checkcompressfile
= pycatfile
.CheckCompressionSubType(
170 getargs
.input, fnamedict
, True)
171 if(checkcompressfile
== "catfile"):
172 tmpout
= pycatfile
.RePackArchiveFile(getargs
.input, getargs
.output
, getargs
.compression
, getargs
.wholefile
,
173 getargs
.level
, False, 0, 0, getargs
.checksum
, getargs
.skipchecksum
, [], fnamedict
, getargs
.verbose
, False)
175 tmpout
= pycatfile
.PackArchiveFileFromInFile(
176 getargs
.input, getargs
.output
, getargs
.compression
, getargs
.wholefile
, getargs
.level
, getargs
.checksum
, [], fnamedict
, getargs
.verbose
, False)
180 pycatfile
.PackArchiveFile(getargs
.input, getargs
.output
, getargs
.text
, getargs
.compression
,
181 getargs
.wholefile
, getargs
.level
, False, getargs
.checksum
, [], fnamedict
, getargs
.verbose
, False)
182 elif active_action
== 'repack':
184 checkcompressfile
= pycatfile
.CheckCompressionSubType(
185 getargs
.input, fnamedict
, True)
186 if(checkcompressfile
== "catfile"):
187 pycatfile
.RePackArchiveFile(getargs
.input, getargs
.output
, getargs
.compression
, getargs
.wholefile
, getargs
.level
,
188 False, 0, 0, getargs
.checksum
, getargs
.skipchecksum
, [], fnamedict
, getargs
.verbose
, False)
190 pycatfile
.PackArchiveFileFromInFile(getargs
.input, getargs
.output
, getargs
.compression
,
191 getargs
.wholefile
, getargs
.level
, getargs
.checksum
, [], fnamedict
, getargs
.verbose
, False)
195 pycatfile
.RePackArchiveFile(getargs
.input, getargs
.output
, getargs
.compression
, getargs
.wholefile
, getargs
.level
,
196 False, 0, 0, getargs
.checksum
, getargs
.skipchecksum
, [], fnamedict
, getargs
.verbose
, False)
197 elif active_action
== 'extract':
199 checkcompressfile
= pycatfile
.CheckCompressionSubType(
200 getargs
.input, fnamedict
, True)
202 if(checkcompressfile
== "catfile"):
203 tmpout
= pycatfile
.RePackArchiveFile(getargs
.input, tempout
, getargs
.compression
, getargs
.wholefile
,
204 getargs
.level
, False, 0, 0, getargs
.checksum
, getargs
.skipchecksum
, [], fnamedict
, False, False)
206 tmpout
= pycatfile
.PackArchiveFileFromInFile(
207 getargs
.input, tempout
, getargs
.compression
, getargs
.wholefile
, getargs
.level
, getargs
.checksum
, [], fnamedict
, False, False)
210 getargs
.input = tempout
211 pycatfile
.UnPackArchiveFile(getargs
.input, getargs
.output
, False, 0, 0, getargs
.skipchecksum
,
212 fnamedict
, getargs
.verbose
, getargs
.preserve
, getargs
.preserve
, False)
213 elif active_action
== 'list':
215 checkcompressfile
= pycatfile
.CheckCompressionSubType(
216 getargs
.input, fnamedict
, True)
217 if(checkcompressfile
== "catfile"):
218 tmpout
= pycatfile
.ArchiveFileListFiles(
219 getargs
.input, 0, 0, getargs
.skipchecksum
, fnamedict
, getargs
.verbose
, False)
221 tmpout
= pycatfile
.InFileListFiles(
222 getargs
.input, getargs
.verbose
, fnamedict
, False)
226 pycatfile
.ArchiveFileListFiles(
227 getargs
.input, 0, 0, getargs
.skipchecksum
, fnamedict
, getargs
.verbose
, False)
228 elif active_action
== 'validate':
230 checkcompressfile
= pycatfile
.CheckCompressionSubType(
231 getargs
.input, fnamedict
, True)
233 if(checkcompressfile
== "catfile"):
234 tmpout
= pycatfile
.RePackArchiveFile(getargs
.input, tempout
, getargs
.compression
, getargs
.wholefile
,
235 getargs
.level
, False, 0, 0, getargs
.checksum
, getargs
.skipchecksum
, [], fnamedict
, False, False)
237 tmpout
= pycatfile
.PackArchiveFileFromInFile(
238 getargs
.input, tempout
, getargs
.compression
, getargs
.wholefile
, getargs
.level
, getargs
.checksum
, [], fnamedict
, False, False)
239 getargs
.input = tempout
242 fvalid
= pycatfile
.ArchiveFileValidate(
243 getargs
.input, fnamedict
, getargs
.verbose
, False)
244 if(not getargs
.verbose
):
247 logging
.basicConfig(format
="%(message)s",
248 stream
=sys
.stdout
, level
=logging
.DEBUG
)
250 pycatfile
.VerbosePrintOut("File is valid: \n" + str(getargs
.input))
252 pycatfile
.VerbosePrintOut(
253 "File is invalid: \n" + str(getargs
.input))