<commit_before>/* Copyright 2007-2015 QReal Research Group
 *
 * 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 "twoDDisplay.h"

using namespace trik::robotModel::twoD::parts;
using namespace kitBase::robotModel;

/// @todo: This constant adjusts screen coordinates shift. It must be 0.
const int yDisplayShift = 8;

Display::Display(const DeviceInfo &info
		, const PortInfo &port
		, twoDModel::engine::TwoDModelEngineInterface &engine)
	: robotModel::parts::TrikDisplay(info, port)
	, mEngine(engine)
	, mBackground(Qt::transparent)
	, mCurrentPenWidth(0)
	, mCurrentPenColor(Qt::black)
{
	mEngine.display()->setPainter(this);
}

void Display::setPainterColor(const QColor &color)
{
	mCurrentPenColor = color;
}

void Display::setPainterWidth(int penWidth)
{
	mCurrentPenWidth = penWidth;
}

void Display::drawPixel(int x, int y)
{
	mPixels << PixelCoordinates(x, y, mCurrentPenColor, mCurrentPenWidth);
	mEngine.display()->repaintDisplay();
}

void Display::drawLine(int x1, int y1, int x2, int y2)
{
	mLines << LineCoordinates(x1, y1, x2, y2, mCurrentPenColor, mCurrentPenWidth);
	mEngine.display()->repaintDisplay();
}

void Display::drawRect(int x, int y, int width, int height)
{
	mRects << RectCoordinates(x, y, width, height, mCurrentPenColor, mCurrentPenWidth);
	mEngine.display()->repaintDisplay();
}

void Display::drawEllipse(int x, int y, int width, int height)
{
	mEllipses << EllipseCoordinates(x, y, width, height, mCurrentPenColor, mCurrentPenWidth);
	mEngine.display()->repaintDisplay();
}

void Display::drawArc(int x, int y, int width, int height, int startAngle, int spanAngle)
{
	mArcs << ArcCoordinates(x, y, width, height, startAngle, spanAngle, mCurrentPenColor, mCurrentPenWidth);
	mEngine.display()->repaintDisplay();
}

void Display::drawSmile(bool sad)
{
	mCurrentImage = QImage(sad ? ":/icons/sadSmile.png" : ":/icons/smile.png");
	mEngine.display()->repaintDisplay();
}

void Display::setBackground(const QColor &color)
{
	mBackground = color;
	mEngine.display()->repaintDisplay();
}

void Display::printText(int x, int y, const QString &text)
{
	mLabels[qMakePair(x, y + yDisplayShift)] = {text, mCurrentPenColor};
	mEngine.display()->repaintDisplay();
}

void Display::clearScreen()
{
	mCurrentImage = QImage();
	mBackground = Qt::transparent;
	mLabels.clear();
	mPixels.clear();
	mLines.clear();
	mRects.clear();
	mEllipses.clear();
	mArcs.clear();
	mCurrentPenWidth = 0;
	mCurrentPenColor = Qt::black;
	if (mEngine.display()) {
		mEngine.display()->repaintDisplay();
	}
}

void Display::paint(QPainter *painter)
{
	const QRect displayRect(0, 0, mEngine.display()->displayWidth(), mEngine.display()->displayHeight());
	painter->save();
	painter->setPen(mBackground);
	painter->setBrush(mBackground);
	painter->drawRect(displayRect);
	painter->drawImage(displayRect, mCurrentImage);

	painter->restore();

	painter->save();
	painter->setPen(Qt::black);

	for (QPair<int, int> const &point : mLabels.keys()) {
		/// @todo: Honest labels must be here, without text overlapping.
		painter->setPen(QPen(mLabels[point].second, 0, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
		painter->drawText(QPoint(point.first, point.second), mLabels[point].first);
	}

	for (int i = 0; i < mPixels.length(); ++i) {
		painter->setPen(QPen(mPixels.at(i).color, mPixels.at(i).penWidth, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
		painter->drawPoint(mPixels.at(i).coord.x(), mPixels.at(i).coord.y());
	}

	for (int i = 0; i < mLines.length(); ++i) {
		painter->setPen(QPen(mLines.at(i).color, mLines.at(i).penWidth, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
		painter->drawLine(mLines.at(i).line.x1(), mLines.at(i).line.y1()
				, mLines.at(i).line.x2(), mLines.at(i).line.y2());
	}

	for (int i = 0; i < mRects.length(); ++i) {
		painter->setPen(QPen(mRects.at(i).color, mRects.at(i).penWidth, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
		painter->drawRect(mRects.at(i).rect.x(), mRects.at(i).rect.y()
				, mRects.at(i).rect.width(), mRects.at(i).rect.height());
	}

	for (int i = 0; i < mEllipses.length(); ++i) {
		painter->setPen(QPen(mEllipses.at(i).color, mEllipses.at(i).penWidth, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
		painter->drawEllipse(mEllipses.at(i).ellipse.x(), mEllipses.at(i).ellipse.y()
				, mEllipses.at(i).ellipse.width(), mEllipses.at(i).ellipse.height());
	}

	for (int i = 0; i < mArcs.length(); ++i) {
		painter->setPen(QPen(mArcs.at(i).color, mArcs.at(i).penWidth, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
		painter->drawArc(mArcs.at(i).arc.x(), mArcs.at(i).arc.y()
				, mArcs.at(i).arc.width(), mArcs.at(i).arc.height()
				, mArcs.at(i).startAngle, mArcs.at(i).spanAngle);
	}

	painter->restore();
}

void Display::clear()
{
	clearScreen();
}
<commit_msg>TRIK screen emulator clearing does not clear the background [ci skip]<commit_after>/* Copyright 2007-2015 QReal Research Group
 *
 * 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 "twoDDisplay.h"

using namespace trik::robotModel::twoD::parts;
using namespace kitBase::robotModel;

/// @todo: This constant adjusts screen coordinates shift. It must be 0.
const int yDisplayShift = 8;

Display::Display(const DeviceInfo &info
		, const PortInfo &port
		, twoDModel::engine::TwoDModelEngineInterface &engine)
	: robotModel::parts::TrikDisplay(info, port)
	, mEngine(engine)
	, mBackground(Qt::transparent)
	, mCurrentPenWidth(0)
	, mCurrentPenColor(Qt::black)
{
	mEngine.display()->setPainter(this);
}

void Display::setPainterColor(const QColor &color)
{
	mCurrentPenColor = color;
}

void Display::setPainterWidth(int penWidth)
{
	mCurrentPenWidth = penWidth;
}

void Display::drawPixel(int x, int y)
{
	mPixels << PixelCoordinates(x, y, mCurrentPenColor, mCurrentPenWidth);
	mEngine.display()->repaintDisplay();
}

void Display::drawLine(int x1, int y1, int x2, int y2)
{
	mLines << LineCoordinates(x1, y1, x2, y2, mCurrentPenColor, mCurrentPenWidth);
	mEngine.display()->repaintDisplay();
}

void Display::drawRect(int x, int y, int width, int height)
{
	mRects << RectCoordinates(x, y, width, height, mCurrentPenColor, mCurrentPenWidth);
	mEngine.display()->repaintDisplay();
}

void Display::drawEllipse(int x, int y, int width, int height)
{
	mEllipses << EllipseCoordinates(x, y, width, height, mCurrentPenColor, mCurrentPenWidth);
	mEngine.display()->repaintDisplay();
}

void Display::drawArc(int x, int y, int width, int height, int startAngle, int spanAngle)
{
	mArcs << ArcCoordinates(x, y, width, height, startAngle, spanAngle, mCurrentPenColor, mCurrentPenWidth);
	mEngine.display()->repaintDisplay();
}

void Display::drawSmile(bool sad)
{
	mCurrentImage = QImage(sad ? ":/icons/sadSmile.png" : ":/icons/smile.png");
	mEngine.display()->repaintDisplay();
}

void Display::setBackground(const QColor &color)
{
	mBackground = color;
	mEngine.display()->repaintDisplay();
}

void Display::printText(int x, int y, const QString &text)
{
	mLabels[qMakePair(x, y + yDisplayShift)] = {text, mCurrentPenColor};
	mEngine.display()->repaintDisplay();
}

void Display::clearScreen()
{
	// Background color is not cleared
	mCurrentImage = QImage();
	mLabels.clear();
	mPixels.clear();
	mLines.clear();
	mRects.clear();
	mEllipses.clear();
	mArcs.clear();
	mCurrentPenWidth = 0;
	mCurrentPenColor = Qt::black;
	if (mEngine.display()) {
		mEngine.display()->repaintDisplay();
	}
}

void Display::paint(QPainter *painter)
{
	const QRect displayRect(0, 0, mEngine.display()->displayWidth(), mEngine.display()->displayHeight());
	painter->save();
	painter->setPen(mBackground);
	painter->setBrush(mBackground);
	painter->drawRect(displayRect);
	painter->drawImage(displayRect, mCurrentImage);

	painter->restore();

	painter->save();
	painter->setPen(Qt::black);

	for (QPair<int, int> const &point : mLabels.keys()) {
		/// @todo: Honest labels must be here, without text overlapping.
		painter->setPen(QPen(mLabels[point].second, 0, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
		painter->drawText(QPoint(point.first, point.second), mLabels[point].first);
	}

	for (int i = 0; i < mPixels.length(); ++i) {
		painter->setPen(QPen(mPixels.at(i).color, mPixels.at(i).penWidth, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
		painter->drawPoint(mPixels.at(i).coord.x(), mPixels.at(i).coord.y());
	}

	for (int i = 0; i < mLines.length(); ++i) {
		painter->setPen(QPen(mLines.at(i).color, mLines.at(i).penWidth, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
		painter->drawLine(mLines.at(i).line.x1(), mLines.at(i).line.y1()
				, mLines.at(i).line.x2(), mLines.at(i).line.y2());
	}

	for (int i = 0; i < mRects.length(); ++i) {
		painter->setPen(QPen(mRects.at(i).color, mRects.at(i).penWidth, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
		painter->drawRect(mRects.at(i).rect.x(), mRects.at(i).rect.y()
				, mRects.at(i).rect.width(), mRects.at(i).rect.height());
	}

	for (int i = 0; i < mEllipses.length(); ++i) {
		painter->setPen(QPen(mEllipses.at(i).color, mEllipses.at(i).penWidth, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
		painter->drawEllipse(mEllipses.at(i).ellipse.x(), mEllipses.at(i).ellipse.y()
				, mEllipses.at(i).ellipse.width(), mEllipses.at(i).ellipse.height());
	}

	for (int i = 0; i < mArcs.length(); ++i) {
		painter->setPen(QPen(mArcs.at(i).color, mArcs.at(i).penWidth, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin));
		painter->drawArc(mArcs.at(i).arc.x(), mArcs.at(i).arc.y()
				, mArcs.at(i).arc.width(), mArcs.at(i).arc.height()
				, mArcs.at(i).startAngle, mArcs.at(i).spanAngle);
	}

	painter->restore();
}

void Display::clear()
{
	clearScreen();
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

#ifndef __FS_HPP__
#define __FS_HPP__

#include <fstab.h>
#include <mntent.h>

#include <sys/mount.h>
#include <sys/types.h>

#include <string>
#include <vector>

#include <stout/nothing.hpp>
#include <stout/option.hpp>
#include <stout/try.hpp>

namespace mesos {
namespace internal {
namespace fs {

// TODO(idownes): These three variations on mount information should
// be consolidated and moved to stout, along with mount and umount.

// Structure describing the per-process mounts as found in
// /proc/[pid]/mountinfo. In particular, entries in this table specify
// the propagation properties of mounts, information not present in
// the MountTable or FileSystemTable. Entry order is preserved when
// parsing /proc/[pid]/mountinfo.
struct MountInfoTable {
  // Structure describing an individual /proc/[pid]/mountinfo entry.
  // See the /proc/[pid]/mountinfo section in 'man proc' for further
  // details on each field.
  struct Entry {
    Entry() {}

    int id;                     // mountinfo[1]: mount ID.
    int parent;                 // mountinfo[2]: parent ID.
    dev_t devno;                // mountinfo[3]: st_dev.

    std::string root;           // mountinfo[4]: root of the mount.
    std::string target;         // mountinfo[5]: mount point.

    // Filesystem independent (VFS) options, e.g., "rw,noatime".
    std::string vfsOptions;     // mountinfo[6]: per-mount options.
    // Filesystem dependent options, e.g., "rw,memory" for a memory
    // cgroup filesystem.
    std::string fsOptions;      // mountinfo[11]: per-block options.

    // Current possible optional fields include shared:X, master:X,
    // propagate_from:X, unbindable.
    std::string optionalFields; // mountinfo[7]: optional fields.

    // mountinfo[8] is a separator.

    std::string type;           // mountinfo[9]: filesystem type.
    std::string source;         // mountinfo[10]: source dev, other.

    static Try<Entry> parse(const std::string& s);
  };

  // If pid is None() the "self" is used, i.e., the mountinfo table
  // for the calling process.
  static Try<MountInfoTable> read(const Option<pid_t>& pid = None());

  std::vector<Entry> entries;
};

// Structure describing a mount table (e.g. /etc/mtab or /proc/mounts).
struct MountTable {
  // Structure describing a mount table entry. This is a wrapper for struct
  // mntent defined in <mntent.h>.
  struct Entry {
    Entry() : freq(0), passno(0) {}

    Entry(const std::string& _fsname,
          const std::string& _dir,
          const std::string& _type,
          const std::string& _opts,
          int _freq,
          int _passno)
      : fsname(_fsname),
        dir(_dir),
        type(_type),
        opts(_opts),
        freq(_freq),
        passno(_passno)
    {}

    // Check whether a given mount option exists in a mount table entry.
    // @param   option    The given mount option.
    // @return  Whether the given mount option exists.
    bool hasOption(const std::string& option) const;

    std::string fsname; // Device or server for filesystem.
    std::string dir;    // Directory mounted on.
    std::string type;   // Type of filesystem: ufs, nfs, etc.
    std::string opts;   // Comma-separated options for fs.
    int freq;           // Dump frequency (in days).
    int passno;         // Pass number for `fsck'.
  };

  // Read the mount table from a file.
  // @param   path    The path of the file storing the mount table.
  // @return  An instance of MountTable if success.
  static Try<MountTable> read(const std::string& path);

  std::vector<Entry> entries;
};

// Structure describing a file system table (e.g. /etc/fstab).
struct FileSystemTable {
  // Structure describing a file system table entry. This is a wrapper for
  // struct fstab defined in <fstab.h>
  struct Entry {
    Entry() : freq(0), passno(0) {}

    Entry(const std::string& _spec,
          const std::string& _file,
          const std::string& _vfstype,
          const std::string& _mntops,
          const std::string& _type,
          int _freq,
          int _passno)
      : spec(_spec),
        file(_file),
        vfstype(_vfstype),
        mntops(_mntops),
        type(_type),
        freq(_freq),
        passno(_passno)
    {}

    std::string spec;     // Block special device name.
    std::string file;     // File system path prefix.
    std::string vfstype;  // File system type, ufs, nfs.
    std::string mntops;   // Mount options ala -o.
    std::string type;     // FSTAB_* from fs_mntops.
    int freq;             // Dump frequency, in days.
    int passno;           // Pass number on parallel dump.
  };

  // Read the file system table from a file.
  // @param   path    The path of the file storing the file system table.
  // @return  An instance of FileSystemTable if success.
  static Try<FileSystemTable> read();

  std::vector<Entry> entries;
};

// Mount a file system.
// @param   source    Specify the file system (often a device name but
//                    it can also be a directory for a bind mount).
//                    If None(), NULL will be passed as a dummy
//                    argument to mount(), i.e., it is not used for
//                    the specified mount operation. For example, you
//                    can mount a filesystem specified in /etc/fstab
//                    by just specifying the target.
// @param   target    Directory to be attached to.
// @param   type      File system type (listed in /proc/filesystems).
//                    If None(), NULL will be passed as a dummy
//                    argument to mount(), i.e., it is not used for
//                    the specified mount operation. For example, it
//                    should be None() for a bind mount as it will
//                    inherit the type of the source.
// @param   flags     Mount flags.
// @param   data      Extra data interpreted by different file systems.
// @return  Whether the mount operation succeeds.
Try<Nothing> mount(const Option<std::string>& source,
                   const std::string& target,
                   const Option<std::string>& type,
                   unsigned long flags,
                   const void* data);

// Unmount a file system.
// @param   target    The (topmost) directory where the file system attaches.
// @param   flags     Unmount flags.
// @return  Whether the unmount operation succeeds.
Try<Nothing> unmount(const std::string& target, int flags = 0);

// Change the root filesystem.
Try<Nothing> pivot_root(const std::string& newRoot, const std::string& putOld);

} // namespace fs {
} // namespace internal {
} // namespace mesos {

#endif // __FS_HPP__
<commit_msg>Define all MS_* mount flags.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

#ifndef __FS_HPP__
#define __FS_HPP__

#include <fstab.h>
#include <mntent.h>

#include <sys/mount.h>
#include <sys/types.h>

#include <string>
#include <vector>

#include <stout/nothing.hpp>
#include <stout/option.hpp>
#include <stout/try.hpp>

// Define relevant MS_* flags for old includes.
// This is taken from the enum in sys/mount.h.
#ifndef MS_RDONLY
#define MS_RDONLY 1
#endif

#ifndef MS_NOSUID
#define MS_NOSUID 2
#endif

#ifndef MS_NODEV
#define MS_NODEV 4
#endif

#ifndef MS_NOEXEC
#define MS_NOEXEC 8
#endif

#ifndef MS_SYNCHRONOUS
#define MS_SYNCHRONOUS 16
#endif

#ifndef MS_REMOUNT
#define MS_REMOUNT 32
#endif

#ifndef MS_MANDLOCK
#define MS_MANDLOCK 64
#endif

#ifndef MS_DIRSYNC
#define MS_DIRSYNC 128
#endif

#ifndef MS_NOATIME
#define MS_NOATIME 1024
#endif

#ifndef MS_NODIRATIME
#define MS_NODIRATIME 2048
#endif

#ifndef MS_BIND
#define MS_BIND 4096
#endif

#ifndef MS_MOVE
#define MS_MOVE 8192
#endif

#ifndef MS_REC
#define MS_REC 16384
#endif

#ifndef MS_SILENT
#define MS_SILENT 32768
#endif

#ifndef MS_POSIXACL
#define MS_POSIXACL (1 << 16)
#endif

#ifndef MS_UNBINDABLE
#define MS_UNBINDABLE (1 << 17)
#endif

#ifndef MS_PRIVATE
#define MS_PRIVATE (1 << 18)
#endif

#ifndef MS_SLAVE
#define MS_SLAVE (1 << 19)
#endif

#ifndef MS_SHARED
#define MS_SHARED (1 << 20)
#endif

#ifndef MS_RELATIME
#define MS_RELATIME (1 << 21)
#endif

#ifndef MS_KERNMOUNT
#define MS_KERNMOUNT (1 << 22)
#endif

#ifndef MS_I_VERSION
#define MS_I_VERSION (1 << 23)
#endif

#ifndef MS_STRICTATIME
#define MS_STRICTATIME (1 << 24)
#endif

#ifndef MS_ACTIVE
#define MS_ACTIVE (1 << 30)
#endif

#ifndef MS_NOUSER
#define MS_NOUSER (1 << 31)
#endif

#ifndef MNT_FORCE
#define MNT_FORCE 1
#endif

#ifndef MNT_DETACH
#define MNT_DETACH 2
#endif

#ifndef MNT_EXPIRE
#define MNT_EXPIRE 4
#endif

#ifndef UMOUNT_NOFOLLOW
#define UMOUNT_NOFOLLOW 8
#endif

namespace mesos {
namespace internal {
namespace fs {

// TODO(idownes): These three variations on mount information should
// be consolidated and moved to stout, along with mount and umount.

// Structure describing the per-process mounts as found in
// /proc/[pid]/mountinfo. In particular, entries in this table specify
// the propagation properties of mounts, information not present in
// the MountTable or FileSystemTable. Entry order is preserved when
// parsing /proc/[pid]/mountinfo.
struct MountInfoTable {
  // Structure describing an individual /proc/[pid]/mountinfo entry.
  // See the /proc/[pid]/mountinfo section in 'man proc' for further
  // details on each field.
  struct Entry {
    Entry() {}

    int id;                     // mountinfo[1]: mount ID.
    int parent;                 // mountinfo[2]: parent ID.
    dev_t devno;                // mountinfo[3]: st_dev.

    std::string root;           // mountinfo[4]: root of the mount.
    std::string target;         // mountinfo[5]: mount point.

    // Filesystem independent (VFS) options, e.g., "rw,noatime".
    std::string vfsOptions;     // mountinfo[6]: per-mount options.
    // Filesystem dependent options, e.g., "rw,memory" for a memory
    // cgroup filesystem.
    std::string fsOptions;      // mountinfo[11]: per-block options.

    // Current possible optional fields include shared:X, master:X,
    // propagate_from:X, unbindable.
    std::string optionalFields; // mountinfo[7]: optional fields.

    // mountinfo[8] is a separator.

    std::string type;           // mountinfo[9]: filesystem type.
    std::string source;         // mountinfo[10]: source dev, other.

    static Try<Entry> parse(const std::string& s);
  };

  // If pid is None() the "self" is used, i.e., the mountinfo table
  // for the calling process.
  static Try<MountInfoTable> read(const Option<pid_t>& pid = None());

  std::vector<Entry> entries;
};

// Structure describing a mount table (e.g. /etc/mtab or /proc/mounts).
struct MountTable {
  // Structure describing a mount table entry. This is a wrapper for struct
  // mntent defined in <mntent.h>.
  struct Entry {
    Entry() : freq(0), passno(0) {}

    Entry(const std::string& _fsname,
          const std::string& _dir,
          const std::string& _type,
          const std::string& _opts,
          int _freq,
          int _passno)
      : fsname(_fsname),
        dir(_dir),
        type(_type),
        opts(_opts),
        freq(_freq),
        passno(_passno)
    {}

    // Check whether a given mount option exists in a mount table entry.
    // @param   option    The given mount option.
    // @return  Whether the given mount option exists.
    bool hasOption(const std::string& option) const;

    std::string fsname; // Device or server for filesystem.
    std::string dir;    // Directory mounted on.
    std::string type;   // Type of filesystem: ufs, nfs, etc.
    std::string opts;   // Comma-separated options for fs.
    int freq;           // Dump frequency (in days).
    int passno;         // Pass number for `fsck'.
  };

  // Read the mount table from a file.
  // @param   path    The path of the file storing the mount table.
  // @return  An instance of MountTable if success.
  static Try<MountTable> read(const std::string& path);

  std::vector<Entry> entries;
};

// Structure describing a file system table (e.g. /etc/fstab).
struct FileSystemTable {
  // Structure describing a file system table entry. This is a wrapper for
  // struct fstab defined in <fstab.h>
  struct Entry {
    Entry() : freq(0), passno(0) {}

    Entry(const std::string& _spec,
          const std::string& _file,
          const std::string& _vfstype,
          const std::string& _mntops,
          const std::string& _type,
          int _freq,
          int _passno)
      : spec(_spec),
        file(_file),
        vfstype(_vfstype),
        mntops(_mntops),
        type(_type),
        freq(_freq),
        passno(_passno)
    {}

    std::string spec;     // Block special device name.
    std::string file;     // File system path prefix.
    std::string vfstype;  // File system type, ufs, nfs.
    std::string mntops;   // Mount options ala -o.
    std::string type;     // FSTAB_* from fs_mntops.
    int freq;             // Dump frequency, in days.
    int passno;           // Pass number on parallel dump.
  };

  // Read the file system table from a file.
  // @param   path    The path of the file storing the file system table.
  // @return  An instance of FileSystemTable if success.
  static Try<FileSystemTable> read();

  std::vector<Entry> entries;
};

// Mount a file system.
// @param   source    Specify the file system (often a device name but
//                    it can also be a directory for a bind mount).
//                    If None(), NULL will be passed as a dummy
//                    argument to mount(), i.e., it is not used for
//                    the specified mount operation. For example, you
//                    can mount a filesystem specified in /etc/fstab
//                    by just specifying the target.
// @param   target    Directory to be attached to.
// @param   type      File system type (listed in /proc/filesystems).
//                    If None(), NULL will be passed as a dummy
//                    argument to mount(), i.e., it is not used for
//                    the specified mount operation. For example, it
//                    should be None() for a bind mount as it will
//                    inherit the type of the source.
// @param   flags     Mount flags.
// @param   data      Extra data interpreted by different file systems.
// @return  Whether the mount operation succeeds.
Try<Nothing> mount(const Option<std::string>& source,
                   const std::string& target,
                   const Option<std::string>& type,
                   unsigned long flags,
                   const void* data);

// Unmount a file system.
// @param   target    The (topmost) directory where the file system attaches.
// @param   flags     Unmount flags.
// @return  Whether the unmount operation succeeds.
Try<Nothing> unmount(const std::string& target, int flags = 0);

// Change the root filesystem.
Try<Nothing> pivot_root(const std::string& newRoot, const std::string& putOld);

} // namespace fs {
} // namespace internal {
} // namespace mesos {

#endif // __FS_HPP__
<|endoftext|>


<commit_before>/**
 * This file is part of Slideshow.
 * Copyright (C) 2008-2010 David Sveningsson <ext@sidvind.com>
 *
 * Slideshow is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Slideshow 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Slideshow.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Log.h"

#ifdef __cplusplus
extern "C" {
#endif

void  log_message(Severity severity, const char* fmt, ...){
	va_list ap;
	va_start(ap, fmt);
	log_vmessage(severity, fmt, ap);
	va_end(ap);
}

void log_vmessage(Severity severity, const char* fmt, va_list ap){
	Log::vmessage(severity, fmt, ap);
}

#ifdef __cplusplus
}
#endif
<commit_msg><commit_after>/**
 * This file is part of Slideshow.
 * Copyright (C) 2008-2010 David Sveningsson <ext@sidvind.com>
 *
 * Slideshow is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Slideshow 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Slideshow.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Log.h"

#ifdef __cplusplus
extern "C" {
#endif

void  log_message(enum Severity severity, const char* fmt, ...){
	va_list ap;
	va_start(ap, fmt);
	log_vmessage(severity, fmt, ap);
	va_end(ap);
}

void log_vmessage(enum Severity severity, const char* fmt, va_list ap){
	Log::vmessage(severity, fmt, ap);
}

#ifdef __cplusplus
}
#endif
<|endoftext|>


<commit_before>#include <zmq.hpp>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <vector>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <map>
#include "rapidxml.hpp"

typedef enum {
	C2S,
	S2S,
	COMP
} SESSION_TYPE;

class NetSession {
	std::string m_buf;
	int m_fd;
	static const size_t buflen = 4096;
	std::string m_stream_buf;
	rapidxml::xml_document<> m_stream;
	rapidxml::xml_document<> m_stanza; // Not, in fact, always a stanza per-se.
	SESSION_TYPE m_type;
public:
	NetSession(int fd, SESSION_TYPE type) : m_fd(fd), m_type(type) {}
	void drain() {
		while (true) {
			auto oldsz = m_buf.length();
			m_buf.resize(oldsz + buflen);
			auto count = ::read(m_fd, &m_buf[oldsz], buflen);
			if (count < 0) {
				if (errno == EWOULDBLOCK || errno == EAGAIN) {
					m_buf.resize(oldsz);
					break;
				} else {
					// Some more serious thing.
					::close(m_fd);
					m_fd = -1;
					m_buf.resize(oldsz);
					break;
				}
			} else if (count == 0) {
				::close(m_fd);
				m_fd = -1;
				m_buf.resize(oldsz);
				break;
			} else {
				m_buf.resize(oldsz + count);
			}
		}
		std::cout << "Drained buffer, now: \n" << m_buf << "\n!!!" << std::endl;
		process();
	}
	void process() {
		using namespace rapidxml;
		if (m_buf.empty()) return;
		if (m_stream.first_node() == NULL) {
			/**
			 * We need to grab the stream open. Do so by parsing the main buffer to find where the open
			 * finishes, and copy that segment over to another buffer. Then reparse, this time properly.
			 */
			char * end = m_stream.parse<parse_open_only|parse_fastest>(const_cast<char *>(m_buf.c_str()));
			auto test = m_stream.first_node();
			if (!test || !test->name()) {
				std::cout << "Cannot parse an element, yet." << std::endl;
				return;
			}
			m_stream_buf.assign(m_buf.data(), end - m_buf.data());
			m_buf.erase(0, end - m_buf.data());
			m_stream.parse<parse_open_only>(const_cast<char *>(m_stream_buf.c_str()));
			stream_open();
			auto stream_open = m_stream.first_node();
			std::cout << "Stream open with {" << stream_open->xmlns() << "}" << stream_open->name() << std::endl;
		}
		while(!m_buf.empty()) {
			char * end = m_stanza.parse<parse_fastest|parse_parse_one>(const_cast<char *>(m_buf.c_str()), m_stream);
			auto element = m_stanza.first_node();
			if (!element || !element->name()) return;
			std::cout << "TLE {" << element->xmlns() << "}" << element->name() << std::endl;
			m_buf.erase(0, end - m_buf.data());
		}
	}

	void stream_open() {
		/**
		 * We may be able to change our minds on what stream type this is, here,
		 * by looking at the default namespace.
		 */
		auto stream = m_stream.first_node();
		auto xmlns = stream->first_attribute("xmlns");
		if (xmlns && xmlns->value()) {
			std::string default_xmlns(xmlns->value(), xmlns->value_size());
			if (default_xmlns == "jabber:client") {
				m_type = C2S;
			} else if (default_xmlns == "jabber:server") {
				m_type = S2S;
			} else {
				std::cout << "Unidentified connection." << std::endl;
			}
		}
		auto domain = stream->first_attribute("to");
		if (domain && domain->value()) {
			std::string to_domain(domain->value(), domain->value_size());
			std::cout << "Requested contact domain {" << to_domain << "}" << std::endl;
		}
		if (!stream->xmlns()) {
			std::cout << "Ooops! No xmlns for stream?" << std::endl;
		}
		if (stream->name() != std::string("stream") ||
			stream->xmlns() != std::string("http://etherx.jabber.org/streams")) {
			std::cout << "Ooops! Wrong name or invalid namespace." << std::endl;
		}
	}
};

