<commit_before>#include "gridmap.hpp"
#include "../utils/utils.hpp"
#include "../utils/geom2d.hpp"
#include "../graphics/image.hpp"
#include <string>
#include <cstring>
#include <cstdio>
#include <cerrno>

static const char *mappath;
static const char *outpath;

static void parseargs(int, char*[]);
static void helpmsg(int);

enum {
	// BlkSz is the size (in points or something) of each
	// grid block in the output image.
	BlkSz = 1,
};

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

	FILE *mapfile = stdin;
	if (mappath != NULL) {
		mapfile = fopen(mappath, "r");
		if (!mapfile)
			fatalx(errno, "Failed to open %s for reading", mapfile);
	} else {
		mappath = "<untitled>";
	}
	GridMap map(mapfile);
	Image img(map.w*BlkSz, map.h*BlkSz, mappath);

	for (unsigned int x = 0; x < map.w; x++) {
	for (unsigned int y = 0; y < map.h; y++) {
		if (!map.blkd(map.index(x, y)))
			continue;

		for (unsigned int i = 0; i < BlkSz; i++) {
		for (unsigned int j = 0; j < BlkSz; j++) {
			img.setpixel(x*BlkSz + i, map.h - (y*BlkSz + j) -1, Image::black);
		}
		}
	}
	}

	FILE *outfile = stdout;
	if (outpath != NULL && strcmp(outpath, "-") != 0) {
		outfile = fopen(outpath, "w");
		if (!outfile)
			fatalx(errno, "Failed to open %s for writing", outpath);
	}
	img.writeeps(outfile);

	return 0;
}

static void parseargs(int argc, char *argv[]) {
	for (int i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-h") == 0) {
			helpmsg(0);

		}else if (i < argc-1 && strcmp(argv[i], "-o") == 0) {
			outpath = argv[++i];

		} else if (mappath != NULL) {
			helpmsg(1);

		} else {
			mappath = argv[i];
		}
	}
}

static void helpmsg(int status) {
	puts("Usage: draw [options] <map path>");
	puts("-h	print this help message");
	puts("-o <path>	specify the output path, '-' for standard output");
	exit(status);
}<commit_msg>gridnav: add the -cellsz argument to draw.<commit_after>#include "gridmap.hpp"
#include "../utils/utils.hpp"
#include "../utils/geom2d.hpp"
#include "../graphics/image.hpp"
#include <string>
#include <cstring>
#include <cstdio>
#include <cerrno>

static const char *mappath;
static const char *outpath;
static unsigned int cellsz = 1;

static void parseargs(int, char*[]);
static void helpmsg(int);

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

	FILE *mapfile = stdin;
	if (mappath != NULL) {
		mapfile = fopen(mappath, "r");
		if (!mapfile)
			fatalx(errno, "Failed to open %s for reading", mapfile);
	} else {
		mappath = "<untitled>";
	}
	GridMap map(mapfile);
	Image img(map.w*cellsz, map.h*cellsz, mappath);

	for (unsigned int x = 0; x < map.w; x++) {
	for (unsigned int y = 0; y < map.h; y++) {
		if (!map.blkd(map.index(x, y)))
			continue;

		for (unsigned int i = 0; i < cellsz; i++) {
		for (unsigned int j = 0; j < cellsz; j++) {
			img.setpixel(x*cellsz + i, map.h - (y*cellsz + j) -1, Image::black);
		}
		}
	}
	}

	FILE *outfile = stdout;
	if (outpath != NULL && strcmp(outpath, "-") != 0) {
		outfile = fopen(outpath, "w");
		if (!outfile)
			fatalx(errno, "Failed to open %s for writing", outpath);
	}
	img.writeeps(outfile);

	return 0;
}

static void parseargs(int argc, char *argv[]) {
	for (int i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-h") == 0) {
			helpmsg(0);

		}else if (i < argc-1 && strcmp(argv[i], "-o") == 0) {
			outpath = argv[++i];

		}else if (i < argc-1 && strcmp(argv[i], "-cellsz") == 0) {
			cellsz = strtol(argv[++i], NULL, 0);

		} else if (mappath != NULL) {
			helpmsg(1);

		} else {
			mappath = argv[i];
		}
	}
}

static void helpmsg(int status) {
	puts("Usage: draw [options] <map path>");
	puts("-h	print this help message");
	puts("-o <path>	specify the output path, '-' for standard output");
	puts("-cellsz <number>	specify the size (in pixels) of each grid cell");
	exit(status);
}<|endoftext|>


<commit_before>#define MS_CLASS "RTC::RtpStreamSend"
// #define MS_LOG_DEV

#include "RTC/RtpStreamSend.h"
#include "Logger.h"

#define RTP_SEQ_MOD (1<<16)
#define MAX_RETRANSMISSION_AGE 200 // Don't retransmit packets older than this (ms).

// Usage:
//   MS_DEBUG_DEV("Leading text "UINT16_TO_BINARY_PATTERN, UINT16_TO_BINARY(bytes));
#define UINT16_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"
#define UINT16_TO_BINARY(bytes)  \
  (bytes & 0x8000 ? '1' : '0'), \
  (bytes & 0x4000 ? '1' : '0'), \
  (bytes & 0x2000 ? '1' : '0'), \
  (bytes & 0x1000 ? '1' : '0'), \
  (bytes & 0x800 ? '1' : '0'), \
  (bytes & 0x400 ? '1' : '0'), \
  (bytes & 0x200 ? '1' : '0'), \
  (bytes & 0x100 ? '1' : '0'), \
  (bytes & 0x80 ? '1' : '0'), \
  (bytes & 0x40 ? '1' : '0'), \
  (bytes & 0x20 ? '1' : '0'), \
  (bytes & 0x10 ? '1' : '0'), \
  (bytes & 0x08 ? '1' : '0'), \
  (bytes & 0x04 ? '1' : '0'), \
  (bytes & 0x02 ? '1' : '0'), \
  (bytes & 0x01 ? '1' : '0')

namespace RTC
{
	/* Instance methods. */

	RtpStreamSend::RtpStreamSend(uint32_t clockRate, size_t bufferSize) :
		RtpStream::RtpStream(clockRate),
		storage(bufferSize)
	{
		MS_TRACE();
	}

	RtpStreamSend::~RtpStreamSend()
	{
		MS_TRACE();

		// Clear buffer.
		ClearBuffer();
	}

	bool RtpStreamSend::ReceivePacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		// Call the parent method.
		if (!RtpStream::ReceivePacket(packet))
			return false;

		// If bufferSize was given, store the packet into the buffer.
		if (this->storage.size() > 0)
			StorePacket(packet);

		return true;
	}

	// This method looks for the requested RTP packets and inserts them into the
	// given container (and set to null the next container position).
	void RtpStreamSend::RequestRtpRetransmission(uint16_t seq, uint16_t bitmask, std::vector<RTC::RtpPacket*>& container)
	{
		MS_TRACE();

		// 17: 16 bit mask + the initial sequence number.
		static size_t maxRequestedPackets = 17;

		// If the buffer is empty, just return.
		if (this->buffer.size() == 0)
			return;

		// Convert the given sequence numbers to 32 bits.
		uint32_t first_seq32 = (uint32_t)seq + this->cycles;
		uint32_t last_seq32 = first_seq32 + maxRequestedPackets - 1;
		size_t container_idx = 0;

		// Number of requested packets cannot be greater than the container size - 1.
		MS_ASSERT(container.size() - 1 >= maxRequestedPackets, "RtpPacket container is too small");

		auto buffer_it = this->buffer.begin();
		auto buffer_it_r = this->buffer.rbegin();
		uint32_t buffer_first_seq32 = (*buffer_it).seq32;
		uint32_t buffer_last_seq32 = (*buffer_it_r).seq32;

		// Requested packet range not found.
		if (first_seq32 > buffer_last_seq32 || last_seq32 < buffer_first_seq32)
		{
			// Let's try with sequence numbers in the previous 16 cycle.
			if (this->cycles > 0)
			{
				first_seq32 -= RTP_SEQ_MOD;
				last_seq32 -= RTP_SEQ_MOD;

				// Try again.
				if (first_seq32 > buffer_last_seq32 || last_seq32 < buffer_first_seq32)
					return;
			}
			// Otherwise just return.
			else
			{
				MS_WARN_TAG(rtp, "requested range not in the buffer");

				return;
			}
		}

		// Look for each requested packet.
		uint32_t seq32 = first_seq32;
		bool requested = true;

		// Some variables for debugging.
		uint16_t orig_bitmask = bitmask;
		uint16_t sent_bitmask = 0b0000000000000000;
		uint8_t counter = 0;
		bool first_packet_sent = false;

		do
		{
			bool sent = false;

			if (requested)
			{
				for (; buffer_it != this->buffer.end(); ++buffer_it)
				{
					auto current_seq32 = (*buffer_it).seq32;

					// Found.
					if (current_seq32 == seq32)
					{
						auto current_packet = (*buffer_it).packet;

						// Just provide the packet if no older than MAX_RETRANSMISSION_AGE ms.
						uint16_t diff = (this->max_timestamp - current_packet->GetTimestamp()) * 1000 / this->clockRate;

						if (diff <= MAX_RETRANSMISSION_AGE)
						{
							// Store the packet in the container and then increment its index.
							container[container_idx++] = current_packet;

							sent = true;
							if (counter == 0)
								first_packet_sent = true;
						}
						else
						{
							MS_WARN_TAG(rtp, "ignoring retransmission for a packet older than %d ms", MAX_RETRANSMISSION_AGE);
						}

						// Exit the loop.
						break;
					}
				}
			}

			requested = (bitmask & 1) ? true : false;
			bitmask >>= 1;
			++seq32;

			// For debugging.
			// NOTE: We don't check whether the first requested packet is sent but
			// just the next 16.
			if (counter > 0)
				sent_bitmask |= (sent ? 1 : 0) << (counter - 1);
			++counter;
		}
		while (bitmask != 0);

		// TODO:
		MS_WARN_TAG(rtcp, "[first_packet_sent:%d, bitmask:" UINT16_TO_BINARY_PATTERN ", sent: " UINT16_TO_BINARY_PATTERN "]",
			first_packet_sent, UINT16_TO_BINARY(orig_bitmask), UINT16_TO_BINARY(sent_bitmask));

		// Set the next container element to null.
		container[container_idx] = nullptr;
	}

	void RtpStreamSend::ClearBuffer()
	{
		MS_TRACE();

		// Delete cloned packets.
		for (auto& buffer_item : this->buffer)
		{
			delete buffer_item.packet;
		}

		// Clear list.
		this->buffer.clear();
	}

	inline
	void RtpStreamSend::StorePacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		// Sum the packet seq number and the number of 16 bits cycles.
		uint32_t packet_seq32 = (uint32_t)packet->GetSequenceNumber() + this->cycles;
		BufferItem buffer_item;

		buffer_item.seq32 = packet_seq32;

		// If empty do it easy.
		if (this->buffer.size() == 0)
		{
			auto store = this->storage[0].store;

			buffer_item.packet = packet->Clone(store);
			this->buffer.push_back(buffer_item);

			return;
		}

		// Otherwise, do the stuff.

		Buffer::iterator new_buffer_it;
		uint8_t* store = nullptr;

		// Iterate the buffer in reverse order and find the proper place to store the
		// packet.
		auto buffer_it_r = this->buffer.rbegin();
		for (; buffer_it_r != this->buffer.rend(); ++buffer_it_r)
		{
			auto current_seq32 = (*buffer_it_r).seq32;

			if (packet_seq32 > current_seq32)
			{
				// Get a forward iterator pointing to the same element.
				auto it = buffer_it_r.base();

				new_buffer_it = this->buffer.insert(it, buffer_item);

				// Exit the loop.
				break;
			}
		}
		// If the packet was older than anything in the buffer, just ignore it.
		// NOTE: This should never happen.
		if (buffer_it_r == this->buffer.rend())
		{
			MS_WARN_TAG(rtp, "packet is older than anything in the buffer, ignoring it");

			return;
		}

		// If the buffer is not full use the next free storage item.
		if (this->buffer.size() - 1 < this->storage.size())
		{
			store = this->storage[this->buffer.size() - 1].store;
		}
		// Otherwise remove the first packet of the buffer and replace its storage area.
		else
		{
			auto& first_buffer_item = *(this->buffer.begin());
			auto first_packet = first_buffer_item.packet;

			// Store points to the store used by the first packet.
			store = (uint8_t*)first_packet->GetData();
			// Free the first packet.
			delete first_packet;
			// Remove the first element in the list.
			this->buffer.pop_front();
		}

		// Update the new buffer item so it points to the cloned packed.
		(*new_buffer_it).packet = packet->Clone(store);
	}

	// TODO: TMP
	void RtpStreamSend::Dump()
	{
		MS_TRACE();

		MS_DEBUG_TAG(rtp, "<RtpStreamSend>");

		MS_DEBUG_TAG(rtp, "  [buffer.size:%zu, storage.size:%zu]", this->buffer.size(), this->storage.size());

		for (auto& buffer_item : this->buffer)
		{
			auto packet = buffer_item.packet;

			MS_DEBUG_TAG(rtp, "  packet [seq:%" PRIu16 ", seq32:%" PRIu32 "]", packet->GetSequenceNumber(), buffer_item.seq32);
		}

		MS_DEBUG_TAG(rtp, "</RtpStreamSend>");
	}
}
<commit_msg>more on RtpStreamSend<commit_after>#define MS_CLASS "RTC::RtpStreamSend"
// #define MS_LOG_DEV

