Task 310: .INFO File Format
Task 310: .INFO File Format
1. List of all the properties of this file format intrinsic to its file system
Based on the GNU Info file format specification, the properties (key components and structures) are:
- Preamble: The initial header containing the magic byte (0x1F) and basic file identification, such as "Info: (filename)dir," followed by a separator.
- Indirect table: A list of subfile names and byte offsets for large Info files split into multiple parts.
- Tag table: A table listing node names and their byte offsets in the file for quick navigation.
- Local variables: A section at the end of the file containing key-value pairs for configuration, such as "dircategory" or "direntry".
- Regular nodes: The main content units, each starting with a header like "File: filename, Node: nodename, Up: upnode, Next: nextnode, Prev: prevnode", followed by the node body.
- Menu: A list of entries within a node for navigation to other nodes, formatted as "* Menu:" followed by "* node:: description".
- Image: Embedded image data within nodes, specified with tags like "* Image: [attributes]".
- Printindex: Formatted index entries for printed output, using "* printindex cp" or similar for index generation.
- Cross-reference: Links to other nodes or external files, formatted as "*note reference: (file)node".
2. Two direct download links for files of format .INFO
- https://www.gnu.org/software/texinfo/manual/texinfo.info
- https://www.gnu.org/software/coreutils/manual/coreutils.info
3. Ghost blog embedded html javascript for drag n drop .INFO file to dump properties
Drag and drop .INFO file here
4. Python class for .INFO file
class InfoFile:
def __init__(self, filename):
self.filename = filename
self.data = None
self.properties = {}
def read(self):
with open(self.filename, 'r') as f:
self.data = f.read()
self.decode()
def decode(self):
if not self.data:
return
# Preamble
preamble_match = self.data[0: self.data.find('\x1F', 1)]
self.properties['preamble'] = preamble_match if 'Info:' in preamble_match else None
# Indirect table
indirect_pos = self.data.find('\x1FIndirect\x1F')
if indirect_pos != -1:
end_pos = self.data.find('\x1F', indirect_pos + 10)
self.properties['indirect_table'] = self.data[indirect_pos + 10:end_pos]
# Tag table
tag_pos = self.data.find('\x1FTag table:\x1F')
if tag_pos != -1:
end_pos = self.data.find('\x1F', tag_pos + 12)
self.properties['tag_table'] = self.data[tag_pos + 12:end_pos]
# Local variables
local_pos = self.data.find('\x1FLocal Variables:\x1F')
if local_pos != -1:
end_pos = self.data.find('End:\x1F', local_pos)
self.properties['local_variables'] = self.data[local_pos + 19:end_pos]
# Regular nodes
node_matches = []
pos = 0
while True:
node_pos = self.data.find('\x1FFile: ', pos)
if node_pos == -1:
break
end_pos = self.data.find('\x1F', node_pos + 1)
node_matches.append(self.data[node_pos + 1:end_pos])
pos = end_pos
self.properties['regular_nodes'] = node_matches
# Menu
menu_pos = self.data.find('* Menu:')
if menu_pos != -1:
end_pos = self.data.find('\n\n', menu_pos)
self.properties['menu'] = self.data[menu_pos:end_pos]
# Image
image_pos = self.data.find('* Image:')
if image_pos != -1:
end_pos = self.data.find('.', image_pos)
self.properties['image'] = self.data[image_pos:end_pos]
# Printindex
printindex_pos = self.data.find('* printindex')
if printindex_pos != -1:
end_pos = self.data.find('\n', printindex_pos)
self.properties['printindex'] = self.data[printindex_pos:end_pos]
# Cross-reference
xref_pos = self.data.find('*note ')
if xref_pos != -1:
end_pos = self.data.find('::', xref_pos)
self.properties['cross_reference'] = self.data[xref_pos:end_pos]
def print_properties(self):
for key, value in self.properties.items():
print(f"{key.upper()}: {value}")
def write(self, new_filename):
with open(new_filename, 'w') as f:
f.write(self.data)
# Example usage
# info = InfoFile('example.info')
# info.read()
# info.print_properties()
# info.write('new.info')
5. Java class for .INFO file
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class InfoFile {
private String filename;
private String data;
private Map<String, String> properties = new HashMap<>();
public InfoFile(String filename) {
this.filename = filename;
}
public void read() throws IOException {
StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
String line;
while (line = br.readLine() != null) {
sb.append(line).append("\n");
}
}
data = sb.toString();
decode();
}
private void decode() {
// Preamble
Pattern preamblePattern = Pattern.compile("^\\u001FInfo: \\((.*)\\)dir,\\u001F");
Matcher preambleMatcher = preamblePattern.matcher(data);
if (preambleMatcher.find()) {
properties.put("preamble", preambleMatcher.group(0));
}
// Indirect table
Pattern indirectPattern = Pattern.compile("\\u001FIndirect\\u001F(.*?)\\u001F", Pattern.DOTALL);
Matcher indirectMatcher = indirectPattern.matcher(data);
if (indirectMatcher.find()) {
properties.put("indirect_table", indirectMatcher.group(1));
}
// Tag table
Pattern tagPattern = Pattern.compile("\\u001FTag table:\\u001F(.*?)\\u001F", Pattern.DOTALL);
Matcher tagMatcher = tagPattern.matcher(data);
if (tagMatcher.find()) {
properties.put("tag_table", tagMatcher.group(1));
}
// Local variables
Pattern localPattern = Pattern.compile("\\u001FLocal Variables:\\u001F(.*? )End:", Pattern.DOTALL);
Matcher localMatcher = localPattern.matcher(data);
if (localMatcher.find()) {
properties.put("local_variables", localMatcher.group(1));
}
// Regular nodes
Pattern nodePattern = Pattern.compile("\\u001FFile: (.*?), Node: (.*?), Up: (.*?), Next: (.*?), Prev: (.*?)\\n", Pattern.DOTALL);
Matcher nodeMatcher = nodePattern.matcher(data);
StringBuilder nodes = new StringBuilder();
while (nodeMatcher.find()) {
nodes.append(nodeMatcher.group(0)).append("\n");
}
if (nodes.length() > 0) {
properties.put("regular_nodes", nodes.toString());
}
// Menu
Pattern menuPattern = Pattern.compile("\\* Menu:(.*?)\\n\\n", Pattern.DOTALL);
Matcher menuMatcher = menuPattern.matcher(data);
if (menuMatcher.find()) {
properties.put("menu", menuMatcher.group(1));
}
// Image
Pattern imagePattern = Pattern.compile("\\* Image: (.*?)\\.");
Matcher imageMatcher = imagePattern.matcher(data);
if (imageMatcher.find()) {
properties.put("image", imageMatcher.group(1));
}
// Printindex
Pattern printindexPattern = Pattern.compile("\\* printindex (.*?)\\n");
Matcher printindexMatcher = printindexPattern.matcher(data);
if (printindexMatcher.find()) {
properties.put("printindex", printindexMatcher.group(1));
}
// Cross-reference
Pattern xrefPattern = Pattern.compile("\\*note (.*?)::");
Matcher xrefMatcher = xrefPattern.matcher(data);
if (xrefMatcher.find()) {
properties.put("cross_reference", xrefMatcher.group(1));
}
}
public void printProperties() {
for (Map.Entry<String, String> entry : properties.entrySet()) {
System.out.println(entry.getKey().toUpperCase() + ": " + entry.getValue());
}
}
public void write(String newFilename) throws IOException {
try (FileWriter fw = new FileWriter(newFilename)) {
fw.write(data);
}
}
// Example usage
// public static void main(String[] args) throws IOException {
// InfoFile info = new InfoFile("example.info");
// info.read();
// info.printProperties();
// info.write("new.info");
// }
}
6. Javascript class for .INFO file
class InfoFile {
constructor(filename) {
this.filename = filename;
this.data = null;
this.properties = {};
}
async read() {
// Assuming node.js with fs
const fs = require('fs');
this.data = fs.readFileSync(this.filename, 'utf8');
this.decode();
}
decode() {
if (!this.data) return;
// Preamble
const preambleMatch = this.data.match(/^\x1FInfo: \((.*)\)dir,\x1F/);
this.properties.preamble = preambleMatch ? preambleMatch[0] : null;
// Indirect table
const indirectMatch = this.data.match(/\x1FIndirect\x1F(.*?)\x1F/gs);
this.properties.indirect_table = indirectMatch ? indirectMatch[0] : null;
// Tag table
const tagMatch = this.data.match(/\x1FTag table:\x1F(.*?)\x1F/gs);
this.properties.tag_table = tagMatch ? tagMatch[0] : null;
// Local variables
const localMatch = this.data.match(/\x1FLocal Variables:\x1F(.*? )End:/gs);
this.properties.local_variables = localMatch ? localMatch[0] : null;
// Regular nodes
const nodeMatch = this.data.match(/\x1FFile: (.*?), Node: (.*?), Up: (.*?), Next: (.*?), Prev: (.*?)\n/gs);
this.properties.regular_nodes = nodeMatch ? nodeMatch : null;
// Menu
const menuMatch = this.data.match(/\* Menu:(.*?)\n\n/gs);
this.properties.menu = menuMatch ? menuMatch[0] : null;
// Image
const imageMatch = this.data.match(/\* Image: (.*?)\./gs);
this.properties.image = imageMatch ? imageMatch[0] : null;
// Printindex
the printindexMatch = this.data.match(/\* printindex (.*?)\n/gs);
this.properties.printindex = printindexMatch ? printindexMatch[0] : null;
// Cross-reference
const xrefMatch = this.data.match(/\*note (.*?)::/gs);
this.properties.cross_reference = xrefMatch ? xrefMatch[0] : null;
}
printProperties() {
for (const [key, value] of Object.entries(this.properties)) {
console.log(`${key.toUpperCase()}: ${value}`);
}
}
write(newFilename) {
const fs = require('fs');
fs.writeFileSync(newFilename, this.data);
}
}
// Example usage
// const info = new InfoFile('example.info');
// await info.read();
// info.printProperties();
// info.write('new.info');
7. C class for .INFO file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *data;
long size;
char *preamble;
char *indirect_table;
char *tag_table;
char *local_variables;
char **regular_nodes;
int node_count;
char *menu;
char *image;
char *printindex;
char *cross_reference;
} InfoFile;
InfoFile *info_file_create(const char *filename) {
InfoFile *info = malloc(sizeof(InfoFile));
FILE *f = fopen(filename, "r");
if (!f) return NULL;
fseek(f, 0, SEEK_END);
info->size = ftell(f);
fseek(f, 0, SEEK_SET);
info->data = malloc(info->size + 1);
fread(info->data, 1, info->size, f);
info->data[info->size] = 0;
fclose(f);
return info;
}
void info_file_decode(InfoFile *info) {
// Preamble
char *preamble_end = strchr(info->data + 1, 31);
if (preamble_end) {
info->preamble = strndup(info->data + 1, preamble_end - (info->data + 1));
}
// Indirect table
char *indirect_start = strstr(info->data, "\x1FIndirect\x1F");
if (indirect_start) {
indirect_start += 11;
char *end = strchr(indirect_start, 31);
info->indirect_table = strndup(indirect_start, end - indirect_start);
}
// Tag table
char *tag_start = strstr(info->data, "\x1FTag table:\x1F");
if (tag_start) {
tag_start += 12;
char *end = strchr(tag_start, 31);
info->tag_table = strndup(tag_start, end - tag_start);
}
// Local variables
char *local_start = strstr(info->data, "\x1FLocal Variables:\x1F");
if (local_start) {
local_start += 19;
char *end = strstr(local_start, "End:");
info->local_variables = strndup(local_start, end - local_start);
}
// Regular nodes (simple count)
char *pos = info->data;
info->node_count = 0;
while ((pos = strstr(pos, "\x1FFile: ")) != NULL) {
info->node_count++;
pos += 8;
}
info->regular_nodes = malloc(info->node_count * sizeof(char*));
pos = info->data;
int i = 0;
while ((pos = strstr(pos, "\x1FFile: ")) != NULL) {
pos += 1;
char *end = strchr(pos, 31);
info->regular_nodes[i++] = strndup(pos, end - pos);
pos = end;
}
// Menu
char *menu_start = strstr(info->data, "* Menu:");
if (menu_start) {
char *end = strstr(menu_start, "\n\n");
info->menu = strndup(menu_start, end - menu_start);
}
// Image
char *image_start = strstr(info->data, "* Image:");
if (image_start) {
char *end = strchr(image_start, '.');
info->image = strndup(image_start, end - image_start + 1);
}
// Printindex
char *printindex_start = strstr(info->data, "* printindex");
if (printindex_start) {
char *end = strchr(printindex_start, '\n');
info->printindex = strndup(printindex_start, end - printindex_start);
}
// Cross-reference
char *xref_start = strstr(info->data, "*note ");
if (xref_start) {
char *end = strstr(xref_start, "::");
info->cross_reference = strndup(xref_start, end - xref_start + 2);
}
}
void info_file_print_properties(InfoFile *info) {
printf("PREAMBLE: %s\n", info->preamble ? info->preamble : "Not found");
printf("INDIRECT_TABLE: %s\n", info->indirect_table ? info->indirect_table : "Not found");
printf("TAG_TABLE: %s\n", info->tag_table ? info->tag_table : "Not found");
printf("LOCAL_VARIABLES: %s\n", info->local_variables ? info->local_variables : "Not found");
printf("REGULAR_NODES:\n");
for (int i = 0; i < info->node_count; i++) {
printf("Node %d: %s\n", i + 1, info->regular_nodes[i]);
}
printf("MENU: %s\n", info->menu ? info->menu : "Not found");
printf("IMAGE: %s\n", info->image ? info->image : "Not found");
printf("PRINTINDEX: %s\n", info->printindex ? info->printindex : "Not found");
printf("CROSS_REFERENCE: %s\n", info->cross_reference ? info->cross_reference : "Not found");
}
void info_file_write(InfoFile *info, const char *new_filename) {
FILE *f = fopen(new_filename, "w");
if (f) {
fwrite(info->data, 1, info->size, f);
fclose(f);
}
}
void info_file_destroy(InfoFile *info) {
free(info->data);
free(info->preamble);
free(info->indirect_table);
free(info->tag_table);
free(info->local_variables);
for (int i = 0; i < info->node_count; i++) {
free(info->regular_nodes[i]);
}
free(info->regular_nodes);
free(info->menu);
free(info->image);
free(info->printindex);
free(info->cross_reference);
free(info);
}
// Example usage
// int main() {
// InfoFile *info = info_file_create("example.info");
// info_file_decode(info);
// info_file_print_properties(info);
// info_file_write(info, "new.info");
// info_file_destroy(info);
// return 0;
// }