<commit_before>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * JS BINDINGS DESIGN
 * ------------------
 *
 * The purpose of the filamentjs library is to offer a first-class JavaScript interface to the core
 * Filament classes: Engine, Renderer, Texture, etc.
 *
 * Emscripten offers two ways to binding JavaScript to C++: embind and WebIDL. We chose embind.
 *
 * With WebIDL, we would need to author WebIDL files and generate opaque C++ from the IDL, which
 * complicates the build process and ultimately results in the same amount of code. Using embind is
 * more direct and controllable.
 *
 * For nested classes, we use $ as the separator character because embind does not support nested
 * classes and it would transform dot separators into $ anyway. By using $, we at least make
 * this explicit rather than mysterious.
 */

#include <filameshio/MeshIO.h>

#include <filament/Camera.h>
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
#include <filament/IndirectLight.h>
#include <filament/LightManager.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/RenderableManager.h>
#include <filament/Renderer.h>
#include <filament/Scene.h>
#include <filament/Skybox.h>
#include <filament/SwapChain.h>
#include <filament/Texture.h>
#include <filament/TransformManager.h>
#include <filament/VertexBuffer.h>
#include <filament/View.h>

#include <image/KtxBundle.h>

#include <math/vec2.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <math/mat4.h>

#include <utils/EntityManager.h>

#include <emscripten.h>
#include <emscripten/bind.h>

#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_STDIO
#define STBI_ONLY_PNG
#include <stb_image.h>

using namespace emscripten;
using namespace filament;
using namespace image;

// Many methods require a thin layer of C++ glue which is elegantly expressed with a lambda.
// However, passing a bare lambda into embind's daisy chain requires a cast to a function pointer.
#define EMBIND_LAMBDA(retval, arglist, impl) (retval (*) arglist) [] arglist impl

// Builder functions that return "this" have verbose binding declarations, this macro reduces
// the amount of boilerplate.
#define BUILDER_FUNCTION(name, btype, arglist, impl) \
        function(name, EMBIND_LAMBDA(btype*, arglist, impl), allow_raw_pointers())

// Explicit instantiation of emscripten::internal::raw_destructor is required for binding classes
// that have non-public destructors.
#define BIND(T) template<> void raw_destructor<T>(T* ptr) {}
namespace emscripten {
    namespace internal {
        BIND(Engine)
        BIND(SwapChain)
        BIND(Renderer)
        BIND(View)
        BIND(Scene)
        BIND(Camera)
        BIND(LightManager)
        BIND(RenderableManager)
        BIND(TransformManager)
        BIND(VertexBuffer)
        BIND(IndexBuffer)
        BIND(IndirectLight)
        BIND(Material)
        BIND(MaterialInstance)
        BIND(Skybox)
        BIND(Texture)
        BIND(utils::Entity)
        BIND(utils::EntityManager)
    }
}
#undef BIND