#include "RTC/RtpStreamSend.h"
#include "Logger.h"

#define RTP_SEQ_MOD (1<<16)
#define MAX_RETRANSMISSION_AGE 200 // Don't retransmit packets older than this (ms).

// Usage:
//   MS_DEBUG_DEV("Leading text "UINT16_TO_BINARY_PATTERN, UINT16_TO_BINARY(bytes));
#define UINT16_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"
#define UINT16_TO_BINARY(bytes)  \
  (bytes & 0x8000 ? '1' : '0'), \
  (bytes & 0x4000 ? '1' : '0'), \
  (bytes & 0x2000 ? '1' : '0'), \
  (bytes & 0x1000 ? '1' : '0'), \
  (bytes & 0x800 ? '1' : '0'), \
  (bytes & 0x400 ? '1' : '0'), \
  (bytes & 0x200 ? '1' : '0'), \
  (bytes & 0x100 ? '1' : '0'), \
  (bytes & 0x80 ? '1' : '0'), \
  (bytes & 0x40 ? '1' : '0'), \
  (bytes & 0x20 ? '1' : '0'), \
  (bytes & 0x10 ? '1' : '0'), \
  (bytes & 0x08 ? '1' : '0'), \
  (bytes & 0x04 ? '1' : '0'), \
  (bytes & 0x02 ? '1' : '0'), \
  (bytes & 0x01 ? '1' : '0')

namespace RTC
{
	/* Instance methods. */

	RtpStreamSend::RtpStreamSend(uint32_t clockRate, size_t bufferSize) :
		RtpStream::RtpStream(clockRate),
		storage(bufferSize)
	{
		MS_TRACE();
	}

	RtpStreamSend::~RtpStreamSend()
	{
		MS_TRACE();

		// Clear buffer.
		ClearBuffer();
	}

	bool RtpStreamSend::ReceivePacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		// Call the parent method.
		if (!RtpStream::ReceivePacket(packet))
			return false;

		// If bufferSize was given, store the packet into the buffer.
		if (this->storage.size() > 0)
			StorePacket(packet);

		return true;
	}

	// This method looks for the requested RTP packets and inserts them into the
	// given container (and set to null the next container position).
	void RtpStreamSend::RequestRtpRetransmission(uint16_t seq, uint16_t bitmask, std::vector<RTC::RtpPacket*>& container)
	{
		MS_TRACE();

		// 17: 16 bit mask + the initial sequence number.
		static size_t maxRequestedPackets = 17;

		// If the buffer is empty, just return.
		if (this->buffer.size() == 0)
			return;

		// Convert the given sequence numbers to 32 bits.
		uint32_t first_seq32 = (uint32_t)seq + this->cycles;
		uint32_t last_seq32 = first_seq32 + maxRequestedPackets - 1;
		size_t container_idx = 0;

		// Number of requested packets cannot be greater than the container size - 1.
		MS_ASSERT(container.size() - 1 >= maxRequestedPackets, "RtpPacket container is too small");

		auto buffer_it = this->buffer.begin();
		auto buffer_it_r = this->buffer.rbegin();
		uint32_t buffer_first_seq32 = (*buffer_it).seq32;
		uint32_t buffer_last_seq32 = (*buffer_it_r).seq32;

		// Requested packet range not found.
		if (first_seq32 > buffer_last_seq32 || last_seq32 < buffer_first_seq32)
		{
			// Let's try with sequence numbers in the previous 16 cycle.
			if (this->cycles > 0)
			{
				first_seq32 -= RTP_SEQ_MOD;
				last_seq32 -= RTP_SEQ_MOD;

				// Try again.
				if (first_seq32 > buffer_last_seq32 || last_seq32 < buffer_first_seq32)
					return;
			}
			// Otherwise just return.
			else
			{
				MS_WARN_TAG(rtp, "requested range not in the buffer");

				return;
			}
		}

		// Look for each requested packet.
		uint32_t seq32 = first_seq32;
		bool requested = true;

		// Some variables for debugging.
		uint16_t orig_bitmask = bitmask;
		uint16_t sent_bitmask = 0b0000000000000000;
		int8_t bitmask_counter = -1;
		bool first_packet_sent = false;

		do
		{
			bool sent = false;

			if (requested)
			{
				for (; buffer_it != this->buffer.end(); ++buffer_it)
				{
					auto current_seq32 = (*buffer_it).seq32;

					// Found.
					if (current_seq32 == seq32)
					{
						auto current_packet = (*buffer_it).packet;

						// Just provide the packet if no older than MAX_RETRANSMISSION_AGE ms.
						uint16_t diff = (this->max_timestamp - current_packet->GetTimestamp()) * 1000 / this->clockRate;

						if (diff <= MAX_RETRANSMISSION_AGE)
						{
							// Store the packet in the container and then increment its index.
							container[container_idx++] = current_packet;

							sent = true;
							if (bitmask_counter == -1)
								first_packet_sent = true;
						}
						else
						{
							MS_WARN_TAG(rtp, "ignoring retransmission for a packet older than %d ms", MAX_RETRANSMISSION_AGE);
						}

						// Exit the loop.
						break;
					}
				}
			}

			requested = (bitmask & 1) ? true : false;
			bitmask >>= 1;
			++seq32;

			// For debugging.
			if (bitmask_counter >= 0)
				sent_bitmask |= (sent ? 1 : 0) << bitmask_counter;
			++bitmask_counter;
		}
		while (bitmask != 0);

		// TODO:
		MS_WARN_TAG(rtcp, "[first_packet_sent:%d, bitmask:" UINT16_TO_BINARY_PATTERN ", sent: " UINT16_TO_BINARY_PATTERN "]",
			first_packet_sent, UINT16_TO_BINARY(orig_bitmask), UINT16_TO_BINARY(sent_bitmask));

		// Set the next container element to null.
		container[container_idx] = nullptr;
	}

	void RtpStreamSend::ClearBuffer()
	{
		MS_TRACE();

		// Delete cloned packets.
		for (auto& buffer_item : this->buffer)
		{
			delete buffer_item.packet;
		}

		// Clear list.
		this->buffer.clear();
	}

	inline
	void RtpStreamSend::StorePacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		// Sum the packet seq number and the number of 16 bits cycles.
		uint32_t packet_seq32 = (uint32_t)packet->GetSequenceNumber() + this->cycles;
		BufferItem buffer_item;

		buffer_item.seq32 = packet_seq32;

		// If empty do it easy.
		if (this->buffer.size() == 0)
		{
			auto store = this->storage[0].store;

			buffer_item.packet = packet->Clone(store);
			this->buffer.push_back(buffer_item);

			return;
		}

		// Otherwise, do the stuff.

		Buffer::iterator new_buffer_it;
		uint8_t* store = nullptr;

		// Iterate the buffer in reverse order and find the proper place to store the
		// packet.
		auto buffer_it_r = this->buffer.rbegin();
		for (; buffer_it_r != this->buffer.rend(); ++buffer_it_r)
		{
			auto current_seq32 = (*buffer_it_r).seq32;

			if (packet_seq32 > current_seq32)
			{
				// Get a forward iterator pointing to the same element.
				auto it = buffer_it_r.base();

				new_buffer_it = this->buffer.insert(it, buffer_item);

				// Exit the loop.
				break;
			}
		}
		// If the packet was older than anything in the buffer, just ignore it.
		// NOTE: This should never happen.
		if (buffer_it_r == this->buffer.rend())
		{
			MS_WARN_TAG(rtp, "packet is older than anything in the buffer, ignoring it");

			return;
		}

		// If the buffer is not full use the next free storage item.
		if (this->buffer.size() - 1 < this->storage.size())
		{
			store = this->storage[this->buffer.size() - 1].store;
		}
		// Otherwise remove the first packet of the buffer and replace its storage area.
		else
		{
			auto& first_buffer_item = *(this->buffer.begin());
			auto first_packet = first_buffer_item.packet;

			// Store points to the store used by the first packet.
			store = (uint8_t*)first_packet->GetData();
			// Free the first packet.
			delete first_packet;
			// Remove the first element in the list.
			this->buffer.pop_front();
		}

		// Update the new buffer item so it points to the cloned packed.
		(*new_buffer_it).packet = packet->Clone(store);
	}

	// TODO: TMP
	void RtpStreamSend::Dump()
	{
		MS_TRACE();

		MS_DEBUG_TAG(rtp, "<RtpStreamSend>");

		MS_DEBUG_TAG(rtp, "  [buffer.size:%zu, storage.size:%zu]", this->buffer.size(), this->storage.size());

		for (auto& buffer_item : this->buffer)
		{
			auto packet = buffer_item.packet;

			MS_DEBUG_TAG(rtp, "  packet [seq:%" PRIu16 ", seq32:%" PRIu32 "]", packet->GetSequenceNumber(), buffer_item.seq32);
		}

		MS_DEBUG_TAG(rtp, "</RtpStreamSend>");
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 the V8 project authors & Olivier Lalonde.
#include <v8.h>
#include <v8-testing.h>
#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

void RunShell(v8::Handle<v8::Context> context);
bool ExecuteString(v8::Handle<v8::String> source,
                   v8::Handle<v8::Value> name,
                   bool print_result,
                   bool report_exceptions);
v8::Handle<v8::Value> Print(const v8::Arguments& args);
v8::Handle<v8::Value> Read(const v8::Arguments& args);
v8::Handle<v8::Value> Load(const v8::Arguments& args);
v8::Handle<v8::Value> Quit(const v8::Arguments& args);
v8::Handle<v8::Value> Version(const v8::Arguments& args);
v8::Handle<v8::String> ReadFile(const char* name);
void ReportException(v8::TryCatch* handler);

// We need those two libraries for the GTK+ notification
#include <gtkmm.h>
#include <libnotifymm.h>
v8::Handle<v8::Value> Alert(const v8::Arguments& args);

int RunMain(int argc, char* argv[]) {
  v8::HandleScope handle_scope;
  // Create a template for the global object.
  v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
  // Bind the global 'print' function to the C++ Print callback.
  global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
  // Bind the global 'alert' function to the C++ Alert callback.
  global->Set(v8::String::New("alert"), v8::FunctionTemplate::New(Alert));
  // Bind the global 'read' function to the C++ Read callback.
  global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read));
  // Bind the global 'load' function to the C++ Load callback.
  global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
  // Bind the 'quit' function
  global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit));
  // Bind the 'version' function
  global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
  // Create a new execution environment containing the built-in
  // functions
  v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
  bool run_shell = (argc == 1);
  for (int i = 1; i < argc; i++) {
    // Enter the execution environment before evaluating any code.
    v8::Context::Scope context_scope(context);
    const char* str = argv[i];
    if (strcmp(str, "--shell") == 0) {
      run_shell = true;
    } else if (strcmp(str, "-f") == 0) {
      // Ignore any -f flags for compatibility with the other stand-
      // alone JavaScript engines.
      continue;
    } else if (strncmp(str, "--", 2) == 0) {
      printf("Warning: unknown flag %s.\nTry --help for options\n", str);
    } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
      // Execute argument given to -e option directly
      v8::HandleScope handle_scope;
      v8::Handle<v8::String> file_name = v8::String::New("unnamed");
      v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
      if (!ExecuteString(source, file_name, false, true))
        return 1;
      i++;
    } else {
      // Use all other arguments as names of files to load and run.
      v8::HandleScope handle_scope;
      v8::Handle<v8::String> file_name = v8::String::New(str);
      v8::Handle<v8::String> source = ReadFile(str);
      if (source.IsEmpty()) {
        printf("Error reading '%s'\n", str);
        return 1;
      }
      if (!ExecuteString(source, file_name, false, true))
        return 1;
    }
  }
  if (run_shell) RunShell(context);
  context.Dispose();
  return 0;
}

