Task 062: .BIN File Format
Task 062: .BIN File Format
1. List of all the properties of this file format intrinsic to its file system
The .BIN file format, as specified in the Hydromagic proprietary bin data file (used for storing echo return/water column data in hydrographic surveying software), has the following properties (fields) in its structure. These are intrinsic metadata fields from the two main headers in each record (the file consists of multiple such records). The properties are:
- Mask: unsigned short (2 bytes) - Bitmask describing items in the following data (must be 1 for water column data).
- Reserved (BinObject): unsigned int (4 bytes) - Reserved for future use.
- Timestamp: double (8 bytes) - Timestamp in seconds since January 1, 1970 (Unix Epoch), including milliseconds as fractional part.
- Latency: double (8 bytes) - Latency value in seconds.
- DataSize: unsigned int (4 bytes) - Number of bytes following the BinObjectHeader (includes WaterColumnHeader and sample data).
- Header (WaterColumn): char[8] (8 bytes) - ASCII header with source (e.g., "#CEE"), channel number, and units (e.g., "M" for meters, "F" for feet, "C" for centimeters).
- PingNumber: unsigned int (4 bytes) - Ping number.
- Reserved1: unsigned short (2 bytes) - Reserved for future use.
- Reserved2: unsigned int (4 bytes) - Reserved for future use.
- Depth: unsigned int (4 bytes) - Digitized depth in centimeters (for meters units) or tenths of feet (for feet units).
- Draft: unsigned short (2 bytes) - Transducer draft in centimeters (for meters) or tenths of feet (for feet).
- IndexOffset: unsigned short (2 bytes) - Index offset.
- GateHi: unsigned int (4 bytes) - High gate value.
- GateLo: unsigned int (4 bytes) - Low gate value.
- ScaleWidth: unsigned short (2 bytes) - Width of the scale (depth range) in units specified in the header.
- EndOfScale: unsigned short (2 bytes) - Maximum scale value (depth range) in units; subtract ScaleWidth for minimum.
- MotionStatus: short (2 bytes) - Motion status.
- MotionHeave: short (2 bytes) - Motion heave value.
- MotionRoll: short (2 bytes) - Motion roll value.
- MotionPitch: short (2 bytes) - Motion pitch value.
- TideCorrection: unsigned int (4 bytes) - Tide correction value.
- SampleCount: unsigned short (2 bytes) - Number of echo return samples following the header.
- SampleResolution: unsigned short (2 bytes) - Sample resolution (typically 2, indicating unsigned 16-bit values).
- SampleFrequency: unsigned int (4 bytes) - Sample frequency.
Notes:
- BinObjectHeader is in little-endian; WaterColumnHeader and sample data are in big-endian (byte swapping required on little-endian systems).
- Sample data (not listed as properties, as they are payload) follows as SampleCount * SampleResolution bytes.
2. Two direct download links for files of format .BIN
- https://filesamples.com/samples/font/bin/fontawesome-webfont.bin
- https://filesamples.com/samples/font/bin/Lato-Regular.bin
3. Ghost blog embedded HTML JavaScript for drag n drop .BIN file dump
Drag and Drop .BIN File to Dump Properties
Drop .BIN file here
4. Python class for .BIN file handling
import struct
import sys
class BinFileHandler:
def __init__(self, filename):
self.filename = filename
self.records = []
def read(self):
with open(self.filename, 'rb') as f:
while True:
# BinObjectHeader (little-endian, 24 bytes)
header_data = f.read(24)
if len(header_data) < 24:
break
mask, reserved, timestamp, latency, data_size = struct.unpack('<I d d I', header_data[0:2] + header_data[4:24]) # Skip reserved manually if needed
# Full unpack: <H I d d I (but reserved is I, adjust)
mask, reserved, timestamp, latency, data_size = struct.unpack('<H I d d I', header_data)
# WaterColumnHeader (big-endian, 58 bytes)
wc_data = f.read(58)
if len(wc_data) < 58:
break
header_str = wc_data[0:8].decode('ascii', errors='ignore')
ping_number, reserved1, reserved2, depth, draft, index_offset, gate_hi, gate_lo, scale_width, end_of_scale, motion_status, motion_heave, motion_roll, motion_pitch, tide_correction, sample_count, sample_resolution, sample_frequency = struct.unpack('>I H I I H H I I H H h h h h I H H I', wc_data[8:58])
record = {
'Mask': mask,
'Reserved (BinObject)': reserved,
'Timestamp': timestamp,
'Latency': latency,
'DataSize': data_size,
'Header (WaterColumn)': header_str,
'PingNumber': ping_number,
'Reserved1': reserved1,
'Reserved2': reserved2,
'Depth': depth,
'Draft': draft,
'IndexOffset': index_offset,
'GateHi': gate_hi,
'GateLo': gate_lo,
'ScaleWidth': scale_width,
'EndOfScale': end_of_scale,
'MotionStatus': motion_status,
'MotionHeave': motion_heave,
'MotionRoll': motion_roll,
'MotionPitch': motion_pitch,
'TideCorrection': tide_correction,
'SampleCount': sample_count,
'SampleResolution': sample_resolution,
'SampleFrequency': sample_frequency
}
self.records.append(record)
# Skip sample data
sample_bytes = sample_count * sample_resolution
f.seek(sample_bytes, 1)
def print_properties(self):
for idx, record in enumerate(self.records, 1):
print(f"Record {idx}:")
for key, value in record.items():
print(f" {key}: {value}")
print()
def write(self, output_filename):
with open(output_filename, 'wb') as f:
for record in self.records:
# Write BinObjectHeader (little-endian)
header_data = struct.pack('<H I d d I', record['Mask'], record['Reserved (BinObject)'], record['Timestamp'], record['Latency'], record['DataSize'])
f.write(header_data)
# Write WaterColumnHeader (big-endian)
wc_header = record['Header (WaterColumn)'].encode('ascii')[:8].ljust(8, b'\0')
wc_data = struct.pack('>I H I I H H I I H H h h h h I H H I',
record['PingNumber'], record['Reserved1'], record['Reserved2'], record['Depth'],
record['Draft'], record['IndexOffset'], record['GateHi'], record['GateLo'],
record['ScaleWidth'], record['EndOfScale'], record['MotionStatus'], record['MotionHeave'],
record['MotionRoll'], record['MotionPitch'], record['TideCorrection'], record['SampleCount'],
record['SampleResolution'], record['SampleFrequency'])
f.write(wc_header + wc_data)
# Note: Sample data not written here as it's not part of properties; extend if needed
# Example usage:
# handler = BinFileHandler('input.bin')
# handler.read()
# handler.print_properties()
# handler.write('output.bin')
5. Java class for .BIN file handling
import java.io.*;
import java.nio.*;
import java.util.*;
public class BinFileHandler {
private String filename;
private List<Map<String, Object>> records = new ArrayList<>();
public BinFileHandler(String filename) {
this.filename = filename;
}
public void read() throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) {
while (raf.getFilePointer() < raf.length()) {
// BinObjectHeader (little-endian, 24 bytes)
ByteBuffer bb = ByteBuffer.allocate(24);
raf.readFully(bb.array());
bb.order(ByteOrder.LITTLE_ENDIAN);
short mask = bb.getShort(0);
int reserved = bb.getInt(2);
double timestamp = bb.getDouble(6);
double latency = bb.getDouble(14);
int dataSize = bb.getInt(22);
// WaterColumnHeader (big-endian, 58 bytes)
ByteBuffer wcBb = ByteBuffer.allocate(58);
raf.readFully(wcBb.array());
wcBb.order(ByteOrder.BIG_ENDIAN);
String headerStr = new String(wcBb.array(), 0, 8, "ASCII");
int pingNumber = wcBb.getInt(8);
short reserved1 = wcBb.getShort(12);
int reserved2 = wcBb.getInt(14);
int depth = wcBb.getInt(18);
short draft = wcBb.getShort(22);
short indexOffset = wcBb.getShort(24);
int gateHi = wcBb.getInt(26);
int gateLo = wcBb.getInt(30);
short scaleWidth = wcBb.getShort(34);
short endOfScale = wcBb.getShort(36);
short motionStatus = wcBb.getShort(38);
short motionHeave = wcBb.getShort(40);
short motionRoll = wcBb.getShort(42);
short motionPitch = wcBb.getShort(44);
int tideCorrection = wcBb.getInt(46);
short sampleCount = wcBb.getShort(50);
short sampleResolution = wcBb.getShort(52);
int sampleFrequency = wcBb.getInt(54);
Map<String, Object> record = new HashMap<>();
record.put("Mask", mask);
record.put("Reserved (BinObject)", reserved);
record.put("Timestamp", timestamp);
record.put("Latency", latency);
record.put("DataSize", dataSize);
record.put("Header (WaterColumn)", headerStr);
record.put("PingNumber", pingNumber);
record.put("Reserved1", reserved1);
record.put("Reserved2", reserved2);
record.put("Depth", depth);
record.put("Draft", draft);
record.put("IndexOffset", indexOffset);
record.put("GateHi", gateHi);
record.put("GateLo", gateLo);
record.put("ScaleWidth", scaleWidth);
record.put("EndOfScale", endOfScale);
record.put("MotionStatus", motionStatus);
record.put("MotionHeave", motionHeave);
record.put("MotionRoll", motionRoll);
record.put("MotionPitch", motionPitch);
record.put("TideCorrection", tideCorrection);
record.put("SampleCount", sampleCount);
record.put("SampleResolution", sampleResolution);
record.put("SampleFrequency", sampleFrequency);
records.add(record);
// Skip sample data
int sampleBytes = sampleCount * sampleResolution;
raf.seek(raf.getFilePointer() + sampleBytes);
}
}
}
public void printProperties() {
for (int i = 0; i < records.size(); i++) {
System.out.println("Record " + (i + 1) + ":");
Map<String, Object> record = records.get(i);
for (Map.Entry<String, Object> entry : record.entrySet()) {
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
}
System.out.println();
}
}
public void write(String outputFilename) throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(outputFilename, "rw")) {
for (Map<String, Object> record : records) {
// Write BinObjectHeader (little-endian)
ByteBuffer bb = ByteBuffer.allocate(24);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.putShort((short) record.get("Mask"));
bb.putInt((int) record.get("Reserved (BinObject)"));
bb.putDouble((double) record.get("Timestamp"));
bb.putDouble((double) record.get("Latency"));
bb.putInt((int) record.get("DataSize"));
raf.write(bb.array());
// Write WaterColumnHeader (big-endian)
ByteBuffer wcBb = ByteBuffer.allocate(58);
wcBb.order(ByteOrder.BIG_ENDIAN);
String headerStr = (String) record.get("Header (WaterColumn)");
wcBb.put(headerStr.getBytes("ASCII"), 0, Math.min(8, headerStr.length()));
wcBb.putInt(8, (int) record.get("PingNumber"));
wcBb.putShort(12, (short) record.get("Reserved1"));
wcBb.putInt(14, (int) record.get("Reserved2"));
wcBb.putInt(18, (int) record.get("Depth"));
wcBb.putShort(22, (short) record.get("Draft"));
wcBb.putShort(24, (short) record.get("IndexOffset"));
wcBb.putInt(26, (int) record.get("GateHi"));
wcBb.putInt(30, (int) record.get("GateLo"));
wcBb.putShort(34, (short) record.get("ScaleWidth"));
wcBb.putShort(36, (short) record.get("EndOfScale"));
wcBb.putShort(38, (short) record.get("MotionStatus"));
wcBb.putShort(40, (short) record.get("MotionHeave"));
wcBb.putShort(42, (short) record.get("MotionRoll"));
wcBb.putShort(44, (short) record.get("MotionPitch"));
wcBb.putInt(46, (int) record.get("TideCorrection"));
wcBb.putShort(50, (short) record.get("SampleCount"));
wcBb.putShort(52, (short) record.get("SampleResolution"));
wcBb.putInt(54, (int) record.get("SampleFrequency"));
raf.write(wcBb.array());
// Note: Sample data not written; extend if needed
}
}
}
// Example usage:
// public static void main(String[] args) throws IOException {
// BinFileHandler handler = new BinFileHandler("input.bin");
// handler.read();
// handler.printProperties();
// handler.write("output.bin");
// }
}
6. JavaScript class for .BIN file handling (Node.js, requires fs module)
const fs = require('fs');
class BinFileHandler {
constructor(filename) {
this.filename = filename;
this.records = [];
}
read() {
const buffer = fs.readFileSync(this.filename);
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.length);
let offset = 0;
while (offset < buffer.length) {
// BinObjectHeader (little-endian)
const mask = view.getUint16(offset, true);
offset += 2;
const reserved = view.getUint32(offset, true);
offset += 4;
const timestamp = view.getFloat64(offset, true);
offset += 8;
const latency = view.getFloat64(offset, true);
offset += 8;
const dataSize = view.getUint32(offset, true);
offset += 4;
if (offset + 58 > buffer.length) break;
// WaterColumnHeader (big-endian)
let headerStr = '';
for (let i = 0; i < 8; i++) {
headerStr += String.fromCharCode(view.getUint8(offset + i));
}
offset += 8;
const pingNumber = view.getUint32(offset, false);
offset += 4;
const reserved1 = view.getUint16(offset, false);
offset += 2;
const reserved2 = view.getUint32(offset, false);
offset += 4;
const depth = view.getUint32(offset, false);
offset += 4;
const draft = view.getUint16(offset, false);
offset += 2;
const indexOffset = view.getUint16(offset, false);
offset += 2;
const gateHi = view.getUint32(offset, false);
offset += 4;
const gateLo = view.getUint32(offset, false);
offset += 4;
const scaleWidth = view.getUint16(offset, false);
offset += 2;
const endOfScale = view.getUint16(offset, false);
offset += 2;
const motionStatus = view.getInt16(offset, false);
offset += 2;
const motionHeave = view.getInt16(offset, false);
offset += 2;
const motionRoll = view.getInt16(offset, false);
offset += 2;
const motionPitch = view.getInt16(offset, false);
offset += 2;
const tideCorrection = view.getUint32(offset, false);
offset += 4;
const sampleCount = view.getUint16(offset, false);
offset += 2;
const sampleResolution = view.getUint16(offset, false);
offset += 2;
const sampleFrequency = view.getUint32(offset, false);
offset += 4;
const record = {
'Mask': mask,
'Reserved (BinObject)': reserved,
'Timestamp': timestamp,
'Latency': latency,
'DataSize': dataSize,
'Header (WaterColumn)': headerStr,
'PingNumber': pingNumber,
'Reserved1': reserved1,
'Reserved2': reserved2,
'Depth': depth,
'Draft': draft,
'IndexOffset': indexOffset,
'GateHi': gateHi,
'GateLo': gateLo,
'ScaleWidth': scaleWidth,
'EndOfScale': endOfScale,
'MotionStatus': motionStatus,
'MotionHeave': motionHeave,
'MotionRoll': motionRoll,
'MotionPitch': motionPitch,
'TideCorrection': tideCorrection,
'SampleCount': sampleCount,
'SampleResolution': sampleResolution,
'SampleFrequency': sampleFrequency
};
this.records.push(record);
// Skip sample data
const sampleBytes = sampleCount * sampleResolution;
offset += sampleBytes;
}
}
printProperties() {
this.records.forEach((record, idx) => {
console.log(`Record ${idx + 1}:`);
Object.entries(record).forEach(([key, value]) => {
console.log(` ${key}: ${value}`);
});
console.log('');
});
}
write(outputFilename) {
let bufferLength = 0;
this.records.forEach(() => bufferLength += 24 + 58); // Headers only
const buffer = Buffer.alloc(bufferLength);
const view = new DataView(buffer.buffer);
let offset = 0;
this.records.forEach((record) => {
// BinObjectHeader (little-endian)
view.setUint16(offset, record['Mask'], true);
offset += 2;
view.setUint32(offset, record['Reserved (BinObject)'], true);
offset += 4;
view.setFloat64(offset, record['Timestamp'], true);
offset += 8;
view.setFloat64(offset, record['Latency'], true);
offset += 8;
view.setUint32(offset, record['DataSize'], true);
offset += 4;
// WaterColumnHeader (big-endian)
const headerBytes = Buffer.from(record['Header (WaterColumn)'], 'ascii').slice(0, 8);
for (let i = 0; i < 8; i++) {
view.setUint8(offset + i, headerBytes[i] || 0);
}
offset += 8;
view.setUint32(offset, record['PingNumber'], false);
offset += 4;
view.setUint16(offset, record['Reserved1'], false);
offset += 2;
view.setUint32(offset, record['Reserved2'], false);
offset += 4;
view.setUint32(offset, record['Depth'], false);
offset += 4;
view.setUint16(offset, record['Draft'], false);
offset += 2;
view.setUint16(offset, record['IndexOffset'], false);
offset += 2;
view.setUint32(offset, record['GateHi'], false);
offset += 4;
view.setUint32(offset, record['GateLo'], false);
offset += 4;
view.setUint16(offset, record['ScaleWidth'], false);
offset += 2;
view.setUint16(offset, record['EndOfScale'], false);
offset += 2;
view.setInt16(offset, record['MotionStatus'], false);
offset += 2;
view.setInt16(offset, record['MotionHeave'], false);
offset += 2;
view.setInt16(offset, record['MotionRoll'], false);
offset += 2;
view.setInt16(offset, record['MotionPitch'], false);
offset += 2;
view.setUint32(offset, record['TideCorrection'], false);
offset += 4;
view.setUint16(offset, record['SampleCount'], false);
offset += 2;
view.setUint16(offset, record['SampleResolution'], false);
offset += 2;
view.setUint32(offset, record['SampleFrequency'], false);
offset += 4;
});
fs.writeFileSync(outputFilename, buffer);
// Note: Sample data not written
}
}
// Example usage:
// const handler = new BinFileHandler('input.bin');
// handler.read();
// handler.printProperties();
// handler.write('output.bin');
7. C class for .BIN file handling (using C++ for class support)
#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <cstring>
#include <algorithm>
#include <cstdint>
class BinFileHandler {
private:
std::string filename;
std::vector<std::map<std::string, double>> records; // Use double for simplicity, cast as needed
public:
BinFileHandler(const std::string& fn) : filename(fn) {}
void read() {
std::ifstream file(filename, std::ios::binary);
if (!file) return;
while (file) {
// BinObjectHeader (little-endian, 24 bytes)
uint16_t mask;
uint32_t reserved;
double timestamp;
double latency;
uint32_t dataSize;
file.read(reinterpret_cast<char*>(&mask), sizeof(mask));
file.read(reinterpret_cast<char*>(&reserved), sizeof(reserved));
file.read(reinterpret_cast<char*>(×tamp), sizeof(timestamp));
file.read(reinterpret_cast<char*>(&latency), sizeof(latency));
file.read(reinterpret_cast<char*>(&dataSize), sizeof(dataSize));
if (file.gcount() < sizeof(dataSize)) break;
// WaterColumnHeader (big-endian, 58 bytes)
char headerStr[9] = {0};
file.read(headerStr, 8);
uint32_t pingNumber = 0;
file.read(reinterpret_cast<char*>(&pingNumber), 4);
std::reverse(reinterpret_cast<char*>(&pingNumber), reinterpret_cast<char*>(&pingNumber) + 4);
uint16_t reserved1 = 0;
file.read(reinterpret_cast<char*>(&reserved1), 2);
std::reverse(reinterpret_cast<char*>(&reserved1), reinterpret_cast<char*>(&reserved1) + 2);
uint32_t reserved2 = 0;
file.read(reinterpret_cast<char*>(&reserved2), 4);
std::reverse(reinterpret_cast<char*>(&reserved2), reinterpret_cast<char*>(&reserved2) + 4);
uint32_t depth = 0;
file.read(reinterpret_cast<char*>(&depth), 4);
std::reverse(reinterpret_cast<char*>(&depth), reinterpret_cast<char*>(&depth) + 4);
uint16_t draft = 0;
file.read(reinterpret_cast<char*>(&draft), 2);
std::reverse(reinterpret_cast<char*>(&draft), reinterpret_cast<char*>(&draft) + 2);
uint16_t indexOffset = 0;
file.read(reinterpret_cast<char*>(&indexOffset), 2);
std::reverse(reinterpret_cast<char*>(&indexOffset), reinterpret_cast<char*>(&indexOffset) + 2);
uint32_t gateHi = 0;
file.read(reinterpret_cast<char*>(&gateHi), 4);
std::reverse(reinterpret_cast<char*>(&gateHi), reinterpret_cast<char*>(&gateHi) + 4);
uint32_t gateLo = 0;
file.read(reinterpret_cast<char*>(&gateLo), 4);
std::reverse(reinterpret_cast<char*>(&gateLo), reinterpret_cast<char*>(&gateLo) + 4);
uint16_t scaleWidth = 0;
file.read(reinterpret_cast<char*>(&scaleWidth), 2);
std::reverse(reinterpret_cast<char*>(&scaleWidth), reinterpret_cast<char*>(&scaleWidth) + 2);
uint16_t endOfScale = 0;
file.read(reinterpret_cast<char*>(&endOfScale), 2);
std::reverse(reinterpret_cast<char*>(&endOfScale), reinterpret_cast<char*>(&endOfScale) + 2);
int16_t motionStatus = 0;
file.read(reinterpret_cast<char*>(&motionStatus), 2);
std::reverse(reinterpret_cast<char*>(&motionStatus), reinterpret_cast<char*>(&motionStatus) + 2);
int16_t motionHeave = 0;
file.read(reinterpret_cast<char*>(&motionHeave), 2);
std::reverse(reinterpret_cast<char*>(&motionHeave), reinterpret_cast<char*>(&motionHeave) + 2);
int16_t motionRoll = 0;
file.read(reinterpret_cast<char*>(&motionRoll), 2);
std::reverse(reinterpret_cast<char*>(&motionRoll), reinterpret_cast<char*>(&motionRoll) + 2);
int16_t motionPitch = 0;
file.read(reinterpret_cast<char*>(&motionPitch), 2);
std::reverse(reinterpret_cast<char*>(&motionPitch), reinterpret_cast<char*>(&motionPitch) + 2);
uint32_t tideCorrection = 0;
file.read(reinterpret_cast<char*>(&tideCorrection), 4);
std::reverse(reinterpret_cast<char*>(&tideCorrection), reinterpret_cast<char*>(&tideCorrection) + 4);
uint16_t sampleCount = 0;
file.read(reinterpret_cast<char*>(&sampleCount), 2);
std::reverse(reinterpret_cast<char*>(&sampleCount), reinterpret_cast<char*>(&sampleCount) + 2);
uint16_t sampleResolution = 0;
file.read(reinterpret_cast<char*>(&sampleResolution), 2);
std::reverse(reinterpret_cast<char*>(&sampleResolution), reinterpret_cast<char*>(&sampleResolution) + 2);
uint32_t sampleFrequency = 0;
file.read(reinterpret_cast<char*>(&sampleFrequency), 4);
std::reverse(reinterpret_cast<char*>(&sampleFrequency), reinterpret_cast<char*>(&sampleFrequency) + 4);
if (file.gcount() < 4) break;
std::map<std::string, double> record;
record["Mask"] = mask;
record["Reserved (BinObject)"] = reserved;
record["Timestamp"] = timestamp;
record["Latency"] = latency;
record["DataSize"] = dataSize;
record["Header (WaterColumn)"] = 0; // String not stored as double; handle separately if needed
record["PingNumber"] = pingNumber;
record["Reserved1"] = reserved1;
record["Reserved2"] = reserved2;
record["Depth"] = depth;
record["Draft"] = draft;
record["IndexOffset"] = indexOffset;
record["GateHi"] = gateHi;
record["GateLo"] = gateLo;
record["ScaleWidth"] = scaleWidth;
record["EndOfScale"] = endOfScale;
record["MotionStatus"] = motionStatus;
record["MotionHeave"] = motionHeave;
record["MotionRoll"] = motionRoll;
record["MotionPitch"] = motionPitch;
record["TideCorrection"] = tideCorrection;
record["SampleCount"] = sampleCount;
record["SampleResolution"] = sampleResolution;
record["SampleFrequency"] = sampleFrequency;
records.push_back(record);
// Skip sample data
uint32_t sampleBytes = sampleCount * sampleResolution;
file.seekg(sampleBytes, std::ios::cur);
}
}
void printProperties() {
for (size_t i = 0; i < records.size(); ++i) {
std::cout << "Record " << (i + 1) << ":" << std::endl;
for (const auto& entry : records[i]) {
std::cout << " " << entry.first << ": " << entry.second << std::endl;
}
std::cout << std::endl;
}
}
void write(const std::string& outputFilename) {
std::ofstream file(outputFilename, std::ios::binary);
if (!file) return;
for (const auto& record : records) {
// Write BinObjectHeader (little-endian)
uint16_t mask = static_cast<uint16_t>(record.at("Mask"));
uint32_t reserved = static_cast<uint32_t>(record.at("Reserved (BinObject)"));
double timestamp = record.at("Timestamp");
double latency = record.at("Latency");
uint32_t dataSize = static_cast<uint32_t>(record.at("DataSize"));
file.write(reinterpret_cast<const char*>(&mask), sizeof(mask));
file.write(reinterpret_cast<const char*>(&reserved), sizeof(reserved));
file.write(reinterpret_cast<const char*>(×tamp), sizeof(timestamp));
file.write(reinterpret_cast<const char*>(&latency), sizeof(latency));
file.write(reinterpret_cast<const char*>(&dataSize), sizeof(dataSize));
// Write WaterColumnHeader (big-endian)
char headerStr[8] = {0}; // Placeholder, extend for string
file.write(headerStr, 8);
uint32_t pingNumber = static_cast<uint32_t>(record.at("PingNumber"));
std::reverse(reinterpret_cast<char*>(&pingNumber), reinterpret_cast<char*>(&pingNumber) + 4);
file.write(reinterpret_cast<const char*>(&pingNumber), 4);
uint16_t reserved1 = static_cast<uint16_t>(record.at("Reserved1"));
std::reverse(reinterpret_cast<char*>(&reserved1), reinterpret_cast<char*>(&reserved1) + 2);
file.write(reinterpret_cast<const char*>(&reserved1), 2);
uint32_t reserved2 = static_cast<uint32_t>(record.at("Reserved2"));
std::reverse(reinterpret_cast<char*>(&reserved2), reinterpret_cast<char*>(&reserved2) + 4);
file.write(reinterpret_cast<const char*>(&reserved2), 4);
uint32_t depth = static_cast<uint32_t>(record.at("Depth"));
std::reverse(reinterpret_cast<char*>(&depth), reinterpret_cast<char*>(&depth) + 4);
file.write(reinterpret_cast<const char*>(&depth), 4);
uint16_t draft = static_cast<uint16_t>(record.at("Draft"));
std::reverse(reinterpret_cast<char*>(&draft), reinterpret_cast<char*>(&draft) + 2);
file.write(reinterpret_cast<const char*>(&draft), 2);
uint16_t indexOffset = static_cast<uint16_t>(record.at("IndexOffset"));
std::reverse(reinterpret_cast<char*>(&indexOffset), reinterpret_cast<char*>(&indexOffset) + 2);
file.write(reinterpret_cast<const char*>(&indexOffset), 2);
uint32_t gateHi = static_cast<uint32_t>(record.at("GateHi"));
std::reverse(reinterpret_cast<char*>(&gateHi), reinterpret_cast<char*>(&gateHi) + 4);
file.write(reinterpret_cast<const char*>(&gateHi), 4);
uint32_t gateLo = static_cast<uint32_t>(record.at("GateLo"));
std::reverse(reinterpret_cast<char*>(&gateLo), reinterpret_cast<char*>(&gateLo) + 4);
file.write(reinterpret_cast<const char*>(&gateLo), 4);
uint16_t scaleWidth = static_cast<uint16_t>(record.at("ScaleWidth"));
std::reverse(reinterpret_cast<char*>(&scaleWidth), reinterpret_cast<char*>(&scaleWidth) + 2);
file.write(reinterpret_cast<const char*>(&scaleWidth), 2);
uint16_t endOfScale = static_cast<uint16_t>(record.at("EndOfScale"));
std::reverse(reinterpret_cast<char*>(&endOfScale), reinterpret_cast<char*>(&endOfScale) + 2);
file.write(reinterpret_cast<const char*>(&endOfScale), 2);
int16_t motionStatus = static_cast<int16_t>(record.at("MotionStatus"));
std::reverse(reinterpret_cast<char*>(&motionStatus), reinterpret_cast<char*>(&motionStatus) + 2);
file.write(reinterpret_cast<const char*>(&motionStatus), 2);
int16_t motionHeave = static_cast<int16_t>(record.at("MotionHeave"));
std::reverse(reinterpret_cast<char*>(&motionHeave), reinterpret_cast<char*>(&motionHeave) + 2);
file.write(reinterpret_cast<const char*>(&motionHeave), 2);
int16_t motionRoll = static_cast<int16_t>(record.at("MotionRoll"));
std::reverse(reinterpret_cast<char*>(&motionRoll), reinterpret_cast<char*>(&motionRoll) + 2);
file.write(reinterpret_cast<const char*>(&motionRoll), 2);
int16_t motionPitch = static_cast<int16_t>(record.at("MotionPitch"));
std::reverse(reinterpret_cast<char*>(&motionPitch), reinterpret_cast<char*>(&motionPitch) + 2);
file.write(reinterpret_cast<const char*>(&motionPitch), 2);
uint32_t tideCorrection = static_cast<uint32_t>(record.at("TideCorrection"));
std::reverse(reinterpret_cast<char*>(&tideCorrection), reinterpret_cast<char*>(&tideCorrection) + 4);
file.write(reinterpret_cast<const char*>(&tideCorrection), 4);
uint16_t sampleCount = static_cast<uint16_t>(record.at("SampleCount"));
std::reverse(reinterpret_cast<char*>(&sampleCount), reinterpret_cast<char*>(&sampleCount) + 2);
file.write(reinterpret_cast<const char*>(&sampleCount), 2);
uint16_t sampleResolution = static_cast<uint16_t>(record.at("SampleResolution"));
std::reverse(reinterpret_cast<char*>(&sampleResolution), reinterpret_cast<char*>(&sampleResolution) + 2);
file.write(reinterpret_cast<const char*>(&sampleResolution), 2);
uint32_t sampleFrequency = static_cast<uint32_t>(record.at("SampleFrequency"));
std::reverse(reinterpret_cast<char*>(&sampleFrequency), reinterpret_cast<char*>(&sampleFrequency) + 4);
file.write(reinterpret_cast<const char*>(&sampleFrequency), 4);
// Note: Sample data not written
}
}
};
// Example usage:
// int main() {
// BinFileHandler handler("input.bin");
// handler.read();
// handler.printProperties();
// handler.write("output.bin");
// return 0;
// }