luxos/Modules/Rom image maker/commands.cpp

247 lines
5.7 KiB
C++

#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
#include "info.h"
using namespace std;
struct Node
{
char Name[256];
unsigned Flags;
unsigned Size;
unsigned Offset;
Node* Parent;
vector<Node*> Children;
};
Node Root;
Node* Current;
vector <Node*> list;
unsigned Flags;
FILE* Out;
char* removeQuotes (char* s)
{
if (*s == '"') s = s + 1;
char* tmp = strrchr(s, '"');
if (tmp) *tmp = '\0';
return s;
}
int32 indexOf (char* s)
{
for (int i = 0; i < (int)Current->Children.size(); i++)
if (strcmp(s, Current->Children[i]->Name) == 0) return i;
return -1;
}
void CommandCreate (char** argv, int argc)
{
if (argc < 2) throw ExcSyntaxError;
argv[1] = removeQuotes(argv[1]);
// Set up root
Root.Parent = &Root;
Root.Flags = 0xB68;
Current = &Root;
Flags = 0xB68;
// Open 'root' file
Out = fopen(argv[1], "wb");
if (!Out) throw ExcCannotOpenOutput;
}
void CommandSetFlags (char** argv, int argc)
{
if (argc < 2) throw ExcSyntaxError;
argv[1] = removeQuotes(argv[1]);
unsigned long tmp = strtoul(argv[1], NULL, 0x10);
Flags = (uint32) tmp & 0x497;
}
void CommandAddFile (char** argv, int argc)
{
if (argc < 2) throw ExcSyntaxError;
argv[1] = removeQuotes(argv[1]);
Node* node = new Node();
memset(node, 0, sizeof(Node));
strcpy(node->Name, argv[1]);
node->Flags = Flags | 0x1; // File
node->Parent = Current;
list.push_back(node);
Current->Children.push_back(node);
}
void CommandAddDirectory (char** argv, int argc)
{
if (argc < 2) throw ExcSyntaxError;
argv[1] = removeQuotes(argv[1]);
Node* node = new Node();
memset(node, 0, sizeof(Node));
strcpy(node->Name, argv[1]);
node->Flags = Flags | 0x2; // Directory
node->Parent = Current;
list.push_back(node);
Current->Children.push_back(node);
}
void CommandChangeDirectory (char** argv, int argc)
{
if (argc < 2) throw ExcSyntaxError;
argv[1] = removeQuotes(argv[1]);
if (argv[1][0] == '\0') return;
// See if we need to go to root
if (argv[1][0] == '\\') {
Current = &Root;
argv[1] = argv[1] + 1;
}
// Process every folder in path
while (argv[1])
{
char* next = strchr(argv[1], '\\');
// mark next entry to parse
if (next) { *next = 0; next = next+1; }
// previous dir?
if (strcmp(argv[1], "..") == 0) Current = Current->Parent;
else {
// Find next node
int index = indexOf(argv[1]);
if (index == -1 && strcmp(argv[1], ".") != 0) throw ExcInvalidPath; // Invalid path
// Set as current
Current = Current->Children[index];
}
argv[1] = next;
}
}
unsigned CurrentOffset;
void ProcessNodes(Node* node)
{
for (int i = 0; i < node->Children.size(); i++)
{
// Calculate size & offset
node->Children[i]->Offset = CurrentOffset;
// File
if (node->Children[i]->Flags & 0x1)
node->Children[i]->Size = InfoGetFileSize(node->Children[i]->Name);
// Directory
else
node->Children[i]->Size = sizeof(unsigned) +
(sizeof(DirectoryEntry) * node->Children[i]->Children.size());
CurrentOffset += node->Children[i]->Size;
// If it is a directory, go in
if (node->Children[i]->Flags & 0x2)
ProcessNodes(node->Children[i]);
}
}
bool NodeSort (Node* a, Node* b)
{
return (a->Offset < b->Offset);
}
void WriteFile (char* path)
{
FILE* in = fopen(path, "rb");
if (!in) throw ExcCannotOpenInput;
void* buffer = malloc(0x1000);
uint32 r = 0;
// Copy in 4kb blocks
while (r = fread(buffer, sizeof(uint8), 0x1000, in))
fwrite(buffer, sizeof(uint8), r, Out );
free(buffer);
}
void WriteDirectory (Node* node)
{
unsigned sz = node->Children.size();
// Write directory header (items count)
fwrite (&sz, 1, sizeof (unsigned), Out);
for (int i = 0; i < sz; i++)
{
// Get the info
DirectoryEntry dir;
memset (&dir, 0, sizeof(DirectoryEntry));
char* temp = InfoGetFileName(node->Children[i]->Name);
strcpy(dir.Name, temp);
dir.Flags = node->Children[i]->Flags;
dir.OwnerId = dir.GroupId = 0;
dir.Size = node->Children[i]->Size;
dir.TimeCreated = InfoGetFileCreated(node->Children[i]->Name);
dir.TimeModified = InfoGetFileModified(node->Children[i]->Name);
dir.TimeAccessed = InfoGetTime();
dir.Offset = node->Children[i]->Offset;
// Write it
fwrite (&dir, 1, sizeof(DirectoryEntry), Out);
}
}
void CommandClose ()
{
unsigned MAGIC = 0xCC23AA90;
char* OemStr = "luxram";
CurrentOffset = sizeof(MAGIC) + strlen(OemStr);
// Process root
Root.Offset = CurrentOffset;
Root.Size = sizeof (unsigned) + (Root.Children.size() * sizeof(DirectoryEntry));
CurrentOffset += Root.Size;
// Process recursively all the nodes
ProcessNodes(&Root);
// Now we need to sort the nodes by offset
sort(list.begin(), list.end(), NodeSort);
// And now we need to write everything to output file
fwrite(&MAGIC, sizeof(uint8), 4, Out); // Magic number
fwrite(OemStr, sizeof(uint8), strlen(OemStr), Out); // Oem string
WriteDirectory(&Root); // Write the root
for (int i = 0; i < list.size(); i++)
{
// If file, write content
if (list[i]->Flags & 1) WriteFile(list[i]->Name);
// If directory, write list
else WriteDirectory(list[i]);
}
// Done; cleanup
while (list.size()) {
delete list.back();
list.pop_back();
}
fclose(Out);
}