int main(int argc, char* argv[]) {
  // Figure out if we're requested to stress the optimization
  // infrastructure by running tests multiple times and forcing
  // optimization in the last run.
  bool FLAG_stress_opt = false;
  bool FLAG_stress_deopt = false;
  for (int i = 0; i < argc; i++) {
    if (strcmp(argv[i], "--stress-opt") == 0) {
      FLAG_stress_opt = true;
      argv[i] = NULL;
    } else if (strcmp(argv[i], "--stress-deopt") == 0) {
      FLAG_stress_deopt = true;
      argv[i] = NULL;
    } else if (strcmp(argv[i], "--noalways-opt") == 0) {
      // No support for stressing if we can't use --always-opt.
      FLAG_stress_opt = false;
      FLAG_stress_deopt = false;
      break;
    }
  }

  v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
  int result = 0;
  if (FLAG_stress_opt || FLAG_stress_deopt) {
    v8::Testing::SetStressRunType(FLAG_stress_opt
                                  ? v8::Testing::kStressTypeOpt
                                  : v8::Testing::kStressTypeDeopt);
    int stress_runs = v8::Testing::GetStressRuns();
    for (int i = 0; i < stress_runs && result == 0; i++) {
      printf("============ Stress %d/%d ============\n",
             i + 1, stress_runs);
      v8::Testing::PrepareStressRun(i);
      result = RunMain(argc, argv);
    }
  } else {
    result = RunMain(argc, argv);
  }
  v8::V8::Dispose();
  return result;
}

// Extracts a C string from a V8 Utf8Value.
const char* ToCString(const v8::String::Utf8Value& value) {
  return *value ? *value : "<string conversion failed>";
}

// The callback that is invoked by v8 whenever the JavaScript 'print'
// function is called.  Prints its arguments on stdout separated by
// spaces and ending with a newline.
v8::Handle<v8::Value> Print(const v8::Arguments& args) {
  bool first = true;
  for (int i = 0; i < args.Length(); i++) {
    v8::HandleScope handle_scope;
    if (first) {
      first = false;
    } else {
      printf(" ");
    }
    v8::String::Utf8Value str(args[i]);
    const char* cstr = ToCString(str);
    printf("%s", cstr);
  }
  printf("\n");
  fflush(stdout);
  return v8::Undefined();
}

// The callback that is invoked by v8 whenever the JavaScript 'read'
// function is called.  This function loads the content of the file named in
// the argument into a JavaScript string.
v8::Handle<v8::Value> Read(const v8::Arguments& args) {
  if (args.Length() != 1) {
    return v8::ThrowException(v8::String::New("Bad parameters"));
  }
  v8::String::Utf8Value file(args[0]);
  if (*file == NULL) {
    return v8::ThrowException(v8::String::New("Error loading file"));
  }
  v8::Handle<v8::String> source = ReadFile(*file);
  if (source.IsEmpty()) {
    return v8::ThrowException(v8::String::New("Error loading file"));
  }
  return source;
}

// The callback that is invoked by v8 whenever the JavaScript 'load'
// function is called.  Loads, compiles and executes its argument
// JavaScript file.
v8::Handle<v8::Value> Load(const v8::Arguments& args) {
  for (int i = 0; i < args.Length(); i++) {
    v8::HandleScope handle_scope;
    v8::String::Utf8Value file(args[i]);
    if (*file == NULL) {
      return v8::ThrowException(v8::String::New("Error loading file"));
    }
    v8::Handle<v8::String> source = ReadFile(*file);
    if (source.IsEmpty()) {
      return v8::ThrowException(v8::String::New("Error loading file"));
    }
    if (!ExecuteString(source, v8::String::New(*file), false, false)) {
      return v8::ThrowException(v8::String::New("Error executing file"));
    }
  }
  return v8::Undefined();
}

// The callback that is invoked by v8 whenever the JavaScript 'quit'
// function is called.  Quits.
v8::Handle<v8::Value> Quit(const v8::Arguments& args) {
  // If not arguments are given args[0] will yield undefined which
  // converts to the integer value 0.
  int exit_code = args[0]->Int32Value();
  exit(exit_code);
  return v8::Undefined();
}

v8::Handle<v8::Value> Version(const v8::Arguments& args) {
  return v8::String::New(v8::V8::GetVersion());
}

// Reads a file into a v8 string.
v8::Handle<v8::String> ReadFile(const char* name) {
  FILE* file = fopen(name, "rb");
  if (file == NULL) return v8::Handle<v8::String>();

  fseek(file, 0, SEEK_END);
  int size = ftell(file);
  rewind(file);

  char* chars = new char[size + 1];
  chars[size] = '\0';
  for (int i = 0; i < size;) {
    int read = fread(&chars[i], 1, size - i, file);
    i += read;
  }
  fclose(file);
  v8::Handle<v8::String> result = v8::String::New(chars, size);
  delete[] chars;
  return result;
}

// The read-eval-execute loop of the shell.
void RunShell(v8::Handle<v8::Context> context) {
  printf("V8 version %s\n", v8::V8::GetVersion());
  static const int kBufferSize = 256;
  // Enter the execution environment before evaluating any code.
  v8::Context::Scope context_scope(context);
  while (true) {
    char buffer[kBufferSize];
    printf("> ");
    char* str = fgets(buffer, kBufferSize, stdin);
    if (str == NULL) break;
    v8::HandleScope handle_scope;
    ExecuteString(v8::String::New(str),
                  v8::String::New("(shell)"),
                  true,
                  true);
  }
  printf("\n");
}

// Executes a string within the current v8 context.
bool ExecuteString(v8::Handle<v8::String> source,
                   v8::Handle<v8::Value> name,
                   bool print_result,
                   bool report_exceptions) {
  v8::HandleScope handle_scope;
  v8::TryCatch try_catch;
  v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
  if (script.IsEmpty()) {
    // Print errors that happened during compilation.
    if (report_exceptions)
      ReportException(&try_catch);
    return false;
  } else {
    v8::Handle<v8::Value> result = script->Run();
    if (result.IsEmpty()) {
      assert(try_catch.HasCaught());
      // Print errors that happened during execution.
      if (report_exceptions)
        ReportException(&try_catch);
      return false;
    } else {
      assert(!try_catch.HasCaught());
      if (print_result && !result->IsUndefined()) {
        // If all went well and the result wasn't undefined then print
        // the returned value.
        v8::String::Utf8Value str(result);
        const char* cstr = ToCString(str);
        printf("%s\n", cstr);
      }
      return true;
    }
  }
}

void ReportException(v8::TryCatch* try_catch) {
  v8::HandleScope handle_scope;
  v8::String::Utf8Value exception(try_catch->Exception());
  const char* exception_string = ToCString(exception);
  v8::Handle<v8::Message> message = try_catch->Message();
  if (message.IsEmpty()) {
    // V8 didn't provide any extra information about this error; just
    // print the exception.
    printf("%s\n", exception_string);
  } else {
    // Print (filename):(line number): (message).
    v8::String::Utf8Value filename(message->GetScriptResourceName());
    const char* filename_string = ToCString(filename);
    int linenum = message->GetLineNumber();
    printf("%s:%i: %s\n", filename_string, linenum, exception_string);
    // Print line of source code.
    v8::String::Utf8Value sourceline(message->GetSourceLine());
    const char* sourceline_string = ToCString(sourceline);
    printf("%s\n", sourceline_string);
    // Print wavy underline (GetUnderline is deprecated).
    int start = message->GetStartColumn();
    for (int i = 0; i < start; i++) {
      printf(" ");
    }
    int end = message->GetEndColumn();
    for (int i = start; i < end; i++) {
      printf("^");
    }
    printf("\n");
    v8::String::Utf8Value stack_trace(try_catch->StackTrace());
    if (stack_trace.length() > 0) {
      const char* stack_trace_string = ToCString(stack_trace);
      printf("%s\n", stack_trace_string);
    }
  }
}

// The callback that is invoked by v8 whenever the JavaScript 'alert'
// function is called.  Displays a GTK+ notification.
v8::Handle<v8::Value> Alert(const v8::Arguments& args) {
  v8::String::Utf8Value str(args[0]); // Convert first argument to V8 String
  const char* cstr = ToCString(str); // Convert V8 String to C string

  Notify::init("Basic");
  // Arguments: title, content, icon
  Notify::Notification n("Alert", cstr, "terminal");
  // Display notification
  n.show();

  return v8::Undefined();
}
<commit_msg>Update API example.<commit_after>// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <include/v8.h>

#include <include/libplatform/libplatform.h>

#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * This sample program shows how to implement a simple javascript shell
 * based on V8.  This includes initializing V8 with command line options,
 * creating global functions, compiling and executing strings.
 *
 * For a more sophisticated shell, consider using the debug shell D8.
 */

v8::Handle<v8::Context> CreateShellContext(v8::Isolate* isolate);
void RunShell(v8::Handle<v8::Context> context);
int RunMain(v8::Isolate* isolate, int argc, char* argv[]);
bool ExecuteString(v8::Isolate* isolate,
                   v8::Handle<v8::String> source,
                   v8::Handle<v8::Value> name,
                   bool print_result,
                   bool report_exceptions);
void Print(const v8::FunctionCallbackInfo<v8::Value>& args);
void Read(const v8::FunctionCallbackInfo<v8::Value>& args);
void Load(const v8::FunctionCallbackInfo<v8::Value>& args);
void Quit(const v8::FunctionCallbackInfo<v8::Value>& args);
void Version(const v8::FunctionCallbackInfo<v8::Value>& args);
v8::Handle<v8::String> ReadFile(v8::Isolate* isolate, const char* name);
void ReportException(v8::Isolate* isolate, v8::TryCatch* handler);

#include <gtkmm.h>
#include <libnotifymm.h>
void Alert(const v8::FunctionCallbackInfo<v8::Value>& args);

static bool run_shell;

class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
 public:
  virtual void* Allocate(size_t length) {
    void* data = AllocateUninitialized(length);
    return data == NULL ? data : memset(data, 0, length);
  }
  virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
  virtual void Free(void* data, size_t) { free(data); }
};

int main(int argc, char* argv[]) {
  v8::V8::InitializeICU();
  v8::Platform* platform = v8::platform::CreateDefaultPlatform();
  v8::V8::InitializePlatform(platform);
  v8::V8::Initialize();
  v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
  ShellArrayBufferAllocator array_buffer_allocator;
  v8::V8::SetArrayBufferAllocator(&array_buffer_allocator);
  v8::Isolate* isolate = v8::Isolate::New();
  run_shell = (argc == 1);
  int result;
  {
    v8::Isolate::Scope isolate_scope(isolate);
    v8::HandleScope handle_scope(isolate);
    v8::Handle<v8::Context> context = CreateShellContext(isolate);
    if (context.IsEmpty()) {
      fprintf(stderr, "Error creating context\n");
      return 1;
    }
    v8::Context::Scope context_scope(context);
    result = RunMain(isolate, argc, argv);
    if (run_shell) RunShell(context);
  }
  isolate->Dispose();
  v8::V8::Dispose();
  v8::V8::ShutdownPlatform();
  delete platform;
  return result;
}

// Extracts a C string from a V8 Utf8Value.
const char* ToCString(const v8::String::Utf8Value& value) {
  return *value ? *value : "<string conversion failed>";
}

