133 lines
3.5 KiB
C++
Raw Normal View History

2022-12-06 14:52:42 +01:00
#include "riff.h"
#include <stdexcept>
namespace riff {
2023-01-01 03:20:49 +01:00
const char* RIFF_SIGNATURE = "RIFF";
const char* LIST_SIGNATURE = "LIST";
const size_t RIFF_LABEL_SIZE = 4;
2022-12-06 14:52:42 +01:00
2023-01-01 03:20:49 +01:00
bool Writer::open(std::string path, const char form[4]) {
std::lock_guard<std::recursive_mutex> lck(mtx);
// Open file
file = std::ofstream(path, std::ios::out | std::ios::binary);
if (!file.is_open()) { return false; }
// Begin RIFF chunk
2022-12-06 14:52:42 +01:00
beginRIFF(form);
2023-01-01 03:20:49 +01:00
return true;
2022-12-06 14:52:42 +01:00
}
bool Writer::isOpen() {
2023-01-01 03:20:49 +01:00
std::lock_guard<std::recursive_mutex> lck(mtx);
return file.is_open();
2022-12-06 14:52:42 +01:00
}
void Writer::close() {
2023-01-01 03:20:49 +01:00
std::lock_guard<std::recursive_mutex> lck(mtx);
2022-12-06 14:52:42 +01:00
if (!isOpen()) { return; }
2023-01-01 03:20:49 +01:00
// Finalize RIFF chunk
2022-12-06 14:52:42 +01:00
endRIFF();
2023-01-01 03:20:49 +01:00
// Close file
2022-12-06 14:52:42 +01:00
file.close();
}
2023-01-01 03:20:49 +01:00
void Writer::beginList(const char id[4]) {
std::lock_guard<std::recursive_mutex> lck(mtx);
// Create chunk with the LIST ID and write id
beginChunk(LIST_SIGNATURE);
write((uint8_t*)id, RIFF_LABEL_SIZE);
}
void Writer::endList() {
std::lock_guard<std::recursive_mutex> lck(mtx);
if (chunks.empty()) {
throw std::runtime_error("No chunk to end");
}
if (memcmp(chunks.top().hdr.id, LIST_SIGNATURE, RIFF_LABEL_SIZE)) {
throw std::runtime_error("Top chunk not LIST chunk");
}
endChunk();
}
void Writer::beginChunk(const char id[4]) {
std::lock_guard<std::recursive_mutex> lck(mtx);
2022-12-06 14:52:42 +01:00
// Create and write header
ChunkDesc desc;
desc.pos = file.tellp();
memcpy(desc.hdr.id, id, sizeof(desc.hdr.id));
desc.hdr.size = 0;
file.write((char*)&desc.hdr, sizeof(ChunkHeader));
// Save descriptor
chunks.push(desc);
}
void Writer::endChunk() {
2023-01-01 03:20:49 +01:00
std::lock_guard<std::recursive_mutex> lck(mtx);
if (chunks.empty()) {
2022-12-06 14:52:42 +01:00
throw std::runtime_error("No chunk to end");
}
// Get descriptor
ChunkDesc desc = chunks.top();
chunks.pop();
// Write size
auto pos = file.tellp();
2023-01-01 03:20:49 +01:00
auto npos = desc.pos;
npos += 4;
file.seekp(npos);
2022-12-06 14:52:42 +01:00
file.write((char*)&desc.hdr.size, sizeof(desc.hdr.size));
file.seekp(pos);
// If parent chunk, increment its size
if (!chunks.empty()) {
chunks.top().hdr.size += desc.hdr.size;
}
}
2023-01-01 03:20:49 +01:00
void Writer::write(const uint8_t* data, size_t len) {
std::lock_guard<std::recursive_mutex> lck(mtx);
if (chunks.empty()) {
2022-12-06 14:52:42 +01:00
throw std::runtime_error("No chunk to write into");
}
file.write((char*)data, len);
chunks.top().hdr.size += len;
}
2023-01-01 03:20:49 +01:00
void Writer::beginRIFF(const char form[4]) {
std::lock_guard<std::recursive_mutex> lck(mtx);
2022-12-06 14:52:42 +01:00
if (!chunks.empty()) {
throw std::runtime_error("Can't create RIFF chunk on an existing RIFF file");
}
// Create chunk with RIFF ID and write form
2023-01-01 03:20:49 +01:00
beginChunk(RIFF_SIGNATURE);
write((uint8_t*)form, RIFF_LABEL_SIZE);
2022-12-06 14:52:42 +01:00
}
void Writer::endRIFF() {
2023-01-01 03:20:49 +01:00
std::lock_guard<std::recursive_mutex> lck(mtx);
if (chunks.empty()) {
2022-12-06 14:52:42 +01:00
throw std::runtime_error("No chunk to end");
}
2023-01-01 03:20:49 +01:00
if (memcmp(chunks.top().hdr.id, RIFF_SIGNATURE, RIFF_LABEL_SIZE)) {
2022-12-06 14:52:42 +01:00
throw std::runtime_error("Top chunk not RIFF chunk");
}
2023-01-01 03:20:49 +01:00
2022-12-06 14:52:42 +01:00
endChunk();
}
}