<commit_before>#define FUSE_USE_VERSION 26
#define _FILE_OFFSET_BITS 64

#include <fuse.h>
#include <iostream>
#include <memory>
#include <functional>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <planet/common.hpp>
#include <planet/fs_core.hpp>
#include <planet/operation_layer.hpp>
#include <planet/planet_handle.hpp>
#include <planet/dns_op.hpp>
#include <planet/tcp_client_op.hpp>
#include <planet/tcp_server_op.hpp>
#include <planet/packet_socket_op.hpp>
#include <syslog.h>

#define LOG_EXCEPTION_MSG(e) \
    ::syslog(LOG_ERR, "%s: %s", __func__, (e).what());

// Core filesystem object
planet::core_file_system fs_root(S_IRWXU);

static int planet_getattr(char const *path, struct stat *stbuf)
{
    ::syslog(LOG_INFO, "%s: path=%s stbuf=%p", __func__, path, stbuf);
    int ret = 0;
    try {
        std::memset(stbuf, 0, sizeof (struct stat));
        fs_root.getattr(path, *stbuf);
        ::syslog(LOG_INFO, "getattr: path=%s size=%llu mode=%o nlink=%d",
            path, stbuf->st_size, stbuf->st_mode, stbuf->st_nlink);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

static int planet_mknod(char const *path, mode_t mode, dev_t device)
{
    ::syslog(LOG_INFO, "%s: path=%s mode=%o %lld", __func__, path, mode, device);
    int ret = 0;
    try {
        ret = fs_root.mknod(path, mode, device);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

static int planet_mkdir(char const *path, mode_t mode)
{
    ::syslog(LOG_INFO, "%s: path=%s mode=%o", __func__, path, mode);
    int ret = 0;
    try {
        ret = fs_root.mkdir(path, 0755 | S_IFDIR);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

static int planet_chmod(char const *path, mode_t mode)
{
    return 0;
}

static int planet_chown(char const *path, uid_t uid, gid_t gid)
{
    return 0;
}

static int planet_utimens(char const* path, struct timespec const tv[2])
{
    int ret = 0;
    try {
        namespace ch = std::chrono;
        if (auto entry = fs_root.get_entry_of(path)) {
            ch::nanoseconds nano_access(tv[0].tv_nsec), nano_mod(tv[1].tv_nsec);
            ch::seconds sec_access(tv[0].tv_nsec), sec_mod(tv[1].tv_nsec);
            planet::st_inode new_inode = entry->inode();
            new_inode.atime = decltype(new_inode.atime)
                (ch::duration_cast<decltype(new_inode.atime)::duration>(nano_access + sec_access));
            new_inode.mtime = decltype(new_inode.atime)
                (ch::duration_cast<decltype(new_inode.atime)::duration>(nano_mod + sec_mod));
            entry->inode(new_inode);
        } else
            throw planet::exception_errno(ENOENT);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

static int planet_open(char const *path, struct fuse_file_info *fi)
{
    ::syslog(LOG_INFO, "%s: path=%s fi=%p", __func__, path, fi);
    int ret = 0;
    try {
        planet::handle_t ph = fs_root.open(path);
        planet::set_handle_to(*fi, ph);
        ::syslog(LOG_INFO, "%s: handle=%d", __func__, ph);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

static int planet_read(char const *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
{
    ::syslog(LOG_INFO, "%s: path=%s buf=%p size=%d offset=%llu", __func__, path, buf, size, offset);
    int bytes_received;
    try {
        planet::handle_t ph = planet::get_handle_from(*fi);
        bytes_received = planet::read(ph, buf, size, offset);
        ::syslog(LOG_INFO, "%s: handle=%d bytes_received=%d", __func__, ph, bytes_received);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        bytes_received = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        bytes_received = -EIO;
    }
    return bytes_received;
}

static int planet_write(char const *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
{
    ::syslog(LOG_INFO, "%s: path=%s buf=%p size=%d offset=%llu", __func__, path, buf, size, offset);
    int bytes_transferred;
    try {
        planet::handle_t ph = planet::get_handle_from(*fi);
        bytes_transferred = planet::write(ph, buf, size, offset);
        ::syslog(LOG_INFO, "%s: handle=%d bytes_transferred=%d", __func__, ph, bytes_transferred);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        bytes_transferred = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        bytes_transferred = -EIO;
    }
    return bytes_transferred;
}

static int planet_readdir(char const *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
{
    ::syslog(LOG_INFO, "%s: path=%s buf=%p offset=%llu", __func__, path, buf, offset);
    int ret = 0;
    try {
        filler(buf, ".", nullptr, 0);
        filler(buf, "..", nullptr, 0);
        for (auto const& entry_name : fs_root.readdir(path))
            if (filler(buf, entry_name.c_str(), nullptr, 0))
                break;
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

static int planet_release(char const *path, struct fuse_file_info *fi)
{
    ::syslog(LOG_INFO, "%s: path=%s fi=%p", __func__, path, fi);
    int ret = 0;
    try {
        planet::handle_t ph = planet::get_handle_from(*fi);
        ::syslog(LOG_INFO, "%s: handle=%d", __func__, ph);
        ret = planet::close(ph);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

// Install certain file operations
void planet_install_file_operations()
{
    fs_root.install_op<planet::dns_op>();
    fs_root.install_op<planet::tcp_client_op>();
    fs_root.install_op<planet::tcp_server_op>(fs_root);
    fs_root.install_op<planet::packet_socket_op>();
    fs_root.install_op<planet::default_file_op>();
}

// Create initial filesystem structure
void planet_create_initial_fs_structure()
{
    fs_root.mkdir("/eth",       S_IFDIR | S_IRWXU);
    fs_root.mkdir("/ip",        S_IFDIR | S_IRWXU);
    fs_root.mkdir("/tcp",       S_IFDIR | S_IRWXU);
    fs_root.mknod("/dns",       S_IFREG | S_IRWXU, 0);
    fs_root.mknod("/eth/eth0",  S_IFREG | S_IRWXU, 0);
    fs_root.mknod("/eth/wlan0", S_IFREG | S_IRWXU, 0);
}

static struct fuse_operations planet_ops{};

int main(int argc, char **argv)
{
    int exit_code = EXIT_SUCCESS;
    try {
        openlog("fuse_planet", LOG_CONS | LOG_PID, LOG_USER);
        ::syslog(LOG_INFO, "fuse_planetfs daemon started");
        planet_install_file_operations();
        planet_create_initial_fs_structure();
        planet_ops.getattr  = planet_getattr;
        planet_ops.mknod    = planet_mknod;
        planet_ops.mkdir    = planet_mkdir;
        planet_ops.chmod    = planet_chmod;
        planet_ops.chown    = planet_chown;
        planet_ops.utimens  = planet_utimens;
        planet_ops.open     = planet_open;
        planet_ops.read     = planet_read;
        planet_ops.write    = planet_write;
        planet_ops.readdir  = planet_readdir;
        planet_ops.release  = planet_release;
        exit_code = fuse_main(argc, argv, &planet_ops, nullptr);
        ::syslog(LOG_INFO, "fuse_planetfs daemon finished");
    } catch (std::exception& e) {
        ::syslog(LOG_ERR, "fatal error occurred: %s", e.what());
        exit_code = EXIT_FAILURE;
    }
    return exit_code;
}
<commit_msg>planet_utimens: fix bug updating wrong time<commit_after>#define FUSE_USE_VERSION 26
#define _FILE_OFFSET_BITS 64

#include <fuse.h>
#include <iostream>
#include <memory>
#include <functional>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <planet/common.hpp>
#include <planet/fs_core.hpp>
#include <planet/operation_layer.hpp>
#include <planet/planet_handle.hpp>
#include <planet/dns_op.hpp>
#include <planet/tcp_client_op.hpp>
#include <planet/tcp_server_op.hpp>
#include <planet/packet_socket_op.hpp>
#include <syslog.h>

#define LOG_EXCEPTION_MSG(e) \
    ::syslog(LOG_ERR, "%s: %s", __func__, (e).what());

// Core filesystem object
planet::core_file_system fs_root(S_IRWXU);

static int planet_getattr(char const *path, struct stat *stbuf)
{
    ::syslog(LOG_INFO, "%s: path=%s stbuf=%p", __func__, path, stbuf);
    int ret = 0;
    try {
        std::memset(stbuf, 0, sizeof (struct stat));
        fs_root.getattr(path, *stbuf);
        ::syslog(LOG_INFO, "getattr: path=%s size=%llu mode=%o nlink=%d",
            path, stbuf->st_size, stbuf->st_mode, stbuf->st_nlink);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

static int planet_mknod(char const *path, mode_t mode, dev_t device)
{
    ::syslog(LOG_INFO, "%s: path=%s mode=%o %lld", __func__, path, mode, device);
    int ret = 0;
    try {
        ret = fs_root.mknod(path, mode, device);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

static int planet_mkdir(char const *path, mode_t mode)
{
    ::syslog(LOG_INFO, "%s: path=%s mode=%o", __func__, path, mode);
    int ret = 0;
    try {
        ret = fs_root.mkdir(path, 0755 | S_IFDIR);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

static int planet_chmod(char const *path, mode_t mode)
{
    return 0;
}

static int planet_chown(char const *path, uid_t uid, gid_t gid)
{
    return 0;
}

static int planet_utimens(char const* path, struct timespec const tv[2])
{
    int ret = 0;
    try {
        namespace ch = std::chrono;
        if (auto entry = fs_root.get_entry_of(path)) {
            ch::nanoseconds nano_access(tv[0].tv_nsec), nano_mod(tv[1].tv_nsec);
            ch::seconds sec_access(tv[0].tv_sec), sec_mod(tv[1].tv_sec);
            planet::st_inode new_inode = entry->inode();
            new_inode.atime = decltype(new_inode.atime)
                (ch::duration_cast<decltype(new_inode.atime)::duration>(nano_access + sec_access));
            new_inode.mtime = decltype(new_inode.atime)
                (ch::duration_cast<decltype(new_inode.atime)::duration>(nano_mod + sec_mod));
            entry->inode(new_inode);
        } else
            throw planet::exception_errno(ENOENT);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

static int planet_open(char const *path, struct fuse_file_info *fi)
{
    ::syslog(LOG_INFO, "%s: path=%s fi=%p", __func__, path, fi);
    int ret = 0;
    try {
        planet::handle_t ph = fs_root.open(path);
        planet::set_handle_to(*fi, ph);
        ::syslog(LOG_INFO, "%s: handle=%d", __func__, ph);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

static int planet_read(char const *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
{
    ::syslog(LOG_INFO, "%s: path=%s buf=%p size=%d offset=%llu", __func__, path, buf, size, offset);
    int bytes_received;
    try {
        planet::handle_t ph = planet::get_handle_from(*fi);
        bytes_received = planet::read(ph, buf, size, offset);
        ::syslog(LOG_INFO, "%s: handle=%d bytes_received=%d", __func__, ph, bytes_received);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        bytes_received = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        bytes_received = -EIO;
    }
    return bytes_received;
}

static int planet_write(char const *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
{
    ::syslog(LOG_INFO, "%s: path=%s buf=%p size=%d offset=%llu", __func__, path, buf, size, offset);
    int bytes_transferred;
    try {
        planet::handle_t ph = planet::get_handle_from(*fi);
        bytes_transferred = planet::write(ph, buf, size, offset);
        ::syslog(LOG_INFO, "%s: handle=%d bytes_transferred=%d", __func__, ph, bytes_transferred);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        bytes_transferred = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        bytes_transferred = -EIO;
    }
    return bytes_transferred;
}

static int planet_readdir(char const *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
{
    ::syslog(LOG_INFO, "%s: path=%s buf=%p offset=%llu", __func__, path, buf, offset);
    int ret = 0;
    try {
        filler(buf, ".", nullptr, 0);
        filler(buf, "..", nullptr, 0);
        for (auto const& entry_name : fs_root.readdir(path))
            if (filler(buf, entry_name.c_str(), nullptr, 0))
                break;
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

static int planet_release(char const *path, struct fuse_file_info *fi)
{
    ::syslog(LOG_INFO, "%s: path=%s fi=%p", __func__, path, fi);
    int ret = 0;
    try {
        planet::handle_t ph = planet::get_handle_from(*fi);
        ::syslog(LOG_INFO, "%s: handle=%d", __func__, ph);
        ret = planet::close(ph);
    } catch (planet::exception_errno& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -e.get_errno();
    } catch (std::exception& e) {
        LOG_EXCEPTION_MSG(e);
        ret = -EIO;
    }
    return ret;
}

// Install certain file operations
void planet_install_file_operations()
{
    fs_root.install_op<planet::dns_op>();
    fs_root.install_op<planet::tcp_client_op>();
    fs_root.install_op<planet::tcp_server_op>(fs_root);
    fs_root.install_op<planet::packet_socket_op>();
    fs_root.install_op<planet::default_file_op>();
}

// Create initial filesystem structure
void planet_create_initial_fs_structure()
{
    fs_root.mkdir("/eth",       S_IFDIR | S_IRWXU);
    fs_root.mkdir("/ip",        S_IFDIR | S_IRWXU);
    fs_root.mkdir("/tcp",       S_IFDIR | S_IRWXU);
    fs_root.mknod("/dns",       S_IFREG | S_IRWXU, 0);
    fs_root.mknod("/eth/eth0",  S_IFREG | S_IRWXU, 0);
    fs_root.mknod("/eth/wlan0", S_IFREG | S_IRWXU, 0);
}

static struct fuse_operations planet_ops{};

int main(int argc, char **argv)
{
    int exit_code = EXIT_SUCCESS;
    try {
        openlog("fuse_planet", LOG_CONS | LOG_PID, LOG_USER);
        ::syslog(LOG_INFO, "fuse_planetfs daemon started");
        planet_install_file_operations();
        planet_create_initial_fs_structure();
        planet_ops.getattr  = planet_getattr;
        planet_ops.mknod    = planet_mknod;
        planet_ops.mkdir    = planet_mkdir;
        planet_ops.chmod    = planet_chmod;
        planet_ops.chown    = planet_chown;
        planet_ops.utimens  = planet_utimens;
        planet_ops.open     = planet_open;
        planet_ops.read     = planet_read;
        planet_ops.write    = planet_write;
        planet_ops.readdir  = planet_readdir;
        planet_ops.release  = planet_release;
        exit_code = fuse_main(argc, argv, &planet_ops, nullptr);
        ::syslog(LOG_INFO, "fuse_planetfs daemon finished");
    } catch (std::exception& e) {
        ::syslog(LOG_ERR, "fatal error occurred: %s", e.what());
        exit_code = EXIT_FAILURE;
    }
    return exit_code;
}
<|endoftext|>


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

#include "loader-png.h"

#include <cstring>
#include <cstdlib>

#include <png.h>

#include <dali/integration-api/bitmap.h>
#include <dali/integration-api/debug.h>
#include <dali/public-api/images/image.h>
#include <dali/public-api/images/image-attributes.h>
#include "dali/public-api/math/math-utils.h"
#include "dali/public-api/math/vector2.h"
#include "platform-capabilities.h"

namespace Dali
{

using Integration::Bitmap;
using Dali::Integration::PixelBuffer;

namespace SlpPlatform
{

namespace
{

// simple class to enforce clean-up of PNG structures
struct auto_png
{
  auto_png(png_structp& _png, png_infop& _info)
  : png(_png),
    info(_info)
  {
  }

  ~auto_png()
  {
    if(NULL != png)
    {
      png_destroy_read_struct(&png, &info, NULL);
    }
  }

  png_structp& png;
  png_infop& info;
}; // struct auto_png;

bool LoadPngHeader(FILE *fp, unsigned int &width, unsigned int &height, png_structp &png, png_infop &info)
{
  png_byte header[8] = { 0 };

  // Check header to see if it is a PNG file
  size_t size = fread(header, 1, 8, fp);
  if(size != 8)
  {
    return false;
  }

  if(png_sig_cmp(header, 0, 8))
  {
    return false;
  }

  png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if(!png)
  {
    DALI_LOG_WARNING("Can't create PNG read structure\n");
    return false;
  }

  info = png_create_info_struct(png);
  if(!info)
  {
    DALI_LOG_WARNING("png_create_info_struct failed\n");
    return false;
  }

  png_set_expand(png);

  if(setjmp(png_jmpbuf(png)))
  {
    DALI_LOG_WARNING("error during png_init_io\n");
    return false;
  }

  png_init_io(png, fp);
  png_set_sig_bytes(png, 8);

  // read image info
  png_read_info(png, info);

  // dimensions
  width = png_get_image_width(png, info);
  height = png_get_image_height(png, info);

  return true;
}

} // namespace - anonymous

bool LoadPngHeader(FILE *fp, const ImageAttributes& attributes, unsigned int &width, unsigned int &height )
{
  png_structp png = NULL;
  png_infop info = NULL;
  auto_png autoPng(png, info);

  bool success = LoadPngHeader(fp, width, height, png, info);

  return success;
}

bool LoadBitmapFromPng( FILE *fp, Bitmap& bitmap, ImageAttributes& attributes, const ResourceLoadingClient& client )
{
  png_structp png = NULL;
  png_infop info = NULL;
  auto_png autoPng(png, info);

  /// @todo: consider parameters
  unsigned int y;
  unsigned int width, height;
  unsigned char *pixels;
  png_bytep *rows;
  unsigned int bpp = 0; // bytes per pixel
  bool valid = false;

  // Load info from the header
  if( !LoadPngHeader(fp, width, height, png, info) )
  {
    return false;
  }

  Pixel::Format pixelFormat = Pixel::RGBA8888;

  // decide pixel format
  unsigned int colordepth = png_get_bit_depth(png, info);

  // Ask PNGLib to convert high precision images into something we can use:
  if (colordepth == 16)
  {
    png_set_strip_16(png);
    colordepth = 8;
  }

  png_byte colortype = png_get_color_type(png, info);

  if(colortype == PNG_COLOR_TYPE_GRAY)
  {
    switch( colordepth )
    {
      case 8:
      {
        pixelFormat = Pixel::L8;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_GRAY_ALPHA)
  {
    switch(colordepth)
    {
      case 8:
      {
        pixelFormat = Pixel::LA88;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_RGB )
  {
    switch(colordepth)
    {
      case 8:
      {
        pixelFormat = Pixel::RGB888;
        valid = true;
        break;
      }
      case 5:      /// @todo is this correct for RGB16 5-6-5 ?
      {
        pixelFormat = Pixel::RGB565;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_RGBA)
  {
    switch(colordepth)
    {
      case 8:
      {
        pixelFormat = Pixel::RGBA8888;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_PALETTE)
  {
    switch(colordepth)
    {
      case 2:
      case 4:
      case 8:
      {
        /* Expand paletted or RGB images with transparency to full alpha channels
         * so the data will be available as RGBA quartets. PNG_INFO_tRNS = 0x10
         */
        if(png_get_valid(png, info, PNG_INFO_tRNS) == 0x10)
        {
          pixelFormat = Pixel::RGBA8888;
          valid = true;
        }
        else
        {
          pixelFormat = Pixel::RGB888;
          png_set_packing(png);
          png_set_packswap(png);
          png_set_palette_to_rgb(png);
          valid = true;
        }
        break;
      }
      default:
      {
        break;
      }
    }
  }

  if( !valid )
  {
    DALI_LOG_WARNING( "Unsupported png format\n" );
    return false;
  }

  // bytes per pixel
  bpp = Pixel::GetBytesPerPixel(pixelFormat);

  png_read_update_info(png, info);

  if(setjmp(png_jmpbuf(png)))
  {
    DALI_LOG_WARNING("error during png_read_image\n");
    return false;
  }

  unsigned int rowBytes = png_get_rowbytes(png, info);

  unsigned int bufferWidth   = GetTextureDimension(width);
  unsigned int bufferHeight  = GetTextureDimension(height);
  unsigned int stride        = bufferWidth*bpp;

  // not sure if this ever happens
  if( rowBytes > stride )
  {
    stride = GetTextureDimension(rowBytes);
    bufferWidth = stride / bpp;
  }

  // decode the whole image into bitmap buffer
  pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(pixelFormat, width, height, bufferWidth, bufferHeight);

  DALI_ASSERT_DEBUG(pixels);
  rows = (png_bytep*) malloc(sizeof(png_bytep) * height);
  for(y=0; y<height; y++)
  {
    rows[y] = (png_byte*) (pixels + y * stride);
  }

  // decode image
  png_read_image(png, rows);

  // set the attributes
  attributes.SetSize( width, height );
  attributes.SetPixelFormat( pixelFormat );

  free(rows);

  return true;
}

// simple class to enforce clean-up of PNG structures
struct AutoPngWrite
{
  AutoPngWrite(png_structp& _png, png_infop& _info)
  : png(_png),
    info(_info)
  {
    DALI_ASSERT_DEBUG(&_png != 0 && &_info != 0);
  }

  ~AutoPngWrite()
  {
    if(NULL != png)
    {
      png_destroy_write_struct(&png, &info);
    }
  }

  png_structp& png;
  png_infop& info;
}; // struct AutoPngWrite;

namespace
{
  // Custom libpng write callbacks that buffer to a vector instead of a file:

  /**
   * extern "C" linkage is used because this is a callback that we pass to a C
   * library which is part of the underlying platform and so potentially compiled
   * as C rather than C++.
   * @see http://stackoverflow.com/a/2594222
   * */
  extern "C" void WriteData(png_structp png_ptr, png_bytep data, png_size_t length)
  {
    using Dali::SlpPlatform::PngBuffer;
    DALI_ASSERT_DEBUG(png_ptr && data);
    if(!png_ptr || !data)
    {
      return;
    }
    // Make sure we don't try to propagate a C++ exception up the call stack of a pure C library:
    try {
      // Recover our buffer for writing into:
      PngBuffer* const encoded_img = (PngBuffer*) png_get_io_ptr(png_ptr);
      if(encoded_img)
      {
        const PngBuffer::size_type bufferSize = encoded_img->size();
        encoded_img->resize(encoded_img->size() + length); //< Can throw OOM.
        PngBuffer::value_type* const bufferBack = &((*encoded_img)[bufferSize]);
        memcpy(bufferBack, data, length);
      }
      else
      {
        DALI_LOG_ERROR("PNG buffer for write to memory was passed from libpng as null.");
      }
    } catch(...)
    {
      DALI_LOG_ERROR("C++ Exception caught");
    }
  }

  /** Override the flush with a NOP to prevent libpng trying cstdlib file io. */
  extern "C" void FlushData(png_structp png_ptr)
  {
#ifdef DEBUG_ENABLED
    Debug::LogMessage(Debug::DebugInfo, "PNG Flush");
#endif // DEBUG_ENABLED
  }
}

/**
 * Potential improvements:
 * 1. Detect <= 256 colours and write in palette mode.
 * 2. Detect grayscale (will early-out quickly for colour images).
 * 3. Store colour space / gamma correction info related to the device screen?
 *    http://www.libpng.org/pub/png/book/chapter10.html
 * 4. Refactor with callers to write straight through to disk and save keeping a big buffer around.
 * 5. Prealloc buffer (reserve) to input size / <A number greater than 2 (expexcted few realloc but without using lots of memory) | 1 (expected zero reallocs but using a lot of memory)>.
 * 6. Set the modification time with png_set_tIME(png_ptr, info_ptr, mod_time);
 * 7. If caller asks for no compression, bypass libpng and blat raw data to
 *    disk, topped and tailed with header/tail blocks.
 */
bool EncodeToPng( const unsigned char* const pixelBuffer, PngBuffer& encodedPixels, std::size_t width, std::size_t height, Pixel::Format pixelFormat )
{
  // Translate pixel format enum:
  int pngPixelFormat = -1;
  unsigned pixelBytes = 0;
  bool rgbaOrder = true;

  // Account for RGB versus BGR and presence of alpha in input pixels:
  switch( pixelFormat )
  {
    case Pixel::RGB888:
    {
      pngPixelFormat = PNG_COLOR_TYPE_RGB;
      pixelBytes = 3;
      break;
    }
    case Pixel::BGRA8888:
    {
      rgbaOrder = false;
      ///! No break: fall through:
    }
    case Pixel::RGBA8888:
    {
      pngPixelFormat = PNG_COLOR_TYPE_RGB_ALPHA;
      pixelBytes = 4;
      break;
    }
    default:
    {
      DALI_LOG_ERROR( "Unsupported pixel format for encoding to PNG." );
      return false;
    }
  }

  const int interlace = PNG_INTERLACE_NONE;

  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if(!png_ptr)
  {
    return false;
  }
  /* Allocate/initialize the image information data.  REQUIRED */
  png_infop info_ptr = png_create_info_struct( png_ptr );
  if(!info_ptr)
  {
    png_destroy_write_struct(&png_ptr, NULL);
    return false;
  }

  /* Set error handling.  REQUIRED if you aren't supplying your own
   * error handling functions in the png_create_write_struct() call.
   */
  if(setjmp(png_jmpbuf(png_ptr)))
  {
    png_destroy_write_struct(&png_ptr, &info_ptr);
    return false;
  }

  // Since we are going to write to memory instead of a file, lets provide
  // libpng with a custom write function and ask it to pass back our
  // std::vector buffer each time it calls back to flush data to "file":
  png_set_write_fn(png_ptr, &encodedPixels, WriteData, FlushData);

  // png_set_compression_level( png_ptr, Z_BEST_COMPRESSION);
  png_set_compression_level(png_ptr, Z_BEST_SPEED);
  // png_set_compression_level( png_ptr, Z_NO_COMPRESSION); //! We could just generate png directly without libpng in this case.

  // Explicitly limit the number of filters used per scanline to speed us up:
  // png_set_filter(png_ptr, 0, PNG_FILTER_NONE); ///!ToDo: Try this once baseline profile is in place.
       // PNG_FILTER_SUB   |
       // PNG_FILTER_UP    |
       // PNG_FILTER_AVE   |
       // PNG_FILTER_PAETH |
       // PNG_ALL_FILTERS);
  // Play with Zlib parameters in optimisation phase:
    // png_set_compression_mem_level(png_ptr, 8);
    // png_set_compression_strategy(png_ptr,
        // Z_DEFAULT_STRATEGY);
    // png_set_compression_window_bits(png_ptr, 15);
    // png_set_compression_method(png_ptr, 8);
    // png_set_compression_buffer_size(png_ptr, 8192)

  // Let lib_png know if the pixel bytes are in BGR(A) order:
  if(!rgbaOrder)
  {
    png_set_bgr( png_ptr );
  }

  // Set the image information:
  png_set_IHDR(png_ptr, info_ptr, width, height, 8,
     pngPixelFormat, interlace,
     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  // Start to output the PNG data to our buffer:
  png_write_info(png_ptr, info_ptr);

  // Walk the rows:
  const unsigned row_step = width * pixelBytes;
  png_bytep row_ptr = const_cast<png_bytep>(pixelBuffer);
  const png_bytep row_end = row_ptr + height * row_step;
  for(; row_ptr < row_end; row_ptr += row_step)
  {
    png_write_row(png_ptr, row_ptr);
  }

  /* It is REQUIRED to call this to finish writing the rest of the file */
  png_write_end(png_ptr, info_ptr);
  /* Clean up after the write, and free any memory allocated */
  png_destroy_write_struct(&png_ptr, &info_ptr);
  return true;
}

} // namespace SlpPlatform

} // namespace Dali
<commit_msg>platform-abstractions: png: need zlib.h to use Z_BEST_SPEED<commit_after>/*
 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "loader-png.h"

#include <cstring>
#include <cstdlib>

#include <zlib.h>
#include <png.h>

#include <dali/integration-api/bitmap.h>
#include <dali/integration-api/debug.h>
#include <dali/public-api/images/image.h>
#include <dali/public-api/images/image-attributes.h>
#include "dali/public-api/math/math-utils.h"
#include "dali/public-api/math/vector2.h"
#include "platform-capabilities.h"

namespace Dali
{

using Integration::Bitmap;
using Dali::Integration::PixelBuffer;

namespace SlpPlatform
{

namespace
{

// simple class to enforce clean-up of PNG structures
struct auto_png
{
  auto_png(png_structp& _png, png_infop& _info)
  : png(_png),
    info(_info)
  {
  }

  ~auto_png()
  {
    if(NULL != png)
    {
      png_destroy_read_struct(&png, &info, NULL);
    }
  }

  png_structp& png;
  png_infop& info;
}; // struct auto_png;

bool LoadPngHeader(FILE *fp, unsigned int &width, unsigned int &height, png_structp &png, png_infop &info)
{
  png_byte header[8] = { 0 };

  // Check header to see if it is a PNG file
  size_t size = fread(header, 1, 8, fp);
  if(size != 8)
  {
    return false;
  }

  if(png_sig_cmp(header, 0, 8))
  {
    return false;
  }

  png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if(!png)
  {
    DALI_LOG_WARNING("Can't create PNG read structure\n");
    return false;
  }

  info = png_create_info_struct(png);
  if(!info)
  {
    DALI_LOG_WARNING("png_create_info_struct failed\n");
    return false;
  }

  png_set_expand(png);

  if(setjmp(png_jmpbuf(png)))
  {
    DALI_LOG_WARNING("error during png_init_io\n");
    return false;
  }

  png_init_io(png, fp);
  png_set_sig_bytes(png, 8);

  // read image info
  png_read_info(png, info);

  // dimensions
  width = png_get_image_width(png, info);
  height = png_get_image_height(png, info);

  return true;
}

} // namespace - anonymous

bool LoadPngHeader(FILE *fp, const ImageAttributes& attributes, unsigned int &width, unsigned int &height )
{
  png_structp png = NULL;
  png_infop info = NULL;
  auto_png autoPng(png, info);

  bool success = LoadPngHeader(fp, width, height, png, info);

  return success;
}

bool LoadBitmapFromPng( FILE *fp, Bitmap& bitmap, ImageAttributes& attributes, const ResourceLoadingClient& client )
{
  png_structp png = NULL;
  png_infop info = NULL;
  auto_png autoPng(png, info);

  /// @todo: consider parameters
  unsigned int y;
  unsigned int width, height;
  unsigned char *pixels;
  png_bytep *rows;
  unsigned int bpp = 0; // bytes per pixel
  bool valid = false;

  // Load info from the header
  if( !LoadPngHeader(fp, width, height, png, info) )
  {
    return false;
  }

  Pixel::Format pixelFormat = Pixel::RGBA8888;

  // decide pixel format
  unsigned int colordepth = png_get_bit_depth(png, info);

  // Ask PNGLib to convert high precision images into something we can use:
  if (colordepth == 16)
  {
    png_set_strip_16(png);
    colordepth = 8;
  }

  png_byte colortype = png_get_color_type(png, info);

  if(colortype == PNG_COLOR_TYPE_GRAY)
  {
    switch( colordepth )
    {
      case 8:
      {
        pixelFormat = Pixel::L8;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_GRAY_ALPHA)
  {
    switch(colordepth)
    {
      case 8:
      {
        pixelFormat = Pixel::LA88;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_RGB )
  {
    switch(colordepth)
    {
      case 8:
      {
        pixelFormat = Pixel::RGB888;
        valid = true;
        break;
      }
      case 5:      /// @todo is this correct for RGB16 5-6-5 ?
      {
        pixelFormat = Pixel::RGB565;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_RGBA)
  {
    switch(colordepth)
    {
      case 8:
      {
        pixelFormat = Pixel::RGBA8888;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_PALETTE)
  {
    switch(colordepth)
    {
      case 2:
      case 4:
      case 8:
      {
        /* Expand paletted or RGB images with transparency to full alpha channels
         * so the data will be available as RGBA quartets. PNG_INFO_tRNS = 0x10
         */
        if(png_get_valid(png, info, PNG_INFO_tRNS) == 0x10)
        {
          pixelFormat = Pixel::RGBA8888;
          valid = true;
        }
        else
        {
          pixelFormat = Pixel::RGB888;
          png_set_packing(png);
          png_set_packswap(png);
          png_set_palette_to_rgb(png);
          valid = true;
        }
        break;
      }
      default:
      {
        break;
      }
    }
  }

  if( !valid )
  {
    DALI_LOG_WARNING( "Unsupported png format\n" );
    return false;
  }

  // bytes per pixel
  bpp = Pixel::GetBytesPerPixel(pixelFormat);

  png_read_update_info(png, info);

  if(setjmp(png_jmpbuf(png)))
  {
    DALI_LOG_WARNING("error during png_read_image\n");
    return false;
  }

  unsigned int rowBytes = png_get_rowbytes(png, info);

  unsigned int bufferWidth   = GetTextureDimension(width);
  unsigned int bufferHeight  = GetTextureDimension(height);
  unsigned int stride        = bufferWidth*bpp;

  // not sure if this ever happens
  if( rowBytes > stride )
  {
    stride = GetTextureDimension(rowBytes);
    bufferWidth = stride / bpp;
  }

  // decode the whole image into bitmap buffer
  pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(pixelFormat, width, height, bufferWidth, bufferHeight);

  DALI_ASSERT_DEBUG(pixels);
  rows = (png_bytep*) malloc(sizeof(png_bytep) * height);
  for(y=0; y<height; y++)
  {
    rows[y] = (png_byte*) (pixels + y * stride);
  }

  // decode image
  png_read_image(png, rows);

  // set the attributes
  attributes.SetSize( width, height );
  attributes.SetPixelFormat( pixelFormat );

  free(rows);

  return true;
}

// simple class to enforce clean-up of PNG structures
struct AutoPngWrite
{
  AutoPngWrite(png_structp& _png, png_infop& _info)
  : png(_png),
    info(_info)
  {
    DALI_ASSERT_DEBUG(&_png != 0 && &_info != 0);
  }

  ~AutoPngWrite()
  {
    if(NULL != png)
    {
      png_destroy_write_struct(&png, &info);
    }
  }

  png_structp& png;
  png_infop& info;
}; // struct AutoPngWrite;

namespace
{
  // Custom libpng write callbacks that buffer to a vector instead of a file:

  /**
   * extern "C" linkage is used because this is a callback that we pass to a C
   * library which is part of the underlying platform and so potentially compiled
   * as C rather than C++.
   * @see http://stackoverflow.com/a/2594222
   * */
  extern "C" void WriteData(png_structp png_ptr, png_bytep data, png_size_t length)
  {
    using Dali::SlpPlatform::PngBuffer;
    DALI_ASSERT_DEBUG(png_ptr && data);
    if(!png_ptr || !data)
    {
      return;
    }
    // Make sure we don't try to propagate a C++ exception up the call stack of a pure C library:
    try {
      // Recover our buffer for writing into:
      PngBuffer* const encoded_img = (PngBuffer*) png_get_io_ptr(png_ptr);
      if(encoded_img)
      {
        const PngBuffer::size_type bufferSize = encoded_img->size();
        encoded_img->resize(encoded_img->size() + length); //< Can throw OOM.
        PngBuffer::value_type* const bufferBack = &((*encoded_img)[bufferSize]);
        memcpy(bufferBack, data, length);
      }
      else
      {
        DALI_LOG_ERROR("PNG buffer for write to memory was passed from libpng as null.");
      }
    } catch(...)
    {
      DALI_LOG_ERROR("C++ Exception caught");
    }
  }

  /** Override the flush with a NOP to prevent libpng trying cstdlib file io. */
  extern "C" void FlushData(png_structp png_ptr)
  {
#ifdef DEBUG_ENABLED
    Debug::LogMessage(Debug::DebugInfo, "PNG Flush");
#endif // DEBUG_ENABLED
  }
}

/**
 * Potential improvements:
 * 1. Detect <= 256 colours and write in palette mode.
 * 2. Detect grayscale (will early-out quickly for colour images).
 * 3. Store colour space / gamma correction info related to the device screen?
 *    http://www.libpng.org/pub/png/book/chapter10.html
 * 4. Refactor with callers to write straight through to disk and save keeping a big buffer around.
 * 5. Prealloc buffer (reserve) to input size / <A number greater than 2 (expexcted few realloc but without using lots of memory) | 1 (expected zero reallocs but using a lot of memory)>.
 * 6. Set the modification time with png_set_tIME(png_ptr, info_ptr, mod_time);
 * 7. If caller asks for no compression, bypass libpng and blat raw data to
 *    disk, topped and tailed with header/tail blocks.
 */
bool EncodeToPng( const unsigned char* const pixelBuffer, PngBuffer& encodedPixels, std::size_t width, std::size_t height, Pixel::Format pixelFormat )
{
  // Translate pixel format enum:
  int pngPixelFormat = -1;
  unsigned pixelBytes = 0;
  bool rgbaOrder = true;

  // Account for RGB versus BGR and presence of alpha in input pixels:
  switch( pixelFormat )
  {
    case Pixel::RGB888:
    {
      pngPixelFormat = PNG_COLOR_TYPE_RGB;
      pixelBytes = 3;
      break;
    }
    case Pixel::BGRA8888:
    {
      rgbaOrder = false;
      ///! No break: fall through:
    }
    case Pixel::RGBA8888:
    {
      pngPixelFormat = PNG_COLOR_TYPE_RGB_ALPHA;
      pixelBytes = 4;
      break;
    }
    default:
    {
      DALI_LOG_ERROR( "Unsupported pixel format for encoding to PNG." );
      return false;
    }
  }

  const int interlace = PNG_INTERLACE_NONE;

  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if(!png_ptr)
  {
    return false;
  }
  /* Allocate/initialize the image information data.  REQUIRED */
  png_infop info_ptr = png_create_info_struct( png_ptr );
  if(!info_ptr)
  {
    png_destroy_write_struct(&png_ptr, NULL);
    return false;
  }

  /* Set error handling.  REQUIRED if you aren't supplying your own
   * error handling functions in the png_create_write_struct() call.
   */
  if(setjmp(png_jmpbuf(png_ptr)))
  {
    png_destroy_write_struct(&png_ptr, &info_ptr);
    return false;
  }

  // Since we are going to write to memory instead of a file, lets provide
  // libpng with a custom write function and ask it to pass back our
  // std::vector buffer each time it calls back to flush data to "file":
  png_set_write_fn(png_ptr, &encodedPixels, WriteData, FlushData);

  // png_set_compression_level( png_ptr, Z_BEST_COMPRESSION);
  png_set_compression_level(png_ptr, Z_BEST_SPEED);
  // png_set_compression_level( png_ptr, Z_NO_COMPRESSION); //! We could just generate png directly without libpng in this case.

  // Explicitly limit the number of filters used per scanline to speed us up:
  // png_set_filter(png_ptr, 0, PNG_FILTER_NONE); ///!ToDo: Try this once baseline profile is in place.
       // PNG_FILTER_SUB   |
       // PNG_FILTER_UP    |
       // PNG_FILTER_AVE   |
       // PNG_FILTER_PAETH |
       // PNG_ALL_FILTERS);
  // Play with Zlib parameters in optimisation phase:
    // png_set_compression_mem_level(png_ptr, 8);
    // png_set_compression_strategy(png_ptr,
        // Z_DEFAULT_STRATEGY);
    // png_set_compression_window_bits(png_ptr, 15);
    // png_set_compression_method(png_ptr, 8);
    // png_set_compression_buffer_size(png_ptr, 8192)

  // Let lib_png know if the pixel bytes are in BGR(A) order:
  if(!rgbaOrder)
  {
    png_set_bgr( png_ptr );
  }

  // Set the image information:
  png_set_IHDR(png_ptr, info_ptr, width, height, 8,
     pngPixelFormat, interlace,
     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  // Start to output the PNG data to our buffer:
  png_write_info(png_ptr, info_ptr);

  // Walk the rows:
  const unsigned row_step = width * pixelBytes;
  png_bytep row_ptr = const_cast<png_bytep>(pixelBuffer);
  const png_bytep row_end = row_ptr + height * row_step;
  for(; row_ptr < row_end; row_ptr += row_step)
  {
    png_write_row(png_ptr, row_ptr);
  }

  /* It is REQUIRED to call this to finish writing the rest of the file */
  png_write_end(png_ptr, info_ptr);
  /* Clean up after the write, and free any memory allocated */
  png_destroy_write_struct(&png_ptr, &info_ptr);
  return true;
}

} // namespace SlpPlatform

} // namespace Dali
<|endoftext|>


<commit_before>/** @file
 *
 * @ingroup dspSoundFileLib
 *
 * @brief Loads soundfile data into a sample matrix
 *
 * @details This object collaborates with #TTSampleMatrix to load values from a sound file into the sample matrix.
 *
 * @see TTSampleMatrix
 *
 * @authors Nathan Wolek
 *
 * @copyright Copyright © 2013 by Nathan Wolek @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTSoundfileLoader.h"

#define thisTTClass			TTSoundfileLoader
#define thisTTClassName		"soundfile.loader"
#define thisTTClassTags		"audio, soundfile, buffer"

TTObjectBasePtr TTSoundfileLoader::instantiate(TTSymbol& name, TTValue& arguments)
{
	return new TTSoundfileLoader(arguments);
}

extern "C" void TTSoundfileLoader::registerClass()
{
	TTClassRegister(thisTTClassName, thisTTClassTags, TTSoundfileLoader::instantiate);
}

TTSoundfileLoader::TTSoundfileLoader(TTValue& arguments) :
TTSoundfile(arguments),
mTargetMatrix(NULL)
{
    // add the attributes and messages here
    //addMessageWithArguments(load);

    // initialize happens as part of the load
}

TTSoundfileLoader::~TTSoundfileLoader()
{
	mTargetMatrix = NULL; // reset to NULL for reference counting
}

// internal method used for initializing the mTargetMatrix
TTErr TTSoundfileLoader::setTargetMatrix(const TTSampleMatrixPtr newTargetMatrix)
{

    // Q: is there a way to query and make sure it is a TTSampleMatrix
    mTargetMatrix = newTargetMatrix;

    return kTTErrNone;

}

TTErr load(const TTValueRef input, TTValueRef unusedOutput)
{

    // set the mFilePath

    // set the mTargetMatrix

    // set the start and end points in source file

    // set the start and end points in mTargetMatrix

    // copy the samples (one at a time initially, to be optimized later)

    // QUESTIONS to consider
    // how will we handle multi channels?
    // should the sample rate get copied across?
    // if the size is different, what is the desired behavior?

    // reset? should mFilePath & mTargetMatrix be reset at the conclusion?

    return kTTErrNone;
}<commit_msg>first attempt at testing for valid samplematrix via the getName() method<commit_after>/** @file
 *
 * @ingroup dspSoundFileLib
 *
 * @brief Loads soundfile data into a sample matrix
 *
 * @details This object collaborates with #TTSampleMatrix to load values from a sound file into the sample matrix.
 *
 * @see TTSampleMatrix
 *
 * @authors Nathan Wolek
 *
 * @copyright Copyright © 2013 by Nathan Wolek @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTSoundfileLoader.h"

#define thisTTClass			TTSoundfileLoader
#define thisTTClassName		"soundfile.loader"
#define thisTTClassTags		"audio, soundfile, buffer"

TTObjectBasePtr TTSoundfileLoader::instantiate(TTSymbol& name, TTValue& arguments)
{
	return new TTSoundfileLoader(arguments);
}

extern "C" void TTSoundfileLoader::registerClass()
{
	TTClassRegister(thisTTClassName, thisTTClassTags, TTSoundfileLoader::instantiate);
}

TTSoundfileLoader::TTSoundfileLoader(TTValue& arguments) :
TTSoundfile(arguments),
mTargetMatrix(NULL)
{
    // add the attributes and messages here
    //addMessageWithArguments(load);

    // initialize happens as part of the load
}

TTSoundfileLoader::~TTSoundfileLoader()
{
	mTargetMatrix = NULL; // reset to NULL for reference counting
}

// internal method used for initializing the mTargetMatrix
TTErr TTSoundfileLoader::setTargetMatrix(const TTSampleMatrixPtr newTargetMatrix)
{
    // we will need a test here since this value will get passed via TTValue.
    // this is a first attempt.
    if (newTargetMatrix->getName() == "samplematrix")
    {
        mTargetMatrix = newTargetMatrix;
        return kTTErrNone;
    } else {
        return kTTErrInvalidValue;
    }

}

TTErr load(const TTValueRef input, TTValueRef unusedOutput)
{

    // set the mFilePath

    // set the mTargetMatrix

    // set the start and end points in source file

    // set the start and end points in mTargetMatrix

    // copy the samples (one at a time initially, to be optimized later)

    // QUESTIONS to consider
    // how will we handle multi channels?
    // should the sample rate get copied across?
    // if the size is different, what is the desired behavior?

    // reset? should mFilePath & mTargetMatrix be reset at the conclusion?

    return kTTErrNone;
}<|endoftext|>


<commit_before>// Copyright (c) 2012-2014 Eric M. Heien, Michael K. Sachs, John B. Rundle
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#include "ReadModelFile.h"

#include <iostream>
#include <iomanip>

void ReadModelFile::initDesc(const SimFramework *_sim) const {
}

/*!
 For dry runs the EqSim files are parsed as usual.
 */
void ReadModelFile::dryRun(SimFramework *_sim) {
    init(_sim);
}

/*!
 Parse the geometry file and optionally the condition and friction files.
 */
void ReadModelFile::init(SimFramework *_sim) {
    Simulation                  *sim = static_cast<Simulation *>(_sim);
    std::string                 file_name, file_type;
    quakelib::ModelWorld        world;
    quakelib::siterator         sit;
    quakelib::eiterator         eit;
    int                         err;
    quakelib::Conversion        c;

    file_name = sim->getModelFile();
    file_type = sim->getModelFileType();

    // Read the file into the world
    if (file_type == "text") {
        err = world.read_file_ascii(file_name);
    } else if (file_type == "hdf5") {
        err = world.read_file_hdf5(file_name);
    } else {
        sim->errConsole() << "ERROR: unknown file type " << file_type << std::endl;
        return;
    }

    // If there was an error then exit
    if (err) {
        sim->errConsole() << "ERROR: could not read file " << file_name << std::endl;
        return;
    }

    // Convert input world to simulation elements
    for (eit=world.begin_element(); eit!=world.end_element(); ++eit) {
        Block                   new_block;
        quakelib::SimElement    new_element;

        new_block.clear();
        new_element.clear();
        new_element = world.create_sim_element(eit->id());

        // Set SimElement values
        for (unsigned int i=0; i<3; ++i) new_block.set_vert(i, new_element.vert(i));

        new_block.set_is_quad(new_element.is_quad());
        new_block.set_rake(new_element.rake());
        new_block.set_slip_rate(new_element.slip_rate());
        new_block.set_aseismic(new_element.aseismic());
        new_block.set_lame_mu(new_element.lame_mu());
        new_block.set_lame_lambda(new_element.lame_lambda());
        new_block.set_max_slip(new_element.max_slip());

        // Set VQ specific values
        // Uncommenting the line setting fault_id (Kasey)

        new_block.setFaultID(world.section(eit->section_id()).fault_id());
        new_block.setSectionID(eit->section_id());    // TODO: add sections?

        BlockID bid = sim->addBlock(new_block);

        sim->setInitShearNormalStress(bid, 0, 0);
    }
}
<commit_msg>Fixed SimElement -> SimBlock init for stress_drops<commit_after>// Copyright (c) 2012-2014 Eric M. Heien, Michael K. Sachs, John B. Rundle
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#include "ReadModelFile.h"

#include <iostream>
#include <iomanip>

void ReadModelFile::initDesc(const SimFramework *_sim) const {
}

/*!
 For dry runs the EqSim files are parsed as usual.
 */
void ReadModelFile::dryRun(SimFramework *_sim) {
    init(_sim);
}

/*!
 Parse the geometry file and optionally the condition and friction files.
 */
void ReadModelFile::init(SimFramework *_sim) {
    Simulation                  *sim = static_cast<Simulation *>(_sim);
    std::string                 file_name, file_type;
    quakelib::ModelWorld        world;
    quakelib::siterator         sit;
    quakelib::eiterator         eit;
    int                         err;
    quakelib::Conversion        c;

    file_name = sim->getModelFile();
    file_type = sim->getModelFileType();

    // Read the file into the world
    if (file_type == "text") {
        err = world.read_file_ascii(file_name);
    } else if (file_type == "hdf5") {
        err = world.read_file_hdf5(file_name);
    } else {
        sim->errConsole() << "ERROR: unknown file type " << file_type << std::endl;
        return;
    }

    // If there was an error then exit
    if (err) {
        sim->errConsole() << "ERROR: could not read file " << file_name << std::endl;
        return;
    }

    // Convert input world to simulation elements
    for (eit=world.begin_element(); eit!=world.end_element(); ++eit) {
        Block                   new_block;
        quakelib::SimElement    new_element;

        new_block.clear();
        new_element.clear();
        new_element = world.create_sim_element(eit->id());

        // Set SimElement values
        for (unsigned int i=0; i<3; ++i) new_block.set_vert(i, new_element.vert(i));

        new_block.set_is_quad(new_element.is_quad());
        new_block.set_rake(new_element.rake());
        new_block.set_slip_rate(new_element.slip_rate());
        new_block.set_aseismic(new_element.aseismic());
        new_block.set_lame_mu(new_element.lame_mu());
        new_block.set_lame_lambda(new_element.lame_lambda());
        new_block.set_max_slip(new_element.max_slip());
        new_block.set_stress_drop(new_element.stress_drop());

        // Set VQ specific values
        // Uncommenting the line setting fault_id (Kasey)

        new_block.setFaultID(world.section(eit->section_id()).fault_id());
        new_block.setSectionID(eit->section_id());    // TODO: add sections?

        BlockID bid = sim->addBlock(new_block);

        sim->setInitShearNormalStress(bid, 0, 0);
    }
}
<|endoftext|>


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

#include <inttypes.h>

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

#include "app_framework.h"  // NOLINT
#include "firebase/app.h"
#include "firebase/log.h"
#include "firebase/remote_config.h"
#include "firebase/util.h"
#include "firebase_test_framework.h"  // NOLINT

// The TO_STRING macro is useful for command line defined strings as the quotes
// get stripped.
#define TO_STRING_EXPAND(X) #X
#define TO_STRING(X) TO_STRING_EXPAND(X)

// Path to the Firebase config file to load.
#ifdef FIREBASE_CONFIG
#define FIREBASE_CONFIG_STRING TO_STRING(FIREBASE_CONFIG)
#else
#define FIREBASE_CONFIG_STRING ""
#endif  // FIREBASE_CONFIG

namespace firebase_testapp_automated {

using app_framework::LogDebug;
using app_framework::LogWarning;
using app_framework::ProcessEvents;
using firebase::Future;
using firebase::remote_config::RemoteConfig;
using firebase_test_framework::FirebaseTest;

using testing::UnorderedElementsAre;

class FirebaseRemoteConfigTest : public FirebaseTest {
 public:
  FirebaseRemoteConfigTest();
  ~FirebaseRemoteConfigTest() override;

  void SetUp() override;
  void TearDown() override;

 protected:
  // Initialize Firebase App and Firebase Remote Config.
  void Initialize();
  // Shut down Firebase Remote Config and Firebase App.
  void Terminate();

  bool initialized_ = false;
  RemoteConfig* rc_ = nullptr;
};

FirebaseRemoteConfigTest::FirebaseRemoteConfigTest() : initialized_(false) {
  FindFirebaseConfig(FIREBASE_CONFIG_STRING);
}

FirebaseRemoteConfigTest::~FirebaseRemoteConfigTest() {
  // Must be cleaned up on exit.
  assert(app_ == nullptr);
  assert(rc_ == nullptr);
}

void FirebaseRemoteConfigTest::SetUp() {
  FirebaseTest::SetUp();
  Initialize();
}

void FirebaseRemoteConfigTest::TearDown() {
  // Delete the shared path, if there is one.
  Terminate();
  FirebaseTest::TearDown();
}

void FirebaseRemoteConfigTest::Initialize() {
  if (initialized_) return;
  SetLogLevel(app_framework::kDebug);

  InitializeApp();

  LogDebug("Initializing Firebase Remote Config.");

  ::firebase::ModuleInitializer initializer;

  void* ptr = nullptr;
  ptr = &rc_;
  initializer.Initialize(app_, ptr, [](::firebase::App* app, void* target) {
    LogDebug("Try to initialize Firebase RemoteConfig");
    RemoteConfig** rc_ptr = reinterpret_cast<RemoteConfig**>(target);
    *rc_ptr = RemoteConfig::GetInstance(app);
    return firebase::kInitResultSuccess;
  });

  WaitForCompletion(initializer.InitializeLastResult(), "Initialize");

  ASSERT_EQ(initializer.InitializeLastResult().error(), 0)
      << initializer.InitializeLastResult().error_message();

  LogDebug("Successfully initialized Firebase RemoteConfig.");

  initialized_ = true;
}

void FirebaseRemoteConfigTest::Terminate() {
  if (!initialized_) return;

  LogDebug("Shutdown the Remote Config library.");
  if (rc_) {
    delete rc_;
    rc_ = nullptr;
  }
  LogDebug("Terminating.");
  TerminateApp();

  initialized_ = false;

  ProcessEvents(100);
}

static const char* ValueSourceToString(
    firebase::remote_config::ValueSource source) {
  static const char* kSourceToString[] = {
      "Static",   // kValueSourceStaticValue
      "Remote",   // kValueSourceRemoteValue
      "Default",  // kValueSourceDefaultValue
  };
  return kSourceToString[source];
}

static const unsigned char kBinaryDefaults[] = {6, 0, 0, 6, 7, 3};
// NOLINTNEXTLINE
static const firebase::remote_config::ConfigKeyValueVariant defaults[] = {
    {"TestBoolean", false},
    {"TestLong", 42},
    {"TestDouble", 3.14},
    {"TestString", "Hello World"},
    {"TestData", firebase::Variant::FromStaticBlob(kBinaryDefaults,
                                                   sizeof(kBinaryDefaults))},
    {"TestDefaultOnly", "Default value that won't be overridden"}};

//   TestData     4321
//   TestDouble   625.63
//   TestLong     119
//   TestBoolean  true
//   TestString   This is a string
// NOLINTNEXTLINE
static const firebase::remote_config::ConfigKeyValueVariant kServerValue[] = {
    {"TestBoolean", true},
    {"TestLong", 119},
    {"TestDouble", 625.63},
    {"TestString", firebase::Variant::FromMutableString("This is a string")},
    {"TestData", 4321},
    {"TestDefaultOnly", firebase::Variant::FromMutableString(
                            "Default value that won't be overridden")}};

static Future<void> SetDefaults(RemoteConfig* rc) {
  size_t default_count = FIREBASE_ARRAYSIZE(defaults);
  return rc->SetDefaults(defaults, default_count);
}

static Future<void> SetDefaultConfigSettings(RemoteConfig* rc) {
  firebase::remote_config::ConfigSettings defaultConfigSettings;
  return rc->SetConfigSettings(defaultConfigSettings);
}

static Future<void> SetZeroIntervalConfigSettings(RemoteConfig* rc) {
  firebase::remote_config::ConfigSettings zeroIntervalConfigSettings;
  zeroIntervalConfigSettings.minimum_fetch_interval_in_milliseconds = 0;
  return rc->SetConfigSettings(zeroIntervalConfigSettings);
}

// Test cases below.

TEST_F(FirebaseRemoteConfigTest, TestInitializeAndTerminate) {
  // Already tested via SetUp() and TearDown().
}

TEST_F(FirebaseRemoteConfigTest, TestSetDefault) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));

  bool validated_defaults = true;
  firebase::remote_config::ValueInfo value_info;
  bool bool_value = rc_->GetBoolean("TestBoolean", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_FALSE(bool_value);
  } else {
    validated_defaults = false;
  }
  int64_t int64_value = rc_->GetLong("TestLong", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_EQ(int64_value, 42);
  } else {
    validated_defaults = false;
  }
  double double_value = rc_->GetDouble("TestDouble", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_NEAR(double_value, 3.14, 0.0001);
  } else {
    validated_defaults = false;
  }
  std::string string_value = rc_->GetString("TestString", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_EQ(string_value, "Hello World");
  } else {
    validated_defaults = false;
  }
  std::vector<unsigned char> blob_value =
      rc_->GetData("TestData");  //, &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_THAT(blob_value, testing::ElementsAreArray(kBinaryDefaults,
                                                      sizeof(kBinaryDefaults)));
  } else {
    validated_defaults = false;
  }

  if (!validated_defaults) {
    LogWarning(
        "Can't validate defaults, they've been overridden by server values.\n"
#if defined(__ANDROID__)
        "Delete the app's data and run this test again to test SetDefaults:\n"
        " adb shell pm clear [bundle ID]"
#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
        "Uninstall and re-install the app and run this again to test "
        "SetDefaults."
#else  // Desktop
        "Delete the Remote Config cache and run this test again to test "
        "SetDefaults:\n"
#if defined(_WIN32)
        " del remote_config_data"
#else
        " rm remote_config_data"
#endif  // defined(_WIN32)
#endif  // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
    );
  }
}

TEST_F(FirebaseRemoteConfigTest, TestGetKeys) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));

  std::vector<std::string> keys = rc_->GetKeys();
  EXPECT_THAT(
      keys, UnorderedElementsAre("TestBoolean", "TestLong", "TestDouble",
                                 "TestString", "TestData", "TestDefaultOnly"));
  std::vector<std::string> keys_subset = rc_->GetKeysByPrefix("TestD");
  EXPECT_THAT(keys_subset, UnorderedElementsAre("TestDouble", "TestData",
                                                "TestDefaultOnly"));
}

//   TestData     4321
//   TestDouble   625.63
//   TestLong     119
//   TestBoolean  true
//   TestString   This is a string
TEST_F(FirebaseRemoteConfigTest, TestGetAll) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->Fetch(); }, rc_),
      "Fetch"));
  EXPECT_TRUE(WaitForCompletion(rc_->Activate(), "Activate"));
  std::map<std::string, firebase::Variant> key_values = rc_->GetAll();
  EXPECT_EQ(key_values.size(), 6);

  for (auto key_valur_pair : kServerValue) {
    firebase::Variant k_value = key_valur_pair.value;
    firebase::Variant fetched_value = key_values[key_valur_pair.key];
    EXPECT_EQ(k_value.type(), fetched_value.type());
    EXPECT_EQ(k_value, fetched_value);
  }
}

/* The following test expects that you have your server values set to:
   TestData     4321
   TestDouble   625.63
   TestLong     119
   TestBoolean  true
   TestString   This is a string
 */
TEST_F(FirebaseRemoteConfigTest, TestFetch) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->Fetch(); }, rc_),
      "Fetch"));
  EXPECT_TRUE(WaitForCompletion(rc_->Activate(), "Activate"));
  LogDebug("Fetch time: %lld", rc_->GetInfo().fetch_time);
  firebase::remote_config::ValueInfo value_info;
  bool bool_value = rc_->GetBoolean("TestBoolean", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestBoolean source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_TRUE(bool_value);

  int64_t int64_value = rc_->GetLong("TestLong", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestLong source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_EQ(int64_value, 119);

  double double_value = rc_->GetDouble("TestDouble", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestDouble source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_NEAR(double_value, 625.63, 0.0001);

  std::string string_value = rc_->GetString("TestString", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestString source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_EQ(string_value, "This is a string");

  std::vector<unsigned char> blob_value =
      rc_->GetData("TestData");  //, &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestData source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";

  const unsigned char kExpectedBlobServerValue[] = {'4', '3', '2', '1'};
  EXPECT_THAT(blob_value,
              testing::ElementsAreArray(kExpectedBlobServerValue,
                                        sizeof(kExpectedBlobServerValue)));
}

TEST_F(FirebaseRemoteConfigTest, TestFetchInterval) {
  ASSERT_NE(rc_, nullptr);
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->FetchAndActivate(); }, rc_),
      "FetchAndActivate"));
  uint64_t current_fetch_time = rc_->GetInfo().fetch_time;
  // Making sure the config settings's fetch interval is 12 hours
  EXPECT_TRUE(WaitForCompletion(SetDefaultConfigSettings(rc_),
                                "SetDefaultConfigSettings"));
  // Second fetch, should respect fetch interval and don't change data.
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->Fetch(); }, rc_),
      "Fetch"));
  EXPECT_EQ(current_fetch_time, rc_->GetInfo().fetch_time);
  // Update fetch interval to 0
  EXPECT_TRUE(WaitForCompletion(SetZeroIntervalConfigSettings(rc_),
                                "SetZeroIntervalConfigSettings"));
  EXPECT_EQ(0, rc_->GetConfigSettings().minimum_fetch_interval_in_milliseconds);
  // Third fetch, this should operate the real fetch and update the fetch time.
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->Fetch(); }, rc_),
      "Fetch"));
  EXPECT_NE(current_fetch_time, rc_->GetInfo().fetch_time);
}

}  // namespace firebase_testapp_automated
<commit_msg>file format<commit_after>// Copyright 2019 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <inttypes.h>

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

#include "app_framework.h"  // NOLINT
#include "firebase/app.h"
#include "firebase/log.h"
#include "firebase/remote_config.h"
#include "firebase/util.h"
#include "firebase_test_framework.h"  // NOLINT

// The TO_STRING macro is useful for command line defined strings as the quotes
// get stripped.
#define TO_STRING_EXPAND(X) #X
#define TO_STRING(X) TO_STRING_EXPAND(X)

// Path to the Firebase config file to load.
#ifdef FIREBASE_CONFIG
#define FIREBASE_CONFIG_STRING TO_STRING(FIREBASE_CONFIG)
#else
#define FIREBASE_CONFIG_STRING ""
#endif  // FIREBASE_CONFIG

namespace firebase_testapp_automated {

using app_framework::LogDebug;
using app_framework::LogWarning;
using app_framework::ProcessEvents;
using firebase::Future;
using firebase::remote_config::RemoteConfig;
using firebase_test_framework::FirebaseTest;

using testing::UnorderedElementsAre;

class FirebaseRemoteConfigTest : public FirebaseTest {
 public:
  FirebaseRemoteConfigTest();
  ~FirebaseRemoteConfigTest() override;

  void SetUp() override;
  void TearDown() override;

 protected:
  // Initialize Firebase App and Firebase Remote Config.
  void Initialize();
  // Shut down Firebase Remote Config and Firebase App.
  void Terminate();

  bool initialized_ = false;
  RemoteConfig* rc_ = nullptr;
};

FirebaseRemoteConfigTest::FirebaseRemoteConfigTest() : initialized_(false) {
  FindFirebaseConfig(FIREBASE_CONFIG_STRING);
}

FirebaseRemoteConfigTest::~FirebaseRemoteConfigTest() {
  // Must be cleaned up on exit.
  assert(app_ == nullptr);
  assert(rc_ == nullptr);
}

void FirebaseRemoteConfigTest::SetUp() {
  FirebaseTest::SetUp();
  Initialize();
}

void FirebaseRemoteConfigTest::TearDown() {
  // Delete the shared path, if there is one.
  Terminate();
  FirebaseTest::TearDown();
}

void FirebaseRemoteConfigTest::Initialize() {
  if (initialized_) return;
  SetLogLevel(app_framework::kDebug);

  InitializeApp();

  LogDebug("Initializing Firebase Remote Config.");

  ::firebase::ModuleInitializer initializer;

  void* ptr = nullptr;
  ptr = &rc_;
  initializer.Initialize(app_, ptr, [](::firebase::App* app, void* target) {
    LogDebug("Try to initialize Firebase RemoteConfig");
    RemoteConfig** rc_ptr = reinterpret_cast<RemoteConfig**>(target);
    *rc_ptr = RemoteConfig::GetInstance(app);
    return firebase::kInitResultSuccess;
  });

  WaitForCompletion(initializer.InitializeLastResult(), "Initialize");

  ASSERT_EQ(initializer.InitializeLastResult().error(), 0)
      << initializer.InitializeLastResult().error_message();

  LogDebug("Successfully initialized Firebase RemoteConfig.");

  initialized_ = true;
}

void FirebaseRemoteConfigTest::Terminate() {
  if (!initialized_) return;

  LogDebug("Shutdown the Remote Config library.");
  if (rc_) {
    delete rc_;
    rc_ = nullptr;
  }
  LogDebug("Terminating.");
  TerminateApp();

  initialized_ = false;

  ProcessEvents(100);
}

static const char* ValueSourceToString(
    firebase::remote_config::ValueSource source) {
  static const char* kSourceToString[] = {
      "Static",   // kValueSourceStaticValue
      "Remote",   // kValueSourceRemoteValue
      "Default",  // kValueSourceDefaultValue
  };
  return kSourceToString[source];
}

static const unsigned char kBinaryDefaults[] = {6, 0, 0, 6, 7, 3};
// NOLINTNEXTLINE
static const firebase::remote_config::ConfigKeyValueVariant defaults[] = {
    {"TestBoolean", false},
    {"TestLong", 42},
    {"TestDouble", 3.14},
    {"TestString", "Hello World"},
    {"TestData", firebase::Variant::FromStaticBlob(kBinaryDefaults,
                                                   sizeof(kBinaryDefaults))},
    {"TestDefaultOnly", "Default value that won't be overridden"}};

//   TestData     4321
//   TestDouble   625.63
//   TestLong     119
//   TestBoolean  true
//   TestString   This is a string
// NOLINTNEXTLINE
static const firebase::remote_config::ConfigKeyValueVariant kServerValue[] = {
    {"TestBoolean", true},
    {"TestLong", 119},
    {"TestDouble", 625.63},
    {"TestString", firebase::Variant::FromMutableString("This is a string")},
    {"TestData", 4321},
    {"TestDefaultOnly", firebase::Variant::FromMutableString(
                            "Default value that won't be overridden")}};

static Future<void> SetDefaults(RemoteConfig* rc) {
  size_t default_count = FIREBASE_ARRAYSIZE(defaults);
  return rc->SetDefaults(defaults, default_count);
}

static Future<void> SetDefaultConfigSettings(RemoteConfig* rc) {
  firebase::remote_config::ConfigSettings defaultConfigSettings;
  return rc->SetConfigSettings(defaultConfigSettings);
}

static Future<void> SetZeroIntervalConfigSettings(RemoteConfig* rc) {
  firebase::remote_config::ConfigSettings zeroIntervalConfigSettings;
  zeroIntervalConfigSettings.minimum_fetch_interval_in_milliseconds = 0;
  return rc->SetConfigSettings(zeroIntervalConfigSettings);
}

// Test cases below.

TEST_F(FirebaseRemoteConfigTest, TestInitializeAndTerminate) {
  // Already tested via SetUp() and TearDown().
}

TEST_F(FirebaseRemoteConfigTest, TestSetDefault) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));

  bool validated_defaults = true;
  firebase::remote_config::ValueInfo value_info;
  bool bool_value = rc_->GetBoolean("TestBoolean", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_FALSE(bool_value);
  } else {
    validated_defaults = false;
  }
  int64_t int64_value = rc_->GetLong("TestLong", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_EQ(int64_value, 42);
  } else {
    validated_defaults = false;
  }
  double double_value = rc_->GetDouble("TestDouble", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_NEAR(double_value, 3.14, 0.0001);
  } else {
    validated_defaults = false;
  }
  std::string string_value = rc_->GetString("TestString", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_EQ(string_value, "Hello World");
  } else {
    validated_defaults = false;
  }
  std::vector<unsigned char> blob_value =
      rc_->GetData("TestData");  //, &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_THAT(blob_value, testing::ElementsAreArray(kBinaryDefaults,
                                                      sizeof(kBinaryDefaults)));
  } else {
    validated_defaults = false;
  }

  if (!validated_defaults) {
    LogWarning(
        "Can't validate defaults, they've been overridden by server values.\n"
#if defined(__ANDROID__)
        "Delete the app's data and run this test again to test SetDefaults:\n"
        " adb shell pm clear [bundle ID]"
#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
        "Uninstall and re-install the app and run this again to test "
        "SetDefaults."
#else  // Desktop
        "Delete the Remote Config cache and run this test again to test "
        "SetDefaults:\n"
#if defined(_WIN32)
        " del remote_config_data"
#else
        " rm remote_config_data"
#endif  // defined(_WIN32)
#endif  // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
    );
  }
}

TEST_F(FirebaseRemoteConfigTest, TestGetKeys) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));

  std::vector<std::string> keys = rc_->GetKeys();
  EXPECT_THAT(
      keys, UnorderedElementsAre("TestBoolean", "TestLong", "TestDouble",
                                 "TestString", "TestData", "TestDefaultOnly"));
  std::vector<std::string> keys_subset = rc_->GetKeysByPrefix("TestD");
  EXPECT_THAT(keys_subset, UnorderedElementsAre("TestDouble", "TestData",
                                                "TestDefaultOnly"));
}

//   TestData     4321
//   TestDouble   625.63
//   TestLong     119
//   TestBoolean  true
//   TestString   This is a string
TEST_F(FirebaseRemoteConfigTest, TestGetAll) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->Fetch(); }, rc_),
      "Fetch"));
  EXPECT_TRUE(WaitForCompletion(rc_->Activate(), "Activate"));
  std::map<std::string, firebase::Variant> key_values = rc_->GetAll();
  EXPECT_EQ(key_values.size(), 6);

  for (auto key_valur_pair : kServerValue) {
    firebase::Variant k_value = key_valur_pair.value;
    firebase::Variant fetched_value = key_values[key_valur_pair.key];
    EXPECT_EQ(k_value.type(), fetched_value.type());
    EXPECT_EQ(k_value, fetched_value);
  }
}

