247 lines
5.7 KiB
C++
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);
|
||
|
}
|