/// <summary> /// This writes changed data without rewriting the entire file /// </summary> public unsafe void QuickWrite() { VoidPtr origAddr = _rootNode.WorkingUncompressed.Address; SakuraiArchiveHeader *hdr = (SakuraiArchiveHeader *)origAddr; VoidPtr origBase = hdr->BaseAddress; var changed = _rootNode.RebuildEntries; if (changed.Count != 0) { foreach (var entry in changed) { int eOffset = entry._offset; bint *lookup = hdr->LookupEntries; int currentOffset = *(bint *)(origBase + *lookup++); for (int i = 0; i < hdr->_lookupEntryCount - 1; i++, lookup++) { int nextOffset = *(bint *)(origBase + *lookup); if (eOffset >= currentOffset && eOffset < nextOffset) { int newSize = entry._calcSize; int oldSize = entry._initSize; int diff = newSize - oldSize; for (int x = i; x < hdr->_lookupEntryCount; x++) { lookup[x] += diff; } } currentOffset = nextOffset; } } } }
/// <summary> /// Creates a table of offsets with a corresponding data size at each offset. /// </summary> private void GetLookupSizes(SakuraiArchiveHeader *hdr) { //Read lookup offsets first and use them to get entry sizes at each offset. bint *lookup = hdr->LookupEntries; //First add each offset to the dictionary with size of 0. //The dictionary will sort the offsets automatically, in case they aren't already. for (int i = 0; i < hdr->_lookupEntryCount; i++) { int w = *(bint *)Address(lookup[i]); if (!_lookupSizes.ContainsKey(w)) { _lookupSizes.Add(w, 0); } } //Now go through each offset and calculate the size with the offset difference. int prev = 0; bool first = true; int[] t = _lookupSizes.Keys.ToArray(); for (int i = 0; i < t.Length; i++) { int off = t[i]; if (first) { first = false; } else { _lookupSizes[prev] = off - prev; } prev = off; } //The last entry in the moveset file goes right up to the lookup offsets. _lookupSizes[prev] = Offset(lookup) - prev; }
/// <summary> /// Initializes all variables. /// </summary> protected virtual void InitData(SakuraiArchiveHeader *hdr) { //Get header values _dataSize = hdr->_fileSize; #if DEBUG for (int i = 0; i < 3; i++) { int value = (&hdr->_pad1)[i]; if (value != 0) { Console.WriteLine("MovesetNode InitData " + i); } } #endif //Create lists _changedEntries = new BindingList <SakuraiEntryNode>(); _rebuildEntries = new BindingList <SakuraiEntryNode>(); _referenceList = new BindingList <TableEntryNode>(); _sectionList = new BindingList <TableEntryNode>(); _lookupSizes = new SortedList <int, int>(); _entryCache = new SortedDictionary <int, SakuraiEntryNode>(); _postParseEntries = new List <SakuraiEntryNode>(); }
protected virtual void ParseInternals(SakuraiArchiveHeader *hdr) { sStringTable *stringTable = hdr->StringTable; _sectionList = new BindingList <TableEntryNode>(); //Parse sections int numSections = hdr->_sectionCount; if (numSections > 0) { sStringEntry *entries = (sStringEntry *)hdr->Sections; List <TableEntryNode> _specialSections = new List <TableEntryNode>(); for (int i = 0; i < numSections; i++) { int offset = entries[i]._dataOffset; string name = stringTable->GetString(entries[i]._stringOffset); TableEntryNode section = TableEntryNode.GetRaw(name); //If null, this type of section doesn't have a dedicated class if (section == null) { //Have the inheriting class handle it. //Initialize the node with Parse() in here!!! section = GetTableEntryNode(name, i); //Still unhandled, so initialize as raw if (section == null) { section = Parse <RawDataNode>(offset); } } else { _specialSections.Add(section); } section._name = name; section._index = i; section.DataOffsets.Add(offset); _sectionList.Add(section); } //Now parse any dedicated-class nodes that may reference other sections. foreach (TableEntryNode section in _specialSections) { section.ParseSelf(this, null, section.DataOffsets[0]); } HandleSpecialSections(_specialSections); } }
public override bool OnInitialize() { //Start initializing. //This enables some functions for use. _initializing = true; SakuraiArchiveHeader *hdr = (SakuraiArchiveHeader *)WorkingUncompressed.Address; InitData(hdr); GetLookupSizes(hdr); ParseExternals(hdr); ParseInternals(hdr); PostParse(); return(_initializing = false); }
protected override void InitData(SakuraiArchiveHeader *hdr) { base.InitData(hdr); _subRoutines = new BindingList <Script>(); _commonSubRoutines = new BindingList <Script>(); _actions = new BindingList <ActionEntry>(); _scriptOffsets = new List <List <int> > [5]; for (int i = 0; i < 5; i++) { _scriptOffsets[i] = new List <List <int> >(); for (int x = 0; x < (i == 0 ? 2 : i == 1 ? 4 : 1); x++) { _scriptOffsets[i].Add(new List <int>()); } } }
/// <summary> /// Reads external subroutine references /// </summary> private void ParseExternals(SakuraiArchiveHeader *hdr) { sStringTable *stringTable = hdr->StringTable; //Parse references int numRefs = hdr->_externalSubRoutineCount; if (numRefs > 0) { sStringEntry *entries = (sStringEntry *)hdr->ExternalSubRoutines; for (int i = 0; i < numRefs; i++) { TableEntryNode e = Parse <TableEntryNode>(entries[i]._dataOffset); e._name = stringTable->GetString(entries[i]._stringOffset); _referenceList.Add(e); } } }
/// <summary> /// This gets the size using entries that need to be rebuilt /// and the original lookup entries to inject the edited data /// into the original file /// </summary> /// <returns></returns> public unsafe int QuickGetSize() { _calculatingSize = true; VoidPtr origAddr = _rootNode.WorkingUncompressed.Address; SakuraiArchiveHeader *hdr = (SakuraiArchiveHeader *)origAddr; VoidPtr origBase = hdr->BaseAddress; _size = _rootNode.WorkingUncompressed.Length; foreach (var entry in _rootNode.RebuildEntries) { int newSize = entry.GetSize(); int oldSize = entry._initSize; int diff = newSize - oldSize; int lookupCount = entry.GetLookupCount(); int prevLookupCount = 0; int minOffset = entry._offset; int maxOffset = minOffset + oldSize; bint *lookup = hdr->LookupEntries; int currentOffset = *(bint *)(origBase + *lookup++); for (int i = 0; i < hdr->_lookupEntryCount - 1; i++, lookup++) { int nextOffset = *(bint *)(origBase + *lookup); if (minOffset >= currentOffset && minOffset < nextOffset) { for (int x = i; x < hdr->_lookupEntryCount; x++) { int insideOffset = *(bint *)(origBase + lookup[x]); } } } _size += diff; } _calculatingSize = false; return(_size); }
public unsafe void Write(SakuraiArchiveNode node, VoidPtr address, int length) { _baseAddress = address + 0x20; _currentAddress = _baseAddress; //Write header SakuraiArchiveHeader *hdr = (SakuraiArchiveHeader *)address; hdr->_sectionCount = _sectionCount; hdr->_externalSubRoutineCount = _referenceCount; hdr->_lookupEntryCount = _lookupManager.Count; hdr->_fileSize = length; hdr->_pad1 = hdr->_pad2 = hdr->_pad3 = 0; List <int> _sectionOffsets = new List <int>(); //Write section data foreach (TableEntryNode section in node.SectionList) { SakuraiEntryNode entry = section; //If this section is referenced from an entry, //write that entry instead if (section.References.Count > 0) { entry = section.References[0]; } _sectionOffsets.Add(entry.Write(_currentAddress)); _currentAddress += entry.TotalSize; } //Write lookup values hdr->_lookupOffset = (int)_currentAddress - (int)_baseAddress; _lookupManager.Write(ref _currentAddress); //These can only be accessed after the lookup offset and count //have been written to the header. sStringEntry *sectionAddr = hdr->Sections; sStringEntry *refAddr = hdr->ExternalSubRoutines; }