// Creates a new execution environment containing the built-in
// functions.
v8::Handle<v8::Context> CreateShellContext(v8::Isolate* isolate) {
  // Create a template for the global object.
  v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
  // INSERT AFTER v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
  // Bind the global 'alert' function to the C++ Alert callback.
  global->Set(v8::String::NewFromUtf8(isolate, "alert"),
              v8::FunctionTemplate::New(isolate, Alert));
  // Bind the global 'print' function to the C++ Print callback.
  global->Set(v8::String::NewFromUtf8(isolate, "print"),
              v8::FunctionTemplate::New(isolate, Print));
  // Bind the global 'read' function to the C++ Read callback.
  global->Set(v8::String::NewFromUtf8(isolate, "read"),
              v8::FunctionTemplate::New(isolate, Read));
  // Bind the global 'load' function to the C++ Load callback.
  global->Set(v8::String::NewFromUtf8(isolate, "load"),
              v8::FunctionTemplate::New(isolate, Load));
  // Bind the 'quit' function
  global->Set(v8::String::NewFromUtf8(isolate, "quit"),
              v8::FunctionTemplate::New(isolate, Quit));
  // Bind the 'version' function
  global->Set(v8::String::NewFromUtf8(isolate, "version"),
              v8::FunctionTemplate::New(isolate, Version));

  return v8::Context::New(isolate, NULL, global);
}

// The callback that is invoked by v8 whenever the JavaScript 'print'
// function is called.  Prints its arguments on stdout separated by
// spaces and ending with a newline.
void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
  bool first = true;
  for (int i = 0; i < args.Length(); i++) {
    v8::HandleScope handle_scope(args.GetIsolate());
    if (first) {
      first = false;
    } else {
      printf(" ");
    }
    v8::String::Utf8Value str(args[i]);
    const char* cstr = ToCString(str);
    printf("%s", cstr);
  }
  printf("\n");
  fflush(stdout);
}

// The callback that is invoked by v8 whenever the JavaScript 'read'
// function is called.  This function loads the content of the file named in
// the argument into a JavaScript string.
void Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
  if (args.Length() != 1) {
    args.GetIsolate()->ThrowException(
        v8::String::NewFromUtf8(args.GetIsolate(), "Bad parameters"));
    return;
  }
  v8::String::Utf8Value file(args[0]);
  if (*file == NULL) {
    args.GetIsolate()->ThrowException(
        v8::String::NewFromUtf8(args.GetIsolate(), "Error loading file"));
    return;
  }
  v8::Handle<v8::String> source = ReadFile(args.GetIsolate(), *file);
  if (source.IsEmpty()) {
    args.GetIsolate()->ThrowException(
        v8::String::NewFromUtf8(args.GetIsolate(), "Error loading file"));
    return;
  }
  args.GetReturnValue().Set(source);
}

// The callback that is invoked by v8 whenever the JavaScript 'load'
// function is called.  Loads, compiles and executes its argument
// JavaScript file.
void Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
  for (int i = 0; i < args.Length(); i++) {
    v8::HandleScope handle_scope(args.GetIsolate());
    v8::String::Utf8Value file(args[i]);
    if (*file == NULL) {
      args.GetIsolate()->ThrowException(
          v8::String::NewFromUtf8(args.GetIsolate(), "Error loading file"));
      return;
    }
    v8::Handle<v8::String> source = ReadFile(args.GetIsolate(), *file);
    if (source.IsEmpty()) {
      args.GetIsolate()->ThrowException(
           v8::String::NewFromUtf8(args.GetIsolate(), "Error loading file"));
      return;
    }
    if (!ExecuteString(args.GetIsolate(),
                       source,
                       v8::String::NewFromUtf8(args.GetIsolate(), *file),
                       false,
                       false)) {
      args.GetIsolate()->ThrowException(
          v8::String::NewFromUtf8(args.GetIsolate(), "Error executing file"));
      return;
    }
  }
}

// The callback that is invoked by v8 whenever the JavaScript 'quit'
// function is called.  Quits.
void Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
  // If not arguments are given args[0] will yield undefined which
  // converts to the integer value 0.
  int exit_code = args[0]->Int32Value();
  fflush(stdout);
  fflush(stderr);
  exit(exit_code);
}

void Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
  args.GetReturnValue().Set(
      v8::String::NewFromUtf8(args.GetIsolate(), v8::V8::GetVersion()));
}

// Reads a file into a v8 string.
v8::Handle<v8::String> ReadFile(v8::Isolate* isolate, const char* name) {
  FILE* file = fopen(name, "rb");
  if (file == NULL) return v8::Handle<v8::String>();

  fseek(file, 0, SEEK_END);
  int size = ftell(file);
  rewind(file);

  char* chars = new char[size + 1];
  chars[size] = '\0';
  for (int i = 0; i < size;) {
    int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
    i += read;
  }
  fclose(file);
  v8::Handle<v8::String> result =
      v8::String::NewFromUtf8(isolate, chars, v8::String::kNormalString, size);
  delete[] chars;
  return result;
}

// INSERT THIS AT END OF FILE
// The callback that is invoked by v8 whenever the JavaScript 'alert'
// function is called.  Displays a GTK+ notification.
void Alert(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::String::Utf8Value str(args[0]); // Convert first argument to V8 String
  const char* cstr = ToCString(str); // Convert V8 String to C string

  Notify::init("Basic");
  // Arguments: title, content, icon
  Notify::Notification n("Alert", cstr, "terminal");
  // Display notification
  n.show();

  return;
}

// Process remaining command line arguments and execute files
int RunMain(v8::Isolate* isolate, int argc, char* argv[]) {
  for (int i = 1; i < argc; i++) {
    const char* str = argv[i];
    if (strcmp(str, "--shell") == 0) {
      run_shell = true;
    } else if (strcmp(str, "-f") == 0) {
      // Ignore any -f flags for compatibility with the other stand-
      // alone JavaScript engines.
      continue;
    } else if (strncmp(str, "--", 2) == 0) {
      fprintf(stderr,
              "Warning: unknown flag %s.\nTry --help for options\n", str);
    } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
      // Execute argument given to -e option directly.
      v8::Handle<v8::String> file_name =
          v8::String::NewFromUtf8(isolate, "unnamed");
      v8::Handle<v8::String> source =
          v8::String::NewFromUtf8(isolate, argv[++i]);
      if (!ExecuteString(isolate, source, file_name, false, true)) return 1;
    } else {
      // Use all other arguments as names of files to load and run.
      v8::Handle<v8::String> file_name = v8::String::NewFromUtf8(isolate, str);
      v8::Handle<v8::String> source = ReadFile(isolate, str);
      if (source.IsEmpty()) {
        fprintf(stderr, "Error reading '%s'\n", str);
        continue;
      }
      if (!ExecuteString(isolate, source, file_name, false, true)) return 1;
    }
  }
  return 0;
}

// The read-eval-execute loop of the shell.
void RunShell(v8::Handle<v8::Context> context) {
  fprintf(stderr, "V8 version %s [sample shell]\n", v8::V8::GetVersion());
  static const int kBufferSize = 256;
  // Enter the execution environment before evaluating any code.
  v8::Context::Scope context_scope(context);
  v8::Local<v8::String> name(
      v8::String::NewFromUtf8(context->GetIsolate(), "(shell)"));
  while (true) {
    char buffer[kBufferSize];
    fprintf(stderr, "> ");
    char* str = fgets(buffer, kBufferSize, stdin);
    if (str == NULL) break;
    v8::HandleScope handle_scope(context->GetIsolate());
    ExecuteString(context->GetIsolate(),
                  v8::String::NewFromUtf8(context->GetIsolate(), str),
                  name,
                  true,
                  true);
  }
  fprintf(stderr, "\n");
}

// Executes a string within the current v8 context.
bool ExecuteString(v8::Isolate* isolate,
                   v8::Handle<v8::String> source,
                   v8::Handle<v8::Value> name,
                   bool print_result,
                   bool report_exceptions) {
  v8::HandleScope handle_scope(isolate);
  v8::TryCatch try_catch;
  v8::ScriptOrigin origin(name);
  v8::Handle<v8::Script> script = v8::Script::Compile(source, &origin);
  if (script.IsEmpty()) {
    // Print errors that happened during compilation.
    if (report_exceptions)
      ReportException(isolate, &try_catch);
    return false;
  } else {
    v8::Handle<v8::Value> result = script->Run();
    if (result.IsEmpty()) {
      assert(try_catch.HasCaught());
      // Print errors that happened during execution.
      if (report_exceptions)
        ReportException(isolate, &try_catch);
      return false;
    } else {
      assert(!try_catch.HasCaught());
      if (print_result && !result->IsUndefined()) {
        // If all went well and the result wasn't undefined then print
        // the returned value.
        v8::String::Utf8Value str(result);
        const char* cstr = ToCString(str);
        printf("%s\n", cstr);
      }
      return true;
    }
  }
}

void ReportException(v8::Isolate* isolate, v8::TryCatch* try_catch) {
  v8::HandleScope handle_scope(isolate);
  v8::String::Utf8Value exception(try_catch->Exception());
  const char* exception_string = ToCString(exception);
  v8::Handle<v8::Message> message = try_catch->Message();
  if (message.IsEmpty()) {
    // V8 didn't provide any extra information about this error; just
    // print the exception.
    fprintf(stderr, "%s\n", exception_string);
  } else {
    // Print (filename):(line number): (message).
    v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
    const char* filename_string = ToCString(filename);
    int linenum = message->GetLineNumber();
    fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
    // Print line of source code.
    v8::String::Utf8Value sourceline(message->GetSourceLine());
    const char* sourceline_string = ToCString(sourceline);
    fprintf(stderr, "%s\n", sourceline_string);
    // Print wavy underline (GetUnderline is deprecated).
    int start = message->GetStartColumn();
    for (int i = 0; i < start; i++) {
      fprintf(stderr, " ");
    }
    int end = message->GetEndColumn();
    for (int i = start; i < end; i++) {
      fprintf(stderr, "^");
    }
    fprintf(stderr, "\n");
    v8::String::Utf8Value stack_trace(try_catch->StackTrace());
    if (stack_trace.length() > 0) {
      const char* stack_trace_string = ToCString(stack_trace);
      fprintf(stderr, "%s\n", stack_trace_string);
    }
  }
}

/*
g++ src/jsnotify.cpp -o jsnotify -Ideps/v8 -lpthread `pkg-config --cflags --libs gtkmm-2.4 libnotifymm-1.0` -Wl,--start-group deps/v8/out/x64.release/obj.target/{tools/gyp/libv8_{base,libbase,snapshot,libplatform},third_party/icu/libicu{uc,i18n,data}}.a -Wl,--end-group -lrt -std=c++0x -ldl
*/
<|endoftext|>


<commit_before>#include "definitions.hpp"

// p(Rnm) = number of clauses if we rename the subformulas in Rnm
static int64_t p(vector<int>& Rnm) {
  vector<int64_t> dp(G.size(),0);
  function<int64_t(int)> f = [&](int u) {
    int64_t& ans = dp[u];
    if (ans) return ans;
    switch (char(G[u].type&~(1<<7))) {
      case CONJ:
        ans = 0; for (int v : G[u].down) ans += (G[v].type&(1<<7) ? 1 : f(v));
        break;
      case DISJ:
        ans = 1; for (int v : G[u].down) ans *= (G[v].type&(1<<7) ? 1 : f(v));
        break;
      default:
        ans = 1;
        break;
    }
    return ans;
  };

  for (int u : Rnm) G[u].type |=  (1<<7);
  int64_t ret = f(0);
  for (int u : Rnm) ret += f(u);
  for (int u : Rnm) G[u].type &= ~(1<<7);
  return ret;
}

