<commit_before>#define FUSE_USE_VERSION 26

#include "FBGraph.h"
#include "FBQuery.h"
#include "Util.h"

#include <boost/filesystem.hpp>
#include <fuse.h>
#include "json_spirit.h"

#include <cerrno>
#include <ctime>
#include <cstring>
#include <iostream>
#include <memory>
#include <set>
#include <string>
#include <system_error>

static const std::string LOGIN_ERROR = "You are not logged in, so the program cannot fetch your profile. Terminating.";
static const std::string LOGIN_SUCCESS = "You are now logged into Facebook.";
static const std::string PERMISSION_CHECK_ERROR = "Could not determine app permissions.";
static const std::string POST_FILE_NAME = "post";

static inline FBGraph* get_fb_graph() {
    return static_cast<FBGraph*>(fuse_get_context()->private_data);
}

static inline std::string dirname(const std::string &path) {
    boost::filesystem::path p(path);
    return p.parent_path().string();
}

static inline std::string basename(const std::string &path) {
    return boost::filesystem::basename(path);
}

static inline std::set<std::string> get_endpoints() {
    return {
        "albums",
        "friends",
        "status",
    };
}

static inline std::string get_node_from_path(const std::string &path) {
    std::string p(path);
    std::string node;

    if (basename(p) == POST_FILE_NAME) {
        p = dirname(p);
    }

    if (dirname(p) == "/") {
        node = "me";
    } else {
        std::string friend_name = basename(dirname(p));
        node = get_fb_graph()->get_uid_from_name(friend_name);
    }

    return node;
}

static int fbfs_getattr(const char* cpath, struct stat *stbuf) {
    std::string path(cpath);
    std::error_condition result;
    std::memset(stbuf, 0, sizeof(struct stat));

    if (path == "/") {
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 2;
        return 0;
    }

    if (basename(dirname(path)) == "friends") {
        // This is a directory representing a friend
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 2;
        return 0;
    }

    if (basename(path) == POST_FILE_NAME) {
        stbuf->st_mode = S_IFREG | 0200;
        stbuf->st_size = 0;
        return 0;
    }

    std::set<std::string> endpoints = get_endpoints();
    if (endpoints.count(basename(path))) {
        // This is an endpoint
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 2;
    } else if (endpoints.count(basename(dirname(path)))) {
        // This is a file inside an endpoint
        stbuf->st_mode = S_IFREG | 0400;
        if (basename(dirname(path)) == "status") {
            // Store the date in the file
            FBQuery query(basename(path));
            query.add_parameter("date_format", "U");
            query.add_parameter("fields", "message,updated_time");
            json_spirit::mObject status_response = get_fb_graph()->get(query);
            if (status_response.count("error")) {
                result = std::errc::no_such_file_or_directory;
                return -result.value();
            }

            const time_t updated_time = status_response.at("updated_time").get_int();
            timespec time;
            time.tv_sec = updated_time;
            stbuf->st_mtim = time;
            stbuf->st_size = status_response.at("message").get_str().length();
        } else if (basename(dirname(path)) == "albums") {
            // This is an album
            stbuf->st_mode = S_IFDIR | 0755;
            return 0;
        }
    } else {
        result = std::errc::no_such_file_or_directory;
        return -result.value();
    }

    return 0;
}

static int fbfs_readdir(const char *cpath, void *buf, fuse_fill_dir_t filler,
                        off_t offset, struct fuse_file_info *fi) {
    (void)offset;
    (void)fi;

    std::string path(cpath);
    std::error_condition result;

    filler(buf, ".", NULL, 0);
    filler(buf, "..", NULL, 0);

    std::set<std::string> endpoints = get_endpoints();
    std::set<std::string> friends = get_fb_graph()->get_friends();

    if (path == "/" || friends.count(basename(path))) {
        for (auto endpoint : endpoints) {
            filler(buf, endpoint.c_str(), NULL, 0);
        }
    } else if (endpoints.count(basename(path))) {
        // Request the user's friends
        FBQuery query("me", "friends");
        json_spirit::mObject friend_response = get_fb_graph()->get(query);
        json_spirit::mArray friends_list = friend_response.at("data").get_array();

        std::string node = get_node_from_path(path);
        if (basename(path) == "friends") {
            if (dirname(path) == "/") {
                for (auto friend_obj : friends_list) {
                    std::string name = friend_obj.get_obj().at("name").get_str();
                    filler(buf, name.c_str(), NULL, 0);
                }
            } else {
                // We are in a friends directory. We should either make the
                // folder read-only, or a symlink to the user's friends.
                // TODO: Implement
            }
        } else if (basename(path) == "status") {
            FBQuery query(node, "statuses");
            query.add_parameter("date_format", "U");
            query.add_parameter("fields", "updated_time,message,id");
            json_spirit::mObject status_response = get_fb_graph()->get(query);
            json_spirit::mArray statuses = status_response.at("data").get_array();

            if (dirname(path) == "/") {
                filler(buf, POST_FILE_NAME.c_str(), NULL, 0);
            }

            for (auto& status : statuses) {
                if (!status.get_obj().count("message")) {
                    // The status doesn't have a message
                    continue;
                }
                std::string id = status.get_obj().at("id").get_str();
                filler(buf, id.c_str(), NULL, 0);
            }
        } else if (basename(path) == "albums") {
            FBQuery query(node, "albums");
            json_spirit::mObject albums_response = get_fb_graph()->get(query);
            json_spirit::mArray albums = albums_response.at("data").get_array();

            for (auto& album : albums) {
                std::string album_name = album.get_obj().at("name").get_str();
                filler(buf, album_name.c_str(), NULL, 0);
            }
        }
    }

    return 0;
}

static int fbfs_open(const char *cpath, struct fuse_file_info *fi) {
    std::string path(cpath);
    std::error_condition result;

    std::set<std::string> endpoints = get_endpoints();

    std::string parent_folder = basename(dirname(path));

    if (fi->flags & O_RDONLY) {
        result = std::errc::permission_denied;
        return -result.value();
    }

    return 0;
}

static int fbfs_truncate(const char *cpath, off_t size) {
    (void)cpath;
    (void)size;
    return 0;
}

static int fbfs_write(const char *cpath, const char *buf, size_t size,
                      off_t offset, struct fuse_file_info *fi) {
    (void)fi;
    std::error_condition result;
    std::string path(cpath);
    std::set<std::string> endpoints = get_endpoints();

    if (endpoints.count(basename(dirname(path)))) {
        // We are in an endpoint directory, so we are able to write the file
        const char *start = buf + offset;
        std::string data(start, size);
        // Determine which endpoint we are in
        std::string endpoint = basename(dirname(path));

        if (endpoint == "status") {
            // TODO: Allow writes to friend's walls as well. Unfortunately, it
            // is not possible to post directly using the Facebook API.
            // Instead, we will have to open a feed dialog.
            // https://developers.facebook.com/docs/sharing/reference/feed-dialog
            FBQuery query("me", "feed");
            query.add_parameter("message", data);
            json_spirit::mObject response = get_fb_graph()->post(query);
            if (response.count("error")) {
                result = std::errc::operation_not_permitted;
                std::cerr << response.at("error").get_obj().at("message").get_str();
                return -result.value();
            }

            return data.size();
        }
    }

    return 0;
}

static int fbfs_read(const char *cpath, char *buf, size_t size, off_t offset,
                     struct fuse_file_info *fi) {
    (void)fi;
    std::string path(cpath);
    std::error_condition result;

    FBQuery query(basename(path));
    query.add_parameter("fields", "message");
    json_spirit::mObject status_response = get_fb_graph()->get(query);
    std::string message = status_response.at("message").get_str();

    if (static_cast<unsigned>(offset) < message.length()) {
        if (offset + size > message.length()) {
            size = message.length() - offset;
        }

        std::memcpy(buf, message.c_str() + offset, size);
    } else {
        size = 0;
    }

    return size;
}

static void* fbfs_init(struct fuse_conn_info *ci) {
    (void)ci;

    FBGraph *fb_graph = new FBGraph();

    // We will ask for both user and friend variants of these permissions.
    // Refer to https://developers.facebook.com/docs/facebook-login/permissions
    // to see what each permission requests.
    std::vector<std::string> permissions = {
        "status",
    };

    std::vector<std::string> extended_permissions = {
        "publish_actions",
    };

    fb_graph->login(permissions, extended_permissions);

    if (!fb_graph->is_logged_in()) {
        std::cout << LOGIN_ERROR << std::endl;
        std::exit(EXIT_SUCCESS);
    }

    std::cout << LOGIN_SUCCESS << std::endl;
    return fb_graph;
}

static void fbfs_destroy(void *private_data) {
    delete static_cast<FBGraph*>(private_data);
}

static struct fuse_operations fbfs_oper;

void initialize_operations(fuse_operations& operations) {
    std::memset(static_cast<void*>(&operations), 0, sizeof(operations));

    operations.getattr  = fbfs_getattr;
    operations.readdir  = fbfs_readdir;
    operations.open     = fbfs_open;
    operations.read     = fbfs_read;
    operations.init     = fbfs_init;
    operations.destroy  = fbfs_destroy;
    operations.truncate = fbfs_truncate;
    operations.write    = fbfs_write;
}