int  main(int argc, char *argv[]) {
	zmq::context_t context(1);
	auto lsock = socket(AF_INET6, SOCK_STREAM, 0);
	sockaddr_in6 sin = { AF_INET6, htons(5222), 0, { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, 0 };
	if (0 < bind(lsock, (sockaddr *)&sin, sizeof(sin))) {
		std::cout << "Cannot bind!" << std::endl;
		return 1;
	}
	int opt = 1;
	setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
	listen(lsock, 5);

	std::vector<zmq::pollitem_t> pollitems;
	zmq::pollitem_t pollitem;
	pollitem.socket = NULL;
	pollitem.fd = lsock;
	pollitem.events = ZMQ_POLLIN;
	pollitems.push_back(pollitem);
	std::map<int, NetSession *> sockets;
	while (true) {
		zmq::poll(&pollitems[0], pollitems.size());
		if (pollitems[0].revents & ZMQ_POLLIN) {
			auto sock = accept(pollitems[0].fd, NULL, NULL);
			int fl = O_NONBLOCK;
			fcntl(sock, F_SETFL, fl);
			zmq::pollitem_t pollitem;
			pollitem.socket = NULL;
			pollitem.fd = sock;
			pollitem.events = ZMQ_POLLIN;
			pollitems.push_back(pollitem);
			sockets[sock] = new NetSession(sock, C2S);
		}
		for (auto pollitem : pollitems) {
			if (pollitem.fd == lsock) continue;
			std::cout << "Activity on " << pollitem.fd << std::endl;
			sockets[pollitem.fd]->drain();
		}
	}
	return 0;
}
<commit_msg>Added some dummy<commit_after>#include <zmq.hpp>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <vector>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <map>
#include "rapidxml.hpp"

typedef enum {
	C2S,
	S2S,
	COMP
} SESSION_TYPE;

namespace std {
	template<typename T>
	class optional {
		char m_void[sizeof(T)];
		bool m_engaged;
	private:
		void doset(T const & t) {
			new(m_void) T(t);
			m_engaged = true;
		}
		T * real() {
			if (!m_engaged) throw std::runtime_error("Deref when unengaged");
			return reinterpret_cast<T *>(&m_void);
		}
		T const * real() const {
			if (!m_engaged) throw std::runtime_error("Deref when unengaged");
			return reinterpret_cast<T const *>(&m_void);
		}
	public:
		optional(T const & t) : m_engaged(false) {
			doset(t);
		}
		optional() : m_engaged(false) {
		}
		void emplace() {
			if (m_engaged) throw std::runtime_error("Emplace when engaged");
			new(m_void) T;
		}
		T & operator * () {
			return *real();
		}
		T * operator -> () {
			return real();
		}
		T & value() {
			return *real();
		}
		T const & operator * () const {
			return *real();
		}
		T const * operator -> () const {
			return real();
		}
		T const & value() const {
			return *real();
		}
		operator bool () const {
			return m_engaged;
		}
	};
}

class Jid {
	std::optional<std::string> m_local;
	std::string m_domain;
	std::optional<std::string> m_resource;

	mutable std::optional<std::string> m_full;
	mutable std::optional<std::string> m_bare;
public:
	Jid(std::string const & jid) {
		// TODO : Parse out //
	}
	Jid(std::string const & local, std::string const & domain)
		: m_local(local), m_domain(domain) {
	}
	std::string const & full() const {
		if (!m_full) {
			m_full.emplace();
			if (m_local) {
				*m_full += *m_local;
				*m_full += "@";
			}
			*m_full += m_domain;
			if (m_resource) {
				*m_full += "/";
				*m_full += *m_resource;
			}
		}
		return *m_full;
	}
	std::string const & bare() const {
		if (!m_bare) {
			m_bare.emplace();
			if (m_local) {
				*m_bare += *m_local;
				*m_bare += "@";
			}
			m_bare.value() += m_domain;
		}
		return *m_bare;
	}
};

class Account {
	Jid m_jid;
public:
	Account(Jid const & jid) : m_jid(jid) {}
	bool test_password(std::string const & password) {
		return password == "yes"; // TODO : Maybe make this more secure? //
	}
};

class Domain {
	std::string m_domain;
	std::map<std::string, Account *> m_accounts;
public:
	Domain(std::string const & domain) : m_domain(domain) {}
	Account & account(Jid const & jid) {
		auto acciter = m_accounts.find(jid.bare());
		if (acciter != m_accounts.end()) {
			return *acciter->second;
		}
		if (jid.bare() != "dave@jekyll.dave.cridland.net") {
			throw std::runtime_error("No such account");
		}
		auto acc = m_accounts[jid.bare()] = new Account(jid);
		return *acc;
	}
};

class Server {
	std::map<std::string, Domain *> m_domains;
public:
	Server() {}
	Domain & domain(std::string const & domain) {
		auto domiter = m_domains.find(domain);
		if (domiter != m_domains.end()) {
			return *domiter->second;
		}
		if (domain != "jekyll.dave.cridland.net") {
			throw std::runtime_error("No such domain");
		}
		auto dom = m_domains[domain] = new Domain(domain);
		return *dom;
	}
};

class NetSession {
	std::string m_buf;
	int m_fd;
	static const size_t buflen = 4096;
	std::string m_stream_buf;
	rapidxml::xml_document<> m_stream;
	rapidxml::xml_document<> m_stanza; // Not, in fact, always a stanza per-se. //
	SESSION_TYPE m_type;
	Server * m_server;
public:
	NetSession(int fd, SESSION_TYPE type, Server * server) : m_fd(fd), m_type(type), m_server(server) {}
	void drain() {
		// This is a phenomenally cool way of reading data from a socket to
		// a std::string. Extend string, read direct to buffer, resize string to
		// read-length.
		// Downside is that when std::string extends, we might cause an alloc,
		// but this should - I think - be rare.
		while (true) {
			auto oldsz = m_buf.length();
			m_buf.resize(oldsz + buflen);
			auto count = ::read(m_fd, &m_buf[oldsz], buflen);
			if (count < 0) {
				if (errno == EWOULDBLOCK || errno == EAGAIN) {
					m_buf.resize(oldsz);
					break;
				} else {
					// Some more serious error.
					::close(m_fd);
					m_fd = -1;
					m_buf.resize(oldsz);
					break;
				}
			} else if (count == 0) {
				::close(m_fd);
				m_fd = -1;
				m_buf.resize(oldsz);
				break;
			} else {
				m_buf.resize(oldsz + count);
			}
		}
		std::cout << "Drained buffer, now: \n" << m_buf << "\n!!!" << std::endl;
		process();
	}
	void process() {
		using namespace rapidxml;
		if (m_buf.empty()) return;
		if (m_stream.first_node() == NULL) {
			/**
			 * We need to grab the stream open. Do so by parsing the main buffer to find where the open
			 * finishes, and copy that segment over to another buffer. Then reparse, this time properly.
			 */
			char * end = m_stream.parse<parse_open_only|parse_fastest>(const_cast<char *>(m_buf.c_str()));
			auto test = m_stream.first_node();
			if (!test || !test->name()) {
				std::cout << "Cannot parse an element, yet." << std::endl;
				return;
			}
			m_stream_buf.assign(m_buf.data(), end - m_buf.data());
			m_buf.erase(0, end - m_buf.data());
			m_stream.parse<parse_open_only>(const_cast<char *>(m_stream_buf.c_str()));
			stream_open();
			auto stream_open = m_stream.first_node();
			std::cout << "Stream open with {" << stream_open->xmlns() << "}" << stream_open->name() << std::endl;
		}
		while(!m_buf.empty()) {
			char * end = m_stanza.parse<parse_fastest|parse_parse_one>(const_cast<char *>(m_buf.c_str()), m_stream);
			auto element = m_stanza.first_node();
			if (!element || !element->name()) return;
			std::cout << "TLE {" << element->xmlns() << "}" << element->name() << std::endl;
			m_buf.erase(0, end - m_buf.data());
		}
	}

	void stream_open() {
		/**
		 * We may be able to change our minds on what stream type this is, here,
		 * by looking at the default namespace.
		 */
		auto stream = m_stream.first_node();
		auto xmlns = stream->first_attribute("xmlns");
		if (xmlns && xmlns->value()) {
			std::string default_xmlns(xmlns->value(), xmlns->value_size());
			if (default_xmlns == "jabber:client") {
				m_type = C2S;
			} else if (default_xmlns == "jabber:server") {
				m_type = S2S;
			} else {
				std::cout << "Unidentified connection." << std::endl;
			}
		}
		auto domainat = stream->first_attribute("to");
		std::string domainname;
		if (domainat && domainat->value()) {
			domainname.assign(domainat->value(), domainat->value_size());
			std::cout << "Requested contact domain {" << domainname << "}" << std::endl;
		} else {
			domainname = "jekyll.dave.cridland.net"; // TODO : Default //
		}
		auto domain = m_server->domain(domainname);
		if (!stream->xmlns()) {
			std::cout << "Ooops! No xmlns for stream?" << std::endl;
		}
		if (stream->name() != std::string("stream") ||
			stream->xmlns() != std::string("http://etherx.jabber.org/streams")) {
			std::cout << "Ooops! Wrong name or invalid namespace." << std::endl;
		}
	}
};

int  main(int argc, char *argv[]) {
	zmq::context_t context(1);
	auto lsock = socket(AF_INET6, SOCK_STREAM, 0);
	sockaddr_in6 sin = { AF_INET6, htons(5222), 0, { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, 0 };
	if (0 < bind(lsock, (sockaddr *)&sin, sizeof(sin))) {
		std::cout << "Cannot bind!" << std::endl;
		return 1;
	}
	int opt = 1;
	setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
	listen(lsock, 5);

	std::vector<zmq::pollitem_t> pollitems;
	zmq::pollitem_t pollitem;
	pollitem.socket = NULL;
	pollitem.fd = lsock;
	pollitem.events = ZMQ_POLLIN;
	pollitems.push_back(pollitem);
	std::map<int, NetSession *> sockets;
	Server server;
	while (true) {
		zmq::poll(&pollitems[0], pollitems.size());
		if (pollitems[0].revents & ZMQ_POLLIN) {
			auto sock = accept(pollitems[0].fd, NULL, NULL);
			int fl = O_NONBLOCK;
			fcntl(sock, F_SETFL, fl);
			zmq::pollitem_t pollitem;
			pollitem.socket = NULL;
			pollitem.fd = sock;
			pollitem.events = ZMQ_POLLIN;
			pollitems.push_back(pollitem);
			sockets[sock] = new NetSession(sock, C2S, &server);
		}
		for (auto pollitem : pollitems) {
			if (pollitem.fd == lsock) continue;
			std::cout << "Activity on " << pollitem.fd << std::endl;
			sockets[pollitem.fd]->drain();
		}
	}
	return 0;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <sstream>
#include <cctype>

#include "mangling.hpp"
#include "Utils.hpp"

#include "VisitorUtils.hpp"
#include "ast/GetTypeVisitor.hpp"

using namespace eddic;

std::string eddic::mangle(Type type){
    if(type.base() == BaseType::INT){
        return type.isArray() ? "AI" : "I";
    } else if(type.base() == BaseType::STRING){
        return type.isArray() ? "AS" : "S";
    } else if(type.base() == BaseType::BOOL){
        return type.isArray() ? "AB" : "B";
    }

    assert(false); //Type not handled
}

std::string eddic::mangle(const std::string& functionName, const std::vector<ParameterType>& types){
    if(functionName == "main"){
        return functionName;
    }

    std::ostringstream ss;

    ss << "_F";
    ss << functionName.length();
    ss << functionName;

    for(const ParameterType& t : types){
        ss << mangle(t.paramType);
    }

    return ss.str();
}

std::string eddic::mangle(const std::string& functionName, const std::vector<ast::Value>& values){
    if(functionName == "main"){
        return functionName;
    }

    std::ostringstream ss;

    ss << "_F";
    ss << functionName.length();
    ss << functionName;

    ast::GetTypeVisitor visitor;

    for(auto& value : values){
        Type type = visit(visitor, value);
        ss << mangle(type);
    }

    return ss.str();
}

std::string eddic::unmangle(std::string mangled){
    if(mangled == "main"){
        return "main";
    }

    std::ostringstream length;
    int digits = 0;

    for(unsigned int i = 2; i < mangled.length(); ++i){
        if(isdigit(mangled[i])){
            length << mangled[i];
            ++digits;
        } else {
            break;
        }
    }

    int l = toNumber<unsigned int>(length.str());

    std::ostringstream function;

    for(int i = 0; i < l; ++i){
        function << mangled[i + 2 + digits];
    }

    function << '(';

    for(unsigned int i = 2 + l + digits; i < mangled.length(); ++i){
        char current = mangled[i];

        bool array = false;
        if(current == 'A'){
            array = true;
            current = mangled[++i];
        }

        if(current == 'I'){
            function << "int";
        } else if(current == 'S'){
            function << "string";
        } else if(current == 'B'){
            function << "bool";
        }

        if(array){
            function << "[]";
        }

        if(i < mangled.length() - 1){
            function << ", ";
        }
    }

    function << ')';

    return function.str();
}
<commit_msg>Fix mangling<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <sstream>
#include <cctype>

#include "mangling.hpp"
#include "Utils.hpp"

#include "VisitorUtils.hpp"
#include "ast/GetTypeVisitor.hpp"

using namespace eddic;

std::string eddic::mangle(Type type){
    if(type.base() == BaseType::INT){
        return type.isArray() ? "AI" : "I";
    } else if(type.base() == BaseType::STRING){
        return type.isArray() ? "AS" : "S";
    } else if(type.base() == BaseType::BOOL){
        return type.isArray() ? "AB" : "B";
    } else if(type.base() == BaseType::FLOAT){
        return type.isArray() ? "AF" : "F";
    }

    assert(false); //Type not handled
}

std::string eddic::mangle(const std::string& functionName, const std::vector<ParameterType>& types){
    if(functionName == "main"){
        return functionName;
    }

    std::ostringstream ss;

    ss << "_F";
    ss << functionName.length();
    ss << functionName;

    for(const ParameterType& t : types){
        ss << mangle(t.paramType);
    }

    return ss.str();
}

std::string eddic::mangle(const std::string& functionName, const std::vector<ast::Value>& values){
    if(functionName == "main"){
        return functionName;
    }

    std::ostringstream ss;

    ss << "_F";
    ss << functionName.length();
    ss << functionName;

    ast::GetTypeVisitor visitor;

    for(auto& value : values){
        Type type = visit(visitor, value);
        ss << mangle(type);
    }

    return ss.str();
}

std::string eddic::unmangle(std::string mangled){
    if(mangled == "main"){
        return "main";
    }

    std::ostringstream length;
    int digits = 0;

    for(unsigned int i = 2; i < mangled.length(); ++i){
        if(isdigit(mangled[i])){
            length << mangled[i];
            ++digits;
        } else {
            break;
        }
    }

    int l = toNumber<unsigned int>(length.str());

    std::ostringstream function;

    for(int i = 0; i < l; ++i){
        function << mangled[i + 2 + digits];
    }

    function << '(';

    for(unsigned int i = 2 + l + digits; i < mangled.length(); ++i){
        char current = mangled[i];

        bool array = false;
        if(current == 'A'){
            array = true;
            current = mangled[++i];
        }

        if(current == 'I'){
            function << "int";
        } else if(current == 'S'){
            function << "string";
        } else if(current == 'B'){
            function << "bool";
        } else if(current == 'F'){
            function << "float";
        }

        if(array){
            function << "[]";
        }

        if(i < mangled.length() - 1){
            function << ", ";
        }
    }

    function << ')';

    return function.str();
}
<|endoftext|>


<commit_before>#define GUILITE_ON  //Do not define this macro once more!!!
#include "GuiLite.h"

#define UI_WIDTH 240
#define UI_HEIGHT 320

#define LAYER_1_X 70
#define LAYER_1_Y 110

#define SHADES_CNT 10
#define SHADE_HEIGHT 10
#define LAYER_1_WIDTH  80
#define LAYER_1_HEIGHT SHADES_CNT * SHADE_HEIGHT

static c_surface* s_surface;
static c_display* s_display;

//////////////////////// start UI ////////////////////////

void draw_on_layer_0()
{
	s_surface->fill_rect(0, 0, UI_WIDTH - 1, UI_HEIGHT - 1, 0, Z_ORDER_LEVEL_0);
	c_word::draw_string(s_surface, Z_ORDER_LEVEL_0, "layer 0: the bottom", 30, LAYER_1_Y + 30, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_ARGB(0, 0, 0, 0));
}

void draw_on_layer_1()
{
	s_surface->fill_rect(LAYER_1_X, LAYER_1_Y, LAYER_1_X + LAYER_1_WIDTH - 1, LAYER_1_Y + LAYER_1_HEIGHT - 1, GL_RGB(0, 122, 204), Z_ORDER_LEVEL_1);
	c_word::draw_string(s_surface, Z_ORDER_LEVEL_1, "layer 1:", LAYER_1_X + 5, LAYER_1_Y + 19, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_RGB(0, 122, 204));
	c_word::draw_string(s_surface, Z_ORDER_LEVEL_1, "the top", LAYER_1_X + 5, LAYER_1_Y + 38, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_RGB(0, 122, 204));
}

void clear_layer_1()
{
#if 0
	//no animation
	c_rect overlapped_rect(LAYER_1_X, LAYER_1_Y, LAYER_1_X + LAYER_1_WIDTH - 1, LAYER_1_Y + LAYER_1_HEIGHT - 1);
	s_surface->show_overlapped_rect(overlapped_rect, Z_ORDER_LEVEL_0);
#else
	//animation
	for (int offset = 0; offset < SHADE_HEIGHT; offset++)
	{
		for (int i = 0; i < SHADES_CNT; i++)
		{
			c_rect overlapped_rect_top(LAYER_1_X, LAYER_1_Y + (SHADE_HEIGHT * i) + offset, LAYER_1_X + LAYER_1_WIDTH - 1, LAYER_1_Y + (SHADE_HEIGHT * i) + offset);
			s_surface->show_overlapped_rect(overlapped_rect_top, Z_ORDER_LEVEL_0);
		}
		thread_sleep(5);
	}
#endif
}

extern const FONT_INFO Consolas_19;
void load_resource()
{
	c_theme::add_font(FONT_DEFAULT, &Consolas_19);
}

void create_ui(void* phy_fb, int screen_width, int screen_height, int color_bytes, struct EXTERNAL_GFX_OP* gfx_op) {
	if (phy_fb)
	{
		static c_surface surface(UI_WIDTH, UI_HEIGHT, color_bytes, Z_ORDER_LEVEL_1, c_rect(LAYER_1_X, LAYER_1_Y, LAYER_1_X + LAYER_1_WIDTH - 1, LAYER_1_Y + LAYER_1_HEIGHT - 1));
		static c_display display(phy_fb, screen_width, screen_height, &surface);
		s_surface = &surface;
		s_display = &display;
	}
	else
	{//for MCU without framebuffer
		static c_surface_no_fb surface_no_fb(UI_WIDTH, UI_HEIGHT, color_bytes, gfx_op, Z_ORDER_LEVEL_1, c_rect(LAYER_1_X, LAYER_1_Y, LAYER_1_X + LAYER_1_WIDTH - 1, LAYER_1_Y + LAYER_1_HEIGHT - 1));
		static c_display display(phy_fb, screen_width, screen_height, &surface_no_fb);
		s_surface = &surface_no_fb;
		s_display = &display;
	}

	load_resource();
	draw_on_layer_0();
	while(1) {
		draw_on_layer_1();
		thread_sleep(3000);
		clear_layer_1();
		thread_sleep(3000);
	}
}

//////////////////////// interface for all platform ////////////////////////
extern "C" void startHelloLayers(void* phy_fb, int width, int height, int color_bytes, struct EXTERNAL_GFX_OP* gfx_op) {
	create_ui(phy_fb, width, height, color_bytes, gfx_op);
}

void* getUiOfHelloLayers(int* width, int* height, bool force_update)
{
	if (s_display)
	{
		return s_display->get_updated_fb(width, height, force_update);
	}
	return NULL;
}
<commit_msg>change text for helloLayers<commit_after>#define GUILITE_ON  //Do not define this macro once more!!!
#include "GuiLite.h"

#define UI_WIDTH 240
#define UI_HEIGHT 320

#define LAYER_1_X 70
#define LAYER_1_Y 100

#define SHADES_CNT 10
#define SHADE_HEIGHT 10
#define LAYER_1_WIDTH  80
#define LAYER_1_HEIGHT SHADES_CNT * SHADE_HEIGHT

static c_surface* s_surface;
static c_display* s_display;

//////////////////////// start UI ////////////////////////

void draw_on_layer_0()
{
	int const start_y = 70;
	s_surface->fill_rect(0, 0, UI_WIDTH - 1, UI_HEIGHT - 1, 0, Z_ORDER_LEVEL_0);
	c_word::draw_string(s_surface, Z_ORDER_LEVEL_0, "We could not to do", 30, start_y + 30, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_ARGB(0, 0, 0, 0));
	c_word::draw_string(s_surface, Z_ORDER_LEVEL_0, "everything for you.", 30, start_y + 50, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_ARGB(0, 0, 0, 0));
	c_word::draw_string(s_surface, Z_ORDER_LEVEL_0, "", 30, start_y + 50, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_ARGB(0, 0, 0, 0));

	c_word::draw_string(s_surface, Z_ORDER_LEVEL_0, "Just keep GUI:", 30, start_y + 90, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_ARGB(0, 0, 0, 0));
	c_word::draw_string(s_surface, Z_ORDER_LEVEL_0, "stupid simple.", 30, start_y + 110, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_ARGB(0, 0, 0, 0));
}

void draw_on_layer_1()
{
	s_surface->fill_rect(LAYER_1_X, LAYER_1_Y, LAYER_1_X + LAYER_1_WIDTH - 1, LAYER_1_Y + LAYER_1_HEIGHT - 1, GL_RGB(0, 122, 204), Z_ORDER_LEVEL_1);
	c_word::draw_string(s_surface, Z_ORDER_LEVEL_1, "GuiLite", LAYER_1_X + 5, LAYER_1_Y + 20, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_RGB(0, 122, 204));
	c_word::draw_string(s_surface, Z_ORDER_LEVEL_1, " 5KLOC", LAYER_1_X + 5, LAYER_1_Y + 60, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_RGB(0, 122, 204));
}

void clear_layer_1()
{
#if 0
	//no animation
	c_rect overlapped_rect(LAYER_1_X, LAYER_1_Y, LAYER_1_X + LAYER_1_WIDTH - 1, LAYER_1_Y + LAYER_1_HEIGHT - 1);
	s_surface->show_overlapped_rect(overlapped_rect, Z_ORDER_LEVEL_0);
#else
	//animation
	for (int offset = 0; offset < SHADE_HEIGHT; offset++)
	{
		for (int i = 0; i < SHADES_CNT; i++)
		{
			c_rect overlapped_rect_top(LAYER_1_X, LAYER_1_Y + (SHADE_HEIGHT * i) + offset, LAYER_1_X + LAYER_1_WIDTH - 1, LAYER_1_Y + (SHADE_HEIGHT * i) + offset);
			s_surface->show_overlapped_rect(overlapped_rect_top, Z_ORDER_LEVEL_0);
		}
		thread_sleep(5);
	}
#endif
}

extern const FONT_INFO Consolas_19;
void load_resource()
{
	c_theme::add_font(FONT_DEFAULT, &Consolas_19);
}

void create_ui(void* phy_fb, int screen_width, int screen_height, int color_bytes, struct EXTERNAL_GFX_OP* gfx_op) {
	if (phy_fb)
	{
		static c_surface surface(UI_WIDTH, UI_HEIGHT, color_bytes, Z_ORDER_LEVEL_1, c_rect(LAYER_1_X, LAYER_1_Y, LAYER_1_X + LAYER_1_WIDTH - 1, LAYER_1_Y + LAYER_1_HEIGHT - 1));
		static c_display display(phy_fb, screen_width, screen_height, &surface);
		s_surface = &surface;
		s_display = &display;
	}
	else
	{//for MCU without framebuffer
		static c_surface_no_fb surface_no_fb(UI_WIDTH, UI_HEIGHT, color_bytes, gfx_op, Z_ORDER_LEVEL_1, c_rect(LAYER_1_X, LAYER_1_Y, LAYER_1_X + LAYER_1_WIDTH - 1, LAYER_1_Y + LAYER_1_HEIGHT - 1));
		static c_display display(phy_fb, screen_width, screen_height, &surface_no_fb);
		s_surface = &surface_no_fb;
		s_display = &display;
	}

	load_resource();
	draw_on_layer_0();
	while(1) {
		draw_on_layer_1();
		thread_sleep(3000);
		clear_layer_1();
		thread_sleep(3000);
	}
}

//////////////////////// interface for all platform ////////////////////////
extern "C" void startHelloLayers(void* phy_fb, int width, int height, int color_bytes, struct EXTERNAL_GFX_OP* gfx_op) {
	create_ui(phy_fb, width, height, color_bytes, gfx_op);
}

void* getUiOfHelloLayers(int* width, int* height, bool force_update)
{
	if (s_display)
	{
		return s_display->get_updated_fb(width, height, force_update);
	}
	return NULL;
}
<|endoftext|>


<commit_before>#include <node_version.h>

#if NODE_VERSION_AT_LEAST(0, 11, 1) && !defined(_MSC_VER)
#include <sys/types.h>
#endif

#include <errno.h>

#include <napi.h>

#if defined(_MSC_VER)
#include <time.h>
#include <windows.h>

// Pick GetSystemTimePreciseAsFileTime or GetSystemTimeAsFileTime depending
// on which is available at runtime.
typedef VOID(WINAPI *WinGetSystemTime)(LPFILETIME);
static WinGetSystemTime getSystemTime = NULL;

struct timezone {
  int tz_minuteswest;
  int tz_dsttime;
};

int gettimeofday(struct timeval *tv, struct timezone *tz) {
  FILETIME ft;
  (*getSystemTime)(&ft);
  unsigned long long t = ft.dwHighDateTime;
  t <<= 32;
  t |= ft.dwLowDateTime;
  t /= 10;
  t -= 11644473600000000ULL;
  tv->tv_sec = (long)(t / 1000000UL);
  tv->tv_usec = (long)(t % 1000000UL);

  return 0;
}
#else
#include <sys/time.h>
#endif

Napi::Value Now(const Napi::CallbackInfo &info) {
  timeval t;
  int r = gettimeofday(&t, NULL);

  if (r < 0) {
    throw Napi::Error::New(info.Env(), "gettimeofday");
  }

  return Napi::Number::New(info.Env(), ((t.tv_sec * 1000000.0) + t.tv_usec));
}

Napi::Value NowDouble(const Napi::CallbackInfo &info) {
  timeval t;
  int r = gettimeofday(&t, NULL);

  if (r < 0) {
    throw Napi::Error::New(info.Env(), "gettimeofday");
  }

  return Napi::Number::New(info.Env(), t.tv_sec + (t.tv_usec * 0.000001));
}

Napi::Value NowStruct(const Napi::CallbackInfo &info) {
  timeval t;
  int r = gettimeofday(&t, NULL);

  if (r < 0) {
    throw Napi::Error::New(info.Env(), "gettimeofday");
  }

  Napi::Array array = Napi::Array::New(info.Env(), 2);
  array.Set((uint32_t)0, (double)t.tv_sec);
  array.Set((uint32_t)1, (double)t.tv_usec);

  return array;
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
  exports.Set(Napi::String::New(env, "now"), Napi::Function::New(env, Now));
  exports.Set(Napi::String::New(env, "nowDouble"),
              Napi::Function::New(env, NowDouble));
  exports.Set(Napi::String::New(env, "nowStruct"),
              Napi::Function::New(env, NowStruct));
#if defined(_MSC_VER)
  getSystemTime = (WinGetSystemTime)GetProcAddress(
      GetModuleHandle(TEXT("kernel32.dll")), "GetSystemTimePreciseAsFileTime");
  if (getSystemTime == NULL) {
    getSystemTime = &GetSystemTimeAsFileTime;
  }
#endif
  return exports;
}

NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init);
<commit_msg>Solution to preserve error code from C land in the error message<commit_after>#include <node_version.h>

#if NODE_VERSION_AT_LEAST(0, 11, 1) && !defined(_MSC_VER)
#include <sys/types.h>
#endif

#include <errno.h>

#include <napi.h>

#if defined(_MSC_VER)
#include <time.h>
#include <windows.h>

// Pick GetSystemTimePreciseAsFileTime or GetSystemTimeAsFileTime depending
// on which is available at runtime.
typedef VOID(WINAPI *WinGetSystemTime)(LPFILETIME);
static WinGetSystemTime getSystemTime = NULL;

struct timezone {
  int tz_minuteswest;
  int tz_dsttime;
};

int gettimeofday(struct timeval *tv, struct timezone *tz) {
  FILETIME ft;
  (*getSystemTime)(&ft);
  unsigned long long t = ft.dwHighDateTime;
  t <<= 32;
  t |= ft.dwLowDateTime;
  t /= 10;
  t -= 11644473600000000ULL;
  tv->tv_sec = (long)(t / 1000000UL);
  tv->tv_usec = (long)(t % 1000000UL);

  return 0;
}
#else
#include <sys/time.h>
#endif

Napi::Value Now(const Napi::CallbackInfo &info) {
  timeval t;
  int r = gettimeofday(&t, NULL);

  if (r < 0) {
    Napi::Error e = Napi::Error::New(info.Env(), "gettimeofday");
    e.Set("code", Napi::Number::New(info.Env(), errno));
    throw e;
  }

  return Napi::Number::New(info.Env(), ((t.tv_sec * 1000000.0) + t.tv_usec));
}

Napi::Value NowDouble(const Napi::CallbackInfo &info) {
  timeval t;
  int r = gettimeofday(&t, NULL);
  if (r < 0) {
    Napi::Error e = Napi::Error::New(info.Env(), "gettimeofday");
    e.Set("code", Napi::Number::New(info.Env(), errno));
    throw e;
  }

  return Napi::Number::New(info.Env(), t.tv_sec + (t.tv_usec * 0.000001));
}

Napi::Value NowStruct(const Napi::CallbackInfo &info) {
  timeval t;
  int r = gettimeofday(&t, NULL);

  if (r < 0) {
    Napi::Error e = Napi::Error::New(info.Env(), "gettimeofday");
    e.Set("code", Napi::Number::New(info.Env(), errno));
    throw e;
  }

  Napi::Array array = Napi::Array::New(info.Env(), 2);
  array.Set((uint32_t)0, (double)t.tv_sec);
  array.Set((uint32_t)1, (double)t.tv_usec);

  return array;
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
  exports.Set(Napi::String::New(env, "now"), Napi::Function::New(env, Now));
  exports.Set(Napi::String::New(env, "nowDouble"),
              Napi::Function::New(env, NowDouble));
  exports.Set(Napi::String::New(env, "nowStruct"),
              Napi::Function::New(env, NowStruct));
#if defined(_MSC_VER)
  getSystemTime = (WinGetSystemTime)GetProcAddress(
      GetModuleHandle(TEXT("kernel32.dll")), "GetSystemTimePreciseAsFileTime");
  if (getSystemTime == NULL) {
    getSystemTime = &GetSystemTimeAsFileTime;
  }
#endif
  return exports;
}

NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init);
<|endoftext|>


<commit_before>/************************************************************************************
This source file is part of the Theora Video Playback Library
For latest info, see http://libtheoraplayer.sourceforge.net/
*************************************************************************************
Copyright (c) 2008-2013 Kresimir Spes (kspes@cateia.com)
This program is free software; you can redistribute it and/or modify it under
the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php
*************************************************************************************/
#define THEORAUTIL_NOMACROS
#include <theoraplayer/TheoraException.h>
#undef exception_cls
#include <theoraplayer/TheoraPlayer.h>
#include <theoraplayer/TheoraTimer.h>
#include <april/RenderSystem.h>
#include <april/april.h>
#include <april/Platform.h>
#include <april/Texture.h>
#include <aprilui/aprilui.h>
#include <aprilui/Dataset.h>
#include <aprilui/NullImage.h>
#include <aprilui/Texture.h>
#include <xal/AudioManager.h>
#include <xal/Player.h>
#include <xal/Sound.h>
#include "aprilvideo.h"
#include "AprilVideoDataSource.h"

namespace aprilvideo
{
	static TheoraVideoManager* gVideoManager = NULL;
	static int gRefCount = 0, gNumWorkerThreads = 1;
	hstr logTag = "aprilvideo", defaultFileExtension = ".ogv";

	static int _nextPow2(int x)
	{
		int y;
		for (y = 1; y < x; y *= 2);
		return y;
	}

	class AudioVideoTimer : public TheoraTimer
	{
		float mSyncOffset;
		xal::Player* mPlayer;
		float mT;
		bool mDisabledAudio;
	public:
		AudioVideoTimer(xal::Player* player, float sync_offset)
		{
			mSyncOffset = sync_offset;
			mPlayer = player;
			mT = 0;
			static hstr audiosystem = xal::mgr->getName(); // Disabled" audio system doesn't sync audio & video
			mDisabledAudio = (audiosystem == "Disabled");
		}

		void update(float time_increase)
		{
			if (!mDisabledAudio)
			{
				if (mPlayer->isPlaying())
					mTime = mPlayer->getTimePosition() - mSyncOffset;
				else
					mTime += time_increase;
			}
			else
			{
				mT += time_increase;
				mTime = mT - mSyncOffset;
			}
		}
	};

	VideoObject::VideoObject(chstr name, grect rect) : aprilui::ImageBox(name, rect)
	{
		mUsingAVFoundation = 0;
		mUseAlpha = 0;
		mPrevDoneFlag = 0;
		mLoop = 1;
		mSpeed = 1.0f;
		mClip = NULL;
		mVideoImage = NULL;
		mTexture = NULL;
		mTimer = NULL;
		mSound = NULL;
		mAudioPlayer = NULL;
		mAudioSyncOffset = 0;
		gRefCount++;
		mAlphaPauseTreshold = 0;
		mPrevFrameNumber = 0;
		mSeeked = 0;
        mPrevAlpha = 255;
		if (!gVideoManager)
		{
			gVideoManager = new TheoraVideoManager(gNumWorkerThreads);
			std::vector<std::string> lst = gVideoManager->getSupportedDecoders();
			foreach (std::string, it, lst)
			{
				if (*it == "AVFoundation") defaultFileExtension = ".mp4";
			}
		}
	}

	VideoObject::~VideoObject()
	{
		gRefCount--;
		destroyResources();
		if (gRefCount <= 0 && gVideoManager)
		{
			delete gVideoManager;
			gVideoManager = NULL;
		}
	}

	bool VideoObject::isPlaying()
	{
		return (mClip != NULL && !mClip->isPaused() && !mClip->isDone());
	}

	bool VideoObject::isPaused()
	{
		return (mClip != NULL && mClip->isPaused());
	}

	bool VideoObject::isStopped()
	{
		return (mClip == NULL || mClip->isDone());
	}

	float VideoObject::getTimePosition()
	{
		return (mClip != NULL ? mClip->getTimePosition() : 0.0f);
	}

	aprilui::Object* VideoObject::createInstance(chstr name, grect rect)
	{
		return new VideoObject(name, rect);
	}

	void VideoObject::notifyEvent(chstr name, void* params)
	{
		if (name == "AttachToObject")
		{
			if (mImage != mVideoImage)
			{
				mImage = mDataset->getImage("null");
			}
		}
		ImageBox::notifyEvent(name, params);
	}

	void VideoObject::destroyResources()
	{
		if (mVideoImage)
		{
			delete mVideoImage;
			mVideoImage = NULL;
			mImage = mDataset->getImage("null");
		}
		if (mTexture)
		{
			delete mTexture;
			mTexture = NULL;
		}
		if (mClip)
		{
			gVideoManager->destroyVideoClip(mClip);
			mClip = NULL;
		}
		if (mAudioPlayer)
		{
			xal::mgr->destroyPlayer(mAudioPlayer);
			mAudioPlayer = NULL;
		}
		if (mSound)
		{
			xal::mgr->destroySound(mSound);
			mSound = NULL;
		}

		if (mTimer)
		{
			delete mTimer;
			mTimer = NULL;
		}
	}

	void VideoObject::createClip()
	{
		destroyResources();
		hstr path = mDataset->getFilePath() + "/video/" + mClipName;
		if (!path.ends_with(".ogg") && !path.ends_with(".ogv") && !path.ends_with(".mp4")) path += defaultFileExtension;

		mUsingAVFoundation = path.ends_with(".mp4");
		april::Texture::Format textureFormat;

//		mUsingAVFoundation ? april::Texture::FORMAT_BGRA :
		try
		{
			TheoraOutputMode mode;
			if (april::rendersys->getName().starts_with("OpenGL"))
			{
				if (mUseAlpha)
				{
					mode = TH_RGBA;
					textureFormat = april::Texture::FORMAT_ARGB;
				}
				else
				{
					mode = mUsingAVFoundation ? TH_BGRX : TH_RGBX;
					textureFormat = mUsingAVFoundation ? april::Texture::FORMAT_BGRA : april::Texture::FORMAT_ARGB;

				}
			}
			else
			{
				mode = mUseAlpha ? TH_BGRA : TH_BGRX;
				textureFormat = april::Texture::FORMAT_ARGB;
			}
			int precached = april::getSystemInfo().ram < 512 ? 8 : 16;
			if (path.ends_with("mp4"))
			{

				if (april::window->getName() == "OpenKODE")
					mClip = gVideoManager->createVideoClip("res/" + path, mode, precached);
				else
					mClip = gVideoManager->createVideoClip(path, mode, precached);
			}
			else
				mClip = gVideoManager->createVideoClip(new AprilVideoDataSource(path), mode, precached);
		}
		catch (_TheoraGenericException& e)
		{
			throw hl_exception(e.getErrorText());
		}
		if (mClip->getWidth() == 0) throw hl_exception("Failed to load video file: " + path);
		mClip->setAutoRestart(mLoop);

		float w = mClip->getWidth(), h = mClip->getHeight();
		april::Texture* tex = april::rendersys->createTexture(_nextPow2(w), _nextPow2(h), textureFormat);
		mTexture = new aprilui::Texture(tex->getFilename(), tex);
		mVideoImage = new aprilui::Image(mTexture, "video_img", grect(0, 0, w, h));
		mClip->waitForCache(4 / 16.0f, 0.5f);

		if (mAudioName != "")
		{
			if (!xal::mgr->hasCategory("video"))
			{
				xal::mgr->createCategory("video", xal::ON_DEMAND, xal::DISK);
			}
			mSound = xal::mgr->createSound(mDataset->getFilePath() + "/video/" + mAudioName, "video");

			mAudioPlayer = xal::mgr->createPlayer(mSound->getName());
			mTimer = new AudioVideoTimer(mAudioPlayer, mAudioSyncOffset);
			mClip->setTimer(mTimer);

			mAudioPlayer->play();
		}
		else if (mSpeed != 1.0f) mClip->setPlaybackSpeed(mSpeed);
		update(0); // to grab the first frame.

	}

	void VideoObject::OnDraw()
	{
		if (mClip == NULL && mClipName != "") createClip();

		ImageBox::OnDraw();
	}

	void VideoObject::update(float k)
	{
		ImageBox::update(k);

		if (mClip)
		{
			if (!mLoop)
			{
				bool done = mClip->isDone();
				if (mPrevDoneFlag == 0 && done == 1) triggerEvent("PlaybackDone");
				mPrevDoneFlag = done;
			}
			mClip->update(k);
			//mClip->decodedAudioCheck();
            if (mPrevAlpha != getAlpha())
            {
                mPrevAlpha = getAlpha();
                bool should_pause = mAlphaPauseTreshold == 0 ? !isVisible() : getAlpha() <= mAlphaPauseTreshold;
                if (should_pause && !mClip->isPaused()) mClip->pause();
                else if (!should_pause && mClip->isPaused()) mClip->play();
			}
			TheoraVideoFrame* f = mClip->getNextFrame();
			if (f)
			{
				mImage = mVideoImage;
				grect r = mImage->getSrcRect();
				r.w = f->getWidth();
				r.h = f->getHeight();
				mImage->setSrcRect(r);
#ifdef _ANDROID
				mTexture->load();
#endif
				mTexture->getRenderTexture()->write(0, 0, f->getBuffer(), r.w, r.h, 4);
				mClip->popFrame();
				if (mLoop)
				{
					int number = f->getFrameNumber();
					if (mSeeked) mSeeked = 0;
					else if (number < mPrevFrameNumber)
					{
						triggerEvent("PlaybackDone");
					}
					mPrevFrameNumber = number;
				}
			}
		}
	}

	void VideoObject::setAlphaTreshold(int treshold)
	{
		mAlphaPauseTreshold = hclamp(treshold, 0, 255);
	}

	bool VideoObject::setProperty(chstr name,chstr value)
	{
		if      (name == "video") mClipName = value;
		else if (name == "video_alpha") mUseAlpha = value;
		else if (name == "alpha_pause_treshold") setAlphaTreshold(value);
		else if (name == "loop")  mLoop = value;
		else if (name == "speed") mSpeed = value;
		else if (name == "time")
		{
			if (!mClip && mClipName != "") update(0); // try to create the clip if it hasn't been created already
			if (mClip)
			{
				float time = value;
				mSeeked = 1;
				mClip->seek(time);
			}
			else hlog::warn(logTag, "VideoObject ignoring 'time' param, mClip is NULL");
		}
		else if (name == "audio")
		{
			mAudioName = value;
		}
		else if (name == "sync_offset")
		{
			mAudioSyncOffset = value;
		}
        else if (name == "state")
        {
            if (value == "playing")
            {
                if (mClip && mClip->isPaused()) mClip->play();
            }
            else if (value == "paused")
            {
                if (mClip && !mClip->isPaused()) mClip->pause();
            }
            else throw hl_exception("VideoObject: unable to set state property to '" + value + "'.");
        }
		else return aprilui::ImageBox::setProperty(name, value);
		return 1;
	}

	hstr VideoObject::getProperty(chstr name, bool* property_exists)
	{
		*property_exists = true;
		if      (name == "video") return mClipName;
		else if (name == "video_alpha") return mUseAlpha ? "1" : "0";
		else if (name == "alpha_pause_treshold") return mAlphaPauseTreshold;
		else if (name == "loop")  return mLoop ? "1" : "0";
		else if (name == "speed") return mSpeed;
		else if (name == "time") return this->getTimePosition();
		else if (name == "duration") return mClip ? hstr(mClip->getDuration()) : hstr(0);
		else if (name == "audio")  return mAudioName;
		else if (name == "sync_offset")  return mAudioSyncOffset;
        else if (name == "state")
        {
			if (this->isPlaying()) return "playing";
			if (this->isPaused()) return "paused";
			if (this->isStopped()) return "stopped";
			return "unknown";
        }
		*property_exists = false;
		return ImageBox::getProperty(name, property_exists);
	}

	static void theoraLogMessage(std::string log)
	{
		hlog::write("aprilvideo", log);
	}

	void init(int num_worker_threads)
	{
		TheoraVideoManager::setLogFunction(theoraLogMessage);
		gNumWorkerThreads = num_worker_threads;
		APRILUI_REGISTER_OBJECT_TYPE(VideoObject);
	}

	void destroy()
	{

	}
}
<commit_msg>- aprilui update<commit_after>/************************************************************************************
This source file is part of the Theora Video Playback Library
For latest info, see http://libtheoraplayer.sourceforge.net/
*************************************************************************************
Copyright (c) 2008-2013 Kresimir Spes (kspes@cateia.com)
This program is free software; you can redistribute it and/or modify it under
the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php
*************************************************************************************/
#define THEORAUTIL_NOMACROS
#include <theoraplayer/TheoraException.h>
#undef exception_cls
#include <theoraplayer/TheoraPlayer.h>
#include <theoraplayer/TheoraTimer.h>
#include <april/RenderSystem.h>
#include <april/april.h>
#include <april/Platform.h>
#include <april/Texture.h>
#include <aprilui/aprilui.h>
#include <aprilui/Dataset.h>
#include <aprilui/NullImage.h>
#include <aprilui/Texture.h>
#include <xal/AudioManager.h>
#include <xal/Player.h>
#include <xal/Sound.h>
#include "aprilvideo.h"
#include "AprilVideoDataSource.h"

namespace aprilvideo
{
	static TheoraVideoManager* gVideoManager = NULL;
	static int gRefCount = 0, gNumWorkerThreads = 1;
	hstr logTag = "aprilvideo", defaultFileExtension = ".ogv";

	static int _nextPow2(int x)
	{
		int y;
		for (y = 1; y < x; y *= 2);
		return y;
	}

	class AudioVideoTimer : public TheoraTimer
	{
		float mSyncOffset;
		xal::Player* mPlayer;
		float mT;
		bool mDisabledAudio;
	public:
		AudioVideoTimer(xal::Player* player, float sync_offset)
		{
			mSyncOffset = sync_offset;
			mPlayer = player;
			mT = 0;
			static hstr audiosystem = xal::mgr->getName(); // Disabled" audio system doesn't sync audio & video
			mDisabledAudio = (audiosystem == "Disabled");
		}

		void update(float time_increase)
		{
			if (!mDisabledAudio)
			{
				if (mPlayer->isPlaying())
					mTime = mPlayer->getTimePosition() - mSyncOffset;
				else
					mTime += time_increase;
			}
			else
			{
				mT += time_increase;
				mTime = mT - mSyncOffset;
			}
		}
	};

	VideoObject::VideoObject(chstr name, grect rect) : aprilui::ImageBox(name, rect)
	{
		mUsingAVFoundation = 0;
		mUseAlpha = 0;
		mPrevDoneFlag = 0;
		mLoop = 1;
		mSpeed = 1.0f;
		mClip = NULL;
		mVideoImage = NULL;
		mTexture = NULL;
		mTimer = NULL;
		mSound = NULL;
		mAudioPlayer = NULL;
		mAudioSyncOffset = 0;
		gRefCount++;
		mAlphaPauseTreshold = 0;
		mPrevFrameNumber = 0;
		mSeeked = 0;
        mPrevAlpha = 255;
		if (!gVideoManager)
		{
			gVideoManager = new TheoraVideoManager(gNumWorkerThreads);
			std::vector<std::string> lst = gVideoManager->getSupportedDecoders();
			foreach (std::string, it, lst)
			{
				if (*it == "AVFoundation") defaultFileExtension = ".mp4";
			}
		}
	}

	VideoObject::~VideoObject()
	{
		gRefCount--;
		destroyResources();
		if (gRefCount <= 0 && gVideoManager)
		{
			delete gVideoManager;
			gVideoManager = NULL;
		}
	}

	bool VideoObject::isPlaying()
	{
		return (mClip != NULL && !mClip->isPaused() && !mClip->isDone());
	}

	bool VideoObject::isPaused()
	{
		return (mClip != NULL && mClip->isPaused());
	}

	bool VideoObject::isStopped()
	{
		return (mClip == NULL || mClip->isDone());
	}

	float VideoObject::getTimePosition()
	{
		return (mClip != NULL ? mClip->getTimePosition() : 0.0f);
	}

	aprilui::Object* VideoObject::createInstance(chstr name, grect rect)
	{
		return new VideoObject(name, rect);
	}

	void VideoObject::notifyEvent(chstr name, void* params)
	{
		if (name == "AttachToObject")
		{
			if (mImage != mVideoImage)
			{
				mImage = mDataset->getImage(APRILUI_IMAGE_NAME_NULL);
			}
		}
		ImageBox::notifyEvent(name, params);
	}

	void VideoObject::destroyResources()
	{
		if (mVideoImage)
		{
			delete mVideoImage;
			mVideoImage = NULL;
			mImage = mDataset->getImage(APRILUI_IMAGE_NAME_NULL);
		}
		if (mTexture)
		{
			delete mTexture;
			mTexture = NULL;
		}
		if (mClip)
		{
			gVideoManager->destroyVideoClip(mClip);
			mClip = NULL;
		}
		if (mAudioPlayer)
		{
			xal::mgr->destroyPlayer(mAudioPlayer);
			mAudioPlayer = NULL;
		}
		if (mSound)
		{
			xal::mgr->destroySound(mSound);
			mSound = NULL;
		}

		if (mTimer)
		{
			delete mTimer;
			mTimer = NULL;
		}
	}

	void VideoObject::createClip()
	{
		destroyResources();
		hstr path = mDataset->getFilePath() + "/video/" + mClipName;
		if (!path.ends_with(".ogg") && !path.ends_with(".ogv") && !path.ends_with(".mp4")) path += defaultFileExtension;

		mUsingAVFoundation = path.ends_with(".mp4");
		april::Texture::Format textureFormat;

//		mUsingAVFoundation ? april::Texture::FORMAT_BGRA :
		try
		{
			TheoraOutputMode mode;
			if (april::rendersys->getName().starts_with("OpenGL"))
			{
				if (mUseAlpha)
				{
					mode = TH_RGBA;
					textureFormat = april::Texture::FORMAT_ARGB;
				}
				else
				{
					mode = mUsingAVFoundation ? TH_BGRX : TH_RGBX;
					textureFormat = mUsingAVFoundation ? april::Texture::FORMAT_BGRA : april::Texture::FORMAT_ARGB;

				}
			}
			else
			{
				mode = mUseAlpha ? TH_BGRA : TH_BGRX;
				textureFormat = april::Texture::FORMAT_ARGB;
			}
			int precached = april::getSystemInfo().ram < 512 ? 8 : 16;
			if (path.ends_with("mp4"))
			{

				if (april::window->getName() == "OpenKODE")
					mClip = gVideoManager->createVideoClip("res/" + path, mode, precached);
				else
					mClip = gVideoManager->createVideoClip(path, mode, precached);
			}
			else
				mClip = gVideoManager->createVideoClip(new AprilVideoDataSource(path), mode, precached);
		}
		catch (_TheoraGenericException& e)
		{
			throw hl_exception(e.getErrorText());
		}
		if (mClip->getWidth() == 0) throw hl_exception("Failed to load video file: " + path);
		mClip->setAutoRestart(mLoop);

		float w = mClip->getWidth(), h = mClip->getHeight();
		april::Texture* tex = april::rendersys->createTexture(_nextPow2(w), _nextPow2(h), textureFormat);
		mTexture = new aprilui::Texture(tex->getFilename(), tex);
		mVideoImage = new aprilui::Image(mTexture, "video_img", grect(0, 0, w, h));
		mClip->waitForCache(4 / 16.0f, 0.5f);

		if (mAudioName != "")
		{
			if (!xal::mgr->hasCategory("video"))
			{
				xal::mgr->createCategory("video", xal::ON_DEMAND, xal::DISK);
			}
			mSound = xal::mgr->createSound(mDataset->getFilePath() + "/video/" + mAudioName, "video");

			mAudioPlayer = xal::mgr->createPlayer(mSound->getName());
			mTimer = new AudioVideoTimer(mAudioPlayer, mAudioSyncOffset);
			mClip->setTimer(mTimer);

			mAudioPlayer->play();
		}
		else if (mSpeed != 1.0f) mClip->setPlaybackSpeed(mSpeed);
		update(0); // to grab the first frame.

	}

	void VideoObject::OnDraw()
	{
		if (mClip == NULL && mClipName != "") createClip();

		ImageBox::OnDraw();
	}

	void VideoObject::update(float k)
	{
		ImageBox::update(k);

		if (mClip)
		{
			if (!mLoop)
			{
				bool done = mClip->isDone();
				if (mPrevDoneFlag == 0 && done == 1) triggerEvent("PlaybackDone");
				mPrevDoneFlag = done;
			}
			mClip->update(k);
			//mClip->decodedAudioCheck();
            if (mPrevAlpha != getAlpha())
            {
                mPrevAlpha = getAlpha();
                bool should_pause = mAlphaPauseTreshold == 0 ? !isVisible() : getAlpha() <= mAlphaPauseTreshold;
                if (should_pause && !mClip->isPaused()) mClip->pause();
                else if (!should_pause && mClip->isPaused()) mClip->play();
			}
			TheoraVideoFrame* f = mClip->getNextFrame();
			if (f)
			{
				mImage = mVideoImage;
				grect r = mImage->getSrcRect();
				r.w = f->getWidth();
				r.h = f->getHeight();
				mImage->setSrcRect(r);
#ifdef _ANDROID
				mTexture->load();
#endif
				mTexture->getRenderTexture()->write(0, 0, f->getBuffer(), r.w, r.h, 4);
				mClip->popFrame();
				if (mLoop)
				{
					int number = f->getFrameNumber();
					if (mSeeked) mSeeked = 0;
					else if (number < mPrevFrameNumber)
					{
						triggerEvent("PlaybackDone");
					}
					mPrevFrameNumber = number;
				}
			}
		}
	}

	void VideoObject::setAlphaTreshold(int treshold)
	{
		mAlphaPauseTreshold = hclamp(treshold, 0, 255);
	}

	bool VideoObject::setProperty(chstr name,chstr value)
	{
		if      (name == "video") mClipName = value;
		else if (name == "video_alpha") mUseAlpha = value;
		else if (name == "alpha_pause_treshold") setAlphaTreshold(value);
		else if (name == "loop")  mLoop = value;
		else if (name == "speed") mSpeed = value;
		else if (name == "time")
		{
			if (!mClip && mClipName != "") update(0); // try to create the clip if it hasn't been created already
			if (mClip)
			{
				float time = value;
				mSeeked = 1;
				mClip->seek(time);
			}
			else hlog::warn(logTag, "VideoObject ignoring 'time' param, mClip is NULL");
		}
		else if (name == "audio")
		{
			mAudioName = value;
		}
		else if (name == "sync_offset")
		{
			mAudioSyncOffset = value;
		}
        else if (name == "state")
        {
            if (value == "playing")
            {
                if (mClip && mClip->isPaused()) mClip->play();
            }
            else if (value == "paused")
            {
                if (mClip && !mClip->isPaused()) mClip->pause();
            }
            else throw hl_exception("VideoObject: unable to set state property to '" + value + "'.");
        }
		else return aprilui::ImageBox::setProperty(name, value);
		return 1;
	}

	hstr VideoObject::getProperty(chstr name, bool* property_exists)
	{
		*property_exists = true;
		if      (name == "video") return mClipName;
		else if (name == "video_alpha") return mUseAlpha ? "1" : "0";
		else if (name == "alpha_pause_treshold") return mAlphaPauseTreshold;
		else if (name == "loop")  return mLoop ? "1" : "0";
		else if (name == "speed") return mSpeed;
		else if (name == "time") return this->getTimePosition();
		else if (name == "duration") return mClip ? hstr(mClip->getDuration()) : hstr(0);
		else if (name == "audio")  return mAudioName;
		else if (name == "sync_offset")  return mAudioSyncOffset;
        else if (name == "state")
        {
			if (this->isPlaying()) return "playing";
			if (this->isPaused()) return "paused";
			if (this->isStopped()) return "stopped";
			return "unknown";
        }
		*property_exists = false;
		return ImageBox::getProperty(name, property_exists);
	}

	static void theoraLogMessage(std::string log)
	{
		hlog::write("aprilvideo", log);
	}

	void init(int num_worker_threads)
	{
		TheoraVideoManager::setLogFunction(theoraLogMessage);
		gNumWorkerThreads = num_worker_threads;
		APRILUI_REGISTER_OBJECT_TYPE(VideoObject);
	}

	void destroy()
	{

	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. 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.
//
// 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 <cassert>
#include <cstddef>
#include <iomanip>
#include <map>
#include <sstream>
#include <string>

#include "jit.h"
#include "jump-x86.h"
#include "plugin.h"
#include "version.h"

#ifdef WIN32
	#include <Windows.h>
#else
	#ifndef _GNU_SOURCE
		#define _GNU_SOURCE 1 // for dladdr()
	#endif
	#include <dlfcn.h>
#endif

extern void *pAMXFunctions;

typedef void (*logprintf_t)(const char *format, ...);
static logprintf_t logprintf;

typedef std::map<AMX*, jit::Jitter*> AmxToJitterMap;
static AmxToJitterMap amx2jitter;

static JumpX86 amx_Exec_hook;

static cell *opcodeTable = 0;

static int AMXAPI amx_Exec_JIT(AMX *amx, cell *retval, int index) {
	#if defined __GNUC__ && !defined WIN32
		if ((amx->flags & AMX_FLAG_BROWSE) == AMX_FLAG_BROWSE) {
			assert(::opcodeTable != 0);
			*retval = reinterpret_cast<cell>(::opcodeTable);
			return AMX_ERR_NONE;
		}
	#endif
	AmxToJitterMap::iterator iterator = ::amx2jitter.find(amx);
	if (iterator == ::amx2jitter.end()) {
		// Compilation previously failed, call normal amx_Exec().
		JumpX86::ScopedRemove r(&amx_Exec_hook);
		return amx_Exec(amx, retval, index);
	} else {
		jit::Jitter *jitter = iterator->second;
		return jitter->exec(index, retval);
	}
}

static std::string GetModuleNameBySymbol(void *symbol) {
	char module[FILENAME_MAX] = "";
	if (symbol != 0) {
		#ifdef WIN32
			MEMORY_BASIC_INFORMATION mbi;
			VirtualQuery(symbol, &mbi, sizeof(mbi));
			GetModuleFileName((HMODULE)mbi.AllocationBase, module, FILENAME_MAX);
		#else
			Dl_info info;
			dladdr(symbol, &info);
			strcpy(module, info.dli_fname);
		#endif
	}
	return std::string(module);
}

static std::string GetFileName(const std::string &path) {
	std::string::size_type lastSep = path.find_last_of("/\\");
	if (lastSep != std::string::npos) {
		return path.substr(lastSep + 1);
	}
	return path;
}

static std::string InstrToString(const jit::AmxInstruction &instr) {
	std::stringstream ss;

	const char *name = instr.getName();
	if (name != 0) {
		ss << instr.getName();
	} else {
		ss << std::setw(8) << std::setfill('0') << std::hex << instr.getOpcode();
	}

	std::vector<cell> opers = instr.getOperands();
	for (std::vector<cell>::const_iterator it = opers.begin(); it != opers.end(); ++it) {
		ss << ' ' << std::setw(8) << std::setfill('0') << std::hex << *it;
	}

	return ss.str();
}

static void CompileError(const jit::AmxVm &vm, const jit::AmxInstruction &instr) {
	logprintf("JIT failed to compile instruction at %08x:", instr.getAddress());
	logprintf("  %s", InstrToString(instr).c_str());
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
	logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];
	pAMXFunctions = reinterpret_cast<void*>(ppData[PLUGIN_DATA_AMX_EXPORTS]);

	void *funAddr = JumpX86::GetTargetAddress(((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec]);
	if (funAddr != 0) {
		std::string module = GetFileName(GetModuleNameBySymbol(funAddr));
		if (!module.empty() && module != "samp-server.exe" && module != "samp03svr") {
			logprintf("  JIT must be loaded before %s", module.c_str());
			return false;
		}
	}

	logprintf("  JIT plugin v%s is OK.", PLUGIN_VERSION_STRING);
	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	for (AmxToJitterMap::iterator it = amx2jitter.begin(); it != amx2jitter.end(); ++it) {
		delete it->second;
	}
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
	typedef int (AMXAPI *amx_Exec_t)(AMX *amx, cell *retval, int index);
	amx_Exec_t amx_Exec = (amx_Exec_t)((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec];

	typedef int (AMXAPI *amx_GetAddr_t)(AMX *amx, cell amx_addr, cell **phys_addr);
	amx_GetAddr_t amx_GetAddr = (amx_GetAddr_t)((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_GetAddr];

	#if defined __GNUC__ && !defined WIN32
		// Get opcode list before we hook amx_Exec().
		if (::opcodeTable == 0) {
			amx->flags |= AMX_FLAG_BROWSE;
			amx_Exec(amx, reinterpret_cast<cell*>(&::opcodeTable), 0);
			amx->flags &= ~AMX_FLAG_BROWSE;
		}
	#endif

	jit::Jitter *jitter = new jit::Jitter(amx, ::opcodeTable);
	if (!jitter->compile(CompileError)) {
		delete jitter;
	} else {
		::amx2jitter.insert(std::make_pair(amx, jitter));
	}

	if (!amx_Exec_hook.IsInstalled()) {
		amx_Exec_hook.Install(
			(void*)amx_Exec,
			(void*)amx_Exec_JIT);
	}

	return AMX_ERR_NONE;
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
	AmxToJitterMap::iterator it = amx2jitter.find(amx);
	if (it != amx2jitter.end()) {
		delete it->second;
		amx2jitter.erase(it);
	}
	return AMX_ERR_NONE;
}
<commit_msg>Make AmxLoad() dump code if "dump_code" variable is set<commit_after>// Copyright (c) 2012, Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. 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.
//
// 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 <cassert>
#include <cstddef>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <map>
#include <sstream>
#include <string>

#include "jit.h"
#include "jump-x86.h"
#include "plugin.h"
#include "version.h"

#ifdef WIN32
	#include <Windows.h>
#else
	#ifndef _GNU_SOURCE
		#define _GNU_SOURCE 1 // for dladdr()
	#endif
	#include <dlfcn.h>
#endif

extern void *pAMXFunctions;

typedef void (*logprintf_t)(const char *format, ...);
static logprintf_t logprintf;

typedef std::map<AMX*, jit::Jitter*> AmxToJitterMap;
static AmxToJitterMap amx2jitter;

static JumpX86 amx_Exec_hook;

static cell *opcodeTable = 0;

static int AMXAPI amx_Exec_JIT(AMX *amx, cell *retval, int index) {
	#if defined __GNUC__ && !defined WIN32
		if ((amx->flags & AMX_FLAG_BROWSE) == AMX_FLAG_BROWSE) {
			assert(::opcodeTable != 0);
			*retval = reinterpret_cast<cell>(::opcodeTable);
			return AMX_ERR_NONE;
		}
	#endif
	AmxToJitterMap::iterator iterator = ::amx2jitter.find(amx);
	if (iterator == ::amx2jitter.end()) {
		// Compilation previously failed, call normal amx_Exec().
		JumpX86::ScopedRemove r(&amx_Exec_hook);
		return amx_Exec(amx, retval, index);
	} else {
		jit::Jitter *jitter = iterator->second;
		return jitter->exec(index, retval);
	}
}

static std::string GetModuleNameBySymbol(void *symbol) {
	char module[FILENAME_MAX] = "";
	if (symbol != 0) {
		#ifdef WIN32
			MEMORY_BASIC_INFORMATION mbi;
			VirtualQuery(symbol, &mbi, sizeof(mbi));
			GetModuleFileName((HMODULE)mbi.AllocationBase, module, FILENAME_MAX);
		#else
			Dl_info info;
			dladdr(symbol, &info);
			strcpy(module, info.dli_fname);
		#endif
	}
	return std::string(module);
}

static std::string GetFileName(const std::string &path) {
	std::string::size_type lastSep = path.find_last_of("/\\");
	if (lastSep != std::string::npos) {
		return path.substr(lastSep + 1);
	}
	return path;
}

static std::string InstrToString(const jit::AmxInstruction &instr) {
	std::stringstream ss;

	const char *name = instr.getName();
	if (name != 0) {
		ss << instr.getName();
	} else {
		ss << std::setw(8) << std::setfill('0') << std::hex << instr.getOpcode();
	}

	std::vector<cell> opers = instr.getOperands();
	for (std::vector<cell>::const_iterator it = opers.begin(); it != opers.end(); ++it) {
		ss << ' ' << std::setw(8) << std::setfill('0') << std::hex << *it;
	}

	return ss.str();
}

static void CompileError(const jit::AmxVm &vm, const jit::AmxInstruction &instr) {
	logprintf("JIT failed to compile instruction at %08x:", instr.getAddress());
	logprintf("  %s", InstrToString(instr).c_str());
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
	logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];
	pAMXFunctions = reinterpret_cast<void*>(ppData[PLUGIN_DATA_AMX_EXPORTS]);

	void *funAddr = JumpX86::GetTargetAddress(((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec]);
	if (funAddr != 0) {
		std::string module = GetFileName(GetModuleNameBySymbol(funAddr));
		if (!module.empty() && module != "samp-server.exe" && module != "samp03svr") {
			logprintf("  JIT must be loaded before %s", module.c_str());
			return false;
		}
	}

	logprintf("  JIT plugin v%s is OK.", PLUGIN_VERSION_STRING);
	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	for (AmxToJitterMap::iterator it = amx2jitter.begin(); it != amx2jitter.end(); ++it) {
		delete it->second;
	}
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
	typedef int (AMXAPI *amx_Exec_t)(AMX *amx, cell *retval, int index);
	amx_Exec_t amx_Exec = (amx_Exec_t)((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec];

	typedef int (AMXAPI *amx_GetAddr_t)(AMX *amx, cell amx_addr, cell **phys_addr);
	amx_GetAddr_t amx_GetAddr = (amx_GetAddr_t)((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_GetAddr];

	#if defined __GNUC__ && !defined WIN32
		// Get opcode list before we hook amx_Exec().
		if (::opcodeTable == 0) {
			amx->flags |= AMX_FLAG_BROWSE;
			amx_Exec(amx, reinterpret_cast<cell*>(&::opcodeTable), 0);
			amx->flags &= ~AMX_FLAG_BROWSE;
		}
	#endif

	jit::Jitter *jitter = new jit::Jitter(amx, ::opcodeTable);
	if (!jitter->compile(CompileError)) {
		delete jitter;
	} else {
		::amx2jitter.insert(std::make_pair(amx, jitter));
		const char *dump_code = getenv("dump_code");
		if (dump_code != 0 && atoi(dump_code) != 0) {
			std::ofstream dump("jit.bin");
			if (dump.is_open()) {
				dump.write(reinterpret_cast<char*>(jitter->getCode()), jitter->getCodeSize());
				dump.close();
			}
		}
	}

	if (!amx_Exec_hook.IsInstalled()) {
		amx_Exec_hook.Install(
			(void*)amx_Exec,
			(void*)amx_Exec_JIT);
	}

	return AMX_ERR_NONE;
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
	AmxToJitterMap::iterator it = amx2jitter.find(amx);
	if (it != amx2jitter.end()) {
		delete it->second;
		amx2jitter.erase(it);
	}
	return AMX_ERR_NONE;
}
<|endoftext|>