5.3 KiB
5.3 KiB
WASM Patch Export Documentation
Overview
The WASM patch export functionality allows users to export their ROM modifications as BPS or IPS patch files directly from the browser. This enables sharing modifications without distributing copyrighted ROM data.
Features
Supported Formats
BPS (Beat Patch Format)
- Modern patch format with advanced features
- Variable-length encoding for efficient storage
- Delta encoding for changed regions
- CRC32 checksums for validation
- No size limitations
- Better compression than IPS
IPS (International Patching System)
- Classic patch format with wide compatibility
- Simple record-based structure
- RLE encoding for repeated bytes
- Maximum file size of 16MB (24-bit addressing)
- Widely supported by emulators and patching tools
API
#include "app/platform/wasm/wasm_patch_export.h"
// Export as BPS patch
absl::Status status = WasmPatchExport::ExportBPS(
original_rom_data, // std::vector<uint8_t>
modified_rom_data, // std::vector<uint8_t>
"my_hack.bps" // filename
);
// Export as IPS patch
absl::Status status = WasmPatchExport::ExportIPS(
original_rom_data,
modified_rom_data,
"my_hack.ips"
);
// Get preview of changes
PatchInfo info = WasmPatchExport::GetPatchPreview(
original_rom_data,
modified_rom_data
);
// info.changed_bytes - total bytes changed
// info.num_regions - number of distinct regions
// info.changed_regions - vector of (offset, length) pairs
Implementation Details
BPS Format Structure
Header:
- "BPS1" magic (4 bytes)
- Source size (variable-length)
- Target size (variable-length)
- Metadata size (variable-length, 0 for no metadata)
Patch Data:
- Actions encoded as variable-length integers
- SourceRead: Copy from source (action = (length-1) << 2)
- TargetRead: Copy from patch (action = ((length-1) << 2) | 1)
Footer:
- Source CRC32 (4 bytes, little-endian)
- Target CRC32 (4 bytes, little-endian)
- Patch CRC32 (4 bytes, little-endian)
IPS Format Structure
Header:
- "PATCH" (5 bytes)
Records (repeating):
Normal Record:
- Offset (3 bytes, big-endian)
- Size (2 bytes, big-endian, non-zero)
- Data (size bytes)
RLE Record:
- Offset (3 bytes, big-endian)
- Size (2 bytes, always 0x0000)
- Run length (2 bytes, big-endian)
- Value (1 byte)
Footer:
- "EOF" (3 bytes)
Browser Integration
The patch files are downloaded using the HTML5 Blob API:
- Patch data is generated in C++
- Data is passed to JavaScript via EM_JS
- JavaScript creates a Blob with the binary data
- Object URL is created from the Blob
- Hidden anchor element triggers download
- Cleanup occurs after download starts
// Simplified download flow
var blob = new Blob([patchData], { type: 'application/octet-stream' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
Usage in Yaze Editor
Menu Integration
Add to MenuOrchestrator or RomFileManager:
if (ImGui::BeginMenu("File")) {
if (ImGui::BeginMenu("Export", rom_->is_loaded())) {
if (ImGui::MenuItem("Export BPS Patch...")) {
ShowPatchExportDialog(PatchFormat::BPS);
}
if (ImGui::MenuItem("Export IPS Patch...")) {
ShowPatchExportDialog(PatchFormat::IPS);
}
ImGui::EndMenu();
}
ImGui::EndMenu();
}
Tracking Original ROM State
To generate patches, the ROM class needs to track both original and modified states:
class Rom {
std::vector<uint8_t> original_data_; // Preserve original
std::vector<uint8_t> data_; // Working copy
public:
void LoadFromFile(const std::string& filename) {
// Load data...
original_data_ = data_; // Save original state
}
const std::vector<uint8_t>& original_data() const {
return original_data_;
}
};
Testing
Unit Tests
# Run patch export tests
./build/bin/yaze_test --gtest_filter="*WasmPatchExport*"
Manual Testing in Browser
- Build for WASM:
emcc ... -s ENVIRONMENT=web - Load a ROM in the web app
- Make modifications
- Use File → Export → Export BPS/IPS Patch
- Verify patch downloads correctly
- Test patch with external patching tool
Limitations
IPS Format
- Maximum ROM size: 16MB (0xFFFFFF bytes)
- No checksum validation
- Less efficient compression than BPS
- No metadata support
BPS Format
- Requires more complex implementation
- Less tool support than IPS
- Larger patch size for small changes
Browser Constraints
- Download triggered via user action only
- No direct filesystem access
- Patch must fit in browser memory
- Download folder determined by browser
Error Handling
Common errors and solutions:
| Error | Cause | Solution |
|---|---|---|
| Empty ROM data | No ROM loaded | Check rom->is_loaded() first |
| IPS size limit | ROM > 16MB | Use BPS format instead |
| No changes | Original = Modified | Show warning to user |
| Download failed | Browser restrictions | Ensure user-triggered action |
Future Enhancements
Potential improvements:
- UPS (Universal Patching Standard) support
- Patch compression (zip/gzip)
- Batch patch export
- Patch preview/validation
- Incremental patch generation
- Patch metadata (author, description)
- Direct patch sharing via URL