namespace {

// For convenience, declare terse private aliases to nested types. This lets us avoid extremely
// verbose binding declarations.
using RenderBuilder = RenderableManager::Builder;
using VertexBuilder = VertexBuffer::Builder;
using IndexBuilder = IndexBuffer::Builder;
using MatBuilder = Material::Builder;
using TexBuilder = Texture::Builder;
using LightBuilder = LightManager::Builder;
using IblBuilder = IndirectLight::Builder;
using SkyBuilder = Skybox::Builder;

// We avoid directly exposing driver::BufferDescriptor because embind does not support move
// semantics and void* doesn't make sense to JavaScript anyway. This little wrapper class is exposed
// to JavaScript as "driver$BufferDescriptor", but clients will normally use our "Filament.Buffer"
// helper function (implemented in utilities.js)
struct BufferDescriptor {
    BufferDescriptor() {}
    // This form is used when JavaScript sends a buffer into WASM.
    BufferDescriptor(val arrdata) {
        auto byteLength = arrdata["byteLength"].as<uint32_t>();
        this->bd.reset(new driver::BufferDescriptor(malloc(byteLength), byteLength,
                [](void* buffer, size_t size, void* user) { free(buffer); }));
    }
    // This form is used when WASM needs to return a buffer to JavaScript.
    BufferDescriptor(uint8_t* data, uint32_t size) {
        this->bd.reset(new driver::BufferDescriptor(data, size));
    }
    val getBytes() {
        unsigned char *byteBuffer = (unsigned char*) bd->buffer;
        size_t bufferLength = bd->size;
        return val(typed_memory_view(bufferLength, byteBuffer));
    }
    // In order to match its JavaScript counterpart, the Buffer wrapper needs to use reference
    // counting, and the easiest way to achieve that is with shared_ptr.
    std::shared_ptr<driver::BufferDescriptor> bd;
};

// Exposed to JavaScript as "driver$PixelBufferDescriptor", but clients will normally use the
// "Filament.PixelBuffer" helper function (implemented in utilities.js)
struct PixelBufferDescriptor {
    PixelBufferDescriptor(val arrdata, driver::PixelDataFormat fmt, driver::PixelDataType dtype) {
        auto byteLength = arrdata["byteLength"].as<uint32_t>();
        this->pbd.reset(new driver::PixelBufferDescriptor(malloc(byteLength), byteLength,
                fmt, dtype, [](void* buffer, size_t size, void* user) { free(buffer); }));
    }
    val getBytes() {
        unsigned char *byteBuffer = (unsigned char*) pbd->buffer;
        size_t bufferLength = pbd->size;
        return val(typed_memory_view(bufferLength, byteBuffer));
    };
    // In order to match its JavaScript counterpart, the Buffer wrapper needs to use reference
    // counting, and the easiest way to achieve that is with shared_ptr.
    std::shared_ptr<driver::PixelBufferDescriptor> pbd;
};

// Small structure whose sole purpose is to return decoded image data to JavaScript.
struct DecodedPng {
    int width;
    int height;
    int encoded_ncomp;
    int decoded_ncomp;
    BufferDescriptor decoded_data;
    ~DecodedPng() {
      if (decoded_data.bd) {
        stbi_image_free(decoded_data.bd->buffer);
      }
    }
};

// JavaScript clients should call [createTextureFromPng] rather than calling this directly.
DecodedPng decodePng(BufferDescriptor encoded_data, int requested_ncomp) {
    DecodedPng result;
    stbi_uc* decoded_data = stbi_load_from_memory(
            (stbi_uc const *) encoded_data.bd->buffer,
            encoded_data.bd->size,
            &result.width,
            &result.height,
            &result.encoded_ncomp,
            requested_ncomp);
    const uint32_t decoded_size = result.width * result.height * requested_ncomp;
    result.decoded_data = BufferDescriptor(decoded_data, decoded_size);
    result.decoded_ncomp = requested_ncomp;
    return result;
}

} // anonymous namespace
<commit_msg>JS: fix use-before-free for PNG data.<commit_after>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * JS BINDINGS DESIGN
 * ------------------
 *
 * The purpose of the filamentjs library is to offer a first-class JavaScript interface to the core
 * Filament classes: Engine, Renderer, Texture, etc.
 *
 * Emscripten offers two ways to binding JavaScript to C++: embind and WebIDL. We chose embind.
 *
 * With WebIDL, we would need to author WebIDL files and generate opaque C++ from the IDL, which
 * complicates the build process and ultimately results in the same amount of code. Using embind is
 * more direct and controllable.
 *
 * For nested classes, we use $ as the separator character because embind does not support nested
 * classes and it would transform dot separators into $ anyway. By using $, we at least make
 * this explicit rather than mysterious.
 */

#include <filameshio/MeshIO.h>

#include <filament/Camera.h>
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
#include <filament/IndirectLight.h>
#include <filament/LightManager.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/RenderableManager.h>
#include <filament/Renderer.h>
#include <filament/Scene.h>
#include <filament/Skybox.h>
#include <filament/SwapChain.h>
#include <filament/Texture.h>
#include <filament/TransformManager.h>
#include <filament/VertexBuffer.h>
#include <filament/View.h>

#include <image/KtxBundle.h>

#include <math/vec2.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <math/mat4.h>

#include <utils/EntityManager.h>

#include <emscripten.h>
#include <emscripten/bind.h>

#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_STDIO
#define STBI_ONLY_PNG
#include <stb_image.h>

using namespace emscripten;
using namespace filament;
using namespace image;

// Many methods require a thin layer of C++ glue which is elegantly expressed with a lambda.
// However, passing a bare lambda into embind's daisy chain requires a cast to a function pointer.
#define EMBIND_LAMBDA(retval, arglist, impl) (retval (*) arglist) [] arglist impl

// Builder functions that return "this" have verbose binding declarations, this macro reduces
// the amount of boilerplate.
#define BUILDER_FUNCTION(name, btype, arglist, impl) \
        function(name, EMBIND_LAMBDA(btype*, arglist, impl), allow_raw_pointers())

// Explicit instantiation of emscripten::internal::raw_destructor is required for binding classes
// that have non-public destructors.
#define BIND(T) template<> void raw_destructor<T>(T* ptr) {}
namespace emscripten {
    namespace internal {
        BIND(Engine)
        BIND(SwapChain)
        BIND(Renderer)
        BIND(View)
        BIND(Scene)
        BIND(Camera)
        BIND(LightManager)
        BIND(RenderableManager)
        BIND(TransformManager)
        BIND(VertexBuffer)
        BIND(IndexBuffer)
        BIND(IndirectLight)
        BIND(Material)
        BIND(MaterialInstance)
        BIND(Skybox)
        BIND(Texture)
        BIND(utils::Entity)
        BIND(utils::EntityManager)
    }
}
#undef BIND

