├── CODSaveManipulator
├── icon.ico
├── App.config
├── Info.cs
├── Endian.cs
├── Properties
│ └── AssemblyInfo.cs
├── IBaseStream.cs
├── Rehash.cs
├── Offsets.cs
├── Adler.cs
├── Program.cs
├── CODSaveManipulator.csproj
├── IWriter.cs
├── IReader.cs
├── EndianWriter.cs
└── EndianReader.cs
├── COPYING.txt
├── CODSaveManipulator.sln
├── README.md
├── .gitattributes
└── .gitignore
/CODSaveManipulator/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HunterStanton/COD-Save-Manipulator/HEAD/CODSaveManipulator/icon.ico
--------------------------------------------------------------------------------
/CODSaveManipulator/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CODSaveManipulator/Info.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace CODSaveManipulator
8 | {
9 |
10 | ///
11 | /// The class for handling the info option for save manipulator.
12 | ///
13 | class Info
14 | {
15 |
16 | ///
17 | /// Structure that is used to store the time of the save.
18 | ///
19 | public struct qtime_s
20 | {
21 | int tm_sec;
22 | int tm_min;
23 | int tm_hour;
24 | int tm_mday;
25 | int tm_mon;
26 | int tm_year;
27 | int tm_wday;
28 | int tm_yday;
29 | int tm_isdst;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/CODSaveManipulator/Endian.cs:
--------------------------------------------------------------------------------
1 | /* Copyright 2012 Aaron Dierking, TJ Tunnell, Jordan Mueller, Alex Reed
2 | *
3 | * This file is part of ExtryzeDLL.
4 | *
5 | * Extryze is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * Extryze is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with ExtryzeDLL. If not, see .
17 | */
18 |
19 | namespace CODSaveManipulator
20 | {
21 | public enum Endian
22 | {
23 | BigEndian, // MSB -> LSB
24 | LittleEndian // LSB -> MSB
25 | }
26 | }
--------------------------------------------------------------------------------
/COPYING.txt:
--------------------------------------------------------------------------------
1 | Copyright 2017 Hunter Stanton
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/CODSaveManipulator.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CODSaveManipulator", "CODSaveManipulator\CODSaveManipulator.csproj", "{57EC37C0-5E6D-4BF5-942B-EC2BE18988EE}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {57EC37C0-5E6D-4BF5-942B-EC2BE18988EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {57EC37C0-5E6D-4BF5-942B-EC2BE18988EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {57EC37C0-5E6D-4BF5-942B-EC2BE18988EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {57EC37C0-5E6D-4BF5-942B-EC2BE18988EE}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/CODSaveManipulator/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("CODSaveManipulator")]
9 | [assembly: AssemblyDescription("A tool for manipulating saves for the popular Call of Duty series.")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Hunter Stanton")]
12 | [assembly: AssemblyProduct("CODSaveManipulator")]
13 | [assembly: AssemblyCopyright("Copyright © Hunter Stanton 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("57ec37c0-5e6d-4bf5-942b-ec2be18988ee")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # COD-Save-Manipulator
2 | A tool for manipulating Call of Duty savegames. This is a natural evolution of my previous IW/MWX/Ghosts Savegame Fixers, because it has support for virtually all modern CODs outside the Black Ops series, on all platforms, and it detects them all automatically. Just input the save into the program, and it will automatically determine which game it is an on which platform.
3 |
4 | ## Usage
5 | ### Rehash
6 |
7 | CODSaveManipulator -rehash savegame.svg
8 |
9 |
10 | ### Info
11 |
12 | CODSaveManipulator -info savegame.svg
13 |
14 | ## Support
15 | | Game | Supported | Platform (XBox One/PS4 are theoretical and untested) |
16 | | ------------- |:-------------:| :--: |
17 | | Call of Duty | No | PC |
18 | | Call of Duty 2 | No | Xbox 360/PC |
19 | | Call of Duty 3 | No | Xbox 360/PS3/Wii |
20 | | Call of Duty 4: Modern Warfare | Planned | Xbox 360/PS3/PC |
21 | | Call of Duty: World at War | Planned | Xbox 360/PS3/PC |
22 | | Call of Duty: Classic | No | Xbox 360/PS3 |
23 | | Call of Duty: Modern Warfare 2 | Yes | Xbox 360/PS3/PC |
24 | | Call of Duty: Black Ops 1 | No | Xbox 360/PS3/PC/Wii |
25 | | Call of Duty: Modern Warfare 3 | Yes | Xbox 360/PS3/PC/Wii |
26 | | Call of Duty: Black Ops 2 | No | Xbox 360/PS3/PC/WiiU |
27 | | Call of Duty: Ghosts | Yes | Xbox 360/PS3/PC/WiiU/Xbox One/PS4 |
28 | | Call of Duty: Advanced Warfare | Yes | Xbox 360/PS3/PC/Xbox One/PS4 |
29 | | Call of Duty: Black Ops 3 | No | Xbox 360/PS3/PC/Xbox One/PS4
30 | | Call of Duty: Modern Warfare: Remastered | Yes | PC/Xbox One/PS4 |
31 | | Call of Duty: Infinite Warfare | Yes | PC/Xbox One/PS4 |
32 |
--------------------------------------------------------------------------------
/CODSaveManipulator/IBaseStream.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace CODSaveManipulator
5 | {
6 | ///
7 | /// The base interface for the stream classes.
8 | /// User classes should not implement this directly - implement and create an
9 | /// , , or from it instead.
10 | ///
11 | public interface IBaseStream : IDisposable
12 | {
13 | ///
14 | /// Gets whether or not the stream pointer is at the end of the stream.
15 | ///
16 | bool EOF { get; }
17 |
18 | ///
19 | /// Gets the length of the stream in bytes.
20 | ///
21 | long Length { get; }
22 |
23 | ///
24 | /// Gets the current position of the stream pointer.
25 | ///
26 | long Position { get; }
27 |
28 | ///
29 | /// Gets or sets the endianness used when reading/writing to/from the stream.
30 | ///
31 | Endian Endianness { get; set; }
32 |
33 | ///
34 | /// Gets the base Stream object the stream was constructed from.
35 | ///
36 | Stream BaseStream { get; }
37 |
38 | ///
39 | /// Seeks to an offset in the stream.
40 | ///
41 | /// The offset to move the stream pointer to.
42 | /// true if the seek was successful.
43 | bool SeekTo(long offset);
44 |
45 | ///
46 | /// Skips over a number of bytes in the stream.
47 | ///
48 | /// The number of bytes to skip.
49 | void Skip(long count);
50 |
51 | ///
52 | /// Closes the stream, releasing any I/O resources it has acquired.
53 | ///
54 | void Close();
55 | }
56 | }
--------------------------------------------------------------------------------
/CODSaveManipulator/Rehash.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace CODSaveManipulator
8 | {
9 | ///
10 | /// Class for handling the rehash option for save manipulator.
11 | ///
12 | class Rehash
13 | {
14 | static public void RehashSavegame(EndianReader reader, EndianWriter writer)
15 | {
16 | // Get the savegame version
17 | uint ver = reader.ReadUInt32();
18 |
19 | // Get the gamesave offset
20 | uint offset = Offsets.GetDataOffset(ver);
21 |
22 | // Storage variable for the calculated checksum
23 | uint sum = 0;
24 |
25 | // Get the original checksum from the file and store it
26 | reader.BaseStream.Position = 8;
27 | uint origChecksum = reader.ReadUInt32();
28 |
29 | // Put the entire savegame after 0x400 (which is the data that is checksummed by the game) into a buffer
30 | reader.BaseStream.Position = offset;
31 | byte[] buffer = reader.ReadBlock((int)(reader.BaseStream.Length - offset));
32 |
33 | // Calculate adler32 checksum of buffer
34 | Adler adler32 = new Adler();
35 | adler32.Update(buffer);
36 |
37 | // Overwrite the adler32 sum that is stored in the savegame
38 | writer.BaseStream.Position = 0x8;
39 |
40 | sum = (uint)adler32.Value;
41 | writer.WriteUInt32(sum);
42 |
43 | // Print new checksum and original
44 | System.Console.WriteLine("Savegame checksum updated!\nOriginal: " + origChecksum + " (" + origChecksum.ToString("X2") + ")" + "\nNew: " + sum + " (" + sum.ToString("X2") + ")");
45 |
46 | return;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/CODSaveManipulator/Offsets.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 |
8 | namespace CODSaveManipulator
9 | {
10 | ///
11 | /// A class that deals with fixing getting offsets for specific games.
12 | ///
13 | class Offsets
14 | {
15 | ///
16 | /// Gets the data offset for the specific game.
17 | /// The data offset is the offset in the SVG file where the data that will be checksummed begins.
18 | /// Data offset --> EOF is the entire block that is checksummed.
19 | ///
20 | /// The version stored in the savegame.svg. It is different per game, so we can use it to know which game the save is for.
21 | /// The offset for the specific game.
22 | static public uint GetDataOffset(uint ver)
23 | {
24 | switch (ver)
25 | {
26 | // The order in the comment is the order of the cases
27 | // Ghosts, Advanced Warfare, Modern Warfare: Remastered
28 | case 71:
29 | case 95:
30 | case 103:
31 | return 0x500;
32 |
33 | // Infinite Warfare
34 | case 331:
35 | return 0x400;
36 |
37 | // Modern Warfare 2, Modern Warfare 3
38 | case 461:
39 | case 40:
40 | return 0x480;
41 |
42 | // Unknown game, default to 0x500 because that might work because 0x500 is the most common offset which is used in the most games.
43 | default:
44 | Console.WriteLine("Unknown.");
45 | return 500;
46 | }
47 |
48 | // Somehow the switch failed completely, so let's just return 0 ¯\_(ツ)_/¯
49 | return 0x0;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/CODSaveManipulator/Adler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | // Implements Adler32 checksumming, used in calculation of Ghosts savegame checksum
3 |
4 | namespace CODSaveManipulator
5 | {
6 | class Adler
7 | {
8 | private static uint MOD_ADLER = 65521;
9 | private uint Checksum;
10 |
11 | public long Value
12 | {
13 | get
14 | {
15 | return (long)this.Checksum;
16 | }
17 | }
18 |
19 | public Adler()
20 | {
21 | this.Reset();
22 | }
23 |
24 | public void Reset()
25 | {
26 | this.Checksum = 1U;
27 | }
28 |
29 | ///
30 | /// Shorthand version of Update.
31 | ///
32 | /// The buffer of data that will be checksummed.
33 | public void Update(byte[] buff)
34 | {
35 | this.Update(buff, buff.Length);
36 | }
37 |
38 | ///
39 | /// Calculates Adler32 checksum of input buffer.
40 | ///
41 | /// The buffer of data that will be checksummed.
42 | /// How much of the buffer to checksum.
43 | public void Update(byte[] buff, int length)
44 | {
45 | int offset = 0;
46 |
47 | if (buff == null)
48 | {
49 | // Buffer should never be null, if is throw error
50 | throw new ArgumentNullException("buf");
51 | }
52 |
53 | uint check1 = this.Checksum & (uint)ushort.MaxValue;
54 | uint check2 = this.Checksum >> 16;
55 | while (length > 0)
56 | {
57 | int check3 = 3800;
58 |
59 | if (check3 > length)
60 | {
61 | check3 = length;
62 | }
63 |
64 | length -= check3;
65 |
66 | while (--check3 >= 0)
67 | {
68 | check1 += (uint)buff[offset++] & (uint)byte.MaxValue;
69 | check2 += check1;
70 | }
71 |
72 | check1 %= Adler.MOD_ADLER;
73 | check2 %= Adler.MOD_ADLER;
74 | }
75 | this.Checksum = check2 << 16 | check1;
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/CODSaveManipulator/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.IO;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace CODSaveManipulator
9 | {
10 | class Program
11 | {
12 | static void Main(string[] args)
13 | {
14 | if(args.Length != 2)
15 | {
16 | System.Console.WriteLine("CODSaveManipulator\nA program for manipulating Call of Duty savegames in various ways.\n\nFunctions that are currently supported:\n\n-rehash\n Fixes the checksum on a Call of Duty savegame\n Usage: CODSavegameManipulator -rehash \n\n-info\n Prints various information about a savegame\n Usage: CODSavegameManipulator -info ");
17 | return;
18 | }
19 |
20 | FileStream savegameStream = new FileStream(args[1], FileMode.Open, FileAccess.ReadWrite);
21 |
22 | // Open our binary reader so we can parse the saves
23 | var reader = new EndianReader(savegameStream, Endian.LittleEndian);
24 | var writer = new EndianWriter(savegameStream, Endian.LittleEndian);
25 |
26 | // Endian checker
27 | // If the first byte of the save is 0, this means it is big endian
28 | // After getting the endian, reset the stream.
29 | if (reader.ReadInt16() == 0)
30 | {
31 | reader.Endianness = Endian.BigEndian;
32 | writer.Endianness = Endian.BigEndian;
33 | }
34 | reader.BaseStream.Position = 0;
35 |
36 | // Check if STFS package
37 | if (reader.ReadInt16() == 20291)
38 | {
39 | // Close our writer/reader and flush the stream
40 | Console.Write("The file you selected is an Xbox 360 STFS package.\nPlease extract the savegame out of the STFS package before using this tool.");
41 | savegameStream.Flush();
42 | reader.Close();
43 | writer.Close();
44 | return;
45 | }
46 | reader.BaseStream.Position = 0;
47 |
48 | if (args[0] == "-rehash") { Rehash.RehashSavegame(reader, writer); }
49 | if (args[1] == "-info") { return; }
50 | else { Console.WriteLine("Invalid argument " + args[1] + ". Valid arguments are -rehash and -info"); }
51 |
52 | // Flush our stream
53 | savegameStream.Flush();
54 |
55 | // Close up our writer and reader
56 | reader.Close();
57 | writer.Close();
58 |
59 | return;
60 |
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/CODSaveManipulator/CODSaveManipulator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {57EC37C0-5E6D-4BF5-942B-EC2BE18988EE}
8 | Exe
9 | Properties
10 | CODSaveManipulator
11 | CODSaveManipulator
12 | v4.5.2
13 | 512
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | true
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 | true
36 |
37 |
38 | icon.ico
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 |
78 |
--------------------------------------------------------------------------------
/CODSaveManipulator/IWriter.cs:
--------------------------------------------------------------------------------
1 | /* Copyright 2012 Aaron Dierking, TJ Tunnell, Jordan Mueller, Alex Reed
2 | *
3 | * This file is part of ExtryzeDLL.
4 | *
5 | * Extryze is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * Extryze is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with ExtryzeDLL. If not, see .
17 | */
18 |
19 | namespace CODSaveManipulator
20 | {
21 | ///
22 | /// Interface for a stream which can be written to.
23 | ///
24 | public interface IWriter : IBaseStream
25 | {
26 | ///
27 | /// Writes an array of bytes to the stream.
28 | ///
29 | /// The bytes to write.
30 | void WriteBlock(byte[] data);
31 |
32 | ///
33 | /// Writes an array of bytes to the stream.
34 | ///
35 | /// The bytes to write.
36 | /// The starting index in the array to write.
37 | /// The number of bytes to write.
38 | void WriteBlock(byte[] data, int offset, int size);
39 |
40 | ///
41 | /// Writes a byte to the stream.
42 | ///
43 | /// The byte to write.
44 | void WriteByte(byte value);
45 |
46 | ///
47 | /// Writes a signed byte to the stream.
48 | ///
49 | /// The signed byte to write.
50 | void WriteSByte(sbyte value);
51 |
52 | ///
53 | /// Writes a signed 16-bit integer to the stream.
54 | ///
55 | /// The signed 16-bit integer to write.
56 | void WriteInt16(short value);
57 |
58 | ///
59 | /// Writes an unsigned 16-bit integer to the stream.
60 | ///
61 | /// The unsigned 16-bit integer to write.
62 | void WriteUInt16(ushort value);
63 |
64 | ///
65 | /// Writes a signed 32-bit integer to the stream.
66 | ///
67 | /// The signed 32-bit integer to write.
68 | void WriteInt32(int value);
69 |
70 | ///
71 | /// Writes an unsigned 32-bit integer to the stream.
72 | ///
73 | /// The unsigned 32-bit integer to write.
74 | void WriteUInt32(uint value);
75 |
76 | ///
77 | /// Writes a signed 64-bit integer to the stream.
78 | ///
79 | /// The signed 64-bit integer to write.
80 | void WriteInt64(long value);
81 |
82 | ///
83 | /// Writes an unsigned 64-bit integer to the stream.
84 | ///
85 | /// The unsigned 64-bit integer to write.
86 | void WriteUInt64(ulong value);
87 |
88 | ///
89 | /// Writes a 32-bit floating-point value to the stream.
90 | ///
91 | /// The 32-bit floating-point value to write.
92 | void WriteFloat(float value);
93 |
94 | ///
95 | /// Writes an ASCII string to the stream, followed by a null terminator.
96 | ///
97 | /// The ASCII string to write.
98 | void WriteAscii(string str);
99 |
100 | ///
101 | /// Writes a UTF-8 string to the stream, followed by a null terminator.
102 | ///
103 | /// The UTF-8 string to write.
104 | void WriteUTF8(string str);
105 |
106 | ///
107 | /// Writes a UTF-16 string to the stream, followed by a null terminator.
108 | ///
109 | /// The UTF-16 string to write.
110 | void WriteUTF16(string str);
111 | }
112 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Windows Store app package directory
170 | AppPackages/
171 | BundleArtifacts/
172 |
173 | # Visual Studio cache files
174 | # files ending in .cache can be ignored
175 | *.[Cc]ache
176 | # but keep track of directories ending in .cache
177 | !*.[Cc]ache/
178 |
179 | # Others
180 | ClientBin/
181 | [Ss]tyle[Cc]op.*
182 | ~$*
183 | *~
184 | *.dbmdl
185 | *.dbproj.schemaview
186 | *.pfx
187 | *.publishsettings
188 | node_modules/
189 | orleans.codegen.cs
190 |
191 | # RIA/Silverlight projects
192 | Generated_Code/
193 |
194 | # Backup & report files from converting an old project file
195 | # to a newer Visual Studio version. Backup files are not needed,
196 | # because we have git ;-)
197 | _UpgradeReport_Files/
198 | Backup*/
199 | UpgradeLog*.XML
200 | UpgradeLog*.htm
201 |
202 | # SQL Server files
203 | *.mdf
204 | *.ldf
205 |
206 | # Business Intelligence projects
207 | *.rdl.data
208 | *.bim.layout
209 | *.bim_*.settings
210 |
211 | # Microsoft Fakes
212 | FakesAssemblies/
213 |
214 | # GhostDoc plugin setting file
215 | *.GhostDoc.xml
216 |
217 | # Node.js Tools for Visual Studio
218 | .ntvs_analysis.dat
219 |
220 | # Visual Studio 6 build log
221 | *.plg
222 |
223 | # Visual Studio 6 workspace options file
224 | *.opt
225 |
226 | # Visual Studio LightSwitch build output
227 | **/*.HTMLClient/GeneratedArtifacts
228 | **/*.DesktopClient/GeneratedArtifacts
229 | **/*.DesktopClient/ModelManifest.xml
230 | **/*.Server/GeneratedArtifacts
231 | **/*.Server/ModelManifest.xml
232 | _Pvt_Extensions
233 |
234 | # LightSwitch generated files
235 | GeneratedArtifacts/
236 | ModelManifest.xml
237 |
238 | # Paket dependency manager
239 | .paket/paket.exe
240 |
241 | # FAKE - F# Make
242 | .fake/
243 |
--------------------------------------------------------------------------------
/CODSaveManipulator/IReader.cs:
--------------------------------------------------------------------------------
1 | /* Copyright 2012 Aaron Dierking, TJ Tunnell, Jordan Mueller, Alex Reed
2 | *
3 | * This file is part of ExtryzeDLL.
4 | *
5 | * Extryze is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * Extryze is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with ExtryzeDLL. If not, see .
17 | */
18 |
19 | namespace CODSaveManipulator
20 | {
21 | ///
22 | /// Interface for a stream which can be read from.
23 | ///
24 | public interface IReader : IBaseStream
25 | {
26 | ///
27 | /// Reads an array of bytes from the stream.
28 | ///
29 | /// The array to store the read bytes to.
30 | /// The starting index in the array to read to.
31 | /// The number of bytes to read.
32 | /// The number of bytes that were actually read.
33 | int ReadBlock(byte[] output, int offset, int size);
34 |
35 | ///
36 | /// Reads an array of bytes from the stream.
37 | ///
38 | /// The number of bytes to read.
39 | /// The bytes that were read.
40 | byte[] ReadBlock(int size);
41 |
42 | ///
43 | /// Reads a byte from the stream.
44 | ///
45 | /// The byte that was read.
46 | byte ReadByte();
47 |
48 | ///
49 | /// Reads a signed byte from the stream.
50 | ///
51 | /// The signed byte that was read.
52 | sbyte ReadSByte();
53 |
54 | ///
55 | /// Reads a 16-bit signed integer from the stream.
56 | ///
57 | /// The 16-bit signed integer that was read.
58 | short ReadInt16();
59 |
60 | ///
61 | /// Reads a 16-bit unsigned integer from the stream.
62 | ///
63 | /// The 16-bit unsigned integer that was read.
64 | ushort ReadUInt16();
65 |
66 | ///
67 | /// Reads a 32-bit signed integer from the stream.
68 | ///
69 | /// The 32-bit signed integer that was read.
70 | int ReadInt32();
71 |
72 | ///
73 | /// Reads a 32-bit unsigned integer from the stream.
74 | ///
75 | /// The 32-bit unsigned integer that was read.
76 | uint ReadUInt32();
77 |
78 | ///
79 | /// Reads a 64-bit signed integer from the stream.
80 | ///
81 | /// The 64-bit signed integer that was read.
82 | long ReadInt64();
83 |
84 | ///
85 | /// Reads a 64-bit unsigned integer from the stream.
86 | ///
87 | /// The 64-bit unsigned integer that was read.
88 | ulong ReadUInt64();
89 |
90 | ///
91 | /// Reads a 32-bit floating-point value from the stream.
92 | ///
93 | /// The 32-bit floating-point value that was read.
94 | float ReadFloat();
95 |
96 | ///
97 | /// Reads a null-terminated ASCII string from the stream.
98 | ///
99 | /// The ASCII string that was read.
100 | string ReadAscii();
101 |
102 | ///
103 | /// Reads a fixed-size null-terminated ASCII string from the stream.
104 | ///
105 | /// The size of the string to read, including the null terminator.
106 | /// The ASCII string that was read, with any 0 padding bytes stripped.
107 | string ReadAscii(int size);
108 |
109 | ///
110 | /// Reads a null-terminated UTF-8 string from the stream.
111 | ///
112 | /// The null-terminated UTF-8 string that was read.
113 | string ReadUTF8();
114 |
115 | ///
116 | /// Reads a fixed-size null-terminated UTF-8 string from the stream.
117 | ///
118 | /// The size in bytes of the string to read, including the null terminator.
119 | /// The UTF-8 string that was read, with any padding bytes stripped.
120 | string ReadUTF8(int size);
121 |
122 | ///
123 | /// Reads a null-terminated UTF-16 string from the stream.
124 | ///
125 | /// The UTF-16 string that was read.
126 | string ReadUTF16();
127 |
128 | ///
129 | /// Reads a fixed-size null-terminated UTF-16 string from the stream.
130 | ///
131 | /// The size in bytes of the string to read, including the null terminator.
132 | /// The UTF-16 string that was read, with any padding bytes stripped.
133 | string ReadUTF16(int size);
134 | }
135 | }
--------------------------------------------------------------------------------
/CODSaveManipulator/EndianWriter.cs:
--------------------------------------------------------------------------------
1 | /* Copyright 2012 Aaron Dierking, TJ Tunnell, Jordan Mueller, Alex Reed
2 | *
3 | * This file is part of ExtryzeDLL.
4 | *
5 | * Extryze is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * Extryze is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with ExtryzeDLL. If not, see .
17 | */
18 |
19 | using System;
20 | using System.IO;
21 | using System.Text;
22 |
23 | namespace CODSaveManipulator
24 | {
25 | ///
26 | /// A stream which can be written to and whose endianness can be changed.
27 | ///
28 | public class EndianWriter : IWriter, IDisposable
29 | {
30 | private readonly byte[] _buffer = new byte[8];
31 | private readonly Stream _stream;
32 | private bool _bigEndian;
33 |
34 | ///
35 | /// Initializes a new instance of the class.
36 | ///
37 | /// The stream to write to.
38 | /// The initial endianness to use when writing to the stream.
39 | public EndianWriter(Stream stream, Endian endianness)
40 | {
41 | _stream = stream;
42 | _bigEndian = (endianness == Endian.BigEndian);
43 | }
44 |
45 | ///
46 | /// Gets or sets the endianness used when reading/writing to/from the stream.
47 | ///
48 | public Endian Endianness
49 | {
50 | get { return _bigEndian ? Endian.BigEndian : Endian.LittleEndian; }
51 | set { _bigEndian = (value == Endian.BigEndian); }
52 | }
53 |
54 | ///
55 | /// Closes the stream, releasing any I/O resources it has acquired.
56 | ///
57 | public void Close()
58 | {
59 | _stream.Close();
60 | }
61 |
62 | ///
63 | /// Writes a byte to the stream.
64 | ///
65 | /// The byte to write.
66 | public void WriteByte(byte value)
67 | {
68 | _buffer[0] = value;
69 | _stream.Write(_buffer, 0, 1);
70 | }
71 |
72 | ///
73 | /// Writes a signed byte to the stream.
74 | ///
75 | /// The signed byte to write.
76 | public void WriteSByte(sbyte value)
77 | {
78 | WriteByte((byte) value);
79 | }
80 |
81 | ///
82 | /// Writes an unsigned 16-bit integer to the stream.
83 | ///
84 | /// The unsigned 16-bit integer to write.
85 | public void WriteUInt16(ushort value)
86 | {
87 | if (_bigEndian)
88 | {
89 | _buffer[0] = (byte) (value >> 8);
90 | _buffer[1] = (byte) (value & 0xFF);
91 | }
92 | else
93 | {
94 | _buffer[0] = (byte) (value & 0xFF);
95 | _buffer[1] = (byte) (value >> 8);
96 | }
97 | _stream.Write(_buffer, 0, 2);
98 | }
99 |
100 | ///
101 | /// Writes a signed 16-bit integer to the stream.
102 | ///
103 | /// The signed 16-bit integer to write.
104 | public void WriteInt16(short value)
105 | {
106 | WriteUInt16((ushort) value);
107 | }
108 |
109 | ///
110 | /// Writes an unsigned 32-bit integer to the stream.
111 | ///
112 | /// The unsigned 32-bit integer to write.
113 | public void WriteUInt32(uint value)
114 | {
115 | if (_bigEndian)
116 | {
117 | _buffer[0] = (byte) (value >> 24);
118 | _buffer[1] = (byte) ((value >> 16) & 0xFF);
119 | _buffer[2] = (byte) ((value >> 8) & 0xFF);
120 | _buffer[3] = (byte) (value & 0xFF);
121 | }
122 | else
123 | {
124 | _buffer[0] = (byte) (value & 0xFF);
125 | _buffer[1] = (byte) ((value >> 8) & 0xFF);
126 | _buffer[2] = (byte) ((value >> 16) & 0xFF);
127 | _buffer[3] = (byte) (value >> 24);
128 | }
129 | _stream.Write(_buffer, 0, 4);
130 | }
131 |
132 | ///
133 | /// Writes a signed 32-bit integer to the stream.
134 | ///
135 | /// The signed 32-bit integer to write.
136 | public void WriteInt32(int value)
137 | {
138 | WriteUInt32((uint) value);
139 | }
140 |
141 | ///
142 | /// Writes an unsigned 64-bit integer to the stream.
143 | ///
144 | /// The unsigned 64-bit integer to write.
145 | public void WriteUInt64(ulong value)
146 | {
147 | if (_bigEndian)
148 | {
149 | _buffer[0] = (byte) (value >> 56);
150 | _buffer[1] = (byte) ((value >> 48) & 0xFF);
151 | _buffer[2] = (byte) ((value >> 40) & 0xFF);
152 | _buffer[3] = (byte) ((value >> 32) & 0xFF);
153 | _buffer[4] = (byte) ((value >> 24) & 0xFF);
154 | _buffer[5] = (byte) ((value >> 16) & 0xFF);
155 | _buffer[6] = (byte) ((value >> 8) & 0xFF);
156 | _buffer[7] = (byte) (value & 0xFF);
157 | }
158 | else
159 | {
160 | _buffer[0] = (byte) (value & 0xFF);
161 | _buffer[1] = (byte) ((value >> 8) & 0xFF);
162 | _buffer[2] = (byte) ((value >> 16) & 0xFF);
163 | _buffer[3] = (byte) ((value >> 24) & 0xFF);
164 | _buffer[4] = (byte) ((value >> 32) & 0xFF);
165 | _buffer[5] = (byte) ((value >> 40) & 0xFF);
166 | _buffer[6] = (byte) ((value >> 48) & 0xFF);
167 | _buffer[7] = (byte) (value >> 56);
168 | }
169 | _stream.Write(_buffer, 0, 8);
170 | }
171 |
172 | ///
173 | /// Writes a signed 64-bit integer to the stream.
174 | ///
175 | /// The signed 64-bit integer to write.
176 | public void WriteInt64(long value)
177 | {
178 | WriteUInt64((ulong) value);
179 | }
180 |
181 | ///
182 | /// Writes a 32-bit floating-point value to the stream.
183 | ///
184 | /// The 32-bit floating-point value to write.
185 | public void WriteFloat(float value)
186 | {
187 | byte[] bytes = BitConverter.GetBytes(value);
188 | if (BitConverter.IsLittleEndian == _bigEndian)
189 | {
190 | // Is there a faster way to do this?
191 | byte temp = bytes[0];
192 | bytes[0] = bytes[3];
193 | bytes[3] = temp;
194 | temp = bytes[1];
195 | bytes[1] = bytes[2];
196 | bytes[2] = temp;
197 | }
198 | _stream.Write(bytes, 0, bytes.Length);
199 | }
200 |
201 | ///
202 | /// Writes an ASCII string to the stream, followed by a null terminator.
203 | ///
204 | /// The ASCII string to write.
205 | public void WriteAscii(string str)
206 | {
207 | byte[] bytes = Encoding.ASCII.GetBytes(str);
208 | WriteBlock(bytes);
209 | WriteByte(0);
210 | }
211 |
212 | ///
213 | /// Writes a UTF-8 string to the stream, followed by a null terminator.
214 | ///
215 | /// The UTF-8 string to write.
216 | public void WriteUTF8(string str)
217 | {
218 | byte[] bytes = Encoding.UTF8.GetBytes(str);
219 | WriteBlock(bytes);
220 | WriteByte(0);
221 | }
222 |
223 | ///
224 | /// Writes a UTF-16 string to the stream, followed by a null terminator.
225 | ///
226 | /// The UTF-16 string to write.
227 | public void WriteUTF16(string str)
228 | {
229 | foreach (char ch in str)
230 | WriteInt16((short) ch);
231 | WriteInt16(0x0000);
232 | }
233 |
234 | ///
235 | /// Writes an array of bytes to the stream.
236 | ///
237 | /// The bytes to write.
238 | public void WriteBlock(byte[] data)
239 | {
240 | _stream.Write(data, 0, data.Length);
241 | }
242 |
243 | ///
244 | /// Writes an array of bytes to the stream.
245 | ///
246 | /// The bytes to write.
247 | /// The starting index in the array to write.
248 | /// The number of bytes to write.
249 | public void WriteBlock(byte[] data, int offset, int size)
250 | {
251 | _stream.Write(data, offset, size);
252 | }
253 |
254 | ///
255 | /// Seeks to an offset in the stream.
256 | ///
257 | /// The offset to move the stream pointer to.
258 | ///
259 | /// true if the seek was successful.
260 | ///
261 | public bool SeekTo(long offset)
262 | {
263 | if (offset < 0)
264 | return false;
265 | _stream.Seek(offset, SeekOrigin.Begin);
266 | return true;
267 | }
268 |
269 | ///
270 | /// Skips over a number of bytes in the stream.
271 | ///
272 | /// The number of bytes to skip.
273 | public void Skip(long count)
274 | {
275 | _stream.Seek(count, SeekOrigin.Current);
276 | }
277 |
278 | ///
279 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
280 | ///
281 | public void Dispose()
282 | {
283 | _stream.Dispose();
284 | }
285 |
286 | ///
287 | /// Gets whether or not the stream pointer is at the end of the stream.
288 | ///
289 | public bool EOF
290 | {
291 | get { return (Position >= Length); }
292 | }
293 |
294 | ///
295 | /// Gets the current position of the stream pointer.
296 | ///
297 | public long Position
298 | {
299 | get { return _stream.Position; }
300 | }
301 |
302 | ///
303 | /// Gets the length of the stream in bytes.
304 | ///
305 | public long Length
306 | {
307 | get { return _stream.Length; }
308 | }
309 |
310 | ///
311 | /// Gets the base Stream object the stream was constructed from.
312 | ///
313 | public Stream BaseStream
314 | {
315 | get { return _stream; }
316 | }
317 | }
318 | }
--------------------------------------------------------------------------------
/CODSaveManipulator/EndianReader.cs:
--------------------------------------------------------------------------------
1 | /* Copyright 2012 Aaron Dierking, TJ Tunnell, Jordan Mueller, Alex Reed
2 | *
3 | * This file is part of ExtryzeDLL.
4 | *
5 | * Extryze is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * Extryze is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with ExtryzeDLL. If not, see .
17 | */
18 |
19 | using System;
20 | using System.Collections.Generic;
21 | using System.IO;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace CODSaveManipulator
26 | {
27 | ///
28 | /// A stream which can be read from and whose endianness can be changed.
29 | ///
30 | public class EndianReader : IDisposable, IReader
31 | {
32 | private readonly byte[] _buffer = new byte[8];
33 | private readonly StringBuilder _currentString = new StringBuilder();
34 | private readonly Stream _stream;
35 | private bool _bigEndian;
36 |
37 | ///
38 | /// Initializes a new instance of the class.
39 | ///
40 | /// The stream to read from.
41 | /// The initial endianness to use when reading from the stream.
42 | public EndianReader(Stream stream, Endian endianness)
43 | {
44 | _stream = stream;
45 | _bigEndian = (endianness == Endian.BigEndian);
46 | }
47 |
48 | ///
49 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
50 | ///
51 | public void Dispose()
52 | {
53 | Close();
54 | }
55 |
56 | ///
57 | /// Gets or sets the endianness used when reading/writing to/from the stream.
58 | ///
59 | public Endian Endianness
60 | {
61 | get { return _bigEndian ? Endian.BigEndian : Endian.LittleEndian; }
62 | set { _bigEndian = (value == Endian.BigEndian); }
63 | }
64 |
65 | ///
66 | /// Closes the stream, releasing any I/O resources it has acquired.
67 | ///
68 | public void Close()
69 | {
70 | _stream.Close();
71 | }
72 |
73 | ///
74 | /// Reads a byte from the stream.
75 | ///
76 | ///
77 | /// The byte that was read.
78 | ///
79 | public byte ReadByte()
80 | {
81 | _stream.Read(_buffer, 0, 1);
82 | return _buffer[0];
83 | }
84 |
85 | ///
86 | /// Reads a signed byte from the stream.
87 | ///
88 | ///
89 | /// The signed byte that was read.
90 | ///
91 | public sbyte ReadSByte()
92 | {
93 | return (sbyte) ReadByte();
94 | }
95 |
96 | ///
97 | /// Reads a 16-bit unsigned integer from the stream.
98 | ///
99 | ///
100 | /// The 16-bit unsigned integer that was read.
101 | ///
102 | public ushort ReadUInt16()
103 | {
104 | _stream.Read(_buffer, 0, 2);
105 | if (_bigEndian)
106 | return (ushort) ((_buffer[0] << 8) | _buffer[1]);
107 | return (ushort) ((_buffer[1] << 8) | _buffer[0]);
108 | }
109 |
110 | ///
111 | /// Reads a 16-bit signed integer from the stream.
112 | ///
113 | ///
114 | /// The 16-bit signed integer that was read.
115 | ///
116 | public short ReadInt16()
117 | {
118 | return (short) ReadUInt16();
119 | }
120 |
121 | ///
122 | /// Reads a 32-bit unsigned integer from the stream.
123 | ///
124 | ///
125 | /// The 32-bit unsigned integer that was read.
126 | ///
127 | public uint ReadUInt32()
128 | {
129 | _stream.Read(_buffer, 0, 4);
130 | if (_bigEndian)
131 | return (uint) ((_buffer[0] << 24) | (_buffer[1] << 16) | (_buffer[2] << 8) | _buffer[3]);
132 | return (uint) ((_buffer[3] << 24) | (_buffer[2] << 16) | (_buffer[1] << 8) | _buffer[0]);
133 | }
134 |
135 | ///
136 | /// Reads a 32-bit signed integer from the stream.
137 | ///
138 | ///
139 | /// The 32-bit signed integer that was read.
140 | ///
141 | public int ReadInt32()
142 | {
143 | return (int) ReadUInt32();
144 | }
145 |
146 | ///
147 | /// Reads a 64-bit unsigned integer from the stream.
148 | ///
149 | ///
150 | /// The 64-bit unsigned integer that was read.
151 | ///
152 | public ulong ReadUInt64()
153 | {
154 | /*_stream.Read(_buffer, 0, 8);
155 | return (ulong)((_buffer[0] << 56) | (_buffer[1] << 48) | (_buffer[2] << 40) | (_buffer[3] << 32) |
156 | (_buffer[4] << 24) | (_buffer[5] << 16) | (_buffer[6] << 8) | _buffer[7]);*/
157 | ulong one = ReadUInt32();
158 | ulong two = ReadUInt32();
159 | if (_bigEndian)
160 | return (one << 32) | two;
161 | return (two << 32) | one;
162 | }
163 |
164 | ///
165 | /// Reads a 64-bit signed integer from the stream.
166 | ///
167 | ///
168 | /// The 64-bit signed integer that was read.
169 | ///
170 | public long ReadInt64()
171 | {
172 | /*_stream.Read(_buffer, 0, 8);
173 | return (long)((_buffer[0] << 56) | (_buffer[1] << 48) | (_buffer[2] << 40) | (_buffer[3] << 32) |
174 | (_buffer[4] << 24) | (_buffer[5] << 16) | (_buffer[6] << 8) | _buffer[7]);*/
175 | return (long) ReadUInt64();
176 | }
177 |
178 | ///
179 | /// Reads a 32-bit floating-point value from the stream.
180 | ///
181 | ///
182 | /// The 32-bit floating-point value that was read.
183 | ///
184 | public float ReadFloat()
185 | {
186 | _stream.Read(_buffer, 0, 4);
187 | if (BitConverter.IsLittleEndian == _bigEndian)
188 | {
189 | // Flip the bytes
190 | // Is there a faster way to do this?
191 | byte temp = _buffer[0];
192 | _buffer[0] = _buffer[3];
193 | _buffer[3] = temp;
194 | temp = _buffer[1];
195 | _buffer[1] = _buffer[2];
196 | _buffer[2] = temp;
197 | }
198 | return BitConverter.ToSingle(_buffer, 0);
199 | }
200 |
201 | ///
202 | /// Seeks to an offset in the stream.
203 | ///
204 | /// The offset to move the stream pointer to.
205 | ///
206 | /// true if the seek was successful.
207 | ///
208 | public bool SeekTo(long offset)
209 | {
210 | if (offset < 0)
211 | return false;
212 | _stream.Seek(offset, SeekOrigin.Begin);
213 | return true;
214 | }
215 |
216 | ///
217 | /// Skips over a number of bytes in the stream.
218 | ///
219 | /// The number of bytes to skip.
220 | public void Skip(long count)
221 | {
222 | _stream.Seek(count, SeekOrigin.Current);
223 | }
224 |
225 | ///
226 | /// Reads a null-terminated ASCII string from the stream.
227 | ///
228 | ///
229 | /// The ASCII string that was read.
230 | ///
231 | public string ReadAscii()
232 | {
233 | _currentString.Clear();
234 | int ch;
235 | while (true)
236 | {
237 | ch = _stream.ReadByte();
238 | if (ch == 0 || ch == -1)
239 | break;
240 | _currentString.Append((char) ch);
241 | }
242 | return _currentString.ToString();
243 | }
244 |
245 | ///
246 | /// Reads a fixed-size null-terminated ASCII string from the stream.
247 | ///
248 | /// The size of the string to read, including the null terminator.
249 | ///
250 | /// The ASCII string that was read, with any 0 padding bytes stripped.
251 | ///
252 | public unsafe string ReadAscii(int size)
253 | {
254 | var chars = new sbyte[size];
255 | string result;
256 | fixed (sbyte* str = chars)
257 | {
258 | _stream.Read((byte[]) (Array) chars, 0, size);
259 | result = new string(str);
260 | }
261 | return result;
262 | }
263 |
264 | ///
265 | /// Reads a null-terminated UTF-8 string from the stream.
266 | ///
267 | ///
268 | /// The null-terminated UTF-8 string that was read.
269 | ///
270 | public unsafe string ReadUTF8()
271 | {
272 | var chars = new List();
273 | sbyte ch;
274 | while (true)
275 | {
276 | ch = ReadSByte();
277 | if (ch == 0)
278 | break;
279 | chars.Add(ch);
280 | }
281 |
282 | sbyte[] charss = chars.ToArray();
283 | fixed (sbyte* prt = charss)
284 | return new string(prt, 0, chars.Count, Encoding.UTF8);
285 | }
286 |
287 | ///
288 | /// Reads a fixed-size null-terminated UTF-8 string from the stream.
289 | ///
290 | /// The size in bytes of the string to read, including the null terminator.
291 | ///
292 | /// The UTF-8 string that was read, with any padding bytes stripped.
293 | ///
294 | public unsafe string ReadUTF8(int size)
295 | {
296 | var chars = new sbyte[size];
297 | string result;
298 | fixed (sbyte* str = chars)
299 | {
300 | _stream.Read((byte[]) (Array) chars, 0, size);
301 | result = new string(str, 0, size, Encoding.UTF8);
302 | }
303 | return result;
304 | }
305 |
306 | ///
307 | /// Reads a null-terminated UTF-16 string from the stream.
308 | ///
309 | ///
310 | /// The UTF-16 string that was read.
311 | ///
312 | public string ReadUTF16()
313 | {
314 | _currentString.Clear();
315 | int ch;
316 | while (true)
317 | {
318 | ch = ReadInt16();
319 | if (ch == 0)
320 | break;
321 | _currentString.Append((char) ch);
322 | }
323 | return _currentString.ToString();
324 | }
325 |
326 | ///
327 | /// Reads a fixed-size null-terminated UTF-16 string from the stream.
328 | ///
329 | /// The size in bytes of the string to read, including the null terminator.
330 | ///
331 | /// The UTF-16 string that was read, with any padding bytes stripped.
332 | ///
333 | public string ReadUTF16(int size)
334 | {
335 | _currentString.Clear();
336 | int ch;
337 | while (_currentString.Length*2 < size)
338 | {
339 | ch = ReadInt16();
340 | if (ch == 0)
341 | break;
342 | _currentString.Append((char) ch);
343 | }
344 | Skip(size - _currentString.Length*2);
345 | return _currentString.ToString();
346 | }
347 |
348 | ///
349 | /// Reads an array of bytes from the stream.
350 | ///
351 | /// The number of bytes to read.
352 | ///
353 | /// The bytes that were read.
354 | ///
355 | public byte[] ReadBlock(int size)
356 | {
357 | var result = new byte[size];
358 | _stream.Read(result, 0, size);
359 | return result;
360 | }
361 |
362 | ///
363 | /// Reads an array of bytes from the stream.
364 | ///
365 | /// The array to store the read bytes to.
366 | /// The starting index in the array to read to.
367 | /// The number of bytes to read.
368 | ///
369 | /// The number of bytes that were actually read.
370 | ///
371 | public int ReadBlock(byte[] output, int offset, int size)
372 | {
373 | return _stream.Read(output, offset, size);
374 | }
375 |
376 | ///
377 | /// Gets whether or not the stream pointer is at the end of the stream.
378 | ///
379 | public bool EOF
380 | {
381 | get { return (Position >= Length); }
382 | }
383 |
384 | ///
385 | /// Gets the current position of the stream pointer.
386 | ///
387 | public long Position
388 | {
389 | get { return _stream.Position; }
390 | }
391 |
392 | ///
393 | /// Gets the length of the stream in bytes.
394 | ///
395 | public long Length
396 | {
397 | get { return _stream.Length; }
398 | }
399 |
400 | ///
401 | /// Gets the base Stream object the stream was constructed from.
402 | ///
403 | public Stream BaseStream
404 | {
405 | get { return _stream; }
406 | }
407 | }
408 | }
--------------------------------------------------------------------------------