void call_fusermount() {
    std::system("fusermount -u testdir");
}

int main(int argc, char *argv[]) {
    umask(0);

    std::atexit(call_fusermount);

    initialize_operations(fbfs_oper);
    return fuse_main(argc, argv, &fbfs_oper, NULL);
}
<commit_msg>move error handling into own function<commit_after>#define FUSE_USE_VERSION 26

#include "FBGraph.h"
#include "FBQuery.h"
#include "Util.h"

#include <boost/filesystem.hpp>
#include <fuse.h>
#include "json_spirit.h"

#include <cerrno>
#include <ctime>
#include <cstring>
#include <iostream>
#include <memory>
#include <set>
#include <string>
#include <system_error>

static const std::string LOGIN_ERROR = "You are not logged in, so the program cannot fetch your profile. Terminating.";
static const std::string LOGIN_SUCCESS = "You are now logged into Facebook.";
static const std::string PERMISSION_CHECK_ERROR = "Could not determine app permissions.";
static const std::string POST_FILE_NAME = "post";

static inline FBGraph* get_fb_graph() {
    return static_cast<FBGraph*>(fuse_get_context()->private_data);
}

static inline std::string dirname(const std::string &path) {
    boost::filesystem::path p(path);
    return p.parent_path().string();
}

static inline std::string basename(const std::string &path) {
    return boost::filesystem::basename(path);
}

static inline std::set<std::string> get_endpoints() {
    return {
        "albums",
        "friends",
        "status",
    };
}

static inline std::error_condition handle_error(const json_spirit::mObject response) {
    json_spirit::mObject error = response.at("error").get_obj();
    std::cerr << error.at("message").get_str() << std::endl;
    if (error.at("type").get_str() == "OAuthException") {
        if (error.at("code").get_int() == 803) {
            return std::errc::no_such_file_or_directory;
        }

        return std::errc::permission_denied;
    }

    return std::errc::operation_not_permitted;
}

static inline std::string get_node_from_path(const std::string &path) {
    std::string p(path);
    std::string node;

    if (basename(p) == POST_FILE_NAME) {
        p = dirname(p);
    }

    if (dirname(p) == "/") {
        node = "me";
    } else {
        std::string friend_name = basename(dirname(p));
        node = get_fb_graph()->get_uid_from_name(friend_name);
    }

    return node;
}

static int fbfs_getattr(const char* cpath, struct stat *stbuf) {
    std::string path(cpath);
    std::error_condition result;
    std::memset(stbuf, 0, sizeof(struct stat));

    if (path == "/") {
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 2;
        return 0;
    }

    if (basename(dirname(path)) == "friends") {
        // This is a directory representing a friend
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 2;
        return 0;
    }

    if (basename(path) == POST_FILE_NAME) {
        stbuf->st_mode = S_IFREG | 0200;
        stbuf->st_size = 0;
        return 0;
    }

    std::set<std::string> endpoints = get_endpoints();
    if (endpoints.count(basename(path))) {
        // This is an endpoint
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 2;
    } else if (endpoints.count(basename(dirname(path)))) {
        // This is a file inside an endpoint
        stbuf->st_mode = S_IFREG | 0400;
        if (basename(dirname(path)) == "status") {
            // Store the date in the file
            FBQuery query(basename(path));
            query.add_parameter("date_format", "U");
            query.add_parameter("fields", "message,updated_time");
            json_spirit::mObject status_response = get_fb_graph()->get(query);
            if (status_response.count("error")) {
                result = handle_error(status_response);
                return -result.value();
            }

            const time_t updated_time = status_response.at("updated_time").get_int();
            timespec time;
            time.tv_sec = updated_time;
            stbuf->st_mtim = time;
            stbuf->st_size = status_response.at("message").get_str().length();
        } else if (basename(dirname(path)) == "albums") {
            // This is an album
            stbuf->st_mode = S_IFDIR | 0755;
            return 0;
        }
    } else {
        result = std::errc::no_such_file_or_directory;
        return -result.value();
    }

    return 0;
}

static int fbfs_readdir(const char *cpath, void *buf, fuse_fill_dir_t filler,
                        off_t offset, struct fuse_file_info *fi) {
    (void)offset;
    (void)fi;

    std::string path(cpath);
    std::error_condition result;

    filler(buf, ".", NULL, 0);
    filler(buf, "..", NULL, 0);

    std::set<std::string> endpoints = get_endpoints();
    std::set<std::string> friends = get_fb_graph()->get_friends();

    if (path == "/" || friends.count(basename(path))) {
        for (auto endpoint : endpoints) {
            filler(buf, endpoint.c_str(), NULL, 0);
        }
    } else if (endpoints.count(basename(path))) {
        // Request the user's friends
        FBQuery query("me", "friends");
        json_spirit::mObject friend_response = get_fb_graph()->get(query);
        json_spirit::mArray friends_list = friend_response.at("data").get_array();

        std::string node = get_node_from_path(path);
        if (basename(path) == "friends") {
            if (dirname(path) == "/") {
                for (auto friend_obj : friends_list) {
                    std::string name = friend_obj.get_obj().at("name").get_str();
                    filler(buf, name.c_str(), NULL, 0);
                }
            } else {
                // We are in a friends directory. We should either make the
                // folder read-only, or a symlink to the user's friends.
                // TODO: Implement
            }
        } else if (basename(path) == "status") {
            FBQuery query(node, "statuses");
            query.add_parameter("date_format", "U");
            query.add_parameter("fields", "updated_time,message,id");
            json_spirit::mObject status_response = get_fb_graph()->get(query);
            json_spirit::mArray statuses = status_response.at("data").get_array();

            if (dirname(path) == "/") {
                filler(buf, POST_FILE_NAME.c_str(), NULL, 0);
            }

            for (auto& status : statuses) {
                if (!status.get_obj().count("message")) {
                    // The status doesn't have a message
                    continue;
                }
                std::string id = status.get_obj().at("id").get_str();
                filler(buf, id.c_str(), NULL, 0);
            }
        } else if (basename(path) == "albums") {
            FBQuery query(node, "albums");
            json_spirit::mObject albums_response = get_fb_graph()->get(query);
            json_spirit::mArray albums = albums_response.at("data").get_array();

            for (auto& album : albums) {
                std::string album_name = album.get_obj().at("name").get_str();
                filler(buf, album_name.c_str(), NULL, 0);
            }
        }
    }

    return 0;
}

static int fbfs_open(const char *cpath, struct fuse_file_info *fi) {
    std::string path(cpath);
    std::error_condition result;

    std::set<std::string> endpoints = get_endpoints();

    std::string parent_folder = basename(dirname(path));

    if (fi->flags & O_RDONLY) {
        result = std::errc::permission_denied;
        return -result.value();
    }

    return 0;
}

static int fbfs_truncate(const char *cpath, off_t size) {
    (void)cpath;
    (void)size;
    return 0;
}

static int fbfs_write(const char *cpath, const char *buf, size_t size,
                      off_t offset, struct fuse_file_info *fi) {
    (void)fi;
    std::error_condition result;
    std::string path(cpath);
    std::set<std::string> endpoints = get_endpoints();

    if (endpoints.count(basename(dirname(path)))) {
        // We are in an endpoint directory, so we are able to write the file
        const char *start = buf + offset;
        std::string data(start, size);
        // Determine which endpoint we are in
        std::string endpoint = basename(dirname(path));

        if (endpoint == "status") {
            // TODO: Allow writes to friend's walls as well. Unfortunately, it
            // is not possible to post directly using the Facebook API.
            // Instead, we will have to open a feed dialog.
            // https://developers.facebook.com/docs/sharing/reference/feed-dialog
            FBQuery query("me", "feed");
            query.add_parameter("message", data);
            json_spirit::mObject response = get_fb_graph()->post(query);
            if (response.count("error")) {
                result = handle_error(response);
                return -result.value();
            }

            return data.size();
        }
    }

    return 0;
}

static int fbfs_read(const char *cpath, char *buf, size_t size, off_t offset,
                     struct fuse_file_info *fi) {
    (void)fi;
    std::string path(cpath);
    std::error_condition result;

    FBQuery query(basename(path));
    query.add_parameter("fields", "message");
    json_spirit::mObject status_response = get_fb_graph()->get(query);
    std::string message = status_response.at("message").get_str();

    if (static_cast<unsigned>(offset) < message.length()) {
        if (offset + size > message.length()) {
            size = message.length() - offset;
        }

        std::memcpy(buf, message.c_str() + offset, size);
    } else {
        size = 0;
    }

    return size;
}

static void* fbfs_init(struct fuse_conn_info *ci) {
    (void)ci;

    FBGraph *fb_graph = new FBGraph();

    // We will ask for both user and friend variants of these permissions.
    // Refer to https://developers.facebook.com/docs/facebook-login/permissions
    // to see what each permission requests.
    std::vector<std::string> permissions = {
        "status",
    };

    std::vector<std::string> extended_permissions = {
        "publish_actions",
    };

    fb_graph->login(permissions, extended_permissions);

    if (!fb_graph->is_logged_in()) {
        std::cout << LOGIN_ERROR << std::endl;
        std::exit(EXIT_SUCCESS);
    }

    std::cout << LOGIN_SUCCESS << std::endl;
    return fb_graph;
}