/* The following test expects that you have your server values set to:
   TestData     4321
   TestDouble   625.63
   TestLong     119
   TestBoolean  true
   TestString   This is a string
 */
TEST_F(FirebaseRemoteConfigTest, TestFetch) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->Fetch(); }, rc_),
      "Fetch"));
  EXPECT_TRUE(WaitForCompletion(rc_->Activate(), "Activate"));
  LogDebug("Fetch time: %lld", rc_->GetInfo().fetch_time);
  firebase::remote_config::ValueInfo value_info;
  bool bool_value = rc_->GetBoolean("TestBoolean", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestBoolean source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_TRUE(bool_value);

  int64_t int64_value = rc_->GetLong("TestLong", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestLong source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_EQ(int64_value, 119);

  double double_value = rc_->GetDouble("TestDouble", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestDouble source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_NEAR(double_value, 625.63, 0.0001);

  std::string string_value = rc_->GetString("TestString", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestString source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_EQ(string_value, "This is a string");

  std::vector<unsigned char> blob_value =
      rc_->GetData("TestData");  //, &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestData source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";

  const unsigned char kExpectedBlobServerValue[] = {'4', '3', '2', '1'};
  EXPECT_THAT(blob_value,
              testing::ElementsAreArray(kExpectedBlobServerValue,
                                        sizeof(kExpectedBlobServerValue)));
}

TEST_F(FirebaseRemoteConfigTest, TestFetchInterval) {
  ASSERT_NE(rc_, nullptr);
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->FetchAndActivate(); },
                   rc_),
      "FetchAndActivate"));
  uint64_t current_fetch_time = rc_->GetInfo().fetch_time;
  // Making sure the config settings's fetch interval is 12 hours
  EXPECT_TRUE(WaitForCompletion(SetDefaultConfigSettings(rc_),
                                "SetDefaultConfigSettings"));
  // Second fetch, should respect fetch interval and don't change data.
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->Fetch(); }, rc_),
      "Fetch"));
  EXPECT_EQ(current_fetch_time, rc_->GetInfo().fetch_time);
  // Update fetch interval to 0
  EXPECT_TRUE(WaitForCompletion(SetZeroIntervalConfigSettings(rc_),
                                "SetZeroIntervalConfigSettings"));
  EXPECT_EQ(0, rc_->GetConfigSettings().minimum_fetch_interval_in_milliseconds);
  // Third fetch, this should operate the real fetch and update the fetch time.
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->Fetch(); }, rc_),
      "Fetch"));
  EXPECT_NE(current_fetch_time, rc_->GetInfo().fetch_time);
}

}  // namespace firebase_testapp_automated
<|endoftext|>


