178 lines
4.6 KiB
C++
178 lines
4.6 KiB
C++
/*
|
|
|
|
Convert files from and to AppleSingle format.
|
|
See docs/formats/AppleSingle.md for more information on this format.
|
|
|
|
Copyright (C) 2019, Guillaume Gonnet
|
|
|
|
This program is free software: you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free Software
|
|
Foundation, either version 3 of the License, or (at your option) any later
|
|
version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include "conv/converters.h"
|
|
|
|
#include <path.hpp>
|
|
|
|
namespace maconv {
|
|
namespace conv {
|
|
|
|
|
|
|
|
// Return true if a file is in AppleSingle format.
|
|
bool IsFileAppleSingle(fs::FileReader &reader)
|
|
{
|
|
IS_COND(reader.file_size >= 26);
|
|
|
|
IS_COND(reader.ReadWordBE() == 0x00051600);
|
|
IS_COND(reader.ReadWordBE() == 0x00020000);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
// Extract a single AppleSingle entry.
|
|
void ExtractAppleSimpleEntry(fs::FileReader &reader, fs::File &file, uint32_t id,
|
|
uint32_t length)
|
|
{
|
|
switch (id) {
|
|
// Data fork.
|
|
case 1: {
|
|
file.data = reader.data + reader.Tell();
|
|
file.data_size = length;
|
|
} break;
|
|
|
|
// Ressource fork.
|
|
case 2: {
|
|
file.res = reader.data + reader.Tell();
|
|
file.res_size = length;
|
|
} break;
|
|
|
|
// Ressource fork.
|
|
case 3: {
|
|
file.filename = reader.ReadString(length);
|
|
} break;
|
|
|
|
// File creation and modification dates.
|
|
case 8: {
|
|
file.creation_date = reader.ReadJ2000Date();
|
|
file.modif_date = reader.ReadJ2000Date();
|
|
} break;
|
|
|
|
// Finder information.
|
|
case 9: {
|
|
file.type = reader.ReadWordBE();
|
|
file.creator = reader.ReadWordBE();
|
|
file.flags = reader.ReadHalfBE();
|
|
} break;
|
|
}
|
|
}
|
|
|
|
|
|
// Read and decode an AppleSingle file.
|
|
void ReadAppleSingle(fs::FileReader &reader, fs::File &file)
|
|
{
|
|
reader.Skip(26);
|
|
int num_entries = reader.ReadHalfBE();
|
|
|
|
// Extract each entries.
|
|
for (int i = 0; i < num_entries; i++) {
|
|
reader.Seek(26 + i * 12);
|
|
|
|
uint32_t id = reader.ReadWordBE();
|
|
uint32_t offset = reader.ReadWordBE();
|
|
uint32_t length = reader.ReadWordBE();
|
|
|
|
reader.Seek(offset);
|
|
ExtractAppleSimpleEntry(reader, file, id, length);
|
|
}
|
|
|
|
|
|
// If the filename is not provided: use the input filename.
|
|
if (file.filename.empty())
|
|
file.filename = Path(file.filename).filename();
|
|
|
|
// Add missing information.
|
|
GetLocalInfo(file.filename, file);
|
|
}
|
|
|
|
|
|
|
|
// Write an AppleSingle file.
|
|
void WriteAppleSingle(fs::File &file, fs::FileWriter &writer)
|
|
{
|
|
// Write file header.
|
|
writer.WriteWordBE(0x00051600);
|
|
writer.WriteWordBE(0x00020000);
|
|
writer.Fill(0x0, 16);
|
|
writer.WriteHalfBE(5); // Number of entries.
|
|
|
|
|
|
// Write filename entry.
|
|
uint32_t offset = 24 + 5 * 12;
|
|
writer.WriteWordBE(3); // ID.
|
|
writer.WriteWordBE(offset); // Offset.
|
|
writer.WriteWordBE(file.filename.size()); // Length.
|
|
|
|
// Write date entry.
|
|
offset += file.filename.size();
|
|
writer.WriteWordBE(3); // ID.
|
|
writer.WriteWordBE(offset); // Offset.
|
|
writer.WriteWordBE(12); // Length.
|
|
|
|
// Write Finder information entry.
|
|
offset += 12;
|
|
writer.WriteWordBE(9); // ID.
|
|
writer.WriteWordBE(offset); // Offset.
|
|
writer.WriteWordBE(32); // Length.
|
|
|
|
// Write data fork entry.
|
|
offset += 32;
|
|
writer.WriteWordBE(1); // ID.
|
|
writer.WriteWordBE(offset); // Offset.
|
|
writer.WriteWordBE(file.data_size); // Length.
|
|
|
|
// Write ressource fork entry.
|
|
offset += file.data_size;
|
|
writer.WriteWordBE(2); // ID.
|
|
writer.WriteWordBE(offset); // Offset.
|
|
writer.WriteWordBE(file.res_size); // Length.
|
|
|
|
|
|
// Write filename.
|
|
writer.WriteString(file.filename);
|
|
|
|
// Write creation and modification dates.
|
|
writer.WriteJ2000Date(file.creation_date);
|
|
writer.WriteJ2000Date(file.modif_date);
|
|
writer.WriteWordBE(0x80000000);
|
|
writer.WriteWordBE(file.modif_date);
|
|
|
|
// Write Finder information.
|
|
writer.WriteWordBE(file.type);
|
|
writer.WriteWordBE(file.creator);
|
|
writer.WriteHalfBE(file.flags);
|
|
writer.Fill(0x0, 22);
|
|
|
|
// Write data fork.
|
|
writer.Write(file.data, file.data_size);
|
|
|
|
// Wrire ressource fork.
|
|
writer.Write(file.res, file.res_size);
|
|
}
|
|
|
|
|
|
|
|
} // namespace maconv
|
|
} // namespace conv
|