static void fbfs_destroy(void *private_data) {
    delete static_cast<FBGraph*>(private_data);
}

static struct fuse_operations fbfs_oper;

void initialize_operations(fuse_operations& operations) {
    std::memset(static_cast<void*>(&operations), 0, sizeof(operations));

    operations.getattr  = fbfs_getattr;
    operations.readdir  = fbfs_readdir;
    operations.open     = fbfs_open;
    operations.read     = fbfs_read;
    operations.init     = fbfs_init;
    operations.destroy  = fbfs_destroy;
    operations.truncate = fbfs_truncate;
    operations.write    = fbfs_write;
}

void call_fusermount() {
    std::system("fusermount -u testdir");
}

int main(int argc, char *argv[]) {
    umask(0);

    std::atexit(call_fusermount);

    initialize_operations(fbfs_oper);
    return fuse_main(argc, argv, &fbfs_oper, NULL);
}
<|endoftext|>


<commit_before>// -*-c++-*-

/*
 * $Id$
 *
 * DirectX file converter for OpenSceneGraph.
 * Copyright (c)2002 Ulrich Hertlein <u.hertlein@sandbox.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "directx.h"

#include <osg/TexEnv>
#include <osg/CullFace>

#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/Image>
#include <osg/Texture2D>

#include <osg/Notify>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/FileNameUtils>

#include <assert.h>

/**
 * OpenSceneGraph plugin wrapper/converter.
 */
class ReaderWriterDirectX : public osgDB::ReaderWriter
{
public:
    ReaderWriterDirectX() { }

    virtual const char* className() {
        return "DirectX Reader/Writer";
    }

    virtual bool acceptsExtension(const std::string& extension) {
        return osgDB::equalCaseInsensitive(extension,"x") ? true : false;
    }

    virtual ReadResult readNode(const std::string& fileName,
                                const osgDB::ReaderWriter::Options* options);

private:
    osg::Geode* convertFromDX(DX::Object& obj, bool flipTexture, float creaseAngle);
};

// Register with Registry to instantiate the above reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterDirectX> g_readerWriter_DirectX_Proxy;

// Read node
osgDB::ReaderWriter::ReadResult ReaderWriterDirectX::readNode(const std::string& fileName,
                                                              const osgDB::ReaderWriter::Options* options)
{
    std::string ext = osgDB::getLowerCaseFileExtension(fileName);
    if (!acceptsExtension(ext))
        return ReadResult::FILE_NOT_HANDLED;

    osg::notify(osg::INFO) << "ReaderWriterDirectX::readNode(" << fileName.c_str() << ")\n";

    // Load DirectX mesh
    DX::Object obj;
    if (obj.load(fileName.c_str())) {

        // Options?
        bool flipTexture = true;
        float creaseAngle = 80.0f;
        if (options) {
            const std::string option = options->getOptionString();
            if (option.find("flipTexture") != std::string::npos)
                flipTexture = false;
            if (option.find("creaseAngle") != std::string::npos) {
                // TODO
            }
        }

        // Convert to osg::Geode
        osg::Geode* geode = convertFromDX(obj, flipTexture, creaseAngle);
        if (!geode)
            return ReadResult::FILE_NOT_HANDLED;

        return geode;
    }

    return ReadResult::FILE_NOT_HANDLED;
}

// Convert DirectX mesh to osg::Geode
osg::Geode* ReaderWriterDirectX::convertFromDX(DX::Object& obj,
                                               bool flipTexture, float creaseAngle)
{
    // Fetch mesh
    const DX::Mesh* mesh = obj.getMesh();
    if (!mesh)
        return NULL;

    const DX::MeshMaterialList* meshMaterial = obj.getMeshMaterialList();
    if (!meshMaterial)
        return NULL;

    const DX::MeshNormals* meshNormals = obj.getMeshNormals();
    if (!meshNormals) {
        obj.generateNormals(creaseAngle);
        meshNormals = obj.getMeshNormals();
    }
    if (!meshNormals)
        return NULL;

    const DX::MeshTextureCoords* meshTexCoords = obj.getMeshTextureCoords();
    if (!meshTexCoords)
        return NULL;

    /*
     * - MeshMaterialList contains a list of Material and a per-face
     *   information with Material is to be applied to which face.
     * - Mesh contains a list of Vertices and a per-face information
     *   which vertices (three or four) belong to this face.
     * - MeshNormals contains a list of Normals and a per-face information
     *   which normal is used by which vertex.
     * - MeshTextureCoords contains a list of per-vertex texture coordinates.
     *
     * - Uses left-hand CS with Y-up, Z-into
     *   obj_x -> osg_x
     *   obj_y -> osg_z
     *   obj_z -> osg_y
     *
     * - Polys are CW oriented
     */
    std::vector<osg::Geometry*> geomList;

    unsigned int i;
    for (i = 0; i < meshMaterial->material.size(); i++) {

        const DX::Material& mtl = meshMaterial->material[i];
        osg::StateSet* state = new osg::StateSet;

        // Material
        osg::Material* material = new osg::Material;
        state->setAttributeAndModes(material);

        float alpha = mtl.faceColor.alpha;
        osg::Vec4 ambient(mtl.faceColor.red,
                          mtl.faceColor.green,
                          mtl.faceColor.blue,
                          alpha);
        material->setAmbient(osg::Material::FRONT, ambient);
        material->setDiffuse(osg::Material::FRONT, ambient);

        material->setShininess(osg::Material::FRONT, mtl.power);

        osg::Vec4 specular(mtl.specularColor.red,
                           mtl.specularColor.green,
                           mtl.specularColor.blue, alpha);
        material->setSpecular(osg::Material::FRONT, specular);

        osg::Vec4 emissive(mtl.emissiveColor.red,
                           mtl.emissiveColor.green,
                           mtl.emissiveColor.blue, alpha);
        material->setEmission(osg::Material::FRONT, emissive);

        // Transparency? Set render hint & blending
        if (alpha < 1.0f) {
            state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
            state->setMode(GL_BLEND, osg::StateAttribute::ON);
        }
        else
            state->setMode(GL_BLEND, osg::StateAttribute::OFF);

        unsigned int textureCount = mtl.texture.size();
        for (unsigned int j = 0; j < textureCount; j++) {
            // Load image
            osg::Image* image = osgDB::readImageFile(mtl.texture[j]);
            if (!image)
                continue;

            // Texture
            osg::Texture2D* texture = new osg::Texture2D;
            texture->setImage(image);
            texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
            texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
            state->setTextureAttributeAndModes(j, texture);
        }

        // Geometry
        osg::Geometry* geom = new osg::Geometry;
        geomList.push_back(geom);

        geom->setStateSet(state);

        // Arrays to hold vertices, normals, and texcoords.
        geom->setVertexArray(new osg::Vec3Array);
        geom->setNormalArray(new osg::Vec3Array);
        geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
        if (textureCount) {
            // All texture units share the same array
            osg::Vec2Array* texCoords = new osg::Vec2Array;
            for (unsigned int j = 0; j < textureCount; j++)
                geom->setTexCoordArray(j, texCoords);
        }

        geom->addPrimitiveSet(new osg::DrawArrayLengths(osg::PrimitiveSet::POLYGON));
    }

    if (mesh->faces.size() != meshMaterial->faceIndices.size())
    {
        osg::notify(osg::FATAL)<<"Error: internal error in DirectX .x loader,"<<std::endl;
        osg::notify(osg::FATAL)<<"       mesh->faces.size() == meshMaterial->faceIndices.size()"<<std::endl;
        return NULL;
    }

    // Add faces to Geometry
    for (i = 0; i < meshMaterial->faceIndices.size(); i++) {

        // Geometry for Material
        unsigned int mi = meshMaterial->faceIndices[i];
        osg::Geometry* geom = geomList[mi];

        // #pts of this face
        unsigned int np = mesh->faces[i].size();
        ((osg::DrawArrayLengths*) geom->getPrimitiveSet(0))->push_back(np);

        assert(np == meshNormals->faceNormals[i].size());

        osg::Vec3Array* vertexArray = (osg::Vec3Array*) geom->getVertexArray();
        osg::Vec3Array* normalArray = (osg::Vec3Array*) geom->getNormalArray();
        osg::Vec2Array* texCoordArray = (osg::Vec2Array*) geom->getTexCoordArray(0);

        // Add vertices, normals, texcoords
        for (unsigned int j = 0; j < np; j++) {

            // Convert CW to CCW order
            unsigned int jj = (j > 0 ? np - j : j);

            // Vertices
            unsigned int vi = mesh->faces[i][jj];
            if (vertexArray) {
                // Transform Xleft/Yup/Zinto to Xleft/Yinto/Zup
                const DX::Vector& v = mesh->vertices[vi];
                vertexArray->push_back(osg::Vec3(v.x,v.z,v.y));
            }

            // Normals
            unsigned int ni = meshNormals->faceNormals[i][jj];
            if (normalArray) {
                // Transform Xleft/Yup/Zinto to Xleft/Yinto/Zup
                const DX::Vector& n = meshNormals->normals[ni];
                normalArray->push_back(osg::Vec3(n.x,n.z,n.y));
            }

            // TexCoords
            if (texCoordArray) {
                const DX::Coords2d& tc = (*meshTexCoords)[vi];
                osg::Vec2 uv;
                if (flipTexture)
                    uv.set(tc.u, 1.0f - tc.v); // Image is upside down
                else
                    uv.set(tc.u, tc.v);
                texCoordArray->push_back(uv);
            }
        }
    }

    // Add non-empty nodes to Geode
    osg::Geode* geode = new osg::Geode;
    for (i = 0; i < geomList.size(); i++) {
        osg::Geometry* geom = geomList[i];
        if (((osg::Vec3Array*) geom->getVertexArray())->size())
            geode->addDrawable(geom);
    }

    // Back-face culling
    osg::StateSet* state = new osg::StateSet;
    geode->setStateSet(state);

    osg::CullFace* cullFace = new osg::CullFace;
    cullFace->setMode(osg::CullFace::BACK);
    state->setAttributeAndModes(cullFace);

    return geode;
}
<commit_msg>Updates from Ulrich for sharing of textures.<commit_after>// -*-c++-*-

