Difference between revisions of "User talk:Timeslip"

From the Oblivion ConstructionSet Wiki
Jump to navigation Jump to search
imported>Timeslip
(→‎PROBLEM: answer)
imported>Timeslip
m (→‎PROBLEM: typo...)
Line 56: Line 56:
[[User:MentalElf]]: What about the other file types... ".mp3", ".spt", ".egm"???
[[User:MentalElf]]: What about the other file types... ".mp3", ".spt", ".egm"???


:[[User:Timeslip|Timeslip]] 15:42, 10 October 2006 (EDT): For any files types other than the ones I've listed in the switch, the lower dword is left untouched. The upper dword is calculated normally with GenHash2.
:[[User:Timeslip|Timeslip]] 15:42, 10 October 2006 (EDT): For any file types other than the ones I've listed in the switch, the lower dword is left untouched. The upper dword is calculated normally with GenHash2.

Revision as of 14:44, 10 October 2006

BSA hashes

Oblivions BSA hashing algorithm is different from morrowinds, and doesn't appear to be documented anywhere. In case anyone else is working on any BSA tools and wants the algorithm, I'll post the C# code that obmm uses here.

//file is the file name without the extension
//Extension is the extension of a file, including the preceding '.'
//For hashing anything other than file names, ext must be an empty string
public static ulong GenHash(string file, string ext) {
  file=file.ToLower();
  ext=ext.ToLower();
  ulong hash=0;
  if(file.Length>0) {
    hash=(ulong)(
      (((byte)file[file.Length-1])*0x1)+
      ((file.Length>2?(byte)file[file.Length-2]:(byte)0)*0x100)+
      (file.Length*0x10000)+
      (((byte)file[0])*0x1000000)
    );
  }
  if(file.Length>3) {
    hash+=(ulong)(GenHash2(file.Substring(1, file.Length-3))*0x100000000);
  }
  if(ext.Length>0) {
    hash+=(ulong)(GenHash2(ext)*0x100000000);
    byte i=0;
    switch(ext) {
      case ".nif": i=1; break;
      case ".kf": i=2; break;
      case ".dds": i=3; break;
      case ".wav": i=4; break;
    }
    if(i!=0) {
      byte a=(byte)(((i&0xfc)<<5)+(byte)((hash&0xff000000)>>24));
      byte b=(byte)(((i&0xfe)<<6)+(byte)(hash&0xff));
      byte c=(byte)((i<<7)+(byte)((hash&0xff00)>>8));
      hash-=hash&0xFF00FFFF;
      hash+=(uint)((a<<24)+b+(c<<8));
    }
  }
  return hash;
}

private static uint GenHash2(string s) {
  uint hash=0;
  for(int i=0;i<s.Length;i++) {
    hash*=0x1003f;
    hash+=(byte)s[i];
  }
  return hash;
}

This may not be 100% accurate, but I've run it over every file and folder in oblivion v1.1's meshes, textures and misc BSAs without any mismatches, so I'm fairly sure it's right.

PROBLEM

User:MentalElf: What about the other file types... ".mp3", ".spt", ".egm"???

Timeslip 15:42, 10 October 2006 (EDT): For any file types other than the ones I've listed in the switch, the lower dword is left untouched. The upper dword is calculated normally with GenHash2.