Esempio n. 1
0
bool Directory::write(const std::string& filename, const Containers::ArrayView<const void> data) {
    std::ofstream file(filename, std::ofstream::binary);
    if(!file) return false;

    file.write(reinterpret_cast<const char*>(data.data()), data.size());
    return true;
}
Esempio n. 2
0
template<UnsignedInt dimensions> void BufferImage<dimensions>::setData(const PixelStorage storage, const PixelFormat format, const PixelType type, const VectorTypeFor<dimensions, Int>& size, Containers::ArrayView<const void> const data, const BufferUsage usage) {
    _storage = storage;
    _format = format;
    _type = type;
    _size = size;

    /* Keep the old storage if zero-sized nullptr buffer was passed */
    if(data.data() == nullptr && data.size() == 0)
        CORRADE_ASSERT(Implementation::imageDataSize(*this) <= _dataSize, "BufferImage::setData(): bad current storage size, got" << _dataSize << "but expected at least" << Implementation::imageDataSize(*this), );
    else {
Esempio n. 3
0
std::pair<TweakableState, unsigned long long> TweakableParser<unsigned long long>::parse(Containers::ArrayView<const char> value) {
    const std::pair<const char*, int> valueBase = integerBase(value);
    char* end;
    const int result = std::strtoull(valueBase.first, &end, valueBase.second);

    if(end == value.begin()) {
        Warning{} << "Utility::TweakableParser:" << std::string{value, value.size()} << "is not an integer literal";
        return {TweakableState::Recompile, {}};
    }

    if(value.size() < 3 ||
      (value[value.size() - 1] != 'l' && value[value.size() - 1] != 'L' &&
       value[value.size() - 2] != 'l' && value[value.size() - 2] != 'L' &&
       value[value.size() - 2] != 'u' && value[value.size() - 2] != 'U'))
    {
        Warning{} << "Utility::TweakableParser:" << std::string{value, value.size()} << "has an unexpected suffix, expected ull";
        return {TweakableState::Recompile, {}};
    }

    if(end != value.end() - 3) {
        Warning{} << "Utility::TweakableParser: unexpected characters" << std::string{const_cast<const char*>(end), value.end()} <<  "after an integer literal";
        return {TweakableState::Recompile, {}};
    }

    return {TweakableState::Success, result};
}
Esempio n. 4
0
void AbstractObject::labelImplementationKhr(const GLenum identifier, const GLuint name, const Containers::ArrayView<const char> label) {
    #ifndef MAGNUM_TARGET_GLES
    glObjectLabel(identifier, name, label.size(), label);
    #elif !defined(CORRADE_TARGET_NACL)
    glObjectLabelKHR(identifier, name, label.size(), label);
    #else
    static_cast<void>(identifier);
    static_cast<void>(name);
    static_cast<void>(label);
    CORRADE_ASSERT_UNREACHABLE();
    #endif
}
Esempio n. 5
0
std::pair<TweakableState, char> TweakableParser<char>::parse(Containers::ArrayView<const char> value) {
    if(value.size() < 3 || value.front() != '\'' || value.back() != '\'') {
        Warning{} << "Utility::TweakableParser:" << std::string{value, value.size()} << "is not a character literal";
        return {TweakableState::Recompile, {}};
    }

    if(value[1] == '\\') {
        Error{} << "Utility::TweakableParser: escape sequences in char literals are not implemented, sorry";
        return {TweakableState::Error, {}};
    }

    return {TweakableState::Success, value[1]};
}
Esempio n. 6
0
void JpegImporter::doOpenData(const Containers::ArrayView<const char> data) {
    /* Because here we're copying the data and using the _in to check if file
       is opened, having them nullptr would mean openData() would fail without
       any error message. It's not possible to do this check on the importer
       side, because empty file is valid in some formats (OBJ or glTF). We also
       can't do the full import here because then doImage2D() would need to
       copy the imported data instead anyway (and the uncompressed size is much
       larger). This way it'll also work nicely with a future openMemory(). */
    if(data.empty()) {
        Error{} << "Trade::JpegImporter::openData(): the file is empty";
        return;
    }

    _in = Containers::Array<unsigned char>(data.size());
    std::copy(data.begin(), data.end(), _in.begin());
}
Esempio n. 7
0
std::pair<TweakableState, int> TweakableParser<int>::parse(Containers::ArrayView<const char> value) {
    const std::pair<const char*, int> valueBase = integerBase(value);
    char* end;
    const int result = std::strtol(valueBase.first, &end, valueBase.second);

    if(end == value.begin()) {
        Warning{} << "Utility::TweakableParser:" << std::string{value, value.size()} << "is not an integer literal";
        return {TweakableState::Recompile, {}};
    }

    if(end != value.end()) {
        Warning{} << "Utility::TweakableParser: unexpected characters" << std::string{const_cast<const char*>(end), value.end()} <<  "after an integer literal";
        return {TweakableState::Recompile, {}};
    }

    return {TweakableState::Success, result};
}
Esempio n. 8
0
std::pair<TweakableState, bool> TweakableParser<bool>::parse(Containers::ArrayView<const char> value) {
    if(value.size() == 4 && std::strncmp(value.data(), "true", value.size()) == 0)
        return {TweakableState::Success, true};
    if(value.size() == 5 && std::strncmp(value.data(), "false", value.size()) == 0)
        return {TweakableState::Success, false};

    Warning{} << "Utility::TweakableParser:" << std::string{value, value.size()} << "is not a boolean literal";
    return {TweakableState::Recompile, {}};
}
Esempio n. 9
0
void AbstractObject::labelImplementationExt(const GLenum identifier, const GLuint name, const Containers::ArrayView<const char> label) {
    #ifndef CORRADE_TARGET_NACL
    const GLenum type = extTypeFromKhrIdentifier(identifier);
    glLabelObjectEXT(type, name, label.size(), label);
    #else
    static_cast<void>(identifier);
    static_cast<void>(name);
    static_cast<void>(label);
    CORRADE_ASSERT_UNREACHABLE();
    #endif
}
Esempio n. 10
0
std::pair<TweakableState, long double> TweakableParser<long double>::parse(Containers::ArrayView<const char> value) {
    char* end;
    const long double result = std::strtold(value, &end);

    if(end == value.begin() || std::find(value.begin(), value.end(), '.') == value.end()) {
        Warning{} << "Utility::TweakableParser:" << std::string{value, value.size()} << "is not a floating-point literal";
        return {TweakableState::Recompile, {}};
    }

    /* If value would be empty, the above catches that */
    if(value.back() != 'l' && value.back() != 'L') {
        Warning{} << "Utility::TweakableParser:" << std::string{value, value.size()} << "has an unexpected suffix, expected l";
        return {TweakableState::Recompile, {}};
    }

    if(end != value.end() - 1) {
        Warning{} << "Utility::TweakableParser: unexpected characters" << std::string{const_cast<const char*>(end), value.end()} <<  "after a floating-point literal";
        return {TweakableState::Recompile, {}};
    }

    return {TweakableState::Success, result};
}
Esempio n. 11
0
std::pair<TweakableState, double> TweakableParser<double>::parse(Containers::ArrayView<const char> value) {
    char* end;
    const double result = std::strtod(value, &end);

    if(end == value.begin() || std::find(value.begin(), value.end(), '.') == value.end()) {
        Warning{} << "Utility::TweakableParser:" << std::string{value, value.size()} << "is not a floating-point literal";
        return {TweakableState::Recompile, {}};
    }

    if(end != value.end()) {
        Warning{} << "Utility::TweakableParser: unexpected characters" << std::string{const_cast<const char*>(end), value.end()} <<  "after a floating-point literal";
        return {TweakableState::Recompile, {}};
    }

    return {TweakableState::Success, result};
}
void StbVorbisImporter::doOpenData(Containers::ArrayView<const char> data) {

    Int numChannels, frequency;
    Short* decodedData = nullptr;

    Int samples = stb_vorbis_decode_memory(reinterpret_cast<const UnsignedByte*>(data.data()), data.size(), &numChannels, &frequency, &decodedData);

    if(samples == -1) {
        Error() << "Audio::StbVorbisImporter::openData(): the file signature is invalid";
        return;
    } else if (samples == -2) {
        /* memory allocation failure */
        Error() << "Audio::StbVorbisImporter::openData(): out of memory";
        return;
    }

    Containers::Array<char> tempData{reinterpret_cast<char*>(decodedData), size_t(samples*numChannels*2),
        [](char* data, size_t) { std::free(data); }};
    _frequency = frequency;

    /* Decide about format */
    if(numChannels == 1)
        _format = Buffer::Format::Mono16;
    else if(numChannels == 2)
        _format = Buffer::Format::Stereo16;
    /** @todo Buffer::Format::*Float32 when extension support is done */
    else {
        Error() << "Audio::StbVorbisImporter::openData(): unsupported channel count"
                << numChannels << "with" << 16 << "bits per sample";
        return;
    }

    _data = std::move(tempData);

    return;
}
Esempio n. 13
0
std::pair<TweakableState, long> TweakableParser<long>::parse(Containers::ArrayView<const char> value) {
    const std::pair<const char*, int> valueBase = integerBase(value);
    char* end;
    const long result = std::strtol(valueBase.first, &end, valueBase.second);

    if(end == value.begin()) {
        Warning{} << "Utility::TweakableParser:" << std::string{value, value.size()} << "is not an integer literal";
        return {TweakableState::Recompile, {}};
    }

    /* If value would be empty, the above catches that */
    if(value.back() != 'l' && value.back() != 'L') {
        Warning{} << "Utility::TweakableParser:" << std::string{value, value.size()} << "has an unexpected suffix, expected l";
        return {TweakableState::Recompile, {}};
    }

    if(end != value.end() - 1) {
        Warning{} << "Utility::TweakableParser: unexpected characters" << std::string{const_cast<const char*>(end), value.end()} <<  "after an integer literal";
        return {TweakableState::Recompile, {}};
    }

    return {TweakableState::Success, result};
}
Esempio n. 14
0
template<UnsignedInt dimensions> BufferImage<dimensions>::BufferImage(const PixelStorage storage, const PixelFormat format, const PixelType type, const VectorTypeFor<dimensions, Int>& size, Containers::ArrayView<const void> const data, const BufferUsage usage): _storage{storage}, _format{format}, _type{type}, _size{size}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{data.size()} {
    CORRADE_ASSERT(Implementation::imageDataSize(*this) <= data.size(), "BufferImage::BufferImage(): bad image data size, got" << data.size() << "but expected at least" << Implementation::imageDataSize(*this), );
    _buffer.setData(data, usage);
}
Esempio n. 15
0
inline bool equalsPrefix(const Containers::ArrayView<const char> data, const char* const prefix) {
    return std::strncmp(data, prefix, data.size()) == 0;
}
Esempio n. 16
0
void JpegImporter::doOpenData(const Containers::ArrayView<const char> data) {
    _in = Containers::Array<unsigned char>(data.size());
    std::copy(data.begin(), data.end(), _in.begin());
}
Esempio n. 17
0
Int AbstractShaderProgram::uniformLocationInternal(const Containers::ArrayView<const char> name) {
    GLint location = glGetUniformLocation(_id, name);
    if(location == -1)
        Warning() << "AbstractShaderProgram: location of uniform \'" + std::string{name, name.size()} + "\' cannot be retrieved!";
    return location;
}
Esempio n. 18
0
void AbstractShaderProgram::setUniform(const Int location, const Containers::ArrayView<const Math::Vector<4, UnsignedInt>> values) {
    (this->*Context::current()->state().shaderProgram->uniform4uivImplementation)(location, values.size(), values);
}
Esempio n. 19
0
void AnyImageImporter::doOpenData(Containers::ArrayView<const char> data) {
    CORRADE_INTERNAL_ASSERT(manager());

    std::string plugin;
    /* https://docs.microsoft.com/cs-cz/windows/desktop/direct3ddds/dx-graphics-dds-pguide */
    if(Utility::String::viewBeginsWith(data, "DDS "))
        plugin = "DdsImporter";
    /* http://www.openexr.com/openexrfilelayout.pdf */
    else if(Utility::String::viewBeginsWith(data, "\x76\x2f\x31\x01"))
        plugin = "OpenExrImporter";
    /* https://en.wikipedia.org/wiki/Radiance_(software)#HDR_image_format */
    else if(Utility::String::viewBeginsWith(data, "#?RADIANCE"))
        plugin = "HdrImporter";
    /* https://en.wikipedia.org/wiki/JPEG#Syntax_and_structure */
    else if(Utility::String::viewBeginsWith(data, "\xff\xd8\xff"))
        plugin = "JpegImporter";
    /* https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header */
    else if(Utility::String::viewBeginsWith(data, "\x89PNG\x0d\x0a\x1a\x0a"))
        plugin = "PngImporter";
    /* https://github.com/file/file/blob/d04de269e0b06ccd0a7d1bf4974fed1d75be7d9e/magic/Magdir/images#L18-L22
       TGAs are a complete guesswork, so try after everything else fails. */
    else if([data]() {
            /* TGA header is 18 bytes */
            if(data.size() < 18) return false;

            /* Third byte (image type) must be one of these */
            if(data[2] != 1 && data[2] != 2  && data[2] != 3 &&
               data[2] != 9 && data[2] != 10 && data[2] != 11) return false;

            /* If image type is 1 or 9, second byte (colormap type) must be 1 */
            if((data[2] == 1 || data[2] == 9) && data[1] != 1) return false;

            /* ... and 0 otherwise */
            if(data[2] != 1 && data[2] != 9 && data[1] != 0) return false;

            /* Colormap index (unsigned short, byte 3+4) should be 0 */
            if(data[3] != 0 && data[4] != 0) return false;

            /* Probably TGA, heh. Or random memory. */
            return true;
        }()) plugin = "TgaImporter";
    else if(!data.size()) {
        Error{} << "Trade::AnyImageImporter::openData(): file is empty";
        return;
    } else {
        std::uint32_t signature = data[0] << 24;
        if(data.size() > 1) signature |= data[1] << 16;
        if(data.size() > 2) signature |= data[2] << 8;
        if(data.size() > 3) signature |= data[3];
        Error() << "Trade::AnyImageImporter::openData(): cannot determine type from signature" << reinterpret_cast<void*>(signature);
        return;
    }

    /* Try to load the plugin */
    if(!(manager()->load(plugin) & PluginManager::LoadState::Loaded)) {
        Error() << "Trade::AnyImageImporter::openData(): cannot load" << plugin << "plugin";
        return;
    }

    /* Try to open the file (error output should be printed by the plugin
       itself) */
    Containers::Pointer<AbstractImporter> importer = static_cast<PluginManager::Manager<AbstractImporter>*>(manager())->instantiate(plugin);
    if(!importer->openData(data)) return;

    /* Success, save the instance */
    _in = std::move(importer);
}
Esempio n. 20
0
void DrWavImporter::doOpenData(const Containers::ArrayView<const char> data) {
    drwav* const handle = drwav_open_memory(data.data(), data.size());
    if(!handle) {
        Error() << "Audio::DrWavImporter::openData(): failed to open and decode WAV data";
        return;
    }
    Containers::ScopeGuard drwavClose{handle, drwav_close};

    const std::uint64_t samples = handle->totalSampleCount;
    const std::uint32_t frequency = handle->sampleRate;
    const std::uint8_t numChannels = handle->channels;
    const std::uint8_t bitsPerSample = handle->bitsPerSample;

    /* If the bits per sample is exact, we can read data raw */
    const Int notExactBitsPerSample = ((bitsPerSample % 8) ? 1 : 0);

    /* Normalize bit amounts to multiples of 8, rounding up */
    const UnsignedInt normalizedBytesPerSample = (bitsPerSample / 8) + notExactBitsPerSample;

    if(numChannels == 0 || numChannels == 3 || numChannels == 5 || numChannels > 8 ||
       normalizedBytesPerSample == 0 || normalizedBytesPerSample > 8) {
        Error() << "Audio::DrWavImporter::openData(): unsupported channel count"
                << numChannels << "with" << bitsPerSample
                << "bits per sample";
        return;
    }

    /* Can't load something with no samples */
    if(samples == 0) {
        Error() << "Audio::DrWavImporter::openData(): no samples";
        return;
    }

    _frequency = frequency;

    /* PCM has a lot of special cases, as we can read many formats directly */
    if(handle->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
        _format = PcmFormatTable[numChannels-1][normalizedBytesPerSample-1];
        CORRADE_INTERNAL_ASSERT(_format != BufferFormat{});

        /* If the data is exactly 8 or 16 bits, we can read it raw */
        if(!notExactBitsPerSample && normalizedBytesPerSample < 3) {
            _data = readRaw(handle, samples, normalizedBytesPerSample);
            return;

        /* If the data is approximately 24 bits or has many channels, a float is more than enough */
        } else if(normalizedBytesPerSample == 3 || (normalizedBytesPerSample > 3 && numChannels > 3)) {
            _data = read32fPcm(handle, samples, numChannels, _format);
            return;

        /* If the data is close to 8 or 16 bits, we can convert it from 32-bit PCM */
        } else if(normalizedBytesPerSample == 1 || normalizedBytesPerSample == 2) {
            Containers::Array<char> tempData(samples*sizeof(Int));
            drwav_read_s32(handle, samples, reinterpret_cast<Int*>(tempData.begin()));

            /* 32-bit PCM can be sliced down to 8 or 16 for direct reading */
            _data = convert32Pcm(tempData, samples, normalizedBytesPerSample);

            /* Convert 8 bit data to unsigned */
            if(normalizedBytesPerSample == 1)
                for(char& item: _data) item = item - 128;
            return;
        }

        /** @todo Allow loading of 32/64 bit streams to Double format to preserve all information */

    /* ALaw of 8/16 bits with 1/2 channels can be loaded directly */
    } else if(handle->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
        if(numChannels < 3 && !notExactBitsPerSample && (bitsPerSample == 8 || bitsPerSample == 16) ) {
            _format = ALawFormatTable[numChannels-1][normalizedBytesPerSample-1];
            _data = readRaw(handle, samples, normalizedBytesPerSample);
            return;
        }

    /* MuLaw of 8/16 bits with 1/2 channels can be loaded directly */
    } else if(handle->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
        if(numChannels < 3 && !notExactBitsPerSample && (bitsPerSample == 8 || bitsPerSample == 16) ) {
            _format = MuLawFormatTable[numChannels-1][normalizedBytesPerSample-1];
            _data = readRaw(handle, samples, normalizedBytesPerSample);
            return;
        }

    /* IEEE float or double can be loaded directly */
    } else if(handle->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
        if(!notExactBitsPerSample && (bitsPerSample == 32 || bitsPerSample == 64)) {
            _format = IeeeFormatTable[numChannels-1][(normalizedBytesPerSample / 4)-1];
            _data = readRaw(handle, samples, normalizedBytesPerSample);
            return;
        }
    }

    /* If we don't know what the format is, read it out as 32 bit float for compatibility */
    _data = read32fPcm(handle, samples, numChannels, _format);
    return;
}
Esempio n. 21
0
void AbstractShaderProgram::setUniform(const Int location, const Containers::ArrayView<const Double> values) {
    (this->*Context::current()->state().shaderProgram->uniform1dvImplementation)(location, values.size(), values);
}
Esempio n. 22
0
void AbstractShaderProgram::setUniform(const Int location, const Containers::ArrayView<const Math::RectangularMatrix<3, 3, Double>> values) {
    (this->*Context::current()->state().shaderProgram->uniformMatrix3dvImplementation)(location, values.size(), values);
}
Esempio n. 23
0
void DrFlacImporter::doOpenData(Containers::ArrayView<const char> data) {
    drflac* const handle = drflac_open_memory(data.data(), data.size());
    if(!handle) {
        Error() << "Audio::DrFlacImporter::openData(): failed to open and decode FLAC data";
        return;
    }
    Containers::ScopeGuard drflacClose{handle, drflac_close};

    const std::uint64_t samples = handle->totalSampleCount;
    const std::uint8_t numChannels = handle->channels;
    const std::uint8_t bitsPerSample = handle->bitsPerSample;

    /* FLAC supports any bitspersample from 4 to 64, but DrFlac always gives us
       32-bit samples. So we normalize bit amounts to multiples of 8, rounding
       up. */
    const UnsignedInt normalizedBytesPerSample = (bitsPerSample + 7)/8;

    if(numChannels == 0 || numChannels == 3 || numChannels == 5 || numChannels > 8 ||
       normalizedBytesPerSample == 0 || normalizedBytesPerSample > 8) {
        Error() << "Audio::DrFlacImporter::openData(): unsupported channel count"
                << numChannels << "with" << bitsPerSample
                << "bits per sample";
        return;
    }

    /* Can't load something with no samples */
    if(samples == 0) {
        Error() << "Audio::DrFlacImporter::openData(): no samples";
        return;
    }

    _frequency = handle->sampleRate;
    _format = flacFormatTable[numChannels-1][normalizedBytesPerSample-1];
    CORRADE_INTERNAL_ASSERT(_format != BufferFormat{});

    /* 32-bit integers need to be normalized to Double (with a 32 bit mantissa) */
    if(normalizedBytesPerSample == 4) {
        Containers::Array<Int> tempData(samples);
        drflac_read_s32(handle, samples, reinterpret_cast<Int*>(tempData.begin()));

        /* If the channel is mono/stereo, we can use double samples */
        if(numChannels < 3) {
            Containers::Array<Double> doubleData(samples);

            for(std::size_t i = 0; i < samples; ++i) {
                doubleData[i] = Math::unpack<Double>(tempData[i]);
            }

            const char* doubleBegin = reinterpret_cast<const char*>(doubleData.begin());
            const char* doubleEnd = reinterpret_cast<const char*>(doubleData.end());

            _data = Containers::Array<char>(samples*sizeof(Double));
            std::copy(doubleBegin, doubleEnd, _data.begin());

        /* Otherwise, convert to float */
        } else {
            Containers::Array<Float> floatData(samples);

            for(std::size_t i = 0; i < samples; ++i) {
                floatData[i] = Math::unpack<Float>(tempData[i]);
            }

            const char* floatBegin = reinterpret_cast<const char*>(floatData.begin());
            const char* floatEnd = reinterpret_cast<const char*>(floatData.end());

            _data = Containers::Array<char>(samples*sizeof(Float));
            std::copy(floatBegin, floatEnd, _data.begin());
        }

        return;
    }

    Containers::Array<char> tempData(samples*sizeof(Int));
    drflac_read_s32(handle, samples, reinterpret_cast<Int*>(tempData.begin()));

    _data = convert32PCM(tempData, samples, normalizedBytesPerSample);

    /* 8-bit needs to become unsigned */
    if(normalizedBytesPerSample == 1) {
        for(char& item: _data) item = item - 128;

    /* 24-bit needs to become float */
    } else if(normalizedBytesPerSample == 3) {
        Containers::Array<Float> floatData(samples);

        for(std::size_t i = 0; i != samples; ++i) {
            const UnsignedInt s0 = _data[i*3 + 0];
            const UnsignedInt s1 = _data[i*3 + 1];
            const UnsignedInt s2 = _data[i*3 + 2];

            const Int intData = Int((s0 << 8) | (s1 << 16) | (s2 << 24));
            floatData[i] = Math::unpack<Float>(intData);
        }

        const char* const floatBegin = reinterpret_cast<const char*>(floatData.begin());
        const char* const floatEnd = reinterpret_cast<const char*>(floatData.end());

        _data = Containers::Array<char>(samples*sizeof(Float));
        std::copy(floatBegin, floatEnd, _data.begin());
    }

    return;
}
Esempio n. 24
0
void TgaImporter::doOpenData(const Containers::ArrayView<const char> data) {
    _in = Containers::Array<char>{data.size()};
    std::copy(data.begin(), data.end(), _in.begin());
}
Esempio n. 25
0
std::string Resource::get(const std::string& filename) const {
    Containers::ArrayView<const char> data = getRaw(filename);
    return data ? std::string{data, data.size()} : std::string{};
}
Esempio n. 26
0
void WavImporter::doOpenData(Containers::ArrayView<const char> data) {
    /* Check file size */
    if(data.size() < sizeof(WavHeader)) {
        Error() << "Audio::WavImporter::openData(): the file is too short:" << data.size() << "bytes";
        return;
    }

    /* Get header contents and fix endianness */
    WavHeader header(*reinterpret_cast<const WavHeader*>(data.begin()));
    Utility::Endianness::littleEndianInPlace(header.chunkSize,
        header.subChunk1Size, header.audioFormat, header.numChannels,
        header.sampleRate, header.byteRate, header.blockAlign,
        header.bitsPerSample, header.subChunk2Size);

    /* Check file signature */
    if(std::strncmp(header.chunkId, "RIFF", 4) != 0 ||
       std::strncmp(header.format, "WAVE", 4) != 0 ||
       std::strncmp(header.subChunk1Id, "fmt ", 4) != 0 ||
       std::strncmp(header.subChunk2Id, "data", 4) != 0) {
        Error() << "Audio::WavImporter::openData(): the file signature is invalid";
        return;
    }

    /* Check file size */
    if(header.chunkSize + 8 != data.size()) {
        Error() << "Audio::WavImporter::openData(): the file has improper size, expected"
                << header.chunkSize + 8 << "but got" << data.size();
        return;
    }

    /* Check PCM format */
    if(header.audioFormat != 1) {
        Error() << "Audio::WavImporter::openData(): unsupported audio format" << header.audioFormat;
        return;
    }

    /* Verify more things */
    if(header.subChunk1Size != 16 ||
       header.subChunk2Size + 44 != data.size() ||
       header.blockAlign != header.numChannels*header.bitsPerSample/8 ||
       header.byteRate != header.sampleRate*header.blockAlign) {
        Error() << "Audio::WavImporter::openData(): the file is corrupted";
        return;
    }

    /* Decide about format */
    if(header.numChannels == 1 && header.bitsPerSample == 8)
        _format = Buffer::Format::Mono8;
    else if(header.numChannels == 1 && header.bitsPerSample == 16)
        _format = Buffer::Format::Mono16;
    else if(header.numChannels == 2 && header.bitsPerSample == 8)
        _format = Buffer::Format::Stereo8;
    else if(header.numChannels == 2 && header.bitsPerSample == 16)
        _format = Buffer::Format::Stereo16;
    else {
        Error() << "Audio::WavImporter::openData(): unsupported channel count"
                << header.numChannels << "with" << header.bitsPerSample
                << "bits per sample";
        return;
    }

    /* Save frequency */
    _frequency = header.sampleRate;

    /** @todo Convert the data from little endian too */
    CORRADE_INTERNAL_ASSERT(!Utility::Endianness::isBigEndian());

    /* Copy the data */
    _data = Containers::Array<char>(header.subChunk2Size);
    std::copy(data.begin()+sizeof(WavHeader), data.end(), _data.begin());
    return;
}