/*
 * $Id$
 *
 * DirectX file converter for OpenSceneGraph.
 * Copyright (c)2002 Ulrich Hertlein <u.hertlein@sandbox.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "directx.h"

#include <osg/TexEnv>
#include <osg/CullFace>

#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/Image>
#include <osg/Texture2D>

#include <osg/Notify>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/FileNameUtils>

#include <assert.h>
#include <map>

/**
 * OpenSceneGraph plugin wrapper/converter.
 */
class ReaderWriterDirectX : public osgDB::ReaderWriter
{
public:
    ReaderWriterDirectX() { }

    virtual const char* className() {
        return "DirectX Reader/Writer";
    }

    virtual bool acceptsExtension(const std::string& extension) {
        return osgDB::equalCaseInsensitive(extension,"x") ? true : false;
    }

    virtual ReadResult readNode(const std::string& fileName,
                                const osgDB::ReaderWriter::Options* options);

private:
    osg::Geode* convertFromDX(DX::Object& obj, bool flipTexture, float creaseAngle);
};

// Register with Registry to instantiate the above reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterDirectX> g_readerWriter_DirectX_Proxy;

// Read node
osgDB::ReaderWriter::ReadResult ReaderWriterDirectX::readNode(const std::string& fileName,
                                                              const osgDB::ReaderWriter::Options* options)
{
    std::string ext = osgDB::getLowerCaseFileExtension(fileName);
    if (!acceptsExtension(ext))
        return ReadResult::FILE_NOT_HANDLED;

    osg::notify(osg::INFO) << "ReaderWriterDirectX::readNode(" << fileName.c_str() << ")\n";

    // Load DirectX mesh
    DX::Object obj;
    if (obj.load(fileName.c_str())) {

        // Options?
        bool flipTexture = true;
        float creaseAngle = 80.0f;
        if (options) {
            const std::string option = options->getOptionString();
            if (option.find("flipTexture") != std::string::npos)
                flipTexture = false;
            if (option.find("creaseAngle") != std::string::npos) {
                // TODO
            }
        }

        // Convert to osg::Geode
        osg::Geode* geode = convertFromDX(obj, flipTexture, creaseAngle);
        if (!geode)
            return ReadResult::FILE_NOT_HANDLED;

        return geode;
    }

    return ReadResult::FILE_NOT_HANDLED;
}

