LCOV - code coverage report
Current view: top level - xpcom/io - SnappyFrameUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 110 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/SnappyFrameUtils.h"
       8             : 
       9             : #include "crc32c.h"
      10             : #include "mozilla/EndianUtils.h"
      11             : #include "nsDebug.h"
      12             : #include "snappy/snappy.h"
      13             : 
      14             : namespace {
      15             : 
      16             : using mozilla::detail::SnappyFrameUtils;
      17             : using mozilla::NativeEndian;
      18             : 
      19           0 : SnappyFrameUtils::ChunkType ReadChunkType(uint8_t aByte)
      20             : {
      21           0 :   if (aByte == 0xff)  {
      22           0 :     return SnappyFrameUtils::StreamIdentifier;
      23           0 :   } else if (aByte == 0x00) {
      24           0 :     return SnappyFrameUtils::CompressedData;
      25           0 :   } else if (aByte == 0x01) {
      26           0 :     return SnappyFrameUtils::UncompressedData;
      27           0 :   } else if (aByte == 0xfe) {
      28           0 :     return SnappyFrameUtils::Padding;
      29             :   }
      30             : 
      31           0 :   return SnappyFrameUtils::Reserved;
      32             : }
      33             : 
      34           0 : void WriteChunkType(char* aDest, SnappyFrameUtils::ChunkType aType)
      35             : {
      36           0 :   unsigned char* dest = reinterpret_cast<unsigned char*>(aDest);
      37           0 :   if (aType == SnappyFrameUtils::StreamIdentifier) {
      38           0 :     *dest = 0xff;
      39           0 :   } else if (aType == SnappyFrameUtils::CompressedData) {
      40           0 :     *dest = 0x00;
      41           0 :   } else if (aType == SnappyFrameUtils::UncompressedData) {
      42           0 :     *dest = 0x01;
      43           0 :   } else if (aType == SnappyFrameUtils::Padding) {
      44           0 :     *dest = 0xfe;
      45             :   } else {
      46           0 :     *dest = 0x02;
      47             :   }
      48           0 : }
      49             : 
      50           0 : void WriteUInt24(char* aBuf, uint32_t aVal)
      51             : {
      52           0 :   MOZ_ASSERT(!(aVal & 0xff000000));
      53           0 :   uint32_t tmp = NativeEndian::swapToLittleEndian(aVal);
      54           0 :   memcpy(aBuf, &tmp, 3);
      55           0 : }
      56             : 
      57           0 : uint32_t ReadUInt24(const char* aBuf)
      58             : {
      59           0 :   uint32_t val = 0;
      60           0 :   memcpy(&val, aBuf, 3);
      61           0 :   return NativeEndian::swapFromLittleEndian(val);
      62             : }
      63             : 
      64             : // This mask is explicitly defined in the snappy framing_format.txt file.
      65           0 : uint32_t MaskChecksum(uint32_t aValue)
      66             : {
      67           0 :   return ((aValue >> 15) | (aValue << 17)) + 0xa282ead8;
      68             : }
      69             : 
      70             : } // namespace
      71             : 
      72             : namespace mozilla {
      73             : namespace detail {
      74             : 
      75             : using mozilla::LittleEndian;
      76             : 
      77             : // static
      78             : nsresult
      79           0 : SnappyFrameUtils::WriteStreamIdentifier(char* aDest, size_t aDestLength,
      80             :                                         size_t* aBytesWrittenOut)
      81             : {
      82           0 :   if (NS_WARN_IF(aDestLength < (kHeaderLength + kStreamIdentifierDataLength))) {
      83           0 :     return NS_ERROR_NOT_AVAILABLE;
      84             :   }
      85             : 
      86           0 :   WriteChunkType(aDest, StreamIdentifier);
      87           0 :   aDest[1] = 0x06;  // Data length
      88           0 :   aDest[2] = 0x00;
      89           0 :   aDest[3] = 0x00;
      90           0 :   aDest[4] = 0x73;  // "sNaPpY"
      91           0 :   aDest[5] = 0x4e;
      92           0 :   aDest[6] = 0x61;
      93           0 :   aDest[7] = 0x50;
      94           0 :   aDest[8] = 0x70;
      95           0 :   aDest[9] = 0x59;
      96             : 
      97             :   static_assert(kHeaderLength + kStreamIdentifierDataLength == 10,
      98             :                 "StreamIdentifier chunk should be exactly 10 bytes long");
      99           0 :   *aBytesWrittenOut = kHeaderLength + kStreamIdentifierDataLength;
     100             : 
     101           0 :   return NS_OK;
     102             : }
     103             : 
     104             : // static
     105             : nsresult
     106           0 : SnappyFrameUtils::WriteCompressedData(char* aDest, size_t aDestLength,
     107             :                                       const char* aData, size_t aDataLength,
     108             :                                       size_t* aBytesWrittenOut)
     109             : {
     110           0 :   *aBytesWrittenOut = 0;
     111             : 
     112           0 :   size_t neededLength = MaxCompressedBufferLength(aDataLength);
     113           0 :   if (NS_WARN_IF(aDestLength < neededLength)) {
     114           0 :     return NS_ERROR_NOT_AVAILABLE;
     115             :   }
     116             : 
     117           0 :   size_t offset = 0;
     118             : 
     119           0 :   WriteChunkType(aDest, CompressedData);
     120           0 :   offset += kChunkTypeLength;
     121             : 
     122             :   // Skip length for now and write it out after we know the compressed length.
     123           0 :   size_t lengthOffset = offset;
     124           0 :   offset += kChunkLengthLength;
     125             : 
     126             :   uint32_t crc = ComputeCrc32c(~0, reinterpret_cast<const unsigned char*>(aData),
     127           0 :                                aDataLength);
     128           0 :   uint32_t maskedCrc = MaskChecksum(crc);
     129           0 :   LittleEndian::writeUint32(aDest + offset, maskedCrc);
     130           0 :   offset += kCRCLength;
     131             : 
     132             :   size_t compressedLength;
     133           0 :   snappy::RawCompress(aData, aDataLength, aDest + offset, &compressedLength);
     134             : 
     135             :   // Go back and write the data length.
     136           0 :   size_t dataLength = compressedLength + kCRCLength;
     137           0 :   WriteUInt24(aDest + lengthOffset, dataLength);
     138             : 
     139           0 :   *aBytesWrittenOut = kHeaderLength + dataLength;
     140             : 
     141           0 :   return NS_OK;
     142             : }
     143             : 
     144             : // static
     145             : nsresult
     146           0 : SnappyFrameUtils::ParseHeader(const char* aSource, size_t aSourceLength,
     147             :                               ChunkType* aTypeOut, size_t* aDataLengthOut)
     148             : {
     149           0 :   if (NS_WARN_IF(aSourceLength < kHeaderLength)) {
     150           0 :     return NS_ERROR_NOT_AVAILABLE;
     151             :   }
     152             : 
     153           0 :   *aTypeOut = ReadChunkType(aSource[0]);
     154           0 :   *aDataLengthOut = ReadUInt24(aSource + kChunkTypeLength);
     155             : 
     156           0 :   return NS_OK;
     157             : }
     158             : 
     159             : // static
     160             : nsresult
     161           0 : SnappyFrameUtils::ParseData(char* aDest, size_t aDestLength,
     162             :                             ChunkType aType, const char* aData,
     163             :                             size_t aDataLength,
     164             :                             size_t* aBytesWrittenOut, size_t* aBytesReadOut)
     165             : {
     166           0 :   switch(aType) {
     167             :     case StreamIdentifier:
     168             :       return ParseStreamIdentifier(aDest, aDestLength, aData, aDataLength,
     169           0 :                                    aBytesWrittenOut, aBytesReadOut);
     170             : 
     171             :     case CompressedData:
     172             :       return ParseCompressedData(aDest, aDestLength, aData, aDataLength,
     173           0 :                                  aBytesWrittenOut, aBytesReadOut);
     174             : 
     175             :     // TODO: support other snappy chunk types
     176             :     default:
     177           0 :       MOZ_ASSERT_UNREACHABLE("Unsupported snappy framing chunk type.");
     178             :       return NS_ERROR_NOT_IMPLEMENTED;
     179             :   }
     180             : }
     181             : 
     182             : // static
     183             : nsresult
     184           0 : SnappyFrameUtils::ParseStreamIdentifier(char*, size_t,
     185             :                                         const char* aData, size_t aDataLength,
     186             :                                         size_t* aBytesWrittenOut,
     187             :                                         size_t* aBytesReadOut)
     188             : {
     189           0 :   *aBytesWrittenOut = 0;
     190           0 :   *aBytesReadOut = 0;
     191           0 :   if (NS_WARN_IF(aDataLength != kStreamIdentifierDataLength ||
     192             :                  aData[0] != 0x73 ||
     193             :                  aData[1] != 0x4e ||
     194             :                  aData[2] != 0x61 ||
     195             :                  aData[3] != 0x50 ||
     196             :                  aData[4] != 0x70 ||
     197             :                  aData[5] != 0x59)) {
     198           0 :     return NS_ERROR_CORRUPTED_CONTENT;
     199             :   }
     200           0 :   *aBytesReadOut = aDataLength;
     201           0 :   return NS_OK;
     202             : }
     203             : 
     204             : // static
     205             : nsresult
     206           0 : SnappyFrameUtils::ParseCompressedData(char* aDest, size_t aDestLength,
     207             :                                       const char* aData, size_t aDataLength,
     208             :                                       size_t* aBytesWrittenOut,
     209             :                                       size_t* aBytesReadOut)
     210             : {
     211           0 :   *aBytesWrittenOut = 0;
     212           0 :   *aBytesReadOut = 0;
     213           0 :   size_t offset = 0;
     214             : 
     215           0 :   uint32_t readCrc = LittleEndian::readUint32(aData + offset);
     216           0 :   offset += kCRCLength;
     217             : 
     218             :   size_t uncompressedLength;
     219           0 :   if (NS_WARN_IF(!snappy::GetUncompressedLength(aData + offset,
     220             :                                                 aDataLength - offset,
     221             :                                                 &uncompressedLength))) {
     222           0 :     return NS_ERROR_CORRUPTED_CONTENT;
     223             :   }
     224             : 
     225           0 :   if (NS_WARN_IF(aDestLength < uncompressedLength)) {
     226           0 :     return NS_ERROR_NOT_AVAILABLE;
     227             :   }
     228             : 
     229           0 :   if (NS_WARN_IF(!snappy::RawUncompress(aData + offset, aDataLength - offset,
     230             :                                         aDest))) {
     231           0 :     return NS_ERROR_CORRUPTED_CONTENT;
     232             :   }
     233             : 
     234           0 :   uint32_t crc = ComputeCrc32c(~0, reinterpret_cast<const unsigned char*>(aDest),
     235           0 :                                uncompressedLength);
     236           0 :   uint32_t maskedCrc = MaskChecksum(crc);
     237           0 :   if (NS_WARN_IF(readCrc != maskedCrc)) {
     238           0 :     return NS_ERROR_CORRUPTED_CONTENT;
     239             :   }
     240             : 
     241           0 :   *aBytesWrittenOut = uncompressedLength;
     242           0 :   *aBytesReadOut = aDataLength;
     243             : 
     244           0 :   return NS_OK;
     245             : }
     246             : 
     247             : // static
     248             : size_t
     249           0 : SnappyFrameUtils::MaxCompressedBufferLength(size_t aSourceLength)
     250             : {
     251           0 :   size_t neededLength = kHeaderLength;
     252           0 :   neededLength += kCRCLength;
     253           0 :   neededLength += snappy::MaxCompressedLength(aSourceLength);
     254           0 :   return neededLength;
     255             : }
     256             : 
     257             : } // namespace detail
     258             : } // namespace mozilla

Generated by: LCOV version 1.13