private static byte[] EncodeToBytes(DecodedDeck deck) { if (deck == null || deck.Heroes == null || deck.Cards == null) { return(null); } //Combine hero and normal cards and sort by id List <CardId> heroesSorted = deck.Heroes.Select(x => (CardId)x).OrderBy(x => x, new SortByComparer()).ToList(); List <CardId> cardsSorted = deck.Cards.Select(x => (CardId)x).OrderBy(x => x, new SortByComparer()).ToList(); int countHeroes = deck.Heroes.Count; List <CardId> allCards = heroesSorted.Concat(cardsSorted).ToList(); byte[] bytes = new byte[0]; //our version and hero count int intVersion = CurrentVersion << 4 | ExtractNBitsWithCarry(countHeroes, 3); byte version = (byte)intVersion; if (!AddByte(ref bytes, version)) { return(null); } //the checksum which will be updated at the end byte nDummyChecksum = 0; int nChecksumByte = bytes.Length; bool addByteResult = AddByte(ref bytes, nDummyChecksum); if (!addByteResult) { return(null); } // write the name size int nameLen = 0; string name = ""; if (!string.IsNullOrEmpty(deck.Name)) { // replace strip_tags() with your own HTML santizer or escaper. name = Helper.StripTags(deck.Name); int trimLen = name.Length; while (trimLen > 63) { int amountToTrim = (int)Math.Floor((trimLen - 63.0) / 4.0); amountToTrim = (amountToTrim > 1) ? amountToTrim : 1; name = name.Substring(0, name.Length - amountToTrim); trimLen = name.Length; } nameLen = name.Length; } addByteResult = AddByte(ref bytes, (byte)nameLen); if (!addByteResult) { return(null); } int keepCount = countHeroes; bool bufferResult = AddRemainingNumberToBuffer(ref countHeroes, 3, ref bytes); if (!bufferResult) { return(null); } int unChecksum = 0; int prevCardId = 0; for (int unCurrHero = 0; unCurrHero < keepCount; unCurrHero++) { CardId card = allCards[unCurrHero]; DecodedHero casted = null; if (card is DecodedHero) { casted = (DecodedHero)card; } else { continue; } if (casted.Turn == 0) { continue; } bufferResult = AddCardToBuffer(casted.Turn, card.Id - prevCardId, ref bytes, unChecksum); if (!bufferResult) { continue; } prevCardId = casted.Id; } //reset our card offset prevCardId = 0; //now all of the cards for (int nCurrCard = countHeroes; nCurrCard < allCards.Count; nCurrCard++) { //see how many cards we can group together CardId card = allCards[nCurrCard]; if (card.Id <= 0) { continue; } DecodedCard castedCard = null; if (card is DecodedCard) { castedCard = (DecodedCard)card; } else { continue; } if (castedCard.Count == 0) { continue; } //record this set of cards, and advance bufferResult = AddCardToBuffer(castedCard.Count, castedCard.Id - prevCardId, ref bytes, unChecksum); if (!bufferResult) { continue; } prevCardId = castedCard.Id; } // save off the pre string bytes for the checksum int preStringByteCount = bytes.Length; //write the string if (!string.IsNullOrEmpty(name)) { byte[] nameBytes = System.Text.Encoding.UTF8.GetBytes(name); foreach (byte nameByte in nameBytes) { addByteResult = AddByte(ref bytes, nameByte); if (!addByteResult) { return(null); } } } int unFullChecksum = ComputeChecksum(ref bytes, preStringByteCount - HeaderSize); int unSmallChecksum = (unFullChecksum & 0x0FF); bytes[nChecksumByte] = (byte)unSmallChecksum; return(bytes); }
private static DecodedDeck ParseDeck(string deckCode, byte[] deckBytes) { int nCurrentByteIndex = 0; int nTotalBytes = deckBytes.Length; byte nVersionAndHeroes = deckBytes[nCurrentByteIndex++]; int version = nVersionAndHeroes >> 4; if (CURRENT_VERSION != version && version != 1) { return(null); } byte checksum = deckBytes[nCurrentByteIndex++]; int nStringLength = 0; if (version > 1) { nStringLength = deckBytes[nCurrentByteIndex++]; } int nTotalCardBytes = nTotalBytes - nStringLength; int computedChecksum = 0; for (int i = nCurrentByteIndex; i < nTotalCardBytes; i++) { computedChecksum += deckBytes[i]; } var masked = (computedChecksum & 0xFF); if (checksum != masked) { return(null); } //read in our hero count (part of the bits are in the version, but we can overflow bits here var nNumHeroes = 0; if (!ReadVarEncodedUint32((int)nVersionAndHeroes, 3, deckBytes, ref nCurrentByteIndex, nTotalCardBytes, ref nNumHeroes)) { return(null); } //now read in the heroes int nPrevCardBase = 0; List <DecodedHero> heroes = new List <DecodedHero>(); for (int nCurrHero = 0; nCurrHero < nNumHeroes; nCurrHero++) { int nHeroTurn = 0; int nHeroCardID = 0; if (!ReadSerializedCard(deckBytes, ref nCurrentByteIndex, nTotalCardBytes, ref nPrevCardBase, ref nHeroTurn, ref nHeroCardID)) { return(null); } DecodedHero currentHero = new DecodedHero() { Id = nHeroCardID, Turn = nHeroTurn, }; heroes.Add(currentHero); } List <DecodedCard> cards = new List <DecodedCard>(); nPrevCardBase = 0; while (nCurrentByteIndex < nTotalCardBytes) { int nCardCount = 0; int nCardID = 0; if (!ReadSerializedCard(deckBytes, ref nCurrentByteIndex, nTotalBytes, ref nPrevCardBase, ref nCardCount, ref nCardID)) { return(null); } cards.Add(new DecodedCard() { Id = nCardID, Count = nCardCount, }); } string name = ""; if (nCurrentByteIndex <= nTotalBytes) { byte[] bytes = deckBytes.Skip(deckBytes.Length - nStringLength).ToArray(); name = System.Text.Encoding.UTF8.GetString(bytes); // replace strip_tags with an HTML sanitizer or escaper as needed. name = Helper.StripTags(name); } return(new DecodedDeck() { Heroes = heroes, Cards = cards, Name = name, }); }