// Convert DirectX mesh to osg::Geode
osg::Geode* ReaderWriterDirectX::convertFromDX(DX::Object& obj,
                                               bool flipTexture, float creaseAngle)
{
    // Fetch mesh
    const DX::Mesh* mesh = obj.getMesh();
    if (!mesh)
        return NULL;

    const DX::MeshMaterialList* meshMaterial = obj.getMeshMaterialList();
    if (!meshMaterial)
        return NULL;

    const DX::MeshNormals* meshNormals = obj.getMeshNormals();
    if (!meshNormals) {
        obj.generateNormals(creaseAngle);
        meshNormals = obj.getMeshNormals();
    }
    if (!meshNormals)
        return NULL;

    const DX::MeshTextureCoords* meshTexCoords = obj.getMeshTextureCoords();
    if (!meshTexCoords)
        return NULL;

    /*
     * - MeshMaterialList contains a list of Material and a per-face
     *   information with Material is to be applied to which face.
     * - Mesh contains a list of Vertices and a per-face information
     *   which vertices (three or four) belong to this face.
     * - MeshNormals contains a list of Normals and a per-face information
     *   which normal is used by which vertex.
     * - MeshTextureCoords contains a list of per-vertex texture coordinates.
     *
     * - Uses left-hand CS with Y-up, Z-into
     *   obj_x -> osg_x
     *   obj_y -> osg_z
     *   obj_z -> osg_y
     *
     * - Polys are CW oriented
     */
    std::vector<osg::Geometry*> geomList;

    // Texture-for-Image map
    std::map<std::string, osg::Texture2D*> texForImage;

    unsigned int i;
    for (i = 0; i < meshMaterial->material.size(); i++) {

        const DX::Material& mtl = meshMaterial->material[i];
        osg::StateSet* state = new osg::StateSet;

        // Material
        osg::Material* material = new osg::Material;
        state->setAttributeAndModes(material);

        float alpha = mtl.faceColor.alpha;
        osg::Vec4 ambient(mtl.faceColor.red,
                          mtl.faceColor.green,
                          mtl.faceColor.blue,
                          alpha);
        material->setAmbient(osg::Material::FRONT, ambient);
        material->setDiffuse(osg::Material::FRONT, ambient);

        material->setShininess(osg::Material::FRONT, mtl.power);

        osg::Vec4 specular(mtl.specularColor.red,
                           mtl.specularColor.green,
                           mtl.specularColor.blue, alpha);
        material->setSpecular(osg::Material::FRONT, specular);

        osg::Vec4 emissive(mtl.emissiveColor.red,
                           mtl.emissiveColor.green,
                           mtl.emissiveColor.blue, alpha);
        material->setEmission(osg::Material::FRONT, emissive);

        // Transparency? Set render hint & blending
        if (alpha < 1.0f) {
            state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
            state->setMode(GL_BLEND, osg::StateAttribute::ON);
        }
        else
            state->setMode(GL_BLEND, osg::StateAttribute::OFF);

        unsigned int textureCount = mtl.texture.size();
        for (unsigned int j = 0; j < textureCount; j++) {

            // Share image/texture pairs
            osg::Texture2D* texture = texForImage[mtl.texture[j]];
            if (!texture) {
                osg::Image* image = osgDB::readImageFile(mtl.texture[j]);
                if (!image)
                    continue;

                // Texture
                texture = new osg::Texture2D;
                texForImage[mtl.texture[j]] = texture;

                texture->setImage(image);
                texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
                texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
            }
            state->setTextureAttributeAndModes(j, texture);
        }

        // Geometry
        osg::Geometry* geom = new osg::Geometry;
        geomList.push_back(geom);

        geom->setStateSet(state);

        // Arrays to hold vertices, normals, and texcoords.
        geom->setVertexArray(new osg::Vec3Array);
        geom->setNormalArray(new osg::Vec3Array);
        geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
        if (textureCount) {
            // All texture units share the same array
            osg::Vec2Array* texCoords = new osg::Vec2Array;
            for (unsigned int j = 0; j < textureCount; j++)
                geom->setTexCoordArray(j, texCoords);
        }

        geom->addPrimitiveSet(new osg::DrawArrayLengths(osg::PrimitiveSet::POLYGON));
    }

    if (mesh->faces.size() != meshMaterial->faceIndices.size())
    {
        osg::notify(osg::FATAL)<<"Error: internal error in DirectX .x loader,"<<std::endl;
        osg::notify(osg::FATAL)<<"       mesh->faces.size() == meshMaterial->faceIndices.size()"<<std::endl;
        return NULL;
    }

    // Add faces to Geometry
    for (i = 0; i < meshMaterial->faceIndices.size(); i++) {

        // Geometry for Material
        unsigned int mi = meshMaterial->faceIndices[i];
        osg::Geometry* geom = geomList[mi];

        // #pts of this face
        unsigned int np = mesh->faces[i].size();
        ((osg::DrawArrayLengths*) geom->getPrimitiveSet(0))->push_back(np);

        assert(np == meshNormals->faceNormals[i].size());

        osg::Vec3Array* vertexArray = (osg::Vec3Array*) geom->getVertexArray();
        osg::Vec3Array* normalArray = (osg::Vec3Array*) geom->getNormalArray();
        osg::Vec2Array* texCoordArray = (osg::Vec2Array*) geom->getTexCoordArray(0);

        // Add vertices, normals, texcoords
        for (unsigned int j = 0; j < np; j++) {

            // Convert CW to CCW order
            unsigned int jj = (j > 0 ? np - j : j);

            // Vertices
            unsigned int vi = mesh->faces[i][jj];
            if (vertexArray) {
                // Transform Xleft/Yup/Zinto to Xleft/Yinto/Zup
                const DX::Vector& v = mesh->vertices[vi];
                vertexArray->push_back(osg::Vec3(v.x,v.z,v.y));
            }

            // Normals
            unsigned int ni = meshNormals->faceNormals[i][jj];
            if (normalArray) {
                // Transform Xleft/Yup/Zinto to Xleft/Yinto/Zup
                const DX::Vector& n = meshNormals->normals[ni];
                normalArray->push_back(osg::Vec3(n.x,n.z,n.y));
            }

            // TexCoords
            if (texCoordArray) {
                const DX::Coords2d& tc = (*meshTexCoords)[vi];
                osg::Vec2 uv;
                if (flipTexture)
                    uv.set(tc.u, 1.0f - tc.v); // Image is upside down
                else
                    uv.set(tc.u, tc.v);
                texCoordArray->push_back(uv);
            }
        }
    }

    // Add non-empty nodes to Geode
    osg::Geode* geode = new osg::Geode;
    for (i = 0; i < geomList.size(); i++) {
        osg::Geometry* geom = geomList[i];
        if (((osg::Vec3Array*) geom->getVertexArray())->size())
            geode->addDrawable(geom);
    }

    // Back-face culling
    osg::StateSet* state = new osg::StateSet;
    geode->setStateSet(state);

    osg::CullFace* cullFace = new osg::CullFace;
    cullFace->setMode(osg::CullFace::BACK);
    state->setAttributeAndModes(cullFace);

    return geode;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qsvgiohandler.h"

#ifndef QT_NO_SVGRENDERER

#include "qsvgrenderer.h"
#include "qimage.h"
#include "qpixmap.h"
#include "qpainter.h"
#include "qvariant.h"
#include "qdebug.h"

QT_BEGIN_NAMESPACE

class QSvgIOHandlerPrivate
{
public:
    QSvgIOHandlerPrivate()
        : r(new QSvgRenderer()), loaded(false)
    {}
    ~QSvgIOHandlerPrivate()
    {
        delete r;
    }

    bool load(QIODevice *device);

    QSvgRenderer *r;
    QSize         defaultSize;
    QSize         currentSize;
    bool          loaded;
};

bool QSvgIOHandlerPrivate::load(QIODevice *device)
{
    if (loaded)
        return true;

    if (r->load(device->readAll())) {
        defaultSize = QSize(r->viewBox().width(), r->viewBox().height());
        if (currentSize.isEmpty())
            currentSize = defaultSize;
    }
    loaded = r->isValid();

    return loaded;
}

QSvgIOHandler::QSvgIOHandler()
    : d(new QSvgIOHandlerPrivate())
{

}

QSvgIOHandler::~QSvgIOHandler()
{
    delete d;
}

bool QSvgIOHandler::canRead() const
{
    QByteArray contents = device()->peek(80);

    return contents.contains("<svg");
}

QByteArray QSvgIOHandler::name() const
{
    return "svg";
}

bool QSvgIOHandler::read(QImage *image)
{
    if (d->load(device())) {
        *image = QImage(d->currentSize, QImage::Format_ARGB32_Premultiplied);
        if (!d->currentSize.isEmpty()) {
            image->fill(0x00000000);
            QPainter p(image);
            d->r->render(&p);
            p.end();
        }
        return true;
    }

    return false;
}

QVariant QSvgIOHandler::option(ImageOption option) const
{
    switch(option) {
    case ImageFormat:
        return QImage::Format_ARGB32_Premultiplied;
        break;
    case Size:
        d->load(device());
        return d->defaultSize;
        break;
    case ScaledSize:
        return d->currentSize;
        break;
    default:
        break;
    }
    return QVariant();
}

void QSvgIOHandler::setOption(ImageOption option, const QVariant & value)
{
    switch(option) {
    case Size:
        d->defaultSize = value.toSize();
        d->currentSize = value.toSize();
        break;
    case ScaledSize:
        d->currentSize = value.toSize();
        break;
    default:
        break;
    }
}

bool QSvgIOHandler::supportsOption(ImageOption option) const
{
    switch(option)
    {
    case ImageFormat:
    case Size:
    case ScaledSize:
        return true;
    default:
        break;
    }
    return false;
}

bool QSvgIOHandler::canRead(QIODevice *device)
{
    QByteArray contents = device->peek(80);
    return contents.contains("<svg");
}

QT_END_NAMESPACE

#endif // QT_NO_SVGRENDERER
<commit_msg>Fixed a validation problem in QSvgIOHandler::canRead().<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qsvgiohandler.h"

#ifndef QT_NO_SVGRENDERER

#include "qsvgrenderer.h"
#include "qimage.h"
#include "qpixmap.h"
#include "qpainter.h"
#include "qvariant.h"
#include "qdebug.h"

QT_BEGIN_NAMESPACE

class QSvgIOHandlerPrivate
{
public:
    QSvgIOHandlerPrivate()
        : r(new QSvgRenderer()), loaded(false)
    {}
    ~QSvgIOHandlerPrivate()
    {
        delete r;
    }

    bool load(QIODevice *device);
    static bool findSvgTag(QIODevice *device);

    QSvgRenderer *r;
    QSize         defaultSize;
    QSize         currentSize;
    bool          loaded;
};

bool QSvgIOHandlerPrivate::load(QIODevice *device)
{
    if (loaded)
        return true;

    if (r->load(device->readAll())) {
        defaultSize = QSize(r->viewBox().width(), r->viewBox().height());
        if (currentSize.isEmpty())
            currentSize = defaultSize;
    }
    loaded = r->isValid();

    return loaded;
}

bool QSvgIOHandlerPrivate::findSvgTag(QIODevice *device)
{
    qint64 pos = device->pos();
    device->seek(0);
    char buffer[256];
    const char svg_tag[] = "<svg";

    while (1) {
        int size = device->read(buffer, 256);
        for (int i=0; i<size - 5; ++i) {
            if (!memcmp(buffer + i, svg_tag, 4)) {
                if (buffer[i+4] == ' ' || buffer[i+4] == '\t'
                    || buffer[i+4] == '\n' || buffer[i+4] == '\r')
                {
                    device->seek(pos);
                    return true;
                }
            }
        }
        if (device->atEnd())
            break;
        device->seek(device->pos()-4);
    }
    device->seek(pos);
    return false;
}

QSvgIOHandler::QSvgIOHandler()
    : d(new QSvgIOHandlerPrivate())
{

}

QSvgIOHandler::~QSvgIOHandler()
{
    delete d;
}

bool QSvgIOHandler::canRead() const
{
    return QSvgIOHandlerPrivate::findSvgTag(device());
}

QByteArray QSvgIOHandler::name() const
{
    return "svg";
}

bool QSvgIOHandler::read(QImage *image)
{
    if (d->load(device())) {
        *image = QImage(d->currentSize, QImage::Format_ARGB32_Premultiplied);
        if (!d->currentSize.isEmpty()) {
            image->fill(0x00000000);
            QPainter p(image);
            d->r->render(&p);
            p.end();
        }
        return true;
    }

    return false;
}

QVariant QSvgIOHandler::option(ImageOption option) const
{
    switch(option) {
    case ImageFormat:
        return QImage::Format_ARGB32_Premultiplied;
        break;
    case Size:
        d->load(device());
        return d->defaultSize;
        break;
    case ScaledSize:
        return d->currentSize;
        break;
    default:
        break;
    }
    return QVariant();
}

void QSvgIOHandler::setOption(ImageOption option, const QVariant & value)
{
    switch(option) {
    case Size:
        d->defaultSize = value.toSize();
        d->currentSize = value.toSize();
        break;
    case ScaledSize:
        d->currentSize = value.toSize();
        break;
    default:
        break;
    }
}

bool QSvgIOHandler::supportsOption(ImageOption option) const
{
    switch(option)
    {
    case ImageFormat:
    case Size:
    case ScaledSize:
        return true;
    default:
        break;
    }
    return false;
}

bool QSvgIOHandler::canRead(QIODevice *device)
{
    return QSvgIOHandlerPrivate::findSvgTag(device);
}

QT_END_NAMESPACE

#endif // QT_NO_SVGRENDERER
<|endoftext|>


<commit_before>// set a very long point contact so that the field is almost the same as a
// coaxial detector. We then compare the field in the middle part of z with the
// analytic result of a true coaxial detector field
{
   // calculate potential for point contact 2D
   GeFiCa::PointContactRZ *ppc = new GeFiCa::PointContactRZ(1036,506);
   ppc->RUpperBound=3.45;
   ppc->RLowerBound=-3.45;
   ppc->ZUpperBound=5.05;
   ppc->PointBegin=-0.135;
   ppc->PointEnd=0.135;
   ppc->PointDepth=5.05;

   ppc->MaxIterations=1e6;
   ppc->Precision=1e-8;
   ppc->Csor=1.996;
   ppc->V0=2500*GeFiCa::volt;
   ppc->V1=0*GeFiCa::volt;
   ppc->Impurity="-0.318e10+0*y";
   ppc->CalculateField(GeFiCa::kSOR2);
   ppc->SaveField("pc2d.root");

   // calculate potential for true coaxial 1D analyitically
   GeFiCa::TrueCoaxial1D *tc1d = new GeFiCa::TrueCoaxial1D(499);
   tc1d->V0=0*GeFiCa::volt;
   tc1d->V1=2500*GeFiCa::volt;
   tc1d->InnerRadius=0.13;
   tc1d->OuterRadius=3.45;

   tc1d->Impurity="-0.318e10";
   tc1d->CalculateField(GeFiCa::kAnalytic);
   tc1d->SaveField("tca.root");

   // compare
   TChain *t1 = new TChain("t");
   t1->Add("pc2d.root");

   t1->Draw("p:c1","c2>2.5 && c2<2.51 && c1>0.13");
   double *p1 = t->GetV1();
   double *r1 = t->GetV2();

   TChain *t2 = new TChain("t");
   t2->Add("tca.root");

   t2->Draw("p:c1");
   double *p2 = t->GetV1();
   double *r2 = t->GetV2();

   const int n = t2->GetSelectedRows();
   double p[n]={0};
   for (int i=0; i<n; i++) p[i] = p1[i] - p2[i];

   TGraph *g = new TGraph(n,r1,p);
   g->Draw("ap");
   g->GetYaxis()->SetRangeUser(-1e-9,1e-9);
}
<commit_msg>changed PointContactRZ setting names<commit_after>// set a very long point contact so that the field is almost the same as a
// coaxial detector. We then compare the field in the middle part of z with the
// analytic result of a true coaxial detector field
{
   // calculate potential for point contact 2D
   GeFiCa::PointContactRZ *ppc = new GeFiCa::PointContactRZ(1036,506);
   ppc->Radius=3.45;
   ppc->ZUpperBound=5.05;
   ppc->PointR=0.135;
   ppc->PointDepth=5.05;

   ppc->MaxIterations=1e6;
   ppc->Precision=1e-8;
   ppc->Csor=1.996;
   ppc->V0=2500*GeFiCa::volt;
   ppc->V1=0*GeFiCa::volt;
   ppc->Impurity="-0.318e10+0*y";
   ppc->CalculateField(GeFiCa::kSOR2);
   ppc->SaveField("pc2d.root");

   // calculate potential for true coaxial 1D analyitically
   GeFiCa::TrueCoaxial1D *tc1d = new GeFiCa::TrueCoaxial1D(499);
   tc1d->V0=0*GeFiCa::volt;
   tc1d->V1=2500*GeFiCa::volt;
   tc1d->InnerRadius=0.13;
   tc1d->OuterRadius=3.45;

   tc1d->Impurity="-0.318e10";
   tc1d->CalculateField(GeFiCa::kAnalytic);
   tc1d->SaveField("tca.root");

   // compare
   TChain *t1 = new TChain("t");
   t1->Add("pc2d.root");

   t1->Draw("p:c1","c2>2.5 && c2<2.51 && c1>0.13");
   double *p1 = t->GetV1();
   double *r1 = t->GetV2();

   TChain *t2 = new TChain("t");
   t2->Add("tca.root");

   t2->Draw("p:c1");
   double *p2 = t->GetV1();
   double *r2 = t->GetV2();

   const int n = t2->GetSelectedRows();
   double p[n]={0};
   for (int i=0; i<n; i++) p[i] = p1[i] - p2[i];

   TGraph *g = new TGraph(n,r1,p);
   g->Draw("ap");
   g->GetYaxis()->SetRangeUser(-1e-9,1e-9);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"
#include "libtorrent/config.hpp"

#include <boost/scoped_ptr.hpp>
#ifdef TORRENT_WINDOWS
// windows part
#include "libtorrent/utf8.hpp"

#include <windows.h>
#include <winioctl.h>

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// posix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>
#include <cstring>
#include <vector>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#include "libtorrent/assert.hpp"

namespace
{
#ifdef TORRENT_WINDOWS
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else

	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		TORRENT_ASSERT(false);
		return 0;
	}
#endif

}

namespace libtorrent
{
	namespace fs = boost::filesystem;

#ifdef TORRENT_WINDOWS
	const file::open_mode file::in(GENERIC_READ);
	const file::open_mode file::out(GENERIC_WRITE);
	const file::seek_mode file::begin(FILE_BEGIN);
	const file::seek_mode file::end(FILE_END);
#else
	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);
	const file::seek_mode file::begin(SEEK_SET);
	const file::seek_mode file::end(SEEK_END);
#endif

	file::file()
#ifdef TORRENT_WINDOWS
		: m_file_handle(INVALID_HANDLE_VALUE)
#else
		: m_fd(-1)
#endif
#ifndef NDEBUG
		, m_open_mode(0)
#endif
	{}

	file::file(fs::path const& path, open_mode mode, error_code& ec)
#ifdef TORRENT_WINDOWS
		: m_file_handle(INVALID_HANDLE_VALUE)
#else
		: m_fd(-1)
#endif
#ifndef NDEBUG
		, m_open_mode(0)
#endif
	{
		open(path, mode, ec);
	}

	file::~file()
	{
		close();
	}

	bool file::open(fs::path const& path, open_mode mode, error_code& ec)
	{
		close();
#ifdef TORRENT_WINDOWS

#ifdef UNICODE
		std::wstring file_path(safe_convert(path.native_file_string()));
#else
		std::string file_path = utf8_native(path.native_file_string());
#endif

		m_file_handle = CreateFile(
			file_path.c_str()
			, mode.m_mask
			, FILE_SHARE_READ
			, 0
			, (mode & out)?OPEN_ALWAYS:OPEN_EXISTING
			, FILE_ATTRIBUTE_NORMAL
			, 0);

		if (m_file_handle == INVALID_HANDLE_VALUE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return false;
		}

		// try to make the file sparse if supported
		if (mode & out)
		{
			DWORD temp;
			::DeviceIoControl(m_file_handle, FSCTL_SET_SPARSE, 0, 0
				, 0, 0, &temp, 0);
		}
#else
		// rely on default umask to filter x and w permissions
		// for group and others
		int permissions = S_IRUSR | S_IWUSR
			| S_IRGRP | S_IWGRP
			| S_IROTH | S_IWOTH;

		m_fd = ::open(path.native_file_string().c_str()
			, map_open_mode(mode.m_mask), permissions);

		if (m_fd == -1)
		{
			ec = error_code(errno, get_posix_category());
			return false;
		}
#endif
#ifndef NDEBUG
		m_open_mode = mode;
#endif
		TORRENT_ASSERT(is_open());
		return true;
	}

	bool file::is_open() const
	{
#ifdef TORRENT_WINDOWS
		return m_file_handle != INVALID_HANDLE_VALUE;
#else
		return m_fd != -1;
#endif
	}

	void file::close()
	{
#ifdef TORRENT_WINDOWS
		if (m_file_handle == INVALID_HANDLE_VALUE) return;
		CloseHandle(m_file_handle);
		m_file_handle = INVALID_HANDLE_VALUE;
#else
		if (m_fd == -1) return;
		::close(m_fd);
		m_fd = -1;
#endif
#ifndef NDEBUG
		m_open_mode = 0;
#endif
	}

	size_type file::read(char* buf, size_type num_bytes, error_code& ec)
	{
		TORRENT_ASSERT((m_open_mode & in) == in);
		TORRENT_ASSERT(buf);
		TORRENT_ASSERT(num_bytes >= 0);
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS

		TORRENT_ASSERT(DWORD(num_bytes) == num_bytes);
		DWORD ret = 0;
		if (num_bytes != 0)
		{
			if (ReadFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
			{
				ec = error_code(GetLastError(), get_system_category());
				return -1;
			}
		}
#else
		size_type ret = ::read(m_fd, buf, num_bytes);
		if (ret == -1) ec = error_code(errno, get_posix_category());
#endif
		return ret;
	}

	size_type file::write(const char* buf, size_type num_bytes, error_code& ec)
	{
		TORRENT_ASSERT((m_open_mode & out) == out);
		TORRENT_ASSERT(buf);
		TORRENT_ASSERT(num_bytes >= 0);
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS

		DWORD ret = 0;
		if (num_bytes != 0)
		{
			if (WriteFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
			{
				ec = error_code(GetLastError(), get_system_category());
				return -1;
			}
		}
#else
		size_type ret = ::write(m_fd, buf, num_bytes);
		if (ret == -1) ec = error_code(errno, get_posix_category());
#endif
		return ret;
	}

  	bool file::set_size(size_type s, error_code& ec)
  	{
  		TORRENT_ASSERT(is_open());
  		TORRENT_ASSERT(s >= 0);

#ifdef TORRENT_WINDOWS
		size_type pos = tell(ec);
		if (ec) return false;
		seek(s, begin, ec);
		if (ec) return false;
		if (::SetEndOfFile(m_file_handle) == FALSE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return false;
		}
#else
		if (ftruncate(m_fd, s) < 0)
		{
			ec = error_code(errno, get_posix_category());
			return false;
		}
#endif
		return true;
	}

	size_type file::seek(size_type offset, seek_mode m, error_code& ec)
	{
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS
		LARGE_INTEGER offs;
		offs.QuadPart = offset;
		if (SetFilePointerEx(m_file_handle, offs, &offs, m.m_val) == FALSE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return -1;
		}
		return offs.QuadPart;
#else
		size_type ret = lseek(m_fd, offset, m.m_val);
		if (ret < 0) ec = error_code(errno, get_posix_category());
		return ret;
#endif
	}

	size_type file::tell(error_code& ec)
	{
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS
		LARGE_INTEGER offs;
		offs.QuadPart = 0;

		// is there any other way to get offset?
		if (SetFilePointerEx(m_file_handle, offs, &offs
			, FILE_CURRENT) == FALSE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return -1;
		}

		return offs.QuadPart;
#else
		size_type ret;
		ret = lseek(m_fd, 0, SEEK_CUR);
		if (ret < 0) ec = error_code(errno, get_posix_category());
		return ret;
#endif
	}
}

<commit_msg>fixed typecast typo in file.cpp<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"
#include "libtorrent/config.hpp"

#include <boost/scoped_ptr.hpp>
#ifdef TORRENT_WINDOWS
// windows part
#include "libtorrent/utf8.hpp"

#include <windows.h>
#include <winioctl.h>

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// posix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>
#include <cstring>
#include <vector>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#include "libtorrent/assert.hpp"

namespace
{
#ifdef TORRENT_WINDOWS
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == std::size_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else

	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		TORRENT_ASSERT(false);
		return 0;
	}
#endif

}

namespace libtorrent
{
	namespace fs = boost::filesystem;

#ifdef TORRENT_WINDOWS
	const file::open_mode file::in(GENERIC_READ);
	const file::open_mode file::out(GENERIC_WRITE);
	const file::seek_mode file::begin(FILE_BEGIN);
	const file::seek_mode file::end(FILE_END);
#else
	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);
	const file::seek_mode file::begin(SEEK_SET);
	const file::seek_mode file::end(SEEK_END);
#endif

	file::file()
#ifdef TORRENT_WINDOWS
		: m_file_handle(INVALID_HANDLE_VALUE)
#else
		: m_fd(-1)
#endif
#ifndef NDEBUG
		, m_open_mode(0)
#endif
	{}

	file::file(fs::path const& path, open_mode mode, error_code& ec)
#ifdef TORRENT_WINDOWS
		: m_file_handle(INVALID_HANDLE_VALUE)
#else
		: m_fd(-1)
#endif
#ifndef NDEBUG
		, m_open_mode(0)
#endif
	{
		open(path, mode, ec);
	}

	file::~file()
	{
		close();
	}

	bool file::open(fs::path const& path, open_mode mode, error_code& ec)
	{
		close();
#ifdef TORRENT_WINDOWS

#ifdef UNICODE
		std::wstring file_path(safe_convert(path.native_file_string()));
#else
		std::string file_path = utf8_native(path.native_file_string());
#endif

		m_file_handle = CreateFile(
			file_path.c_str()
			, mode.m_mask
			, FILE_SHARE_READ
			, 0
			, (mode & out)?OPEN_ALWAYS:OPEN_EXISTING
			, FILE_ATTRIBUTE_NORMAL
			, 0);

		if (m_file_handle == INVALID_HANDLE_VALUE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return false;
		}

		// try to make the file sparse if supported
		if (mode & out)
		{
			DWORD temp;
			::DeviceIoControl(m_file_handle, FSCTL_SET_SPARSE, 0, 0
				, 0, 0, &temp, 0);
		}
#else
		// rely on default umask to filter x and w permissions
		// for group and others
		int permissions = S_IRUSR | S_IWUSR
			| S_IRGRP | S_IWGRP
			| S_IROTH | S_IWOTH;

		m_fd = ::open(path.native_file_string().c_str()
			, map_open_mode(mode.m_mask), permissions);

		if (m_fd == -1)
		{
			ec = error_code(errno, get_posix_category());
			return false;
		}
#endif
#ifndef NDEBUG
		m_open_mode = mode;
#endif
		TORRENT_ASSERT(is_open());
		return true;
	}

	bool file::is_open() const
	{
#ifdef TORRENT_WINDOWS
		return m_file_handle != INVALID_HANDLE_VALUE;
#else
		return m_fd != -1;
#endif
	}

	void file::close()
	{
#ifdef TORRENT_WINDOWS
		if (m_file_handle == INVALID_HANDLE_VALUE) return;
		CloseHandle(m_file_handle);
		m_file_handle = INVALID_HANDLE_VALUE;
#else
		if (m_fd == -1) return;
		::close(m_fd);
		m_fd = -1;
#endif
#ifndef NDEBUG
		m_open_mode = 0;
#endif
	}

	size_type file::read(char* buf, size_type num_bytes, error_code& ec)
	{
		TORRENT_ASSERT((m_open_mode & in) == in);
		TORRENT_ASSERT(buf);
		TORRENT_ASSERT(num_bytes >= 0);
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS

		TORRENT_ASSERT(DWORD(num_bytes) == num_bytes);
		DWORD ret = 0;
		if (num_bytes != 0)
		{
			if (ReadFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
			{
				ec = error_code(GetLastError(), get_system_category());
				return -1;
			}
		}
#else
		size_type ret = ::read(m_fd, buf, num_bytes);
		if (ret == -1) ec = error_code(errno, get_posix_category());
#endif
		return ret;
	}

	size_type file::write(const char* buf, size_type num_bytes, error_code& ec)
	{
		TORRENT_ASSERT((m_open_mode & out) == out);
		TORRENT_ASSERT(buf);
		TORRENT_ASSERT(num_bytes >= 0);
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS

		DWORD ret = 0;
		if (num_bytes != 0)
		{
			if (WriteFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
			{
				ec = error_code(GetLastError(), get_system_category());
				return -1;
			}
		}
#else
		size_type ret = ::write(m_fd, buf, num_bytes);
		if (ret == -1) ec = error_code(errno, get_posix_category());
#endif
		return ret;
	}

  	bool file::set_size(size_type s, error_code& ec)
  	{
  		TORRENT_ASSERT(is_open());
  		TORRENT_ASSERT(s >= 0);

#ifdef TORRENT_WINDOWS
		size_type pos = tell(ec);
		if (ec) return false;
		seek(s, begin, ec);
		if (ec) return false;
		if (::SetEndOfFile(m_file_handle) == FALSE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return false;
		}
#else
		if (ftruncate(m_fd, s) < 0)
		{
			ec = error_code(errno, get_posix_category());
			return false;
		}
#endif
		return true;
	}

	size_type file::seek(size_type offset, seek_mode m, error_code& ec)
	{
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS
		LARGE_INTEGER offs;
		offs.QuadPart = offset;
		if (SetFilePointerEx(m_file_handle, offs, &offs, m.m_val) == FALSE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return -1;
		}
		return offs.QuadPart;
#else
		size_type ret = lseek(m_fd, offset, m.m_val);
		if (ret < 0) ec = error_code(errno, get_posix_category());
		return ret;
#endif
	}

	size_type file::tell(error_code& ec)
	{
		TORRENT_ASSERT(is_open());

#ifdef TORRENT_WINDOWS
		LARGE_INTEGER offs;
		offs.QuadPart = 0;

		// is there any other way to get offset?
		if (SetFilePointerEx(m_file_handle, offs, &offs
			, FILE_CURRENT) == FALSE)
		{
			ec = error_code(GetLastError(), get_system_category());
			return -1;
		}

		return offs.QuadPart;
#else
		size_type ret;
		ret = lseek(m_fd, 0, SEEK_CUR);
		if (ret < 0) ec = error_code(errno, get_posix_category());
		return ret;
#endif
	}
}

<|endoftext|>


<commit_before>#include <common/buffer.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/channel.h>
#include <io/pipe.h>
#include <io/splice.h>

/*
 * A Splice passes data unidirectionall between StreamChannels across a Pipe.
 */

Splice::Splice(StreamChannel *source, Pipe *pipe, StreamChannel *sink)
: log_("/splice"),
  source_(source),
  pipe_(pipe),
  sink_(sink),
  callback_(NULL),
  callback_action_(NULL),
  read_eos_(false),
  read_action_(NULL),
  input_action_(NULL),
  output_action_(NULL),
  write_action_(NULL),
  shutdown_action_(NULL)
{
	ASSERT(source_ != NULL);
	ASSERT(pipe_ != NULL);
	ASSERT(sink_ != NULL);
}

Splice::~Splice()
{
	ASSERT(callback_ == NULL);
	ASSERT(callback_action_ == NULL);
	ASSERT(read_action_ == NULL);
	ASSERT(input_action_ == NULL);
	ASSERT(output_action_ == NULL);
	ASSERT(write_action_ == NULL);
	ASSERT(shutdown_action_ == NULL);
}

Action *
Splice::start(EventCallback *cb)
{
	ASSERT(callback_ == NULL && callback_action_ == NULL);
	callback_ = cb;

	EventCallback *scb = callback(this, &Splice::read_complete);
	read_action_ = source_->read(0, scb);

	EventCallback *pcb = callback(this, &Splice::output_complete);
	output_action_ = pipe_->output(pcb);

	return (cancellation(this, &Splice::cancel));
}

void
Splice::cancel(void)
{
	if (callback_ != NULL) {
		delete callback_;
		callback_ = NULL;

		ASSERT(callback_action_ == NULL);

		if (read_action_ != NULL) {
			read_action_->cancel();
			read_action_ = NULL;
		}

		if (input_action_ != NULL) {
			input_action_->cancel();
			input_action_ = NULL;
		}

		if (output_action_ != NULL) {
			output_action_->cancel();
			output_action_ = NULL;
		}

		if (write_action_ != NULL) {
			write_action_->cancel();
			write_action_ = NULL;
		}

		if (shutdown_action_ != NULL) {
			shutdown_action_->cancel();
			shutdown_action_ = NULL;
		}
	} else {
		ASSERT(callback_action_ != NULL);
		callback_action_->cancel();
		callback_action_ = NULL;
	}
}

void
Splice::complete(Event e)
{
	ASSERT(callback_ != NULL);
	ASSERT(callback_action_ == NULL);

	if (read_action_ != NULL) {
		read_action_->cancel();
		read_action_ = NULL;
	}

	if (input_action_ != NULL) {
		input_action_->cancel();
		input_action_ = NULL;
	}

	if (output_action_ != NULL) {
		output_action_->cancel();
		output_action_ = NULL;
	}

	if (write_action_ != NULL) {
		write_action_->cancel();
		write_action_ = NULL;
	}

	callback_->param(e);
	callback_action_ = EventSystem::instance()->schedule(callback_);
	callback_ = NULL;
}

void
Splice::read_complete(Event e)
{
	read_action_->cancel();
	read_action_ = NULL;

	ASSERT(!read_eos_);

	switch (e.type_) {
	case Event::Done:
	case Event::EOS:
		break;
	default:
		DEBUG(log_) << "Unexpected event: " << e;
		complete(e);
		return;
	}

	if (e.buffer_.empty()) {
		ASSERT(e.type_ == Event::EOS);

		read_eos_ = true;
	}

	ASSERT(input_action_ == NULL);
	EventCallback *cb = callback(this, &Splice::input_complete);
	input_action_ = pipe_->input(&e.buffer_, cb);
}

void
Splice::input_complete(Event e)
{
	input_action_->cancel();
	input_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
		break;
	default:
		DEBUG(log_) << "Unexpected event: " << e;
		complete(e);
		return;
	}

	ASSERT(read_action_ == NULL);
	if (!read_eos_) {
		EventCallback *cb = callback(this, &Splice::read_complete);
		read_action_ = source_->read(0, cb);
	}
}

void
Splice::output_complete(Event e)
{
	output_action_->cancel();
	output_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
	case Event::EOS:
		break;
	default:
		DEBUG(log_) << "Unexpected event: " << e;
		complete(e);
		return;
	}

	if (e.type_ == Event::EOS && e.buffer_.empty()) {
		EventCallback *cb = callback(this, &Splice::shutdown_complete);
		shutdown_action_ = sink_->shutdown(false, true, cb);
		return;
	}

	ASSERT(write_action_ == NULL);
	EventCallback *cb = callback(this, &Splice::write_complete);
	write_action_ = sink_->write(&e.buffer_, cb);
}

