LZ4Compressor.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "LZ4Compressor.h"
  9. #include <lz4.h>
  10. #include <lz4hc.h>
  11. namespace MultiplayerCompression
  12. {
  13. size_t LZ4Compressor::GetMaxChunkSize(size_t maxCompSize) const
  14. {
  15. return maxCompSize;
  16. }
  17. size_t LZ4Compressor::GetMaxCompressedBufferSize(size_t uncompSize) const
  18. {
  19. return LZ4_compressBound(static_cast<int>(uncompSize));
  20. }
  21. AzNetworking::CompressorError LZ4Compressor::Compress
  22. (
  23. const void* uncompData,
  24. size_t uncompSize,
  25. void* compData,
  26. [[maybe_unused]] size_t compDataSize,
  27. size_t& compSize
  28. )
  29. {
  30. if (uncompData == nullptr)
  31. {
  32. // LZ4 actually never checks for this
  33. AZ_Warning("Multiplayer Compressor", false, "Input buffer is uninitialized");
  34. return AzNetworking::CompressorError::Uninitialized;
  35. }
  36. if (compData == nullptr)
  37. {
  38. // LZ4 actually never checks for this
  39. AZ_Warning("Multiplayer Compressor", false, "Output buffer is uninitialized");
  40. return AzNetworking::CompressorError::Uninitialized;
  41. }
  42. const int compWorstCaseSize = LZ4_compressBound(static_cast<int>(uncompSize));
  43. if (compWorstCaseSize == 0)
  44. {
  45. AZ_Warning("Multiplayer Compressor", false, "Input size (%lu) passed to Compress() is greater than max allowed (%lu)", uncompSize, LZ4_MAX_INPUT_SIZE);
  46. return AzNetworking::CompressorError::InsufficientBuffer;
  47. }
  48. AZ_Warning("Multiplayer Compressor", compDataSize >= compWorstCaseSize, "Outbuffer size (%lu B) passed to Compress() is less than estimated worst case (%lu B)", compDataSize, compWorstCaseSize);
  49. // Note that this returns a non-negative int so we are narrowing into a size_t here
  50. compSize = LZ4_compress_HC(
  51. reinterpret_cast<const char*>(uncompData),
  52. reinterpret_cast<char*>(compData),
  53. static_cast<int>(uncompSize),
  54. static_cast<int>(compDataSize),
  55. 0);
  56. if (compSize == 0)
  57. {
  58. // LZ4_compress_HC returns a zero value for corrupt data and insufficient buffer
  59. AZ_Warning("Multiplayer Compressor", false, "Compression failed for uncompSize:(%lu B) compDataSize:(%lu B) compSize:(%lu B)", uncompSize, compDataSize, compSize);
  60. return AzNetworking::CompressorError::CorruptData;
  61. }
  62. return AzNetworking::CompressorError::Ok;
  63. }
  64. AzNetworking::CompressorError LZ4Compressor::Decompress(const void* compData, size_t compDataSize, void* uncompData, size_t uncompDataSize, size_t& consumedSizeOut, size_t& uncompSizeOut)
  65. {
  66. if (uncompData == nullptr)
  67. {
  68. // LZ4 actually never checks for this
  69. AZ_Warning("Multiplayer Compressor", false, "Input buffer is uninitialized");
  70. return AzNetworking::CompressorError::Uninitialized;
  71. }
  72. if (compData == nullptr)
  73. {
  74. // LZ4 actually never checks for this
  75. AZ_Warning("Multiplayer Compressor", false, "Output buffer is uninitialized");
  76. return AzNetworking::CompressorError::Uninitialized;
  77. }
  78. const int uncompSize = LZ4_decompress_safe(reinterpret_cast<const char*>(compData), reinterpret_cast<char*>(uncompData), static_cast<int>(compDataSize), static_cast<int>(uncompDataSize));
  79. consumedSizeOut = compDataSize;
  80. if (uncompSize < 0)
  81. {
  82. // LZ4_decompress_safe returns a negative value for corrupt data and insufficient buffer
  83. AZ_Warning("Multiplayer Compressor", false, "Decompression failed for compDataSize:(%lu B) uncompDataSize:(%lu B) uncompSize:(%d B)", compDataSize, uncompDataSize, uncompSize);
  84. return AzNetworking::CompressorError::CorruptData;
  85. }
  86. // Assign into the outbound size_t after validating the negative error case
  87. uncompSizeOut = uncompSize;
  88. return AzNetworking::CompressorError::Ok;
  89. }
  90. }