// f(i,j) = "optimal renaming, with at most j subformulas, considering
//           subformulas labeled from 1 to i"
// then...
// f(0,j) = f(i,0) = {}
// f(i,j) = { f(i-1,j-1) U {i}          if p(f(i-1,j-1) U {i}) < p(f(i-1,j))
//          { f(i-1,j)                  otherwise
void knapsack() {
  vector<int> subformulas;
  { // find subformulas with BFS
    vector<bool> found(G.size(),false);
    found[0] = true;
    queue<int> Q;
    Q.push(0);
    while (!Q.empty()) {
      int u = Q.front(); Q.pop();
      for (int v : G[u].down) if (!found[v]) {
        found[v] = true;
        Q.push(v);
        subformulas.push_back(v);
      }
    }
  }

  // knapsack 0-1
  int n = subformulas.size()-1;
  vector<vector<int>> dp(n+1);
  for (int i = 0; i < n; i++) for (int j = n; 1 <= j; j--) {
    vector<int> alt = dp[j-1]; alt.push_back(subformulas[i]);
    if (p(alt) < p(dp[j])) dp[j] = alt;
  }
  // as dp[j] is now f(n,j), we have that R = dp[n] = f(n,n).
  // alternatively, R may be f(n,K), for some K <= n.
  R = dp[n];
}
<commit_msg>Fixing bug<commit_after>#include "definitions.hpp"

// p(Rnm) = number of clauses if we rename the subformulas in Rnm
static int64_t p(const vector<int>& Rnm) {
  vector<int64_t> dp(G.size(),0);
  function<int64_t(int)> f = [&](int u) {
    int64_t& ans = dp[u];
    if (ans) return ans;
    switch (char(G[u].type&~(1<<7))) {
      case CONJ:
        ans = 0; for (int v : G[u].down) ans += (G[v].type&(1<<7) ? 1 : f(v));
        break;
      case DISJ:
        ans = 1; for (int v : G[u].down) ans *= (G[v].type&(1<<7) ? 1 : f(v));
        break;
      default:
        ans = 1;
        break;
    }
    return ans;
  };

  for (int u : Rnm) G[u].type |=  (1<<7);
  int64_t ret = f(0);
  for (int u : Rnm) ret += f(u);
  for (int u : Rnm) G[u].type &= ~(1<<7);
  return ret;
}

// f(i,j) = "optimal renaming, with at most j subformulas, considering
//           subformulas labeled from 1 to i"
// then...
// f(0,j) = f(i,0) = {}
// f(i,j) = { f(i-1,j-1) U {i}          if p(f(i-1,j-1) U {i}) < p(f(i-1,j))
//          { f(i-1,j)                  otherwise
void knapsack() {
  vector<int> subformulas;
  { // find subformulas with BFS
    vector<bool> found(G.size(),false);
    found[0] = true;
    queue<int> Q;
    Q.push(0);
    while (!Q.empty()) {
      int u = Q.front(); Q.pop();
      for (int v : G[u].down) if (!found[v]) {
        found[v] = true;
        Q.push(v);
        subformulas.push_back(v);
      }
    }
  }

  // knapsack 0-1
  int n = subformulas.size();
  vector<vector<int>> dp(n+1);
  for (int i = 0; i < n; i++) for (int j = n; 1 <= j; j--) {
    vector<int> alt = dp[j-1]; alt.push_back(subformulas[i]);
    if (p(alt) < p(dp[j])) dp[j] = alt;
  }

  // as dp[j] is now f(n,j), we have that R = dp[n] = f(n,n).
  // alternatively, R may be f(n,K), for some K <= n.
  R = dp[n];
}
<|endoftext|>


