├── 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 | } --------------------------------------------------------------------------------