//this ensures that only human players and observers are parsed
        //empty, closed, unused, and computer occupied slots are skipped
        //it may be worthwhile to eventually parse the other slots
        private void ParseSlotRecords(byte[] replayData, ref int index, ref Warcraft3Replay replay)
        {
            ushort ID;
            byte numSlots = replayData[index += 2];
            index++;

            for (int i = 0; i < numSlots; i++)
            {
                ID = replayData[index++]; //0x00 for comp

                //if the player exists in the slot
                if (ID != 0x00)
                {
                    Warcraft3Player player = replay.players[ID];
                    player.DownloadPercent = replayData[index++];
                    player.SlotStatus = replayData[index++];
                    player.PlayerFlag = replayData[index++];
                    player.TeamNumber = replayData[index++];
                    player.Color = replayData[index++];
                    player.RaceFlag = replayData[index++];
                    player.CompStrength = replayData[index++];
                    player.Handicap = replayData[index++];

                    //mapping the slot to the player
                    replay.slots[i] = ID;

                    if (player.TeamNumber != 12)
                    {
                        player.Prepare();

                        if (!replay.teams.ContainsKey(player.TeamNumber))
                        {
                            replay.teams.Add(player.TeamNumber, new List<Warcraft3Player>());
                            replay.teams[player.TeamNumber].Add(player);
                        }
                        else
                        {
                            replay.teams[player.TeamNumber].Add(player);
                        }
                    }
                }
                else
                {
                    index += 8;
                }
            }
        }
        private void ParseReplayInfo(byte[] replayData, ref int index, ref Warcraft3Replay replay)
        {
            //playercount: in ladder, # of players; custom, # of slots available
            replay.PlayerCount = BitConverter.ToUInt32(replayData, index );
            replay.GameType = replayData[index += 4];
            index += 8; //skipping some unused info

            //this is a valid player
            while (replayData[index] == 0x16)
            {
                LoadPlayer(replayData, ref index, ref replay);
                index += 4; //skipping checksum
            }

            //should always be this value
            if (replayData[index++] != 0x19)
                return;

            //parsing the slot records
            ParseSlotRecords(replayData, ref index, ref replay);

            //leftover info
            //random seed, 4 bytes
            //selection mode, 1 byte
            //num start spots, 1 byte
            index += 6;
        }
        private byte[] DecompressReplay(byte[] replayData, int index, Warcraft3Replay replay)
        {
            uint numChunks = replay.replayHeader.NumDataBlocks;
            ushort compChunkSize = BitConverter.ToUInt16(replayData, index);
            ushort decompChunkSize = BitConverter.ToUInt16(replayData, index += 2);
            index -= 2; //rewind

            byte[] decompressedData = new byte[numChunks * decompChunkSize];
            byte[] compChunk;
            byte[] decompChunk = new byte[decompChunkSize];

            ZStream stream = new ZStream();
            stream.avail_in = 0;
            stream.next_in_index = 0;

            for (int i = 0; i < numChunks; i++)
            {
                if (stream.inflateInit() != zlibConst.Z_OK)
                    return null; //error

                compChunkSize = BitConverter.ToUInt16(replayData, index);
                decompChunkSize = BitConverter.ToUInt16(replayData, index += 2);
                index += 6; //skipping checksum

                compChunk = new byte[compChunkSize];
                for (int j = 0; j < compChunkSize; j++, index++)
                    compChunk[j] = replayData[index];

                stream.avail_in = compChunkSize;
                stream.next_in = compChunk;
                stream.next_in_index = 0;

                stream.avail_out = decompChunkSize;
                stream.next_out = decompressedData;
                stream.next_out_index = i * decompChunkSize;

                stream.inflate(zlibConst.Z_NO_FLUSH);
                stream.inflateEnd();
            }

            return decompressedData;
        }
        //the work in here is incomplete, the actual algorithm is complex and not 100% accurate.
        private void ParseLeaveGameBlock(byte[] replayData, ref int index, ref Warcraft3Replay replay, ref uint numLeaves, uint timePassed)
        {
            uint reason = BitConverter.ToUInt32(replayData, index);
            byte ID = replayData[index += 4];
            uint result = BitConverter.ToUInt32(replayData, ++index);
            uint unknown = BitConverter.ToUInt32(replayData, index += 4);
            index += 4;

            if (reason == 0x01)
            {
                if (result == 0x07 || result == 0x08)
                    replay.players[ID].WinStatus = 0; //player lost
                else if (result == 0x09)
                    replay.players[ID].WinStatus = 1; //player won
                else if (result == 0x0A)
                    replay.players[ID].WinStatus = 2; //draw
            }
        }
        private void ParseReplayData(byte[] replayData, ref int index, ref Warcraft3Replay replay)
        {
            byte prevBlockID;
            byte blockID = replayData[index++];
            uint numBlocks = 0;
            uint timePassed = 0;
            uint numLeaves = 0;

            while (index < replayData.Length)
            {
                switch (blockID)
                {
                    case 0x17: //leavegame block, 13 bytes
                        ParseLeaveGameBlock(replayData, ref index, ref replay, ref numLeaves, timePassed);
                        //Console.WriteLine("case 0x17");
                        break;

                    //unknowns, 4 bytes each
                    case 0x1A:
                    case 0x1B:
                    case 0x1C:
                        //Console.WriteLine("case 0x1a/0x1b/0x1c");
                        index += 4;
                        break;

                    case 0x1E: //old timeslot block
                    case 0x1F: //new timeslot block n+2 bytes
                        //Console.WriteLine("case 0x1e/0x1f");
                        ushort numBytes = BitConverter.ToUInt16(replayData, index);
                        ushort timeInc = BitConverter.ToUInt16(replayData, index += 2);
                        index += 2;
                        timePassed += timeInc;
                        if (numBytes != 2)
                            ParseActionBlock(replayData, ref index, ref replay, numBytes, timePassed);
                        break;

                    case 0x20: //chat block, n+3 bytes
                        //Console.WriteLine("case 0x20");
                        ParseChatBlock(replayData, ref index, ref replay, timePassed);
                        break;

                    case 0x22: //random seed or checksum, 5 bytes
                        //Console.WriteLine("case 0x22");
                        index += 5;
                        break;

                    case 0x23: //unknown, 10 bytes
                        //Console.WriteLine("case 0x23");
                        index += 10;
                        break;

                    case 0x2f: //forced game countdown, tourny games 8 bytes
                        //Console.WriteLine("case 0x2f");
                        index += 8;
                        break;

                    //there is occasionally heavy padding of 0s (due to lag?)
                    case 0x00:
                        //Console.WriteLine("case 0x00");
                        break;

                    //error
                    default:
                        throw new ParseDataException();
                        //TextWriter output = new StreamWriter("..\\..\\Resources\\binary.txt");
                        //for (int j = 0; j < 5; j++)
                        //{
                        //    output.WriteLine(BitConverter.ToString(replayData, index, 80));
                        //    index += 80;
                        //}
                        //break;
                }

                numBlocks++;
                prevBlockID = blockID;
                blockID = replayData[index++];
            }
        }
        private void ParseEncodedStrings(byte[] replayData, ref int index, ref Warcraft3Replay replay)
        {
            byte[] encodedString = new byte[200];
            byte[] decodedString;
            int length = 0;

            while (replayData[index] != 0)
                encodedString[length++] = replayData[index++];
            index++; //passing over the null byte

            decodedString = new byte[length];
            decodedString = DecodeStrings(encodedString, decodedString);
            ParseDecodedStrings(decodedString, ref replay);
        }
        private void ParseHeader(byte[] replayData, ref int index, ref Warcraft3Replay replay)
        {
            //validating the replay format
            System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
            string w3g = enc.GetString(replayData, 0, 28);
            index += 28;

            if (w3g.CompareTo("Warcraft III recorded game\x1A\0") != 0)
                return; //throw exception

            //note: the bit converter doesn't move index forward, so the next subsequent
            //call to bitconverter should be moved forward the previous call's number of bytes
            //ie, look at the first 2 lines immediately below this comment

            replay.replayHeader.EndOfHeader = BitConverter.ToUInt32(replayData, index);
            replay.replayHeader.CompDataSize = BitConverter.ToUInt32(replayData, index += 4);
            replay.replayHeader.HeaderVersion = BitConverter.ToUInt32(replayData, index += 4);
            replay.replayHeader.DecompDataSize = BitConverter.ToUInt32(replayData, index += 4);
            replay.replayHeader.NumDataBlocks = BitConverter.ToUInt32(replayData, index += 4);

            //enter subheader (for 1.06 and below)
            if (replay.replayHeader.HeaderVersion == 0x00)
            {
                index += 4;
                replay.replayHeader.GameVersion = BitConverter.ToUInt16(replayData, index += 2);
                replay.replayHeader.Build = BitConverter.ToUInt16(replayData, index += 2);
                replay.replayHeader.Flags = BitConverter.ToUInt16(replayData, index += 2);
                replay.replayHeader.GameLength = BitConverter.ToUInt32(replayData, index += 2);
                index += 8; //skip checksum
            }

            //enter subheader (for only 1.07 and above)
            else if (replay.replayHeader.HeaderVersion == 0x01)
            {
                index += 4;
                replay.replayHeader.GameVersion = BitConverter.ToUInt32(replayData, index += 4);
                replay.replayHeader.Build = BitConverter.ToUInt16(replayData, index += 4);
                replay.replayHeader.Flags = BitConverter.ToUInt16(replayData, index += 2);
                replay.replayHeader.GameLength = BitConverter.ToUInt32(replayData, index += 2);
                index += 8; //skip checksum
            }
        }
        private void ParseDecodedStrings(byte[] decodedString, ref Warcraft3Replay replay)
        {
            replay.replaySettings.GameSpeed = decodedString[0];

            //visibility settings
            if ((decodedString[1] & 1) == 1)
               replay.replaySettings.Visibility = 1; //hide terrain
            else if ((decodedString[1] & 2) == 2)
                replay.replaySettings.Visibility = 2; //map explored
            else if ((decodedString[1] & 4) == 4)
                replay.replaySettings.Visibility = 3; //always visible
            else if ((decodedString[1] & 8) == 8)
                replay.replaySettings.Visibility = 4; //default

            //observer settings
            if ((decodedString[1] & 16) == 0)
                replay.replaySettings.Observers = 0; //obs off or referees
            else if ((decodedString[1] & 16) == 0 & (decodedString[1] & 32) == 32)
                replay.replaySettings.Observers = 2; //obs on defeat
            else if ((decodedString[1] & 16) == 16 && (decodedString[1] & 32) == 0)
                replay.replaySettings.Observers = 1; //obs unused
            else if ((decodedString[1] & 16) == 61 && (decodedString[1] & 32) == 32)
                replay.replaySettings.Observers = 3; //obs on or referees

            if ((decodedString[3] & 64) == 1)
                replay.replaySettings.Observers = 4; //referees

            replay.replaySettings.TeamsTogether = (decodedString[1] & 64) == 64;
            replay.replaySettings.LockTeams = (decodedString[2] > 0);
            replay.replaySettings.SharedControl = (decodedString[3] & 1) == 1;
            replay.replaySettings.RandomHero = (decodedString[3] & 2) == 2;
            replay.replaySettings.RandomRace = (decodedString[3] & 4) == 4;

            int i = 13; //skipping 9 bytes + checksum (4 bytes)
            while (decodedString[i] != 0)
                replay.MapName += (char)decodedString[i++];
            i++; //skipping the null byte

            //removing the folder structure, this may be worth taking out
            //replay.MapName = replay.MapName.Remove(0, replay.MapName.LastIndexOf('\\')+1);

            while (decodedString[i] != 0)
                replay.HostName += (char)decodedString[i++];
            i++; //skipping the nullbyte
        }
        private void ParseChatBlock(byte[] replayData, ref int index, ref Warcraft3Replay replay, uint timePassed)
        {
            byte ID = replayData[index++];
            ushort numBytes = BitConverter.ToUInt16(replayData, index);
            byte flag = replayData[index += 2];
            uint mode;
            string chatMsg = "";

            //mode: 0x00 to all, 0x01 to allies, 0x02 to obs, 0x03+N to player where N = slot #
            if (flag == 0x20)
            {
                mode = BitConverter.ToUInt32(replayData, ++index);
            }

            else //otherwise flag = 0x10, these aren't shown in the replay and have no mode
            {
                //spin over the system messages
                while (replayData[index++] != 0x00) ;
                return;
            }

            //moving the index forward after reading in mode
            index += 4;

            //appending the time to the front of the chat block
            chatMsg += "[" + HelperFunctions.FormatTimeSpan(TimeSpan.FromMilliseconds(timePassed)) + "]";

            switch (mode)
            {
                case 0x00:
                    chatMsg += "[All] ";
                    break;

                case 0x01:
                    chatMsg += "[Allies] ";
                    break;

                case 0x02:
                    chatMsg += "[Observers] ";
                    break;

                default:
                    //chatMsg += "[To " + replay.players[replay.slots[(int)(mode - 0x03)]] + "] ";
                    break;
            }

            //adding the playername
            chatMsg += replay.players[ID].Name + ": ";

            //chat parsing
            while (replayData[index] != 0x00)
                chatMsg += (char)replayData[index++];

            replay.chatLog.Add(chatMsg);
        }
        private void ParseActionBlock(byte[] replayData, ref int index, ref Warcraft3Replay replay, ushort numBytes, uint timePassed)
        {
            byte playerID = 0;
            byte actionID = 0;
            byte groupNumber;
            string itemID;
            ushort blockLength = 0;
            ushort totalBytesParsed = 0;
            ushort actionBytesParsed = 0;

            //change selection block
            byte prevActionID = 0;
            byte prevMode = 0;
            byte mode = 0;
            ushort numSelected = 0;

            numBytes -= 2;
            while (totalBytesParsed < numBytes)
            {
                playerID = replayData[index++];
                blockLength = BitConverter.ToUInt16(replayData, index);
                index += 2;
                totalBytesParsed += 3;

                //error parsing
                if (playerID <= 0 || playerID >= 12)
                    return;
                Warcraft3Player player = replay.players[playerID];

                actionBytesParsed = 0;
                while (actionBytesParsed < blockLength)
                {
                    actionID = replayData[index++];
                    //while (actionID == 0x00)
                    //    actionID = replayData[index++];
                    actionBytesParsed++;

                    switch (actionID)
                    {
                        case 0x01: //pause game, 0 bytes
                        case 0x02: //resume game, 0 bytes
                            break;

                        case 0x03: //set game speed, 1 byte
                            index++;
                            actionBytesParsed++;
                            break;

                        case 0x04: //increase game speed, 0 bytes
                        case 0x05: //decrease game speed, 0 bytes
                            break;

                        //save game, n bytes with a null terminating character
                        case 0x06:
                            while (replayData[index] != 0x00)
                            {
                                index++;
                                actionBytesParsed++;
                            }

                            index++;
                            actionBytesParsed++;
                            break;

                        //save game finished, 4 bytes
                        //normally follows 0x06
                        case 0x07:
                            index += 4;
                            actionBytesParsed += 4;
                            break;

                        //pre 1.07: this block is 5 bytes (build 6031)
                        //pre 1.13: this block is 13 bytes (build 6037)
                        //otherwise: unit/building abilitiy, 14 bytes
                        case 0x10:
                            if (replay.replayHeader.Build < 6037)
                            {
                                index++;
                                actionBytesParsed++;
                            }
                            else
                            {
                                index += 2;
                                actionBytesParsed += 2;
                            }

                            itemID = "";
                            itemID += (char)replayData[index + 3];
                            itemID += (char)replayData[index + 2];
                            itemID += (char)replayData[index + 1];
                            itemID += (char)replayData[index];

                            if (replay.replayHeader.Build < 6031)
                            {
                                //4 itemID bytes
                                index += 4;
                                actionBytesParsed += 4;
                            }
                            else
                            {
                                //passing over 8 bytes, + 4 itemID bytes
                                index += 12;
                                actionBytesParsed += 12;
                            }

                            if (timePassed > 1500)
                            {
                                //checking for numeric id
                                if (!itemID.Contains("\0\r"))
                                {
                                    itemID = Warcraft3DataConverter.ConvertItemID(itemID);

                                    //helps mitigate duplicates
                                    if (!player.BuildOrder.ContainsKey(timePassed))
                                    {
                                        player.BuildOrder.Add(timePassed, itemID);
                                        HelperFunctions.AddDictionaryItem(player.BuildingCount, itemID, 1);
                                    }
            #if (OUTPUT)
                                    TextWriter output = new StreamWriter("..\\..\\Resources\\output.txt", true);
                                    output.WriteLine(itemID);
                                    output.Close();
            #endif
                                }

                            }

                            break;

                        //pre 1.07: this block is 13 bytes (build 6031)
                        //pre 1.13: this block is 21 bytes (build 6037)
                        //otherwise: unit/building ability with target pos, 22 bytes
                        case 0x11:
                            if (replay.replayHeader.Build < 6037)
                            {
                                index++;
                                actionBytesParsed++;
                            }
                            else
                            {
                                index += 2;
                                actionBytesParsed += 2;
                            }

                            itemID = "";
                            itemID += (char)replayData[index + 3];
                            itemID += (char)replayData[index + 2];
                            itemID += (char)replayData[index + 1];
                            itemID += (char)replayData[index];

                            if (replay.replayHeader.Build < 6031)
                            {
                                //passing over 8 bytes + 4 itemID bytes
                                index += 12;
                                actionBytesParsed += 12;
                            }
                            else
                            {
                                //passing over 16 bytes + 4 itemID bytes
                                index += 20;
                                actionBytesParsed += 20;
                            }

                            //checking for numeric id
                            if (!itemID.Contains("\0\r"))
                            {
                                itemID = Warcraft3DataConverter.ConvertItemID(itemID);

                                //helps mitigate duplicates
                                if (!player.BuildOrder.ContainsKey(timePassed))
                                {
                                    player.BuildOrder.Add(timePassed, itemID);
                                    HelperFunctions.AddDictionaryItem(player.BuildingCount, itemID, 1);
                                }
            #if (OUTPUT)
                                TextWriter output = new StreamWriter("..\\..\\Resources\\output.txt", true);
                                output.WriteLine(itemID);
                                output.Close();
            #endif
                            }

                            break;

                        //pre 1.07: this block is 22 bytes (build 6031)
                        //pre 1.13: this block is 29 bytes (build 6037)
                        //otherwise: unit/building ability with target pos and obj, 30 bytes
                        case 0x12:
                            if (replay.replayHeader.Build < 6031)
                            {
                                index += 22;
                                actionBytesParsed += 22;
                            }
                            else if (replay.replayHeader.Build < 6037)
                            {
                                index += 29;
                                actionBytesParsed += 29;
                            }
                            else
                            {
                                index += 30;
                                actionBytesParsed += 30;
                            }
                            break;

                        //pre 1.07: this block is 30 bytes (build 6031)
                        //pre 1.13: this block is 37 bytes (build 6037)
                        //otherwise: pass item, 38 bytes
                        case 0x13:
                            if (replay.replayHeader.Build < 6031)
                            {
                                index += 30;
                                actionBytesParsed += 30;
                            }
                            else if (replay.replayHeader.Build < 6037)
                            {
                                index += 37;
                                actionBytesParsed += 37;
                            }
                            else
                            {
                                index += 38;
                                actionBytesParsed += 38;
                            }
                            break;

                        //pre 1.07: this block is 35 bytes (build 6031)
                        //pre 1.13: this block is 42 bytes (build 6037)
                        //otherwise: unit/building ability with 2 target pos and 2 itemID, 43 bytes
                        case 0x14:
                            if (replay.replayHeader.Build < 6031)
                            {
                                index += 35;
                                actionBytesParsed += 35;
                            }
                            else if (replay.replayHeader.Build < 6037)
                            {
                                index += 42;
                                actionBytesParsed += 42;
                            }
                            else
                            {
                                index += 43;
                                actionBytesParsed += 43;
                            }
                            break;

                        //change selection 3+n*8 bytes
                        case 0x16:
                            prevMode = mode;

                            mode = replayData[index++]; //0x01 select, 0x02 deselect
                            numSelected = BitConverter.ToUInt16(replayData, index);
                            index += (numSelected * 8) + 2;

                            //apm handling

                            actionBytesParsed += (ushort)(3 + numSelected * 8);
                            break;

                        //assign group hotkey 3+n*8 bytes
                        //group number is shifted by 1: ie, ctrl+1 = 0
                        case 0x17:
                            groupNumber = replayData[index++];
                            numSelected = BitConverter.ToUInt16(replayData, index);
                            index += (numSelected * 8) + 2;

                            //action handling

                            actionBytesParsed += (ushort)(3 + numSelected * 8);
                            break;

                        //select group hotkey, 2 bytes
                        //group number is shifted by 1: ie, ctrl+1 = 0
                        case 0x18:
                            groupNumber = replayData[index++];
                            index++; //skipping unknown byte
                            actionBytesParsed += 2;
                            break;

                        //pre 1.14b: 1 byte (build 6040)
                        //otherwise: select subgroup, 12 bytes
                        case 0x19:
                            // <= 1.14b this byte is the subgroup number
                            if (replay.replayHeader.Build < 6040)
                            {
                                index++;
                                actionBytesParsed++;
                            }
                            else
                            {

                                index += 12;
                                actionBytesParsed += 12;
                            }
                            break;

                        //pre 1.14b: 9 bytes, unknown
                        //otherwise: pre subselection, 0 bytes
                        case 0x1A:
                            if (replay.replayHeader.Build < 6040)
                            {
                                index += 9;
                                actionBytesParsed += 9;
                            }
                            break;

                        //pre 1.14b: 9 bytes, select ground item
                        //otherwise: 9 bytes, unknown
                        case 0x1B:
                            index += 9;
                            actionBytesParsed += 9;
                            break;

                        //pre 1.14b: cancel hero revival, 8 bytes
                        //otherwise: 9 bytes, select ground item
                        case 0x1C:
                            if (replay.replayHeader.Build < 6040)
                            {
                                index += 8;
                                actionBytesParsed += 8;
                            }
                            else
                            {
                                index += 9;
                                actionBytesParsed += 9;
                            }
                            break;

                        //pre 1.14b: remove unit from building queue, 5 bytes,
                        //otherwise: cancel hero revival, 8 bytes
                        case 0x1D:
                            if (replay.replayHeader.Build < 6040)
                            {
                                index += 5;
                                actionBytesParsed += 5;
                            }
                            else
                            {
                                index += 8;
                                actionBytesParsed += 8;
                            }
                            break;

                        //remove unit from building queue, 5 bytes
                        case 0x1E:
                            index += 5;
                            actionBytesParsed += 5;
                            break;

                        //unknown, 8 bytes
                        case 0x21:
                            index += 8;
                            actionBytesParsed += 8;
                            break;

                        //case 0x20, 0x22-0x32 single player cheats

                        //change ally options, 5 bytes
                        case 0x50:
                            index += 5;
                            actionBytesParsed += 5;
                            break;

                        //transfer ally resources, 9 bytes
                        case 0x51:
                            index += 9;
                            actionBytesParsed += 9;
                            break;

                        //map trigger command, n+8 bytes
                        case 0x60:
                            index += 8;
                            actionBytesParsed += 8;

                            //while (replayData[index++] != 0)
                            //    actionBytesParsed++;

                            while (replayData[index] != 0x00)
                            {
                                index++;
                                actionBytesParsed++;
                            }

                            index++;
                            actionBytesParsed++;
                            break;

                        //esc pressed, 0 bytes
                        case 0x61:
                            break;

                        //scenario trigger
                        //pre 1.07: 8 bytes
                        //otherwise: 12 bytes
                        case 0x62:
                            if (replay.replayHeader.Build < 6031)
                            {
                                index += 8;
                                actionBytesParsed += 8;
                            }
                            else
                            {
                                index += 12;
                                actionBytesParsed += 12;
                            }
                            break;

                        //enter hero skill menu, 0 bytes
                        case 0x66:
                            break;

                        //enter build submenu, 0 bytes
                        case 0x67:
                            break;

                        //map ping, 12 bytes
                        case 0x68:
                            index += 12;
                            actionBytesParsed += 12;
                            break;

                        //continue game block A, 16 bytes
                        case 0x69:
                            index += 16;
                            actionBytesParsed += 16;
                            break;

                        //continue game block B, 16 bytes
                        case 0x6A:
                            index += 16;
                            actionBytesParsed += 16;
                            break;

                        //DOTA cases?
                        //case 0x6B:
                        //    break;

                        //case 0x70:
                        //    break;

                        //unknown 1 byte
                        case 0x75:
                            index++;
                            actionBytesParsed++;
                            break;

                        //error or unknown action
                        default:
                            throw new ParseActionException();
                    };

                    prevActionID = actionID;
                }

                totalBytesParsed += actionBytesParsed;

            }
        }
        //add exception handling, each function call should have different errors thrown
        private void Parse()
        {
            Warcraft3Replay replay = new Warcraft3Replay();
            replay.Path = FilePath;

            byte[] replayData = File.ReadAllBytes(FilePath);
            int index = 0;

            //parsing the initial data, verifying it's a valid replay
            ParseHeader(replayData, ref index, ref replay);

            //replayData will now contain all the decompressed data
            replayData = DecompressReplay(replayData, index, replay);

            //the index is reset to the top of the decompressed data
            index = 4;

            //load the first player
            LoadPlayer(replayData, ref index, ref replay);

            //extract the game name
            while (replayData[index] != 0)
                replay.GameName += (char)replayData[index++];
            index += 2; //passing over 2 null bytes

            //parsing the encoded strings
            ParseEncodedStrings(replayData, ref index, ref replay);

            //parse general replay info
            ParseReplayInfo(replayData, ref index, ref replay);

            //parse replay data (ie, actions)
            try
            {
                ParseReplayData(replayData, ref index, ref replay);
                Replay = replay;
            }
            catch (Exception e)
            {
                throw e;
            }
        }
        private void LoadPlayer(byte[] replayData, ref int index, ref Warcraft3Replay replay)
        {
            Warcraft3Player player = new Warcraft3Player();
            player.Record = replayData[index++];
            player.ID = replayData[index++];

            while (replayData[index] != 0)
                player.Name += (char)replayData[index++];
            index++; //passing over the null byte

            //FFA players are unnamed
            if (player.Name == null)
                player.Name = "Player" + Convert.ToString(player.ID);

            //there are 8 additional bytes if its a ladder game (type = 0x08)
            player.GameType = replayData[index++];
            if (player.GameType == 8)
            {
                player.UpTime = BitConverter.ToUInt32(replayData, index);
                player.PlayerRace = BitConverter.ToUInt32(replayData, index += 4);
                index += 4;
            }

            //otherwise there is just a null byte
            else
            {
                index++;
            }

            replay.players.Add(player.ID, player);
        }