<commit_before>/*ckwg +29
 *
* Copyright 2017 by Kitware, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  * Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
*  * Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
*  * Neither name of Kitware, Inc. nor the names of any contributors may be used
*    to endorse or promote products derived from this software without specific
*    prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 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 <super3d/depth/super_config.h>

#include <super3d/depth/tv_refine_search.h>
#include <super3d/depth/cost_volume.h>

#include <super3d/depth/file_io.h>
#include <super3d/depth/depth_map.h>
#include <super3d/depth/multiscale.h>
#include <super3d/depth/tv_refine_plane.h>
#include <super3d/depth/world_rectilinear.h>
#include <super3d/depth/world_frustum.h>
#include <super3d/depth/world_angled_frustum.h>
#include <super3d/depth/exposure.h>

// VXL includes
#include <vil/vil_convert.h>
#include <vil/vil_save.h>
#include <vil/vil_crop.h>
#include <vil/vil_load.h>
#include <vil/vil_copy.h>
#include <vil/vil_decimate.h>
#include <vul/vul_timer.h>
#include <super3d/imesh/imesh_mesh.h>
#include <super3d/imesh/imesh_fileio.h>

#include <vpgl/vpgl_perspective_camera.h>
#include <fstream>
#include <sstream>

int main(int argc, char* argv[])
{
  try
  {
    std::unique_ptr<super3d::config> cfg(new super3d::config);
    cfg->read_config(argv[1]);

    std::string frame_file = cfg->get_value<std::string>("frame_list");
    std::string dir("");
    if (cfg->is_set("directory"))
      dir = cfg->get_value<std::string>("directory");
    std::string camera_dir = cfg->get_value<std::string>("camera_dir");
    std::cout << "Using frame file: " << frame_file << " to find images and " << camera_dir << " to find cameras.\n";

    std::ifstream frame_infile(frame_file.c_str());
    std::vector<std::string> filenames;
    std::string x;
    while (frame_infile >> x) filenames.push_back(x);
    frame_infile.close();

    int numsupport = cfg->get_value<int>("support_frames");
    int stride = cfg->get_value<int>("stride");

    std::cout << "Read " << filenames.size() << " filenames.\n";

    std::vector<std::string> masknames;
    if (cfg->is_set("mask_list"))
    {
      std::string mask_list = cfg->get_value<std::string>("mask_list");
      std::ifstream mask_file_stream(mask_list.c_str());
      while (mask_file_stream >> x) masknames.push_back(x);
      mask_file_stream.close();
    }

    std::string outdir = cfg->get_value<std::string>("outdir");
    std::ofstream vtiList(outdir + "/vtiList.txt");
    std::ofstream kList(outdir + "/kList.txt");
    if( !vtiList || !kList )
    {
      std::cerr << "unable to open vtiList.txt or kList.txt for writing" << std::endl;
      return EXIT_FAILURE;
    }

    bool use_world_planes = false;
    vnl_double_3 normal;
    if (cfg->is_set("world_plane_normal"))
    {
      // use world coordinate slices in this direction instead of depth
      std::istringstream ss(cfg->get_value<std::string>("world_plane_normal"));
      ss >> normal;
      normal.normalize();
      use_world_planes = true;
    }

    int halfsupport = numsupport / 2;
    for (int i = halfsupport; i < static_cast<int>(filenames.size()) - halfsupport; i += stride)
    {
      std::cout << "Computing depth map on frame: " << i << "\n";
      std::vector<std::string> support_frames(filenames.begin() + (i - halfsupport), filenames.begin() + (i + halfsupport));

      std::vector<std::string> support_masks;
      if (!masknames.empty())
      {
        support_masks = std::vector<std::string>(masknames.begin() + (i - halfsupport), masknames.begin() + (i + halfsupport));
      }
      else if (masknames.size() == 1)
      {
        support_masks = std::vector<std::string>(2 * halfsupport, masknames[0]);
      }
      std::cout << support_frames.size() << std::endl;

      std::vector<vil_image_view<double> > frames;
      std::vector<vil_image_view<double> > masks;
      std::vector<vpgl_perspective_camera<double> >  cameras;

      super3d::load_frames(support_frames, frames, cfg->get_value<bool>("use_color"), cfg->get_value<bool>("use_rgb12"));
      std::string ref_cam_name;
      for (unsigned int f = 0; f < support_frames.size(); f++)
      {
        std::string camname = support_frames[f];
        unsigned int found = camname.find_last_of("/\\");
        camname = camname.substr(found + 1, camname.size() - 4 - found - 1);
        if (f==halfsupport)
        {
          ref_cam_name = camname;
        }
        camname = cfg->get_value<std::string>("camera_dir") + "/" + camname + ".krtd";
        cameras.push_back(super3d::load_cam(camname));

        vil_image_view<double> mask;
        if (support_masks.empty())
        {
          mask = vil_image_view<double>(frames[f].ni(), frames[f].nj(), 1);
          mask.fill(1.0);
          vil_crop(mask, 2, mask.ni()-4, 2, mask.nj()-4).fill(0.0);
        }
        else
        {
          std::cout << support_masks[f] << "\n";
          vil_image_view<bool> maskb = vil_load(support_masks[f].c_str());
          vil_convert_cast(maskb, mask);
        }
        masks.push_back(mask);
      }

      unsigned int ref_frame = halfsupport;
      vpgl_perspective_camera<double> ref_cam = cameras[ref_frame];

      super3d::world_space *ws = NULL;
      int ni = frames[ref_frame].ni(), nj = frames[ref_frame].nj();
      double depth_min, depth_max;

      std::cout << "Computing depth range from " << cfg->get_value<std::string>("landmarks_path") << "\n";
      std::vector<vnl_double_3> landmarks;
      super3d::read_landmark_file(cfg->get_value<std::string>("landmarks_path"), landmarks);
      std::vector<vnl_double_3> visible_landmarks =
        super3d::filter_visible_landmarks(cameras[ref_frame], 0, ni, 0, nj, landmarks);
      if (use_world_planes)
      {
        super3d::compute_offset_range(visible_landmarks, normal, depth_min, depth_max, 0.0, 0.5);
        std::cout << "Max estimated offset: " << depth_max << "\n";
        std::cout << "Min estimated offset: " << depth_min << "\n";
        ws = new super3d::world_angled_frustum(cameras[ref_frame], normal, depth_min, depth_max, ni, nj);
      }
      else
      {
        super3d::compute_depth_range(visible_landmarks, cameras[ref_frame], depth_min, depth_max);
        std::cout << "Max estimated depth: " << depth_max << "\n";
        std::cout << "Min estimated depth: " << depth_min << "\n";
        ws = new super3d::world_frustum(cameras[ref_frame], depth_min, depth_max, ni, nj);
      }

      std::cout << "Refining depth" << std::endl;
      unsigned int S = cfg->get_value<unsigned int>("num_slices");
      double theta0 = cfg->get_value<double>("theta_start");
      double theta_end = cfg->get_value<double>("theta_end");
      //double beta = cfg->get_value<double>("beta");
      double lambda = cfg->get_value<double>("lambda");
      double gw_alpha = cfg->get_value<double>("gw_alpha");
      double epsilon = cfg->get_value<double>("epsilon");

      vil_image_view<double> g;
      vil_image_view<double> cost_volume;

      double iw = cfg->get_value<double>("intensity_cost_weight");
      double gw = cfg->get_value<double>("gradient_cost_weight");
      double cw = cfg->get_value<double>("census_cost_weight");
      super3d::compute_world_cost_volume(frames, cameras, ws, ref_frame, S, cost_volume, iw, gw, cw,&masks);
      //compute_cost_volume_warp(frames, cameras, ref_frame, S, depth_min, depth_max, cost_volume);
      ws->compute_g(frames[ref_frame], g, gw_alpha, 1.0, &masks[ref_frame]);

      std::cout << "Refining Depth. ..\n";
      vil_image_view<double> depth(cost_volume.ni(), cost_volume.nj(), 1);

      vul_timer timer;

      unsigned int iterations = 2000;
      if (cfg->is_set("iterations"))
        iterations = cfg->get_value<unsigned int>("iterations");
      super3d::refine_depth(cost_volume, g, depth, iterations, theta0, theta_end, lambda, epsilon);

      double sec = 1e-3 * timer.real();
      std::cout << "super3d took " << sec << " seconds.\n";

      std::string depth_name = outdir + "/" + ref_cam_name;

      super3d::save_depth_to_vtp((depth_name + ".vtp").c_str(), depth, frames[ref_frame], ref_cam, ws);

      // map depth from normalized range back into true depth
      double depth_scale = depth_max - depth_min;
      vil_math_scale_and_offset_values(depth, depth_scale, depth_min);

      vil_image_view<double> height_map;
      if (use_world_planes)
      {
        height_map = depth;
        depth = vil_image_view<double>();
        super3d::height_map_to_depth_map(cameras[ref_frame], height_map, depth);
      }
      else
      {
        super3d::depth_map_to_height_map(cameras[ref_frame], depth, height_map);
      }

      // save byte depth map
      vil_image_view<vxl_byte> bmap;
      vil_convert_stretch_range(depth, bmap);
      // depth map are drawn inverted (white == closest) for viewing
      vil_math_scale_and_offset_values(bmap, -1.0, 255);
      std::string depthmap_file = depth_name + "_depth.png";
      vil_save(bmap, depthmap_file.c_str());
      // save byte height map
      vil_convert_stretch_range(height_map, bmap);
      std::string heightmap_file = depth_name + "_height.png";
      vil_save(bmap, heightmap_file.c_str());

      double minv, maxv;
      vil_math_value_range(depth, minv, maxv);
      std::cout << "Depth range: " << minv << " - " << maxv << "\n";
      vil_math_value_range(height_map, minv, maxv);
      std::cout << "Height range: " << minv << " - " << maxv << "\n";

      vil_image_view<vxl_byte> ref_img_color = vil_load(support_frames[ref_frame].c_str());
      super3d::save_depth_to_vti((depth_name + ".vti").c_str(), depth, ref_img_color);
      std::cout << "Saved : " << depth_name + ".vti" << std::endl;

      vtiList << i << " " << ref_cam_name + ".vti\n";
      kList << i << " ../krtd/" << ref_cam_name << ".krtd\n";

      if (ws) delete ws;
    }
    vtiList.close();
    kList.close();

  }
  catch (const super3d::config::cfg_exception &e)
  {
    std::cout << "Error in config: " << e.what() << "\n";
  }

  return 0;
}
<commit_msg>Handle conditionals in correct order<commit_after>/*ckwg +29
 *
* Copyright 2017 by Kitware, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  * Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
*  * Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
*  * Neither name of Kitware, Inc. nor the names of any contributors may be used
*    to endorse or promote products derived from this software without specific
*    prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 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 <super3d/depth/super_config.h>

#include <super3d/depth/tv_refine_search.h>
#include <super3d/depth/cost_volume.h>

#include <super3d/depth/file_io.h>
#include <super3d/depth/depth_map.h>
#include <super3d/depth/multiscale.h>
#include <super3d/depth/tv_refine_plane.h>
#include <super3d/depth/world_rectilinear.h>
#include <super3d/depth/world_frustum.h>
#include <super3d/depth/world_angled_frustum.h>
#include <super3d/depth/exposure.h>

// VXL includes
#include <vil/vil_convert.h>
#include <vil/vil_save.h>
#include <vil/vil_crop.h>
#include <vil/vil_load.h>
#include <vil/vil_copy.h>
#include <vil/vil_decimate.h>
#include <vul/vul_timer.h>
#include <super3d/imesh/imesh_mesh.h>
#include <super3d/imesh/imesh_fileio.h>

#include <vpgl/vpgl_perspective_camera.h>
#include <fstream>
#include <sstream>

int main(int argc, char* argv[])
{
  try
  {
    std::unique_ptr<super3d::config> cfg(new super3d::config);
    cfg->read_config(argv[1]);

    std::string frame_file = cfg->get_value<std::string>("frame_list");
    std::string dir("");
    if (cfg->is_set("directory"))
      dir = cfg->get_value<std::string>("directory");
    std::string camera_dir = cfg->get_value<std::string>("camera_dir");
    std::cout << "Using frame file: " << frame_file << " to find images and " << camera_dir << " to find cameras.\n";

    std::ifstream frame_infile(frame_file.c_str());
    std::vector<std::string> filenames;
    std::string x;
    while (frame_infile >> x) filenames.push_back(x);
    frame_infile.close();

    int numsupport = cfg->get_value<int>("support_frames");
    int stride = cfg->get_value<int>("stride");

    std::cout << "Read " << filenames.size() << " filenames.\n";

    std::vector<std::string> masknames;
    if (cfg->is_set("mask_list"))
    {
      std::string mask_list = cfg->get_value<std::string>("mask_list");
      std::ifstream mask_file_stream(mask_list.c_str());
      while (mask_file_stream >> x) masknames.push_back(x);
      mask_file_stream.close();
    }

    std::string outdir = cfg->get_value<std::string>("outdir");
    std::ofstream vtiList(outdir + "/vtiList.txt");
    std::ofstream kList(outdir + "/kList.txt");
    if( !vtiList || !kList )
    {
      std::cerr << "unable to open vtiList.txt or kList.txt for writing" << std::endl;
      return EXIT_FAILURE;
    }

    bool use_world_planes = false;
    vnl_double_3 normal;
    if (cfg->is_set("world_plane_normal"))
    {
      // use world coordinate slices in this direction instead of depth
      std::istringstream ss(cfg->get_value<std::string>("world_plane_normal"));
      ss >> normal;
      normal.normalize();
      use_world_planes = true;
    }

    int halfsupport = numsupport / 2;
    for (int i = halfsupport; i < static_cast<int>(filenames.size()) - halfsupport; i += stride)
    {
      std::cout << "Computing depth map on frame: " << i << "\n";
      std::vector<std::string> support_frames(filenames.begin() + (i - halfsupport), filenames.begin() + (i + halfsupport));

      std::vector<std::string> support_masks;
      if (masknames.size() == 1)
      {
        support_masks = std::vector<std::string>(support_frames.size(), masknames[0]);
      }
      else if (!masknames.empty())
      {
        support_masks = std::vector<std::string>(masknames.begin() + (i - halfsupport), masknames.begin() + (i + halfsupport));
      }
      std::cout << support_frames.size() << std::endl;

      std::vector<vil_image_view<double> > frames;
      std::vector<vil_image_view<double> > masks;
      std::vector<vpgl_perspective_camera<double> >  cameras;

      super3d::load_frames(support_frames, frames, cfg->get_value<bool>("use_color"), cfg->get_value<bool>("use_rgb12"));
      std::string ref_cam_name;
      for (unsigned int f = 0; f < support_frames.size(); f++)
      {
        std::string camname = support_frames[f];
        unsigned int found = camname.find_last_of("/\\");
        camname = camname.substr(found + 1, camname.size() - 4 - found - 1);
        if (f==halfsupport)
        {
          ref_cam_name = camname;
        }
        camname = cfg->get_value<std::string>("camera_dir") + "/" + camname + ".krtd";
        cameras.push_back(super3d::load_cam(camname));

        vil_image_view<double> mask;
        if (support_masks.empty())
        {
          mask = vil_image_view<double>(frames[f].ni(), frames[f].nj(), 1);
          mask.fill(1.0);
          vil_crop(mask, 2, mask.ni()-4, 2, mask.nj()-4).fill(0.0);
        }
        else
        {
          std::cout << support_masks[f] << "\n";
          vil_image_view<bool> maskb = vil_load(support_masks[f].c_str());
          vil_convert_cast(maskb, mask);
        }
        masks.push_back(mask);
      }

      unsigned int ref_frame = halfsupport;
      vpgl_perspective_camera<double> ref_cam = cameras[ref_frame];

      super3d::world_space *ws = NULL;
      int ni = frames[ref_frame].ni(), nj = frames[ref_frame].nj();
      double depth_min, depth_max;

      std::cout << "Computing depth range from " << cfg->get_value<std::string>("landmarks_path") << "\n";
      std::vector<vnl_double_3> landmarks;
      super3d::read_landmark_file(cfg->get_value<std::string>("landmarks_path"), landmarks);
      std::vector<vnl_double_3> visible_landmarks =
        super3d::filter_visible_landmarks(cameras[ref_frame], 0, ni, 0, nj, landmarks);
      if (use_world_planes)
      {
        super3d::compute_offset_range(visible_landmarks, normal, depth_min, depth_max, 0.0, 0.5);
        std::cout << "Max estimated offset: " << depth_max << "\n";
        std::cout << "Min estimated offset: " << depth_min << "\n";
        ws = new super3d::world_angled_frustum(cameras[ref_frame], normal, depth_min, depth_max, ni, nj);
      }
      else
      {
        super3d::compute_depth_range(visible_landmarks, cameras[ref_frame], depth_min, depth_max);
        std::cout << "Max estimated depth: " << depth_max << "\n";
        std::cout << "Min estimated depth: " << depth_min << "\n";
        ws = new super3d::world_frustum(cameras[ref_frame], depth_min, depth_max, ni, nj);
      }

      std::cout << "Refining depth" << std::endl;
      unsigned int S = cfg->get_value<unsigned int>("num_slices");
      double theta0 = cfg->get_value<double>("theta_start");
      double theta_end = cfg->get_value<double>("theta_end");
      //double beta = cfg->get_value<double>("beta");
      double lambda = cfg->get_value<double>("lambda");
      double gw_alpha = cfg->get_value<double>("gw_alpha");
      double epsilon = cfg->get_value<double>("epsilon");

      vil_image_view<double> g;
      vil_image_view<double> cost_volume;

      double iw = cfg->get_value<double>("intensity_cost_weight");
      double gw = cfg->get_value<double>("gradient_cost_weight");
      double cw = cfg->get_value<double>("census_cost_weight");
      super3d::compute_world_cost_volume(frames, cameras, ws, ref_frame, S, cost_volume, iw, gw, cw,&masks);
      //compute_cost_volume_warp(frames, cameras, ref_frame, S, depth_min, depth_max, cost_volume);
      ws->compute_g(frames[ref_frame], g, gw_alpha, 1.0, &masks[ref_frame]);

      std::cout << "Refining Depth. ..\n";
      vil_image_view<double> depth(cost_volume.ni(), cost_volume.nj(), 1);

      vul_timer timer;

      unsigned int iterations = 2000;
      if (cfg->is_set("iterations"))
        iterations = cfg->get_value<unsigned int>("iterations");
      super3d::refine_depth(cost_volume, g, depth, iterations, theta0, theta_end, lambda, epsilon);

      double sec = 1e-3 * timer.real();
      std::cout << "super3d took " << sec << " seconds.\n";

      std::string depth_name = outdir + "/" + ref_cam_name;

      super3d::save_depth_to_vtp((depth_name + ".vtp").c_str(), depth, frames[ref_frame], ref_cam, ws);

      // map depth from normalized range back into true depth
      double depth_scale = depth_max - depth_min;
      vil_math_scale_and_offset_values(depth, depth_scale, depth_min);

      vil_image_view<double> height_map;
      if (use_world_planes)
      {
        height_map = depth;
        depth = vil_image_view<double>();
        super3d::height_map_to_depth_map(cameras[ref_frame], height_map, depth);
      }
      else
      {
        super3d::depth_map_to_height_map(cameras[ref_frame], depth, height_map);
      }

      // save byte depth map
      vil_image_view<vxl_byte> bmap;
      vil_convert_stretch_range(depth, bmap);
      // depth map are drawn inverted (white == closest) for viewing
      vil_math_scale_and_offset_values(bmap, -1.0, 255);
      std::string depthmap_file = depth_name + "_depth.png";
      vil_save(bmap, depthmap_file.c_str());
      // save byte height map
      vil_convert_stretch_range(height_map, bmap);
      std::string heightmap_file = depth_name + "_height.png";
      vil_save(bmap, heightmap_file.c_str());

      double minv, maxv;
      vil_math_value_range(depth, minv, maxv);
      std::cout << "Depth range: " << minv << " - " << maxv << "\n";
      vil_math_value_range(height_map, minv, maxv);
      std::cout << "Height range: " << minv << " - " << maxv << "\n";

      vil_image_view<vxl_byte> ref_img_color = vil_load(support_frames[ref_frame].c_str());
      super3d::save_depth_to_vti((depth_name + ".vti").c_str(), depth, ref_img_color);
      std::cout << "Saved : " << depth_name + ".vti" << std::endl;

      vtiList << i << " " << ref_cam_name + ".vti\n";
      kList << i << " ../krtd/" << ref_cam_name << ".krtd\n";

      if (ws) delete ws;
    }
    vtiList.close();
    kList.close();

  }
  catch (const super3d::config::cfg_exception &e)
  {
    std::cout << "Error in config: " << e.what() << "\n";
  }

  return 0;
}
<|endoftext|>


<commit_before>/*
 *  Level.cpp
 *  OniLevelTool
 *
 *  Created by Sam Marshall on 4/29/12.
 *  Copyright 2012 Sam Marshall. All rights reserved.
 *
 */

#include "Level.h"

OniLevel::OniLevel() {
	this->header = (LevelHeader *)malloc(sizeof(LevelHeader));
	this->has_raw = false;
	this->has_sep = false;
}