<commit_before>/*-----------------------------------------------------------------------------------------------
The MIT License (MIT)

Copyright (c) 2015-2018 OSRE ( Open Source Render Engine ) by Kim Kulling

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-----------------------------------------------------------------------------------------------*/
#include <osre/IO/IOService.h>
#include <osre/Common/Tokenizer.h>
#include <osre/Common/Logger.h>
#include <src/Engine/IO/ZipFileSystem.h>
#include <src/Engine/IO/LocaleFileSystem.h>

IMPLEMENT_SINGLETON( ::OSRE::IO::IOService )

namespace OSRE {
namespace IO {

using namespace OSRE::Common;

static const String Tag = "IOService";
static const String Zip_Extension = "zip";

static AbstractFileSystem *createFS( const Uri &file ) {
    if ( !file.isValid() ) {
        return nullptr;
    }

    const String &schema( file.getScheme() );
    if( Zip_Extension == schema ) {
        return new ZipFileSystem( file );
    }

    return nullptr;
}

IOService::IOService()
: AbstractService( "io/ioserver" )
, m_mountedMap() {
    CREATE_SINGLETON( IOService );
}

IOService::~IOService() {
    DESTROY_SINGLETON( IOService );
}

bool IOService::onOpen() {
    // create the locale file system
    AbstractFileSystem *pFileSystem( nullptr );
    pFileSystem = new LocaleFileSystem;
    mountFileSystem( pFileSystem->getSchema(), pFileSystem );

    return true;
}

bool IOService::onClose() {
    return true;
}

bool IOService::onUpdate() {
    return true;
}

AbstractFileSystem *IOService::addFileSystem( const String &name, const Uri &file ) {
    if( file.isEmpty() || !file.isValid() ) {
        return nullptr;
    }

    AbstractFileSystem *fs( nullptr );
    if( fileExists( file ) ) {
        fs = createFS( file );
        if( fs ) {
            m_mountedMap[ name ] = fs;
        } else {
            osre_debug( Tag, "Cannot create file system " + file.getResource() );
        }
    }

    return fs;
}

void IOService::mountFileSystem( const String &schema, AbstractFileSystem *pFileSystem ) {
    assert( nullptr != pFileSystem );

    m_mountedMap[ schema ] = pFileSystem;
}

void IOService::umountFileSystem( const String &schema, AbstractFileSystem *pFileSystem ) {
    assert( nullptr != pFileSystem );

    MountedMap::iterator it = m_mountedMap.find( schema );
    if ( m_mountedMap.end() == it ) {
        return;
    }

    m_mountedMap.erase( it );
}

Stream *IOService::openStream( const Uri &file, Stream::AccessMode mode ) {
    Stream *pStream( nullptr );
    AbstractFileSystem *pFS = getFileSystem( file.getScheme() );
    if ( pFS ) {
        pStream  = pFS->open( file, mode );
    }

    return pStream;
}

void IOService::closeStream( Stream **ppStream ) {
    if( nullptr == ppStream ) {
        return;
    }

    const String &schema( (*ppStream)->getUri().getScheme() );
    AbstractFileSystem *pFS = getFileSystem( schema );
    if( pFS ) {
        pFS->close( ppStream );
    }
}

AbstractFileSystem *IOService::getFileSystem( const String &schema ) const {
    if ( m_mountedMap.empty() ) {
        return nullptr;
    }

    MountedMap::const_iterator it = m_mountedMap.find( schema );
    if ( m_mountedMap.end() != it ) {
        return it->second;
    }

    return nullptr;
}

bool IOService::fileExists( const Uri &file ) const {
    bool exists( false );
    AbstractFileSystem *fs = this->getFileSystem( file.getScheme() );
    if ( fs ) {
        exists = fs->fileExist( file );
    }

    return exists;
}

IOService *IOService::create() {
    return new IOService;
}

} // Namespace IO
} // Namespace OSRE
<commit_msg>Modelloading: add missing file system mount.<commit_after>/*-----------------------------------------------------------------------------------------------
The MIT License (MIT)

Copyright (c) 2015-2018 OSRE ( Open Source Render Engine ) by Kim Kulling

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-----------------------------------------------------------------------------------------------*/
#include <osre/IO/IOService.h>
#include <osre/Common/Tokenizer.h>
#include <osre/Common/Logger.h>
#include <src/Engine/IO/ZipFileSystem.h>
#include <src/Engine/IO/LocaleFileSystem.h>

