-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathMpqArchive.cs
More file actions
212 lines (180 loc) · 7.53 KB
/
MpqArchive.cs
File metadata and controls
212 lines (180 loc) · 7.53 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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/*
MBNCSUtil -- Managed Battle.net Authentication Library
Copyright (C) 2005-2008 by Robert Paveza
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1.) Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2.) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3.) The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
See LICENSE.TXT that should have accompanied this software for full terms and
conditions.
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Security.Permissions;
namespace MBNCSUtil.Data
{
/// <summary>
/// Represents an MPQ archive.
/// </summary>
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public class MpqArchive : IDisposable
{
private IntPtr m_hMPQ;
private bool m_disposed;
private List<MpqFileStream> m_files;
[DebuggerStepThrough]
private void checkDisposed()
{
if (m_disposed)
throw new ObjectDisposedException("MpqArchive");
}
internal MpqArchive(string path)
{
m_files = new List<MpqFileStream>();
if (!File.Exists(path))
throw new FileNotFoundException(Resources.fileNotFound, path);
m_hMPQ = LateBoundStormDllApi.SFileOpenArchive(path, 1, 0);
}
/// <summary>
/// Opens the specified file contained within the MPQ.
/// </summary>
/// <param name="mpqFilePath">The path to the file relative to the MPQ root.</param>
/// <returns>An <see cref="MpqFileStream">MpqFileStream</see> to the file within the MPQ.</returns>
/// <exception cref="MpqException">Thrown if the file is not found or there is a problem reading from the MPQ.</exception>
/// <exception cref="ArgumentNullException">Thrown if <c>mpqFilePath</c> is <b>null</b> (<b>Nothing</b> in Visual Basic).</exception>
public MpqFileStream OpenFile(string mpqFilePath)
{
if (mpqFilePath == null) throw new ArgumentNullException(Resources.param_mpqFilePath, Resources.mpqFilePathArgNull);
return new MpqFileStream(mpqFilePath, this);
}
internal IntPtr Handle
{
[DebuggerStepThrough]
get { checkDisposed(); return m_hMPQ; }
}
[DebuggerStepThrough]
internal void FileIsDisposed(MpqFileStream mfs)
{
checkDisposed();
m_files.Remove(mfs);
}
/// <summary>
/// Determines whether the archive contains the specified file.
/// </summary>
/// <param name="fileName">The path to the file relative to the MPQ root.</param>
/// <returns><b>True</b> if the file is contained within the MPQ; otherwise <b>false</b>.</returns>
public bool ContainsFile(string fileName)
{
return LateBoundStormDllApi.SFileHasFile(m_hMPQ, fileName);
}
/// <summary>
/// Saves the specified file to the provided path.
/// </summary>
/// <param name="mpqFileName">The fully-qualified name of the file in the MPQ.</param>
/// <param name="pathBase">The path to which to save the file.</param>
/// <remarks>
/// <para>The file is saved as an immediate child of the path specified in <paramref name="pathBase"/>.</para>
/// </remarks>
public void SaveToPath(string mpqFileName, string pathBase)
{
SaveToPath(mpqFileName, pathBase, false);
}
/// <summary>
/// Saves the specified file to the specified path, optionally expanding the paths used in the MPQ.
/// </summary>
/// <param name="mpqFileName">The fully-qualified name of the file in the MPQ.</param>
/// <param name="pathBase">The root path to which to save the file.</param>
/// <param name="useFullMpqPath">Whether to create child directories based on the path to the file in the MPQ.</param>
public void SaveToPath(string mpqFileName, string pathBase, bool useFullMpqPath)
{
string path;
if (useFullMpqPath)
path = Path.Combine(pathBase, mpqFileName);
else
path = Path.Combine(pathBase, mpqFileName.Substring(mpqFileName.LastIndexOf('\\') + 1));
string directoryName = Path.GetDirectoryName(path);
if (!Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
using (MpqFileStream fs = OpenFile(mpqFileName))
{
byte[] fileData = new byte[fs.Length];
fs.Read(fileData, 0, fileData.Length);
File.WriteAllBytes(path, fileData);
}
}
#region IDisposable Members
/// <summary>
/// Called when the .NET Framework is removing this object from memory.
/// </summary>
~MpqArchive()
{
Dispose(false);
}
/// <summary>
/// Disposes this archive.
/// </summary>
/// <remarks>
/// <para>If you call Dispose on an archive you do not need to call <see cref="MpqServices.CloseArchive">MpqServices.CloseArchive</see> to close it.</para>
/// </remarks>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Cleans up unmanaged resources used by this archive.
/// </summary>
/// <param name="disposing"><c>true</c> if the object is being disposed; <c>false</c> if it is being finalized.</param>
protected virtual void Dispose(bool disposing)
{
if (m_disposed) return;
if (disposing)
{
foreach (MpqFileStream mfs in m_files)
{
mfs.Dispose();
}
m_files.Clear();
m_files = null;
}
if (m_hMPQ != IntPtr.Zero)
{
LateBoundStormDllApi.SFileCloseArchive(m_hMPQ);
}
m_disposed = true;
MpqServices.NotifyArchiveDisposed(this);
}
#endregion
#region IMpqArchive Members
/// <summary>
/// Gets the full text of the MPQ list file.
/// </summary>
/// <remarks>
/// <para>In later versions of Blizzard's games, the developers included a file called "(listfile)" in
/// most MPQ archives identifying the names of the files contained in the MPQ (since they are hashed and
/// therefore unavailable otherwise).</para>
/// </remarks>
/// <returns>A string containing the full text of the list file.</returns>
/// <exception cref="MpqException">Thrown if the list file is not located.</exception>
public string GetListFile()
{
string list = string.Empty;
using (MpqFileStream mfs = OpenFile("(listfile)"))
{
StreamReader sr = new StreamReader(mfs, Encoding.Latin1);
list = sr.ReadToEnd();
sr.Close();
}
return list;
}
#endregion
}
}