OniLevel::~OniLevel() {
	free(this->header);
	free(this->name);
	free(this->level_path);
	if (this->platform != OPundefined) {
		if (this->type == DAT) {
			free(this->raw_path);
			if (this->platform == DemoMac)
				free(this->sep_path);
		}
		free(this->instance_descriptors);
		free(this->name_descriptors);
		free(this->template_descriptors);
		free(this->data_table);
		free(this->names_table);
	}
}

bool OniLevel::LoadPath(char *path) {
	bool status = false;
	FILE *file_ = fopen(path,"rb");
	if (file_) {
		char *pos;
		char path_delimiter;
		#ifdef _WIN32
			path_delimiter = '\\';
		#else
			path_delimiter = '/';
		#endif
		pos = strrchr(path, path_delimiter)+1;
		int32_t p_length = (int32_t)(pos-path);
		this->name = (char *)malloc(sizeof(char)*p_length);
		memcpy(this->name, &path[p_length], (strlen(path)-(pos-path)));

		this->level_path = (char *)malloc(sizeof(char)*strlen(path));
		strcpy(this->level_path, path);

		size_t read_length = fread(this->header,sizeof(LevelHeader),1,file_);
		if (read_length) {
			if (this->header->checksum == DemoMacPlatformChecksum) { this->platform = DemoMac; }
			else if (this->header->checksum == PCPlatformChecksum) { this->platform = PC; }
			else { this->platform = OPundefined; }

			if (this->platform != OPundefined) {
				if (this->header->version == DATFileVersion) { this->type = DAT; }
				else if (this->header->version == ONIFileVersion) { this->type = ONI; }
				else { this->type = LTundefined; }

				if (this->type == DAT) {
					this->raw_path = (char *)malloc(sizeof(char)*strlen(path));
					strncpy(this->raw_path, path, strlen(path)-3);
					strcat(this->raw_path, "raw");
					FILE *raw_ = fopen(this->raw_path, "rb");
					if (raw_)
						this->has_raw = true;
					fclose(raw_);

					if (this->platform == DemoMac) {
						this->sep_path = (char *)malloc(sizeof(char)*strlen(path));
						strncpy(this->sep_path, path, strlen(path)-3);
						strcat(this->sep_path, "sep");
						FILE *sep_ = fopen(this->sep_path, "rb");
						if (sep_)
							this->has_sep = true;
						fclose(sep_);
					}
				}

				this->instance_descriptors = (OniInstanceStruct *)malloc(sizeof(OniInstanceStruct)*this->header->instance_count);
				this->name_descriptors = (OniNameStruct *)malloc(sizeof(OniNameStruct)*this->header->name_count);
				this->template_descriptors = (OniTemplateStruct *)malloc(sizeof(OniTemplateStruct)*this->header->template_count);
				this->data_table = (char *)malloc(sizeof(char)*this->header->data_size);
				this->names_table = (char *)malloc(sizeof(char)*this->header->names_size);

				read_length = fread(this->instance_descriptors,sizeof(OniInstanceStruct),this->header->instance_count,file_);
				if (read_length != this->header->instance_count) { return status; }

				read_length = fread(this->name_descriptors,sizeof(OniNameStruct),this->header->name_count,file_);
				if (read_length != this->header->name_count) { return status; }

				read_length = fread(this->template_descriptors,sizeof(OniTemplateStruct),this->header->template_count,file_);
				if (read_length != this->header->template_count) { return status; }

				fpos_t data_pos = this->header->data_offset;
				fsetpos(file_,&data_pos);
				read_length = fread(this->data_table,sizeof(char)*this->header->data_size,1,file_);
				if (read_length != 1) { return status; }

				fpos_t names_pos = this->header->names_offset;
				fsetpos(file_,&names_pos);
				read_length = fread(this->names_table,sizeof(char)*this->header->names_size,1,file_);
				if (read_length != 1) { return status; }

				status = true;
			}
		}
	}
	fclose(file_);
	return status;
}

void OniLevel::LoadTags() {
	if (this->platform != OPundefined) {
		if (!this->tags.empty()) {
			this->tags.clear();
		}
		for (int32_t i = 0; i < this->header->instance_count; i++) {
			OniTag *a_tag = new OniTag;
			a_tag->LoadFrom(&this->instance_descriptors[i], this->data_table, this->names_table);
			if (a_tag->external_data) {
				//a_tag->LoadExternal(this->raw_path, this->sep_path, )
			}
			this->tags.push_back(a_tag);
		}
	}
}

void OniLevel::ExportTagToPath(OniTag *tag, char *path) {
	if (this->platform != OPundefined) {
		if (strcmp(tag->name, "unnamed\0") != 0) {
			if (!this->export_tags.empty())
				this->export_tags.clear();

			char *file_path = (char *)malloc(sizeof(char)*(strlen(path)+strlen(tag->name)+6));
			strcpy(file_path, path);
			#ifdef _WIN32
				strcat(file_path, "\\");
			#else
				strcat(file_path, "/");
			#endif
			strcat(file_path, tag->name);
			strcat(file_path, ".oni\0");

			FILE *export_tag_file = fopen(file_path, "w+");
			if (export_tag_file) {
				std::cout << file_path << std::endl;

				LevelHeader *output_header = this->CreateOniHeader(tag);
				int64_t file_size = (sizeof(LevelHeader));
				file_size = file_size + GetFileSizeDelta((output_header->names_offset - file_size) + output_header->names_size);
				file_size = file_size + GetFileSizeDelta((output_header->data_offset - file_size) + output_header->data_size);
				file_size = file_size + GetFileSizeDelta((output_header->raw_offset - file_size) + output_header->raw_size);

				uint64_t pos = 0;

				char *write_out = (char *)malloc(file_size);
				memcpy(&write_out[pos], &output_header, sizeof(LevelHeader));
				pos = pos + sizeof(LevelHeader);

				//fwrite(output_header, 1, sizeof(LevelHeader), export_tag_file);

				// write instance descriptors
				for (int32_t i = 0; i < this->export_tags.size(); i++) {
					memcpy(&write_out[pos], (void*)CharToInt(this->export_tags.at(i).tag->type), 4);
					pos = pos + 4;
					//fwrite((void*)CharToInt(this->export_tags.at(i).tag->type), 4, 1, export_tag_file);
					memcpy(&write_out[pos], &this->export_tags.at(i).data_offset, 4);
					pos = pos + 4;
					//fwrite(&this->export_tags.at(i).data_offset, 4, 1, export_tag_file);
					memcpy(&write_out[pos], &this->export_tags.at(i).name_offset, 4);
					pos = pos + 4;
					//fwrite(&this->export_tags.at(i).name_offset, 4, 1, export_tag_file);
					memcpy(&write_out[pos], (void*)this->export_tags.at(i).tag->GetDataLength(), 4);
					pos = pos + 4;
					//fwrite((void*)this->export_tags.at(i).tag->GetDataLength(), 4, 1, export_tag_file);
					memcpy(&write_out[pos], &this->export_tags.at(i).tag->flags, 4);
					pos = pos + 4;
					//fwrite(&this->export_tags.at(i).tag->flags, 4, 1, export_tag_file);
				}

				// write names table
				if (pos <= output_header->names_offset) {
					pos = output_header->names_offset;
					for (int32_t i = 0; i < this->export_tags.size(); i++) {
						if (strcmp(this->export_tags.at(i).tag->name, "unnamed") != 0) {
							int32_t name_length = strlen(this->export_tags.at(i).tag->name);
							memcpy(&write_out[pos], &this->export_tags.at(i).tag->name, name_length);
							pos = pos + name_length;
							//fwrite(this->export_tags.at(i).tag->name, strlen(this->export_tags.at(i).tag->name), 1, export_tag_file);
						}
					}
				}

				// write data table
				/*for (int32_t i = 0; i < this->export_tags.size(); i++) {
					char *data = tag->GetExportData();
					fwrite(data, 1, sizeof(tag->GetDataLength()), export_tag_);
					free(data);
				}*/

				// write raw

				// write file
				free(output_header);
				fwrite(&write_out, file_size, 1, export_tag_file);
				free(write_out);
			}
			fclose(export_tag_file);
			free(file_path);

			this->export_tags.clear();
		}
	}
}

void OniLevel::ExportAllTags() {
	if (this->platform != OPundefined) {
		if (!this->tags.empty()) {
			char *temp_ = (char *)malloc(sizeof(char)*(strlen(this->level_path)-4));
			strncpy(temp_, this->level_path, strlen(this->level_path)-4);
			int32_t mkdir_result;
			#ifdef _WIN32
				mkdir_result = _mkdir(temp_);
			#else
				mkdir_result = mkdir(temp_ ,0777);
			#endif
			if (mkdir_result == 0) {
				for (int32_t i = 0; i < this->tags.size(); i++) {
					OniTag *a_tag = this->tags.at(i);

					// before we ship to export, remapping has to be done to the instance ids.

					this->ExportTagToPath(a_tag, temp_);
				}
			} else {
				std::cout << "Export directory for \"" << this->name << "\" already exists." << std::endl;
			}
			free(temp_);
		}
	}
}

LevelHeader* OniLevel::CreateOniHeader(OniTag *tag) {
	LevelHeader *new_header = (LevelHeader *)malloc(sizeof(LevelHeader));
	new_header->checksum = this->header->checksum;
	new_header->version = ONIFileVersion;
	new_header->signature = this->header->signature;

	new_header->instance_count = this->GetInstanceCount(tag);
	new_header->name_count = 0; // always zero
	new_header->template_count = 0; // always zero

	new_header->names_offset = this->ComputeNamesOffset();
	new_header->names_size = this->ComputeNamesSize();

	new_header->data_offset = new_header->names_offset+new_header->names_size;
	new_header->data_size = this->ComputeDataSize();

	new_header->raw_offset = new_header->data_offset+new_header->data_size; // end of normal dat file
	new_header->raw_size = this->ComputeRawSize();

	new_header->unused[0] = 0;
	new_header->unused[1] = 0;

	return new_header;
}

int32_t OniLevel::GetInstanceCount(OniTag *tag) {
	int32_t count = tag->tm_tag->instance_count;
	if (count) {
		this->export_tags.push_back((Exporter){GetResID(tag->tm_tag->header->res_id),tag});
		int32_t *instance_ids = (int32_t *)malloc(sizeof(int32_t)*tag->tm_tag->instance_count);
		instance_ids = tag->tm_tag->GetInstanceIDs();
		for (int32_t i = 0; i < tag->tm_tag->instance_count; i++) {
			for (int32_t j = 0; j < this->tags.size(); j++) {
				printf("%i %i\n", instance_ids[i], CharToInt(this->tags.at(j)->tm_tag->header->res_id));
				if (instance_ids[i] == CharToInt(this->tags.at(j)->tm_tag->header->res_id)) {
					printf("Found %i linked to %i\n",instance_ids[i],CharToInt(tag->tm_tag->header->res_id));
					count = count + this->GetInstanceCount(this->tags.at(j));
					break;
				}
			}
		}
		free(instance_ids);
	}
	return count;
}

int32_t OniLevel::ComputeNamesOffset() {
	return 20*this->export_tags.size();
}

int32_t OniLevel::ComputeDataSize() {
	int32_t total = 0;
	for (int32_t i = 0; i < this->export_tags.size(); i++) {
		this->export_tags.at(i).data_offset = total;
		total = total + this->export_tags.at(i).tag->GetDataLength();
	}
	return total;
}

int32_t OniLevel::ComputeNamesSize() {
	int32_t length = 0;
	for (int32_t i = 0; i < this->export_tags.size(); i++) {
		if (strcmp(this->export_tags.at(i).tag->name, "unnamed") != 0) {
			this->export_tags.at(i).name_offset = length;
			length = length + strlen(this->export_tags.at(i).tag->name);
		} else {
			this->export_tags.at(i).name_offset = 0;
		}
	}
	return length;
}

int32_t OniLevel::ComputeRawSize() {
	int32_t length = 0;
	for (int32_t i = 0; i < this->export_tags.size(); i++) {
		length = length + this->export_tags.at(i).tag->tm_tag->raw_size;
	}
	return length;
}<commit_msg>new instance write code<commit_after>/*
 *  Level.cpp
 *  OniLevelTool
 *
 *  Created by Sam Marshall on 4/29/12.
 *  Copyright 2012 Sam Marshall. All rights reserved.
 *
 */

