public static byte[] Chunk(List <byte[]> input) { var ms = new System.IO.MemoryStream(); byte[] scratch = new byte[4]; ms.Write(scratch, 0, 2); ms.Write(BitConverter.GetBytes(input.Count), 0, 4); int offset = 0x2A; foreach (var s in input) { Bytes.WriteInt(ms, offset); offset += 4; offset += s.Length; } foreach (var s in input) { Bytes.WriteInt(ms, s.Length); ms.Write(s, 0, s.Length); } ms.Position = 0; var compress = new System.IO.MemoryStream(); Lzs.Encode(ms, compress); byte[] data = new byte[compress.Length + 4]; compress.Position = 0; compress.Read(data, 4, (int)compress.Length); Bytes.WriteInt(data, 0, (int)compress.Length); return(data); }
public VRangeChunked(string name, List <RuntimeMod> mods, IntPtr fallbackHandle, uint fallbackOffset, int fallbackLen) { _mods = mods; _fbHandle = fallbackHandle; _fbOffset = fallbackOffset; _fbLen = fallbackLen; _header = new byte[24]; byte[] bname = System.Text.Encoding.ASCII.GetBytes(name); Array.Copy(bname, _header, bname.Length); Bytes.WriteInt(_header, 20, _fbLen); }
public VRangeConditional(string name, List <OverrideFile> files, IntPtr fallbackHandle, uint fallbackOffset) { _files = files; _handle = IntPtr.Zero; _current = null; _header = new byte[24]; _fallbackHandle = fallbackHandle; _fallbackOffset = fallbackOffset; byte[] bname = System.Text.Encoding.ASCII.GetBytes(name); Array.Copy(bname, _header, bname.Length); Bytes.WriteInt(_header, 20, files.Select(f => f.Size).Max()); }
private unsafe void Recalculate() { DebugLogger.WriteLine($"Chunked file {Name} recalculating contents..."); byte[] original = new byte[_fbLen]; Win32.OVERLAPPED ov = new Win32.OVERLAPPED() { EventHandle = IntPtr.Zero, Internal = UIntPtr.Zero, InternalHigh = UIntPtr.Zero, Offset = _fbOffset, OffsetHigh = 0 }; fixed(byte *bp = &original[0]) { uint bytesRead = 0; //TODO should loop... Win32.ReadFile(_fbHandle, new IntPtr(bp), (uint)_fbLen, ref bytesRead, ref ov); } DebugLogger.WriteLine($"Original read {_fbLen} from {_fbOffset} sig {original[0]} {original[1]} {original[2]} {original[3]}"); var orig = FieldFile.Unchunk(original); foreach (int i in Enumerable.Range(0, orig.Count)) { string fn = Name + ".chunk." + (i + 1); foreach (var of in _mods.SelectMany(m => m.GetOverrides(fn))) { if (of.CFolder == null || of.CFolder.IsActive(of.CName)) { if (of.Archive == null) { orig[i] = System.IO.File.ReadAllBytes(of.File); } else { orig[i] = of.Archive.GetBytes(of.File); } break; } } } _calculated = FieldFile.Chunk(orig); Bytes.WriteInt(_header, 20, _calculated.Length); DebugLogger.WriteLine($"New length of {Name} is {_calculated.Length}"); }
public static byte[] CalculateHeaders(List <LGPEntry> files, Func <string, int> headerSortKey, Func <string, uint> dataSortKey, out List <LGPEntryMade> entries) { files = files.OrderBy(e => e.HashCode).ThenBy(e => headerSortKey(e.Name)).ToList(); byte[] hash = new byte[LGPEntry.HashValues * LGPEntry.HashValues * 4]; TOC[] toc = new TOC[files.Count]; var hfiles = files.GroupBy(e => e.HashCode).OrderBy(g => g.Key); List <List <PathEntry> > paths = new List <List <PathEntry> >(); entries = new List <LGPEntryMade>(); int count = 0; //int position = 0; foreach (var group in hfiles) { Bytes.WriteUShort(hash, 4 * group.Key, (ushort)(count + 1)); Bytes.WriteUShort(hash, 4 * group.Key + 2, (ushort)(group.Count())); foreach (var name in group.OfType <LGPEntry>().GroupBy(e => e.TOCName).OrderBy(g => headerSortKey(g.Key))) { bool hasPaths = name.Count() > 1; if (hasPaths) { paths.Add(new List <PathEntry>()); } foreach (var file in name) { toc[count] = new TOC(file.TOCName); toc[count].Type = 14; toc[count].Path = (ushort)(hasPaths ? paths.Count : 0); toc[count].Source = file; //toc[count].Offset = position; //just use file sizes so far, we'll calculate the additional offset due to header later - once the file paths are done //position += 24 + file.MaxSize; if (hasPaths) { paths.Last().Add(new PathEntry() { Index = (ushort)count, Path = file.Path }); } entries.Add(new LGPEntryMade() { Entry = file, TOCIndex = count }); count++; } } } int headerSize = 16 //initial header + (27 * toc.Length) //toc + hash.Length //hashtable + 2 //path count + paths.Select(L => 2 + L.Count * 130).Sum() //path entries - 2 byte count for each list, followed by 130 bytes per entry ; int position = 0; count = 0; foreach (var em in entries.OrderBy(em => dataSortKey(em.Entry.Name)).ThenBy(em => em.Entry.Name)) { em.DataOffset = toc[em.TOCIndex].Offset = position + headerSize; em.DataIndex = count; position += 24 + em.Entry.MaxSize; count++; } byte[] header = new byte[headerSize]; //Initial header Array.Copy(System.Text.Encoding.ASCII.GetBytes("SQUARESOFT"), 0, header, 2, 10); Bytes.WriteInt(header, 12, toc.Length); //Now write TOC int offset = 16; foreach (var entry in toc) { Array.Copy(entry.Name, 0, header, offset, entry.Name.Length); offset += 20; Bytes.WriteInt(header, offset, entry.Offset); offset += 4; header[offset] = entry.Type; offset++; Bytes.WriteUShort(header, offset, entry.Path); offset += 2; } //Now hash table Array.Copy(hash, 0, header, offset, hash.Length); offset += hash.Length; //Now path array... Bytes.WriteUShort(header, offset, (ushort)(paths.Count)); offset += 2; foreach (var pathlist in paths) { Bytes.WriteUShort(header, offset, (ushort)(pathlist.Count)); offset += 2; foreach (var path in pathlist) { byte[] p = System.Text.Encoding.ASCII.GetBytes(path.Path); Array.Copy(p, 0, header, offset, p.Length); offset += 128; Bytes.WriteUShort(header, offset, path.Index); offset += 2; } } return(header); }
public override void Read(uint offset, uint length, IntPtr dest, ref uint bytesRead) { //DebugLogger.WriteLine("Conditional {2} reading from OS {0} L {1}", offset, length, Name); bool header = (offset < 24); bool init = (offset == 24); if ((!_lastHeader && header) || (init && !_lastInit)) //re-evaluate { _current = null; if (!_handle.Equals(IntPtr.Zero)) { Win32.CloseHandle(_handle); } _handle = IntPtr.Zero; foreach (var of in _files) { if (of.CFolder == null || of.CFolder.IsActive(of.CName)) { DebugLogger.WriteLine($"Conditional {Name} switching to {of.File}"); _current = of; Bytes.WriteInt(_header, 20, of.Size); break; } } if (_current == null) { DebugLogger.WriteLine($"Conditional {Name} switching to fallback"); } _lastInit = true; //we're ready to read file headers } else { _lastInit = init; } if (_current != null && _handle.Equals(IntPtr.Zero) && _current.Archive == null) { _handle = Wrap.CreateFileW(_current.File, System.IO.FileAccess.Read, System.IO.FileShare.Read, IntPtr.Zero, System.IO.FileMode.Open, System.IO.FileAttributes.Normal, IntPtr.Zero); } _lastHeader = header; _access = DateTime.Now; if (_current == null) //read from fallback //DebugLogger.WriteLine("Conditional reading from fallback handle {0} with extra offset {1}", _fallbackHandle, _fallbackOffset); { Win32.OVERLAPPED ov = new Win32.OVERLAPPED() { EventHandle = IntPtr.Zero, Internal = UIntPtr.Zero, InternalHigh = UIntPtr.Zero, Offset = _fallbackOffset + offset, OffsetHigh = 0 }; Win32.ReadFile(_fallbackHandle, dest, length, ref bytesRead, ref ov); //DebugLogger.WriteLine("Conditional {1} reading from fallback - {0} bytes read", bytesRead, Name); } else { if (offset < 24) { length = Math.Min(length, 24 - offset); System.Runtime.InteropServices.Marshal.Copy(_header, (int)offset, dest, (int)length); bytesRead = length; //DebugLogger.WriteLine("Conditional {2} reading from cheader - {0} bytes read [current size is {1}]", bytesRead, BitConverter.ToInt32(_header, 20), Name); return; } else { offset -= 24; if (_current.Archive == null) { Wrap.SetFilePointer(_handle, (int)offset, IntPtr.Zero, Wrap.EMoveMethod.Begin); Win32.ReadFile(_handle, dest, length, ref bytesRead, IntPtr.Zero); //DebugLogger.WriteLine("Conditional {1} reading from cfile - {0} bytes read", bytesRead, Name); } else { _current.Archive.RawRead(_current.File, offset, length, dest, ref bytesRead); //DebugLogger.WriteLine("Conditional {1} reading from cfile archive offset {2} length {3} - {0} bytes read", bytesRead, Name, offset, length); } } } }