using
System;
using
System.Collections.Generic;
using
System.IO;
using
System.Text;
using
System.Threading.Tasks;
namespace
PCKExtractetor
{
/// <summary>
/// PCK解压操作类
/// </summary>
internal
class
PCKExtractetor
{
/// <summary>
/// <五元List> 取PCK内部文件列表
/// <param name="pckfilePath">(文本型 欲获取内部文件列表的PCK文件) </param>
/// <returns><para>成功返回PCK文件的单个文件的目录长度、完整文件路径、、文件偏移、实际大小、压缩大小,并封装在 <List>中</para></returns>
/// </summary>
public
static
List<Tuple<
int
,
string
,
long
,
long
,
long
>> GetPCKInformation(
string
pckfilePath)
{
List<Tuple<
int
,
string
,
long
,
long
,
long
>> returnList =
new
List<Tuple<
int
,
string
,
long
,
long
,
long
>>();
FileInfo fileInfo =
new
FileInfo(pckfilePath);
long
pckfileSize = fileInfo.Length;
Console.WriteLine(
"PCK文件大小:"
+ fileInfo.Length +
" 字节(十六进制:"
+ fileInfo.Length.ToString(
"X"
) +
")"
);
long
pckSignatureSize = 272;
using
(FileStream fs =
new
FileStream(pckfilePath, FileMode.Open))
{
byte
[] dataSizeBit =
new
byte
[4];
long
dataSize;
fs.Seek(pckfileSize - pckSignatureSize + 4, SeekOrigin.Begin);
fs.Read(dataSizeBit, 0, dataSizeBit.Length);
dataSize = BitConverter.ToInt64(PublicFunction.EightByteConverter(dataSizeBit), 0);
Console.WriteLine(
"该文件的数据区物理大小为 "
+ dataSize.ToString() +
" 字节(十六进制:"
+ dataSize.ToString(
"X"
) +
")"
);
byte
[] fileCountBit =
new
byte
[4];
long
fileCount;
fs.Seek(pckfileSize - 8, SeekOrigin.Begin);
fs.Read(fileCountBit, 0, fileCountBit.Length);
fileCount = BitConverter.ToInt64(PublicFunction.EightByteConverter(fileCountBit), 0);
Console.WriteLine(
"该PCK文件包应有 "
+ fileCount.ToString() +
" 个文件(十六进制:"
+ fileCount.ToString(
"X"
) +
")"
);
byte
[] fileIdxByte =
new
byte
[pckfileSize - dataSize - pckSignatureSize];
fs.Seek(dataSize, SeekOrigin.Begin);
fs.Read(fileIdxByte, 0, fileIdxByte.Length);
Console.WriteLine(
"该PCK文件包的文件索引大小为 "
+ fileIdxByte.Length.ToString() +
" 字节(十六进制:"
+ fileIdxByte.Length.ToString(
"X"
) +
")"
);
int
byteOffset = 0;
for
(
int
i = 0; i < fileCount; i++)
{
byte
[] filePathLengthBit =
new
byte
[4];
Array.Copy(fileIdxByte, byteOffset, filePathLengthBit, 0, filePathLengthBit.Length);
int
filePathLength = BitConverter.ToInt32(PublicFunction.EightByteConverter(filePathLengthBit), 0) - 1;
byteOffset += 4;
byte
[] filePathStringBit =
new
byte
[filePathLength];
Array.Copy(fileIdxByte, byteOffset, filePathStringBit, 0, filePathLength);
string
filePathString = Encoding.Default.GetString(filePathStringBit);
byteOffset += filePathLength + 1;
byte
[] fileOffsetBit =
new
byte
[4];
Array.Copy(fileIdxByte, byteOffset, fileOffsetBit, 0, fileOffsetBit.Length);
long
fileOffset = BitConverter.ToInt64(PublicFunction.EightByteConverter(fileOffsetBit), 0);
byteOffset += 4;
byte
[] fileActualsizeBit =
new
byte
[4];
Array.Copy(fileIdxByte, byteOffset, fileActualsizeBit, 0, fileActualsizeBit.Length);
long
fileActualsize = BitConverter.ToInt64(PublicFunction.EightByteConverter(fileActualsizeBit), 0);
byteOffset += 4;
byte
[] filecompressionsizeBit =
new
byte
[4];
Array.Copy(fileIdxByte, byteOffset, filecompressionsizeBit, 0, filecompressionsizeBit.Length);
long
filecompressionsize = BitConverter.ToInt64(PublicFunction.EightByteConverter(filecompressionsizeBit), 0);
byteOffset += 4;
returnList.Add(Tuple.Create(filePathLength, filePathString, fileOffset, fileActualsize, filecompressionsize));
}
fs.Close();
}
return
returnList;
}
/// <summary>
/// 解压单独文件
/// <param name="pckfilePath">(文本型 欲单独解压的PCK文件, </param>
/// <param name="fileList">List 已处理好的文件列表, </param>
/// <param name="targetNum">欲解压的文件顺序号, </param>
/// <param name="savePath">欲保存的路径)</param>
/// </summary>
public
static
void
ExtractFileSingle(
string
pckfilePath, List<Tuple<
int
,
string
,
long
,
long
,
long
>> fileList,
int
targetNum,
string
savePath)
{
string
fileName = Path.GetFileName(fileList[targetNum].Item2);
long
pckOffset = fileList[targetNum].Item3;
long
actualDataSize = fileList[targetNum].Item4;
long
compressionDataSize = fileList[targetNum].Item5;
byte
[] actualData;
byte
[] compressionData =
new
byte
[compressionDataSize];
using
(FileStream fs =
new
FileStream(pckfilePath, FileMode.Open))
{
fs.Seek(pckOffset, SeekOrigin.Begin);
fs.Read(compressionData, 0, (
int
)compressionDataSize);
if
(actualDataSize == compressionDataSize)
{
actualData = compressionData;
}
else
{
actualData = ZLibHelper.DeZlibcompress(compressionData);
}
File.WriteAllBytes(savePath, actualData);
fs.Close();
}
}
/// <summary>
/// 解压所有文件
/// <param name="pckfilePath">(文本型 欲单解压的PCK文件, </param>
/// <param name="fileList">List 已处理好的文件列表, </param>
/// <param name="savePath">欲保存的路径)</param>
/// </summary>
public
static
void
ExtractAllFile(
string
pckfilePath, List<Tuple<
int
,
string
,
long
,
long
,
long
>> fileList,
string
savePath)
{
int
fileCount = fileList.Count;
string
extractFolder = Path.GetFileNameWithoutExtension(pckfilePath) +
"_PCKUnpacked"
;
Directory.CreateDirectory(extractFolder);
using
(FileStream fs =
new
FileStream(pckfilePath, FileMode.Open))
{
for
(
int
i = 0; i < fileCount; i++)
{
string
filePath = fileList[i].Item2;
string
fileDir = Path.GetDirectoryName(filePath);
string
fileName = Path.GetFileName(filePath);
string
finalPath = savePath +
"\\"
+ extractFolder +
"\\"
+ filePath;
long
pckOffset = fileList[i].Item3;
long
actualDataSize = fileList[i].Item4;
long
compressionDataSize = fileList[i].Item5;
byte
[] actualData;
byte
[] compressionData =
new
byte
[compressionDataSize];
fs.Seek(pckOffset, SeekOrigin.Begin);
fs.Read(compressionData, 0, (
int
)compressionDataSize);
if
(actualDataSize == compressionDataSize)
{
actualData = compressionData;
}
else
{
actualData = ZLibHelper.DeZlibcompress(compressionData);
}
if
(!Directory.Exists(Path.GetDirectoryName(finalPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(finalPath));
}
File.WriteAllBytes(finalPath, actualData);
}
fs.Close();
}
}
}
}