Hi everybody, Today I bring you a small project I've been working on (and struggling with).
The idea was to create a opensource dotZip-similar type of extracting and packaging library for the black ops soundfiles.
Sadly I was unable to finish the packaging (replacing) part.
I hope I can get people excited about this and you are free to improve it (please do)
I do not have that much experience involving algorithms and hex'n'bytes'n'stuff so excuse me if I didn't use the right methods (criticism is welcome)
I do believe that the information and the offsets of each flac file is defined in the header, because there's a lot of stuff in the header (that I don't understand, sadly)
Pro's:
Cons:
master131-flac-extractor-style code example:
Code:
Result:
All that with 20 lines of code?
Yes, that's the power of SABSFile
Download (library, no source, just example source)
SABSFile.zip (Size: 4.4 KB / Downloads: 126)
Source
The idea was to create a opensource dotZip-similar type of extracting and packaging library for the black ops soundfiles.
Sadly I was unable to finish the packaging (replacing) part.
I hope I can get people excited about this and you are free to improve it (please do)
I do not have that much experience involving algorithms and hex'n'bytes'n'stuff so excuse me if I didn't use the right methods (criticism is welcome)
I do believe that the information and the offsets of each flac file is defined in the header, because there's a lot of stuff in the header (that I don't understand, sadly)
Pro's:
- Scan for FLAC files inside of sabs files
- Get raw bytes from each flac file in there
- Extract file directly from class
- Replace (doesn't work properly, works when extracting again but crashes game.)
- Very low memory usage
Cons:
- Keep in mind that when calling the constructor (new SABSFile("d.sabs")) the class starts looking for offsets which takes a few seconds. Do NOT call it from the main thread in a form application.
- Replacing fails ingame (soundbank failed to initialize)
master131-flac-extractor-style code example:
Code:
CSHARP Code
- Console.WriteLine("SABSFile library example extractor");
- string a = GetSteamPath()+"\\steamapps\\common\\Call of Duty Black Ops II";
- foreach(string file in Directory.GetFiles(GetSteamPath()+"\\steamapps\\common\\Call of Duty Black Ops II\\sound", "*.sabs"))
- {
- Console.WriteLine("Extracting " + Path.GetFileName(file));
- string path = Path.GetDirectoryName(Application.ExecutablePath);
- int i = 0;
- string dir = path+"\\extracted\\"+Path.GetFileNameWithoutExtension(file);
- if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
- else foreach (string filef in Directory.GetFiles(dir)) File.Delete(filef);
- foreach (SABSEntry entry in sabs.Entries)
- {
- i++;
- Console.Write("\r Progress: "+Convert.ToInt32((double)i / (double)sabs.Entries.Length * 100.0) + "%");
- entry.Extract(dir + "\\" + entry.Offset.ToString("X").ToLower() + ".flac");
- }
- Console.WriteLine();
- }
Result:
All that with 20 lines of code?
Yes, that's the power of SABSFile
Download (library, no source, just example source)
SABSFile.zip (Size: 4.4 KB / Downloads: 126)
Source
CSHARP Code
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.IO;
- using System.Collections;
-
- namespace JariZ
- {
- public class SABSFile
- {
- public SABSFile(string filename) {
- if (Path.GetExtension(filename) != ".sabs") throw new FileLoadException("Only SABS files supported");
- /*
- try
- {*/
- _filename = filename;
- {
- int read;
- int index = 0x800;
- reader.Position = 0x800;
-
- while ((read = reader.ReadByte()) >= 0)
- {
- index++;
- if (hs.Search((byte)read))
- {
- int offset = index - header.Length;
- offsets.Add(offset);
- }
- }
- offsets.Add(Convert.ToInt32(reader.Position-1));
-
- int indexx = 0;
- foreach(int offset in offsets)
- {
- indexx++;
- if (indexx != 1)
- }
-
- }
- /*
- }
- catch (Exception z)
- {
- throw new Exception("Unable to read file", z);
- }*/
- }
-
- string _filename = null;
- public string Filename
- {
- get
- {
- return _filename;
- }
- }
-
-
- public SABSEntry[] Entries
- {
- get
- {
- return _entries.ToArray();
- }
- }
- }
-
- public class SABSEntry
- {
- public SABSEntry(SABSFile parent, int offsetstart, int offsetend)
- {
- _offsetend = offsetend;
- _offsetstart = offsetstart;
- _parent = parent;
- }
-
- public int Offset
- {
- get
- {
- return _offsetstart;
- }
- }
-
- public void Extract(out byte[] buffer)
- {
- {
- fs.Position = _offsetstart;
- while (fs.Position <= _offsetend) lbuffer.Add((byte)fs.ReadByte());
- }
- buffer = lbuffer.ToArray();
- }
-
- SABSFile _parent;
- public void Extract(string filename)
- {
- using (FileStream fs = new FileStream(_parent.Filename, FileMode.Open, FileAccess.Read, FileShare.None))
- {
- if (!Directory.Exists(Path.GetDirectoryName(filename))) Directory.CreateDirectory(Path.GetDirectoryName(filename));
- if (!File.Exists(filename)) File.Create(filename).Dispose();
- using(FileStream gs = new FileStream(filename, FileMode.Truncate, FileAccess.Write, FileShare.None))
- {
- fs.Position = _offsetstart;
- while (fs.Position <= _offsetend) gs.WriteByte((byte)fs.ReadByte());
- gs.Flush();
- gs.Close();
- fs.Close();
- gs.Dispose();
- fs.Dispose();
- }
- }
- }
-
- public void Replace(byte[] content)
- {
- byte[] b = File.ReadAllBytes(_parent.Filename);
- lb.AddRange(b);
- lb.RemoveRange(_offsetstart, _offsetend - _offsetstart);
- lb.InsertRange(_offsetstart, content);
- File.WriteAllBytes(_parent.Filename, lb.ToArray());
-
- /*using (FileStream fs = new FileStream(_parent.Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
- {
- fs.Position = _offsetstart;
- byte[] otherdata = null;
- bool crossed_offset = false;
- string tempfile = string.Empty;
- foreach(byte bite in content)
- {
- if (fs.Position <= _offsetend)
- {
- fs.WriteByte(bite);
- }
- else
- {
- //we've crossed our offset, no worries, but we need to start inserting data from now on.
- //this is simple. we read the rest of the data, write it to a temporary file (to prevent memleaks)
- if (!crossed_offset)
- {
- int b4 = Convert.ToInt32(fs.Position);
- FileStream gs = new FileStream((tempfile = Path.GetRandomFileName()), FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
- while (fs.Position < Convert.ToInt32(fs.Length)) gs.WriteByte((byte)fs.ReadByte());
- gs.Flush();
- gs.Close();
- gs.Dispose();
- crossed_offset = true;
- fs.Position = b4;
- }
- fs.WriteByte(bite);
- }
- }
- //now that we have written our new file, update the offset
- _offsetend = Convert.ToInt32(fs.Position);
- if (crossed_offset)
- {
- fs.Position = _offsetend;
- FileStream gs = new FileStream(tempfile, FileMode.Open, FileAccess.Read, FileShare.None);
- while (gs.Position < Convert.ToInt32(gs.Length)) fs.WriteByte((byte)gs.ReadByte());
- gs.Flush();
- gs.Close();
- gs.Dispose();
- }
- fs.Flush();
- fs.Close();
- fs.Dispose();
- }*/
- }
-
- public void Replace(string filename)
- {
- Replace(File.ReadAllBytes(filename));
- }
-
- int _offsetstart = 0;
- int _offsetend = 0;
- }
-
- public class HeaderSearch
- {
- public HeaderSearch(byte[] header)
- {
- _bufferlength = header.Length;
- _header = header;
- _headerend = _header[_header.Length-1];
-
- //fill buffer
- while (buffer.Count != _bufferlength) buffer.Add(0);
- }
-
- byte[] _header;
- int _bufferlength = 0;
- List<byte> buffer;
- int _headerend = 0;
- public bool Search(byte newbyte)
- {
- buffer.RemoveAt(0);
- buffer.Add(newbyte);
- if (newbyte == _headerend)
- {
- byte[] bbuffer = buffer.ToArray();
- if (bbuffer.SequenceEqual(_header))
- return true;
- else return false;
- }
- else return false;
- }
- }
- }