| 
									
										
										
										
											2019-02-08 06:45:50 +01:00
										 |  |  | // Copyright 2019 yuzu Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | #include <lz4hc.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "common/assert.h"
 | 
					
						
							|  |  |  | #include "common/lz4_compression.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Common::Compression { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 05:25:28 -04:00
										 |  |  | std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size) { | 
					
						
							|  |  |  |     ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size"); | 
					
						
							| 
									
										
										
										
											2019-02-08 06:45:50 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 05:25:28 -04:00
										 |  |  |     const auto source_size_int = static_cast<int>(source_size); | 
					
						
							|  |  |  |     const auto max_compressed_size = static_cast<std::size_t>(LZ4_compressBound(source_size_int)); | 
					
						
							| 
									
										
										
										
											2019-02-08 06:45:50 +01:00
										 |  |  |     std::vector<u8> compressed(max_compressed_size); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 05:25:28 -04:00
										 |  |  |     const int compressed_size = LZ4_compress_default( | 
					
						
							|  |  |  |         reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()), | 
					
						
							|  |  |  |         source_size_int, static_cast<int>(max_compressed_size)); | 
					
						
							| 
									
										
										
										
											2019-02-08 06:45:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (compressed_size <= 0) { | 
					
						
							|  |  |  |         // Compression failed
 | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 05:25:28 -04:00
										 |  |  |     compressed.resize(static_cast<std::size_t>(compressed_size)); | 
					
						
							| 
									
										
										
										
											2019-02-08 06:45:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return compressed; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 05:25:28 -04:00
										 |  |  | std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, | 
					
						
							|  |  |  |                                   s32 compression_level) { | 
					
						
							|  |  |  |     ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size"); | 
					
						
							| 
									
										
										
										
											2019-02-08 06:45:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 05:25:28 -04:00
										 |  |  |     const auto source_size_int = static_cast<int>(source_size); | 
					
						
							|  |  |  |     const auto max_compressed_size = static_cast<std::size_t>(LZ4_compressBound(source_size_int)); | 
					
						
							| 
									
										
										
										
											2019-02-08 06:45:50 +01:00
										 |  |  |     std::vector<u8> compressed(max_compressed_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const int compressed_size = LZ4_compress_HC( | 
					
						
							| 
									
										
										
										
											2020-08-15 05:25:28 -04:00
										 |  |  |         reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()), | 
					
						
							|  |  |  |         source_size_int, static_cast<int>(max_compressed_size), compression_level); | 
					
						
							| 
									
										
										
										
											2019-02-08 06:45:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (compressed_size <= 0) { | 
					
						
							|  |  |  |         // Compression failed
 | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 05:25:28 -04:00
										 |  |  |     compressed.resize(static_cast<std::size_t>(compressed_size)); | 
					
						
							| 
									
										
										
										
											2019-02-08 06:45:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return compressed; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 05:25:28 -04:00
										 |  |  | std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size) { | 
					
						
							|  |  |  |     return CompressDataLZ4HC(source, source_size, LZ4HC_CLEVEL_MAX); | 
					
						
							| 
									
										
										
										
											2019-02-08 06:45:50 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-24 05:28:45 -04:00
										 |  |  | std::vector<u8> DecompressDataLZ4(std::span<const u8> compressed, std::size_t uncompressed_size) { | 
					
						
							| 
									
										
										
										
											2019-02-08 06:45:50 +01:00
										 |  |  |     std::vector<u8> uncompressed(uncompressed_size); | 
					
						
							|  |  |  |     const int size_check = LZ4_decompress_safe(reinterpret_cast<const char*>(compressed.data()), | 
					
						
							|  |  |  |                                                reinterpret_cast<char*>(uncompressed.data()), | 
					
						
							|  |  |  |                                                static_cast<int>(compressed.size()), | 
					
						
							|  |  |  |                                                static_cast<int>(uncompressed.size())); | 
					
						
							|  |  |  |     if (static_cast<int>(uncompressed_size) != size_check) { | 
					
						
							|  |  |  |         // Decompression failed
 | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return uncompressed; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace Common::Compression
 |