void
Splice::write_complete(Event e)
{
	write_action_->cancel();
	write_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
		break;
	default:
		DEBUG(log_) << "Unexpected event: " << e;
		complete(e);
		return;
	}

	ASSERT(output_action_ == NULL);
	EventCallback *cb = callback(this, &Splice::output_complete);
	output_action_ = pipe_->output(cb);
}

void
Splice::shutdown_complete(Event e)
{
	shutdown_action_->cancel();
	shutdown_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
	case Event::Error:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
		return;
	}

	if (e.type_ == Event::Error)
		DEBUG(log_) << "Could not shut down write channel.";
	complete(Event::EOS);
}
<commit_msg>Clean up shutdown actions when the splice is finished, too.<commit_after>#include <common/buffer.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/channel.h>
#include <io/pipe.h>
#include <io/splice.h>

/*
 * A Splice passes data unidirectionall between StreamChannels across a Pipe.
 */

Splice::Splice(StreamChannel *source, Pipe *pipe, StreamChannel *sink)
: log_("/splice"),
  source_(source),
  pipe_(pipe),
  sink_(sink),
  callback_(NULL),
  callback_action_(NULL),
  read_eos_(false),
  read_action_(NULL),
  input_action_(NULL),
  output_action_(NULL),
  write_action_(NULL),
  shutdown_action_(NULL)
{
	ASSERT(source_ != NULL);
	ASSERT(pipe_ != NULL);
	ASSERT(sink_ != NULL);
}

