Task 607: .RC File Format
Task 607: .RC File Format
File Format Specifications for the .RC File Format
The .RC file format is a text-based resource script used in Windows development to define application resources such as icons, menus, dialog boxes, and strings. It is processed by the Resource Compiler (rc.exe) to produce a binary .RES file that is linked into executables (.EXE or .DLL). The format supports C-style preprocessor directives (#include, #define, #if, etc.) and resource-definition statements. The syntax is case-insensitive for keywords, and files are typically encoded in ANSI or UTF-8/UTF-16, with CRLF line endings. The specifications are documented in Microsoft docs, including resource types, controls, and statements.
- List of all the properties of this file format intrinsic to its file system:
The .RC file is a plain text format, so it has no binary magic number or fixed structure. Intrinsic properties when stored in a file system include standard file metadata (e.g., on NTFS or FAT32 in Windows):
- File extension: .rc
- MIME type: text/plain or application/x-resource-script
- Encoding: ANSI (default), UTF-8, or UTF-16 (with BOM if Unicode)
- Line endings: CRLF (Windows standard)
- File size: Variable (text-based)
- Creation time
- Last modification time
- Last access time
- File attributes (e.g., read-only, hidden, system)
- Owner SID
- Group SID
- Permissions (ACLs in NTFS)
- Inode/File ID (if applicable in the file system)
Resource-specific properties extracted from content (via parsing):
- Resource types: ACCELERATORS, BITMAP, CURSOR, DIALOG, DIALOGEX, FONT, HTML, ICON, MENU, MENUEX, MESSAGETABLE, POPUP, PLUGPLAY, RCDATA, STRINGTABLE, TEXTINCLUDE, TYPELIB, User-Defined, VERSIONINFO, VXD
- Control types (for dialogs/menus): AUTO3STATE, AUTOCHECKBOX, AUTORADIOBUTTON, CHECKBOX, COMBOBOX, CONTROL, CTEXT, DEFPUSHBUTTON, EDITTEXT, GROUPBOX, ICON, LISTBOX, LTEXT, PUSHBOX, PUSHBUTTON, RADIOBUTTON, RTEXT, SCROLLBAR, STATE3
- Statement properties: CAPTION, CHARACTERISTICS, CLASS, EXSTYLE, FONT, LANGUAGE, MENU, MENUITEM, STYLE, VERSION
- Two direct download links for files of format .RC:
- https://raw.githubusercontent.com/microsoft/Windows-classic-samples/main/Samples/Win7Samples/multimedia/mediafoundation/topoedit/topoview/resource.rc
- https://raw.githubusercontent.com/microsoft/Windows-classic-samples/main/Samples/Win7Samples/winui/shell/appplatform/folderfileviewer/resource.rc
- Ghost blog embedded HTML JavaScript for drag and drop .RC file dump:
- Python class for .RC file:
import re
import os
class RCFileHandler:
def __init__(self, filename):
self.filename = filename
self.content = None
self.properties = []
self.read_and_decode()
def read_and_decode(self):
with open(self.filename, 'r', encoding='utf-8', errors='ignore') as f:
self.content = f.read()
self.properties = self.parse()
def parse(self):
resource_types = ['ACCELERATORS', 'BITMAP', 'CURSOR', 'DIALOG', 'DIALOGEX', 'FONT', 'HTML', 'ICON', 'MENU', 'MENUEX', 'MESSAGETABLE', 'POPUP', 'PLUGPLAY', 'RCDATA', 'STRINGTABLE', 'TEXTINCLUDE', 'TYPELIB', 'VERSIONINFO', 'VXD']
lines = self.content.splitlines()
properties = []
in_block = False
current_prop = None
for line in lines:
line = line.strip()
if not line or line.startswith('//') or line.startswith('#'):
continue
words = re.split(r'\s+', line)
if words[0].upper() in resource_types:
current_prop = {'type': words[0].upper(), 'name': words[1] if len(words) > 1 else '', 'params': ' '.join(words[2:])}
properties.append(current_prop)
if 'BEGIN' in line.upper():
in_block = True
elif in_block:
if 'END' in line.upper():
in_block = False
elif current_prop:
current_prop['params'] += f'\n{line}'
return properties
def print_properties(self):
for prop in self.properties:
print(f"Type: {prop['type']}, Name: {prop['name']}, Params: {prop['params']}")
def write(self, new_filename):
with open(new_filename, 'w', encoding='utf-8') as f:
f.write(self.content)
# Example usage:
# handler = RCFileHandler('example.rc')
# handler.print_properties()
# handler.write('output.rc')
- Java class for .RC file:
import java.io.*;
import java.util.*;
public class RCFileHandler {
private String filename;
private String content;
private List<Map<String, String>> properties;
public RCFileHandler(String filename) {
this.filename = filename;
this.properties = new ArrayList<>();
readAndDecode();
}
private void readAndDecode() {
StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
content = sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
parse();
}
private void parse() {
String[] resourceTypes = {"ACCELERATORS", "BITMAP", "CURSOR", "DIALOG", "DIALOGEX", "FONT", "HTML", "ICON", "MENU", "MENUEX", "MESSAGETABLE", "POPUP", "PLUGPLAY", "RCDATA", "STRINGTABLE", "TEXTINCLUDE", "TYPELIB", "VERSIONINFO", "VXD"};
Set<String> typeSet = new HashSet<>(Arrays.asList(resourceTypes));
String[] lines = content.split("\n");
boolean inBlock = false;
Map<String, String> currentProp = null;
StringBuilder params = new StringBuilder();
for (String line : lines) {
line = line.trim();
if (line.isEmpty() || line.startsWith("//") || line.startsWith("#")) continue;
String[] words = line.split("\\s+");
if (typeSet.contains(words[0].toUpperCase())) {
if (currentProp != null) {
currentProp.put("params", params.toString().trim());
properties.add(currentProp);
}
currentProp = new HashMap<>();
currentProp.put("type", words[0].toUpperCase());
currentProp.put("name", words.length > 1 ? words[1] : "");
params = new StringBuilder(String.join(" ", Arrays.copyOfRange(words, 2, words.length)));
if (line.toUpperCase().contains("BEGIN")) inBlock = true;
} else if (inBlock) {
if (line.toUpperCase().contains("END")) {
inBlock = false;
} else if (currentProp != null) {
params.append("\n").append(line);
}
}
}
if (currentProp != null) {
currentProp.put("params", params.toString().trim());
properties.add(currentProp);
}
}
public void printProperties() {
for (Map<String, String> prop : properties) {
System.out.println("Type: " + prop.get("type") + ", Name: " + prop.get("name") + ", Params: " + prop.get("params"));
}
}
public void write(String newFilename) {
try (PrintWriter pw = new PrintWriter(new File(newFilename))) {
pw.print(content);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
// Example usage:
// public static void main(String[] args) {
// RCFileHandler handler = new RCFileHandler("example.rc");
// handler.printProperties();
// handler.write("output.rc");
// }
}
- JavaScript class for .RC file:
class RCFileHandler {
constructor(content) {
this.content = content;
this.properties = this.parse();
}
parse() {
const resourceTypes = ['ACCELERATORS', 'BITMAP', 'CURSOR', 'DIALOG', 'DIALOGEX', 'FONT', 'HTML', 'ICON', 'MENU', 'MENUEX', 'MESSAGETABLE', 'POPUP', 'PLUGPLAY', 'RCDATA', 'STRINGTABLE', 'TEXTINCLUDE', 'TYPELIB', 'VERSIONINFO', 'VXD'];
const lines = this.content.split('\n');
const properties = [];
let inBlock = false;
let currentProp = null;
let params = '';
lines.forEach(line => {
line = line.trim();
if (!line || line.startsWith('//') || line.startsWith('#')) return;
const words = line.split(/\s+/);
if (resourceTypes.includes(words[0].toUpperCase())) {
if (currentProp) {
currentProp.params = params.trim();
properties.push(currentProp);
}
currentProp = { type: words[0].toUpperCase(), name: words[1] || '', params: '' };
params = words.slice(2).join(' ');
if (line.toUpperCase().includes('BEGIN')) inBlock = true;
} else if (inBlock) {
if (line.toUpperCase().includes('END')) {
inBlock = false;
} else if (currentProp) {
params += `\n${line}`;
}
}
});
if (currentProp) {
currentProp.params = params.trim();
properties.push(currentProp);
}
return properties;
}
printProperties() {
this.properties.forEach(prop => {
console.log(`Type: ${prop.type}, Name: ${prop.name}, Params: ${prop.params}`);
});
}
write() {
// For Node.js, use fs.writeFileSync('output.rc', this.content);
// For browser, return content for download.
return this.content;
}
}
// Example usage (Node.js):
// const fs = require('fs');
// const content = fs.readFileSync('example.rc', 'utf8');
// const handler = new RCFileHandler(content);
// handler.printProperties();
// fs.writeFileSync('output.rc', handler.write());
- C class (using C++ for class support) for .RC file:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <algorithm>
#include <string>
class RCFileHandler {
private:
std::string filename;
std::string content;
std::vector<std::map<std::string, std::string>> properties;
void readAndDecode() {
std::ifstream file(filename);
if (!file.is_open()) {
std::cerr << "Error opening file" << std::endl;
return;
}
std::stringstream ss;
ss << file.rdbuf();
content = ss.str();
file.close();
parse();
}
void parse() {
std::vector<std::string> resourceTypes = {"ACCELERATORS", "BITMAP", "CURSOR", "DIALOG", "DIALOGEX", "FONT", "HTML", "ICON", "MENU", "MENUEX", "MESSAGETABLE", "POPUP", "PLUGPLAY", "RCDATA", "STRINGTABLE", "TEXTINCLUDE", "TYPELIB", "VERSIONINFO", "VXD"};
std::stringstream ss(content);
std::string line;
bool inBlock = false;
std::map<std::string, std::string> currentProp;
std::string params;
while (std::getline(ss, line)) {
line.erase(0, line.find_first_not_of(" \t"));
line.erase(line.find_last_not_of(" \t") + 1);
if (line.empty() || line.rfind("//", 0) == 0 || line.rfind("#", 0) == 0) continue;
std::stringstream wordStream(line);
std::string firstWord;
wordStream >> firstWord;
std::transform(firstWord.begin(), firstWord.end(), firstWord.begin(), ::toupper);
if (std::find(resourceTypes.begin(), resourceTypes.end(), firstWord) != resourceTypes.end()) {
if (!currentProp.empty()) {
currentProp["params"] = params;
properties.push_back(currentProp);
currentProp.clear();
params.clear();
}
std::string name, temp;
wordStream >> name;
while (wordStream >> temp) params += temp + " ";
currentProp["type"] = firstWord;
currentProp["name"] = name;
if (line.find("BEGIN") != std::string::npos || line.find("begin") != std::string::npos) inBlock = true;
} else if (inBlock) {
if (line.find("END") != std::string::npos || line.find("end") != std::string::npos) {
inBlock = false;
} else {
params += line + "\n";
}
}
}
if (!currentProp.empty()) {
currentProp["params"] = params;
properties.push_back(currentProp);
}
}
public:
RCFileHandler(const std::string& fn) : filename(fn) {
readAndDecode();
}
void printProperties() {
for (const auto& prop : properties) {
std::cout << "Type: " << prop.at("type") << ", Name: " << prop.at("name") << ", Params: " << prop.at("params") << std::endl;
}
}
void write(const std::string& newFilename) {
std::ofstream outFile(newFilename);
if (outFile.is_open()) {
outFile << content;
outFile.close();
} else {
std::cerr << "Error writing file" << std::endl;
}
}
};
// Example usage:
// int main() {
// RCFileHandler handler("example.rc");
// handler.printProperties();
// handler.write("output.rc");
// return 0;
// }