tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

wav_header_unittest.cc (17565B)


      1 /*
      2 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #include "common_audio/wav_header.h"
     12 
     13 #include <cstdint>
     14 #include <cstring>
     15 #include <limits>
     16 
     17 #include "test/gtest.h"
     18 
     19 namespace webrtc {
     20 
     21 // Doesn't take ownership of the buffer.
     22 class WavHeaderBufferReader : public WavHeaderReader {
     23 public:
     24  WavHeaderBufferReader(const uint8_t* buf, size_t size, bool check_read_size)
     25      : buf_(buf),
     26        size_(size),
     27        pos_(0),
     28        buf_exhausted_(false),
     29        check_read_size_(check_read_size) {}
     30 
     31  ~WavHeaderBufferReader() override {
     32    // Verify the entire buffer has been read.
     33    if (check_read_size_)
     34      EXPECT_EQ(size_, pos_);
     35  }
     36 
     37  size_t Read(void* buf, size_t num_bytes) override {
     38    EXPECT_FALSE(buf_exhausted_);
     39 
     40    const size_t bytes_remaining = size_ - pos_;
     41    if (num_bytes > bytes_remaining) {
     42      // The caller is signalled about an exhausted buffer when we return fewer
     43      // bytes than requested. There should not be another read attempt after
     44      // this point.
     45      buf_exhausted_ = true;
     46      num_bytes = bytes_remaining;
     47    }
     48    memcpy(buf, &buf_[pos_], num_bytes);
     49    pos_ += num_bytes;
     50    return num_bytes;
     51  }
     52 
     53  bool SeekForward(uint32_t num_bytes) override {
     54    // Verify we don't try to read outside of a properly sized header.
     55    if (size_ >= kPcmWavHeaderSize)
     56      EXPECT_GE(size_, pos_ + num_bytes);
     57    EXPECT_FALSE(buf_exhausted_);
     58 
     59    const size_t bytes_remaining = size_ - pos_;
     60    if (num_bytes > bytes_remaining) {
     61      // Error: cannot seek beyond EOF.
     62      return false;
     63    }
     64    if (num_bytes == bytes_remaining) {
     65      // There should not be another read attempt after this point.
     66      buf_exhausted_ = true;
     67    }
     68    pos_ += num_bytes;
     69    return true;
     70  }
     71 
     72  int64_t GetPosition() override { return pos_; }
     73 
     74 private:
     75  const uint8_t* buf_;
     76  const size_t size_;
     77  size_t pos_;
     78  bool buf_exhausted_;
     79  const bool check_read_size_;
     80 };
     81 
     82 // Try various choices of WAV header parameters, and make sure that the good
     83 // ones are accepted and the bad ones rejected.
     84 TEST(WavHeaderTest, CheckWavParameters) {
     85  // Try some really stupid values for one parameter at a time.
     86  EXPECT_TRUE(CheckWavParameters(1, 8000, WavFormat::kWavFormatPcm, 0));
     87  EXPECT_FALSE(CheckWavParameters(0, 8000, WavFormat::kWavFormatPcm, 0));
     88  EXPECT_FALSE(CheckWavParameters(0x10000, 8000, WavFormat::kWavFormatPcm, 0));
     89  EXPECT_FALSE(CheckWavParameters(1, 0, WavFormat::kWavFormatPcm, 0));
     90 
     91  // Too large values.
     92  EXPECT_FALSE(
     93      CheckWavParameters(1 << 20, 1 << 20, WavFormat::kWavFormatPcm, 0));
     94  EXPECT_FALSE(CheckWavParameters(1, 8000, WavFormat::kWavFormatPcm,
     95                                  std::numeric_limits<uint32_t>::max()));
     96 
     97  // Not the same number of samples for each channel.
     98  EXPECT_FALSE(CheckWavParameters(3, 8000, WavFormat::kWavFormatPcm, 5));
     99 }
    100 
    101 TEST(WavHeaderTest, ReadWavHeaderWithErrors) {
    102  size_t num_channels = 0;
    103  int sample_rate = 0;
    104  WavFormat format = WavFormat::kWavFormatPcm;
    105  size_t bytes_per_sample = 0;
    106  size_t num_samples = 0;
    107  int64_t data_start_pos = 0;
    108 
    109  // Test a few ways the header can be invalid. We start with the valid header
    110  // used in WriteAndReadWavHeader, and invalidate one field per test. The
    111  // invalid field is indicated in the array name, and in the comments with
    112  // *BAD*.
    113  {
    114    constexpr uint8_t kBadRiffID[] = {
    115        // clang-format off
    116        // clang formatting doesn't respect inline comments.
    117      'R', 'i', 'f', 'f',  // *BAD*
    118      0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
    119      'W', 'A', 'V', 'E',
    120      'f', 'm', 't', ' ',
    121      16, 0, 0, 0,  // size of fmt block - 8: 24 - 8
    122      1, 0,  // format: PCM (1)
    123      17, 0,  // channels: 17
    124      0x39, 0x30, 0, 0,  // sample rate: 12345
    125      0xc9, 0x33, 0x03, 0,  // byte rate: 1 * 17 * 12345
    126      17, 0,  // block align: NumChannels * BytesPerSample
    127      8, 0,  // bits per sample: 1 * 8
    128      'd', 'a', 't', 'a',
    129      0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
    130        // clang-format on
    131    };
    132    WavHeaderBufferReader r(kBadRiffID, sizeof(kBadRiffID),
    133                            /*check_read_size=*/false);
    134    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
    135                               &bytes_per_sample, &num_samples,
    136                               &data_start_pos));
    137  }
    138  {
    139    constexpr uint8_t kBadBitsPerSample[] = {
    140        // clang-format off
    141        // clang formatting doesn't respect inline comments.
    142      'R', 'I', 'F', 'F',
    143      0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
    144      'W', 'A', 'V', 'E',
    145      'f', 'm', 't', ' ',
    146      16, 0, 0, 0,  // size of fmt block - 8: 24 - 8
    147      1, 0,  // format: PCM (1)
    148      17, 0,  // channels: 17
    149      0x39, 0x30, 0, 0,  // sample rate: 12345
    150      0xc9, 0x33, 0x03, 0,  // byte rate: 1 * 17 * 12345
    151      17, 0,  // block align: NumChannels * BytesPerSample
    152      1, 0,  // bits per sample: *BAD*
    153      'd', 'a', 't', 'a',
    154      0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
    155        // clang-format on
    156    };
    157    WavHeaderBufferReader r(kBadBitsPerSample, sizeof(kBadBitsPerSample),
    158                            /*check_read_size=*/true);
    159    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
    160                               &bytes_per_sample, &num_samples,
    161                               &data_start_pos));
    162  }
    163  {
    164    constexpr uint8_t kBadByteRate[] = {
    165        // clang-format off
    166        // clang formatting doesn't respect inline comments.
    167      'R', 'I', 'F', 'F',
    168      0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
    169      'W', 'A', 'V', 'E',
    170      'f', 'm', 't', ' ',
    171      16, 0, 0, 0,  // size of fmt block - 8: 24 - 8
    172      1, 0,  // format: PCM (1)
    173      17, 0,  // channels: 17
    174      0x39, 0x30, 0, 0,  // sample rate: 12345
    175      0x00, 0x33, 0x03, 0,  // byte rate: *BAD*
    176      17, 0,  // block align: NumChannels * BytesPerSample
    177      8, 0,  // bits per sample: 1 * 8
    178      'd', 'a', 't', 'a',
    179      0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
    180        // clang-format on
    181    };
    182    WavHeaderBufferReader r(kBadByteRate, sizeof(kBadByteRate),
    183                            /*check_read_size=*/true);
    184    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
    185                               &bytes_per_sample, &num_samples,
    186                               &data_start_pos));
    187  }
    188  {
    189    constexpr uint8_t kBadFmtHeaderSize[] = {
    190        // clang-format off
    191        // clang formatting doesn't respect inline comments.
    192      'R', 'I', 'F', 'F',
    193      0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
    194      'W', 'A', 'V', 'E',
    195      'f', 'm', 't', ' ',
    196      17, 0, 0, 0,  // size of fmt block *BAD*. Only 16 and 18 permitted.
    197      1, 0,  // format: PCM (1)
    198      17, 0,  // channels: 17
    199      0x39, 0x30, 0, 0,  // sample rate: 12345
    200      0xc9, 0x33, 0x03, 0,  // byte rate: 1 * 17 * 12345
    201      17, 0,  // block align: NumChannels * BytesPerSample
    202      8, 0,  // bits per sample: 1 * 8
    203      0,  // extra (though invalid) header byte
    204      'd', 'a', 't', 'a',
    205      0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
    206        // clang-format on
    207    };
    208    WavHeaderBufferReader r(kBadFmtHeaderSize, sizeof(kBadFmtHeaderSize),
    209                            /*check_read_size=*/false);
    210    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
    211                               &bytes_per_sample, &num_samples,
    212                               &data_start_pos));
    213  }
    214  {
    215    constexpr uint8_t kNonZeroExtensionField[] = {
    216        // clang-format off
    217        // clang formatting doesn't respect inline comments.
    218      'R', 'I', 'F', 'F',
    219      0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
    220      'W', 'A', 'V', 'E',
    221      'f', 'm', 't', ' ',
    222      18, 0, 0, 0,  // size of fmt block - 8: 24 - 8
    223      1, 0,  // format: PCM (1)
    224      17, 0,  // channels: 17
    225      0x39, 0x30, 0, 0,  // sample rate: 12345
    226      0xc9, 0x33, 0x03, 0,  // byte rate: 1 * 17 * 12345
    227      17, 0,  // block align: NumChannels * BytesPerSample
    228      8, 0,  // bits per sample: 1 * 8
    229      1, 0,  // non-zero extension field *BAD*
    230      'd', 'a', 't', 'a',
    231      0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
    232        // clang-format on
    233    };
    234    WavHeaderBufferReader r(kNonZeroExtensionField,
    235                            sizeof(kNonZeroExtensionField),
    236                            /*check_read_size=*/false);
    237    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
    238                               &bytes_per_sample, &num_samples,
    239                               &data_start_pos));
    240  }
    241  {
    242    constexpr uint8_t kMissingDataChunk[] = {
    243        // clang-format off
    244        // clang formatting doesn't respect inline comments.
    245      'R', 'I', 'F', 'F',
    246      0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
    247      'W', 'A', 'V', 'E',
    248      'f', 'm', 't', ' ',
    249      16, 0, 0, 0,  // size of fmt block - 8: 24 - 8
    250      1, 0,  // format: PCM (1)
    251      17, 0,  // channels: 17
    252      0x39, 0x30, 0, 0,  // sample rate: 12345
    253      0xc9, 0x33, 0x03, 0,  // byte rate: 1 * 17 * 12345
    254      17, 0,  // block align: NumChannels * BytesPerSample
    255      8, 0,  // bits per sample: 1 * 8
    256        // clang-format on
    257    };
    258    WavHeaderBufferReader r(kMissingDataChunk, sizeof(kMissingDataChunk),
    259                            /*check_read_size=*/true);
    260    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
    261                               &bytes_per_sample, &num_samples,
    262                               &data_start_pos));
    263  }
    264  {
    265    constexpr uint8_t kMissingFmtAndDataChunks[] = {
    266        // clang-format off
    267        // clang formatting doesn't respect inline comments.
    268      'R', 'I', 'F', 'F',
    269      0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
    270      'W', 'A', 'V', 'E',
    271        // clang-format on
    272    };
    273    WavHeaderBufferReader r(kMissingFmtAndDataChunks,
    274                            sizeof(kMissingFmtAndDataChunks),
    275                            /*check_read_size=*/true);
    276    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
    277                               &bytes_per_sample, &num_samples,
    278                               &data_start_pos));
    279  }
    280 }
    281 
    282 // Try writing and reading a valid WAV header and make sure it looks OK.
    283 TEST(WavHeaderTest, WriteAndReadWavHeader) {
    284  constexpr int kSize = 4 + kPcmWavHeaderSize + 4;
    285  uint8_t buf[kSize];
    286  size_t header_size;
    287  memset(buf, 0xa4, sizeof(buf));
    288  WriteWavHeader(17, 12345, WavFormat::kWavFormatPcm, 123457689, buf + 4,
    289                 &header_size);
    290  constexpr uint8_t kExpectedBuf[] = {
    291      // clang-format off
    292    // clang formatting doesn't respect inline comments.
    293    0xa4, 0xa4, 0xa4, 0xa4,  // untouched bytes before header
    294    'R', 'I', 'F', 'F',
    295    0x56, 0xa1, 0xb7, 0x0e,  // size of whole file - 8: 123457689 + 44 - 8
    296    'W', 'A', 'V', 'E',
    297    'f', 'm', 't', ' ',
    298    16, 0, 0, 0,  // size of fmt block - 8: 24 - 8
    299    1, 0,  // format: PCM (1)
    300    17, 0,  // channels: 17
    301    0x39, 0x30, 0, 0,  // sample rate: 12345
    302    0x92, 0x67, 0x06, 0,  // byte rate: 2 * 17 * 12345
    303    34, 0,  // block align: NumChannels * BytesPerSample
    304    16, 0,  // bits per sample: 2 * 8
    305    'd', 'a', 't', 'a',
    306    0x32, 0xa1, 0xb7, 0x0e,  // size of payload: 2 * 123457689
    307    0xa4, 0xa4, 0xa4, 0xa4,  // untouched bytes after header
    308      // clang-format on
    309  };
    310  static_assert(sizeof(kExpectedBuf) == kSize, "buffer size");
    311  EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize));
    312 
    313  size_t num_channels = 0;
    314  int sample_rate = 0;
    315  WavFormat format = WavFormat::kWavFormatPcm;
    316  size_t bytes_per_sample = 0;
    317  size_t num_samples = 0;
    318  int64_t data_start_pos = 0;
    319  WavHeaderBufferReader r(buf + 4, sizeof(buf) - 8,
    320                          /*check_read_size=*/true);
    321  EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
    322                            &bytes_per_sample, &num_samples, &data_start_pos));
    323  EXPECT_EQ(17u, num_channels);
    324  EXPECT_EQ(12345, sample_rate);
    325  EXPECT_EQ(WavFormat::kWavFormatPcm, format);
    326  EXPECT_EQ(2u, bytes_per_sample);
    327  EXPECT_EQ(123457689u, num_samples);
    328 }
    329 
    330 // Try reading an atypical but valid WAV header and make sure it's parsed OK.
    331 TEST(WavHeaderTest, ReadAtypicalWavHeader) {
    332  constexpr uint8_t kBuf[] = {
    333      // clang-format off
    334      // clang formatting doesn't respect inline comments.
    335    'R', 'I', 'F', 'F',
    336    0xbf, 0xd0, 0x5b, 0x07,  // Size of whole file - 8 + extra 2 bytes of zero
    337                             // extension: 123457689 + 44 - 8 + 2 (atypical).
    338    'W', 'A', 'V', 'E',
    339    'f', 'm', 't', ' ',
    340    18, 0, 0, 0,             // Size of fmt block (with an atypical extension
    341                             // size field).
    342    1, 0,                    // Format: PCM (1).
    343    17, 0,                   // Channels: 17.
    344    0x39, 0x30, 0, 0,        // Sample rate: 12345.
    345    0xc9, 0x33, 0x03, 0,     // Byte rate: 1 * 17 * 12345.
    346    17, 0,                   // Block align: NumChannels * BytesPerSample.
    347    8, 0,                    // Bits per sample: 1 * 8.
    348    0, 0,                    // Zero extension size field (atypical).
    349    'd', 'a', 't', 'a',
    350    0x99, 0xd0, 0x5b, 0x07,  // Size of payload: 123457689.
    351      // clang-format on
    352  };
    353 
    354  size_t num_channels = 0;
    355  int sample_rate = 0;
    356  WavFormat format = WavFormat::kWavFormatPcm;
    357  size_t bytes_per_sample = 0;
    358  size_t num_samples = 0;
    359  int64_t data_start_pos = 0;
    360  WavHeaderBufferReader r(kBuf, sizeof(kBuf), /*check_read_size=*/true);
    361  EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
    362                            &bytes_per_sample, &num_samples, &data_start_pos));
    363  EXPECT_EQ(17u, num_channels);
    364  EXPECT_EQ(12345, sample_rate);
    365  EXPECT_EQ(WavFormat::kWavFormatPcm, format);
    366  EXPECT_EQ(1u, bytes_per_sample);
    367  EXPECT_EQ(123457689u, num_samples);
    368 }
    369 
    370 // Try reading a valid WAV header which contains an optional chunk and make sure
    371 // it's parsed OK.
    372 TEST(WavHeaderTest, ReadWavHeaderWithOptionalChunk) {
    373  constexpr uint8_t kBuf[] = {
    374      // clang-format off
    375      // clang formatting doesn't respect inline comments.
    376    'R', 'I', 'F', 'F',
    377    0xcd, 0xd0, 0x5b, 0x07,  // Size of whole file - 8 + an extra 16 bytes of
    378                             // "metadata" (8 bytes header, 16 bytes payload):
    379                             // 123457689 + 44 - 8 + 16.
    380    'W', 'A', 'V', 'E',
    381    'f', 'm', 't', ' ',
    382    16, 0, 0, 0,             // Size of fmt block.
    383    1, 0,                    // Format: PCM (1).
    384    17, 0,                   // Channels: 17.
    385    0x39, 0x30, 0, 0,        // Sample rate: 12345.
    386    0xc9, 0x33, 0x03, 0,     // Byte rate: 1 * 17 * 12345.
    387    17, 0,                   // Block align: NumChannels * BytesPerSample.
    388    8, 0,                    // Bits per sample: 1 * 8.
    389    'L', 'I', 'S', 'T',      // Metadata chunk ID.
    390    16, 0, 0, 0,             // Metadata chunk payload size.
    391    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // Metadata (16 bytes).
    392    'd', 'a', 't', 'a',
    393    0x99, 0xd0, 0x5b, 0x07,  // Size of payload: 123457689.
    394      // clang-format on
    395  };
    396 
    397  size_t num_channels = 0;
    398  int sample_rate = 0;
    399  WavFormat format = WavFormat::kWavFormatPcm;
    400  size_t bytes_per_sample = 0;
    401  size_t num_samples = 0;
    402  int64_t data_start_pos = 0;
    403  WavHeaderBufferReader r(kBuf, sizeof(kBuf), /*check_read_size=*/true);
    404  EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
    405                            &bytes_per_sample, &num_samples, &data_start_pos));
    406  EXPECT_EQ(17u, num_channels);
    407  EXPECT_EQ(12345, sample_rate);
    408  EXPECT_EQ(WavFormat::kWavFormatPcm, format);
    409  EXPECT_EQ(1u, bytes_per_sample);
    410  EXPECT_EQ(123457689u, num_samples);
    411 }
    412 
    413 // Try reading an invalid WAV header which has the the data chunk before the
    414 // format one and make sure it's not parsed.
    415 TEST(WavHeaderTest, ReadWavHeaderWithDataBeforeFormat) {
    416  constexpr uint8_t kBuf[] = {
    417      // clang-format off
    418      // clang formatting doesn't respect inline comments.
    419    'R', 'I', 'F', 'F',
    420    52,  0,   0,   0,    // Size of whole file - 8: 16 + 44 - 8.
    421    'W', 'A', 'V', 'E',
    422    'd', 'a', 't', 'a',
    423    16, 0, 0, 0,         // Data chunk payload size.
    424    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // Data 16 bytes.
    425    'f', 'm', 't', ' ',
    426    16,  0,   0,   0,    // Size of fmt block.
    427    1,   0,              // Format: Pcm (1).
    428    1,   0,              // Channels: 1.
    429    60,  0,   0,   0,    // Sample rate: 60.
    430    60,  0,   0,   0,    // Byte rate: 1 * 1 * 60.
    431    1,   0,              // Block align: NumChannels * BytesPerSample.
    432    8,   0,              // Bits per sample: 1 * 8.
    433      // clang-format on
    434  };
    435 
    436  size_t num_channels = 0;
    437  int sample_rate = 0;
    438  WavFormat format = WavFormat::kWavFormatPcm;
    439  size_t bytes_per_sample = 0;
    440  size_t num_samples = 0;
    441  int64_t data_start_pos = 0;
    442  WavHeaderBufferReader r(kBuf, sizeof(kBuf), /*check_read_size=*/false);
    443  EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
    444                             &bytes_per_sample, &num_samples, &data_start_pos));
    445 }
    446 
    447 }  // namespace webrtc