Task 595: .R01 File Format
Task 595: .R01 File Format
1. List of Properties of the .R01 File Format Intrinsic to Its File System
The .R01 file format is part of the RAR archive format for multi-volume archives (typically RAR versions 1.5-4.0, where .rar is the first volume, .r00 the second, .r01 the third, etc.). It shares the same structure as other RAR volumes, including headers and blocks. The intrinsic properties refer to the structural and metadata fields in the format's headers, which define its layout, compression, encryption, and file system-like organization (e.g., files, directories, attributes). Based on the RAR format specifications, the key properties are:
- Magic Signature: The 7-byte identifier (0x52 0x61 0x72 0x21 0x1A 0x07 0x00) at the start of the file.
- Header CRC16: 2-byte CRC-16 checksum of the header.
- Header Type: 1-byte value indicating block type (e.g., 0x73 for main archive header, 0x74 for file header).
- Header Flags: 2-byte flags controlling behavior (e.g., volume, solid, locked, password, split before/after for multi-volume).
- Header Size: 2-byte size of the header block.
- Add Size: 4-byte size of additional data (if flag 0x8000 is set).
- HighPosAV: 2-byte high part of AV position (main header).
- PosAV: 4-byte AV position (main header).
- EncryptVer: 1-byte encryption version (if flag 0x0200 is set in main header).
- PackSize: 4-byte compressed size (low 32 bits; file header).
- UnpSize: 4-byte uncompressed size (low 32 bits; file header).
- HostOS: 1-byte host OS code (0=MS-DOS, 1=OS/2, 2=Windows, 3=Unix, 4=Mac OS, 5=BeOS).
- FileCRC: 4-byte CRC-32 of the uncompressed file.
- FileTime: 4-byte MS-DOS timestamp for modification time.
- UnpVer: 1-byte version needed to unpack (e.g., 15, 20, 29).
- Method: 1-byte compression method (0x30=store, 0x31=fastest, 0x32=fast, 0x33=normal, 0x34=good, 0x35=best).
- NameSize: 2-byte length of the file name.
- FileAttr: 4-byte file attributes (OS-specific).
- HighPackSize: 4-byte compressed size (high 32 bits, if large file flag 0x0100 set).
- HighUnpSize: 4-byte uncompressed size (high 32 bits, if large file flag 0x0100 set).
- FileName: Variable-length string (up to NameSize bytes; Unicode if flag 0x0200 set).
- Salt: 8-byte encryption salt (if flag 0x0400 set).
- ExtTime: Variable-length extended timestamps (if flag 0x1000 set; includes ctime, atime, arctime with fractional seconds).
- Compression Algorithm: Derived from UnpVer (e.g., Unpack15 for 15, Unpack20 for 20/26, Unpack29 for 29/36; uses LZSS and PPM).
- Encryption: Password-based (if flag 0x0004 set; supports salt and version).
- Multi-Volume Flags: Split before (0x0001), split after (0x0002) for volume spanning.
- Solid Flag: 0x0010 if files are compressed together across volumes.
- Unicode Flag: 0x0200 if file name is Unicode.
These properties allow the format to function as a compressed file system, supporting directories (via file attr), timestamps, attributes, and spanning.
2. Two Direct Download Links for .R01 Files
Despite extensive searches, direct download links for sample .R01 files were not found in reliable sources (most results were for NIH R01 grant documents or general RAR files). .R01 files are typically part of multi-volume sets and not commonly hosted as isolated test files. As a fallback, here are direct links to sample multi-volume RAR archives that include .r01-like parts (e.g., .part03.rar, which is structurally identical):
- https://getsamplefiles.com/download/rar/sample.rar (sample RAR archive; rename extensions for testing multi-volume)
- https://www.learningcontainer.com/wp-content/uploads/2020/07/sample.rar (another sample RAR; can be split into volumes for .r01 simulation)
For real .R01, you can create one by splitting a RAR archive using WinRAR with the old naming scheme.
3. Ghost Blog Embedded HTML JavaScript for Drag and Drop .R01 File Dump
Here is an HTML page with embedded JavaScript that can be embedded in a Ghost blog post. It allows drag-and-drop of a .R01 file and dumps the properties to the screen using a simple parser based on the RAR format.
4. Python Class for .R01 File
Here is a Python class that can open, decode, read, write, and print the properties from a .R01 file. The write method creates a simple .R01-like file with a main header and one file header (for demonstration; full write is complex).
import struct
class R01Handler:
def __init__(self, filename):
self.filename = filename
self.data = None
def read(self):
with open(self.filename, 'rb') as f:
self.data = f.read()
def decode_and_print(self):
if self.data is None:
self.read()
view = memoryview(self.data)
pos = 0
signature = ' '.join(f'{b:02x}' for b in view[pos:pos+7])
print(f'Magic Signature: {signature}')
pos += 7
while pos < len(view):
crc16, = struct.unpack_from('<H', view, pos)
pos += 2
type_, = struct.unpack_from('<B', view, pos)
pos += 1
flags, = struct.unpack_from('<H', view, pos)
pos += 2
size, = struct.unpack_from('<H', view, pos)
pos += 2
print(f'Header CRC16: 0x{crc16:04x}')
print(f'Header Type: 0x{type_:02x}')
print(f'Header Flags: 0x{flags:04x}')
print(f'Header Size: {size}')
if flags & 0x8000:
add_size, = struct.unpack_from('<I', view, pos)
pos += 4
print(f'Add Size: {add_size}')
if type_ == 0x73: # Main header
high_pos_av, = struct.unpack_from('<H', view, pos)
pos += 2
pos_av, = struct.unpack_from('<I', view, pos)
pos += 4
print(f'HighPosAV: {high_pos_av}')
print(f'PosAV: {pos_av}')
if flags & 0x0200:
encrypt_ver, = struct.unpack_from('<B', view, pos)
pos += 1
print(f'EncryptVer: {encrypt_ver}')
elif type_ == 0x74: # File header
pack_size, = struct.unpack_from('<I', view, pos)
pos += 4
unp_size, = struct.unpack_from('<I', view, pos)
pos += 4
host_os, = struct.unpack_from('<B', view, pos)
pos += 1
file_crc, = struct.unpack_from('<I', view, pos)
pos += 4
file_time, = struct.unpack_from('<I', view, pos)
pos += 4
unp_ver, = struct.unpack_from('<B', view, pos)
pos += 1
method, = struct.unpack_from('<B', view, pos)
pos += 1
name_size, = struct.unpack_from('<H', view, pos)
pos += 2
file_attr, = struct.unpack_from('<I', view, pos)
pos += 4
print(f'PackSize: {pack_size}')
print(f'UnpSize: {unp_size}')
print(f'HostOS: {host_os}')
print(f'FileCRC: 0x{file_crc:08x}')
print(f'FileTime: {file_time}')
print(f'UnpVer: {unp_ver}')
print(f'Method: 0x{method:02x}')
print(f'NameSize: {name_size}')
print(f'FileAttr: 0x{file_attr:08x}')
if flags & 0x0100:
high_pack_size, = struct.unpack_from('<I', view, pos)
pos += 4
high_unp_size, = struct.unpack_from('<I', view, pos)
pos += 4
print(f'HighPackSize: {high_pack_size}')
print(f'HighUnpSize: {high_unp_size}')
file_name = view[pos:pos+name_size].tobytes().decode('utf-8', errors='ignore')
pos += name_size
print(f'FileName: {file_name}')
if flags & 0x0400:
salt = ' '.join(f'{b:02x}' for b in view[pos:pos+8])
pos += 8
print(f'Salt: {salt}')
if flags & 0x1000:
ext_flags, = struct.unpack_from('<H', view, pos)
pos += 2
print(f'ExtTime Flags: 0x{ext_flags:04x}')
# Further parsing omitted for brevity
# Skip to next (simplified; adjust for exact size)
pos += size - 7 - (4 if flags & 0x8000 else 0)
def write(self, output_filename, sample_data=b'Hello World'):
# Simple write: create a basic .R01 with main and file header (no compression)
sig = b'\x52\x61\x72\x21\x1A\x07\x00'
# Main header
main_header = struct.pack('<H B H H', 0, 0x73, 0, 13) # CRC, type, flags, size (dummy)
main_body = struct.pack('<H I B', 0, 0, 0) # HighPosAV, PosAV, EncryptVer
# File header
file_header = struct.pack('<H B H H', 0, 0x74, 0, 32 + len(sample_data)) # CRC, type, flags, size
file_body = struct.pack('<I I B I I B B H I', len(sample_data), len(sample_data), 2, 0, 0, 29, 0x30, 11, 0) # Pack/Unp size, HostOS, CRC, Time, Ver, Method, NameSize, Attr
file_name = b'sample.txt'
file_body += file_name
file_body += sample_data # "Compressed" data (stored)
data = sig + main_header + main_body + file_header + file_body
with open(output_filename, 'wb') as f:
f.write(data)
print(f'Wrote sample .R01 to {output_filename}')
5. Java Class for .R01 File
Here is a Java class that can open, decode, read, write, and print the properties from a .R01 file.
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class R01Handler {
private String filename;
private byte[] data;
public R01Handler(String filename) {
this.filename = filename;
}
public void read() throws IOException {
try (FileInputStream fis = new FileInputStream(filename)) {
data = fis.readAllBytes();
}
}
public void decodeAndPrint() throws IOException {
if (data == null) read();
ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
int pos = 0;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 7; i++) sb.append(String.format("%02x ", bb.get(pos++)));
System.out.println("Magic Signature: " + sb.toString().trim());
while (pos < data.length) {
short crc16 = bb.getShort(pos);
pos += 2;
byte type = bb.get(pos);
pos += 1;
short flags = bb.getShort(pos);
pos += 2;
short size = bb.getShort(pos);
pos += 2;
System.out.println("Header CRC16: 0x" + Integer.toHexString(crc16 & 0xFFFF));
System.out.println("Header Type: 0x" + Integer.toHexString(type & 0xFF));
System.out.println("Header Flags: 0x" + Integer.toHexString(flags & 0xFFFF));
System.out.println("Header Size: " + (size & 0xFFFF));
if ((flags & 0x8000) != 0) {
int addSize = bb.getInt(pos);
pos += 4;
System.out.println("Add Size: " + addSize);
}
if (type == 0x73) { // Main header
short highPosAv = bb.getShort(pos);
pos += 2;
int posAv = bb.getInt(pos);
pos += 4;
System.out.println("HighPosAV: " + highPosAv);
System.out.println("PosAV: " + posAv);
if ((flags & 0x0200) != 0) {
byte encryptVer = bb.get(pos);
pos += 1;
System.out.println("EncryptVer: " + (encryptVer & 0xFF));
}
} else if (type == 0x74) { // File header
int packSize = bb.getInt(pos);
pos += 4;
int unpSize = bb.getInt(pos);
pos += 4;
byte hostOS = bb.get(pos);
pos += 1;
int fileCRC = bb.getInt(pos);
pos += 4;
int fileTime = bb.getInt(pos);
pos += 4;
byte unpVer = bb.get(pos);
pos += 1;
byte method = bb.get(pos);
pos += 1;
short nameSize = bb.getShort(pos);
pos += 2;
int fileAttr = bb.getInt(pos);
pos += 4;
System.out.println("PackSize: " + packSize);
System.out.println("UnpSize: " + unpSize);
System.out.println("HostOS: " + (hostOS & 0xFF));
System.out.println("FileCRC: 0x" + Integer.toHexString(fileCRC));
System.out.println("FileTime: " + fileTime);
System.out.println("UnpVer: " + (unpVer & 0xFF));
System.out.println("Method: 0x" + Integer.toHexString(method & 0xFF));
System.out.println("NameSize: " + (nameSize & 0xFFFF));
System.out.println("FileAttr: 0x" + Integer.toHexString(fileAttr));
if ((flags & 0x0100) != 0) {
int highPackSize = bb.getInt(pos);
pos += 4;
int highUnpSize = bb.getInt(pos);
pos += 4;
System.out.println("HighPackSize: " + highPackSize);
System.out.println("HighUnpSize: " + highUnpSize);
}
String fileName = new String(data, pos, nameSize);
pos += nameSize;
System.out.println("FileName: " + fileName);
if ((flags & 0x0400) != 0) {
sb = new StringBuilder();
for (int i = 0; i < 8; i++) sb.append(String.format("%02x ", bb.get(pos++)));
System.out.println("Salt: " + sb.toString().trim());
}
if ((flags & 0x1000) != 0) {
short extFlags = bb.getShort(pos);
pos += 2;
System.out.println("ExtTime Flags: 0x" + Integer.toHexString(extFlags & 0xFFFF));
// Further parsing omitted
}
}
// Skip to next
pos += size - 7 - (((flags & 0x8000) != 0) ? 4 : 0);
}
}
public void write(String outputFilename, byte[] sampleData) throws IOException {
// Simple write: basic .R01 with main and file header
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(new byte[]{0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00});
// Main header
ByteBuffer mainBb = ByteBuffer.allocate(13).order(ByteOrder.LITTLE_ENDIAN);
mainBb.putShort((short)0); // CRC
mainBb.put((byte)0x73); // Type
mainBb.putShort((short)0); // Flags
mainBb.putShort((short)13); // Size
mainBb.putShort((short)0); // HighPosAV
mainBb.putInt(0); // PosAV
mainBb.put((byte)0); // EncryptVer
baos.write(mainBb.array());
// File header
int nameLen = 11; // "sample.txt"
int headerSize = 32 + nameLen;
ByteBuffer fileBb = ByteBuffer.allocate(headerSize).order(ByteOrder.LITTLE_ENDIAN);
fileBb.putShort((short)0); // CRC
fileBb.put((byte)0x74); // Type
fileBb.putShort((short)0); // Flags
fileBb.putShort((short)headerSize); // Size
fileBb.putInt(sampleData.length); // PackSize
fileBb.putInt(sampleData.length); // UnpSize
fileBb.put((byte)2); // HostOS
fileBb.putInt(0); // FileCRC
fileBb.putInt(0); // FileTime
fileBb.put((byte)29); // UnpVer
fileBb.put((byte)0x30); // Method
fileBb.putShort((short)nameLen); // NameSize
fileBb.putInt(0); // FileAttr
fileBb.put("sample.txt".getBytes()); // Name
baos.write(fileBb.array());
baos.write(sampleData); // Data
try (FileOutputStream fos = new FileOutputStream(outputFilename)) {
fos.write(baos.toByteArray());
}
System.out.println("Wrote sample .R01 to " + outputFilename);
}
}
6. JavaScript Class for .R01 File
Here is a JavaScript class (for Node.js) that can open, decode, read, write, and print the properties from a .R01 file.
const fs = require('fs');
class R01Handler {
constructor(filename) {
this.filename = filename;
this.data = null;
}
read() {
this.data = fs.readFileSync(this.filename);
}
decodeAndPrint() {
if (!this.data) this.read();
const view = new DataView(this.data.buffer);
let pos = 0;
let sb = '';
for (let i = 0; i < 7; i++) sb += view.getUint8(pos++).toString(16).padStart(2, '0') + ' ';
console.log('Magic Signature: ' + sb.trim());
while (pos < this.data.length) {
const crc16 = view.getUint16(pos, true);
pos += 2;
const type = view.getUint8(pos);
pos += 1;
const flags = view.getUint16(pos, true);
pos += 2;
const size = view.getUint16(pos, true);
pos += 2;
console.log('Header CRC16: 0x' + crc16.toString(16));
console.log('Header Type: 0x' + type.toString(16));
console.log('Header Flags: 0x' + flags.toString(16));
console.log('Header Size: ' + size);
if (flags & 0x8000) {
const addSize = view.getUint32(pos, true);
pos += 4;
console.log('Add Size: ' + addSize);
}
if (type === 0x73) { // Main header
const highPosAv = view.getUint16(pos, true);
pos += 2;
const posAv = view.getUint32(pos, true);
pos += 4;
console.log('HighPosAV: ' + highPosAv);
console.log('PosAV: ' + posAv);
if (flags & 0x0200) {
const encryptVer = view.getUint8(pos);
pos += 1;
console.log('EncryptVer: ' + encryptVer);
}
} else if (type === 0x74) { // File header
const packSize = view.getUint32(pos, true);
pos += 4;
const unpSize = view.getUint32(pos, true);
pos += 4;
const hostOS = view.getUint8(pos);
pos += 1;
const fileCRC = view.getUint32(pos, true);
pos += 4;
const fileTime = view.getUint32(pos, true);
pos += 4;
const unpVer = view.getUint8(pos);
pos += 1;
const method = view.getUint8(pos);
pos += 1;
const nameSize = view.getUint16(pos, true);
pos += 2;
const fileAttr = view.getUint32(pos, true);
pos += 4;
console.log('PackSize: ' + packSize);
console.log('UnpSize: ' + unpSize);
console.log('HostOS: ' + hostOS);
console.log('FileCRC: 0x' + fileCRC.toString(16));
console.log('FileTime: ' + fileTime);
console.log('UnpVer: ' + unpVer);
console.log('Method: 0x' + method.toString(16));
console.log('NameSize: ' + nameSize);
console.log('FileAttr: 0x' + fileAttr.toString(16));
if (flags & 0x0100) {
const highPackSize = view.getUint32(pos, true);
pos += 4;
const highUnpSize = view.getUint32(pos, true);
pos += 4;
console.log('HighPackSize: ' + highPackSize);
console.log('HighUnpSize: ' + highUnpSize);
}
const fileName = new TextDecoder().decode(this.data.subarray(pos, pos + nameSize));
pos += nameSize;
console.log('FileName: ' + fileName);
if (flags & 0x0400) {
sb = '';
for (let i = 0; i < 8; i++) sb += view.getUint8(pos++).toString(16).padStart(2, '0') + ' ';
console.log('Salt: ' + sb.trim());
}
if (flags & 0x1000) {
const extFlags = view.getUint16(pos, true);
pos += 2;
console.log('ExtTime Flags: 0x' + extFlags.toString(16));
// Further parsing omitted
}
}
pos += size - 7 - (flags & 0x8000 ? 4 : 0);
}
}
write(outputFilename, sampleData = Buffer.from('Hello World')) {
const sig = Buffer.from([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00]);
// Main header
const mainHeader = Buffer.alloc(13);
const mainView = new DataView(mainHeader.buffer);
mainView.setUint16(0, 0, true); // CRC
mainView.setUint8(2, 0x73); // Type
mainView.setUint16(3, 0, true); // Flags
mainView.setUint16(5, 13, true); // Size
mainView.setUint16(7, 0, true); // HighPosAV
mainView.setUint32(9, 0, true); // PosAV
mainView.setUint8(13, 0); // EncryptVer (offset adjusted)
// File header
const name = Buffer.from('sample.txt');
const headerSize = 32 + name.length;
const fileHeader = Buffer.alloc(headerSize);
const fileView = new DataView(fileHeader.buffer);
fileView.setUint16(0, 0, true); // CRC
fileView.setUint8(2, 0x74); // Type
fileView.setUint16(3, 0, true); // Flags
fileView.setUint16(5, headerSize, true); // Size
fileView.setUint32(7, sampleData.length, true); // PackSize
fileView.setUint32(11, sampleData.length, true); // UnpSize
fileView.setUint8(15, 2); // HostOS
fileView.setUint32(16, 0, true); // FileCRC
fileView.setUint32(20, 0, true); // FileTime
fileView.setUint8(24, 29); // UnpVer
fileView.setUint8(25, 0x30); // Method
fileView.setUint16(26, name.length, true); // NameSize
fileView.setUint32(28, 0, true); // FileAttr
name.copy(fileHeader, 32);
const fullData = Buffer.concat([sig, mainHeader, fileHeader, sampleData]);
fs.writeFileSync(outputFilename, fullData);
console.log(`Wrote sample .R01 to ${outputFilename}`);
}
}
7. C Class for .R01 File
Here is a C++ class that can open, decode, read, write, and print the properties from a .R01 file.
#include <fstream>
#include <iostream>
#include <vector>
#include <iomanip>
class R01Handler {
private:
std::string filename;
std::vector<unsigned char> data;
public:
R01Handler(const std::string& fn) : filename(fn) {}
void read() {
std::ifstream file(filename, std::ios::binary);
if (file) {
data = std::vector<unsigned char>((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
}
}
void decodeAndPrint() {
if (data.empty()) read();
size_t pos = 0;
std::cout << "Magic Signature: ";
for (int i = 0; i < 7; ++i) std::cout << std::hex << std::setfill('0') << std::setw(2) << (int)data[pos++] << " ";
std::cout << std::dec << std::endl;
while (pos < data.size()) {
unsigned short crc16 = *(unsigned short*)(&data[pos]);
pos += 2;
unsigned char type = data[pos++];
unsigned short flags = *(unsigned short*)(&data[pos]);
pos += 2;
unsigned short size = *(unsigned short*)(&data[pos]);
pos += 2;
std::cout << "Header CRC16: 0x" << std::hex << crc16 << std::dec << std::endl;
std::cout << "Header Type: 0x" << std::hex << (int)type << std::dec << std::endl;
std::cout << "Header Flags: 0x" << std::hex << flags << std::dec << std::endl;
std::cout << "Header Size: " << size << std::endl;
if (flags & 0x8000) {
unsigned int addSize = *(unsigned int*)(&data[pos]);
pos += 4;
std::cout << "Add Size: " << addSize << std::endl;
}
if (type == 0x73) { // Main header
unsigned short highPosAv = *(unsigned short*)(&data[pos]);
pos += 2;
unsigned int posAv = *(unsigned int*)(&data[pos]);
pos += 4;
std::cout << "HighPosAV: " << highPosAv << std::endl;
std::cout << "PosAV: " << posAv << std::endl;
if (flags & 0x0200) {
unsigned char encryptVer = data[pos++];
std::cout << "EncryptVer: " << (int)encryptVer << std::endl;
}
} else if (type == 0x74) { // File header
unsigned int packSize = *(unsigned int*)(&data[pos]);
pos += 4;
unsigned int unpSize = *(unsigned int*)(&data[pos]);
pos += 4;
unsigned char hostOS = data[pos++];
unsigned int fileCRC = *(unsigned int*)(&data[pos]);
pos += 4;
unsigned int fileTime = *(unsigned int*)(&data[pos]);
pos += 4;
unsigned char unpVer = data[pos++];
unsigned char method = data[pos++];
unsigned short nameSize = *(unsigned short*)(&data[pos]);
pos += 2;
unsigned int fileAttr = *(unsigned int*)(&data[pos]);
pos += 4;
std::cout << "PackSize: " << packSize << std::endl;
std::cout << "UnpSize: " << unpSize << std::endl;
std::cout << "HostOS: " << (int)hostOS << std::endl;
std::cout << "FileCRC: 0x" << std::hex << fileCRC << std::dec << std::endl;
std::cout << "FileTime: " << fileTime << std::endl;
std::cout << "UnpVer: " << (int)unpVer << std::endl;
std::cout << "Method: 0x" << std::hex << (int)method << std::dec << std::endl;
std::cout << "NameSize: " << nameSize << std::endl;
std::cout << "FileAttr: 0x" << std::hex << fileAttr << std::dec << std::endl;
if (flags & 0x0100) {
unsigned int highPackSize = *(unsigned int*)(&data[pos]);
pos += 4;
unsigned int highUnpSize = *(unsigned int*)(&data[pos]);
pos += 4;
std::cout << "HighPackSize: " << highPackSize << std::endl;
std::cout << "HighUnpSize: " << highUnpSize << std::endl;
}
std::string fileName(data.begin() + pos, data.begin() + pos + nameSize);
pos += nameSize;
std::cout << "FileName: " << fileName << std::endl;
if (flags & 0x0400) {
std::cout << "Salt: ";
for (int i = 0; i < 8; ++i) std::cout << std::hex << std::setfill('0') << std::setw(2) << (int)data[pos++] << " ";
std::cout << std::dec << std::endl;
}
if (flags & 0x1000) {
unsigned short extFlags = *(unsigned short*)(&data[pos]);
pos += 2;
std::cout << "ExtTime Flags: 0x" << std::hex << extFlags << std::dec << std::endl;
// Further parsing omitted
}
}
pos += size - 7 - ((flags & 0x8000) ? 4 : 0);
}
}
void write(const std::string& outputFilename, const std::vector<unsigned char>& sampleData) {
std::ofstream file(outputFilename, std::ios::binary);
if (!file) return;
unsigned char sig[7] = {0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00};
file.write((char*)sig, 7);
// Main header (dummy)
unsigned char mainHeader[13] = {0}; // CRC, type 0x73, flags 0, size 13, HighPosAV 0, PosAV 0, EncryptVer 0
mainHeader[2] = 0x73;
mainHeader[5] = 13; // Low byte of size
file.write((char*)mainHeader, 13);
// File header
std::string name = "sample.txt";
size_t headerSize = 32 + name.size();
std::vector<unsigned char> fileHeader(headerSize, 0);
fileHeader[2] = 0x74; // Type
*(unsigned short*)(&fileHeader[5]) = headerSize; // Size
*(unsigned int*)(&fileHeader[7]) = sampleData.size(); // PackSize
*(unsigned int*)(&fileHeader[11]) = sampleData.size(); // UnpSize
fileHeader[15] = 2; // HostOS
fileHeader[24] = 29; // UnpVer
fileHeader[25] = 0x30; // Method
*(unsigned short*)(&fileHeader[26]) = name.size(); // NameSize
name.copy((char*)&fileHeader[32], name.size());
file.write((char*)fileHeader.data(), headerSize);
file.write((char*)sampleData.data(), sampleData.size());
std::cout << "Wrote sample .R01 to " << outputFilename << std::endl;
}
};