IMPLEMENT_SINGLETON( ::OSRE::IO::IOService )

namespace OSRE {
namespace IO {

using namespace OSRE::Common;

static const String Tag = "IOService";
static const String Zip_Extension = "zip";

static AbstractFileSystem *createFS( const Uri &file ) {
    if ( !file.isValid() ) {
        return nullptr;
    }

    const String &schema( file.getScheme() );
    if( Zip_Extension == schema ) {
        return new ZipFileSystem( file );
    }

    return nullptr;
}

IOService::IOService()
: AbstractService( "io/ioserver" )
, m_mountedMap() {
    CREATE_SINGLETON( IOService );

    m_mountedMap["file"] = new LocaleFileSystem();
}

IOService::~IOService() {
    DESTROY_SINGLETON( IOService );
}

bool IOService::onOpen() {
    // create the locale file system
    AbstractFileSystem *pFileSystem( nullptr );
    pFileSystem = new LocaleFileSystem;
    mountFileSystem( pFileSystem->getSchema(), pFileSystem );

    return true;
}

bool IOService::onClose() {
    return true;
}

bool IOService::onUpdate() {
    return true;
}

AbstractFileSystem *IOService::addFileSystem( const String &name, const Uri &file ) {
    if( file.isEmpty() || !file.isValid() ) {
        return nullptr;
    }

    AbstractFileSystem *fs( nullptr );
    if( fileExists( file ) ) {
        fs = createFS( file );
        if( fs ) {
            m_mountedMap[ name ] = fs;
        } else {
            osre_debug( Tag, "Cannot create file system " + file.getResource() );
        }
    }

    return fs;
}

void IOService::mountFileSystem( const String &schema, AbstractFileSystem *pFileSystem ) {
    assert( nullptr != pFileSystem );

    m_mountedMap[ schema ] = pFileSystem;
}

void IOService::umountFileSystem( const String &schema, AbstractFileSystem *pFileSystem ) {
    assert( nullptr != pFileSystem );

    MountedMap::iterator it = m_mountedMap.find( schema );
    if ( m_mountedMap.end() == it ) {
        return;
    }

    m_mountedMap.erase( it );
}

Stream *IOService::openStream( const Uri &file, Stream::AccessMode mode ) {
    Stream *pStream( nullptr );
    AbstractFileSystem *pFS = getFileSystem( file.getScheme() );
    if ( pFS ) {
        pStream  = pFS->open( file, mode );
    }

    return pStream;
}

void IOService::closeStream( Stream **ppStream ) {
    if( nullptr == ppStream ) {
        return;
    }

    const String &schema( (*ppStream)->getUri().getScheme() );
    AbstractFileSystem *pFS = getFileSystem( schema );
    if( pFS ) {
        pFS->close( ppStream );
    }
}

AbstractFileSystem *IOService::getFileSystem( const String &schema ) const {
    if ( m_mountedMap.empty() ) {
        return nullptr;
    }

    MountedMap::const_iterator it = m_mountedMap.find( schema );
    if ( m_mountedMap.end() != it ) {
        return it->second;
    }

    return nullptr;
}

bool IOService::fileExists( const Uri &file ) const {
    bool exists( false );
    AbstractFileSystem *fs = this->getFileSystem( file.getScheme() );
    if ( fs ) {
        exists = fs->fileExist( file );
    }

    return exists;
}

IOService *IOService::create() {
    return new IOService;
}

} // Namespace IO
} // Namespace OSRE
<|endoftext|>