public static Bitmap DecodeCatImage(ShandalarAsset asset) { //Console.WriteLine("Decompressing " + asset.filename); byte[] uncompressedData = Vlc.VlcDecompress(asset.data); int width = (int)BitConverter.ToUInt32(asset.data, 0x1c); int height = (int)BitConverter.ToUInt32(asset.data, 0x20); int smallTableSize = (int)BitConverter.ToUInt32(asset.data, 0x24); int newWidth; int newHeight; if ((int)BitConverter.ToUInt32(asset.data, 0) != 0) { bool halfSize = BitConverter.ToUInt32(asset.data, 0x28) == 1 ? true : false; if (halfSize) { newWidth = width / 2; newHeight = height / 2; } else { newWidth = width; newHeight = height; } } else { newWidth = width; newHeight = height; } int ptr1 = 0; int ptr2 = ptr1 + width * width * 4 + 0x80; int ptr3 = ptr2 + newWidth * newWidth * 4 + 0x80; int[] tempArray = GeneralUtilityFunctions.ByteArrayToIntArray(uncompressedData, 0); Wavelet.WaveletDecode(ref tempArray, ptr1, width, smallTableSize); Wavelet.WaveletDecode(ref tempArray, ptr2 / 4, newWidth, smallTableSize); Wavelet.WaveletDecode(ref tempArray, ptr3 / 4, newWidth, smallTableSize); /// YCbCr -> RGB Bitmap outputImage = Wavelet.Decode_YCbCrToRGB(tempArray, ptr1, width, height, ptr2 / 4, ptr3 / 4, newWidth, newHeight); // Return image return(outputImage); }
public static byte[] VlcDecompress(byte[] srcBytes) // 0x4928AF { int decompressedSize = (int)BitConverter.ToUInt32(srcBytes, 0x90) + 20000; byte[] result = new byte[decompressedSize]; /// Block 1 int ecx = (int)BitConverter.ToUInt32(srcBytes, 0x28) - 1; ecx = (ecx == 0) ? 1 : 2; int width = (int)BitConverter.ToUInt32(srcBytes, 0x1c); int var_30 = width / ecx; int var_2C = var_30; /// Block 2 ecx = BitConverter.ToUInt32(srcBytes, 0) == 0 ? 1 : 2; int var_18 = var_2C / ecx; int var_10 = var_18; byte[] dataPtr = srcBytes.Skip(0x9c).ToArray(); // skip header int smallTableSize = (int)BitConverter.ToUInt32(srcBytes, 0x24); int eax = var_18 * var_10; ecx = var_30 * var_2C; int var_C = ecx + 2 * eax; /// Step 1 int dataOffset = 0; int bigIndexCount = (int)BitConverter.ToUInt32(dataPtr, dataOffset); dataOffset += 4; int[] bigIndexTabPtr = GeneralUtilityFunctions.ByteArrayToIntArray(dataPtr, dataOffset); bigIndexTabPtr[0] = int.MinValue; dataOffset += bigIndexCount * 4; // Skip large index table dataOffset += Vlc_GenTabs(dataPtr, dataOffset, bigIndexTabPtr, bigIndexCount); /// Loop int pieceNum = 0; /// piece num while (pieceNum < BitConverter.ToUInt32(srcBytes, 0x28)) { int size; /// Calculate pointers int tableSize = smallTableSize * smallTableSize * 4; int var_24_offset = (var_C + 0x40) * pieceNum * 4; int var_38_offset = var_24_offset + var_30 * var_2C * 4 + 0x80; int var_34_offset = var_38_offset + var_18 * var_10 * 4 + 0x80; /// Small index table + data 1 Array.Copy(dataPtr, dataOffset, result, var_24_offset, tableSize); var_24_offset += tableSize; dataOffset += tableSize; size = (int)BitConverter.ToUInt32(srcBytes, pieceNum * 4 + 0x5c); Vlc_DecompressChunk(dataPtr, dataOffset, ref result, var_24_offset, size); dataOffset += size; /// Small index table + data 2 Array.Copy(dataPtr, dataOffset, result, var_38_offset, tableSize); var_38_offset += tableSize; dataOffset += tableSize; size = (int)BitConverter.ToUInt32(srcBytes, pieceNum * 4 + 0x6c); Vlc_DecompressChunk(dataPtr, dataOffset, ref result, var_38_offset, size); dataOffset += size; /// Small index table + data 3 Array.Copy(dataPtr, dataOffset, result, var_34_offset, tableSize); var_34_offset += tableSize; dataOffset += tableSize; size = (int)BitConverter.ToUInt32(srcBytes, pieceNum * 4 + 0x7c); Vlc_DecompressChunk(dataPtr, dataOffset, ref result, var_34_offset, size); dataOffset += size; pieceNum++; } return(result); }