Fix Stuffit5 conv and some code cleanup.

This commit is contained in:
Guillaume Gonnet 2019-03-10 11:12:10 +01:00
parent ea24dbaeff
commit e54e2f5b5e
12 changed files with 132 additions and 124 deletions

View File

@ -70,7 +70,7 @@ set(MACONV_SRC
"src/main.cc" "src/main.cc"
) )
# Include "src" and "vendors" folder for resolving #include. # Include "src" and "vendors" folders for resolving #include.
include_directories("src" "vendors") include_directories("src" "vendors")

View File

@ -37,7 +37,7 @@ Data are arranged as follows:
| 102 **³** | Word | Signature for indentification purposes (always `mBIN`) | | 102 **³** | Word | Signature for indentification purposes (always `mBIN`) |
| 106 **³** | Byte | Script of file name (from the fdScript field of an fxInfo record) | | 106 **³** | Byte | Script of file name (from the fdScript field of an fxInfo record) |
| 107 **³** | Byte | Extended Finder flags (from the fdXFlags field of an fxInfo record) | | 107 **³** | Byte | Extended Finder flags (from the fdXFlags field of an fxInfo record) |
| 108-115 | | Unused (must be zeroed by creators, must be ignored by readers) | | 108 | 8 Bytes | Unused (must be zeroed by creators, must be ignored by readers) |
| 116 **²** | Word | Length of total files when packed files are unpacked. As of the writing of this document, this field has never been used. | | 116 **²** | Word | Length of total files when packed files are unpacked. As of the writing of this document, this field has never been used. |
| 120 **²** | Half | Length of a secondary header. If this is non-zero, skip this many bytes (rounded up to the next multiple of 128). This is for future expansion only, when sending files with MacBinary, this word should be zero. | | 120 **²** | Half | Length of a secondary header. If this is non-zero, skip this many bytes (rounded up to the next multiple of 128). This is for future expansion only, when sending files with MacBinary, this word should be zero. |
| 122 **²** | Byte | Version number of MacBinary (`129` for MacBinary II, `130` for MacBinary III) | | 122 **²** | Byte | Version number of MacBinary (`129` for MacBinary II, `130` for MacBinary III) |
@ -52,13 +52,13 @@ Cyclic redundancy check (CRC) used in header is CRC-16-CCITT, i.e. uses
polynomial number `0x1021` and starts with `0`. polynomial number `0x1021` and starts with `0`.
## Data and ressource forks. ## Data and ressource forks
Data fork directly follow the header (at byte 128). The length of these data Data fork directly follows the header (at byte 128). The length of these data
(which can be zero) must correspond with the length given in the header (at byte (which can be zero) must correspond with the length given in the header (at byte
83). 83).
Data are completed with some padding bytes (normally `0x00` but some Data are completed with some padding bytes (usually `0x00` but some
implementations use `0x7F`) until the total length of file is a multiple of 128. implementations use `0x7F`) until the total length of file is a multiple of 128.
If the total length is already a multiple of 128 after adding the data fork, no If the total length is already a multiple of 128 after adding the data fork, no
padding is added. padding is added.

View File

@ -178,7 +178,7 @@ void WriteMacBinary(fs::File &file, fs::FileWriter &base)
writer.Fill(0x0, 2); writer.Fill(0x0, 2);
writer.WriteByte(file.flags & 0xFF); writer.WriteByte(file.flags & 0xFF);
// Write MacBinray III magic strings/numbers. // Write MacBinary III magic strings/numbers.
writer.WriteString("mBIN"); writer.WriteString("mBIN");
writer.Fill(0x0, 16); writer.Fill(0x0, 16);
writer.WriteByte(130); writer.WriteByte(130);

View File

@ -39,7 +39,7 @@ extern "C" void LogDebug(const char *fmt, ...)
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
vfprintf(stderr, fmt, args); vprintf(fmt, args);
va_end(args); va_end(args);
printf("\n"); printf("\n");
} }

View File

