<commit_before>#include <tiramisu/tiramisu.h>

#include "configuration.h"

using namespace tiramisu;

int main(int argc, char **argv)
{
    // Single LSTM block without minibatching
    tiramisu::init("lstm");

    // -------------------------------------------------------
    // Layer I
    // -------------------------------------------------------

    // Inner dimensions
    var i("i", 0, FEATURE_SIZE), j("j", 0, FEATURE_SIZE), k("k", 0, BATCH_SIZE);
    var i_merged("i_merged", 0, 4 * FEATURE_SIZE);
    var i0("i0"), i1("i1"), k0("k0"), k1("k1");
    // Outer dimensions
    var l("l", 0, NUM_LAYERS), m("m", 0, SEQ_LENGTH);

    input R("R", {l, i_merged, j}, p_float32);
    input W("W", {l, i_merged, j}, p_float32);
    input b("b", {l, i_merged}, p_float32);
    input x({m, k, i}, p_float32);

    buffer buf_Weights_cpu("buf_Weights_cpu", {NUM_LAYERS, 2, 4 * FEATURE_SIZE, FEATURE_SIZE}, p_float32, a_input);
    buffer buf_Weights("buf_Weights", {NUM_LAYERS, 2, 4 * FEATURE_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_h("buf_h", {SEQ_LENGTH + 1, NUM_LAYERS + 1, BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_tmp("buf_tmp", {BATCH_SIZE, 4 * FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_biases_cpu("buf_biases_cpu", {NUM_LAYERS, 4 * FEATURE_SIZE}, p_float32, a_input);
    buffer buf_x_cpu("buf_x_cpu", {SEQ_LENGTH, BATCH_SIZE, FEATURE_SIZE}, p_float32, a_input);
    buffer buf_y_cpu("buf_y_cpu", {SEQ_LENGTH, BATCH_SIZE, FEATURE_SIZE}, p_float32, a_output);
    buffer buf_biases("buf_biases", {NUM_LAYERS, 4 * FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_x("buf_x", {SEQ_LENGTH, BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_y("buf_y", {SEQ_LENGTH, BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_tmp_i("buf_tmp_i", {BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_tmp_z("buf_tmp_z", {BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_tmp_o("buf_tmp_o", {BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_tmp_f("buf_tmp_f", {BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_c("buf_c", {SEQ_LENGTH + 1, NUM_LAYERS, BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buf_Weights.tag_gpu_global();
    buf_h.tag_gpu_global();
    buf_tmp.tag_gpu_global();
    buf_biases.tag_gpu_global();
    buf_x.tag_gpu_global();
    buf_y.tag_gpu_global();
    buf_tmp_i.tag_gpu_global();
    buf_tmp_z.tag_gpu_global();
    buf_tmp_o.tag_gpu_global();
    buf_tmp_f.tag_gpu_global();
    buf_c.tag_gpu_global();

    // h(m, l) is the output of the block (m, l)
    // which takes h(m - 1, l) and h(m, l - 1) as inputs
    // initial hidden states are h(-1, l) and c(-1, l)
    // input x is copied to h(m, -1)
    computation h({m, l, k, i}, p_float32);
    computation c({m, l, k, i}, p_float32);
    computation h_init({l, k, i}, expr(float(0)));
    computation c_init({l, k, i}, expr(float(0)));
    computation h_copy_x({m, k, i}, x(m, k, i));
    computation sum_init({m, l, k, i_merged}, b(l, i_merged));
    computation sum1({m, l},
        cublas_sgemm(buf_h, buf_Weights, buf_tmp,
                     BATCH_SIZE, 4 * FEATURE_SIZE, FEATURE_SIZE,
                     1, 1,  // alpha, beta
                     0, 0, 0,  // ldABC
                     (m * (NUM_LAYERS + 1) + l + 1) * BATCH_SIZE * FEATURE_SIZE,  //offsetA
                     (l * 2) * 4 * FEATURE_SIZE * FEATURE_SIZE,  //offsetB
                     0,  // offsetC
                     false, true));
    computation sum2({m, l},
        cublas_sgemm(buf_h, buf_Weights, buf_tmp,
                     BATCH_SIZE, 4 * FEATURE_SIZE, FEATURE_SIZE,
                     1, 1,  // alpha, beta
                     0, 0, 0,  // ldABC
                     ((m + 1) * (NUM_LAYERS + 1) + l) * BATCH_SIZE * FEATURE_SIZE,  //offsetA
                     (l * 2 + 1) * 4 * FEATURE_SIZE * FEATURE_SIZE,  //offsetB
                     0,  // offsetC
                     false, true));
    #define sigmoid(x) expr(float(1)) / (1 + expr(o_expo, -(x)))
    computation sig_i({m, l, k, i}, sigmoid(sum_init(m, l, k, i)));
    computation tnh_z({m, l, k, i}, expr(o_tanh, sum_init(m, l, k, i + FEATURE_SIZE)));
    computation sig_o({m, l, k, i}, sigmoid(sum_init(m, l, k, i + 2 * FEATURE_SIZE)));
    computation sig_f({m, l, k, i}, sigmoid(sum_init(m, l, k, i + 3 * FEATURE_SIZE)));
    computation mul_iz({m, l, k, i}, sig_i(m, l, k, i) * tnh_z(m, l, k, i));
    computation mul_fc({m, l, k, i}, sig_f(m, l, k, i) * c(m - 1, l, k, i));
    c.set_expression(mul_iz(m, l, k, i) + mul_fc(m, l, k, i));
    computation tnh_c({m, l, k, i}, expr(o_tanh, c(m, l, k, i)));
    h.set_expression(tnh_c(m, l, k, i) * sig_o(m, l, k, i));
    // Output is the last layer
    computation y({m, k, i}, h(m, NUM_LAYERS - 1, k, i));
    // Copies
    computation copy_Weights_to_device({}, memcpy(buf_Weights_cpu, buf_Weights));
    computation copy_biases_to_device({}, memcpy(buf_biases_cpu, buf_biases));
    computation copy_x_to_device({}, memcpy(buf_x_cpu, buf_x));
    computation copy_y_to_host({}, memcpy(buf_y, buf_y_cpu));

    // -------------------------------------------------------
    // Layer II
    // -------------------------------------------------------

    block({&h_init, &c_init, &h_copy_x, &sig_i, &tnh_z, &sig_o, &sig_f, &mul_iz,
           &mul_fc, &c, &tnh_c, &h, &y}).gpu_tile(k, i, 16, 16, k0, i0, k1, i1);
    sum_init.gpu_tile(k, i_merged, 16, 16, k0, i0, k1, i1);

    // Scheduling commands
    copy_Weights_to_device
            .then(copy_biases_to_device, computation::root)
            .then(copy_x_to_device, computation::root)
            .then(h_init, computation::root)
            .then(c_init, computation::root)
            .then(h_copy_x, computation::root)
            .then(sum_init, computation::root)
            .then(sum1, l)
            .then(sum2, l)
            .then(sig_i, l)
            .then(tnh_z, l)
            .then(sig_o, l)
            .then(sig_f, l)
            .then(mul_iz, l)
            .then(mul_fc, l)
            .then(c, l)
            .then(tnh_c, l)
            .then(h, l)
            .then(y, computation::root)
            .then(copy_y_to_host, computation::root);

    // -------------------------------------------------------
    // Layer III
    // -------------------------------------------------------

    // Weights and biases are packed
    R.store_in(&buf_Weights, {l, 0, i_merged, j});
    W.store_in(&buf_Weights, {l, 1, i_merged, j});
    b.store_in(&buf_biases, {l, i_merged});
    x.store_in(&buf_x);
    y.store_in(&buf_y);
    sum_init.store_in(&buf_tmp, {k, i_merged});
    sig_i.store_in(&buf_tmp_i, {k, i});
    tnh_z.store_in(&buf_tmp_z, {k, i});
    sig_o.store_in(&buf_tmp_o, {k, i});
    sig_f.store_in(&buf_tmp_f, {k, i});
    mul_iz.store_in(&buf_tmp_i, {k, i});
    mul_fc.store_in(&buf_tmp_f, {k, i});
    tnh_c.store_in(&buf_tmp_i, {k, i});
    h.store_in(&buf_h, {m + 1, l + 1, k, i});
    c.store_in(&buf_c, {m + 1, l, k, i});
    h_init.store_in(&buf_h, {0, l + 1, k, i});
    c_init.store_in(&buf_c, {0, l, k, i});
    h_copy_x.store_in(&buf_h, {m + 1, 0, k, i});

    // -------------------------------------------------------
    // Code Generation
    // -------------------------------------------------------

    // Generate object files.
    tiramisu::codegen({
            &buf_Weights_cpu,
            &buf_biases_cpu,
            &buf_x_cpu,
            &buf_y_cpu,
        }, "lstm.o", true);

    return 0;
}
<commit_msg>LSTM_lib fuse<commit_after>#include <tiramisu/tiramisu.h>

#include "configuration.h"

using namespace tiramisu;

int main(int argc, char **argv)
{
    // Single LSTM block without minibatching
    tiramisu::init("lstm");

    // -------------------------------------------------------
    // Layer I
    // -------------------------------------------------------

    // Inner dimensions
    var i("i", 0, FEATURE_SIZE), j("j", 0, FEATURE_SIZE), k("k", 0, BATCH_SIZE);
    var i_merged("i_merged", 0, 4 * FEATURE_SIZE);
    var i0("i0"), i1("i1"), k0("k0"), k1("k1");
    // Outer dimensions
    var l("l", 0, NUM_LAYERS), m("m", 0, SEQ_LENGTH);

    input R("R", {l, i_merged, j}, p_float32);
    input W("W", {l, i_merged, j}, p_float32);
    input b("b", {l, i_merged}, p_float32);
    input x({m, k, i}, p_float32);

    buffer buf_Weights_cpu("buf_Weights_cpu", {NUM_LAYERS, 2, 4 * FEATURE_SIZE, FEATURE_SIZE}, p_float32, a_input);
    buffer buf_Weights("buf_Weights", {NUM_LAYERS, 2, 4 * FEATURE_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_h("buf_h", {SEQ_LENGTH + 1, NUM_LAYERS + 1, BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_tmp("buf_tmp", {BATCH_SIZE, 4 * FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_biases_cpu("buf_biases_cpu", {NUM_LAYERS, 4 * FEATURE_SIZE}, p_float32, a_input);
    buffer buf_x_cpu("buf_x_cpu", {SEQ_LENGTH, BATCH_SIZE, FEATURE_SIZE}, p_float32, a_input);
    buffer buf_y_cpu("buf_y_cpu", {SEQ_LENGTH, BATCH_SIZE, FEATURE_SIZE}, p_float32, a_output);
    buffer buf_biases("buf_biases", {NUM_LAYERS, 4 * FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_x("buf_x", {SEQ_LENGTH, BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_y("buf_y", {SEQ_LENGTH, BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_tmp_i("buf_tmp_i", {BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_tmp_z("buf_tmp_z", {BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_tmp_o("buf_tmp_o", {BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_tmp_f("buf_tmp_f", {BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buffer buf_c("buf_c", {SEQ_LENGTH + 1, NUM_LAYERS, BATCH_SIZE, FEATURE_SIZE}, p_float32, a_temporary);
    buf_Weights.tag_gpu_global();
    buf_h.tag_gpu_global();
    buf_tmp.tag_gpu_global();
    buf_biases.tag_gpu_global();
    buf_x.tag_gpu_global();
    buf_y.tag_gpu_global();
    buf_tmp_i.tag_gpu_global();
    buf_tmp_z.tag_gpu_global();
    buf_tmp_o.tag_gpu_global();
    buf_tmp_f.tag_gpu_global();
    buf_c.tag_gpu_global();

    // h(m, l) is the output of the block (m, l)
    // which takes h(m - 1, l) and h(m, l - 1) as inputs
    // initial hidden states are h(-1, l) and c(-1, l)
    // input x is copied to h(m, -1)
    computation h({m, l, k, i}, p_float32);
    computation c({m, l, k, i}, p_float32);
    computation h_init({l, k, i}, expr(float(0)));
    computation c_init({l, k, i}, expr(float(0)));
    computation h_copy_x({m, k, i}, x(m, k, i));
    computation sum_init({m, l, k, i_merged}, b(l, i_merged));
    computation sum1({m, l},
        cublas_sgemm(buf_h, buf_Weights, buf_tmp,
                     BATCH_SIZE, 4 * FEATURE_SIZE, FEATURE_SIZE,
                     1, 1,  // alpha, beta
                     0, 0, 0,  // ldABC
                     (m * (NUM_LAYERS + 1) + l + 1) * BATCH_SIZE * FEATURE_SIZE,  //offsetA
                     (l * 2) * 4 * FEATURE_SIZE * FEATURE_SIZE,  //offsetB
                     0,  // offsetC
                     false, true));
    computation sum2({m, l},
        cublas_sgemm(buf_h, buf_Weights, buf_tmp,
                     BATCH_SIZE, 4 * FEATURE_SIZE, FEATURE_SIZE,
                     1, 1,  // alpha, beta
                     0, 0, 0,  // ldABC
                     ((m + 1) * (NUM_LAYERS + 1) + l) * BATCH_SIZE * FEATURE_SIZE,  //offsetA
                     (l * 2 + 1) * 4 * FEATURE_SIZE * FEATURE_SIZE,  //offsetB
                     0,  // offsetC
                     false, true));
    #define sigmoid(x) expr(float(1)) / (1 + expr(o_expo, -(x)))
    computation sig_i({m, l, k, i}, sigmoid(sum_init(m, l, k, i)));
    computation tnh_z({m, l, k, i}, expr(o_tanh, sum_init(m, l, k, i + FEATURE_SIZE)));
    computation sig_o({m, l, k, i}, sigmoid(sum_init(m, l, k, i + 2 * FEATURE_SIZE)));
    computation sig_f({m, l, k, i}, sigmoid(sum_init(m, l, k, i + 3 * FEATURE_SIZE)));
    computation mul_iz({m, l, k, i}, sig_i(m, l, k, i) * tnh_z(m, l, k, i));
    computation mul_fc({m, l, k, i}, sig_f(m, l, k, i) * c(m - 1, l, k, i));
    c.set_expression(mul_iz(m, l, k, i) + mul_fc(m, l, k, i));
    computation tnh_c({m, l, k, i}, expr(o_tanh, c(m, l, k, i)));
    h.set_expression(tnh_c(m, l, k, i) * sig_o(m, l, k, i));
    // Output is the last layer
    computation y({m, k, i}, h(m, NUM_LAYERS - 1, k, i));
    // Copies
    computation copy_Weights_to_device({}, memcpy(buf_Weights_cpu, buf_Weights));
    computation copy_biases_to_device({}, memcpy(buf_biases_cpu, buf_biases));
    computation copy_x_to_device({}, memcpy(buf_x_cpu, buf_x));
    computation copy_y_to_host({}, memcpy(buf_y, buf_y_cpu));

    // -------------------------------------------------------
    // Layer II
    // -------------------------------------------------------

    block({&h_init, &c_init, &h_copy_x, &sig_i, &tnh_z, &sig_o, &sig_f, &mul_iz,
           &mul_fc, &c, &tnh_c, &h, &y}).gpu_tile(k, i, 16, 16, k0, i0, k1, i1);
    sum_init.gpu_tile(k, i_merged, 16, 16, k0, i0, k1, i1);

    // Scheduling commands
    copy_Weights_to_device
            .then(copy_biases_to_device, computation::root)
            .then(copy_x_to_device, computation::root)
            .then(h_init, computation::root)
            .then(c_init, computation::root)
            .then(h_copy_x, computation::root)
            .then(sum_init, computation::root)
            .then(sum1, l)
            .then(sum2, l)
            .then(sig_i, i1)
            .then(tnh_z, i1)
            .then(sig_o, i1)
            .then(sig_f, i1)
            .then(mul_iz, i1)
            .then(mul_fc, i1)
            .then(c, i1)
            .then(tnh_c, i1)
            .then(h, i1)
            .then(y, computation::root)
            .then(copy_y_to_host, computation::root);

    // -------------------------------------------------------
    // Layer III
    // -------------------------------------------------------

    // Weights and biases are packed
    R.store_in(&buf_Weights, {l, 0, i_merged, j});
    W.store_in(&buf_Weights, {l, 1, i_merged, j});
    b.store_in(&buf_biases, {l, i_merged});
    x.store_in(&buf_x);
    y.store_in(&buf_y);
    sum_init.store_in(&buf_tmp, {k, i_merged});
    sig_i.store_in(&buf_tmp_i, {k, i});
    tnh_z.store_in(&buf_tmp_z, {k, i});
    sig_o.store_in(&buf_tmp_o, {k, i});
    sig_f.store_in(&buf_tmp_f, {k, i});
    mul_iz.store_in(&buf_tmp_i, {k, i});
    mul_fc.store_in(&buf_tmp_f, {k, i});
    tnh_c.store_in(&buf_tmp_i, {k, i});
    h.store_in(&buf_h, {m + 1, l + 1, k, i});
    c.store_in(&buf_c, {m + 1, l, k, i});
    h_init.store_in(&buf_h, {0, l + 1, k, i});
    c_init.store_in(&buf_c, {0, l, k, i});
    h_copy_x.store_in(&buf_h, {m + 1, 0, k, i});

    // -------------------------------------------------------
    // Code Generation
    // -------------------------------------------------------

    // Generate object files.
    tiramisu::codegen({
            &buf_Weights_cpu,
            &buf_biases_cpu,
            &buf_x_cpu,
            &buf_y_cpu,
        }, "lstm.o", true);

    return 0;
}
<|endoftext|>


<commit_before>// File: btBoostDynamicsShapes.hpp
#ifndef _btBoostDynamicsShapes_hpp
#define _btBoostDynamicsShapes_hpp

#include <btBulletDynamicsCommon.h>
#include <BulletCollision/CollisionShapes/btBox2dShape.h>
#include <boost/python.hpp>
#include "array_helpers.hpp"

using namespace boost::python;

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(chullshape_addPoint_overloads,
                                       btConvexHullShape::addPoint,
                                       1, 2)

void defineShapes()
{
    // Base classes, not for developer use

    class_<btCollisionShape, boost::noncopyable>
        ("btCollisionShape", no_init)
        .def_readonly("polyhedral", &btCollisionShape::isPolyhedral)
        .def_readonly("convex2d", &btCollisionShape::isConvex2d)
        .def_readonly("convex", &btCollisionShape::isConvex)
        .def_readonly("non_moving", &btCollisionShape::isNonMoving)
        .def_readonly("concave", &btCollisionShape::isConcave)
        .def_readonly("compound", &btCollisionShape::isCompound)
        .def_readonly("soft_body", &btCollisionShape::isSoftBody)
        .def_readonly("infinite", &btCollisionShape::isInfinite)
        .def_readonly("shape_type", &btCollisionShape::getShapeType)
        .add_property("margin", &btCollisionShape::getMargin,
                      &btCollisionShape::setMargin)
        .def("get_aabb", &btCollisionShape::getAabb)
        .def_readonly("aabb", &btCollisionShape::getAabb)
        .def("get_bounding_sphere", &btCollisionShape::getBoundingSphere)
        .def_readonly("angular_motion_disc",
                      &btCollisionShape::getAngularMotionDisc)
        .def("get_contact_breaking_threshold",
             &btCollisionShape::getContactBreakingThreshold)
        .def("calculate_temporal_aabb",
             &btCollisionShape::calculateTemporalAabb)
        .add_property("local_scaling",
                      make_function(&btCollisionShape::getLocalScaling,
                                    return_value_policy<copy_const_reference>()),
                      &btCollisionShape::setLocalScaling)
        .def("calculate_local_inertia", &btCollisionShape::calculateLocalInertia)
        .def("anisotropic_rolling_friction_direction",
             &btCollisionShape::getAnisotropicRollingFrictionDirection)
    ;

    class_<btConvexShape, bases<btCollisionShape>, boost::noncopyable>
        ("btConvexShape", no_init)
        .def("local_get_supporting_vertex",
             &btConvexShape::localGetSupportingVertexWithoutMargin)
        .def("local_get_supporting_vertex_without_margin_non_virtual",
             &btConvexShape::localGetSupportVertexWithoutMarginNonVirtual)
        .def("local_get_support_vertex_non_virtual",
             &btConvexShape::localGetSupportVertexNonVirtual)
        .def("get_margin_non_virtual",
             &btConvexShape::getMarginNonVirtual)
        .def("get_aabb_non_virtual",
             &btConvexShape::getAabbNonVirtual)
        .def("project", &btConvexShape::project)
        .def("batched_unit_vector_get_supporting_vertex_without_margin",
             &btConvexShape::batchedUnitVectorGetSupportingVertexWithoutMargin)
        .def("get_aabb_slow",
             &btConvexShape::getAabbSlow)
    ;

    class_<btConvexInternalShape, bases<btConvexShape>, boost::noncopyable>
        ("btConvexInternalShape", no_init)
        .add_property("implicit_shape_dimensions",
                      make_function(&btConvexInternalShape::getImplicitShapeDimensions,
                                    return_value_policy<copy_const_reference>()),
                      &btConvexInternalShape::setImplicitShapeDimensions)
        // TODO: wrap setSafeMargin overloads
        .def_readonly("local_scaling_non_virtual",
                      make_function(&btConvexInternalShape::getLocalScalingNV,
                                    return_value_policy<copy_const_reference>()))
        .def_readonly("margin_non_virtual",
                      make_function(&btConvexInternalShape::getMarginNV,
                                    return_value_policy<return_by_value>()))
        .def_readonly("num_preferred_penetration_directions",
                      &btConvexInternalShape::getNumPreferredPenetrationDirections)
        .def("get_preferred_penetration_direction",
             &btConvexInternalShape::getPreferredPenetrationDirection)
    ;

    class_<btPolyhedralConvexShape, bases<btConvexInternalShape>,
           boost::noncopyable>
        ("btPolyhedralConvexShape", no_init)
        .def_readonly("num_vertices", &btPolyhedralConvexShape::getNumVertices)
        .def_readonly("num_edges", &btPolyhedralConvexShape::getNumEdges)
        .def("get_edge", &btPolyhedralConvexShape::getEdge)
        .def("get_vertex", &btPolyhedralConvexShape::getVertex)
        .def_readonly("num_planes", &btPolyhedralConvexShape::getNumPlanes)
        .def("get_plane", &btPolyhedralConvexShape::getPlane)
        .def_readonly("is_inside", &btPolyhedralConvexShape::isInside)
    ;

    class_<btPolyhedralConvexAabbCachingShape, bases<btPolyhedralConvexShape>,
           boost::noncopyable>
        ("btPolyhedralConvexAabbCachingShape", no_init)
        .def("get_nonvirtual_aabb",
             &btPolyhedralConvexAabbCachingShape::getNonvirtualAabb)
        .def("recalc_local_aabb",
             &btPolyhedralConvexAabbCachingShape::getAabb)
    ;

    class_<btConcaveShape, bases<btCollisionShape>, boost::noncopyable>
        ("btConcaveShape", no_init)
    ;

    class_<btTriangleMeshShape, bases<btConcaveShape>, boost::noncopyable>
        ("btTriangleMeshShape", no_init)
    ;

    // End base classes

    // TODO: Add tests
    class_<btConvexHullShape, bases<btPolyhedralConvexAabbCachingShape> >
        ("btConvexHullShape")
        .def("add_point", &btConvexHullShape::addPoint,
             chullshape_addPoint_overloads())
        .def("get_unscaled_points",
             &btConvexHullShape::getUnscaledPoints_wrap,
             return_internal_reference<>())
        .def("get_scaled_point", &btConvexHullShape::getScaledPoint)
        .def("get_num_points", &btConvexHullShape::getNumPoints)
    ;

    // TODO: Add tests
    class_<btBox2dShape, bases<btPolyhedralConvexShape> >
        ("btBox2dShape", init<const btVector3&>())
        .def_readonly("half_extents_with_margin",
                      make_function(&btBox2dShape::getHalfExtentsWithMargin,
                                    return_value_policy<return_by_value>()))
        .def_readonly("half_extents_without_margin",
                      make_function(&btBox2dShape::getHalfExtentsWithoutMargin,
                                    return_internal_reference<>()))
    ;

    // TODO: Add tests
    class_<btBoxShape, bases<btPolyhedralConvexShape> >
        ("btBoxShape", init<const btVector3&>())
        .def_readonly("half_extents_with_margin",
                      make_function(&btBoxShape::getHalfExtentsWithMargin,
                                    return_value_policy<return_by_value>()))
        .def_readonly("half_extents_without_margin",
                      make_function(&btBoxShape::getHalfExtentsWithoutMargin,
                                    return_internal_reference<>()))
    ;

}

#endif // _btBoostDynamicsShapes_hpp
<commit_msg>Added non-defined btBvhTriangleMeshShape for data transfer<commit_after>// File: btBoostDynamicsShapes.hpp
#ifndef _btBoostDynamicsShapes_hpp
#define _btBoostDynamicsShapes_hpp

#include <btBulletDynamicsCommon.h>
#include <BulletCollision/CollisionShapes/btBox2dShape.h>
#include <boost/python.hpp>
#include "array_helpers.hpp"

using namespace boost::python;

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(chullshape_addPoint_overloads,
                                       btConvexHullShape::addPoint,
                                       1, 2)

void defineShapes()
{
    // Base classes, not for developer use

    class_<btCollisionShape, boost::noncopyable>
        ("btCollisionShape", no_init)
        .def_readonly("polyhedral", &btCollisionShape::isPolyhedral)
        .def_readonly("convex2d", &btCollisionShape::isConvex2d)
        .def_readonly("convex", &btCollisionShape::isConvex)
        .def_readonly("non_moving", &btCollisionShape::isNonMoving)
        .def_readonly("concave", &btCollisionShape::isConcave)
        .def_readonly("compound", &btCollisionShape::isCompound)
        .def_readonly("soft_body", &btCollisionShape::isSoftBody)
        .def_readonly("infinite", &btCollisionShape::isInfinite)
        .def_readonly("shape_type", &btCollisionShape::getShapeType)
        .add_property("margin", &btCollisionShape::getMargin,
                      &btCollisionShape::setMargin)
        .def("get_aabb", &btCollisionShape::getAabb)
        .def_readonly("aabb", &btCollisionShape::getAabb)
        .def("get_bounding_sphere", &btCollisionShape::getBoundingSphere)
        .def_readonly("angular_motion_disc",
                      &btCollisionShape::getAngularMotionDisc)
        .def("get_contact_breaking_threshold",
             &btCollisionShape::getContactBreakingThreshold)
        .def("calculate_temporal_aabb",
             &btCollisionShape::calculateTemporalAabb)
        .add_property("local_scaling",
                      make_function(&btCollisionShape::getLocalScaling,
                                    return_value_policy<copy_const_reference>()),
                      &btCollisionShape::setLocalScaling)
        .def("calculate_local_inertia", &btCollisionShape::calculateLocalInertia)
        .def("anisotropic_rolling_friction_direction",
             &btCollisionShape::getAnisotropicRollingFrictionDirection)
    ;

    class_<btConvexShape, bases<btCollisionShape>, boost::noncopyable>
        ("btConvexShape", no_init)
        .def("local_get_supporting_vertex",
             &btConvexShape::localGetSupportingVertexWithoutMargin)
        .def("local_get_supporting_vertex_without_margin_non_virtual",
             &btConvexShape::localGetSupportVertexWithoutMarginNonVirtual)
        .def("local_get_support_vertex_non_virtual",
             &btConvexShape::localGetSupportVertexNonVirtual)
        .def("get_margin_non_virtual",
             &btConvexShape::getMarginNonVirtual)
        .def("get_aabb_non_virtual",
             &btConvexShape::getAabbNonVirtual)
        .def("project", &btConvexShape::project)
        .def("batched_unit_vector_get_supporting_vertex_without_margin",
             &btConvexShape::batchedUnitVectorGetSupportingVertexWithoutMargin)
        .def("get_aabb_slow",
             &btConvexShape::getAabbSlow)
    ;

    class_<btConvexInternalShape, bases<btConvexShape>, boost::noncopyable>
        ("btConvexInternalShape", no_init)
        .add_property("implicit_shape_dimensions",
                      make_function(&btConvexInternalShape::getImplicitShapeDimensions,
                                    return_value_policy<copy_const_reference>()),
                      &btConvexInternalShape::setImplicitShapeDimensions)
        // TODO: wrap setSafeMargin overloads
        .def_readonly("local_scaling_non_virtual",
                      make_function(&btConvexInternalShape::getLocalScalingNV,
                                    return_value_policy<copy_const_reference>()))
        .def_readonly("margin_non_virtual",
                      make_function(&btConvexInternalShape::getMarginNV,
                                    return_value_policy<return_by_value>()))
        .def_readonly("num_preferred_penetration_directions",
                      &btConvexInternalShape::getNumPreferredPenetrationDirections)
        .def("get_preferred_penetration_direction",
             &btConvexInternalShape::getPreferredPenetrationDirection)
    ;

    class_<btPolyhedralConvexShape, bases<btConvexInternalShape>,
           boost::noncopyable>
        ("btPolyhedralConvexShape", no_init)
        .def_readonly("num_vertices", &btPolyhedralConvexShape::getNumVertices)
        .def_readonly("num_edges", &btPolyhedralConvexShape::getNumEdges)
        .def("get_edge", &btPolyhedralConvexShape::getEdge)
        .def("get_vertex", &btPolyhedralConvexShape::getVertex)
        .def_readonly("num_planes", &btPolyhedralConvexShape::getNumPlanes)
        .def("get_plane", &btPolyhedralConvexShape::getPlane)
        .def_readonly("is_inside", &btPolyhedralConvexShape::isInside)
    ;

    class_<btPolyhedralConvexAabbCachingShape, bases<btPolyhedralConvexShape>,
           boost::noncopyable>
        ("btPolyhedralConvexAabbCachingShape", no_init)
        .def("get_nonvirtual_aabb",
             &btPolyhedralConvexAabbCachingShape::getNonvirtualAabb)
        .def("recalc_local_aabb",
             &btPolyhedralConvexAabbCachingShape::getAabb)
    ;

    class_<btConcaveShape, bases<btCollisionShape>, boost::noncopyable>
        ("btConcaveShape", no_init)
    ;

    class_<btTriangleMeshShape, bases<btConcaveShape>, boost::noncopyable>
        ("btTriangleMeshShape", no_init)
    ;

    // End base classes

    // TODO: Add tests
    class_<btConvexHullShape, bases<btPolyhedralConvexAabbCachingShape> >
        ("btConvexHullShape")
        .def("add_point", &btConvexHullShape::addPoint,
             chullshape_addPoint_overloads())
        .def("get_unscaled_points",
             &btConvexHullShape::getUnscaledPoints_wrap,
             return_internal_reference<>())
        .def("get_scaled_point", &btConvexHullShape::getScaledPoint)
        .def("get_num_points", &btConvexHullShape::getNumPoints)
    ;

    // TODO: Add tests
    class_<btBox2dShape, bases<btPolyhedralConvexShape> >
        ("btBox2dShape", init<const btVector3&>())
        .def_readonly("half_extents_with_margin",
                      make_function(&btBox2dShape::getHalfExtentsWithMargin,
                                    return_value_policy<return_by_value>()))
        .def_readonly("half_extents_without_margin",
                      make_function(&btBox2dShape::getHalfExtentsWithoutMargin,
                                    return_internal_reference<>()))
    ;

    // TODO: Add tests
    class_<btBoxShape, bases<btPolyhedralConvexShape> >
        ("btBoxShape", init<const btVector3&>())
        .def_readonly("half_extents_with_margin",
                      make_function(&btBoxShape::getHalfExtentsWithMargin,
                                    return_value_policy<return_by_value>()))
        .def_readonly("half_extents_without_margin",
                      make_function(&btBoxShape::getHalfExtentsWithoutMargin,
                                    return_internal_reference<>()))
    ;

    class_<btBvhTriangleMeshShape, bases<btTriangleMeshShape>, boost::noncopyable>
        ("btBvhTriangleMeshShape", no_init)
    ; // TODO: Implement - left empty while deciding whether to define and wrap btStridingMeshInterface

}

#endif // _btBoostDynamicsShapes_hpp
<|endoftext|>


<commit_before>#include "chainerx/native/native_device.h"

#include <cmath>
#include <cstdint>
#include <type_traits>

#ifdef CHAINERX_ENABLE_BLAS
#include <cblas.h>
#endif  // CHAINERX_ENABLE_BLAS

#include "chainerx/array.h"
#include "chainerx/backend.h"
#include "chainerx/device.h"
#include "chainerx/dtype.h"
#include "chainerx/indexable_array.h"
#include "chainerx/kernels/creation.h"
#include "chainerx/kernels/linalg.h"
#include "chainerx/macro.h"
#include "chainerx/native/data_type.h"
#include "chainerx/native/elementwise.h"
#include "chainerx/native/kernel_regist.h"
#include "chainerx/routines/creation.h"
#include "chainerx/shape.h"

namespace chainerx {
namespace native {

#ifdef CHAINERX_ENABLE_BLAS
namespace {

// Dispatch gemm routines based on the element type T
template <typename T>
struct GemmImpl;

template <>
struct GemmImpl<float> {
    template <typename... Args>
    void operator()(Args&&... args) const {
        cblas_sgemm(std::forward<Args>(args)...);
    }
};

template <>
struct GemmImpl<double> {
    template <typename... Args>
    void operator()(Args&&... args) const {
        cblas_dgemm(std::forward<Args>(args)...);
    }
};

struct GemmInputLayout {
    int64_t ld = 0;
    CBLAS_TRANSPOSE trans = CblasNoTrans;

    // Configure leading dimension and transposition accordingly, and makes the array C contiguous if necessary
    Array Configure(const Array& a) {
        CHAINERX_ASSERT(a.ndim() == 2);
        // Row-major
        // Note that this condition is slightly relaxed than Array::IsContiguous() which requires
        // a.strides()[0] == a.GetItemSize() * a.shape()[1]
        if (a.strides()[1] == a.GetItemSize() && a.strides()[0] / a.GetItemSize() >= a.shape()[1] &&
            a.strides()[0] % a.GetItemSize() == 0) {
            ld = a.strides()[0] / a.GetItemSize();
            return a;
        }
        // Column-major
        if (a.strides()[0] == a.GetItemSize() && a.strides()[1] / a.GetItemSize() >= a.shape()[0] &&
            a.strides()[1] % a.GetItemSize() == 0) {
            ld = a.strides()[1] / a.GetItemSize();
            trans = CblasTrans;
            return a;
        }
        // Force row-major contiguous
        ld = a.shape()[1];
        return AsContiguous(a);
    }
};

void Gemm(const Array& a, const Array& b, const Array& out) {
    CHAINERX_ASSERT(a.ndim() == 2);
    CHAINERX_ASSERT(b.ndim() == 2);
    CHAINERX_ASSERT(out.ndim() == 2);
    CHAINERX_ASSERT(out.dtype() == Dtype::kFloat32 || out.dtype() == Dtype::kFloat64);

    int64_t m = a.shape()[0];
    int64_t k = a.shape()[1];
    int64_t n = b.shape()[1];
    CHAINERX_ASSERT(b.shape()[0] == k);
    CHAINERX_ASSERT(out.shape()[0] == m);
    CHAINERX_ASSERT(out.shape()[1] == n);

    bool is_out_contiguous = out.IsContiguous();
    Array out_contiguous = is_out_contiguous ? out : EmptyLike(out, out.device());

    auto gemm_impl = [&](auto pt) {
        using T = typename decltype(pt)::type;

        GemmInputLayout a_layout;
        GemmInputLayout b_layout;
        Array a_config = a_layout.Configure(a);
        Array b_config = b_layout.Configure(b);

        const T one = 1;
        const T zero = 0;
        const T* a_ptr = static_cast<const T*>(internal::GetRawOffsetData(a_config));
        const T* b_ptr = static_cast<const T*>(internal::GetRawOffsetData(b_config));
        T* out_ptr = static_cast<T*>(internal::GetRawOffsetData(out_contiguous));
        GemmImpl<T>{}(
                CblasRowMajor, a_layout.trans, b_layout.trans, m, n, k, one, a_ptr, a_layout.ld, b_ptr, b_layout.ld, zero, out_ptr, n);
    };

    if (a.dtype() == Dtype::kFloat32) {
        gemm_impl(PrimitiveType<float>{});
    } else {
        CHAINERX_ASSERT(a.dtype() == Dtype::kFloat64);
        gemm_impl(PrimitiveType<double>{});
    }

    if (!is_out_contiguous) {
        out.device().backend().CallKernel<CopyKernel>(out_contiguous, out);
    }
}

}  // namespace
#endif  // CHAINERX_ENABLE_BLAS

namespace {

template <typename T>
T MultiplyAdd(T x, T y, T z) {
    return x * y + z;
}

bool MultiplyAdd(bool x, bool y, bool z) { return (x && y) || z; }

float MultiplyAdd(Float16 x, Float16 y, float z) { return std::fmaf(static_cast<float>(x), static_cast<float>(y), z); }

float MultiplyAdd(float x, float y, float z) { return std::fmaf(x, y, z); }

double MultiplyAdd(double x, double y, double z) { return std::fma(x, y, z); }

}  // namespace

class NativeDotKernel : public DotKernel {
public:
    void Call(const Array& a, const Array& b, const Array& out) override {
        Device& device = a.device();
        device.CheckDevicesCompatible(a, b, out);

        // TODO(sonots): Support ndim >= 2
        if (a.ndim() != 2 || b.ndim() != 2 || out.ndim() != 2) {
            throw DimensionError{"ChainerX dot supports only 2-dimensional arrays."};
        }

#ifdef CHAINERX_ENABLE_BLAS
        if (out.dtype() == Dtype::kFloat32 || out.dtype() == Dtype::kFloat64) {
            Gemm(a.dtype() == out.dtype() ? a : a.AsType(out.dtype()), b.dtype() == out.dtype() ? b : b.AsType(out.dtype()), out);
            return;
        }

        if (out.dtype() == Dtype::kFloat16) {
            Array a32 = a.AsType(Dtype::kFloat32, false);
            Array b32 = b.AsType(Dtype::kFloat32, false);
            Array acc = out.AsType(Dtype::kFloat32);
            Gemm(a32, b32, acc);

            // TODO(gwtnb): Replace Fill(0) and += with CopyTo when CopyTo is added
            out.Fill(0);
            out += acc.AsType(Dtype::kFloat16);
            return;
        }
#endif  // CHAINERX_ENABLE_BLAS

        const Array& a_cast = a.dtype() == out.dtype() ? a : a.AsType(out.dtype());
        const Array& b_cast = b.dtype() == out.dtype() ? b : b.AsType(out.dtype());

        out.Fill(0);
        VisitDtype(out.dtype(), [&](auto pt) {
            CHAINERX_ASSERT(a_cast.dtype() == out.dtype());
            CHAINERX_ASSERT(b_cast.dtype() == out.dtype());

            using T = typename decltype(pt)::type;

            IndexableArray<const T, 2> a_cast_iarray{a_cast};
            IndexableArray<const T, 2> b_cast_iarray{b_cast};
            IndexableArray<T, 2> out_iarray{out};

            int64_t m = a_cast.shape()[0];
            int64_t k = a_cast.shape()[1];
            int64_t n = b_cast.shape()[1];
            CHAINERX_ASSERT(b_cast.shape()[0] == k);
            CHAINERX_ASSERT(out.shape()[0] == m);
            CHAINERX_ASSERT(out.shape()[1] == n);

            using AccT = std::conditional_t<std::is_same<T, Float16>{}, float, T>;
            constexpr auto acc_dtype = PrimitiveType<AccT>::kDtype;

            Array acc = out.AsType(acc_dtype, false);
            IndexableArray<AccT, 2> acc_iarray{acc};
            for (int64_t i = 0; i < m; ++i) {
                for (int64_t l = 0; l < k; ++l) {
                    int64_t a_i_l[] = {i, l};
                    T a_value = native_internal::StorageToDataType<const T>(a_cast_iarray[a_i_l]);
                    for (int64_t j = 0; j < n; ++j) {
                        int64_t acc_i_j[] = {i, j};
                        int64_t b_l_j[] = {l, j};
                        T b_value = native_internal::StorageToDataType<const T>(b_cast_iarray[b_l_j]);
                        AccT& acc_value = native_internal::StorageToDataType<AccT>(acc_iarray[acc_i_j]);
                        acc_value = MultiplyAdd(a_value, b_value, acc_value);
                    }
                }
            }
            if (!std::is_same<T, AccT>{}) {
                for (int64_t i = 0; i < m; ++i) {
                    for (int64_t j = 0; j < n; ++j) {
                        int64_t i_j[] = {i, j};
                        AccT acc_value = native_internal::StorageToDataType<AccT>(acc_iarray[i_j]);
                        T& out_value = native_internal::StorageToDataType<T>(out_iarray[i_j]);
                        out_value = static_cast<T>(acc_value);
                    }
                }
            }
        });
    }
};

CHAINERX_NATIVE_REGISTER_KERNEL(DotKernel, NativeDotKernel);

}  // namespace native
}  // namespace chainerx
<commit_msg>Fixed error for zero-sized input for native dot kernel<commit_after>#include "chainerx/native/native_device.h"

#include <cmath>
#include <cstdint>
#include <type_traits>

#ifdef CHAINERX_ENABLE_BLAS
#include <cblas.h>
#endif  // CHAINERX_ENABLE_BLAS

#include "chainerx/array.h"
#include "chainerx/backend.h"
#include "chainerx/device.h"
#include "chainerx/dtype.h"
#include "chainerx/indexable_array.h"
#include "chainerx/kernels/creation.h"
#include "chainerx/kernels/linalg.h"
#include "chainerx/macro.h"
#include "chainerx/native/data_type.h"
#include "chainerx/native/elementwise.h"
#include "chainerx/native/kernel_regist.h"
#include "chainerx/routines/creation.h"
#include "chainerx/shape.h"

namespace chainerx {
namespace native {

#ifdef CHAINERX_ENABLE_BLAS
namespace {

// Dispatch gemm routines based on the element type T
template <typename T>
struct GemmImpl;

template <>
struct GemmImpl<float> {
    template <typename... Args>
    void operator()(Args&&... args) const {
        cblas_sgemm(std::forward<Args>(args)...);
    }
};

template <>
struct GemmImpl<double> {
    template <typename... Args>
    void operator()(Args&&... args) const {
        cblas_dgemm(std::forward<Args>(args)...);
    }
};

struct GemmInputLayout {
    int64_t ld = 0;
    CBLAS_TRANSPOSE trans = CblasNoTrans;

    // Configure leading dimension and transposition accordingly, and makes the array C contiguous if necessary
    Array Configure(const Array& a) {
        CHAINERX_ASSERT(a.ndim() == 2);
        // Row-major
        // Note that this condition is slightly relaxed than Array::IsContiguous() which requires
        // a.strides()[0] == a.GetItemSize() * a.shape()[1]
        if (a.strides()[1] == a.GetItemSize() && a.strides()[0] / a.GetItemSize() >= a.shape()[1] &&
            a.strides()[0] % a.GetItemSize() == 0) {
            ld = a.strides()[0] / a.GetItemSize();
            return a;
        }
        // Column-major
        if (a.strides()[0] == a.GetItemSize() && a.strides()[1] / a.GetItemSize() >= a.shape()[0] &&
            a.strides()[1] % a.GetItemSize() == 0) {
            ld = a.strides()[1] / a.GetItemSize();
            trans = CblasTrans;
            return a;
        }
        // Force row-major contiguous
        ld = a.shape()[1];
        return AsContiguous(a);
    }
};

void Gemm(const Array& a, const Array& b, const Array& out) {
    CHAINERX_ASSERT(a.ndim() == 2);
    CHAINERX_ASSERT(b.ndim() == 2);
    CHAINERX_ASSERT(out.ndim() == 2);
    CHAINERX_ASSERT(out.dtype() == Dtype::kFloat32 || out.dtype() == Dtype::kFloat64);

    int64_t m = a.shape()[0];
    int64_t k = a.shape()[1];
    int64_t n = b.shape()[1];
    CHAINERX_ASSERT(b.shape()[0] == k);
    CHAINERX_ASSERT(out.shape()[0] == m);
    CHAINERX_ASSERT(out.shape()[1] == n);

    bool is_out_contiguous = out.IsContiguous();
    Array out_contiguous = is_out_contiguous ? out : EmptyLike(out, out.device());

    auto gemm_impl = [&](auto pt) {
        using T = typename decltype(pt)::type;

        GemmInputLayout a_layout;
        GemmInputLayout b_layout;
        Array a_config = a_layout.Configure(a);
        Array b_config = b_layout.Configure(b);

        const T one = 1;
        const T zero = 0;
        const T* a_ptr = static_cast<const T*>(internal::GetRawOffsetData(a_config));
        const T* b_ptr = static_cast<const T*>(internal::GetRawOffsetData(b_config));
        T* out_ptr = static_cast<T*>(internal::GetRawOffsetData(out_contiguous));
        GemmImpl<T>{}(
                CblasRowMajor, a_layout.trans, b_layout.trans, m, n, k, one, a_ptr, a_layout.ld, b_ptr, b_layout.ld, zero, out_ptr, std::max(int64_t{1}, n));
    };

    if (a.dtype() == Dtype::kFloat32) {
        gemm_impl(PrimitiveType<float>{});
    } else {
        CHAINERX_ASSERT(a.dtype() == Dtype::kFloat64);
        gemm_impl(PrimitiveType<double>{});
    }

    if (!is_out_contiguous) {
        out.device().backend().CallKernel<CopyKernel>(out_contiguous, out);
    }
}

}  // namespace
#endif  // CHAINERX_ENABLE_BLAS

namespace {

template <typename T>
T MultiplyAdd(T x, T y, T z) {
    return x * y + z;
}

bool MultiplyAdd(bool x, bool y, bool z) { return (x && y) || z; }

float MultiplyAdd(Float16 x, Float16 y, float z) { return std::fmaf(static_cast<float>(x), static_cast<float>(y), z); }

float MultiplyAdd(float x, float y, float z) { return std::fmaf(x, y, z); }

double MultiplyAdd(double x, double y, double z) { return std::fma(x, y, z); }

}  // namespace

class NativeDotKernel : public DotKernel {
public:
    void Call(const Array& a, const Array& b, const Array& out) override {
        Device& device = a.device();
        device.CheckDevicesCompatible(a, b, out);

        // TODO(sonots): Support ndim >= 2
        if (a.ndim() != 2 || b.ndim() != 2 || out.ndim() != 2) {
            throw DimensionError{"ChainerX dot supports only 2-dimensional arrays."};
        }

#ifdef CHAINERX_ENABLE_BLAS
        if (out.dtype() == Dtype::kFloat32 || out.dtype() == Dtype::kFloat64) {
            Gemm(a.dtype() == out.dtype() ? a : a.AsType(out.dtype()), b.dtype() == out.dtype() ? b : b.AsType(out.dtype()), out);
            return;
        }

        if (out.dtype() == Dtype::kFloat16) {
            Array a32 = a.AsType(Dtype::kFloat32, false);
            Array b32 = b.AsType(Dtype::kFloat32, false);
            Array acc = out.AsType(Dtype::kFloat32);
            Gemm(a32, b32, acc);

            // TODO(gwtnb): Replace Fill(0) and += with CopyTo when CopyTo is added
            out.Fill(0);
            out += acc.AsType(Dtype::kFloat16);
            return;
        }
#endif  // CHAINERX_ENABLE_BLAS

        const Array& a_cast = a.dtype() == out.dtype() ? a : a.AsType(out.dtype());
        const Array& b_cast = b.dtype() == out.dtype() ? b : b.AsType(out.dtype());

        out.Fill(0);
        VisitDtype(out.dtype(), [&](auto pt) {
            CHAINERX_ASSERT(a_cast.dtype() == out.dtype());
            CHAINERX_ASSERT(b_cast.dtype() == out.dtype());

            using T = typename decltype(pt)::type;

            IndexableArray<const T, 2> a_cast_iarray{a_cast};
            IndexableArray<const T, 2> b_cast_iarray{b_cast};
            IndexableArray<T, 2> out_iarray{out};

            int64_t m = a_cast.shape()[0];
            int64_t k = a_cast.shape()[1];
            int64_t n = b_cast.shape()[1];
            CHAINERX_ASSERT(b_cast.shape()[0] == k);
            CHAINERX_ASSERT(out.shape()[0] == m);
            CHAINERX_ASSERT(out.shape()[1] == n);

            using AccT = std::conditional_t<std::is_same<T, Float16>{}, float, T>;
            constexpr auto acc_dtype = PrimitiveType<AccT>::kDtype;

            Array acc = out.AsType(acc_dtype, false);
            IndexableArray<AccT, 2> acc_iarray{acc};
            for (int64_t i = 0; i < m; ++i) {
                for (int64_t l = 0; l < k; ++l) {
                    int64_t a_i_l[] = {i, l};
                    T a_value = native_internal::StorageToDataType<const T>(a_cast_iarray[a_i_l]);
                    for (int64_t j = 0; j < n; ++j) {
                        int64_t acc_i_j[] = {i, j};
                        int64_t b_l_j[] = {l, j};
                        T b_value = native_internal::StorageToDataType<const T>(b_cast_iarray[b_l_j]);
                        AccT& acc_value = native_internal::StorageToDataType<AccT>(acc_iarray[acc_i_j]);
                        acc_value = MultiplyAdd(a_value, b_value, acc_value);
                    }
                }
            }
            if (!std::is_same<T, AccT>{}) {
                for (int64_t i = 0; i < m; ++i) {
                    for (int64_t j = 0; j < n; ++j) {
                        int64_t i_j[] = {i, j};
                        AccT acc_value = native_internal::StorageToDataType<AccT>(acc_iarray[i_j]);
                        T& out_value = native_internal::StorageToDataType<T>(out_iarray[i_j]);
                        out_value = static_cast<T>(acc_value);
                    }
                }
            }
        });
    }
};

CHAINERX_NATIVE_REGISTER_KERNEL(DotKernel, NativeDotKernel);

}  // namespace native
}  // namespace chainerx
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/bookmarks/bookmark_html_writer.h"

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/platform_file.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_codec.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/common/l10n_util.h"
#include "grit/generated_resources.h"
#include "net/base/escape.h"
#include "net/base/file_stream.h"
#include "net/base/net_errors.h"

namespace bookmark_html_writer {

namespace {

// File header.
const char kHeader[] =
    "<!DOCTYPE NETSCAPE-Bookmark-file-1>\r\n"
    "\r\n"
    "<META HTTP-EQUIV=\"Content-Type\""
    " CONTENT=\"text/html; charset=UTF-8\">\r\n"
    "<TITLE>Bookmarks</TITLE>\r\n"
    "
Bookmarks
\r\n"
    "

\r\n";

// Newline separator.
const char kNewline[] = "\r\n";

// The following are used for bookmarks.

// Start of a bookmark.
const char kBookmarkStart[] = "
";
// End of a bookmark.
const char kBookmarkEnd[] = "";

// The following are used when writing folders.

// Start of a folder.
const char kFolderStart[] = "

";
// After kLastModified when writing a user created folder.
const char kFolderAttributeEnd[] = "\">";
// End of the folder.
const char kFolderEnd[] = "
";
// Start of the children of a folder.
const char kFolderChildren[] = "

";
// End of the children for a folder.
const char kFolderChildrenEnd[] = "

";

// Number of characters to indent by.
const size_t kIndentSize = 4;

// Class responsible for the actual writing.
class Writer : public Task {
 public:
  Writer(Value* bookmarks, const FilePath& path)
      : bookmarks_(bookmarks),
        path_(path) {
  }

  virtual void Run() {
    if (!OpenFile())
      return;

    Value* roots;
    if (!Write(kHeader) ||
        bookmarks_->GetType() != Value::TYPE_DICTIONARY ||
        !static_cast<DictionaryValue*>(bookmarks_.get())->Get(
            BookmarkCodec::kRootsKey, &roots) ||
        roots->GetType() != Value::TYPE_DICTIONARY) {
      NOTREACHED();
      return;
    }

    DictionaryValue* roots_d_value = static_cast<DictionaryValue*>(roots);
    Value* root_folder_value;
    Value* other_folder_value;
    if (!roots_d_value->Get(BookmarkCodec::kRootFolderNameKey,
                            &root_folder_value) ||
        root_folder_value->GetType() != Value::TYPE_DICTIONARY ||
        !roots_d_value->Get(BookmarkCodec::kOtherBookmarFolderNameKey,
                            &other_folder_value) ||
        other_folder_value->GetType() != Value::TYPE_DICTIONARY) {
      NOTREACHED();
      return;  // Invalid type for root folder and/or other folder.
    }

    IncrementIndent();

    if (!WriteNode(*static_cast<DictionaryValue*>(root_folder_value),
                   history::StarredEntry::BOOKMARK_BAR) ||
        !WriteNode(*static_cast<DictionaryValue*>(other_folder_value),
                   history::StarredEntry::OTHER)) {
      return;
    }

    DecrementIndent();

    Write(kFolderChildrenEnd);
    Write(kNewline);
  }

 private:
  // Types of text being written out. The type dictates how the text is
  // escaped.
  enum TextType {
    // The text is the value of an html attribute, eg foo in
    // .
    ATTRIBUTE_VALUE,

    // Actual content, eg foo in
foo
.
    CONTENT
  };

  // Opens the file, returning true on success.
  bool OpenFile() {
    int flags = base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE;
    return (file_stream_.Open(path_, flags) == net::OK);
  }

  // Increments the indent.
  void IncrementIndent() {
    indent_.resize(indent_.size() + kIndentSize, ' ');
  }

  // Decrements the indent.
  void DecrementIndent() {
    DCHECK(!indent_.empty());
    indent_.resize(indent_.size() - kIndentSize, ' ');
  }

  // Writes raw text out returning true on success. This does not escape
  // the text in anyway.
  bool Write(const std::string& text) {
    size_t wrote = file_stream_.Write(text.c_str(), text.length(), NULL);
    bool result = (wrote == text.length());
    DCHECK(result);
    return result;
  }

  // Writes out the text string (as UTF8). The text is escaped based on
  // type.
  bool Write(const std::wstring& text, TextType type) {
    std::string utf8_string;

    switch (type) {
      case ATTRIBUTE_VALUE:
        // Convert " to \"
        if (text.find(L"\"") != std::wstring::npos) {
          string16 replaced_string = WideToUTF16Hack(text);
          ReplaceSubstringsAfterOffset(&replaced_string, 0,
                                       ASCIIToUTF16("\""),
                                       ASCIIToUTF16("\\\""));
          utf8_string = UTF16ToUTF8(replaced_string);
        } else {
          utf8_string = WideToUTF8(text);
        }
        break;

      case CONTENT:
        utf8_string = WideToUTF8(EscapeForHTML(text));
        break;

      default:
        NOTREACHED();
    }

    return Write(utf8_string);
  }

  // Indents the current line.
  bool WriteIndent() {
    return Write(indent_);
  }

  // Converts a time string written to the JSON codec into a time_t string
  // (used by bookmarks.html) and writes it.
  bool WriteTime(const std::wstring& time_string) {
    base::Time time = base::Time::FromInternalValue(
        StringToInt64(WideToUTF16Hack(time_string)));
    return Write(Int64ToString(time.ToTimeT()));
  }

  // Writes the node and all its children, returning true on success.
  bool WriteNode(const DictionaryValue& value,
                 history::StarredEntry::Type folder_type) {
    std::wstring title, date_added_string, type_string;
    if (!value.GetString(BookmarkCodec::kNameKey, &title) ||
        !value.GetString(BookmarkCodec::kDateAddedKey, &date_added_string) ||
        !value.GetString(BookmarkCodec::kTypeKey, &type_string) ||
        (type_string != BookmarkCodec::kTypeURL &&
         type_string != BookmarkCodec::kTypeFolder))  {
      NOTREACHED();
      return false;
    }

    if (type_string == BookmarkCodec::kTypeURL) {
      std::wstring url_string;
      if (!value.GetString(BookmarkCodec::kURLKey, &url_string)) {
        NOTREACHED();
        return false;
      }
      if (!WriteIndent() ||
          !Write(kBookmarkStart) ||
          !Write(url_string, ATTRIBUTE_VALUE) ||
          !Write(kAddDate) ||
          !WriteTime(date_added_string) ||
          !Write(kBookmarkAttributeEnd) ||
          !Write(title, CONTENT) ||
          !Write(kBookmarkEnd) ||
          !Write(kNewline)) {
        return false;
      }
      return true;
    }

    // Folder.
    std::wstring last_modified_date;
    Value* child_values;
    if (!value.GetString(BookmarkCodec::kDateModifiedKey,
                         &last_modified_date) ||
        !value.Get(BookmarkCodec::kChildrenKey, &child_values) ||
        child_values->GetType() != Value::TYPE_LIST) {
      NOTREACHED();
      return false;
    }
    if (folder_type != history::StarredEntry::OTHER) {
      // The other folder name is not written out. This gives the effect of
      // making the contents of the 'other folder' be a sibling to the bookmark
      // bar folder.
      if (!WriteIndent() ||
          !Write(kFolderStart) ||
          !WriteTime(date_added_string) ||
          !Write(kLastModified) ||
          !WriteTime(last_modified_date)) {
        return false;
      }
      if (folder_type == history::StarredEntry::BOOKMARK_BAR) {
        if (!Write(kBookmarkBar))
          return false;
        title = l10n_util::GetString(IDS_BOOMARK_BAR_FOLDER_NAME);
      } else if (!Write(kFolderAttributeEnd)) {
        return false;
      }
      if (!Write(title, CONTENT) ||
          !Write(kFolderEnd) ||
          !Write(kNewline) ||
          !WriteIndent() ||
          !Write(kFolderChildren) ||
          !Write(kNewline)) {
        return false;
      }
      IncrementIndent();
    }

    // Write the children.
    ListValue* children = static_cast<ListValue*>(child_values);
    for (size_t i = 0; i < children->GetSize(); ++i) {
      Value* child_value;
      if (!children->Get(i, &child_value) ||
          child_value->GetType() != Value::TYPE_DICTIONARY) {
        NOTREACHED();
        return false;
      }
      if (!WriteNode(*static_cast<DictionaryValue*>(child_value),
                     history::StarredEntry::USER_GROUP)) {
        return false;
      }
    }
    if (folder_type != history::StarredEntry::OTHER) {
      // Close out the folder.
      DecrementIndent();
      if (!WriteIndent() ||
          !Write(kFolderChildrenEnd) ||
          !Write(kNewline)) {
        return false;
      }
    }
    return true;
  }

  // The BookmarkModel as a Value. This value was generated from the
  // BookmarkCodec.
  scoped_ptr<Value> bookmarks_;

  // Path we're writing to.
  FilePath path_;

  // File we're writing to.
  net::FileStream file_stream_;

  // How much we indent when writing a bookmark/folder. This is modified
  // via IncrementIndent and DecrementIndent.
  std::string indent_;
};

}  // namespace

void WriteBookmarks(MessageLoop* thread,
                    BookmarkModel* model,
                    const std::wstring& path) {
  // BookmarkModel isn't thread safe (nor would we want to lock it down
  // for the duration of the write), as such we make a copy of the
  // BookmarkModel using BookmarkCodec then write from that.
  BookmarkCodec codec;
  scoped_ptr<Writer> writer(new Writer(codec.Encode(model),
                            FilePath::FromWStringHack(path)));
  if (thread)
    thread->PostTask(FROM_HERE, writer.release());
  else
    writer->Run();
}

}  // namespace bookmark_html_writer
<commit_msg>Reverting change 11746 because it broke the unit tests.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/bookmarks/bookmark_html_writer.h"

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/platform_file.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_codec.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/history/history_types.h"
#include "net/base/escape.h"
#include "net/base/file_stream.h"
#include "net/base/net_errors.h"

namespace bookmark_html_writer {

namespace {

// File header.
const char kHeader[] =
    "<!DOCTYPE NETSCAPE-Bookmark-file-1>\r\n"
    "\r\n"
    "<META HTTP-EQUIV=\"Content-Type\""
    " CONTENT=\"text/html; charset=UTF-8\">\r\n"
    "<TITLE>Bookmarks</TITLE>\r\n"
    "
Bookmarks
\r\n"
    "

\r\n";

// Newline separator.
const char kNewline[] = "\r\n";

// The following are used for bookmarks.

// Start of a bookmark.
const char kBookmarkStart[] = "
";
// End of a bookmark.
const char kBookmarkEnd[] = "";

// The following are used when writing folders.

// Start of a folder.
const char kFolderStart[] = "

";
// After kLastModified when writing a user created folder.
const char kFolderAttributeEnd[] = "\">";
// End of the folder.
const char kFolderEnd[] = "
";
// Start of the children of a folder.
const char kFolderChildren[] = "

";
// End of the children for a folder.
const char kFolderChildrenEnd[] = "

";

// Number of characters to indent by.
const size_t kIndentSize = 4;

// Class responsible for the actual writing.
class Writer : public Task {
 public:
  Writer(Value* bookmarks, const FilePath& path)
      : bookmarks_(bookmarks),
        path_(path) {
  }

  virtual void Run() {
    if (!OpenFile())
      return;

    Value* roots;
    if (!Write(kHeader) ||
        bookmarks_->GetType() != Value::TYPE_DICTIONARY ||
        !static_cast<DictionaryValue*>(bookmarks_.get())->Get(
            BookmarkCodec::kRootsKey, &roots) ||
        roots->GetType() != Value::TYPE_DICTIONARY) {
      NOTREACHED();
      return;
    }

    DictionaryValue* roots_d_value = static_cast<DictionaryValue*>(roots);
    Value* root_folder_value;
    Value* other_folder_value;
    if (!roots_d_value->Get(BookmarkCodec::kRootFolderNameKey,
                            &root_folder_value) ||
        root_folder_value->GetType() != Value::TYPE_DICTIONARY ||
        !roots_d_value->Get(BookmarkCodec::kOtherBookmarFolderNameKey,
                            &other_folder_value) ||
        other_folder_value->GetType() != Value::TYPE_DICTIONARY) {
      NOTREACHED();
      return;  // Invalid type for root folder and/or other folder.
    }

    IncrementIndent();

    if (!WriteNode(*static_cast<DictionaryValue*>(root_folder_value),
                   history::StarredEntry::BOOKMARK_BAR) ||
        !WriteNode(*static_cast<DictionaryValue*>(other_folder_value),
                   history::StarredEntry::OTHER)) {
      return;
    }

    DecrementIndent();

    Write(kFolderChildrenEnd);
    Write(kNewline);
  }

 private:
  // Types of text being written out. The type dictates how the text is
  // escaped.
  enum TextType {
    // The text is the value of an html attribute, eg foo in
    // .
    ATTRIBUTE_VALUE,

    // Actual content, eg foo in
foo
.
    CONTENT
  };

  // Opens the file, returning true on success.
  bool OpenFile() {
    int flags = base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE;
    return (file_stream_.Open(path_, flags) == net::OK);
  }

  // Increments the indent.
  void IncrementIndent() {
    indent_.resize(indent_.size() + kIndentSize, ' ');
  }

  // Decrements the indent.
  void DecrementIndent() {
    DCHECK(!indent_.empty());
    indent_.resize(indent_.size() - kIndentSize, ' ');
  }

  // Writes raw text out returning true on success. This does not escape
  // the text in anyway.
  bool Write(const std::string& text) {
    size_t wrote = file_stream_.Write(text.c_str(), text.length(), NULL);
    bool result = (wrote == text.length());
    DCHECK(result);
    return result;
  }

  // Writes out the text string (as UTF8). The text is escaped based on
  // type.
  bool Write(const std::wstring& text, TextType type) {
    std::string utf8_string;

    switch (type) {
      case ATTRIBUTE_VALUE:
        // Convert " to \"
        if (text.find(L"\"") != std::wstring::npos) {
          string16 replaced_string = WideToUTF16Hack(text);
          ReplaceSubstringsAfterOffset(&replaced_string, 0,
                                       ASCIIToUTF16("\""),
                                       ASCIIToUTF16("\\\""));
          utf8_string = UTF16ToUTF8(replaced_string);
        } else {
          utf8_string = WideToUTF8(text);
        }
        break;

      case CONTENT:
        utf8_string = WideToUTF8(EscapeForHTML(text));
        break;

      default:
        NOTREACHED();
    }

    return Write(utf8_string);
  }

  // Indents the current line.
  bool WriteIndent() {
    return Write(indent_);
  }

  // Converts a time string written to the JSON codec into a time_t string
  // (used by bookmarks.html) and writes it.
  bool WriteTime(const std::wstring& time_string) {
    base::Time time = base::Time::FromInternalValue(
        StringToInt64(WideToUTF16Hack(time_string)));
    return Write(Int64ToString(time.ToTimeT()));
  }

  // Writes the node and all its children, returning true on success.
  bool WriteNode(const DictionaryValue& value,
                 history::StarredEntry::Type folder_type) {
    std::wstring title, date_added_string, type_string;
    if (!value.GetString(BookmarkCodec::kNameKey, &title) ||
        !value.GetString(BookmarkCodec::kDateAddedKey, &date_added_string) ||
        !value.GetString(BookmarkCodec::kTypeKey, &type_string) ||
        (type_string != BookmarkCodec::kTypeURL &&
         type_string != BookmarkCodec::kTypeFolder))  {
      NOTREACHED();
      return false;
    }

    if (type_string == BookmarkCodec::kTypeURL) {
      std::wstring url_string;
      if (!value.GetString(BookmarkCodec::kURLKey, &url_string)) {
        NOTREACHED();
        return false;
      }
      if (!WriteIndent() ||
          !Write(kBookmarkStart) ||
          !Write(url_string, ATTRIBUTE_VALUE) ||
          !Write(kAddDate) ||
          !WriteTime(date_added_string) ||
          !Write(kBookmarkAttributeEnd) ||
          !Write(title, CONTENT) ||
          !Write(kBookmarkEnd) ||
          !Write(kNewline)) {
        return false;
      }
      return true;
    }

    // Folder.
    std::wstring last_modified_date;
    Value* child_values;
    if (!value.GetString(BookmarkCodec::kDateModifiedKey,
                         &last_modified_date) ||
        !value.Get(BookmarkCodec::kChildrenKey, &child_values) ||
        child_values->GetType() != Value::TYPE_LIST) {
      NOTREACHED();
      return false;
    }
    if (folder_type != history::StarredEntry::OTHER) {
      // The other folder name is not written out. This gives the effect of
      // making the contents of the 'other folder' be a sibling to the bookmark
      // bar folder.
      if (!WriteIndent() ||
          !Write(kFolderStart) ||
          !WriteTime(date_added_string) ||
          !Write(kLastModified) ||
          !WriteTime(last_modified_date)) {
        return false;
      }
      if (folder_type == history::StarredEntry::BOOKMARK_BAR) {
        if (!Write(kBookmarkBar))
          return false;
        title = L"Bookmark Bar";
      } else if (!Write(kFolderAttributeEnd)) {
        return false;
      }
      if (!Write(title, CONTENT) ||
          !Write(kFolderEnd) ||
          !Write(kNewline) ||
          !WriteIndent() ||
          !Write(kFolderChildren) ||
          !Write(kNewline)) {
        return false;
      }
      IncrementIndent();
    }

    // Write the children.
    ListValue* children = static_cast<ListValue*>(child_values);
    for (size_t i = 0; i < children->GetSize(); ++i) {
      Value* child_value;
      if (!children->Get(i, &child_value) ||
          child_value->GetType() != Value::TYPE_DICTIONARY) {
        NOTREACHED();
        return false;
      }
      if (!WriteNode(*static_cast<DictionaryValue*>(child_value),
                     history::StarredEntry::USER_GROUP)) {
        return false;
      }
    }
    if (folder_type != history::StarredEntry::OTHER) {
      // Close out the folder.
      DecrementIndent();
      if (!WriteIndent() ||
          !Write(kFolderChildrenEnd) ||
          !Write(kNewline)) {
        return false;
      }
    }
    return true;
  }

  // The BookmarkModel as a Value. This value was generated from the
  // BookmarkCodec.
  scoped_ptr<Value> bookmarks_;

  // Path we're writing to.
  FilePath path_;

  // File we're writing to.
  net::FileStream file_stream_;

  // How much we indent when writing a bookmark/folder. This is modified
  // via IncrementIndent and DecrementIndent.
  std::string indent_;
};

}  // namespace

void WriteBookmarks(MessageLoop* thread,
                    BookmarkModel* model,
                    const std::wstring& path) {
  // BookmarkModel isn't thread safe (nor would we want to lock it down
  // for the duration of the write), as such we make a copy of the
  // BookmarkModel using BookmarkCodec then write from that.
  BookmarkCodec codec;
  scoped_ptr<Writer> writer(new Writer(codec.Encode(model),
                            FilePath::FromWStringHack(path)));
  if (thread)
    thread->PostTask(FROM_HERE, writer.release());
  else
    writer->Run();
}

}  // namespace bookmark_html_writer
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/login/owner_key_utils.h"

#include <keyhi.h>     // SECKEY_CreateSubjectPublicKeyInfo()
#include <pk11pub.h>
#include <prerror.h>   // PR_GetError()
#include <secder.h>    // DER_Encode()
#include <secmod.h>

#include <limits>

#include "base/crypto/rsa_private_key.h"
#include "base/crypto/signature_creator.h"
#include "base/crypto/signature_verifier.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/nss_util.h"
#include "base/nss_util_internal.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/login_library.h"
#include "chrome/common/extensions/extension_constants.h"

using base::RSAPrivateKey;
using extension_misc::kSignatureAlgorithm;

namespace chromeos {

///////////////////////////////////////////////////////////////////////////
// OwnerKeyUtils

// static
OwnerKeyUtils::Factory* OwnerKeyUtils::factory_ = NULL;

OwnerKeyUtils::OwnerKeyUtils() {}

OwnerKeyUtils::~OwnerKeyUtils() {}

///////////////////////////////////////////////////////////////////////////
// OwnerKeyUtilsImpl

class OwnerKeyUtilsImpl : public OwnerKeyUtils {
 public:
  OwnerKeyUtilsImpl();

  RSAPrivateKey* GenerateKeyPair();

  bool ExportPublicKeyViaDbus(RSAPrivateKey* pair,
                              LoginLibrary::Delegate* d);

  bool ExportPublicKeyToFile(RSAPrivateKey* pair, const FilePath& key_file);

  bool ImportPublicKey(const FilePath& key_file,
                       std::vector<uint8>* output);

  bool Verify(const std::string& data,
              const std::vector<uint8> signature,
              const std::vector<uint8> public_key);

  bool Sign(const std::string& data,
            std::vector<uint8>* OUT_signature,
            base::RSAPrivateKey* key);

  RSAPrivateKey* FindPrivateKey(const std::vector<uint8>& key);

  FilePath GetOwnerKeyFilePath();

 protected:
  virtual ~OwnerKeyUtilsImpl();

 private:
  // The file outside the owner's encrypted home directory where her
  // key will live.
  static const char kOwnerKeyFile[];

  // Key generation parameters.
  static const uint16 kKeySizeInBits;

  DISALLOW_COPY_AND_ASSIGN(OwnerKeyUtilsImpl);
};

// Defined here, instead of up above, because we need OwnerKeyUtilsImpl.
OwnerKeyUtils* OwnerKeyUtils::Create() {
  if (!factory_)
    return new OwnerKeyUtilsImpl();
  else
    return factory_->CreateOwnerKeyUtils();
}

// static
const char OwnerKeyUtilsImpl::kOwnerKeyFile[] = "/var/lib/whitelist/owner.key";

// We're generating and using 2048-bit RSA keys.
// static
const uint16 OwnerKeyUtilsImpl::kKeySizeInBits = 2048;

OwnerKeyUtilsImpl::OwnerKeyUtilsImpl() {
  // Ensure NSS is initialized.
  base::EnsureNSSInit();
}

OwnerKeyUtilsImpl::~OwnerKeyUtilsImpl() {}

RSAPrivateKey* OwnerKeyUtilsImpl::GenerateKeyPair() {
  return RSAPrivateKey::CreateSensitive(kKeySizeInBits);
}

bool OwnerKeyUtilsImpl::ExportPublicKeyViaDbus(RSAPrivateKey* pair,
                                               LoginLibrary::Delegate* d) {
  DCHECK(pair);
  bool ok = false;

  std::vector<uint8> to_export;
  if (!pair->ExportPublicKey(&to_export)) {
    LOG(ERROR) << "Formatting key for export via dbus failed!";
    return false;
  }

  if (CrosLibrary::Get()->EnsureLoaded())
    ok = CrosLibrary::Get()->GetLoginLibrary()->SetOwnerKeyAsync(to_export, d);

  return ok;
}

bool OwnerKeyUtilsImpl::ExportPublicKeyToFile(RSAPrivateKey* pair,
                                              const FilePath& key_file) {
  DCHECK(pair);
  bool ok = false;
  int safe_file_size = 0;

  std::vector<uint8> to_export;
  if (!pair->ExportPublicKey(&to_export)) {
    LOG(ERROR) << "Formatting key for export failed!";
    return false;
  }

  if (to_export.size() > static_cast<uint>(INT_MAX)) {
    LOG(ERROR) << "key is too big! " << to_export.size();
  } else {
    safe_file_size = static_cast<int>(to_export.size());

    ok = (safe_file_size ==
          file_util::WriteFile(key_file,
                               reinterpret_cast<char*>(&to_export.front()),
                               safe_file_size));
  }
  return ok;
}

bool OwnerKeyUtilsImpl::ImportPublicKey(const FilePath& key_file,
                                        std::vector<uint8>* output) {
  // Get the file size (must fit in a 32 bit int for NSS).
  int64 file_size;
  if (!file_util::GetFileSize(key_file, &file_size)) {
    LOG(ERROR) << "Could not get size of " << key_file.value();
    return false;
  }
  if (file_size > static_cast<int64>(std::numeric_limits<int>::max())) {
    LOG(ERROR) << key_file.value() << "is "
               << file_size << "bytes!!!  Too big!";
    return false;
  }
  int32 safe_file_size = static_cast<int32>(file_size);

  output->resize(safe_file_size);
  // Get the key data off of disk
  int data_read = file_util::ReadFile(key_file,
                                      reinterpret_cast<char*>(&(output->at(0))),
                                      safe_file_size);
  return data_read == safe_file_size;
}

bool OwnerKeyUtilsImpl::Verify(const std::string& data,
                               const std::vector<uint8> signature,
                               const std::vector<uint8> public_key) {
  base::SignatureVerifier verifier;
  if (!verifier.VerifyInit(kSignatureAlgorithm, sizeof(kSignatureAlgorithm),
                           &signature[0], signature.size(),
                           &public_key[0], public_key.size())) {
    return false;
  }

  verifier.VerifyUpdate(reinterpret_cast<const uint8*>(data.c_str()),
                        data.length());
  return (verifier.VerifyFinal());
}

bool OwnerKeyUtilsImpl::Sign(const std::string& data,
                             std::vector<uint8>* OUT_signature,
                             base::RSAPrivateKey* key) {
  scoped_ptr<base::SignatureCreator> signer(
      base::SignatureCreator::Create(key));
  if (!signer->Update(reinterpret_cast<const uint8*>(data.c_str()),
                      data.length())) {
    return false;
  }
  return signer->Final(OUT_signature);
}

RSAPrivateKey* OwnerKeyUtilsImpl::FindPrivateKey(
    const std::vector<uint8>& key) {
  return RSAPrivateKey::FindFromPublicKeyInfo(key);
}

FilePath OwnerKeyUtilsImpl::GetOwnerKeyFilePath() {
  return FilePath(OwnerKeyUtilsImpl::kOwnerKeyFile);
}

}  // namespace chromeos
<commit_msg>Remove unneeded NSS headers and the base::EnsureNSSInit() call.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/login/owner_key_utils.h"

#include <limits>

#include "base/crypto/rsa_private_key.h"
#include "base/crypto/signature_creator.h"
#include "base/crypto/signature_verifier.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/login_library.h"
#include "chrome/common/extensions/extension_constants.h"

using base::RSAPrivateKey;
using extension_misc::kSignatureAlgorithm;

namespace chromeos {

///////////////////////////////////////////////////////////////////////////
// OwnerKeyUtils

// static
OwnerKeyUtils::Factory* OwnerKeyUtils::factory_ = NULL;

OwnerKeyUtils::OwnerKeyUtils() {}

OwnerKeyUtils::~OwnerKeyUtils() {}

///////////////////////////////////////////////////////////////////////////
// OwnerKeyUtilsImpl

class OwnerKeyUtilsImpl : public OwnerKeyUtils {
 public:
  OwnerKeyUtilsImpl();

  RSAPrivateKey* GenerateKeyPair();

  bool ExportPublicKeyViaDbus(RSAPrivateKey* pair,
                              LoginLibrary::Delegate* d);

  bool ExportPublicKeyToFile(RSAPrivateKey* pair, const FilePath& key_file);

  bool ImportPublicKey(const FilePath& key_file,
                       std::vector<uint8>* output);

  bool Verify(const std::string& data,
              const std::vector<uint8> signature,
              const std::vector<uint8> public_key);

  bool Sign(const std::string& data,
            std::vector<uint8>* OUT_signature,
            base::RSAPrivateKey* key);

  RSAPrivateKey* FindPrivateKey(const std::vector<uint8>& key);

  FilePath GetOwnerKeyFilePath();

 protected:
  virtual ~OwnerKeyUtilsImpl();

 private:
  // The file outside the owner's encrypted home directory where her
  // key will live.
  static const char kOwnerKeyFile[];

  // Key generation parameters.
  static const uint16 kKeySizeInBits;

  DISALLOW_COPY_AND_ASSIGN(OwnerKeyUtilsImpl);
};

// Defined here, instead of up above, because we need OwnerKeyUtilsImpl.
OwnerKeyUtils* OwnerKeyUtils::Create() {
  if (!factory_)
    return new OwnerKeyUtilsImpl();
  else
    return factory_->CreateOwnerKeyUtils();
}

// static
const char OwnerKeyUtilsImpl::kOwnerKeyFile[] = "/var/lib/whitelist/owner.key";

// We're generating and using 2048-bit RSA keys.
// static
const uint16 OwnerKeyUtilsImpl::kKeySizeInBits = 2048;

OwnerKeyUtilsImpl::OwnerKeyUtilsImpl() {}

OwnerKeyUtilsImpl::~OwnerKeyUtilsImpl() {}

RSAPrivateKey* OwnerKeyUtilsImpl::GenerateKeyPair() {
  return RSAPrivateKey::CreateSensitive(kKeySizeInBits);
}

bool OwnerKeyUtilsImpl::ExportPublicKeyViaDbus(RSAPrivateKey* pair,
                                               LoginLibrary::Delegate* d) {
  DCHECK(pair);
  bool ok = false;

  std::vector<uint8> to_export;
  if (!pair->ExportPublicKey(&to_export)) {
    LOG(ERROR) << "Formatting key for export via dbus failed!";
    return false;
  }

  if (CrosLibrary::Get()->EnsureLoaded())
    ok = CrosLibrary::Get()->GetLoginLibrary()->SetOwnerKeyAsync(to_export, d);

  return ok;
}

bool OwnerKeyUtilsImpl::ExportPublicKeyToFile(RSAPrivateKey* pair,
                                              const FilePath& key_file) {
  DCHECK(pair);
  bool ok = false;
  int safe_file_size = 0;

  std::vector<uint8> to_export;
  if (!pair->ExportPublicKey(&to_export)) {
    LOG(ERROR) << "Formatting key for export failed!";
    return false;
  }

  if (to_export.size() > static_cast<uint>(INT_MAX)) {
    LOG(ERROR) << "key is too big! " << to_export.size();
  } else {
    safe_file_size = static_cast<int>(to_export.size());

    ok = (safe_file_size ==
          file_util::WriteFile(key_file,
                               reinterpret_cast<char*>(&to_export.front()),
                               safe_file_size));
  }
  return ok;
}

bool OwnerKeyUtilsImpl::ImportPublicKey(const FilePath& key_file,
                                        std::vector<uint8>* output) {
  // Get the file size (must fit in a 32 bit int for NSS).
  int64 file_size;
  if (!file_util::GetFileSize(key_file, &file_size)) {
    LOG(ERROR) << "Could not get size of " << key_file.value();
    return false;
  }
  if (file_size > static_cast<int64>(std::numeric_limits<int>::max())) {
    LOG(ERROR) << key_file.value() << "is "
               << file_size << "bytes!!!  Too big!";
    return false;
  }
  int32 safe_file_size = static_cast<int32>(file_size);

  output->resize(safe_file_size);
  // Get the key data off of disk
  int data_read = file_util::ReadFile(key_file,
                                      reinterpret_cast<char*>(&(output->at(0))),
                                      safe_file_size);
  return data_read == safe_file_size;
}

bool OwnerKeyUtilsImpl::Verify(const std::string& data,
                               const std::vector<uint8> signature,
                               const std::vector<uint8> public_key) {
  base::SignatureVerifier verifier;
  if (!verifier.VerifyInit(kSignatureAlgorithm, sizeof(kSignatureAlgorithm),
                           &signature[0], signature.size(),
                           &public_key[0], public_key.size())) {
    return false;
  }

  verifier.VerifyUpdate(reinterpret_cast<const uint8*>(data.c_str()),
                        data.length());
  return (verifier.VerifyFinal());
}

bool OwnerKeyUtilsImpl::Sign(const std::string& data,
                             std::vector<uint8>* OUT_signature,
                             base::RSAPrivateKey* key) {
  scoped_ptr<base::SignatureCreator> signer(
      base::SignatureCreator::Create(key));
  if (!signer->Update(reinterpret_cast<const uint8*>(data.c_str()),
                      data.length())) {
    return false;
  }
  return signer->Final(OUT_signature);
}

RSAPrivateKey* OwnerKeyUtilsImpl::FindPrivateKey(
    const std::vector<uint8>& key) {
  return RSAPrivateKey::FindFromPublicKeyInfo(key);
}

FilePath OwnerKeyUtilsImpl::GetOwnerKeyFilePath() {
  return FilePath(OwnerKeyUtilsImpl::kOwnerKeyFile);
}

}  // namespace chromeos
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/debugger/inspectable_tab_proxy.h"

#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/debugger/debugger_remote_service.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/sessions/session_id.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/devtools_messages.h"

// The debugged tab has closed.
void DevToolsClientHostImpl::InspectedTabClosing() {
  TabClosed();
  delete this;
}

// The remote debugger has detached.
void DevToolsClientHostImpl::Close() {
  NotifyCloseListener();
  delete this;
}

void DevToolsClientHostImpl::SendMessageToClient(
    const IPC::Message& msg) {
  IPC_BEGIN_MESSAGE_MAP(DevToolsClientHostImpl, msg)
    IPC_MESSAGE_HANDLER(DevToolsClientMsg_RpcMessage, OnRpcMessage);
    IPC_MESSAGE_UNHANDLED_ERROR()
  IPC_END_MESSAGE_MAP()
}

void DevToolsClientHostImpl::OnRpcMessage(const DevToolsMessageData& data) {
  static const std::string kDebuggerAgentDelegate = "DebuggerAgentDelegate";
  static const std::string kToolsAgentDelegate = "ToolsAgentDelegate";
  static const std::string kDebuggerOutput = "DebuggerOutput";
  static const std::string kFrameNavigate = "FrameNavigate";

  if (data.class_name == kDebuggerAgentDelegate &&
      data.method_name == kDebuggerOutput) {
    DebuggerOutput(data.arguments[0]);
  } else if (data.class_name == kToolsAgentDelegate &&
             data.method_name == kFrameNavigate) {
    FrameNavigate(data.arguments[0]);
  }
}

void DevToolsClientHostImpl::DebuggerOutput(const std::string& msg) {
  service_->DebuggerOutput(id_, msg);
}

void DevToolsClientHostImpl::FrameNavigate(const std::string& url) {
  service_->FrameNavigate(id_, url);
}

void DevToolsClientHostImpl::TabClosed() {
  service_->TabClosed(id_);
}

const InspectableTabProxy::ControllersMap&
    InspectableTabProxy::controllers_map() {
  controllers_map_.clear();
  for (BrowserList::const_iterator it = BrowserList::begin(),
       end = BrowserList::end(); it != end; ++it) {
    TabStripModel* model = (*it)->tabstrip_model();
    for (int i = 0, size = model->count(); i < size; ++i) {
      NavigationController& controller =
          model->GetTabContentsAt(i)->controller();
      controllers_map_[controller.session_id().id()] = &controller;
    }
  }
  return controllers_map_;
}

DevToolsClientHostImpl* InspectableTabProxy::ClientHostForTabId(
    int32 id) {
  InspectableTabProxy::IdToClientHostMap::const_iterator it =
      id_to_client_host_map_.find(id);
  if (it == id_to_client_host_map_.end()) {
    return NULL;
  }
  return it->second;
}

DevToolsClientHost* InspectableTabProxy::NewClientHost(
    int32 id,
    DebuggerRemoteService* service) {
  DevToolsClientHostImpl* client_host =
      new DevToolsClientHostImpl(id, service, &id_to_client_host_map_);
  id_to_client_host_map_[id] = client_host;
  return client_host;
}

void InspectableTabProxy::OnRemoteDebuggerDetached() {
  while (id_to_client_host_map_.size() > 0) {
    IdToClientHostMap::iterator it = id_to_client_host_map_.begin();
    it->second->debugger_remote_service()->DetachFromTab(IntToString(it->first),
                                                         NULL);
  }
}
<commit_msg>Repair remote debugging<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/debugger/inspectable_tab_proxy.h"

#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/debugger/debugger_remote_service.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/sessions/session_id.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/devtools_messages.h"

// The debugged tab has closed.
void DevToolsClientHostImpl::InspectedTabClosing() {
  TabClosed();
  delete this;
}

// The remote debugger has detached.
void DevToolsClientHostImpl::Close() {
  NotifyCloseListener();
  delete this;
}

void DevToolsClientHostImpl::SendMessageToClient(
    const IPC::Message& msg) {
  IPC_BEGIN_MESSAGE_MAP(DevToolsClientHostImpl, msg)
    IPC_MESSAGE_HANDLER(DevToolsClientMsg_RpcMessage, OnRpcMessage);
    IPC_MESSAGE_UNHANDLED_ERROR()
  IPC_END_MESSAGE_MAP()
}

void DevToolsClientHostImpl::OnRpcMessage(const DevToolsMessageData& data) {
  static const std::string kDebuggerAgentDelegate = "DebuggerAgentDelegate";
  static const std::string kToolsAgentDelegate = "ToolsAgentDelegate";
  static const std::string kDebuggerOutput = "debuggerOutput";
  static const std::string kFrameNavigate = "frameNavigate";

  if (data.class_name == kDebuggerAgentDelegate &&
      data.method_name == kDebuggerOutput) {
    DebuggerOutput(data.arguments[0]);
  } else if (data.class_name == kToolsAgentDelegate &&
             data.method_name == kFrameNavigate) {
    FrameNavigate(data.arguments[0]);
  }
}

void DevToolsClientHostImpl::DebuggerOutput(const std::string& msg) {
  service_->DebuggerOutput(id_, msg);
}

void DevToolsClientHostImpl::FrameNavigate(const std::string& url) {
  service_->FrameNavigate(id_, url);
}

void DevToolsClientHostImpl::TabClosed() {
  service_->TabClosed(id_);
}

const InspectableTabProxy::ControllersMap&
    InspectableTabProxy::controllers_map() {
  controllers_map_.clear();
  for (BrowserList::const_iterator it = BrowserList::begin(),
       end = BrowserList::end(); it != end; ++it) {
    TabStripModel* model = (*it)->tabstrip_model();
    for (int i = 0, size = model->count(); i < size; ++i) {
      NavigationController& controller =
          model->GetTabContentsAt(i)->controller();
      controllers_map_[controller.session_id().id()] = &controller;
    }
  }
  return controllers_map_;
}

DevToolsClientHostImpl* InspectableTabProxy::ClientHostForTabId(
    int32 id) {
  InspectableTabProxy::IdToClientHostMap::const_iterator it =
      id_to_client_host_map_.find(id);
  if (it == id_to_client_host_map_.end()) {
    return NULL;
  }
  return it->second;
}

DevToolsClientHost* InspectableTabProxy::NewClientHost(
    int32 id,
    DebuggerRemoteService* service) {
  DevToolsClientHostImpl* client_host =
      new DevToolsClientHostImpl(id, service, &id_to_client_host_map_);
  id_to_client_host_map_[id] = client_host;
  return client_host;
}

void InspectableTabProxy::OnRemoteDebuggerDetached() {
  while (id_to_client_host_map_.size() > 0) {
    IdToClientHostMap::iterator it = id_to_client_host_map_.begin();
    it->second->debugger_remote_service()->DetachFromTab(IntToString(it->first),
                                                         NULL);
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/convert_user_script.h"

#include <string>
#include <vector>

#include "base/base64.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/scoped_temp_dir.h"
#include "base/sha2.h"
#include "base/string_util.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/user_script.h"
#include "chrome/common/json_value_serializer.h"
#include "googleurl/src/gurl.h"

namespace keys = extension_manifest_keys;

Extension* ConvertUserScriptToExtension(const FilePath& user_script_path,
                                        const GURL& original_url,
                                        std::string* error) {
  std::string content;
  if (!file_util::ReadFileToString(user_script_path, &content)) {
    *error = "Could not read source file: " +
        WideToASCII(user_script_path.ToWStringHack());
    return NULL;
  }

  UserScript script;
  if (!UserScriptMaster::ScriptReloader::ParseMetadataHeader(content,
                                                             &script)) {
    *error = "Invalid script header.";
    return NULL;
  }

  ScopedTempDir temp_dir;
  if (!temp_dir.CreateUniqueTempDir()) {
    *error = "Could not create temporary directory.";
    return NULL;
  }

  // Create the manifest
  scoped_ptr<DictionaryValue> root(new DictionaryValue);
  std::string script_name;
  if (!script.name().empty() && !script.name_space().empty())
    script_name = script.name_space() + "/" + script.name();
  else
    script_name = original_url.spec();

  // Create the public key.
  // User scripts are not signed, but the public key for an extension doubles as
  // its unique identity, and we need one of those. A user script's unique
  // identity is its namespace+name, so we hash that to create a public key.
  // There will be no corresponding private key, which means user scripts cannot
  // be auto-updated, or claimed in the gallery.
  char raw[base::SHA256_LENGTH] = {0};
  std::string key;
  base::SHA256HashString(script_name, raw, base::SHA256_LENGTH);
  base::Base64Encode(std::string(raw, base::SHA256_LENGTH), &key);

  // The script may not have a name field, but we need one for an extension. If
  // it is missing, use the filename of the original URL.
  if (!script.name().empty())
    root->SetString(keys::kName, script.name());
  else
    root->SetString(keys::kName, original_url.ExtractFileName());

  // Not all scripts have a version, but we need one. Default to 1.0 if it is
  // missing.
  if (!script.version().empty())
    root->SetString(keys::kVersion, script.version());
  else
    root->SetString(keys::kVersion, "1.0");

  root->SetString(keys::kDescription, script.description());
  root->SetString(keys::kPublicKey, key);
  root->SetBoolean(keys::kConvertedFromUserScript, true);

  ListValue* js_files = new ListValue();
  js_files->Append(Value::CreateStringValue("script.js"));

  // If the script provides its own match patterns, we use those. Otherwise, we
  // generate some using the include globs.
  ListValue* matches = new ListValue();
  if (!script.url_patterns().empty()) {
    for (size_t i = 0; i < script.url_patterns().size(); ++i) {
      matches->Append(Value::CreateStringValue(
          script.url_patterns()[i].GetAsString()));
    }
  } else {
    // TODO(aa): Derive tighter matches where possible.
    matches->Append(Value::CreateStringValue("http://*/*"));
    matches->Append(Value::CreateStringValue("https://*/*"));
  }

  ListValue* includes = new ListValue();
  for (size_t i = 0; i < script.globs().size(); ++i)
    includes->Append(Value::CreateStringValue(script.globs().at(i)));

  ListValue* excludes = new ListValue();
  for (size_t i = 0; i < script.exclude_globs().size(); ++i)
    excludes->Append(Value::CreateStringValue(script.exclude_globs().at(i)));

  DictionaryValue* content_script = new DictionaryValue();
  content_script->Set(keys::kMatches, matches);
  content_script->Set(keys::kIncludeGlobs, includes);
  content_script->Set(keys::kExcludeGlobs, excludes);
  content_script->Set(keys::kJs, js_files);

  ListValue* content_scripts = new ListValue();
  content_scripts->Append(content_script);

  root->Set(keys::kContentScripts, content_scripts);

  FilePath manifest_path = temp_dir.path().Append(
      Extension::kManifestFilename);
  JSONFileValueSerializer serializer(manifest_path);
  if (!serializer.Serialize(*root)) {
    *error = "Could not write JSON.";
    return NULL;
  }

  // Write the script file.
  if (!file_util::CopyFile(user_script_path,
                           temp_dir.path().AppendASCII("script.js"))) {
    *error = "Could not copy script file.";
    return NULL;
  }

  scoped_ptr<Extension> extension(new Extension(temp_dir.path()));
  if (!extension->InitFromValue(*root, false, error)) {
    NOTREACHED() << "Could not init extension " << *error;
    return NULL;
  }

  temp_dir.Take();  // The caller takes ownership of the directory.
  return extension.release();
}
<commit_msg>Pack content scripts in a temp directory in the profile dir.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/convert_user_script.h"

#include <string>
#include <vector>

#include "base/base64.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
#include "base/sha2.h"
#include "base/string_util.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/user_script.h"
#include "chrome/common/json_value_serializer.h"
#include "googleurl/src/gurl.h"

namespace keys = extension_manifest_keys;

Extension* ConvertUserScriptToExtension(const FilePath& user_script_path,
                                        const GURL& original_url,
                                        std::string* error) {
  std::string content;
  if (!file_util::ReadFileToString(user_script_path, &content)) {
    *error = "Could not read source file: " +
        WideToASCII(user_script_path.ToWStringHack());
    return NULL;
  }

  UserScript script;
  if (!UserScriptMaster::ScriptReloader::ParseMetadataHeader(content,
                                                             &script)) {
    *error = "Invalid script header.";
    return NULL;
  }

  FilePath user_data_temp_dir;
  CHECK(PathService::Get(chrome::DIR_USER_DATA_TEMP, &user_data_temp_dir));

  ScopedTempDir temp_dir;
  if (!temp_dir.CreateUniqueTempDirUnderPath(user_data_temp_dir, false)) {
    *error = "Could not create temporary directory.";
    return NULL;
  }

  // Create the manifest
  scoped_ptr<DictionaryValue> root(new DictionaryValue);
  std::string script_name;
  if (!script.name().empty() && !script.name_space().empty())
    script_name = script.name_space() + "/" + script.name();
  else
    script_name = original_url.spec();

  // Create the public key.
  // User scripts are not signed, but the public key for an extension doubles as
  // its unique identity, and we need one of those. A user script's unique
  // identity is its namespace+name, so we hash that to create a public key.
  // There will be no corresponding private key, which means user scripts cannot
  // be auto-updated, or claimed in the gallery.
  char raw[base::SHA256_LENGTH] = {0};
  std::string key;
  base::SHA256HashString(script_name, raw, base::SHA256_LENGTH);
  base::Base64Encode(std::string(raw, base::SHA256_LENGTH), &key);

  // The script may not have a name field, but we need one for an extension. If
  // it is missing, use the filename of the original URL.
  if (!script.name().empty())
    root->SetString(keys::kName, script.name());
  else
    root->SetString(keys::kName, original_url.ExtractFileName());

  // Not all scripts have a version, but we need one. Default to 1.0 if it is
  // missing.
  if (!script.version().empty())
    root->SetString(keys::kVersion, script.version());
  else
    root->SetString(keys::kVersion, "1.0");

  root->SetString(keys::kDescription, script.description());
  root->SetString(keys::kPublicKey, key);
  root->SetBoolean(keys::kConvertedFromUserScript, true);

  ListValue* js_files = new ListValue();
  js_files->Append(Value::CreateStringValue("script.js"));

  // If the script provides its own match patterns, we use those. Otherwise, we
  // generate some using the include globs.
  ListValue* matches = new ListValue();
  if (!script.url_patterns().empty()) {
    for (size_t i = 0; i < script.url_patterns().size(); ++i) {
      matches->Append(Value::CreateStringValue(
          script.url_patterns()[i].GetAsString()));
    }
  } else {
    // TODO(aa): Derive tighter matches where possible.
    matches->Append(Value::CreateStringValue("http://*/*"));
    matches->Append(Value::CreateStringValue("https://*/*"));
  }

  ListValue* includes = new ListValue();
  for (size_t i = 0; i < script.globs().size(); ++i)
    includes->Append(Value::CreateStringValue(script.globs().at(i)));

  ListValue* excludes = new ListValue();
  for (size_t i = 0; i < script.exclude_globs().size(); ++i)
    excludes->Append(Value::CreateStringValue(script.exclude_globs().at(i)));

  DictionaryValue* content_script = new DictionaryValue();
  content_script->Set(keys::kMatches, matches);
  content_script->Set(keys::kIncludeGlobs, includes);
  content_script->Set(keys::kExcludeGlobs, excludes);
  content_script->Set(keys::kJs, js_files);

  ListValue* content_scripts = new ListValue();
  content_scripts->Append(content_script);

  root->Set(keys::kContentScripts, content_scripts);

  FilePath manifest_path = temp_dir.path().Append(
      Extension::kManifestFilename);
  JSONFileValueSerializer serializer(manifest_path);
  if (!serializer.Serialize(*root)) {
    *error = "Could not write JSON.";
    return NULL;
  }

  // Write the script file.
  if (!file_util::CopyFile(user_script_path,
                           temp_dir.path().AppendASCII("script.js"))) {
    *error = "Could not copy script file.";
    return NULL;
  }

  scoped_ptr<Extension> extension(new Extension(temp_dir.path()));
  if (!extension->InitFromValue(*root, false, error)) {
    NOTREACHED() << "Could not init extension " << *error;
    return NULL;
  }

  temp_dir.Take();  // The caller takes ownership of the directory.
  return extension.release();
}
<|endoftext|>