Splice::~Splice()
{
	ASSERT(callback_ == NULL);
	ASSERT(callback_action_ == NULL);
	ASSERT(read_action_ == NULL);
	ASSERT(input_action_ == NULL);
	ASSERT(output_action_ == NULL);
	ASSERT(write_action_ == NULL);
	ASSERT(shutdown_action_ == NULL);
}

Action *
Splice::start(EventCallback *cb)
{
	ASSERT(callback_ == NULL && callback_action_ == NULL);
	callback_ = cb;

	EventCallback *scb = callback(this, &Splice::read_complete);
	read_action_ = source_->read(0, scb);

	EventCallback *pcb = callback(this, &Splice::output_complete);
	output_action_ = pipe_->output(pcb);

	return (cancellation(this, &Splice::cancel));
}

void
Splice::cancel(void)
{
	if (callback_ != NULL) {
		delete callback_;
		callback_ = NULL;

		ASSERT(callback_action_ == NULL);

		if (read_action_ != NULL) {
			read_action_->cancel();
			read_action_ = NULL;
		}

		if (input_action_ != NULL) {
			input_action_->cancel();
			input_action_ = NULL;
		}

		if (output_action_ != NULL) {
			output_action_->cancel();
			output_action_ = NULL;
		}

		if (write_action_ != NULL) {
			write_action_->cancel();
			write_action_ = NULL;
		}

		if (shutdown_action_ != NULL) {
			shutdown_action_->cancel();
			shutdown_action_ = NULL;
		}
	} else {
		ASSERT(callback_action_ != NULL);
		callback_action_->cancel();
		callback_action_ = NULL;
	}
}

