| 1 |
using System; |
| 2 |
using System.Collections.Generic; |
| 3 |
using System.IO; |
| 4 |
using Oni.Metadata; |
| 5 |
|
| 6 |
namespace Oni |
| 7 |
{ |
| 8 |
internal sealed class InstanceDescriptor |
| 9 |
{ |
| 10 |
private InstanceFile file; |
| 11 |
private string fullName; |
| 12 |
private int index; |
| 13 |
private Template template; |
| 14 |
private int dataOffset; |
| 15 |
private int nameOffset; |
| 16 |
private int dataSize; |
| 17 |
private InstanceDescriptorFlags flags; |
| 18 |
|
| 19 |
internal static InstanceDescriptor Read(InstanceFile file, BinaryReader reader, int index) |
| 20 |
{ |
| 21 |
var metadata = InstanceMetadata.GetMetadata(file); |
| 22 |
|
| 23 |
var descriptor = new InstanceDescriptor |
| 24 |
{ |
| 25 |
file = file, |
| 26 |
index = index, |
| 27 |
template = metadata.GetTemplate((TemplateTag)reader.ReadInt32()), |
| 28 |
dataOffset = reader.ReadInt32(), |
| 29 |
nameOffset = reader.ReadInt32(), |
| 30 |
dataSize = reader.ReadInt32(), |
| 31 |
flags = (InstanceDescriptorFlags)(reader.ReadInt32() & 0xff) |
| 32 |
}; |
| 33 |
|
| 34 |
if (descriptor.IsPlaceholder && !descriptor.HasName) |
| 35 |
throw new InvalidDataException("Empty descriptors must have names"); |
| 36 |
|
| 37 |
return descriptor; |
| 38 |
} |
| 39 |
|
| 40 |
public InstanceFile File => file; |
| 41 |
|
| 42 |
public int Index => index; |
| 43 |
|
| 44 |
public string FullName |
| 45 |
{ |
| 46 |
get |
| 47 |
{ |
| 48 |
if (fullName == null) |
| 49 |
fullName = index.ToString(); |
| 50 |
|
| 51 |
return fullName; |
| 52 |
} |
| 53 |
} |
| 54 |
|
| 55 |
public string Name |
| 56 |
{ |
| 57 |
get |
| 58 |
{ |
| 59 |
string name = FullName; |
| 60 |
|
| 61 |
if (name.StartsWith(Template.Tag.ToString(), StringComparison.Ordinal)) |
| 62 |
name = name.Substring(4); |
| 63 |
|
| 64 |
return name; |
| 65 |
} |
| 66 |
} |
| 67 |
|
| 68 |
public Template Template => template; |
| 69 |
|
| 70 |
public bool HasName => ((flags & InstanceDescriptorFlags.Private) == 0); |
| 71 |
|
| 72 |
public bool IsPlaceholder => ((flags & InstanceDescriptorFlags.Placeholder) != 0 || dataSize == 0 || dataOffset == 0); |
| 73 |
|
| 74 |
public int DataOffset => file.Header.DataTableOffset + dataOffset; |
| 75 |
|
| 76 |
public int DataSize => dataSize; |
| 77 |
|
| 78 |
internal void ReadName(Dictionary<int, string> names) |
| 79 |
{ |
| 80 |
if (!HasName) |
| 81 |
return; |
| 82 |
|
| 83 |
if (IsPlaceholder || file.Header.Version == InstanceFileHeader.Version31) |
| 84 |
{ |
| 85 |
names.TryGetValue(nameOffset, out fullName); |
| 86 |
} |
| 87 |
else |
| 88 |
{ |
| 89 |
fullName = Importer.DecodeFileName(file.FilePath); |
| 90 |
|
| 91 |
string tagName = template.Tag.ToString(); |
| 92 |
|
| 93 |
if (!fullName.StartsWith(tagName, StringComparison.Ordinal)) |
| 94 |
fullName = tagName + fullName; |
| 95 |
} |
| 96 |
} |
| 97 |
|
| 98 |
internal void SetName(string newName) |
| 99 |
{ |
| 100 |
flags &= ~InstanceDescriptorFlags.Private; |
| 101 |
fullName = newName; |
| 102 |
} |
| 103 |
|
| 104 |
public List<InstanceDescriptor> GetReferencedDescriptors() => file.GetReferencedDescriptors(this); |
| 105 |
|
| 106 |
internal BinaryReader OpenRead() |
| 107 |
{ |
| 108 |
if (IsPlaceholder) |
| 109 |
throw new InvalidOperationException(); |
| 110 |
|
| 111 |
return new BinaryReader(file.FilePath, file) |
| 112 |
{ |
| 113 |
Position = DataOffset |
| 114 |
}; |
| 115 |
} |
| 116 |
|
| 117 |
internal BinaryReader OpenRead(int offset) |
| 118 |
{ |
| 119 |
if (IsPlaceholder) |
| 120 |
throw new InvalidOperationException(); |
| 121 |
|
| 122 |
return new BinaryReader(file.FilePath, file) |
| 123 |
{ |
| 124 |
Position = DataOffset + offset |
| 125 |
}; |
| 126 |
} |
| 127 |
|
| 128 |
internal BinaryReader GetRawReader(int offset) => file.GetRawReader(offset); |
| 129 |
|
| 130 |
internal BinaryReader GetSepReader(int offset) |
| 131 |
{ |
| 132 |
if (!IsMacFile) |
| 133 |
return GetRawReader(offset); |
| 134 |
|
| 135 |
return file.GetSepReader(offset); |
| 136 |
} |
| 137 |
|
| 138 |
internal bool IsMacFile => (file.Header.TemplateChecksum == InstanceFileHeader.OniMacTemplateChecksum); |
| 139 |
|
| 140 |
public long TemplateChecksum => file.Header.TemplateChecksum; |
| 141 |
|
| 142 |
public string FilePath => file.FilePath; |
| 143 |
|
| 144 |
public bool HasRawParts() |
| 145 |
{ |
| 146 |
if (IsPlaceholder) |
| 147 |
return false; |
| 148 |
|
| 149 |
switch (template.Tag) |
| 150 |
{ |
| 151 |
case TemplateTag.AKVA: |
| 152 |
case TemplateTag.AGDB: |
| 153 |
case TemplateTag.BINA: |
| 154 |
case TemplateTag.TXMP: |
| 155 |
case TemplateTag.OSBD: |
| 156 |
case TemplateTag.SNDD: |
| 157 |
case TemplateTag.SUBT: |
| 158 |
case TemplateTag.TRAM: |
| 159 |
return true; |
| 160 |
|
| 161 |
default: |
| 162 |
return false; |
| 163 |
} |
| 164 |
} |
| 165 |
} |
| 166 |
} |