@ -320,7 +320,7 @@ constexpr int kLzssEnd = -2;
void Algorithm13Method::InitializeLZSS() void Algorithm13Method::InitializeLZSS()
{ {
int val = *(input.data++); int val = *(input.data++);
int code = (val >> 4); int code = ((val & 0xFF) >> 4);
if (code == 0) { if (code == 0) {
HuffmanDecoder metacode; HuffmanDecoder metacode;

View File

@ -26,6 +26,7 @@ this program. If not, see <https://www.gnu.org/licenses/>.
#include <path.hpp> #include <path.hpp>
#include <cstdarg> #include <cstdarg>
#include <algorithm>
namespace maconv { namespace maconv {
namespace stuffit { namespace stuffit {
@ -61,6 +62,7 @@ static void ExtractFork(StuffitEntry &ent, bool is_res, fs::File &file,
return (void)WarnForkError(ent, is_res, "compression method %u not supported", info.method); return (void)WarnForkError(ent, is_res, "compression method %u not supported", info.method);
// Try extracting the fork. // Try extracting the fork.
LogDebug(" Extracting %s fork using algo %d", (is_res ? "ressource" : "data"), info.method);
try { try {
ptr->Extract(info, data, file.mem_pool); ptr->Extract(info, data, file.mem_pool);
} catch (ExtractException &e) { } catch (ExtractException &e) {
@ -96,6 +98,7 @@ static void ExtractFile(fs::FileReader &reader, StuffitEntry &ent,
// Log information to user. // Log information to user.
std::string filename = dest_folder + "/" + GetFilenameFor(ent.name, prefered_conv); std::string filename = dest_folder + "/" + GetFilenameFor(ent.name, prefered_conv);
filename.erase(std::remove(filename.begin(), filename.end(), '\r'), filename.end());
LogDebug("Extracting %s ...", filename.c_str()); LogDebug("Extracting %s ...", filename.c_str());
// Uncompress forks (if not empty). // Uncompress forks (if not empty).

View File

@ -3,6 +3,9 @@
Extract files from Stuffit (v5) archives. Extract files from Stuffit (v5) archives.
See docs/stuffit/Stuffit_v5.md for more information on this format. See docs/stuffit/Stuffit_v5.md for more information on this format.
The code in this file is based on TheUnarchiver.
See README.md and docs/licenses/TheUnarchiver.txt for more information.
Copyright (C) 2019, Guillaume Gonnet Copyright (C) 2019, Guillaume Gonnet
This program is free software: you can redistribute it and/or modify it under This program is free software: you can redistribute it and/or modify it under
@ -30,6 +33,7 @@ namespace stuffit {
// Stuffit (v5) entity flags. // Stuffit (v5) entity flags.
constexpr uint8_t kFlagDirectory = 0x40; constexpr uint8_t kFlagDirectory = 0x40;
constexpr uint8_t kFlagCrypted = 0x20;
constexpr uint8_t kFlagHasRessource = 0x1; constexpr uint8_t kFlagHasRessource = 0x1;
@ -85,7 +89,8 @@ static void ReadFileHeader(fs::FileReader &reader, StuffitEntry &ent)
reader.Skip(1); reader.Skip(1);
// Read flags for knowing if entry is a file or a folder. // Read flags for knowing if entry is a file or a folder.
ent.etype = (reader.ReadByte() & kFlagDirectory) ? StuffitEntryType::Folder int flags = reader.ReadByte();
ent.etype = (flags & kFlagDirectory) ? StuffitEntryType::Folder
: StuffitEntryType::File; : StuffitEntryType::File;
// Read creation and modification dates. // Read creation and modification dates.
@ -99,10 +104,10 @@ static void ReadFileHeader(fs::FileReader &reader, StuffitEntry &ent)
// Read name and data lengths. // Read name and data lengths.
uint16_t name_length = reader.ReadHalfBE(); uint16_t name_length = reader.ReadHalfBE();
reader.Skip(2); reader.Skip(2); // Skip header CRC.
ent.data.size = reader.ReadWordBE(); ent.data.size = reader.ReadWordBE();
ent.data.comp_size = reader.ReadWordBE(); ent.data.comp_size = reader.ReadWordBE();
reader.Skip(4); reader.Skip(4); // Skip data CRC.
// The entry is a folder: read the number of files. // The entry is a folder: read the number of files.
@ -120,7 +125,7 @@ static void ReadFileHeader(fs::FileReader &reader, StuffitEntry &ent)
else { else {
ent.num_files = 0; ent.num_files = 0;
ent.data.method = reader.ReadByte(); ent.data.method = reader.ReadByte();
reader.Skip(1); reader.Skip(1); // Skip password length (as archive is not encrypted).
} }
@ -149,9 +154,9 @@ static void ReadFileHeader(fs::FileReader &reader, StuffitEntry &ent)
if (has_res) { if (has_res) {
ent.res.size = reader.ReadWordBE(); ent.res.size = reader.ReadWordBE();
ent.res.comp_size = reader.ReadWordBE(); ent.res.comp_size = reader.ReadWordBE();
reader.Skip(4); reader.Skip(4); // Skip ressource CRC.
ent.res.method = reader.ReadByte(); ent.res.method = reader.ReadByte();
reader.Skip(1); reader.Skip(1); // Skip password length (as archive is not encrypted).
} else { } else {
ent.res.size = 0; ent.res.size = 0;
ent.res.comp_size = 0; ent.res.comp_size = 0;
@ -163,11 +168,11 @@ static void ReadFileHeader(fs::FileReader &reader, StuffitEntry &ent)
// Set data and res offsets. // Set data and res offsets.
ent.data.offset = reader.Tell(); ent.res.offset = reader.Tell();
ent.res.offset = ent.data.offset + ent.data.comp_size; ent.data.offset = ent.res.offset + ent.res.comp_size;
// Seek to the next entry (if it's a file). // Seek to the next entry (if it's a file).
reader.Seek(ent.res.offset + ent.res.comp_size); reader.Seek(ent.data.offset + ent.data.comp_size);
} }

View File

@ -204,16 +204,16 @@ void HuffmanDecoder::MakeTableRecursLE(int node, HuffmanTableEntry *table,
int curr_table_size = (1 << (table_size - depth)); int curr_table_size = (1 << (table_size - depth));
int curr_stride = (1 << depth); int curr_stride = (1 << depth);
if (IsLeafNode(node)) { if (IsInvalidNode(node)) {
for (int i = 0; i < curr_table_size; i++)
table[i * curr_stride].length = -1;
}
else if (IsLeafNode(node)) {
for (int i = 0; i < curr_table_size; i++) { for (int i = 0; i < curr_table_size; i++) {
table[i * curr_stride].length = depth; table[i * curr_stride].length = depth;
table[i * curr_stride].value = LeafValue(node); table[i * curr_stride].value = LeafValue(node);
} }
} }
else if (IsInvalidNode(node)) {
for (int i = 0; i < curr_table_size; i++)
table[i * curr_stride].length = -1;
}
else { else {
if (depth == table_size) { if (depth == table_size) {
table[0].length = table_size + 1; table[0].length = table_size + 1;