void
Splice::complete(Event e)
{
	ASSERT(callback_ != NULL);
	ASSERT(callback_action_ == NULL);

	if (read_action_ != NULL) {
		read_action_->cancel();
		read_action_ = NULL;
	}

	if (input_action_ != NULL) {
		input_action_->cancel();
		input_action_ = NULL;
	}

	if (output_action_ != NULL) {
		output_action_->cancel();
		output_action_ = NULL;
	}

	if (write_action_ != NULL) {
		write_action_->cancel();
		write_action_ = NULL;
	}

	if (shutdown_action_ != NULL) {
		shutdown_action_->cancel();
		shutdown_action_ = NULL;
	}

	callback_->param(e);
	callback_action_ = EventSystem::instance()->schedule(callback_);
	callback_ = NULL;
}

void
Splice::read_complete(Event e)
{
	read_action_->cancel();
	read_action_ = NULL;

	ASSERT(!read_eos_);

	switch (e.type_) {
	case Event::Done:
	case Event::EOS:
		break;
	default:
		DEBUG(log_) << "Unexpected event: " << e;
		complete(e);
		return;
	}

	if (e.buffer_.empty()) {
		ASSERT(e.type_ == Event::EOS);

		read_eos_ = true;
	}

	ASSERT(input_action_ == NULL);
	EventCallback *cb = callback(this, &Splice::input_complete);
	input_action_ = pipe_->input(&e.buffer_, cb);
}

void
Splice::input_complete(Event e)
{
	input_action_->cancel();
	input_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
		break;
	default:
		DEBUG(log_) << "Unexpected event: " << e;
		complete(e);
		return;
	}

	ASSERT(read_action_ == NULL);
	if (!read_eos_) {
		EventCallback *cb = callback(this, &Splice::read_complete);
		read_action_ = source_->read(0, cb);
	}
}

void
Splice::output_complete(Event e)
{
	output_action_->cancel();
	output_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
	case Event::EOS:
		break;
	default:
		DEBUG(log_) << "Unexpected event: " << e;
		complete(e);
		return;
	}

	if (e.type_ == Event::EOS && e.buffer_.empty()) {
		EventCallback *cb = callback(this, &Splice::shutdown_complete);
		shutdown_action_ = sink_->shutdown(false, true, cb);
		return;
	}

	ASSERT(write_action_ == NULL);
	EventCallback *cb = callback(this, &Splice::write_complete);
	write_action_ = sink_->write(&e.buffer_, cb);
}

void
Splice::write_complete(Event e)
{
	write_action_->cancel();
	write_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
		break;
	default:
		DEBUG(log_) << "Unexpected event: " << e;
		complete(e);
		return;
	}

	ASSERT(output_action_ == NULL);
	EventCallback *cb = callback(this, &Splice::output_complete);
	output_action_ = pipe_->output(cb);
}

void
Splice::shutdown_complete(Event e)
{
	shutdown_action_->cancel();
	shutdown_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
	case Event::Error:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
		return;
	}

	if (e.type_ == Event::Error)
		DEBUG(log_) << "Could not shut down write channel.";
	complete(Event::EOS);
}
<|endoftext|>