public ReplayHeader ParseReplayHeader(byte[] totalReplayBytes, out int currIndex) { currIndex = 0; byte[] replayHeaderBytes = totalReplayBytes.SubArray(0, HEADER_SIZE); ReplayHeader parsedReplayHeader = new ReplayHeader(replayHeaderBytes); //Check if the replay file starts with the expected header string of "Warcraft III recorded game" byte[] replayStartHeader = replayHeaderBytes.SubArray(0, REPLAY_HEADER_ST_BYTES.Length); if (!replayStartHeader.SequenceEqual(REPLAY_HEADER_ST_BYTES)) { throw new InvalidDataException(String.Format(ERROR_INVALID_HEADER_START_STRING, Encoding.UTF8.GetString(replayStartHeader))); } currIndex += REPLAY_HEADER_ST_BYTES.Length; //Move 26 characters forward //Get file offset uint replayFileOffset = ByteUtility.ReadDoubleWord(replayHeaderBytes, currIndex); if (replayFileOffset != FILE_OFFSET_FIRST_COMPRESSED_DATA_BLOCK) { throw new InvalidDataException(String.Format(ERROR_INVALID_REPLAY_FILE_OFFSET, BitConverter.ToString(BitConverter.GetBytes(replayFileOffset)))); } currIndex += 4; //Get overall size of compressed file uint compressedFileSize = ByteUtility.ReadDoubleWord(replayHeaderBytes, currIndex); parsedReplayHeader.CompressedFileSize = compressedFileSize; currIndex += 4; //Get replay version uint replayHeaderVersion = ByteUtility.ReadDoubleWord(replayHeaderBytes, currIndex); if (replayHeaderVersion != SUPPORTED_REPLAY_HEADER_VERSION) { throw new InvalidDataException(String.Format(ERROR_INVALID_REPLAY_HEADER_VERSION, BitConverter.ToString(BitConverter.GetBytes(replayHeaderVersion)))); } currIndex += 4; //Get overall size of decompressed file uint decompressedFileSize = ByteUtility.ReadDoubleWord(replayHeaderBytes, currIndex); parsedReplayHeader.DecompressedFileSize = decompressedFileSize; currIndex += 4; //Get total number of compressed data blocks in file uint compressedDataBlockCount = ByteUtility.ReadDoubleWord(replayHeaderBytes, currIndex); parsedReplayHeader.CompressedDataBlockCount = (int)compressedDataBlockCount; currIndex += 4; //Start SubHeaderParsing (Version 1) //Get version identifier (Classic, TFT) string clientType = ByteUtility.ReadDoubleWordString(replayHeaderBytes, currIndex); if (clientType != SUPPORTED_WC3_CLIENT_TYPE) { throw new InvalidDataException(String.Format(ERROR_INVALID_REPLAY_CLIENT_TYPE, clientType)); } currIndex += 4; //Get Client Version Number string replayVersion = ByteUtility.ReadDoubleWordString(replayHeaderBytes, currIndex); double replayVersionValue = 0; Double.TryParse(replayVersion, out replayVersionValue); //For some reason, replays generated by GHost doesn't follow the standard replay format //This part is commented out until I figure out what's going on //if (replayVersionValue < 1.0 && replayVersionValue > 2.0) //{ // throw new InvalidDataException(String.Format(ERROR_INVALID_REPLAY_VERSION, replayVersion)); //} parsedReplayHeader.ReplayVersion = replayVersion; currIndex += 4; ushort buildNumber = ByteUtility.ReadWord(replayHeaderBytes, currIndex); parsedReplayHeader.BuildNumber = buildNumber; currIndex += 2; ushort flag = ByteUtility.ReadWord(replayHeaderBytes, currIndex); if (flag != FLAG_MULTIPLAYER) { //throw new InvalidDataException(String.Format(ERROR_INVALID_GAME_TYPE, BitConverter.ToString(BitConverter.GetBytes(flag)))); } currIndex += 2; uint replayLength = ByteUtility.ReadDoubleWord(replayHeaderBytes, currIndex); parsedReplayHeader.ReplayLength = replayLength; currIndex += 4; uint checksum = ByteUtility.ReadDoubleWord(replayHeaderBytes, currIndex); parsedReplayHeader.CRC32 = checksum; currIndex += 4; return(parsedReplayHeader); }