namespace {

// For convenience, declare terse private aliases to nested types. This lets us avoid extremely
// verbose binding declarations.
using RenderBuilder = RenderableManager::Builder;
using VertexBuilder = VertexBuffer::Builder;
using IndexBuilder = IndexBuffer::Builder;
using MatBuilder = Material::Builder;
using TexBuilder = Texture::Builder;
using LightBuilder = LightManager::Builder;
using IblBuilder = IndirectLight::Builder;
using SkyBuilder = Skybox::Builder;

// We avoid directly exposing driver::BufferDescriptor because embind does not support move
// semantics and void* doesn't make sense to JavaScript anyway. This little wrapper class is exposed
// to JavaScript as "driver$BufferDescriptor", but clients will normally use our "Filament.Buffer"
// helper function (implemented in utilities.js)
struct BufferDescriptor {
    BufferDescriptor() {}
    // This form is used when JavaScript sends a buffer into WASM.
    BufferDescriptor(val arrdata) {
        auto byteLength = arrdata["byteLength"].as<uint32_t>();
        this->bd.reset(new driver::BufferDescriptor(malloc(byteLength), byteLength,
                [](void* buffer, size_t size, void* user) { free(buffer); }));
    }
    // This form is used when WASM needs to return a buffer to JavaScript.
    BufferDescriptor(uint8_t* data, uint32_t size) {
        this->bd.reset(new driver::BufferDescriptor(data, size));
    }
    val getBytes() {
        unsigned char *byteBuffer = (unsigned char*) bd->buffer;
        size_t bufferLength = bd->size;
        return val(typed_memory_view(bufferLength, byteBuffer));
    }
    // In order to match its JavaScript counterpart, the Buffer wrapper needs to use reference
    // counting, and the easiest way to achieve that is with shared_ptr.
    std::shared_ptr<driver::BufferDescriptor> bd;
};

// Exposed to JavaScript as "driver$PixelBufferDescriptor", but clients will normally use the
// "Filament.PixelBuffer" helper function (implemented in utilities.js)
struct PixelBufferDescriptor {
    PixelBufferDescriptor(val arrdata, driver::PixelDataFormat fmt, driver::PixelDataType dtype) {
        auto byteLength = arrdata["byteLength"].as<uint32_t>();
        this->pbd.reset(new driver::PixelBufferDescriptor(malloc(byteLength), byteLength,
                fmt, dtype, [](void* buffer, size_t size, void* user) { free(buffer); }));
    }
    val getBytes() {
        unsigned char *byteBuffer = (unsigned char*) pbd->buffer;
        size_t bufferLength = pbd->size;
        return val(typed_memory_view(bufferLength, byteBuffer));
    };
    // In order to match its JavaScript counterpart, the Buffer wrapper needs to use reference
    // counting, and the easiest way to achieve that is with shared_ptr.
    std::shared_ptr<driver::PixelBufferDescriptor> pbd;
};

// Small structure whose sole purpose is to return decoded image data to JavaScript.
struct DecodedPng {
    int width;
    int height;
    int encoded_ncomp;
    int decoded_ncomp;
    BufferDescriptor decoded_data;
};

// JavaScript clients should call [createTextureFromPng] rather than calling this directly.
DecodedPng decodePng(BufferDescriptor encoded_data, int requested_ncomp) {
    DecodedPng result;
    stbi_uc* decoded_data = stbi_load_from_memory(
            (stbi_uc const *) encoded_data.bd->buffer,
            encoded_data.bd->size,
            &result.width,
            &result.height,
            &result.encoded_ncomp,
            requested_ncomp);
    const uint32_t decoded_size = result.width * result.height * requested_ncomp;
    result.decoded_data = BufferDescriptor(decoded_data, decoded_size);
    result.decoded_data.bd->setCallback([](void* buffer, size_t size, void* user) {
        stbi_image_free(buffer);
    });
    result.decoded_ncomp = requested_ncomp;
    return result;
}

} // anonymous namespace

{'fraction_non_alphanumeric': 0.09582999198075381, 'fraction_numerical': 0.0028067361668003207, 'mean_word_length': 3.814993564993565, 'pattern_counts': {'":': 0, '<': 67, '<?xml version=': 0, '>': 87, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7196247', 'n_tokens_mistral': 4306, 'n_tokens_neox': 4226, 'n_words': 1412}