-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathRmap.cs
More file actions
184 lines (171 loc) · 7.33 KB
/
Copy pathRmap.cs
File metadata and controls
184 lines (171 loc) · 7.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
* Idmr.LfdReader.dll, Library file to read and write LFD resource files
* Copyright (C) 2009-2026 Michael Gaisser (mjgaisser@gmail.com)
* Licensed under the MPL v2.0 or later
*
* Full notice in help/Idmr.LfdReader.chm
* Version: 3.0
*/
/* CHANGE LOG
* v3.0, 260821
* [ADD] Dispose
* v1.1, 141215
* [UPD] changed license to MPL
* v1.0
*/
using System;
using System.IO;
using Idmr.Common;
namespace Idmr.LfdReader
{
/// <summary>Object for "RMAP" header resources.</summary>
/// <remarks>The Rmap resource is the Resource Map for the file.
/// This contains the <see cref="Resource.Type"/>, <see cref="Resource.Name"/> and <see cref="Resource.Length"/> of every Resource in the file.
/// Reading through the Rmap can produce a jump table for the resource.</remarks>
/// <example><h4>Raw Data definition</h4>
/// <code>
/// RawData
/// {
/// /* 0x00 */ SubHeader[Rmap.Length / 16] SubHeaders;
/// }
///
/// SubHeader
/// {
/// /* 0x00 */ char[4] Type;
/// /* 0x04 */ char[8] Name;
/// /* 0x0C */ int Length;
/// }</code>
/// <para>The Rmap's RawData block contains no unique information, as it is merely a listing of the Headers from the other resources in the file.<br/>
/// The Rmap's <see cref="Resource.Name"/> is typically "<b>resource</b>" and <see cref="Resource.Length"/> is <c>(NumberOfHeaders * 16)</c>.</para></example>
public class Rmap : Resource
{
SubHeader[] _headers; // only thing RMAP needs
#region constructors
/// <summary>Creates a new instance with the specified number of SubHeaders.</summary>
/// <param name="numberOfHeaders">The number of entries.</param>
/// <exception cref="ArgumentException"><paramref name="numberOfHeaders"/> must be positive.</exception>
public Rmap(int numberOfHeaders)
{
if (numberOfHeaders < 1) throw new ArgumentException("Invalid number of headers", "numberOfHeaders");
_name = "resource";
_headers = new SubHeader[numberOfHeaders];
_type = ResourceType.Rmap;
}
/// <summary>Creates a new instance from an existing opened file.</summary>
/// <param name="stream">The opened LFD file.</param>
/// <exception cref="LoadFileException">Typically due to file corruption.</exception>
public Rmap(FileStream stream)
{
read(stream);
}
/// <summary>Creates a new instance from an exsiting file.</summary>
/// <param name="path">The full path to the unopened LFD file.</param>
/// <exception cref="LoadFileException">Typically due to file corruption.</exception>
public Rmap(string path)
{
FileStream stream = File.OpenRead(path);
read(stream);
stream.Close();
}
/// <summary>Create a new Rmap instance with the specific LFD template.</summary>
/// <param name="category">The type of LFD file.</param>
/// <exception cref="ArgumentException">Cockpit LFDs do not contain Rmaps<br/><b>-or-</b><br/>Normal LFDs must be initialized with <see cref="Rmap(int)"/>.</exception>
/// <remarks>Only usable with <see cref="LfdFile.LfdCategory.Battle"/> files, initializes for a <see cref="Text"/> and <see cref="Delt"/> resources.</remarks>
public Rmap(LfdFile.LfdCategory category) : this(2)
{
if (category == LfdFile.LfdCategory.Battle)
{
_headers[0].Type = ResourceType.Text;
_headers[0].Name = "battle#";
_headers[0].Offset = HeaderLength;
_headers[0].Length = -1;
_headers[1].Type = ResourceType.Delt;
_headers[1].Name = "b#gal";
_headers[1].Offset = -1;
_headers[1].Length = -1;
}
else if (category == LfdFile.LfdCategory.Cockpit) throw new ArgumentException("Cockpit LFDs do not use RMAP", "category");
else throw new ArgumentException("Normal LFDs must be initialized with Rmap(int)", "category");
}
#endregion constructors
void read(FileStream stream)
{
try { _process(stream, 0); }
catch (Exception x) { throw new LoadFileException(x); }
}
/// <summary>Clean up any resources being used.</summary>
/// <param name="disposing"><see langword="true"/> if managed resources should be disposed; otherwise, <see langword="false"/>.</param>
protected override void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing) { /* do nothing */ }
_headers = null;
base.Dispose(disposing);
}
#region public methods
/// <summary>Processes raw data to populate the resource.</summary>
/// <param name="raw">Raw byte data.</param>
/// <param name="containsHeader">Whether or not <paramref name="raw"/> contains the resource Header information.</param>
/// <exception cref="ArgumentException">Header-defined <see cref="Type"/> is not <see cref="Resource.ResourceType.Rmap"/>.</exception>
public override void DecodeResource(byte[] raw, bool containsHeader)
{
_decodeResource(raw, containsHeader);
if (_type != ResourceType.Rmap) throw new ArgumentException("Raw header is not for a Rmap resource");
int offset = 0;
_headers = new SubHeader[_rawData.Length >> 4];
int resourceOffset = _rawData.Length + HeaderLength;
for (int i = 0; i < _headers.Length; i++)
{
_headers[i].Type = (ResourceType)BitConverter.ToInt32(raw, offset + TypeOffset);
_headers[i].Name = ArrayFunctions.ReadStringFromArray(_rawData, offset + NameOffset, 8);
_headers[i].Length = BitConverter.ToInt32(_rawData, offset + LengthOffset);
_headers[i].Offset = resourceOffset; // store the position of the actual resource
resourceOffset += _headers[i].Length + HeaderLength;
offset += HeaderLength;
}
}
/// <summary>Prepares the resource for writing and updates <see cref="Resource.RawData"/>.</summary>
public override void EncodeResource()
{
byte[] raw = new byte[_headers.Length * HeaderLength];
for (int i = 0; i < _headers.Length; i++)
{
ArrayFunctions.WriteToArray((int)_headers[i].Type, raw, i * HeaderLength + TypeOffset);
ArrayFunctions.WriteToArray(_headers[i].Name, raw, i * HeaderLength + NameOffset);
ArrayFunctions.WriteToArray(_headers[i].Length, raw, i * HeaderLength + LengthOffset);
}
_rawData = raw;
}
#endregion public methods
/// <summary>Gets the number of headers contained within the Rmap.</summary>
public int NumberOfHeaders => _headers.Length;
/// <summary>Gets the SubHeader information within the Rmap.</summary>
public SubHeader[] SubHeaders => _headers;
/// <summary>Represents the information for a single SubHeader.</summary>
public struct SubHeader
{
string _name;
/// <summary>Initialize the SubHeader with the provided details.</summary>
/// <param name="type">Resource Type.</param>
/// <param name="name">Resource Name.</param>
/// <param name="length">Resource Length.</param>
/// <remarks><see cref="Offset"/> initialized to <b>0</b>, <paramref name="name"/> truncated to 8 characters.</remarks>
public SubHeader(ResourceType type, string name, int length)
{
Type = type;
_name = StringFunctions.GetTrimmed(name, 8);
Length = length;
Offset = 0;
}
/// <summary>Gets or sets the Type of the resource.</summary>
public ResourceType Type { get; set; }
/// <summary>Gets or sets the Name of the resource.</summary>
/// <remarks>Value is trimmed to 8 characters.</remarks>
public string Name { get => _name; set => _name = StringFunctions.GetTrimmed(value, 8); }
/// <summary>Gets or sets the Length of the resource.</summary>
public int Length { get; set; }
/// <summary>Gets or sets the File.Position of the resource.</summary>
public int Offset { get; set; }
}
}
}