#include "Level.h"

OniLevel::OniLevel() {
	this->header = (LevelHeader *)malloc(sizeof(LevelHeader));
	this->has_raw = false;
	this->has_sep = false;
}

OniLevel::~OniLevel() {
	free(this->header);
	free(this->name);
	free(this->level_path);
	if (this->platform != OPundefined) {
		if (this->type == DAT) {
			free(this->raw_path);
			if (this->platform == DemoMac)
				free(this->sep_path);
		}
		free(this->instance_descriptors);
		free(this->name_descriptors);
		free(this->template_descriptors);
		free(this->data_table);
		free(this->names_table);
	}
}

bool OniLevel::LoadPath(char *path) {
	bool status = false;
	FILE *file_ = fopen(path,"rb");
	if (file_) {
		char *pos;
		char path_delimiter;
		#ifdef _WIN32
			path_delimiter = '\\';
		#else
			path_delimiter = '/';
		#endif
		pos = strrchr(path, path_delimiter)+1;
		int32_t p_length = (int32_t)(pos-path);
		this->name = (char *)malloc(sizeof(char)*p_length);
		memcpy(this->name, &path[p_length], (strlen(path)-(pos-path)));

		this->level_path = (char *)malloc(sizeof(char)*strlen(path));
		strcpy(this->level_path, path);

		size_t read_length = fread(this->header,sizeof(LevelHeader),1,file_);
		if (read_length) {
			if (this->header->checksum == DemoMacPlatformChecksum) { this->platform = DemoMac; }
			else if (this->header->checksum == PCPlatformChecksum) { this->platform = PC; }
			else { this->platform = OPundefined; }

			if (this->platform != OPundefined) {
				if (this->header->version == DATFileVersion) { this->type = DAT; }
				else if (this->header->version == ONIFileVersion) { this->type = ONI; }
				else { this->type = LTundefined; }

				if (this->type == DAT) {
					this->raw_path = (char *)malloc(sizeof(char)*strlen(path));
					strncpy(this->raw_path, path, strlen(path)-3);
					strcat(this->raw_path, "raw");
					FILE *raw_ = fopen(this->raw_path, "rb");
					if (raw_)
						this->has_raw = true;
					fclose(raw_);

					if (this->platform == DemoMac) {
						this->sep_path = (char *)malloc(sizeof(char)*strlen(path));
						strncpy(this->sep_path, path, strlen(path)-3);
						strcat(this->sep_path, "sep");
						FILE *sep_ = fopen(this->sep_path, "rb");
						if (sep_)
							this->has_sep = true;
						fclose(sep_);
					}
				}

				this->instance_descriptors = (OniInstanceStruct *)malloc(sizeof(OniInstanceStruct)*this->header->instance_count);
				this->name_descriptors = (OniNameStruct *)malloc(sizeof(OniNameStruct)*this->header->name_count);
				this->template_descriptors = (OniTemplateStruct *)malloc(sizeof(OniTemplateStruct)*this->header->template_count);
				this->data_table = (char *)malloc(sizeof(char)*this->header->data_size);
				this->names_table = (char *)malloc(sizeof(char)*this->header->names_size);

				read_length = fread(this->instance_descriptors,sizeof(OniInstanceStruct),this->header->instance_count,file_);
				if (read_length != this->header->instance_count) { return status; }

				read_length = fread(this->name_descriptors,sizeof(OniNameStruct),this->header->name_count,file_);
				if (read_length != this->header->name_count) { return status; }

				read_length = fread(this->template_descriptors,sizeof(OniTemplateStruct),this->header->template_count,file_);
				if (read_length != this->header->template_count) { return status; }

				fpos_t data_pos = this->header->data_offset;
				fsetpos(file_,&data_pos);
				read_length = fread(this->data_table,sizeof(char)*this->header->data_size,1,file_);
				if (read_length != 1) { return status; }

				fpos_t names_pos = this->header->names_offset;
				fsetpos(file_,&names_pos);
				read_length = fread(this->names_table,sizeof(char)*this->header->names_size,1,file_);
				if (read_length != 1) { return status; }

				status = true;
			}
		}
	}
	fclose(file_);
	return status;
}

void OniLevel::LoadTags() {
	if (this->platform != OPundefined) {
		if (!this->tags.empty()) {
			this->tags.clear();
		}
		for (int32_t i = 0; i < this->header->instance_count; i++) {
			OniTag *a_tag = new OniTag;
			a_tag->LoadFrom(&this->instance_descriptors[i], this->data_table, this->names_table);
			if (a_tag->external_data) {
				//a_tag->LoadExternal(this->raw_path, this->sep_path, )
			}
			this->tags.push_back(a_tag);
		}
	}
}

void OniLevel::ExportTagToPath(OniTag *tag, char *path) {
	if (this->platform != OPundefined) {
		if (strcmp(tag->name, "unnamed\0") != 0) {
			if (!this->export_tags.empty())
				this->export_tags.clear();

			char *file_path = (char *)malloc(sizeof(char)*(strlen(path)+strlen(tag->name)+6));
			strcpy(file_path, path);
			#ifdef _WIN32
				strcat(file_path, "\\");
			#else
				strcat(file_path, "/");
			#endif
			strcat(file_path, tag->name);
			strcat(file_path, ".oni\0");

			FILE *export_tag_file = fopen(file_path, "w+");
			if (export_tag_file) {
				std::cout << file_path << std::endl;

				LevelHeader *output_header = this->CreateOniHeader(tag);
				int64_t file_size = (sizeof(LevelHeader));
				file_size = file_size + GetFileSizeDelta((output_header->names_offset - file_size) + output_header->names_size);
				file_size = file_size + GetFileSizeDelta((output_header->data_offset - file_size) + output_header->data_size);
				file_size = file_size + GetFileSizeDelta((output_header->raw_offset - file_size) + output_header->raw_size);

				uint64_t pos = 0;

				char *write_out = (char *)malloc(file_size);
				memcpy(&write_out[pos], &output_header, sizeof(LevelHeader));
				pos = pos + sizeof(LevelHeader);

				// write instance descriptors
				for (int32_t i = 0; i < this->export_tags.size(); i++) {
					OniInstanceStruct an_instance = {CharToInt(this->export_tags.at(i).tag->type), this->export_tags.at(i).data_offset, this->export_tags.at(i).name_offset, this->export_tags.at(i).tag->GetDataLength(), this->export_tags.at(i).tag->flags};
					memcpy(&write_out[pos], &an_instance, sizeof(OniInstanceStruct));
					pos = pos + sizeof(OniInstanceStruct);

					/*memcpy(&write_out[pos], (void*)CharToInt(this->export_tags.at(i).tag->type), 4);
					pos = pos + 4;
					memcpy(&write_out[pos], &this->export_tags.at(i).data_offset, 4);
					pos = pos + 4;
					memcpy(&write_out[pos], &this->export_tags.at(i).name_offset, 4);
					pos = pos + 4;
					memcpy(&write_out[pos], (void*)this->export_tags.at(i).tag->GetDataLength(), 4);
					pos = pos + 4;
					memcpy(&write_out[pos], &this->export_tags.at(i).tag->flags, 4);
					pos = pos + 4;*/
				}

				// write names table
				if (pos <= output_header->names_offset) {
					pos = output_header->names_offset;
					for (int32_t i = 0; i < this->export_tags.size(); i++) {
						if (strcmp(this->export_tags.at(i).tag->name, "unnamed") != 0) {
							int32_t name_length = strlen(this->export_tags.at(i).tag->name);
							memcpy(&write_out[pos], &this->export_tags.at(i).tag->name, name_length);
							pos = pos + name_length;
						}
					}
				}

				// write data table
				/*for (int32_t i = 0; i < this->export_tags.size(); i++) {
					char *data = tag->GetExportData();
					fwrite(data, 1, sizeof(tag->GetDataLength()), export_tag_);
					free(data);
				}*/

				// write raw

				// write file
				free(output_header);
				fwrite(&write_out, file_size, 1, export_tag_file);
				free(write_out);
			}
			fclose(export_tag_file);
			free(file_path);

			this->export_tags.clear();
		}
	}
}

void OniLevel::ExportAllTags() {
	if (this->platform != OPundefined) {
		if (!this->tags.empty()) {
			char *temp_ = (char *)malloc(sizeof(char)*(strlen(this->level_path)-4));
			strncpy(temp_, this->level_path, strlen(this->level_path)-4);
			int32_t mkdir_result;
			#ifdef _WIN32
				mkdir_result = _mkdir(temp_);
			#else
				mkdir_result = mkdir(temp_ ,0777);
			#endif
			if (mkdir_result == 0) {
				for (int32_t i = 0; i < this->tags.size(); i++) {
					OniTag *a_tag = this->tags.at(i);

					// before we ship to export, remapping has to be done to the instance ids.

					this->ExportTagToPath(a_tag, temp_);
				}
			} else {
				std::cout << "Export directory for \"" << this->name << "\" already exists." << std::endl;
			}
			free(temp_);
		}
	}
}

LevelHeader* OniLevel::CreateOniHeader(OniTag *tag) {
	LevelHeader *new_header = (LevelHeader *)malloc(sizeof(LevelHeader));
	new_header->checksum = this->header->checksum;
	new_header->version = ONIFileVersion;
	new_header->signature = this->header->signature;

	new_header->instance_count = this->GetInstanceCount(tag);
	new_header->name_count = 0; // always zero
	new_header->template_count = 0; // always zero

	new_header->names_offset = this->ComputeNamesOffset();
	new_header->names_size = this->ComputeNamesSize();

	new_header->data_offset = new_header->names_offset+new_header->names_size;
	new_header->data_size = this->ComputeDataSize();

	new_header->raw_offset = new_header->data_offset+new_header->data_size; // end of normal dat file
	new_header->raw_size = this->ComputeRawSize();

	new_header->unused[0] = 0;
	new_header->unused[1] = 0;

	return new_header;
}

int32_t OniLevel::GetInstanceCount(OniTag *tag) {
	int32_t count = tag->tm_tag->instance_count;
	if (count) {
		this->export_tags.push_back((Exporter){GetResID(tag->tm_tag->header->res_id),tag});
		int32_t *instance_ids = (int32_t *)malloc(sizeof(int32_t)*tag->tm_tag->instance_count);
		instance_ids = tag->tm_tag->GetInstanceIDs();
		for (int32_t i = 0; i < tag->tm_tag->instance_count; i++) {
			for (int32_t j = 0; j < this->tags.size(); j++) {
				printf("%i %i\n", instance_ids[i], CharToInt(this->tags.at(j)->tm_tag->header->res_id));
				if (instance_ids[i] == CharToInt(this->tags.at(j)->tm_tag->header->res_id)) {
					printf("Found %i linked to %i\n",instance_ids[i],CharToInt(tag->tm_tag->header->res_id));
					count = count + this->GetInstanceCount(this->tags.at(j));
					break;
				}
			}
		}
		free(instance_ids);
	}
	return count;
}

int32_t OniLevel::ComputeNamesOffset() {
	return 20*this->export_tags.size();
}

int32_t OniLevel::ComputeDataSize() {
	int32_t total = 0;
	for (int32_t i = 0; i < this->export_tags.size(); i++) {
		this->export_tags.at(i).data_offset = total;
		total = total + this->export_tags.at(i).tag->GetDataLength();
	}
	return total;
}

int32_t OniLevel::ComputeNamesSize() {
	int32_t length = 0;
	for (int32_t i = 0; i < this->export_tags.size(); i++) {
		if (strcmp(this->export_tags.at(i).tag->name, "unnamed") != 0) {
			this->export_tags.at(i).name_offset = length;
			length = length + strlen(this->export_tags.at(i).tag->name);
		} else {
			this->export_tags.at(i).name_offset = 0;
		}
	}
	return length;
}

int32_t OniLevel::ComputeRawSize() {
	int32_t length = 0;
	for (int32_t i = 0; i < this->export_tags.size(); i++) {
		length = length + this->export_tags.at(i).tag->tm_tag->raw_size;
	}
	return length;
}<|endoftext|>